aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec
downloadsrc-f034231a6a1fd5d6395206c1651de8cd9402cca3.tar.gz
src-f034231a6a1fd5d6395206c1651de8cd9402cca3.zip
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=254721
-rw-r--r--LICENSE.TXT38
-rw-r--r--include/lldb/API/LLDB.h54
-rw-r--r--include/lldb/API/SBAddress.h150
-rw-r--r--include/lldb/API/SBBlock.h123
-rw-r--r--include/lldb/API/SBBreakpoint.h175
-rw-r--r--include/lldb/API/SBBreakpointLocation.h110
-rw-r--r--include/lldb/API/SBBroadcaster.h97
-rw-r--r--include/lldb/API/SBCommandInterpreter.h193
-rw-r--r--include/lldb/API/SBCommandReturnObject.h133
-rw-r--r--include/lldb/API/SBCommunication.h99
-rw-r--r--include/lldb/API/SBCompileUnit.h116
-rw-r--r--include/lldb/API/SBData.h180
-rw-r--r--include/lldb/API/SBDebugger.h339
-rw-r--r--include/lldb/API/SBDeclaration.h89
-rw-r--r--include/lldb/API/SBDefines.h84
-rw-r--r--include/lldb/API/SBError.h106
-rw-r--r--include/lldb/API/SBEvent.h102
-rw-r--r--include/lldb/API/SBExpressionOptions.h89
-rw-r--r--include/lldb/API/SBFileSpec.h96
-rw-r--r--include/lldb/API/SBFileSpecList.h72
-rw-r--r--include/lldb/API/SBFrame.h242
-rw-r--r--include/lldb/API/SBFunction.h93
-rw-r--r--include/lldb/API/SBHostOS.h57
-rw-r--r--include/lldb/API/SBInputReader.h97
-rw-r--r--include/lldb/API/SBInstruction.h94
-rw-r--r--include/lldb/API/SBInstructionList.h71
-rw-r--r--include/lldb/API/SBLineEntry.h99
-rw-r--r--include/lldb/API/SBListener.h135
-rw-r--r--include/lldb/API/SBModule.h287
-rw-r--r--include/lldb/API/SBModuleSpec.h154
-rw-r--r--include/lldb/API/SBProcess.h295
-rw-r--r--include/lldb/API/SBSection.h104
-rw-r--r--include/lldb/API/SBSourceManager.h53
-rw-r--r--include/lldb/API/SBStream.h111
-rw-r--r--include/lldb/API/SBStringList.h71
-rw-r--r--include/lldb/API/SBSymbol.h109
-rw-r--r--include/lldb/API/SBSymbolContext.h94
-rw-r--r--include/lldb/API/SBSymbolContextList.h69
-rw-r--r--include/lldb/API/SBTarget.h828
-rw-r--r--include/lldb/API/SBThread.h220
-rw-r--r--include/lldb/API/SBType.h244
-rw-r--r--include/lldb/API/SBTypeCategory.h168
-rw-r--r--include/lldb/API/SBTypeFilter.h92
-rw-r--r--include/lldb/API/SBTypeFormat.h84
-rw-r--r--include/lldb/API/SBTypeNameSpecifier.h77
-rw-r--r--include/lldb/API/SBTypeSummary.h115
-rw-r--r--include/lldb/API/SBTypeSynthetic.h102
-rw-r--r--include/lldb/API/SBValue.h488
-rw-r--r--include/lldb/API/SBValueList.h93
-rw-r--r--include/lldb/API/SBWatchpoint.h104
-rw-r--r--include/lldb/Breakpoint/Breakpoint.h630
-rw-r--r--include/lldb/Breakpoint/BreakpointID.h117
-rw-r--r--include/lldb/Breakpoint/BreakpointIDList.h82
-rw-r--r--include/lldb/Breakpoint/BreakpointList.h193
-rw-r--r--include/lldb/Breakpoint/BreakpointLocation.h401
-rw-r--r--include/lldb/Breakpoint/BreakpointLocationCollection.h209
-rw-r--r--include/lldb/Breakpoint/BreakpointLocationList.h269
-rw-r--r--include/lldb/Breakpoint/BreakpointOptions.h358
-rw-r--r--include/lldb/Breakpoint/BreakpointResolver.h147
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverAddress.h74
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverFileLine.h74
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverFileRegex.h68
-rw-r--r--include/lldb/Breakpoint/BreakpointResolverName.h122
-rw-r--r--include/lldb/Breakpoint/BreakpointSite.h295
-rw-r--r--include/lldb/Breakpoint/BreakpointSiteList.h216
-rw-r--r--include/lldb/Breakpoint/Stoppoint.h63
-rw-r--r--include/lldb/Breakpoint/StoppointCallbackContext.h58
-rw-r--r--include/lldb/Breakpoint/StoppointLocation.h147
-rw-r--r--include/lldb/Breakpoint/Watchpoint.h252
-rw-r--r--include/lldb/Breakpoint/WatchpointList.h276
-rw-r--r--include/lldb/Breakpoint/WatchpointOptions.h255
-rw-r--r--include/lldb/Core/Address.h570
-rw-r--r--include/lldb/Core/AddressRange.h284
-rw-r--r--include/lldb/Core/AddressResolver.h89
-rw-r--r--include/lldb/Core/AddressResolverFileLine.h59
-rw-r--r--include/lldb/Core/AddressResolverName.h68
-rw-r--r--include/lldb/Core/ArchSpec.h422
-rw-r--r--include/lldb/Core/Baton.h62
-rw-r--r--include/lldb/Core/Broadcaster.h475
-rw-r--r--include/lldb/Core/ClangForward.h136
-rw-r--r--include/lldb/Core/Communication.h413
-rw-r--r--include/lldb/Core/Connection.h162
-rw-r--r--include/lldb/Core/ConnectionFileDescriptor.h139
-rw-r--r--include/lldb/Core/ConnectionMachPort.h92
-rw-r--r--include/lldb/Core/ConnectionSharedMemory.h70
-rw-r--r--include/lldb/Core/ConstString.h507
-rw-r--r--include/lldb/Core/DataBuffer.h94
-rw-r--r--include/lldb/Core/DataBufferHeap.h139
-rw-r--r--include/lldb/Core/DataBufferMemoryMap.h160
-rw-r--r--include/lldb/Core/DataEncoder.h459
-rw-r--r--include/lldb/Core/DataExtractor.h1298
-rw-r--r--include/lldb/Core/Debugger.h397
-rw-r--r--include/lldb/Core/Disassembler.h422
-rw-r--r--include/lldb/Core/EmulateInstruction.h641
-rw-r--r--include/lldb/Core/Error.h312
-rw-r--r--include/lldb/Core/Event.h217
-rw-r--r--include/lldb/Core/FileLineResolver.h81
-rw-r--r--include/lldb/Core/FileSpecList.h243
-rw-r--r--include/lldb/Core/Flags.h253
-rw-r--r--include/lldb/Core/History.h177
-rw-r--r--include/lldb/Core/IOStreamMacros.h38
-rw-r--r--include/lldb/Core/InputReader.h274
-rw-r--r--include/lldb/Core/InputReaderEZ.h87
-rw-r--r--include/lldb/Core/InputReaderStack.h58
-rw-r--r--include/lldb/Core/Language.h117
-rw-r--r--include/lldb/Core/Listener.h194
-rw-r--r--include/lldb/Core/Log.h236
-rw-r--r--include/lldb/Core/Mangled.h306
-rw-r--r--include/lldb/Core/MappedHash.h552
-rw-r--r--include/lldb/Core/Module.h1085
-rw-r--r--include/lldb/Core/ModuleChild.h90
-rw-r--r--include/lldb/Core/ModuleList.h556
-rw-r--r--include/lldb/Core/ModuleSpec.h594
-rw-r--r--include/lldb/Core/Opcode.h270
-rw-r--r--include/lldb/Core/PluginInterface.h37
-rw-r--r--include/lldb/Core/PluginManager.h352
-rw-r--r--include/lldb/Core/RangeMap.h1543
-rw-r--r--include/lldb/Core/RegisterValue.h406
-rw-r--r--include/lldb/Core/RegularExpression.h253
-rw-r--r--include/lldb/Core/STLUtils.h94
-rw-r--r--include/lldb/Core/Scalar.h341
-rw-r--r--include/lldb/Core/SearchFilter.h447
-rw-r--r--include/lldb/Core/Section.h313
-rw-r--r--include/lldb/Core/SourceManager.h196
-rw-r--r--include/lldb/Core/State.h78
-rw-r--r--include/lldb/Core/Stream.h612
-rw-r--r--include/lldb/Core/StreamAsynchronousIO.h42
-rw-r--r--include/lldb/Core/StreamBuffer.h87
-rw-r--r--include/lldb/Core/StreamCallback.h47
-rw-r--r--include/lldb/Core/StreamFile.h75
-rw-r--r--include/lldb/Core/StreamString.h64
-rw-r--r--include/lldb/Core/StreamTee.h175
-rw-r--r--include/lldb/Core/StringList.h107
-rw-r--r--include/lldb/Core/ThreadSafeSTLMap.h184
-rw-r--r--include/lldb/Core/ThreadSafeValue.h96
-rw-r--r--include/lldb/Core/Timer.h160
-rw-r--r--include/lldb/Core/UUID.h109
-rw-r--r--include/lldb/Core/UniqueCStringMap.h361
-rw-r--r--include/lldb/Core/UserID.h130
-rw-r--r--include/lldb/Core/UserSettingsController.h98
-rw-r--r--include/lldb/Core/VMRange.h181
-rw-r--r--include/lldb/Core/Value.h314
-rw-r--r--include/lldb/Core/ValueObject.h1375
-rw-r--r--include/lldb/Core/ValueObjectCast.h87
-rw-r--r--include/lldb/Core/ValueObjectChild.h122
-rw-r--r--include/lldb/Core/ValueObjectConstResult.h179
-rw-r--r--include/lldb/Core/ValueObjectConstResultChild.h77
-rw-r--r--include/lldb/Core/ValueObjectConstResultImpl.h96
-rw-r--r--include/lldb/Core/ValueObjectDynamicValue.h133
-rw-r--r--include/lldb/Core/ValueObjectList.h90
-rw-r--r--include/lldb/Core/ValueObjectMemory.h91
-rw-r--r--include/lldb/Core/ValueObjectRegister.h195
-rw-r--r--include/lldb/Core/ValueObjectSyntheticFilter.h182
-rw-r--r--include/lldb/Core/ValueObjectVariable.h90
-rw-r--r--include/lldb/Core/dwarf.h64
-rw-r--r--include/lldb/DataFormatters/CXXFormatterFunctions.h874
-rw-r--r--include/lldb/DataFormatters/DataVisualization.h174
-rw-r--r--include/lldb/DataFormatters/FormatCache.h101
-rw-r--r--include/lldb/DataFormatters/FormatClasses.h128
-rw-r--r--include/lldb/DataFormatters/FormatManager.h251
-rw-r--r--include/lldb/DataFormatters/FormatNavigator.h690
-rw-r--r--include/lldb/DataFormatters/TypeCategory.h230
-rw-r--r--include/lldb/DataFormatters/TypeCategoryMap.h148
-rw-r--r--include/lldb/DataFormatters/TypeFormat.h220
-rw-r--r--include/lldb/DataFormatters/TypeSummary.h547
-rw-r--r--include/lldb/DataFormatters/TypeSynthetic.h594
-rw-r--r--include/lldb/Expression/ASTDumper.h43
-rw-r--r--include/lldb/Expression/ASTResultSynthesizer.h184
-rw-r--r--include/lldb/Expression/ASTStructExtractor.h156
-rw-r--r--include/lldb/Expression/ClangASTSource.h530
-rw-r--r--include/lldb/Expression/ClangExpression.h153
-rw-r--r--include/lldb/Expression/ClangExpressionDeclMap.h698
-rw-r--r--include/lldb/Expression/ClangExpressionParser.h151
-rw-r--r--include/lldb/Expression/ClangExpressionVariable.h451
-rw-r--r--include/lldb/Expression/ClangFunction.h652
-rw-r--r--include/lldb/Expression/ClangPersistentVariables.h75
-rw-r--r--include/lldb/Expression/ClangUserExpression.h432
-rw-r--r--include/lldb/Expression/ClangUtilityFunction.h179
-rw-r--r--include/lldb/Expression/DWARFExpression.h424
-rw-r--r--include/lldb/Expression/ExpressionSourceCode.h78
-rw-r--r--include/lldb/Expression/IRDynamicChecks.h169
-rw-r--r--include/lldb/Expression/IRExecutionUnit.h495
-rw-r--r--include/lldb/Expression/IRForTarget.h733
-rw-r--r--include/lldb/Expression/IRInterpreter.h64
-rw-r--r--include/lldb/Expression/IRMemoryMap.h126
-rw-r--r--include/lldb/Expression/IRToDWARF.h111
-rw-r--r--include/lldb/Expression/Materializer.h173
-rw-r--r--include/lldb/Host/Condition.h124
-rw-r--r--include/lldb/Host/Config.h35
-rw-r--r--include/lldb/Host/DynamicLibrary.h51
-rw-r--r--include/lldb/Host/Endian.h33
-rw-r--r--include/lldb/Host/File.h500
-rw-r--r--include/lldb/Host/FileSpec.h692
-rw-r--r--include/lldb/Host/Host.h502
-rw-r--r--include/lldb/Host/Mutex.h312
-rw-r--r--include/lldb/Host/Predicate.h509
-rw-r--r--include/lldb/Host/ProcessRunLock.h165
-rw-r--r--include/lldb/Host/SocketAddress.h256
-rw-r--r--include/lldb/Host/Symbols.h69
-rw-r--r--include/lldb/Host/Terminal.h254
-rw-r--r--include/lldb/Host/TimeValue.h107
-rw-r--r--include/lldb/Host/freebsd/Config.h28
-rw-r--r--include/lldb/Interpreter/Args.h467
-rw-r--r--include/lldb/Interpreter/CommandCompletions.h307
-rw-r--r--include/lldb/Interpreter/CommandHistory.h76
-rw-r--r--include/lldb/Interpreter/CommandInterpreter.h486
-rw-r--r--include/lldb/Interpreter/CommandObject.h608
-rw-r--r--include/lldb/Interpreter/CommandObjectMultiword.h187
-rw-r--r--include/lldb/Interpreter/CommandObjectRegexCommand.h81
-rw-r--r--include/lldb/Interpreter/CommandReturnObject.h183
-rw-r--r--include/lldb/Interpreter/OptionGroupArchitecture.h73
-rw-r--r--include/lldb/Interpreter/OptionGroupBoolean.h83
-rw-r--r--include/lldb/Interpreter/OptionGroupFile.h142
-rw-r--r--include/lldb/Interpreter/OptionGroupFormat.h133
-rw-r--r--include/lldb/Interpreter/OptionGroupOutputFile.h76
-rw-r--r--include/lldb/Interpreter/OptionGroupPlatform.h120
-rw-r--r--include/lldb/Interpreter/OptionGroupString.h82
-rw-r--r--include/lldb/Interpreter/OptionGroupUInt64.h82
-rw-r--r--include/lldb/Interpreter/OptionGroupUUID.h61
-rw-r--r--include/lldb/Interpreter/OptionGroupValueObjectDisplay.h85
-rw-r--r--include/lldb/Interpreter/OptionGroupVariable.h65
-rw-r--r--include/lldb/Interpreter/OptionGroupWatchpoint.h71
-rw-r--r--include/lldb/Interpreter/OptionValue.h384
-rw-r--r--include/lldb/Interpreter/OptionValueArch.h139
-rw-r--r--include/lldb/Interpreter/OptionValueArgs.h46
-rw-r--r--include/lldb/Interpreter/OptionValueArray.h178
-rw-r--r--include/lldb/Interpreter/OptionValueBoolean.h141
-rw-r--r--include/lldb/Interpreter/OptionValueDictionary.h139
-rw-r--r--include/lldb/Interpreter/OptionValueEnumeration.h126
-rw-r--r--include/lldb/Interpreter/OptionValueFileSpec.h129
-rw-r--r--include/lldb/Interpreter/OptionValueFileSpecList.h105
-rw-r--r--include/lldb/Interpreter/OptionValueFormat.h107
-rw-r--r--include/lldb/Interpreter/OptionValuePathMappings.h94
-rw-r--r--include/lldb/Interpreter/OptionValueProperties.h265
-rw-r--r--include/lldb/Interpreter/OptionValueRegex.h98
-rw-r--r--include/lldb/Interpreter/OptionValueSInt64.h172
-rw-r--r--include/lldb/Interpreter/OptionValueString.h227
-rw-r--r--include/lldb/Interpreter/OptionValueUInt64.h134
-rw-r--r--include/lldb/Interpreter/OptionValueUUID.h106
-rw-r--r--include/lldb/Interpreter/OptionValues.h31
-rw-r--r--include/lldb/Interpreter/Options.h487
-rw-r--r--include/lldb/Interpreter/Property.h109
-rw-r--r--include/lldb/Interpreter/PythonDataObjects.h233
-rw-r--r--include/lldb/Interpreter/ScriptInterpreter.h519
-rw-r--r--include/lldb/Interpreter/ScriptInterpreterNone.h35
-rw-r--r--include/lldb/Interpreter/ScriptInterpreterPython.h407
-rw-r--r--include/lldb/Symbol/Block.h496
-rw-r--r--include/lldb/Symbol/ClangASTContext.h441
-rw-r--r--include/lldb/Symbol/ClangASTImporter.h371
-rw-r--r--include/lldb/Symbol/ClangASTType.h679
-rw-r--r--include/lldb/Symbol/ClangExternalASTSourceCallbacks.h171
-rw-r--r--include/lldb/Symbol/ClangExternalASTSourceCommon.h188
-rw-r--r--include/lldb/Symbol/ClangNamespaceDecl.h103
-rw-r--r--include/lldb/Symbol/CompileUnit.h422
-rw-r--r--include/lldb/Symbol/DWARFCallFrameInfo.h150
-rw-r--r--include/lldb/Symbol/Declaration.h278
-rw-r--r--include/lldb/Symbol/FuncUnwinders.h106
-rw-r--r--include/lldb/Symbol/Function.h638
-rw-r--r--include/lldb/Symbol/LineEntry.h174
-rw-r--r--include/lldb/Symbol/LineTable.h422
-rw-r--r--include/lldb/Symbol/ObjectContainer.h236
-rw-r--r--include/lldb/Symbol/ObjectFile.h706
-rw-r--r--include/lldb/Symbol/Symbol.h317
-rw-r--r--include/lldb/Symbol/SymbolContext.h566
-rw-r--r--include/lldb/Symbol/SymbolContextScope.h137
-rw-r--r--include/lldb/Symbol/SymbolFile.h167
-rw-r--r--include/lldb/Symbol/SymbolVendor.h207
-rw-r--r--include/lldb/Symbol/Symtab.h160
-rw-r--r--include/lldb/Symbol/TaggedASTType.h61
-rw-r--r--include/lldb/Symbol/Type.h596
-rw-r--r--include/lldb/Symbol/TypeList.h88
-rw-r--r--include/lldb/Symbol/TypeVendor.h61
-rw-r--r--include/lldb/Symbol/UnwindPlan.h499
-rw-r--r--include/lldb/Symbol/UnwindTable.h69
-rw-r--r--include/lldb/Symbol/Variable.h184
-rw-r--r--include/lldb/Symbol/VariableList.h95
-rw-r--r--include/lldb/Symbol/VerifyDecl.h20
-rw-r--r--include/lldb/Target/ABI.h137
-rw-r--r--include/lldb/Target/CPPLanguageRuntime.h158
-rw-r--r--include/lldb/Target/DynamicLoader.h239
-rw-r--r--include/lldb/Target/ExecutionContext.h778
-rw-r--r--include/lldb/Target/ExecutionContextScope.h74
-rw-r--r--include/lldb/Target/LanguageRuntime.h113
-rw-r--r--include/lldb/Target/Memory.h196
-rw-r--r--include/lldb/Target/ObjCLanguageRuntime.h604
-rw-r--r--include/lldb/Target/OperatingSystem.h101
-rw-r--r--include/lldb/Target/PathMappingList.h171
-rw-r--r--include/lldb/Target/Platform.h755
-rw-r--r--include/lldb/Target/Process.h3786
-rw-r--r--include/lldb/Target/RegisterContext.h213
-rw-r--r--include/lldb/Target/SectionLoadList.h89
-rw-r--r--include/lldb/Target/StackFrame.h207
-rw-r--r--include/lldb/Target/StackFrameList.h157
-rw-r--r--include/lldb/Target/StackID.h149
-rw-r--r--include/lldb/Target/StopInfo.h227
-rw-r--r--include/lldb/Target/Target.h1223
-rw-r--r--include/lldb/Target/TargetList.h239
-rw-r--r--include/lldb/Target/Thread.h1067
-rw-r--r--include/lldb/Target/ThreadList.h163
-rw-r--r--include/lldb/Target/ThreadPlan.h658
-rw-r--r--include/lldb/Target/ThreadPlanBase.h71
-rw-r--r--include/lldb/Target/ThreadPlanCallFunction.h193
-rw-r--r--include/lldb/Target/ThreadPlanCallUserExpression.h65
-rw-r--r--include/lldb/Target/ThreadPlanRunToAddress.h85
-rw-r--r--include/lldb/Target/ThreadPlanShouldStopHere.h94
-rw-r--r--include/lldb/Target/ThreadPlanStepInRange.h110
-rw-r--r--include/lldb/Target/ThreadPlanStepInstruction.h64
-rw-r--r--include/lldb/Target/ThreadPlanStepOut.h90
-rw-r--r--include/lldb/Target/ThreadPlanStepOverBreakpoint.h57
-rw-r--r--include/lldb/Target/ThreadPlanStepOverRange.h52
-rw-r--r--include/lldb/Target/ThreadPlanStepRange.h94
-rw-r--r--include/lldb/Target/ThreadPlanStepThrough.h71
-rw-r--r--include/lldb/Target/ThreadPlanStepUntil.h80
-rw-r--r--include/lldb/Target/ThreadPlanTracer.h131
-rw-r--r--include/lldb/Target/ThreadSpec.h155
-rw-r--r--include/lldb/Target/UnixSignals.h144
-rw-r--r--include/lldb/Target/Unwind.h120
-rw-r--r--include/lldb/Target/UnwindAssembly.h58
-rw-r--r--include/lldb/Utility/AnsiTerminal.h156
-rw-r--r--include/lldb/Utility/CleanUp.h322
-rw-r--r--include/lldb/Utility/PriorityPointerPair.h150
-rw-r--r--include/lldb/Utility/PseudoTerminal.h266
-rw-r--r--include/lldb/Utility/PythonPointer.h77
-rw-r--r--include/lldb/Utility/Range.h89
-rw-r--r--include/lldb/Utility/RefCounter.h56
-rw-r--r--include/lldb/Utility/SharedCluster.h108
-rw-r--r--include/lldb/Utility/SharingPtr.h816
-rw-r--r--include/lldb/Utility/Utils.h22
-rw-r--r--include/lldb/lldb-defines.h125
-rw-r--r--include/lldb/lldb-enumerations.h685
-rw-r--r--include/lldb/lldb-forward.h378
-rw-r--r--include/lldb/lldb-private-enumerations.h245
-rw-r--r--include/lldb/lldb-private-interfaces.h46
-rw-r--r--include/lldb/lldb-private-log.h90
-rw-r--r--include/lldb/lldb-private-types.h74
-rw-r--r--include/lldb/lldb-private.h84
-rw-r--r--include/lldb/lldb-public.h18
-rw-r--r--include/lldb/lldb-python.h29
-rw-r--r--include/lldb/lldb-types.h83
-rw-r--r--include/lldb/lldb-versioning.h1607
-rw-r--r--source/API/SBAddress.cpp326
-rw-r--r--source/API/SBBlock.cpp373
-rw-r--r--source/API/SBBreakpoint.cpp648
-rw-r--r--source/API/SBBreakpointLocation.cpp320
-rw-r--r--source/API/SBBroadcaster.cpp196
-rw-r--r--source/API/SBCommandInterpreter.cpp490
-rw-r--r--source/API/SBCommandReturnObject.cpp352
-rw-r--r--source/API/SBCommunication.cpp285
-rw-r--r--source/API/SBCompileUnit.cpp278
-rw-r--r--source/API/SBData.cpp785
-rw-r--r--source/API/SBDebugger.cpp1264
-rw-r--r--source/API/SBDeclaration.cpp206
-rw-r--r--source/API/SBError.cpp233
-rw-r--r--source/API/SBEvent.cpp245
-rw-r--r--source/API/SBExpressionOptions.cpp126
-rw-r--r--source/API/SBFileSpec.cpp181
-rw-r--r--source/API/SBFileSpecList.cpp142
-rw-r--r--source/API/SBFrame.cpp1526
-rw-r--r--source/API/SBFunction.cpp225
-rw-r--r--source/API/SBHostOS.cpp85
-rw-r--r--source/API/SBInputReader.cpp216
-rw-r--r--source/API/SBInstruction.cpp248
-rw-r--r--source/API/SBInstructionList.cpp132
-rw-r--r--source/API/SBLineEntry.cpp250
-rw-r--r--source/API/SBListener.cpp443
-rw-r--r--source/API/SBModule.cpp655
-rw-r--r--source/API/SBModuleSpec.cpp230
-rw-r--r--source/API/SBProcess.cpp1256
-rw-r--r--source/API/SBSection.cpp291
-rw-r--r--source/API/SBSourceManager.cpp146
-rw-r--r--source/API/SBStream.cpp187
-rw-r--r--source/API/SBStringList.cpp136
-rw-r--r--source/API/SBSymbol.cpp223
-rw-r--r--source/API/SBSymbolContext.cpp285
-rw-r--r--source/API/SBSymbolContextList.cpp117
-rw-r--r--source/API/SBTarget.cpp2660
-rw-r--r--source/API/SBThread.cpp1229
-rw-r--r--source/API/SBType.cpp648
-rw-r--r--source/API/SBTypeCategory.cpp576
-rw-r--r--source/API/SBTypeFilter.cpp199
-rw-r--r--source/API/SBTypeFormat.cpp155
-rw-r--r--source/API/SBTypeNameSpecifier.cpp150
-rw-r--r--source/API/SBTypeSummary.cpp335
-rw-r--r--source/API/SBTypeSynthetic.cpp209
-rw-r--r--source/API/SBValue.cpp1719
-rw-r--r--source/API/SBValueList.cpp275
-rw-r--r--source/API/SBWatchpoint.cpp298
-rw-r--r--source/Breakpoint/Breakpoint.cpp794
-rw-r--r--source/Breakpoint/BreakpointID.cpp123
-rw-r--r--source/Breakpoint/BreakpointIDList.cpp397
-rw-r--r--source/Breakpoint/BreakpointList.cpp243
-rw-r--r--source/Breakpoint/BreakpointLocation.cpp677
-rw-r--r--source/Breakpoint/BreakpointLocationCollection.cpp198
-rw-r--r--source/Breakpoint/BreakpointLocationList.cpp305
-rw-r--r--source/Breakpoint/BreakpointOptions.cpp298
-rw-r--r--source/Breakpoint/BreakpointResolver.cpp61
-rw-r--r--source/Breakpoint/BreakpointResolverAddress.cpp111
-rw-r--r--source/Breakpoint/BreakpointResolverFileLine.cpp246
-rw-r--r--source/Breakpoint/BreakpointResolverFileRegex.cpp134
-rw-r--r--source/Breakpoint/BreakpointResolverName.cpp357
-rw-r--r--source/Breakpoint/BreakpointSite.cpp234
-rw-r--r--source/Breakpoint/BreakpointSiteList.cpp240
-rw-r--r--source/Breakpoint/Stoppoint.cpp46
-rw-r--r--source/Breakpoint/StoppointCallbackContext.cpp39
-rw-r--r--source/Breakpoint/StoppointLocation.cpp48
-rw-r--r--source/Breakpoint/Watchpoint.cpp489
-rw-r--r--source/Breakpoint/WatchpointList.cpp306
-rw-r--r--source/Breakpoint/WatchpointOptions.cpp241
-rw-r--r--source/Commands/CommandCompletions.cpp754
-rw-r--r--source/Commands/CommandObjectApropos.cpp154
-rw-r--r--source/Commands/CommandObjectApropos.h44
-rw-r--r--source/Commands/CommandObjectArgs.cpp272
-rw-r--r--source/Commands/CommandObjectArgs.h72
-rw-r--r--source/Commands/CommandObjectBreakpoint.cpp1843
-rw-r--r--source/Commands/CommandObjectBreakpoint.h47
-rw-r--r--source/Commands/CommandObjectBreakpointCommand.cpp915
-rw-r--r--source/Commands/CommandObjectBreakpointCommand.h46
-rw-r--r--source/Commands/CommandObjectCommands.cpp2021
-rw-r--r--source/Commands/CommandObjectCommands.h40
-rw-r--r--source/Commands/CommandObjectDisassemble.cpp574
-rw-r--r--source/Commands/CommandObjectDisassemble.h110
-rw-r--r--source/Commands/CommandObjectExpression.cpp505
-rw-r--r--source/Commands/CommandObjectExpression.h99
-rw-r--r--source/Commands/CommandObjectFrame.cpp624
-rw-r--r--source/Commands/CommandObjectFrame.h40
-rw-r--r--source/Commands/CommandObjectHelp.cpp249
-rw-r--r--source/Commands/CommandObjectHelp.h119
-rw-r--r--source/Commands/CommandObjectLog.cpp503
-rw-r--r--source/Commands/CommandObjectLog.h48
-rw-r--r--source/Commands/CommandObjectMemory.cpp1370
-rw-r--r--source/Commands/CommandObjectMemory.h33
-rw-r--r--source/Commands/CommandObjectMultiword.cpp520
-rw-r--r--source/Commands/CommandObjectPlatform.cpp987
-rw-r--r--source/Commands/CommandObjectPlatform.h40
-rw-r--r--source/Commands/CommandObjectPlugin.cpp122
-rw-r--r--source/Commands/CommandObjectPlugin.h36
-rw-r--r--source/Commands/CommandObjectProcess.cpp1945
-rw-r--r--source/Commands/CommandObjectProcess.h37
-rw-r--r--source/Commands/CommandObjectQuit.cpp99
-rw-r--r--source/Commands/CommandObjectQuit.h46
-rw-r--r--source/Commands/CommandObjectRegister.cpp499
-rw-r--r--source/Commands/CommandObjectRegister.h45
-rw-r--r--source/Commands/CommandObjectSettings.cpp1208
-rw-r--r--source/Commands/CommandObjectSettings.h41
-rw-r--r--source/Commands/CommandObjectSource.cpp925
-rw-r--r--source/Commands/CommandObjectSource.h40
-rw-r--r--source/Commands/CommandObjectSyntax.cpp113
-rw-r--r--source/Commands/CommandObjectSyntax.h44
-rw-r--r--source/Commands/CommandObjectTarget.cpp5354
-rw-r--r--source/Commands/CommandObjectTarget.h41
-rw-r--r--source/Commands/CommandObjectThread.cpp1526
-rw-r--r--source/Commands/CommandObjectThread.h34
-rw-r--r--source/Commands/CommandObjectType.cpp4112
-rw-r--r--source/Commands/CommandObjectType.h37
-rw-r--r--source/Commands/CommandObjectVersion.cpp53
-rw-r--r--source/Commands/CommandObjectVersion.h43
-rw-r--r--source/Commands/CommandObjectWatchpoint.cpp1394
-rw-r--r--source/Commands/CommandObjectWatchpoint.h43
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.cpp850
-rw-r--r--source/Commands/CommandObjectWatchpointCommand.h46
-rw-r--r--source/Core/Address.cpp1045
-rw-r--r--source/Core/AddressRange.cpp208
-rw-r--r--source/Core/AddressResolver.cpp67
-rw-r--r--source/Core/AddressResolverFileLine.cpp102
-rw-r--r--source/Core/AddressResolverName.cpp255
-rw-r--r--source/Core/ArchSpec.cpp893
-rw-r--r--source/Core/Baton.cpp24
-rw-r--r--source/Core/Broadcaster.cpp499
-rw-r--r--source/Core/Communication.cpp431
-rw-r--r--source/Core/Connection.cpp24
-rw-r--r--source/Core/ConnectionFileDescriptor.cpp1528
-rw-r--r--source/Core/ConnectionMachPort.cpp323
-rw-r--r--source/Core/ConnectionSharedMemory.cpp131
-rw-r--r--source/Core/ConstString.cpp342
-rw-r--r--source/Core/DataBufferHeap.cpp111
-rw-r--r--source/Core/DataBufferMemoryMap.cpp258
-rw-r--r--source/Core/DataEncoder.cpp335
-rw-r--r--source/Core/DataExtractor.cpp2179
-rw-r--r--source/Core/Debugger.cpp2695
-rw-r--r--source/Core/Disassembler.cpp1269
-rw-r--r--source/Core/DynamicLoader.cpp76
-rw-r--r--source/Core/EmulateInstruction.cpp670
-rw-r--r--source/Core/Error.cpp399
-rw-r--r--source/Core/Event.cpp225
-rw-r--r--source/Core/FileLineResolver.cpp117
-rw-r--r--source/Core/FileSpecList.cpp234
-rw-r--r--source/Core/History.cpp26
-rw-r--r--source/Core/InputReader.cpp387
-rw-r--r--source/Core/InputReaderEZ.cpp91
-rw-r--r--source/Core/InputReaderStack.cpp80
-rw-r--r--source/Core/Language.cpp151
-rw-r--r--source/Core/Listener.cpp557
-rw-r--r--source/Core/Log.cpp529
-rw-r--r--source/Core/Mangled.cpp313
-rw-r--r--source/Core/Module.cpp1609
-rw-r--r--source/Core/ModuleChild.cpp46
-rw-r--r--source/Core/ModuleList.cpp1103
-rw-r--r--source/Core/Opcode.cpp134
-rw-r--r--source/Core/PluginManager.cpp2064
-rw-r--r--source/Core/RegisterValue.cpp1272
-rw-r--r--source/Core/RegularExpression.cpp279
-rw-r--r--source/Core/Scalar.cpp2279
-rw-r--r--source/Core/SearchFilter.cpp816
-rw-r--r--source/Core/Section.cpp562
-rw-r--r--source/Core/SourceManager.cpp651
-rw-r--r--source/Core/State.cpp115
-rw-r--r--source/Core/Stream.cpp786
-rw-r--r--source/Core/StreamAsynchronousIO.cpp52
-rw-r--r--source/Core/StreamCallback.cpp64
-rw-r--r--source/Core/StreamFile.cpp72
-rw-r--r--source/Core/StreamString.cpp100
-rw-r--r--source/Core/StringList.cpp290
-rw-r--r--source/Core/Timer.cpp250
-rw-r--r--source/Core/UUID.cpp279
-rw-r--r--source/Core/UserID.cpp23
-rw-r--r--source/Core/UserSettingsController.cpp111
-rw-r--r--source/Core/VMRange.cpp112
-rw-r--r--source/Core/Value.cpp761
-rw-r--r--source/Core/ValueObject.cpp4199
-rw-r--r--source/Core/ValueObjectCast.cpp129
-rw-r--r--source/Core/ValueObjectChild.cpp234
-rw-r--r--source/Core/ValueObjectConstResult.cpp354
-rw-r--r--source/Core/ValueObjectConstResultChild.cpp80
-rw-r--r--source/Core/ValueObjectConstResultImpl.cpp236
-rw-r--r--source/Core/ValueObjectDynamicValue.cpp372
-rw-r--r--source/Core/ValueObjectList.cpp166
-rw-r--r--source/Core/ValueObjectMemory.cpp275
-rw-r--r--source/Core/ValueObjectRegister.cpp431
-rw-r--r--source/Core/ValueObjectSyntheticFilter.cpp270
-rw-r--r--source/Core/ValueObjectVariable.cpp386
-rw-r--r--source/DataFormatters/CF.cpp299
-rw-r--r--source/DataFormatters/CXXFormatterFunctions.cpp1351
-rw-r--r--source/DataFormatters/Cocoa.cpp565
-rw-r--r--source/DataFormatters/DataVisualization.cpp279
-rw-r--r--source/DataFormatters/FormatCache.cpp169
-rw-r--r--source/DataFormatters/FormatClasses.cpp33
-rw-r--r--source/DataFormatters/FormatManager.cpp1083
-rw-r--r--source/DataFormatters/LibCxx.cpp519
-rw-r--r--source/DataFormatters/LibCxxList.cpp310
-rw-r--r--source/DataFormatters/LibCxxMap.cpp409
-rw-r--r--source/DataFormatters/LibStdcpp.cpp331
-rw-r--r--source/DataFormatters/NSArray.cpp371
-rw-r--r--source/DataFormatters/NSDictionary.cpp579
-rw-r--r--source/DataFormatters/NSSet.cpp513
-rw-r--r--source/DataFormatters/TypeCategory.cpp382
-rw-r--r--source/DataFormatters/TypeCategoryMap.cpp285
-rw-r--r--source/DataFormatters/TypeFormat.cpp52
-rw-r--r--source/DataFormatters/TypeSummary.cpp250
-rw-r--r--source/DataFormatters/TypeSynthetic.cpp114
-rw-r--r--source/Expression/ASTDumper.cpp132
-rw-r--r--source/Expression/ASTResultSynthesizer.cpp512
-rw-r--r--source/Expression/ASTStructExtractor.cpp220
-rw-r--r--source/Expression/ClangASTSource.cpp1866
-rw-r--r--source/Expression/ClangExpressionDeclMap.cpp1956
-rw-r--r--source/Expression/ClangExpressionParser.cpp595
-rw-r--r--source/Expression/ClangExpressionVariable.cpp136
-rw-r--r--source/Expression/ClangFunction.cpp633
-rw-r--r--source/Expression/ClangPersistentVariables.cpp89
-rw-r--r--source/Expression/ClangUserExpression.cpp1091
-rw-r--r--source/Expression/ClangUtilityFunction.cpp169
-rw-r--r--source/Expression/DWARFExpression.cpp2691
-rw-r--r--source/Expression/ExpressionSourceCode.cpp142
-rw-r--r--source/Expression/IRDynamicChecks.cpp659
-rw-r--r--source/Expression/IRExecutionUnit.cpp704
-rw-r--r--source/Expression/IRForTarget.cpp2879
-rw-r--r--source/Expression/IRInterpreter.cpp1379
-rw-r--r--source/Expression/IRMemoryMap.cpp758
-rw-r--r--source/Expression/Materializer.cpp1414
-rw-r--r--source/Host/common/Condition.cpp106
-rw-r--r--source/Host/common/DynamicLibrary.cpp33
-rw-r--r--source/Host/common/File.cpp716
-rw-r--r--source/Host/common/FileSpec.cpp1059
-rw-r--r--source/Host/common/Host.cpp1568
-rw-r--r--source/Host/common/Mutex.cpp390
-rw-r--r--source/Host/common/SocketAddress.cpp260
-rw-r--r--source/Host/common/Symbols.cpp163
-rw-r--r--source/Host/common/Terminal.cpp307
-rw-r--r--source/Host/common/TimeValue.cpp210
-rw-r--r--source/Host/freebsd/Host.cpp337
-rw-r--r--source/Interpreter/Args.cpp1789
-rw-r--r--source/Interpreter/CommandHistory.cpp143
-rw-r--r--source/Interpreter/CommandInterpreter.cpp2882
-rw-r--r--source/Interpreter/CommandObject.cpp1174
-rw-r--r--source/Interpreter/CommandObjectRegexCommand.cpp150
-rw-r--r--source/Interpreter/CommandObjectScript.cpp93
-rw-r--r--source/Interpreter/CommandObjectScript.h42
-rw-r--r--source/Interpreter/CommandReturnObject.cpp219
-rw-r--r--source/Interpreter/OptionGroupArchitecture.cpp86
-rw-r--r--source/Interpreter/OptionGroupBoolean.cpp67
-rw-r--r--source/Interpreter/OptionGroupFile.cpp97
-rw-r--r--source/Interpreter/OptionGroupFormat.cpp249
-rw-r--r--source/Interpreter/OptionGroupOutputFile.cpp81
-rw-r--r--source/Interpreter/OptionGroupPlatform.cpp149
-rw-r--r--source/Interpreter/OptionGroupString.cpp58
-rw-r--r--source/Interpreter/OptionGroupUInt64.cpp58
-rw-r--r--source/Interpreter/OptionGroupUUID.cpp76
-rw-r--r--source/Interpreter/OptionGroupValueObjectDisplay.cpp181
-rw-r--r--source/Interpreter/OptionGroupVariable.cpp144
-rw-r--r--source/Interpreter/OptionGroupWatchpoint.cpp121
-rw-r--r--source/Interpreter/OptionValue.cpp633
-rw-r--r--source/Interpreter/OptionValueArch.cpp111
-rw-r--r--source/Interpreter/OptionValueArgs.cpp38
-rw-r--r--source/Interpreter/OptionValueArray.cpp350
-rw-r--r--source/Interpreter/OptionValueBoolean.cpp135
-rw-r--r--source/Interpreter/OptionValueDictionary.cpp436
-rw-r--r--source/Interpreter/OptionValueEnumeration.cpp166
-rw-r--r--source/Interpreter/OptionValueFileSpec.cpp159
-rw-r--r--source/Interpreter/OptionValueFileSpecLIst.cpp186
-rw-r--r--source/Interpreter/OptionValueFormat.cpp78
-rw-r--r--source/Interpreter/OptionValuePathMappings.cpp185
-rw-r--r--source/Interpreter/OptionValueProperties.cpp762
-rw-r--r--source/Interpreter/OptionValueRegex.cpp86
-rw-r--r--source/Interpreter/OptionValueSInt64.cpp89
-rw-r--r--source/Interpreter/OptionValueString.cpp186
-rw-r--r--source/Interpreter/OptionValueUInt64.cpp89
-rw-r--r--source/Interpreter/OptionValueUUID.cpp123
-rw-r--r--source/Interpreter/Options.cpp1077
-rw-r--r--source/Interpreter/Property.cpp275
-rw-r--r--source/Interpreter/PythonDataObjects.cpp430
-rw-r--r--source/Interpreter/ScriptInterpreter.cpp105
-rw-r--r--source/Interpreter/ScriptInterpreterNone.cpp43
-rw-r--r--source/Interpreter/ScriptInterpreterPython.cpp3166
-rw-r--r--source/Interpreter/embedded_interpreter.py103
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp861
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h138
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp977
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h139
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp1288
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h138
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp864
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h166
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp177
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h115
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp336
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h230
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp481
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h170
-rw-r--r--source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp209
-rw-r--r--source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h88
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp13625
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.h990
-rw-r--r--source/Plugins/Instruction/ARM/EmulationStateARM.cpp406
-rw-r--r--source/Plugins/Instruction/ARM/EmulationStateARM.h100
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp461
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h101
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp585
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h229
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.cpp465
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.h433
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp1893
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h333
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp417
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.h109
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp648
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h162
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp418
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h147
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp132
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.h82
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp1677
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h322
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.cpp89
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.h120
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.cpp578
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.h133
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.cpp258
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.h207
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.cpp911
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.h211
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp193
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.h111
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp136
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp180
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIX.h70
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.cpp551
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.h169
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86.h110
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp1563
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.h347
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h110
-rw-r--r--source/Plugins/Process/Utility/ARMUtils.h394
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp279
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.h85
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp274
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.h43
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h136
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1226
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.h333
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp980
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.h269
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1066
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h274
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.cpp137
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp1541
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h212
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp206
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.cpp87
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.h56
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.cpp174
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.h102
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp261
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.h114
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp482
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.h77
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.cpp140
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.h152
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp322
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.h125
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp275
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h74
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp619
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h171
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h47
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h54
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp176
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.h174
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp643
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h268
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp2348
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h430
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp839
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h147
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp971
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h311
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp3291
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h396
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp196
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h57
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp214
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h107
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp211
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAttribute.h45
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp1027
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h210
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp62
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h51
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp202
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h74
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp274
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h76
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp177
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp797
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp2317
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h457
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp1436
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h225
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp48
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h29
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp132
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h57
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp296
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h38
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp166
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h99
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp192
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h46
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp104
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h109
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp497
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.h116
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp599
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp172
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h24
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.h34
-rw-r--r--source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h933
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp232
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.cpp87
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.h65
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp7973
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h622
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp1586
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h420
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h175
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp407
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h142
-rw-r--r--source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp199
-rw-r--r--source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h58
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp670
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h185
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp973
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h73
-rw-r--r--source/Symbol/Block.cpp631
-rw-r--r--source/Symbol/ClangASTContext.cpp2291
-rw-r--r--source/Symbol/ClangASTImporter.cpp718
-rw-r--r--source/Symbol/ClangASTType.cpp6486
-rw-r--r--source/Symbol/ClangExternalASTSourceCallbacks.cpp163
-rw-r--r--source/Symbol/ClangExternalASTSourceCommon.cpp89
-rw-r--r--source/Symbol/ClangNamespaceDecl.cpp25
-rw-r--r--source/Symbol/CompileUnit.cpp464
-rw-r--r--source/Symbol/DWARFCallFrameInfo.cpp815
-rw-r--r--source/Symbol/Declaration.cpp117
-rw-r--r--source/Symbol/FuncUnwinders.cpp247
-rw-r--r--source/Symbol/Function.cpp572
-rw-r--r--source/Symbol/LineEntry.cpp246
-rw-r--r--source/Symbol/LineTable.cpp588
-rw-r--r--source/Symbol/ObjectFile.cpp621
-rw-r--r--source/Symbol/Symbol.cpp462
-rw-r--r--source/Symbol/SymbolContext.cpp1205
-rw-r--r--source/Symbol/SymbolFile.cpp89
-rw-r--r--source/Symbol/SymbolVendor.cpp486
-rw-r--r--source/Symbol/Symtab.cpp1211
-rw-r--r--source/Symbol/Type.cpp990
-rw-r--r--source/Symbol/TypeList.cpp356
-rw-r--r--source/Symbol/UnwindPlan.cpp441
-rw-r--r--source/Symbol/UnwindTable.cpp153
-rw-r--r--source/Symbol/Variable.cpp894
-rw-r--r--source/Symbol/VariableList.cpp201
-rw-r--r--source/Symbol/VerifyDecl.cpp16
-rw-r--r--source/Target/ABI.cpp175
-rw-r--r--source/Target/CPPLanguageRuntime.cpp386
-rw-r--r--source/Target/ExecutionContext.cpp824
-rw-r--r--source/Target/LanguageRuntime.cpp343
-rw-r--r--source/Target/Memory.cpp461
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp605
-rw-r--r--source/Target/OperatingSystem.cpp67
-rw-r--r--source/Target/PathMappingList.cpp348
-rw-r--r--source/Target/Platform.cpp779
-rw-r--r--source/Target/Process.cpp5595
-rw-r--r--source/Target/RegisterContext.cpp600
-rw-r--r--source/Target/SectionLoadList.cpp276
-rw-r--r--source/Target/StackFrame.cpp1449
-rw-r--r--source/Target/StackFrameList.cpp899
-rw-r--r--source/Target/StackID.cpp110
-rw-r--r--source/Target/StopInfo.cpp1143
-rw-r--r--source/Target/Target.cpp2866
-rw-r--r--source/Target/TargetList.cpp576
-rw-r--r--source/Target/Thread.cpp1988
-rw-r--r--source/Target/ThreadList.cpp785
-rw-r--r--source/Target/ThreadPlan.cpp353
-rw-r--r--source/Target/ThreadPlanBase.cpp237
-rw-r--r--source/Target/ThreadPlanCallFunction.cpp614
-rw-r--r--source/Target/ThreadPlanCallUserExpression.cpp82
-rw-r--r--source/Target/ThreadPlanRunToAddress.cpp268
-rw-r--r--source/Target/ThreadPlanShouldStopHere.cpp74
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp485
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp227
-rw-r--r--source/Target/ThreadPlanStepOut.cpp489
-rw-r--r--source/Target/ThreadPlanStepOverBreakpoint.cpp165
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp388
-rw-r--r--source/Target/ThreadPlanStepRange.cpp522
-rw-r--r--source/Target/ThreadPlanStepThrough.cpp290
-rw-r--r--source/Target/ThreadPlanStepUntil.cpp413
-rw-r--r--source/Target/ThreadPlanTracer.cpp286
-rw-r--r--source/Target/ThreadSpec.cpp158
-rw-r--r--source/Target/UnixSignals.cpp293
-rw-r--r--source/Target/UnwindAssembly.cpp41
-rw-r--r--source/Utility/ARM_DWARF_Registers.cpp435
-rw-r--r--source/Utility/ARM_DWARF_Registers.h217
-rw-r--r--source/Utility/ARM_GCC_Registers.h146
-rw-r--r--source/Utility/KQueue.cpp87
-rw-r--r--source/Utility/KQueue.h72
-rw-r--r--source/Utility/PseudoTerminal.cpp339
-rw-r--r--source/Utility/Range.cpp103
-rw-r--r--source/Utility/RefCounter.cpp25
-rw-r--r--source/Utility/SharingPtr.cpp158
-rw-r--r--source/Utility/StringExtractor.cpp397
-rw-r--r--source/Utility/StringExtractor.h141
-rw-r--r--source/Utility/StringExtractorGDBRemote.cpp182
-rw-r--r--source/Utility/StringExtractorGDBRemote.h103
-rw-r--r--source/Utility/TimeSpecTimeout.cpp48
-rw-r--r--source/Utility/TimeSpecTimeout.h90
-rw-r--r--source/Utility/UuidCompatibility.h18
-rw-r--r--source/lldb-log.cpp257
-rw-r--r--source/lldb.cpp425
-rw-r--r--tools/driver/Driver.cpp1733
-rw-r--r--tools/driver/Driver.h201
-rw-r--r--tools/driver/IOChannel.cpp647
-rw-r--r--tools/driver/IOChannel.h174
885 files changed, 362847 insertions, 0 deletions
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 000000000000..1f0309419d78
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,38 @@
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2010 Apple Inc.
+All rights reserved.
+
+Developed by:
+
+ LLDB Team
+
+ http://lldb.llvm.org/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLDB Team, copyright holders, nor the names of
+ its contributors may be used to endorse or promote products derived from
+ this Software without specific prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
diff --git a/include/lldb/API/LLDB.h b/include/lldb/API/LLDB.h
new file mode 100644
index 000000000000..93bc3bc121e2
--- /dev/null
+++ b/include/lldb/API/LLDB.h
@@ -0,0 +1,54 @@
+//===-- LLDB.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_LLDB_h_
+#define LLDB_LLDB_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBBlock.h"
+#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBCommunication.h"
+#include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBData.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBDeclaration.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBFunction.h"
+#include "lldb/API/SBHostOS.h"
+#include "lldb/API/SBInputReader.h"
+#include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBInstructionList.h"
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBModule.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBSourceManager.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBSymbol.h"
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBType.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/API/SBValueList.h"
+
+#endif // LLDB_LLDB_h_
diff --git a/include/lldb/API/SBAddress.h b/include/lldb/API/SBAddress.h
new file mode 100644
index 000000000000..c5e8cc685a4c
--- /dev/null
+++ b/include/lldb/API/SBAddress.h
@@ -0,0 +1,150 @@
+//===-- SBAddress.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBAddress_h_
+#define LLDB_SBAddress_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBModule.h"
+
+namespace lldb {
+
+class SBAddress
+{
+public:
+
+ SBAddress ();
+
+ SBAddress (const lldb::SBAddress &rhs);
+
+ SBAddress (lldb::SBSection section, lldb::addr_t offset);
+
+ // Create an address by resolving a load address using the supplied target
+ SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target);
+
+ ~SBAddress ();
+
+ const lldb::SBAddress &
+ operator = (const lldb::SBAddress &rhs);
+
+ bool
+ IsValid () const;
+
+ void
+ Clear ();
+
+ addr_t
+ GetFileAddress () const;
+
+ addr_t
+ GetLoadAddress (const lldb::SBTarget &target) const;
+
+ void
+ SetAddress (lldb::SBSection section, lldb::addr_t offset);
+
+ void
+ SetLoadAddress (lldb::addr_t load_addr,
+ lldb::SBTarget &target);
+ bool
+ OffsetAddress (addr_t offset);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ // The following queries can lookup symbol information for a given address.
+ // An address might refer to code or data from an existing module, or it
+ // might refer to something on the stack or heap. The following functions
+ // will only return valid values if the address has been resolved to a code
+ // or data address using "void SBAddress::SetLoadAddress(...)" or
+ // "lldb::SBAddress SBTarget::ResolveLoadAddress (...)".
+ lldb::SBSymbolContext
+ GetSymbolContext (uint32_t resolve_scope);
+
+
+ // The following functions grab individual objects for a given address and
+ // are less efficient if you want more than one symbol related objects.
+ // Use one of the following when you want multiple debug symbol related
+ // objects for an address:
+ // lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t resolve_scope);
+ // lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const SBAddress &addr, uint32_t resolve_scope);
+ // One or more bits from the SymbolContextItem enumerations can be logically
+ // OR'ed together to more efficiently retrieve multiple symbol objects.
+
+ lldb::SBSection
+ GetSection ();
+
+ lldb::addr_t
+ GetOffset ();
+
+ lldb::SBModule
+ GetModule ();
+
+ lldb::SBCompileUnit
+ GetCompileUnit ();
+
+ lldb::SBFunction
+ GetFunction ();
+
+ lldb::SBBlock
+ GetBlock ();
+
+ lldb::SBSymbol
+ GetSymbol ();
+
+ lldb::SBLineEntry
+ GetLineEntry ();
+
+ lldb::AddressClass
+ GetAddressClass ();
+
+protected:
+
+ friend class SBBlock;
+ friend class SBBreakpointLocation;
+ friend class SBFrame;
+ friend class SBFunction;
+ friend class SBLineEntry;
+ friend class SBInstruction;
+ friend class SBModule;
+ friend class SBSection;
+ friend class SBSymbol;
+ friend class SBSymbolContext;
+ friend class SBTarget;
+ friend class SBThread;
+ friend class SBValue;
+
+ lldb_private::Address *
+ operator->();
+
+ const lldb_private::Address *
+ operator->() const;
+
+ lldb_private::Address *
+ get ();
+
+ lldb_private::Address &
+ ref();
+
+ const lldb_private::Address &
+ ref() const;
+
+ SBAddress (const lldb_private::Address *lldb_object_ptr);
+
+ void
+ SetAddress (const lldb_private::Address *lldb_object_ptr);
+
+private:
+
+ std::unique_ptr<lldb_private::Address> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBAddress_h_
diff --git a/include/lldb/API/SBBlock.h b/include/lldb/API/SBBlock.h
new file mode 100644
index 000000000000..b8e61fc6eb27
--- /dev/null
+++ b/include/lldb/API/SBBlock.h
@@ -0,0 +1,123 @@
+//===-- SBBlock.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBBlock_h_
+#define LLDB_SBBlock_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBValueList.h"
+
+namespace lldb {
+
+class SBBlock
+{
+public:
+
+ SBBlock ();
+
+ SBBlock (const lldb::SBBlock &rhs);
+
+ ~SBBlock ();
+
+ const lldb::SBBlock &
+ operator = (const lldb::SBBlock &rhs);
+
+ bool
+ IsInlined () const;
+
+ bool
+ IsValid () const;
+
+ const char *
+ GetInlinedName () const;
+
+ lldb::SBFileSpec
+ GetInlinedCallSiteFile () const;
+
+ uint32_t
+ GetInlinedCallSiteLine () const;
+
+ uint32_t
+ GetInlinedCallSiteColumn () const;
+
+ lldb::SBBlock
+ GetParent ();
+
+ lldb::SBBlock
+ GetSibling ();
+
+ lldb::SBBlock
+ GetFirstChild ();
+
+ uint32_t
+ GetNumRanges ();
+
+ lldb::SBAddress
+ GetRangeStartAddress (uint32_t idx);
+
+ lldb::SBAddress
+ GetRangeEndAddress (uint32_t idx);
+
+ uint32_t
+ GetRangeIndexForBlockAddress (lldb::SBAddress block_addr);
+
+ lldb::SBValueList
+ GetVariables (lldb::SBFrame& frame,
+ bool arguments,
+ bool locals,
+ bool statics,
+ lldb::DynamicValueType use_dynamic);
+
+ lldb::SBValueList
+ GetVariables (lldb::SBTarget& target,
+ bool arguments,
+ bool locals,
+ bool statics);
+ //------------------------------------------------------------------
+ /// Get the inlined block that contains this block.
+ ///
+ /// @return
+ /// If this block is inlined, it will return this block, else
+ /// parent blocks will be searched to see if any contain this
+ /// block and are themselves inlined. An invalid SBBlock will
+ /// be returned if this block nor any parent blocks are inlined
+ /// function blocks.
+ //------------------------------------------------------------------
+ lldb::SBBlock
+ GetContainingInlinedBlock ();
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+private:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBFunction;
+ friend class SBSymbolContext;
+
+ lldb_private::Block *
+ GetPtr ();
+
+ void
+ SetPtr (lldb_private::Block *lldb_object_ptr);
+
+ SBBlock (lldb_private::Block *lldb_object_ptr);
+
+ void
+ AppendVariables (bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list);
+
+ lldb_private::Block *m_opaque_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBBlock_h_
diff --git a/include/lldb/API/SBBreakpoint.h b/include/lldb/API/SBBreakpoint.h
new file mode 100644
index 000000000000..be9c499798e1
--- /dev/null
+++ b/include/lldb/API/SBBreakpoint.h
@@ -0,0 +1,175 @@
+//===-- SBBreakpoint.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBBreakpoint_h_
+#define LLDB_SBBreakpoint_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBBreakpoint
+{
+public:
+
+ typedef bool (*BreakpointHitCallback) (void *baton,
+ SBProcess &process,
+ SBThread &thread,
+ lldb::SBBreakpointLocation &location);
+
+ SBBreakpoint ();
+
+ SBBreakpoint (const lldb::SBBreakpoint& rhs);
+
+ ~SBBreakpoint();
+
+ const lldb::SBBreakpoint &
+ operator = (const lldb::SBBreakpoint& rhs);
+
+ // Tests to see if the opaque breakpoint object in this object matches the
+ // opaque breakpoint object in "rhs".
+ bool
+ operator == (const lldb::SBBreakpoint& rhs);
+
+ bool
+ operator != (const lldb::SBBreakpoint& rhs);
+
+ break_id_t
+ GetID () const;
+
+ bool
+ IsValid() const;
+
+ void
+ ClearAllBreakpointSites ();
+
+ lldb::SBBreakpointLocation
+ FindLocationByAddress (lldb::addr_t vm_addr);
+
+ lldb::break_id_t
+ FindLocationIDByAddress (lldb::addr_t vm_addr);
+
+ lldb::SBBreakpointLocation
+ FindLocationByID (lldb::break_id_t bp_loc_id);
+
+ lldb::SBBreakpointLocation
+ GetLocationAtIndex (uint32_t index);
+
+ void
+ SetEnabled (bool enable);
+
+ bool
+ IsEnabled ();
+
+ void
+ SetOneShot (bool one_shot);
+
+ bool
+ IsOneShot () const;
+
+ bool
+ IsInternal ();
+
+ uint32_t
+ GetHitCount () const;
+
+ void
+ SetIgnoreCount (uint32_t count);
+
+ uint32_t
+ GetIgnoreCount () const;
+
+ void
+ SetCondition (const char *condition);
+
+ const char *
+ GetCondition ();
+
+ void
+ SetThreadID (lldb::tid_t sb_thread_id);
+
+ lldb::tid_t
+ GetThreadID ();
+
+ void
+ SetThreadIndex (uint32_t index);
+
+ uint32_t
+ GetThreadIndex() const;
+
+ void
+ SetThreadName (const char *thread_name);
+
+ const char *
+ GetThreadName () const;
+
+ void
+ SetQueueName (const char *queue_name);
+
+ const char *
+ GetQueueName () const;
+
+ void
+ SetCallback (BreakpointHitCallback callback, void *baton);
+
+ size_t
+ GetNumResolvedLocations() const;
+
+ size_t
+ GetNumLocations() const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ static bool
+ EventIsBreakpointEvent (const lldb::SBEvent &event);
+
+ static lldb::BreakpointEventType
+ GetBreakpointEventTypeFromEvent (const lldb::SBEvent& event);
+
+ static lldb::SBBreakpoint
+ GetBreakpointFromEvent (const lldb::SBEvent& event);
+
+ static lldb::SBBreakpointLocation
+ GetBreakpointLocationAtIndexFromEvent (const lldb::SBEvent& event, uint32_t loc_idx);
+
+ static uint32_t
+ GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp);
+
+
+private:
+ friend class SBBreakpointLocation;
+ friend class SBTarget;
+
+ SBBreakpoint (const lldb::BreakpointSP &bp_sp);
+
+ lldb_private::Breakpoint *
+ operator->() const;
+
+ lldb_private::Breakpoint *
+ get() const;
+
+ lldb::BreakpointSP &
+ operator *();
+
+ const lldb::BreakpointSP &
+ operator *() const;
+
+ static bool
+ PrivateBreakpointHitCallback (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ lldb::BreakpointSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBreakpoint_h_
diff --git a/include/lldb/API/SBBreakpointLocation.h b/include/lldb/API/SBBreakpointLocation.h
new file mode 100644
index 000000000000..3b2ca2cf88e8
--- /dev/null
+++ b/include/lldb/API/SBBreakpointLocation.h
@@ -0,0 +1,110 @@
+//===-- SBBreakpointLocation.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBBreakpointLocation_h_
+#define LLDB_SBBreakpointLocation_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBBreakpoint.h"
+
+namespace lldb {
+
+class SBBreakpointLocation
+{
+public:
+
+ SBBreakpointLocation ();
+
+ SBBreakpointLocation (const lldb::SBBreakpointLocation &rhs);
+
+ ~SBBreakpointLocation ();
+
+ const lldb::SBBreakpointLocation &
+ operator = (const lldb::SBBreakpointLocation &rhs);
+
+ break_id_t
+ GetID ();
+
+ bool
+ IsValid() const;
+
+ lldb::SBAddress
+ GetAddress ();
+
+ lldb::addr_t
+ GetLoadAddress ();
+
+ void
+ SetEnabled(bool enabled);
+
+ bool
+ IsEnabled ();
+
+ uint32_t
+ GetIgnoreCount ();
+
+ void
+ SetIgnoreCount (uint32_t n);
+
+ void
+ SetCondition (const char *condition);
+
+ const char *
+ GetCondition ();
+
+ void
+ SetThreadID (lldb::tid_t sb_thread_id);
+
+ lldb::tid_t
+ GetThreadID ();
+
+ void
+ SetThreadIndex (uint32_t index);
+
+ uint32_t
+ GetThreadIndex() const;
+
+ void
+ SetThreadName (const char *thread_name);
+
+ const char *
+ GetThreadName () const;
+
+ void
+ SetQueueName (const char *queue_name);
+
+ const char *
+ GetQueueName () const;
+
+ bool
+ IsResolved ();
+
+ bool
+ GetDescription (lldb::SBStream &description, DescriptionLevel level);
+
+ SBBreakpoint
+ GetBreakpoint ();
+
+ SBBreakpointLocation (const lldb::BreakpointLocationSP &break_loc_sp);
+
+private:
+ friend class SBBreakpoint;
+#ifndef LLDB_DISABLE_PYTHON
+ friend class lldb_private::ScriptInterpreterPython;
+#endif
+ void
+ SetLocation (const lldb::BreakpointLocationSP &break_loc_sp);
+
+ lldb::BreakpointLocationSP m_opaque_sp;
+
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBreakpointLocation_h_
diff --git a/include/lldb/API/SBBroadcaster.h b/include/lldb/API/SBBroadcaster.h
new file mode 100644
index 000000000000..7b32d85faa0f
--- /dev/null
+++ b/include/lldb/API/SBBroadcaster.h
@@ -0,0 +1,97 @@
+//===-- SBBroadcaster.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBBroadcaster_h_
+#define LLDB_SBBroadcaster_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBBroadcaster
+{
+public:
+ SBBroadcaster ();
+
+ SBBroadcaster (const char *name);
+
+ SBBroadcaster (const SBBroadcaster &rhs);
+
+ const SBBroadcaster &
+ operator = (const SBBroadcaster &rhs);
+
+ ~SBBroadcaster();
+
+ bool
+ IsValid () const;
+
+ void
+ Clear ();
+
+ void
+ BroadcastEventByType (uint32_t event_type, bool unique = false);
+
+ void
+ BroadcastEvent (const lldb::SBEvent &event, bool unique = false);
+
+ void
+ AddInitialEventsToListener (const lldb::SBListener &listener, uint32_t requested_events);
+
+ uint32_t
+ AddListener (const lldb::SBListener &listener, uint32_t event_mask);
+
+ const char *
+ GetName () const;
+
+ bool
+ EventTypeHasListeners (uint32_t event_type);
+
+ bool
+ RemoveListener (const lldb::SBListener &listener, uint32_t event_mask = UINT32_MAX);
+
+ // This comparison is checking if the internal opaque pointer value
+ // is equal to that in "rhs".
+ bool
+ operator == (const lldb::SBBroadcaster &rhs) const;
+
+ // This comparison is checking if the internal opaque pointer value
+ // is not equal to that in "rhs".
+ bool
+ operator != (const lldb::SBBroadcaster &rhs) const;
+
+ // This comparison is checking if the internal opaque pointer value
+ // is less than that in "rhs" so SBBroadcaster objects can be contained
+ // in ordered containers.
+ bool
+ operator < (const lldb::SBBroadcaster &rhs) const;
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBCommunication;
+ friend class SBEvent;
+ friend class SBListener;
+ friend class SBProcess;
+ friend class SBTarget;
+
+ SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns);
+
+ lldb_private::Broadcaster *
+ get () const;
+
+ void
+ reset (lldb_private::Broadcaster *broadcaster, bool owns);
+
+private:
+ lldb::BroadcasterSP m_opaque_sp;
+ lldb_private::Broadcaster *m_opaque_ptr;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBBroadcaster_h_
diff --git a/include/lldb/API/SBCommandInterpreter.h b/include/lldb/API/SBCommandInterpreter.h
new file mode 100644
index 000000000000..9b2583cd85ca
--- /dev/null
+++ b/include/lldb/API/SBCommandInterpreter.h
@@ -0,0 +1,193 @@
+//===-- SBCommandInterpreter.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBCommandInterpreter_h_
+#define LLDB_SBCommandInterpreter_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBDebugger.h"
+
+namespace lldb {
+
+class SBCommandInterpreter
+{
+public:
+ enum
+ {
+ eBroadcastBitThreadShouldExit = (1 << 0),
+ eBroadcastBitResetPrompt = (1 << 1),
+ eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
+ eBroadcastBitAsynchronousOutputData = (1 << 3),
+ eBroadcastBitAsynchronousErrorData = (1 << 4)
+ };
+
+ SBCommandInterpreter (const lldb::SBCommandInterpreter &rhs);
+
+ const lldb::SBCommandInterpreter &
+ operator = (const lldb::SBCommandInterpreter &rhs);
+
+ ~SBCommandInterpreter ();
+
+ static const char *
+ GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type);
+
+ static const char *
+ GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
+
+ bool
+ IsValid() const;
+
+ bool
+ CommandExists (const char *cmd);
+
+ bool
+ AliasExists (const char *cmd);
+
+ lldb::SBBroadcaster
+ GetBroadcaster ();
+
+ static const char *
+ GetBroadcasterClass ();
+
+ bool
+ HasCommands ();
+
+ bool
+ HasAliases ();
+
+ bool
+ HasAliasOptions ();
+
+ lldb::SBProcess
+ GetProcess ();
+
+ lldb::SBDebugger
+ GetDebugger ();
+
+ lldb::SBCommand
+ AddMultiwordCommand (const char* name, const char* help);
+
+ lldb::SBCommand
+ AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, const char* help);
+
+ void
+ SourceInitFileInHomeDirectory (lldb::SBCommandReturnObject &result);
+
+ void
+ SourceInitFileInCurrentWorkingDirectory (lldb::SBCommandReturnObject &result);
+
+ lldb::ReturnStatus
+ HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false);
+
+ // The pointer based interface is not useful in SWIG, since the cursor & last_char arguments are string pointers INTO current_line
+ // and you can't do that in a scripting language interface in general...
+
+ // In either case, the way this works is that the you give it a line and cursor position in the line. The function
+ // will return the number of completions. The matches list will contain number_of_completions + 1 elements. The first
+ // element is the common substring after the cursor position for all the matches. The rest of the elements are the
+ // matches. The first element is useful if you are emulating the common shell behavior where the tab completes
+ // to the string that is common among all the matches, then you should first check if the first element is non-empty,
+ // and if so just insert it and move the cursor to the end of the insertion. The next tab will return an empty
+ // common substring, and a list of choices (if any), at which point you should display the choices and let the user
+ // type further to disambiguate.
+
+ int
+ HandleCompletion (const char *current_line,
+ const char *cursor,
+ const char *last_char,
+ int match_start_point,
+ int max_return_elements,
+ lldb::SBStringList &matches);
+
+ int
+ HandleCompletion (const char *current_line,
+ uint32_t cursor_pos,
+ int match_start_point,
+ int max_return_elements,
+ lldb::SBStringList &matches);
+
+ // Catch commands before they execute by registering a callback that will
+ // get called when the command gets executed. This allows GUI or command
+ // line interfaces to intercept a command and stop it from happening
+ bool
+ SetCommandOverrideCallback (const char *command_name,
+ lldb::CommandOverrideCallback callback,
+ void *baton);
+
+ SBCommandInterpreter (lldb_private::CommandInterpreter *interpreter_ptr = NULL); // Access using SBDebugger::GetCommandInterpreter();
+
+protected:
+
+ lldb_private::CommandInterpreter &
+ ref ();
+
+ lldb_private::CommandInterpreter *
+ get ();
+
+ void
+ reset (lldb_private::CommandInterpreter *);
+private:
+ friend class SBDebugger;
+
+ static void
+ InitializeSWIG ();
+
+ lldb_private::CommandInterpreter *m_opaque_ptr;
+};
+
+class SBCommandPluginInterface
+{
+public:
+ virtual bool
+ DoExecute (lldb::SBDebugger debugger,
+ char** command,
+ lldb::SBCommandReturnObject &result)
+ {
+ return false;
+ }
+
+ virtual
+ ~SBCommandPluginInterface ()
+ {}
+};
+
+class SBCommand
+{
+public:
+
+ SBCommand ();
+
+ bool
+ IsValid ();
+
+ const char*
+ GetName ();
+
+ const char*
+ GetHelp ();
+
+ lldb::SBCommand
+ AddMultiwordCommand (const char* name, const char* help = NULL);
+
+ lldb::SBCommand
+ AddCommand (const char* name, lldb::SBCommandPluginInterface* impl, const char* help = NULL);
+
+private:
+
+ friend class SBDebugger;
+ friend class SBCommandInterpreter;
+
+ SBCommand (lldb::CommandObjectSP cmd_sp);
+
+ lldb::CommandObjectSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBCommandInterpreter_h_
diff --git a/include/lldb/API/SBCommandReturnObject.h b/include/lldb/API/SBCommandReturnObject.h
new file mode 100644
index 000000000000..f2d274802330
--- /dev/null
+++ b/include/lldb/API/SBCommandReturnObject.h
@@ -0,0 +1,133 @@
+//===-- SBCommandReturnObject.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBCommandReturnObject_h_
+#define LLDB_SBCommandReturnObject_h_
+
+#include <stdio.h>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBCommandReturnObject
+{
+public:
+
+ SBCommandReturnObject ();
+
+ SBCommandReturnObject (const lldb::SBCommandReturnObject &rhs);
+
+ const lldb::SBCommandReturnObject &
+ operator = (const lldb::SBCommandReturnObject &rhs);
+
+
+ SBCommandReturnObject (lldb_private::CommandReturnObject *ptr);
+
+ lldb_private::CommandReturnObject *
+ Release ();
+
+ ~SBCommandReturnObject ();
+
+ bool
+ IsValid() const;
+
+ const char *
+ GetOutput ();
+
+ const char *
+ GetError ();
+
+ size_t
+ PutOutput (FILE *fh);
+
+ size_t
+ GetOutputSize ();
+
+ size_t
+ GetErrorSize ();
+
+ size_t
+ PutError (FILE *fh);
+
+ void
+ Clear();
+
+ lldb::ReturnStatus
+ GetStatus();
+
+ void
+ SetStatus (lldb::ReturnStatus status);
+
+ bool
+ Succeeded ();
+
+ bool
+ HasResult ();
+
+ void
+ AppendMessage (const char *message);
+
+ void
+ AppendWarning (const char *message);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ void
+ SetImmediateOutputFile (FILE *fh);
+
+ void
+ SetImmediateErrorFile (FILE *fh);
+
+ void
+ PutCString(const char* string, int len = -1);
+
+ size_t
+ Printf(const char* format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ const char *
+ GetOutput (bool only_if_no_immediate);
+
+ const char *
+ GetError (bool only_if_no_immediate);
+
+ void
+ SetError (lldb::SBError &error,
+ const char *fallback_error_cstr = NULL);
+
+ void
+ SetError (const char* error_cstr);
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBOptions;
+
+ lldb_private::CommandReturnObject *
+ operator->() const;
+
+ lldb_private::CommandReturnObject *
+ get() const;
+
+ lldb_private::CommandReturnObject &
+ operator*() const;
+
+ lldb_private::CommandReturnObject &
+ ref() const;
+
+ void
+ SetLLDBObjectPtr (lldb_private::CommandReturnObject *ptr);
+
+ private:
+ std::unique_ptr<lldb_private::CommandReturnObject> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBCommandReturnObject_h_
diff --git a/include/lldb/API/SBCommunication.h b/include/lldb/API/SBCommunication.h
new file mode 100644
index 000000000000..ecaaa3523c91
--- /dev/null
+++ b/include/lldb/API/SBCommunication.h
@@ -0,0 +1,99 @@
+//===-- SBCommunication.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBCommunication_h_
+#define LLDB_SBCommunication_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBError.h"
+
+namespace lldb {
+
+class SBCommunication
+{
+public:
+ enum {
+ eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost.
+ eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available.
+ eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients.
+ eBroadcastBitReadThreadShouldExit = (1 << 3), ///< Sent by clients that need to cancel the read thread.
+ eBroadcastBitPacketAvailable = (1 << 4), ///< Sent when data received makes a complete packet.
+ eAllEventBits = 0xffffffff
+ };
+
+ typedef void (*ReadThreadBytesReceived) (void *baton, const void *src, size_t src_len);
+
+ SBCommunication ();
+ SBCommunication (const char * broadcaster_name);
+ ~SBCommunication ();
+
+
+ bool
+ IsValid () const;
+
+ lldb::SBBroadcaster
+ GetBroadcaster ();
+
+ static const char *GetBroadcasterClass();
+
+ lldb::ConnectionStatus
+ AdoptFileDesriptor (int fd, bool owns_fd);
+
+ lldb::ConnectionStatus
+ Connect (const char *url);
+
+ lldb::ConnectionStatus
+ Disconnect ();
+
+ bool
+ IsConnected () const;
+
+ bool
+ GetCloseOnEOF ();
+
+ void
+ SetCloseOnEOF (bool b);
+
+ size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status);
+
+ size_t
+ Write (const void *src,
+ size_t src_len,
+ lldb::ConnectionStatus &status);
+
+ bool
+ ReadThreadStart ();
+
+ bool
+ ReadThreadStop ();
+
+ bool
+ ReadThreadIsRunning ();
+
+ bool
+ SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback,
+ void *callback_baton);
+
+
+private:
+
+ DISALLOW_COPY_AND_ASSIGN (SBCommunication);
+
+ lldb_private::Communication *m_opaque;
+ bool m_opaque_owned;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBCommunication_h_
diff --git a/include/lldb/API/SBCompileUnit.h b/include/lldb/API/SBCompileUnit.h
new file mode 100644
index 000000000000..95af3d4722ce
--- /dev/null
+++ b/include/lldb/API/SBCompileUnit.h
@@ -0,0 +1,116 @@
+//===-- SBCompileUnit.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBCompileUnit_h_
+#define LLDB_SBCompileUnit_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFileSpec.h"
+
+namespace lldb {
+
+class SBCompileUnit
+{
+public:
+
+ SBCompileUnit ();
+
+ SBCompileUnit (const lldb::SBCompileUnit &rhs);
+
+ ~SBCompileUnit ();
+
+ const lldb::SBCompileUnit &
+ operator = (const lldb::SBCompileUnit &rhs);
+
+ bool
+ IsValid () const;
+
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ uint32_t
+ GetNumLineEntries () const;
+
+ lldb::SBLineEntry
+ GetLineEntryAtIndex (uint32_t idx) const;
+
+ uint32_t
+ FindLineEntryIndex (uint32_t start_idx,
+ uint32_t line,
+ lldb::SBFileSpec *inline_file_spec) const;
+
+ uint32_t
+ FindLineEntryIndex (uint32_t start_idx,
+ uint32_t line,
+ lldb::SBFileSpec *inline_file_spec,
+ bool exact) const;
+
+ SBFileSpec
+ GetSupportFileAtIndex (uint32_t idx) const;
+
+ uint32_t
+ GetNumSupportFiles () const;
+
+ uint32_t
+ FindSupportFileIndex (uint32_t start_idx, const SBFileSpec &sb_file, bool full);
+
+ //------------------------------------------------------------------
+ /// Get all types matching \a type_mask from debug info in this
+ /// compile unit.
+ ///
+ /// @param[in] type_mask
+ /// A bitfield that consists of one or more bits logically OR'ed
+ /// together from the lldb::TypeClass enumeration. This allows
+ /// you to request only structure types, or only class, struct
+ /// and union types. Passing in lldb::eTypeClassAny will return
+ /// all types found in the debug information for this compile
+ /// unit.
+ ///
+ /// @return
+ /// A list of types in this compile unit that match \a type_mask
+ //------------------------------------------------------------------
+ lldb::SBTypeList
+ GetTypes (uint32_t type_mask = lldb::eTypeClassAny);
+
+ bool
+ operator == (const lldb::SBCompileUnit &rhs) const;
+
+ bool
+ operator != (const lldb::SBCompileUnit &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+private:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBSymbolContext;
+ friend class SBModule;
+
+ SBCompileUnit (lldb_private::CompileUnit *lldb_object_ptr);
+
+ const lldb_private::CompileUnit *
+ operator->() const;
+
+ const lldb_private::CompileUnit &
+ operator*() const;
+
+ lldb_private::CompileUnit *
+ get ();
+
+ void
+ reset (lldb_private::CompileUnit *lldb_object_ptr);
+
+ lldb_private::CompileUnit *m_opaque_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBCompileUnit_h_
diff --git a/include/lldb/API/SBData.h b/include/lldb/API/SBData.h
new file mode 100644
index 000000000000..10c002247271
--- /dev/null
+++ b/include/lldb/API/SBData.h
@@ -0,0 +1,180 @@
+//===-- SBData.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBData_h_
+#define LLDB_SBData_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBData
+{
+public:
+
+ SBData ();
+
+ SBData (const SBData &rhs);
+
+ const SBData &
+ operator = (const SBData &rhs);
+
+ ~SBData ();
+
+ uint8_t
+ GetAddressByteSize ();
+
+ void
+ SetAddressByteSize (uint8_t addr_byte_size);
+
+ void
+ Clear ();
+
+ bool
+ IsValid();
+
+ size_t
+ GetByteSize ();
+
+ lldb::ByteOrder
+ GetByteOrder();
+
+ void
+ SetByteOrder (lldb::ByteOrder endian);
+
+ float
+ GetFloat (lldb::SBError& error, lldb::offset_t offset);
+
+ double
+ GetDouble (lldb::SBError& error, lldb::offset_t offset);
+
+ long double
+ GetLongDouble (lldb::SBError& error, lldb::offset_t offset);
+
+ lldb::addr_t
+ GetAddress (lldb::SBError& error, lldb::offset_t offset);
+
+ uint8_t
+ GetUnsignedInt8 (lldb::SBError& error, lldb::offset_t offset);
+
+ uint16_t
+ GetUnsignedInt16 (lldb::SBError& error, lldb::offset_t offset);
+
+ uint32_t
+ GetUnsignedInt32 (lldb::SBError& error, lldb::offset_t offset);
+
+ uint64_t
+ GetUnsignedInt64 (lldb::SBError& error, lldb::offset_t offset);
+
+ int8_t
+ GetSignedInt8 (lldb::SBError& error, lldb::offset_t offset);
+
+ int16_t
+ GetSignedInt16 (lldb::SBError& error, lldb::offset_t offset);
+
+ int32_t
+ GetSignedInt32 (lldb::SBError& error, lldb::offset_t offset);
+
+ int64_t
+ GetSignedInt64 (lldb::SBError& error, lldb::offset_t offset);
+
+ const char*
+ GetString (lldb::SBError& error, lldb::offset_t offset);
+
+ size_t
+ ReadRawData (lldb::SBError& error,
+ lldb::offset_t offset,
+ void *buf,
+ size_t size);
+
+ bool
+ GetDescription (lldb::SBStream &description, lldb::addr_t base_addr = LLDB_INVALID_ADDRESS);
+
+ // it would be nice to have SetData(SBError, const void*, size_t) when endianness and address size can be
+ // inferred from the existing DataExtractor, but having two SetData() signatures triggers a SWIG bug where
+ // the typemap isn't applied before resolving the overload, and thus the right function never gets called
+ void
+ SetData (lldb::SBError& error, const void *buf, size_t size, lldb::ByteOrder endian, uint8_t addr_size);
+
+ // see SetData() for why we don't have Append(const void* buf, size_t size)
+ bool
+ Append (const SBData& rhs);
+
+ static lldb::SBData
+ CreateDataFromCString (lldb::ByteOrder endian, uint32_t addr_byte_size, const char* data);
+
+ // in the following CreateData*() and SetData*() prototypes, the two parameters array and array_len
+ // should not be renamed or rearranged, because doing so will break the SWIG typemap
+ static lldb::SBData
+ CreateDataFromUInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint64_t* array, size_t array_len);
+
+ static lldb::SBData
+ CreateDataFromUInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint32_t* array, size_t array_len);
+
+ static lldb::SBData
+ CreateDataFromSInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int64_t* array, size_t array_len);
+
+ static lldb::SBData
+ CreateDataFromSInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int32_t* array, size_t array_len);
+
+ static lldb::SBData
+ CreateDataFromDoubleArray (lldb::ByteOrder endian, uint32_t addr_byte_size, double* array, size_t array_len);
+
+ bool
+ SetDataFromCString (const char* data);
+
+ bool
+ SetDataFromUInt64Array (uint64_t* array, size_t array_len);
+
+ bool
+ SetDataFromUInt32Array (uint32_t* array, size_t array_len);
+
+ bool
+ SetDataFromSInt64Array (int64_t* array, size_t array_len);
+
+ bool
+ SetDataFromSInt32Array (int32_t* array, size_t array_len);
+
+ bool
+ SetDataFromDoubleArray (double* array, size_t array_len);
+
+
+protected:
+
+ // Mimic shared pointer...
+ lldb_private::DataExtractor *
+ get() const;
+
+ lldb_private::DataExtractor *
+ operator->() const;
+
+ lldb::DataExtractorSP &
+ operator*();
+
+ const lldb::DataExtractorSP &
+ operator*() const;
+
+ SBData (const lldb::DataExtractorSP &data_sp);
+
+ void
+ SetOpaque (const lldb::DataExtractorSP &data_sp);
+
+private:
+ friend class SBInstruction;
+ friend class SBProcess;
+ friend class SBSection;
+ friend class SBValue;
+
+ lldb::DataExtractorSP m_opaque_sp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBData_h_
diff --git a/include/lldb/API/SBDebugger.h b/include/lldb/API/SBDebugger.h
new file mode 100644
index 000000000000..518cbf67c932
--- /dev/null
+++ b/include/lldb/API/SBDebugger.h
@@ -0,0 +1,339 @@
+//===-- SBDebugger.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBDebugger_h_
+#define LLDB_SBDebugger_h_
+
+#include "lldb/API/SBDefines.h"
+#include <stdio.h>
+
+namespace lldb {
+
+class SBDebugger
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ // Deprecated, use the one that takes a source_init_files bool.
+ static lldb::SBDebugger
+ Create();
+
+ static lldb::SBDebugger
+ Create(bool source_init_files);
+
+ static lldb::SBDebugger
+ Create(bool source_init_files, lldb::LogOutputCallback log_callback, void *baton);
+
+ static void
+ Destroy (lldb::SBDebugger &debugger);
+
+ static void
+ MemoryPressureDetected ();
+
+ SBDebugger();
+
+ SBDebugger(const lldb::SBDebugger &rhs);
+
+ SBDebugger(const lldb::DebuggerSP &debugger_sp);
+
+ lldb::SBDebugger &
+ operator = (const lldb::SBDebugger &rhs);
+
+ ~SBDebugger();
+
+ bool
+ IsValid() const;
+
+ void
+ Clear ();
+
+ void
+ SetAsync (bool b);
+
+ bool
+ GetAsync ();
+
+ void
+ SkipLLDBInitFiles (bool b);
+
+ void
+ SkipAppInitFiles (bool b);
+
+ void
+ SetInputFileHandle (FILE *f, bool transfer_ownership);
+
+ void
+ SetOutputFileHandle (FILE *f, bool transfer_ownership);
+
+ void
+ SetErrorFileHandle (FILE *f, bool transfer_ownership);
+
+ FILE *
+ GetInputFileHandle ();
+
+ FILE *
+ GetOutputFileHandle ();
+
+ FILE *
+ GetErrorFileHandle ();
+
+ void
+ SaveInputTerminalState();
+
+ void
+ RestoreInputTerminalState();
+
+ lldb::SBCommandInterpreter
+ GetCommandInterpreter ();
+
+ void
+ HandleCommand (const char *command);
+
+ lldb::SBListener
+ GetListener ();
+
+ void
+ HandleProcessEvent (const lldb::SBProcess &process,
+ const lldb::SBEvent &event,
+ FILE *out,
+ FILE *err);
+
+ lldb::SBTarget
+ CreateTarget (const char *filename,
+ const char *target_triple,
+ const char *platform_name,
+ bool add_dependent_modules,
+ lldb::SBError& error);
+
+ lldb::SBTarget
+ CreateTargetWithFileAndTargetTriple (const char *filename,
+ const char *target_triple);
+
+ lldb::SBTarget
+ CreateTargetWithFileAndArch (const char *filename,
+ const char *archname);
+
+ lldb::SBTarget
+ CreateTarget (const char *filename);
+
+ // Return true if target is deleted from the target list of the debugger.
+ bool
+ DeleteTarget (lldb::SBTarget &target);
+
+ lldb::SBTarget
+ GetTargetAtIndex (uint32_t idx);
+
+ uint32_t
+ GetIndexOfTarget (lldb::SBTarget target);
+
+ lldb::SBTarget
+ FindTargetWithProcessID (pid_t pid);
+
+ lldb::SBTarget
+ FindTargetWithFileAndArch (const char *filename,
+ const char *arch);
+
+ uint32_t
+ GetNumTargets ();
+
+ lldb::SBTarget
+ GetSelectedTarget ();
+
+ void
+ SetSelectedTarget (SBTarget& target);
+
+ lldb::SBSourceManager
+ GetSourceManager ();
+
+ // REMOVE: just for a quick fix, need to expose platforms through
+ // SBPlatform from this class.
+ lldb::SBError
+ SetCurrentPlatform (const char *platform_name);
+
+ bool
+ SetCurrentPlatformSDKRoot (const char *sysroot);
+
+ // FIXME: Once we get the set show stuff in place, the driver won't need
+ // an interface to the Set/Get UseExternalEditor.
+ bool
+ SetUseExternalEditor (bool input);
+
+ bool
+ GetUseExternalEditor ();
+
+ bool
+ SetUseColor (bool use_color);
+
+ bool
+ GetUseColor () const;
+
+ static bool
+ GetDefaultArchitecture (char *arch_name, size_t arch_name_len);
+
+ static bool
+ SetDefaultArchitecture (const char *arch_name);
+
+ lldb::ScriptLanguage
+ GetScriptingLanguage (const char *script_language_name);
+
+ static const char *
+ GetVersionString ();
+
+ static const char *
+ StateAsCString (lldb::StateType state);
+
+ static bool
+ StateIsRunningState (lldb::StateType state);
+
+ static bool
+ StateIsStoppedState (lldb::StateType state);
+
+ bool
+ EnableLog (const char *channel, const char **categories);
+
+ void
+ SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton);
+
+ // DEPRECATED
+ void
+ DispatchInput (void* baton,
+ const void* data,
+ size_t data_len);
+
+ void
+ DispatchInput (const void *data, size_t data_len);
+
+ void
+ DispatchInputInterrupt ();
+
+ void
+ DispatchInputEndOfFile ();
+
+ void
+ PushInputReader (lldb::SBInputReader &reader);
+
+ void
+ NotifyTopInputReader (lldb::InputReaderAction notification);
+
+ bool
+ InputReaderIsTopReader (const lldb::SBInputReader &reader);
+
+ const char *
+ GetInstanceName ();
+
+ static SBDebugger
+ FindDebuggerWithID (int id);
+
+ static lldb::SBError
+ SetInternalVariable (const char *var_name, const char *value, const char *debugger_instance_name);
+
+ static lldb::SBStringList
+ GetInternalVariableValue (const char *var_name, const char *debugger_instance_name);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ uint32_t
+ GetTerminalWidth () const;
+
+ void
+ SetTerminalWidth (uint32_t term_width);
+
+ lldb::user_id_t
+ GetID ();
+
+ const char *
+ GetPrompt() const;
+
+ void
+ SetPrompt (const char *prompt);
+
+ lldb::ScriptLanguage
+ GetScriptLanguage() const;
+
+ void
+ SetScriptLanguage (lldb::ScriptLanguage script_lang);
+
+ bool
+ GetCloseInputOnEOF () const;
+
+ void
+ SetCloseInputOnEOF (bool b);
+
+ SBTypeCategory
+ GetCategory (const char* category_name);
+
+ SBTypeCategory
+ CreateCategory (const char* category_name);
+
+ bool
+ DeleteCategory (const char* category_name);
+
+ uint32_t
+ GetNumCategories ();
+
+ SBTypeCategory
+ GetCategoryAtIndex (uint32_t);
+
+ SBTypeCategory
+ GetDefaultCategory();
+
+ SBTypeFormat
+ GetFormatForType (SBTypeNameSpecifier);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSummary
+ GetSummaryForType (SBTypeNameSpecifier);
+#endif
+
+ SBTypeFilter
+ GetFilterForType (SBTypeNameSpecifier);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSynthetic
+ GetSyntheticForType (SBTypeNameSpecifier);
+#endif
+
+private:
+
+ friend class SBCommandInterpreter;
+ friend class SBInputReader;
+ friend class SBListener;
+ friend class SBProcess;
+ friend class SBSourceManager;
+ friend class SBTarget;
+
+ lldb::SBTarget
+ FindTargetWithLLDBProcess (const lldb::ProcessSP &processSP);
+
+ void
+ reset (const lldb::DebuggerSP &debugger_sp);
+
+ lldb_private::Debugger *
+ get () const;
+
+ lldb_private::Debugger &
+ ref () const;
+
+ const lldb::DebuggerSP &
+ get_sp () const;
+
+ lldb::DebuggerSP m_opaque_sp;
+
+}; // class SBDebugger
+
+
+} // namespace lldb
+
+#endif // LLDB_SBDebugger_h_
diff --git a/include/lldb/API/SBDeclaration.h b/include/lldb/API/SBDeclaration.h
new file mode 100644
index 000000000000..190026c0d2d0
--- /dev/null
+++ b/include/lldb/API/SBDeclaration.h
@@ -0,0 +1,89 @@
+//===-- SBDeclaration.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBDeclaration_h_
+#define LLDB_SBDeclaration_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFileSpec.h"
+
+namespace lldb {
+
+ class SBDeclaration
+ {
+ public:
+
+ SBDeclaration ();
+
+ SBDeclaration (const lldb::SBDeclaration &rhs);
+
+ ~SBDeclaration ();
+
+ const lldb::SBDeclaration &
+ operator = (const lldb::SBDeclaration &rhs);
+
+ bool
+ IsValid () const;
+
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ uint32_t
+ GetLine () const;
+
+ uint32_t
+ GetColumn () const;
+
+ void
+ SetFileSpec (lldb::SBFileSpec filespec);
+
+ void
+ SetLine (uint32_t line);
+
+ void
+ SetColumn (uint32_t column);
+
+ bool
+ operator == (const lldb::SBDeclaration &rhs) const;
+
+ bool
+ operator != (const lldb::SBDeclaration &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ protected:
+
+ lldb_private::Declaration *
+ get ();
+
+ private:
+ friend class SBValue;
+
+ const lldb_private::Declaration *
+ operator->() const;
+
+ lldb_private::Declaration &
+ ref();
+
+ const lldb_private::Declaration &
+ ref() const;
+
+ SBDeclaration (const lldb_private::Declaration *lldb_object_ptr);
+
+ void
+ SetDeclaration (const lldb_private::Declaration &lldb_object_ref);
+
+ std::unique_ptr<lldb_private::Declaration> m_opaque_ap;
+ };
+
+
+} // namespace lldb
+
+#endif // LLDB_SBDeclaration_h_
diff --git a/include/lldb/API/SBDefines.h b/include/lldb/API/SBDefines.h
new file mode 100644
index 000000000000..2cdf92170d8d
--- /dev/null
+++ b/include/lldb/API/SBDefines.h
@@ -0,0 +1,84 @@
+//===-- SBDefines.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBDefines_h_
+#define LLDB_SBDefines_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-versioning.h"
+
+// Forward Declarations
+
+namespace lldb {
+
+class SBAddress;
+class SBBlock;
+class SBBreakpoint;
+class SBBreakpointLocation;
+class SBBroadcaster;
+class SBCommand;
+class SBCommandInterpreter;
+class SBCommandPluginInterface;
+class SBCommandReturnObject;
+class SBCommunication;
+class SBCompileUnit;
+class SBData;
+class SBDebugger;
+class SBDeclaration;
+class SBError;
+class SBEvent;
+class SBEventList;
+class SBExpressionOptions;
+class SBFileSpec;
+class SBFileSpecList;
+class SBFrame;
+class SBFunction;
+class SBHostOS;
+class SBInputReader;
+class SBInstruction;
+class SBInstructionList;
+class SBLineEntry;
+class SBListener;
+class SBModule;
+class SBModuleSpec;
+class SBModuleSpecList;
+class SBProcess;
+class SBSourceManager;
+class SBStream;
+class SBStringList;
+class SBSymbol;
+class SBSymbolContext;
+class SBSymbolContextList;
+class SBTarget;
+class SBThread;
+class SBType;
+class SBTypeCategory;
+class SBTypeFilter;
+class SBTypeFormat;
+class SBTypeNameSpecifier;
+class SBTypeSummary;
+#ifndef LLDB_DISABLE_PYTHON
+class SBTypeSynthetic;
+#endif
+class SBTypeList;
+class SBValue;
+class SBValueList;
+class SBWatchpoint;
+
+}
+
+#endif // LLDB_SBDefines_h_
diff --git a/include/lldb/API/SBError.h b/include/lldb/API/SBError.h
new file mode 100644
index 000000000000..a6d3dacb4549
--- /dev/null
+++ b/include/lldb/API/SBError.h
@@ -0,0 +1,106 @@
+//===-- SBError.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBError_h_
+#define LLDB_SBError_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBError {
+public:
+ SBError ();
+
+ SBError (const lldb::SBError &rhs);
+
+ ~SBError();
+
+ const SBError &
+ operator =(const lldb::SBError &rhs);
+
+ const char *
+ GetCString () const;
+
+ void
+ Clear ();
+
+ bool
+ Fail () const;
+
+ bool
+ Success () const;
+
+ uint32_t
+ GetError () const;
+
+ lldb::ErrorType
+ GetType () const;
+
+ void
+ SetError (uint32_t err, lldb::ErrorType type);
+
+ void
+ SetErrorToErrno ();
+
+ void
+ SetErrorToGenericError ();
+
+ void
+ SetErrorString (const char *err_str);
+
+ int
+ SetErrorStringWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ bool
+ IsValid () const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+protected:
+
+ friend class SBCommandReturnObject;
+ friend class SBData;
+ friend class SBDebugger;
+ friend class SBCommunication;
+ friend class SBHostOS;
+ friend class SBInputReader;
+ friend class SBProcess;
+ friend class SBThread;
+ friend class SBTarget;
+ friend class SBValue;
+ friend class SBWatchpoint;
+
+ lldb_private::Error *
+ get();
+
+ lldb_private::Error *
+ operator->();
+
+ const lldb_private::Error &
+ operator*() const;
+
+ lldb_private::Error &
+ ref();
+
+ void
+ SetError (const lldb_private::Error &lldb_error);
+
+private:
+ std::unique_ptr<lldb_private::Error> m_opaque_ap;
+
+ void
+ CreateIfNeeded ();
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBError_h_
diff --git a/include/lldb/API/SBEvent.h b/include/lldb/API/SBEvent.h
new file mode 100644
index 000000000000..6cb975a1ff7b
--- /dev/null
+++ b/include/lldb/API/SBEvent.h
@@ -0,0 +1,102 @@
+//===-- SBEvent.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBEvent_h_
+#define LLDB_SBEvent_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <stdio.h>
+#include <vector>
+
+
+namespace lldb {
+
+class SBBroadcaster;
+
+class SBEvent
+{
+public:
+ SBEvent();
+
+ SBEvent (const lldb::SBEvent &rhs);
+
+ // Make an event that contains a C string.
+ SBEvent (uint32_t event, const char *cstr, uint32_t cstr_len);
+
+ ~SBEvent();
+
+ const SBEvent &
+ operator = (const lldb::SBEvent &rhs);
+
+ bool
+ IsValid() const;
+
+ const char *
+ GetDataFlavor ();
+
+ uint32_t
+ GetType () const;
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+ const char *
+ GetBroadcasterClass () const;
+
+ bool
+ BroadcasterMatchesPtr (const lldb::SBBroadcaster *broadcaster);
+
+ bool
+ BroadcasterMatchesRef (const lldb::SBBroadcaster &broadcaster);
+
+ void
+ Clear();
+
+ static const char *
+ GetCStringFromEvent (const lldb::SBEvent &event);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ bool
+ GetDescription (lldb::SBStream &description) const;
+
+protected:
+ friend class SBListener;
+ friend class SBBroadcaster;
+ friend class SBBreakpoint;
+ friend class SBDebugger;
+ friend class SBProcess;
+ friend class SBThread;
+ friend class SBWatchpoint;
+
+ SBEvent (lldb::EventSP &event_sp);
+
+ lldb::EventSP &
+ GetSP () const;
+
+ void
+ reset (lldb::EventSP &event_sp);
+
+ void
+ reset (lldb_private::Event* event);
+
+ lldb_private::Event *
+ get () const;
+
+private:
+
+ mutable lldb::EventSP m_event_sp;
+ mutable lldb_private::Event *m_opaque_ptr;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBEvent_h_
diff --git a/include/lldb/API/SBExpressionOptions.h b/include/lldb/API/SBExpressionOptions.h
new file mode 100644
index 000000000000..eed9ed528bef
--- /dev/null
+++ b/include/lldb/API/SBExpressionOptions.h
@@ -0,0 +1,89 @@
+//===-- SBEvent.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBExpressionOptions_h_
+#define LLDB_SBExpressionOptions_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <vector>
+
+namespace lldb {
+
+
+class SBExpressionOptions
+{
+public:
+ SBExpressionOptions();
+
+ SBExpressionOptions (const lldb::SBExpressionOptions &rhs);
+
+ ~SBExpressionOptions();
+
+ const SBExpressionOptions &
+ operator = (const lldb::SBExpressionOptions &rhs);
+
+ bool
+ GetCoerceResultToId () const;
+
+ void
+ SetCoerceResultToId (bool coerce = true);
+
+ bool
+ GetUnwindOnError () const;
+
+ void
+ SetUnwindOnError (bool unwind = true);
+
+ bool
+ GetIgnoreBreakpoints () const;
+
+ void
+ SetIgnoreBreakpoints (bool ignore = true);
+
+ lldb::DynamicValueType
+ GetFetchDynamicValue () const;
+
+ void
+ SetFetchDynamicValue (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget);
+
+ uint32_t
+ GetTimeoutInMicroSeconds () const;
+
+ void
+ SetTimeoutInMicroSeconds (uint32_t timeout = 0);
+
+ bool
+ GetTryAllThreads () const;
+
+ void
+ SetTryAllThreads (bool run_others = true);
+
+protected:
+
+ SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options);
+
+ lldb_private::EvaluateExpressionOptions *
+ get () const;
+
+ lldb_private::EvaluateExpressionOptions &
+ ref () const;
+
+ friend class SBFrame;
+ friend class SBValue;
+ friend class SBTarget;
+
+private:
+ // This auto_pointer is made in the constructor and is always valid.
+ mutable std::unique_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBExpressionOptions_h_
diff --git a/include/lldb/API/SBFileSpec.h b/include/lldb/API/SBFileSpec.h
new file mode 100644
index 000000000000..e44abe4759c6
--- /dev/null
+++ b/include/lldb/API/SBFileSpec.h
@@ -0,0 +1,96 @@
+//===-- SBFileSpec.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBFileSpec_h_
+#define LLDB_SBFileSpec_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBFileSpec
+{
+public:
+ SBFileSpec ();
+
+ SBFileSpec (const lldb::SBFileSpec &rhs);
+
+ SBFileSpec (const char *path);// Deprected, use SBFileSpec (const char *path, bool resolve)
+
+ SBFileSpec (const char *path, bool resolve);
+
+ ~SBFileSpec ();
+
+ const SBFileSpec &
+ operator = (const lldb::SBFileSpec &rhs);
+
+ bool
+ IsValid() const;
+
+ bool
+ Exists () const;
+
+ bool
+ ResolveExecutableLocation ();
+
+ const char *
+ GetFilename() const;
+
+ const char *
+ GetDirectory() const;
+
+ uint32_t
+ GetPath (char *dst_path, size_t dst_len) const;
+
+ static int
+ ResolvePath (const char *src_path, char *dst_path, size_t dst_len);
+
+ bool
+ GetDescription (lldb::SBStream &description) const;
+
+private:
+ friend class SBAttachInfo;
+ friend class SBBlock;
+ friend class SBCompileUnit;
+ friend class SBDeclaration;
+ friend class SBFileSpecList;
+ friend class SBHostOS;
+ friend class SBLaunchInfo;
+ friend class SBLineEntry;
+ friend class SBModule;
+ friend class SBModuleSpec;
+ friend class SBProcess;
+ friend class SBSourceManager;
+ friend class SBThread;
+ friend class SBTarget;
+
+ SBFileSpec (const lldb_private::FileSpec& fspec);
+
+ void
+ SetFileSpec (const lldb_private::FileSpec& fspec);
+
+ const lldb_private::FileSpec *
+ operator->() const;
+
+ const lldb_private::FileSpec *
+ get() const;
+
+ const lldb_private::FileSpec &
+ operator*() const;
+
+ const lldb_private::FileSpec &
+ ref() const;
+
+ std::unique_ptr<lldb_private::FileSpec> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBFileSpec_h_
diff --git a/include/lldb/API/SBFileSpecList.h b/include/lldb/API/SBFileSpecList.h
new file mode 100644
index 000000000000..734e7d4d35cc
--- /dev/null
+++ b/include/lldb/API/SBFileSpecList.h
@@ -0,0 +1,72 @@
+//===-- SBFileSpecList.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBFileSpecList_h_
+#define LLDB_SBFileSpecList_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBFileSpecList
+{
+public:
+ SBFileSpecList ();
+
+ SBFileSpecList (const lldb::SBFileSpecList &rhs);
+
+ ~SBFileSpecList ();
+
+ const SBFileSpecList &
+ operator = (const lldb::SBFileSpecList &rhs);
+
+ uint32_t
+ GetSize () const;
+
+ bool
+ GetDescription (SBStream &description) const;
+
+ void
+ Append (const SBFileSpec &sb_file);
+
+ bool
+ AppendIfUnique (const SBFileSpec &sb_file);
+
+ void
+ Clear();
+
+ uint32_t
+ FindFileIndex (uint32_t idx, const SBFileSpec &sb_file, bool full);
+
+ const SBFileSpec
+ GetFileSpecAtIndex (uint32_t idx) const;
+
+private:
+
+friend class SBTarget;
+
+ const lldb_private::FileSpecList *
+ operator->() const;
+
+ const lldb_private::FileSpecList *
+ get() const;
+
+ const lldb_private::FileSpecList &
+ operator*() const;
+
+ const lldb_private::FileSpecList &
+ ref() const;
+
+ std::unique_ptr<lldb_private::FileSpecList> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBFileSpecList_h_
diff --git a/include/lldb/API/SBFrame.h b/include/lldb/API/SBFrame.h
new file mode 100644
index 000000000000..4ae38c13bede
--- /dev/null
+++ b/include/lldb/API/SBFrame.h
@@ -0,0 +1,242 @@
+//===-- SBFrame.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBFrame_h_
+#define LLDB_SBFrame_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBValueList.h"
+
+namespace lldb {
+
+class SBFrame
+{
+public:
+ SBFrame ();
+
+ SBFrame (const lldb::SBFrame &rhs);
+
+ const lldb::SBFrame &
+ operator =(const lldb::SBFrame &rhs);
+
+ ~SBFrame();
+
+ bool
+ IsEqual (const lldb::SBFrame &that) const;
+
+ bool
+ IsValid() const;
+
+ uint32_t
+ GetFrameID () const;
+
+ lldb::addr_t
+ GetPC () const;
+
+ bool
+ SetPC (lldb::addr_t new_pc);
+
+ lldb::addr_t
+ GetSP () const;
+
+ lldb::addr_t
+ GetFP () const;
+
+ lldb::SBAddress
+ GetPCAddress () const;
+
+ lldb::SBSymbolContext
+ GetSymbolContext (uint32_t resolve_scope) const;
+
+ lldb::SBModule
+ GetModule () const;
+
+ lldb::SBCompileUnit
+ GetCompileUnit () const;
+
+ lldb::SBFunction
+ GetFunction () const;
+
+ lldb::SBSymbol
+ GetSymbol () const;
+
+ /// Gets the deepest block that contains the frame PC.
+ ///
+ /// See also GetFrameBlock().
+ lldb::SBBlock
+ GetBlock () const;
+
+ /// Get the appropriate function name for this frame. Inlined functions in
+ /// LLDB are represented by Blocks that have inlined function information, so
+ /// just looking at the SBFunction or SBSymbol for a frame isn't enough.
+ /// This function will return the appriopriate function, symbol or inlined
+ /// function name for the frame.
+ ///
+ /// This function returns:
+ /// - the name of the inlined function (if there is one)
+ /// - the name of the concrete function (if there is one)
+ /// - the name of the symbol (if there is one)
+ /// - NULL
+ ///
+ /// See also IsInlined().
+ const char *
+ GetFunctionName();
+
+ /// Return true if this frame represents an inlined function.
+ ///
+ /// See also GetFunctionName().
+ bool
+ IsInlined();
+
+ /// The version that doesn't supply a 'use_dynamic' value will use the
+ /// target's default.
+ lldb::SBValue
+ EvaluateExpression (const char *expr);
+
+ lldb::SBValue
+ EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic);
+
+ lldb::SBValue
+ EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error);
+
+ lldb::SBValue
+ EvaluateExpression (const char *expr, const SBExpressionOptions &options);
+
+ /// Gets the lexical block that defines the stack frame. Another way to think
+ /// of this is it will return the block that contains all of the variables
+ /// for a stack frame. Inlined functions are represented as SBBlock objects
+ /// that have inlined function information: the name of the inlined function,
+ /// where it was called from. The block that is returned will be the first
+ /// block at or above the block for the PC (SBFrame::GetBlock()) that defines
+ /// the scope of the frame. When a function contains no inlined functions,
+ /// this will be the top most lexical block that defines the function.
+ /// When a function has inlined functions and the PC is currently
+ /// in one of those inlined functions, this method will return the inlined
+ /// block that defines this frame. If the PC isn't currently in an inlined
+ /// function, the lexical block that defines the function is returned.
+ lldb::SBBlock
+ GetFrameBlock () const;
+
+ lldb::SBLineEntry
+ GetLineEntry () const;
+
+ lldb::SBThread
+ GetThread () const;
+
+ const char *
+ Disassemble () const;
+
+ void
+ Clear();
+
+ bool
+ operator == (const lldb::SBFrame &rhs) const;
+
+ bool
+ operator != (const lldb::SBFrame &rhs) const;
+
+ /// The version that doesn't supply a 'use_dynamic' value will use the
+ /// target's default.
+ lldb::SBValueList
+ GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only);
+
+ lldb::SBValueList
+ GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only,
+ lldb::DynamicValueType use_dynamic);
+
+ lldb::SBValueList
+ GetRegisters ();
+
+ lldb::SBValue
+ FindRegister (const char *name);
+
+ /// The version that doesn't supply a 'use_dynamic' value will use the
+ /// target's default.
+ lldb::SBValue
+ FindVariable (const char *var_name);
+
+ lldb::SBValue
+ FindVariable (const char *var_name, lldb::DynamicValueType use_dynamic);
+
+ // Find a value for a variable expression path like "rect.origin.x" or
+ // "pt_ptr->x", "*self", "*this->obj_ptr". The returned value is _not_
+ // and expression result and is not a constant object like
+ // SBFrame::EvaluateExpression(...) returns, but a child object of
+ // the variable value.
+ lldb::SBValue
+ GetValueForVariablePath (const char *var_expr_cstr,
+ DynamicValueType use_dynamic);
+
+ /// The version that doesn't supply a 'use_dynamic' value will use the
+ /// target's default.
+ lldb::SBValue
+ GetValueForVariablePath (const char *var_path);
+
+ /// Find variables, register sets, registers, or persistent variables using
+ /// the frame as the scope.
+ ///
+ /// NB. This function does not look up ivars in the function object pointer.
+ /// To do that use GetValueForVariablePath.
+ ///
+ /// The version that doesn't supply a 'use_dynamic' value will use the
+ /// target's default.
+ lldb::SBValue
+ FindValue (const char *name, ValueType value_type);
+
+ lldb::SBValue
+ FindValue (const char *name, ValueType value_type, lldb::DynamicValueType use_dynamic);
+
+ /// Find and watch a variable using the frame as the scope.
+ /// It returns an SBValue, similar to FindValue() method, if find-and-watch
+ /// operation succeeds. Otherwise, an invalid SBValue is returned.
+ /// You can use LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE for 'rw' watch.
+ lldb::SBValue
+ WatchValue (const char *name, ValueType value_type, uint32_t watch_type);
+
+ /// Find and watch the location pointed to by a variable using the frame as
+ /// the scope.
+ /// It returns an SBValue, similar to FindValue() method, if find-and-watch
+ /// operation succeeds. Otherwise, an invalid SBValue is returned.
+ /// You can use LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE for 'rw' watch.
+ lldb::SBValue
+ WatchLocation (const char *name, ValueType value_type, uint32_t watch_type, size_t size);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ SBFrame (const lldb::StackFrameSP &lldb_object_sp);
+
+protected:
+
+ friend class SBBlock;
+ friend class SBInstruction;
+ friend class SBThread;
+ friend class SBValue;
+#ifndef LLDB_DISABLE_PYTHON
+ friend class lldb_private::ScriptInterpreterPython;
+#endif
+
+ lldb::StackFrameSP
+ GetFrameSP() const;
+
+ void
+ SetFrameSP (const lldb::StackFrameSP &lldb_object_sp);
+
+ lldb::ExecutionContextRefSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBFrame_h_
diff --git a/include/lldb/API/SBFunction.h b/include/lldb/API/SBFunction.h
new file mode 100644
index 000000000000..49a3847efbec
--- /dev/null
+++ b/include/lldb/API/SBFunction.h
@@ -0,0 +1,93 @@
+//===-- SBFunction.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBFunction_h_
+#define LLDB_SBFunction_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBInstructionList.h"
+
+namespace lldb {
+
+class SBFunction
+{
+public:
+
+ SBFunction ();
+
+ SBFunction (const lldb::SBFunction &rhs);
+
+ const lldb::SBFunction &
+ operator = (const lldb::SBFunction &rhs);
+
+ ~SBFunction ();
+
+ bool
+ IsValid () const;
+
+ const char *
+ GetName() const;
+
+ const char *
+ GetMangledName () const;
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::SBTarget target);
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::SBTarget target, const char *flavor);
+
+ lldb::SBAddress
+ GetStartAddress ();
+
+ lldb::SBAddress
+ GetEndAddress ();
+
+ uint32_t
+ GetPrologueByteSize ();
+
+ lldb::SBType
+ GetType ();
+
+ lldb::SBBlock
+ GetBlock ();
+
+ bool
+ operator == (const lldb::SBFunction &rhs) const;
+
+ bool
+ operator != (const lldb::SBFunction &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+protected:
+
+ lldb_private::Function *
+ get ();
+
+ void
+ reset (lldb_private::Function *lldb_object_ptr);
+
+private:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+ SBFunction (lldb_private::Function *lldb_object_ptr);
+
+
+ lldb_private::Function *m_opaque_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBFunction_h_
diff --git a/include/lldb/API/SBHostOS.h b/include/lldb/API/SBHostOS.h
new file mode 100644
index 000000000000..52754ea4e829
--- /dev/null
+++ b/include/lldb/API/SBHostOS.h
@@ -0,0 +1,57 @@
+//===-- SBHostOS.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBHostOS_h_
+#define LLDB_SBHostOS_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFileSpec.h"
+
+namespace lldb {
+
+class SBHostOS
+{
+public:
+
+ static lldb::SBFileSpec
+ GetProgramFileSpec ();
+
+ static lldb::SBFileSpec
+ GetLLDBPythonPath ();
+
+ static void
+ ThreadCreated (const char *name);
+
+ static lldb::thread_t
+ ThreadCreate (const char *name,
+ void *(*thread_function)(void *),
+ void *thread_arg,
+ lldb::SBError *err);
+
+ static bool
+ ThreadCancel (lldb::thread_t thread,
+ lldb::SBError *err);
+
+ static bool
+ ThreadDetach (lldb::thread_t thread,
+ lldb::SBError *err);
+ static bool
+ ThreadJoin (lldb::thread_t thread,
+ void **result,
+ lldb::SBError *err);
+
+
+private:
+
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBHostOS_h_
diff --git a/include/lldb/API/SBInputReader.h b/include/lldb/API/SBInputReader.h
new file mode 100644
index 000000000000..61f7de4fde4c
--- /dev/null
+++ b/include/lldb/API/SBInputReader.h
@@ -0,0 +1,97 @@
+//===-- SBInputReader.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBInputReader_h_
+#define LLDB_SBInputReader_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBInputReader
+{
+public:
+
+ typedef size_t (*Callback) (void *baton,
+ SBInputReader *reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ SBInputReader ();
+
+ SBInputReader (const lldb::InputReaderSP &reader_sp);
+
+ SBInputReader (const lldb::SBInputReader &rhs);
+
+ ~SBInputReader ();
+
+
+ SBError
+ Initialize (SBDebugger &debugger,
+ Callback callback,
+ void *callback_baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo);
+
+ bool
+ IsValid () const;
+
+ const lldb::SBInputReader &
+ operator = (const lldb::SBInputReader &rhs);
+
+ bool
+ IsActive () const;
+
+ bool
+ IsDone () const;
+
+ void
+ SetIsDone (bool value);
+
+ InputReaderGranularity
+ GetGranularity ();
+
+protected:
+ friend class SBDebugger;
+
+ lldb_private::InputReader *
+ operator->() const;
+
+ lldb::InputReaderSP &
+ operator *();
+
+ const lldb::InputReaderSP &
+ operator *() const;
+
+ lldb_private::InputReader *
+ get() const;
+
+ lldb_private::InputReader &
+ ref() const;
+
+private:
+
+ static size_t
+ PrivateCallback (void *baton,
+ lldb_private::InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ lldb::InputReaderSP m_opaque_sp;
+ Callback m_callback_function;
+ void *m_callback_baton;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBInputReader_h_
diff --git a/include/lldb/API/SBInstruction.h b/include/lldb/API/SBInstruction.h
new file mode 100644
index 000000000000..aad2d87f4f33
--- /dev/null
+++ b/include/lldb/API/SBInstruction.h
@@ -0,0 +1,94 @@
+//===-- SBInstruction.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBInstruction_h_
+#define LLDB_SBInstruction_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBData.h"
+
+#include <stdio.h>
+
+// There's a lot to be fixed here, but need to wait for underlying insn implementation
+// to be revised & settle down first.
+
+namespace lldb {
+
+class SBInstruction
+{
+public:
+
+ SBInstruction ();
+
+ SBInstruction (const SBInstruction &rhs);
+
+ const SBInstruction &
+ operator = (const SBInstruction &rhs);
+
+ ~SBInstruction ();
+
+ bool
+ IsValid();
+
+ SBAddress
+ GetAddress();
+
+ lldb::AddressClass
+ GetAddressClass ();
+
+ const char *
+ GetMnemonic (lldb::SBTarget target);
+
+ const char *
+ GetOperands (lldb::SBTarget target);
+
+ const char *
+ GetComment (lldb::SBTarget target);
+
+ lldb::SBData
+ GetData (lldb::SBTarget target);
+
+ size_t
+ GetByteSize ();
+
+ bool
+ DoesBranch ();
+
+ void
+ Print (FILE *out);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ bool
+ EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options);
+
+ bool
+ DumpEmulation (const char * triple); // triple is to specify the architecture, e.g. 'armv6' or 'armv7-apple-ios'
+
+ bool
+ TestEmulation (lldb::SBStream &output_stream, const char *test_file);
+
+protected:
+ friend class SBInstructionList;
+
+ SBInstruction (const lldb::InstructionSP &inst_sp);
+
+ void
+ SetOpaque (const lldb::InstructionSP &inst_sp);
+
+private:
+
+ lldb::InstructionSP m_opaque_sp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBInstruction_h_
diff --git a/include/lldb/API/SBInstructionList.h b/include/lldb/API/SBInstructionList.h
new file mode 100644
index 000000000000..944e144a1480
--- /dev/null
+++ b/include/lldb/API/SBInstructionList.h
@@ -0,0 +1,71 @@
+//===-- SBInstructionList.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBInstructionList_h_
+#define LLDB_SBInstructionList_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <stdio.h>
+
+namespace lldb {
+
+class SBInstructionList
+{
+public:
+
+ SBInstructionList ();
+
+ SBInstructionList (const SBInstructionList &rhs);
+
+ const SBInstructionList &
+ operator = (const SBInstructionList &rhs);
+
+ ~SBInstructionList ();
+
+ bool
+ IsValid () const;
+
+ size_t
+ GetSize ();
+
+ lldb::SBInstruction
+ GetInstructionAtIndex (uint32_t idx);
+
+ void
+ Clear ();
+
+ void
+ AppendInstruction (lldb::SBInstruction inst);
+
+ void
+ Print (FILE *out);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ bool
+ DumpEmulationForAllInstructions (const char *triple);
+
+protected:
+ friend class SBFunction;
+ friend class SBSymbol;
+ friend class SBTarget;
+
+ void
+ SetDisassembler (const lldb::DisassemblerSP &opaque_sp);
+
+private:
+ lldb::DisassemblerSP m_opaque_sp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBInstructionList_h_
diff --git a/include/lldb/API/SBLineEntry.h b/include/lldb/API/SBLineEntry.h
new file mode 100644
index 000000000000..2d099a297980
--- /dev/null
+++ b/include/lldb/API/SBLineEntry.h
@@ -0,0 +1,99 @@
+//===-- SBLineEntry.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBLineEntry_h_
+#define LLDB_SBLineEntry_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBFileSpec.h"
+
+namespace lldb {
+
+class SBLineEntry
+{
+public:
+
+ SBLineEntry ();
+
+ SBLineEntry (const lldb::SBLineEntry &rhs);
+
+ ~SBLineEntry ();
+
+ const lldb::SBLineEntry &
+ operator = (const lldb::SBLineEntry &rhs);
+
+ lldb::SBAddress
+ GetStartAddress () const;
+
+ lldb::SBAddress
+ GetEndAddress () const;
+
+ bool
+ IsValid () const;
+
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ uint32_t
+ GetLine () const;
+
+ uint32_t
+ GetColumn () const;
+
+ void
+ SetFileSpec (lldb::SBFileSpec filespec);
+
+ void
+ SetLine (uint32_t line);
+
+ void
+ SetColumn (uint32_t column);
+
+ bool
+ operator == (const lldb::SBLineEntry &rhs) const;
+
+ bool
+ operator != (const lldb::SBLineEntry &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+protected:
+
+ lldb_private::LineEntry *
+ get ();
+
+private:
+ friend class SBAddress;
+ friend class SBCompileUnit;
+ friend class SBFrame;
+ friend class SBSymbolContext;
+
+ const lldb_private::LineEntry *
+ operator->() const;
+
+ lldb_private::LineEntry &
+ ref();
+
+ const lldb_private::LineEntry &
+ ref() const;
+
+ SBLineEntry (const lldb_private::LineEntry *lldb_object_ptr);
+
+ void
+ SetLineEntry (const lldb_private::LineEntry &lldb_object_ref);
+
+ std::unique_ptr<lldb_private::LineEntry> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBLineEntry_h_
diff --git a/include/lldb/API/SBListener.h b/include/lldb/API/SBListener.h
new file mode 100644
index 000000000000..c5a047341741
--- /dev/null
+++ b/include/lldb/API/SBListener.h
@@ -0,0 +1,135 @@
+//===-- SBListener.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBListener_h_
+#define LLDB_SBListener_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBListener
+{
+public:
+ SBListener ();
+
+ SBListener (const char *name);
+
+ SBListener (const SBListener &rhs);
+
+ ~SBListener ();
+
+ const lldb::SBListener &
+ operator = (const lldb::SBListener &rhs);
+
+ void
+ AddEvent (const lldb::SBEvent &event);
+
+ void
+ Clear ();
+
+ bool
+ IsValid () const;
+
+ uint32_t
+ StartListeningForEventClass (SBDebugger &debugger,
+ const char *broadcaster_class,
+ uint32_t event_mask);
+
+ bool
+ StopListeningForEventClass (SBDebugger &debugger,
+ const char *broadcaster_class,
+ uint32_t event_mask);
+
+ uint32_t
+ StartListeningForEvents (const lldb::SBBroadcaster& broadcaster,
+ uint32_t event_mask);
+
+ bool
+ StopListeningForEvents (const lldb::SBBroadcaster& broadcaster,
+ uint32_t event_mask);
+
+ // Returns true if an event was recieved, false if we timed out.
+ bool
+ WaitForEvent (uint32_t num_seconds,
+ lldb::SBEvent &event);
+
+ bool
+ WaitForEventForBroadcaster (uint32_t num_seconds,
+ const lldb::SBBroadcaster &broadcaster,
+ lldb::SBEvent &sb_event);
+
+ bool
+ WaitForEventForBroadcasterWithType (uint32_t num_seconds,
+ const lldb::SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ lldb::SBEvent &sb_event);
+
+ bool
+ PeekAtNextEvent (lldb::SBEvent &sb_event);
+
+ bool
+ PeekAtNextEventForBroadcaster (const lldb::SBBroadcaster &broadcaster,
+ lldb::SBEvent &sb_event);
+
+ bool
+ PeekAtNextEventForBroadcasterWithType (const lldb::SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ lldb::SBEvent &sb_event);
+
+ bool
+ GetNextEvent (lldb::SBEvent &sb_event);
+
+ bool
+ GetNextEventForBroadcaster (const lldb::SBBroadcaster &broadcaster,
+ lldb::SBEvent &sb_event);
+
+ bool
+ GetNextEventForBroadcasterWithType (const lldb::SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ lldb::SBEvent &sb_event);
+
+ bool
+ HandleBroadcastEvent (const lldb::SBEvent &event);
+
+protected:
+ friend class SBBroadcaster;
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+ friend class SBTarget;
+
+ SBListener (lldb_private::Listener &listener);
+
+private:
+
+ lldb_private::Listener *
+ operator->() const;
+
+ lldb_private::Listener *
+ get() const;
+
+ lldb_private::Listener &
+ ref() const;
+
+ lldb_private::Listener &
+ operator *();
+
+ const lldb_private::Listener &
+ operator *() const;
+
+ void
+ reset(lldb_private::Listener *listener, bool transfer_ownership);
+
+ lldb::ListenerSP m_opaque_sp;
+ lldb_private::Listener *m_opaque_ptr;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBListener_h_
diff --git a/include/lldb/API/SBModule.h b/include/lldb/API/SBModule.h
new file mode 100644
index 000000000000..a3c4879aa2f9
--- /dev/null
+++ b/include/lldb/API/SBModule.h
@@ -0,0 +1,287 @@
+//===-- SBModule.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBModule_h_
+#define LLDB_SBModule_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBSection.h"
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBValueList.h"
+
+namespace lldb {
+
+class SBModule
+{
+public:
+
+ SBModule ();
+
+ SBModule (const SBModule &rhs);
+
+ SBModule (const SBModuleSpec &module_spec);
+
+ const SBModule &
+ operator = (const SBModule &rhs);
+
+ SBModule (lldb::SBProcess &process,
+ lldb::addr_t header_addr);
+
+ ~SBModule ();
+
+ bool
+ IsValid () const;
+
+ void
+ Clear();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module file specification.
+ ///
+ /// This function returns the file for the module on the host system
+ /// that is running LLDB. This can differ from the path on the
+ /// platform since we might be doing remote debugging.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ lldb::SBFileSpec
+ GetFileSpec () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the module platform file specification.
+ ///
+ /// Platform file refers to the path of the module as it is known on
+ /// the remote system on which it is being debugged. For local
+ /// debugging this is always the same as Module::GetFileSpec(). But
+ /// remote debugging might mention a file '/usr/lib/liba.dylib'
+ /// which might be locally downloaded and cached. In this case the
+ /// platform file could be something like:
+ /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib'
+ /// The file could also be cached in a local developer kit directory.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ lldb::SBFileSpec
+ GetPlatformFileSpec () const;
+
+ bool
+ SetPlatformFileSpec (const lldb::SBFileSpec &platform_file);
+
+ lldb::ByteOrder
+ GetByteOrder ();
+
+ uint32_t
+ GetAddressByteSize();
+
+ const char *
+ GetTriple ();
+
+ const uint8_t *
+ GetUUIDBytes () const;
+
+ const char *
+ GetUUIDString () const;
+
+ bool
+ operator == (const lldb::SBModule &rhs) const;
+
+ bool
+ operator != (const lldb::SBModule &rhs) const;
+
+ lldb::SBSection
+ FindSection (const char *sect_name);
+
+ lldb::SBAddress
+ ResolveFileAddress (lldb::addr_t vm_addr);
+
+ lldb::SBSymbolContext
+ ResolveSymbolContextForAddress (const lldb::SBAddress& addr,
+ uint32_t resolve_scope);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ uint32_t
+ GetNumCompileUnits();
+
+ lldb::SBCompileUnit
+ GetCompileUnitAtIndex (uint32_t);
+
+ size_t
+ GetNumSymbols ();
+
+ lldb::SBSymbol
+ GetSymbolAtIndex (size_t idx);
+
+ lldb::SBSymbol
+ FindSymbol (const char *name,
+ lldb::SymbolType type = eSymbolTypeAny);
+
+ lldb::SBSymbolContextList
+ FindSymbols (const char *name,
+ lldb::SymbolType type = eSymbolTypeAny);
+
+ size_t
+ GetNumSections ();
+
+ lldb::SBSection
+ GetSectionAtIndex (size_t idx);
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// @param[in] name
+ /// The name of the function we are looking for.
+ ///
+ /// @param[in] name_type_mask
+ /// A logical OR of one or more FunctionNameType enum bits that
+ /// indicate what kind of names should be used when doing the
+ /// lookup. Bits include fully qualified names, base names,
+ /// C++ methods, or ObjC selectors.
+ /// See FunctionNameType for more details.
+ ///
+ /// @return
+ /// A lldb::SBSymbolContextList that gets filled in with all of
+ /// the symbol contexts for all the matches.
+ //------------------------------------------------------------------
+ lldb::SBSymbolContextList
+ FindFunctions (const char *name,
+ uint32_t name_type_mask = lldb::eFunctionNameTypeAny);
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by name.
+ ///
+ /// @param[in] target
+ /// A valid SBTarget instance representing the debuggee.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a max_matches.
+ ///
+ /// @return
+ /// A list of matched variables in an SBValueList.
+ //------------------------------------------------------------------
+ lldb::SBValueList
+ FindGlobalVariables (lldb::SBTarget &target,
+ const char *name,
+ uint32_t max_matches);
+
+ //------------------------------------------------------------------
+ /// Find the first global (or static) variable by name.
+ ///
+ /// @param[in] target
+ /// A valid SBTarget instance representing the debuggee.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @return
+ /// An SBValue that gets filled in with the found variable (if any).
+ //------------------------------------------------------------------
+ lldb::SBValue
+ FindFirstGlobalVariable (lldb::SBTarget &target, const char *name);
+
+ lldb::SBType
+ FindFirstType (const char* name);
+
+ lldb::SBTypeList
+ FindTypes (const char* type);
+
+ lldb::SBType
+ GetBasicType(lldb::BasicType type);
+
+ //------------------------------------------------------------------
+ /// Get all types matching \a type_mask from debug info in this
+ /// module.
+ ///
+ /// @param[in] type_mask
+ /// A bitfield that consists of one or more bits logically OR'ed
+ /// together from the lldb::TypeClass enumeration. This allows
+ /// you to request only structure types, or only class, struct
+ /// and union types. Passing in lldb::eTypeClassAny will return
+ /// all types found in the debug information for this module.
+ ///
+ /// @return
+ /// A list of types in this module that match \a type_mask
+ //------------------------------------------------------------------
+ lldb::SBTypeList
+ GetTypes (uint32_t type_mask = lldb::eTypeClassAny);
+
+ //------------------------------------------------------------------
+ /// Get the module version numbers.
+ ///
+ /// Many object files have a set of version numbers that describe
+ /// the version of the executable or shared library. Typically there
+ /// are major, minor and build, but there may be more. This function
+ /// will extract the versions from object files if they are available.
+ ///
+ /// If \a versions is NULL, or if \a num_versions is 0, the return
+ /// value will indicate how many version numbers are available in
+ /// this object file. Then a subsequent call can be made to this
+ /// function with a value of \a versions and \a num_versions that
+ /// has enough storage to store some or all version numbers.
+ ///
+ /// @param[out] versions
+ /// A pointer to an array of uint32_t types that is \a num_versions
+ /// long. If this value is NULL, the return value will indicate
+ /// how many version numbers are required for a subsequent call
+ /// to this function so that all versions can be retrieved. If
+ /// the value is non-NULL, then at most \a num_versions of the
+ /// existing versions numbers will be filled into \a versions.
+ /// If there is no version information available, \a versions
+ /// will be filled with \a num_versions UINT32_MAX values
+ /// and zero will be returned.
+ ///
+ /// @param[in] num_versions
+ /// The maximum number of entries to fill into \a versions. If
+ /// this value is zero, then the return value will indicate
+ /// how many version numbers there are in total so another call
+ /// to this function can be make with adequate storage in
+ /// \a versions to get all of the version numbers. If \a
+ /// num_versions is less than the actual number of version
+ /// numbers in this object file, only \a num_versions will be
+ /// filled into \a versions (if \a versions is non-NULL).
+ ///
+ /// @return
+ /// This function always returns the number of version numbers
+ /// that this object file has regardless of the number of
+ /// version numbers that were copied into \a versions.
+ //------------------------------------------------------------------
+ uint32_t
+ GetVersion (uint32_t *versions,
+ uint32_t num_versions);
+
+private:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBSection;
+ friend class SBSymbolContext;
+ friend class SBTarget;
+
+ explicit SBModule (const lldb::ModuleSP& module_sp);
+
+ ModuleSP
+ GetSP () const;
+
+ void
+ SetSP (const ModuleSP &module_sp);
+
+ lldb::ModuleSP m_opaque_sp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBModule_h_
diff --git a/include/lldb/API/SBModuleSpec.h b/include/lldb/API/SBModuleSpec.h
new file mode 100644
index 000000000000..a615e017cbc8
--- /dev/null
+++ b/include/lldb/API/SBModuleSpec.h
@@ -0,0 +1,154 @@
+//===-- SBModuleSpec.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBModuleSpec_h_
+#define LLDB_SBModuleSpec_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBFileSpec.h"
+
+namespace lldb {
+
+class SBModuleSpec
+{
+public:
+
+ SBModuleSpec ();
+
+ SBModuleSpec (const SBModuleSpec &rhs);
+
+ ~SBModuleSpec ();
+
+ const SBModuleSpec &
+ operator = (const SBModuleSpec &rhs);
+
+ bool
+ IsValid () const;
+
+ void
+ Clear();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module file.
+ ///
+ /// This function returns the file for the module on the host system
+ /// that is running LLDB. This can differ from the path on the
+ /// platform since we might be doing remote debugging.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ lldb::SBFileSpec
+ GetFileSpec ();
+
+ void
+ SetFileSpec (const lldb::SBFileSpec &fspec);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the module platform file.
+ ///
+ /// Platform file refers to the path of the module as it is known on
+ /// the remote system on which it is being debugged. For local
+ /// debugging this is always the same as Module::GetFileSpec(). But
+ /// remote debugging might mention a file '/usr/lib/liba.dylib'
+ /// which might be locally downloaded and cached. In this case the
+ /// platform file could be something like:
+ /// '/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib'
+ /// The file could also be cached in a local developer kit directory.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ lldb::SBFileSpec
+ GetPlatformFileSpec ();
+
+ void
+ SetPlatformFileSpec (const lldb::SBFileSpec &fspec);
+
+ lldb::SBFileSpec
+ GetSymbolFileSpec ();
+
+ void
+ SetSymbolFileSpec (const lldb::SBFileSpec &fspec);
+
+ const char *
+ GetObjectName ();
+
+ void
+ SetObjectName (const char *name);
+
+ const char *
+ GetTriple ();
+
+ void
+ SetTriple (const char *triple);
+
+ const uint8_t *
+ GetUUIDBytes ();
+
+ size_t
+ GetUUIDLength ();
+
+ bool
+ SetUUIDBytes (const uint8_t *uuid, size_t uuid_len);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+private:
+ friend class SBModuleSpecList;
+ friend class SBModule;
+ friend class SBTarget;
+
+ std::unique_ptr<lldb_private::ModuleSpec> m_opaque_ap;
+};
+
+class SBModuleSpecList
+{
+public:
+ SBModuleSpecList();
+
+ SBModuleSpecList (const SBModuleSpecList &rhs);
+
+ ~SBModuleSpecList();
+
+ SBModuleSpecList &
+ operator = (const SBModuleSpecList &rhs);
+
+ static SBModuleSpecList
+ GetModuleSpecifications (const char *path);
+
+ void
+ Append (const SBModuleSpec &spec);
+
+ void
+ Append (const SBModuleSpecList &spec_list);
+
+ SBModuleSpec
+ FindFirstMatchingSpec (const SBModuleSpec &match_spec);
+
+ SBModuleSpecList
+ FindMatchingSpecs (const SBModuleSpec &match_spec);
+
+ size_t
+ GetSize();
+
+ SBModuleSpec
+ GetSpecAtIndex (size_t i);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+private:
+ std::unique_ptr<lldb_private::ModuleSpecList> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBModuleSpec_h_
diff --git a/include/lldb/API/SBProcess.h b/include/lldb/API/SBProcess.h
new file mode 100644
index 000000000000..784f362122a9
--- /dev/null
+++ b/include/lldb/API/SBProcess.h
@@ -0,0 +1,295 @@
+//===-- SBProcess.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBProcess_h_
+#define LLDB_SBProcess_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBTarget.h"
+#include <stdio.h>
+
+namespace lldb {
+
+class SBEvent;
+
+class SBProcess
+{
+public:
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitStateChanged = (1 << 0),
+ eBroadcastBitInterrupt = (1 << 1),
+ eBroadcastBitSTDOUT = (1 << 2),
+ eBroadcastBitSTDERR = (1 << 3),
+ eBroadcastBitProfileData = (1 << 4)
+ };
+
+ SBProcess ();
+
+ SBProcess (const lldb::SBProcess& rhs);
+
+ const lldb::SBProcess&
+ operator = (const lldb::SBProcess& rhs);
+
+ SBProcess (const lldb::ProcessSP &process_sp);
+
+ ~SBProcess();
+
+ static const char *
+ GetBroadcasterClassName ();
+
+ const char *
+ GetPluginName ();
+
+ // DEPRECATED: use GetPluginName()
+ const char *
+ GetShortPluginName ();
+
+ void
+ Clear ();
+
+ bool
+ IsValid() const;
+
+ lldb::SBTarget
+ GetTarget() const;
+
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ size_t
+ PutSTDIN (const char *src, size_t src_len);
+
+ size_t
+ GetSTDOUT (char *dst, size_t dst_len) const;
+
+ size_t
+ GetSTDERR (char *dst, size_t dst_len) const;
+
+ size_t
+ GetAsyncProfileData(char *dst, size_t dst_len) const;
+
+ void
+ ReportEventState (const lldb::SBEvent &event, FILE *out) const;
+
+ void
+ AppendEventStateReport (const lldb::SBEvent &event, lldb::SBCommandReturnObject &result);
+
+ //------------------------------------------------------------------
+ /// Remote connection related functions. These will fail if the
+ /// process is not in eStateConnected. They are intended for use
+ /// when connecting to an externally managed debugserver instance.
+ //------------------------------------------------------------------
+ bool
+ RemoteAttachToProcessWithID (lldb::pid_t pid,
+ lldb::SBError& error);
+
+ bool
+ RemoteLaunch (char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_directory,
+ uint32_t launch_flags,
+ bool stop_at_entry,
+ lldb::SBError& error);
+
+ //------------------------------------------------------------------
+ // Thread related functions
+ //------------------------------------------------------------------
+ uint32_t
+ GetNumThreads ();
+
+ lldb::SBThread
+ GetThreadAtIndex (size_t index);
+
+ lldb::SBThread
+ GetThreadByID (lldb::tid_t sb_thread_id);
+
+ lldb::SBThread
+ GetThreadByIndexID (uint32_t index_id);
+
+ lldb::SBThread
+ GetSelectedThread () const;
+
+ //------------------------------------------------------------------
+ // Function for lazily creating a thread using the current OS
+ // plug-in. This function will be removed in the future when there
+ // are APIs to create SBThread objects through the interface and add
+ // them to the process through the SBProcess API.
+ //------------------------------------------------------------------
+ lldb::SBThread
+ CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context);
+
+ bool
+ SetSelectedThread (const lldb::SBThread &thread);
+
+ bool
+ SetSelectedThreadByID (lldb::tid_t tid);
+
+ bool
+ SetSelectedThreadByIndexID (uint32_t index_id);
+
+ //------------------------------------------------------------------
+ // Stepping related functions
+ //------------------------------------------------------------------
+
+ lldb::StateType
+ GetState ();
+
+ int
+ GetExitStatus ();
+
+ const char *
+ GetExitDescription ();
+
+ //------------------------------------------------------------------
+ /// Gets the process ID
+ ///
+ /// Returns the process identifier for the process as it is known
+ /// on the system on which the process is running. For unix systems
+ /// this is typically the same as if you called "getpid()" in the
+ /// process.
+ ///
+ /// @return
+ /// Returns LLDB_INVALID_PROCESS_ID if this object does not
+ /// contain a valid process object, or if the process has not
+ /// been launched. Returns a valid process ID if the process is
+ /// valid.
+ //------------------------------------------------------------------
+ lldb::pid_t
+ GetProcessID ();
+
+ //------------------------------------------------------------------
+ /// Gets the unique ID associated with this process object
+ ///
+ /// Unique IDs start at 1 and increment up with each new process
+ /// instance. Since starting a process on a system might always
+ /// create a process with the same process ID, there needs to be a
+ /// way to tell two process instances apart.
+ ///
+ /// @return
+ /// Returns a non-zero integer ID if this object contains a
+ /// valid process object, zero if this object does not contain
+ /// a valid process object.
+ //------------------------------------------------------------------
+ uint32_t
+ GetUniqueID();
+
+ uint32_t
+ GetAddressByteSize() const;
+
+ lldb::SBError
+ Destroy ();
+
+ lldb::SBError
+ Continue ();
+
+ lldb::SBError
+ Stop ();
+
+ lldb::SBError
+ Kill ();
+
+ lldb::SBError
+ Detach ();
+
+ lldb::SBError
+ Detach (bool keep_stopped);
+
+ lldb::SBError
+ Signal (int signal);
+
+ void
+ SendAsyncInterrupt();
+
+ uint32_t
+ GetStopID(bool include_expression_stops = false);
+
+ size_t
+ ReadMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error);
+
+ size_t
+ WriteMemory (addr_t addr, const void *buf, size_t size, lldb::SBError &error);
+
+ size_t
+ ReadCStringFromMemory (addr_t addr, void *buf, size_t size, lldb::SBError &error);
+
+ uint64_t
+ ReadUnsignedFromMemory (addr_t addr, uint32_t byte_size, lldb::SBError &error);
+
+ lldb::addr_t
+ ReadPointerFromMemory (addr_t addr, lldb::SBError &error);
+
+ // Events
+ static lldb::StateType
+ GetStateFromEvent (const lldb::SBEvent &event);
+
+ static bool
+ GetRestartedFromEvent (const lldb::SBEvent &event);
+
+ static size_t
+ GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event);
+
+ static const char *
+ GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx);
+
+ static lldb::SBProcess
+ GetProcessFromEvent (const lldb::SBEvent &event);
+
+ static bool
+ EventIsProcessEvent (const lldb::SBEvent &event);
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+ static const char *
+ GetBroadcasterClass ();
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ uint32_t
+ GetNumSupportedHardwareWatchpoints (lldb::SBError &error) const;
+
+ uint32_t
+ LoadImage (lldb::SBFileSpec &image_spec, lldb::SBError &error);
+
+ lldb::SBError
+ UnloadImage (uint32_t image_token);
+
+protected:
+ friend class SBAddress;
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+ friend class SBFunction;
+ friend class SBModule;
+ friend class SBTarget;
+ friend class SBThread;
+ friend class SBValue;
+
+ lldb::ProcessSP
+ GetSP() const;
+
+ void
+ SetSP (const lldb::ProcessSP &process_sp);
+
+ lldb::ProcessWP m_opaque_wp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBProcess_h_
diff --git a/include/lldb/API/SBSection.h b/include/lldb/API/SBSection.h
new file mode 100644
index 000000000000..3386484f6496
--- /dev/null
+++ b/include/lldb/API/SBSection.h
@@ -0,0 +1,104 @@
+//===-- SBSection.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBSection_h_
+#define LLDB_SBSection_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBData.h"
+
+namespace lldb {
+
+class SBSection
+{
+public:
+
+ SBSection ();
+
+ SBSection (const lldb::SBSection &rhs);
+
+ ~SBSection ();
+
+ const lldb::SBSection &
+ operator = (const lldb::SBSection &rhs);
+
+ bool
+ IsValid () const;
+
+ const char *
+ GetName ();
+
+ lldb::SBSection
+ GetParent();
+
+ lldb::SBSection
+ FindSubSection (const char *sect_name);
+
+ size_t
+ GetNumSubSections ();
+
+ lldb::SBSection
+ GetSubSectionAtIndex (size_t idx);
+
+ lldb::addr_t
+ GetFileAddress ();
+
+ lldb::addr_t
+ GetLoadAddress (lldb::SBTarget &target);
+
+ lldb::addr_t
+ GetByteSize ();
+
+ uint64_t
+ GetFileOffset ();
+
+ uint64_t
+ GetFileByteSize ();
+
+ lldb::SBData
+ GetSectionData ();
+
+ lldb::SBData
+ GetSectionData (uint64_t offset,
+ uint64_t size);
+
+ SectionType
+ GetSectionType ();
+
+ bool
+ operator == (const lldb::SBSection &rhs);
+
+ bool
+ operator != (const lldb::SBSection &rhs);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+
+private:
+
+ friend class SBAddress;
+ friend class SBModule;
+ friend class SBTarget;
+
+ SBSection (const lldb::SectionSP &section_sp);
+
+ lldb::SectionSP
+ GetSP() const;
+
+ void
+ SetSP(const lldb::SectionSP &section_sp);
+
+ lldb::SectionWP m_opaque_wp;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSection_h_
diff --git a/include/lldb/API/SBSourceManager.h b/include/lldb/API/SBSourceManager.h
new file mode 100644
index 000000000000..5b52c49ff3ee
--- /dev/null
+++ b/include/lldb/API/SBSourceManager.h
@@ -0,0 +1,53 @@
+//===-- SBSourceManager.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBSourceManager_h_
+#define LLDB_SBSourceManager_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <stdio.h>
+
+namespace lldb {
+
+class SBSourceManager
+{
+public:
+ SBSourceManager (const SBDebugger &debugger);
+ SBSourceManager (const SBTarget &target);
+ SBSourceManager (const SBSourceManager &rhs);
+
+ ~SBSourceManager();
+
+ const lldb::SBSourceManager &
+ operator = (const lldb::SBSourceManager &rhs);
+
+ size_t
+ DisplaySourceLinesWithLineNumbers (const lldb::SBFileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ lldb::SBStream &s);
+
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+
+ SBSourceManager(lldb_private::SourceManager *source_manager);
+
+private:
+
+ std::unique_ptr<lldb_private::SourceManagerImpl> m_opaque_ap;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBSourceManager_h_
diff --git a/include/lldb/API/SBStream.h b/include/lldb/API/SBStream.h
new file mode 100644
index 000000000000..038adf68542c
--- /dev/null
+++ b/include/lldb/API/SBStream.h
@@ -0,0 +1,111 @@
+//===-- SBStream.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBStream_h_
+#define LLDB_SBStream_h_
+
+#include <stdio.h>
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBStream
+{
+public:
+
+ SBStream ();
+
+ ~SBStream ();
+
+ bool
+ IsValid() const;
+
+ // If this stream is not redirected to a file, it will maintain a local
+ // cache for the stream data which can be accessed using this accessor.
+ const char *
+ GetData ();
+
+ // If this stream is not redirected to a file, it will maintain a local
+ // cache for the stream output whose length can be accessed using this
+ // accessor.
+ size_t
+ GetSize();
+
+ void
+ Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ RedirectToFile (const char *path, bool append);
+
+ void
+ RedirectToFileHandle (FILE *fh, bool transfer_fh_ownership);
+
+ void
+ RedirectToFileDescriptor (int fd, bool transfer_fh_ownership);
+
+ // If the stream is redirected to a file, forget about the file and if
+ // ownership of the file was transfered to this object, close the file.
+ // If the stream is backed by a local cache, clear this cache.
+ void
+ Clear ();
+
+protected:
+ friend class SBAddress;
+ friend class SBBlock;
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBCommandReturnObject;
+ friend class SBCompileUnit;
+ friend class SBData;
+ friend class SBDebugger;
+ friend class SBDeclaration;
+ friend class SBEvent;
+ friend class SBFileSpec;
+ friend class SBFileSpecList;
+ friend class SBFrame;
+ friend class SBFunction;
+ friend class SBInstruction;
+ friend class SBInstructionList;
+ friend class SBLineEntry;
+ friend class SBModule;
+ friend class SBModuleSpec;
+ friend class SBModuleSpecList;
+ friend class SBProcess;
+ friend class SBSection;
+ friend class SBSourceManager;
+ friend class SBSymbol;
+ friend class SBSymbolContext;
+ friend class SBSymbolContextList;
+ friend class SBTarget;
+ friend class SBThread;
+ friend class SBType;
+ friend class SBTypeMember;
+ friend class SBValue;
+ friend class SBWatchpoint;
+
+ lldb_private::Stream *
+ operator->();
+
+ lldb_private::Stream *
+ get();
+
+ lldb_private::Stream &
+ ref();
+
+private:
+
+ DISALLOW_COPY_AND_ASSIGN (SBStream);
+ std::unique_ptr<lldb_private::Stream> m_opaque_ap;
+ bool m_is_file;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBStream_h_
diff --git a/include/lldb/API/SBStringList.h b/include/lldb/API/SBStringList.h
new file mode 100644
index 000000000000..9d0be6e8a741
--- /dev/null
+++ b/include/lldb/API/SBStringList.h
@@ -0,0 +1,71 @@
+//===-- SBStringList.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBStringList_h_
+#define LLDB_SBStringList_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBStringList
+{
+public:
+
+ SBStringList ();
+
+ SBStringList (const lldb::SBStringList &rhs);
+
+ const SBStringList &
+ operator = (const SBStringList &rhs);
+
+ ~SBStringList ();
+
+ bool
+ IsValid() const;
+
+ void
+ AppendString (const char *str);
+
+ void
+ AppendList (const char **strv, int strc);
+
+ void
+ AppendList (const lldb::SBStringList &strings);
+
+ uint32_t
+ GetSize () const;
+
+ const char *
+ GetStringAtIndex (size_t idx);
+
+ void
+ Clear ();
+
+protected:
+ friend class SBCommandInterpreter;
+ friend class SBDebugger;
+
+ SBStringList (const lldb_private::StringList *lldb_strings);
+
+ const lldb_private::StringList *
+ operator->() const;
+
+ const lldb_private::StringList &
+ operator*() const;
+
+private:
+
+ std::unique_ptr<lldb_private::StringList> m_opaque_ap;
+
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBStringList_h_
diff --git a/include/lldb/API/SBSymbol.h b/include/lldb/API/SBSymbol.h
new file mode 100644
index 000000000000..0a528a9ac96f
--- /dev/null
+++ b/include/lldb/API/SBSymbol.h
@@ -0,0 +1,109 @@
+//===-- SBSymbol.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBSymbol_h_
+#define LLDB_SBSymbol_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBInstructionList.h"
+#include "lldb/API/SBTarget.h"
+
+namespace lldb {
+
+class SBSymbol
+{
+public:
+
+ SBSymbol ();
+
+ ~SBSymbol ();
+
+ SBSymbol (const lldb::SBSymbol &rhs);
+
+ const lldb::SBSymbol &
+ operator = (const lldb::SBSymbol &rhs);
+
+ bool
+ IsValid () const;
+
+
+ const char *
+ GetName() const;
+
+ const char *
+ GetMangledName () const;
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::SBTarget target);
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::SBTarget target, const char *flavor_string);
+
+ SBAddress
+ GetStartAddress ();
+
+ SBAddress
+ GetEndAddress ();
+
+ uint32_t
+ GetPrologueByteSize ();
+
+ SymbolType
+ GetType ();
+
+ bool
+ operator == (const lldb::SBSymbol &rhs) const;
+
+ bool
+ operator != (const lldb::SBSymbol &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ //----------------------------------------------------------------------
+ // Returns true if the symbol is externally visible in the module that
+ // it is defined in
+ //----------------------------------------------------------------------
+ bool
+ IsExternal();
+
+ //----------------------------------------------------------------------
+ // Returns true if the symbol was synthetically generated from something
+ // other than the actual symbol table itself in the object file.
+ //----------------------------------------------------------------------
+ bool
+ IsSynthetic();
+
+protected:
+
+ lldb_private::Symbol *
+ get ();
+
+ void
+ reset (lldb_private::Symbol *);
+
+private:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBModule;
+ friend class SBSymbolContext;
+
+ SBSymbol (lldb_private::Symbol *lldb_object_ptr);
+
+ void
+ SetSymbol (lldb_private::Symbol *lldb_object_ptr);
+
+ lldb_private::Symbol *m_opaque_ptr;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSymbol_h_
diff --git a/include/lldb/API/SBSymbolContext.h b/include/lldb/API/SBSymbolContext.h
new file mode 100644
index 000000000000..fee2d19179d0
--- /dev/null
+++ b/include/lldb/API/SBSymbolContext.h
@@ -0,0 +1,94 @@
+//===-- SBSymbolContext.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBSymbolContext_h_
+#define LLDB_SBSymbolContext_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBBlock.h"
+#include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBFunction.h"
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBModule.h"
+#include "lldb/API/SBSymbol.h"
+
+namespace lldb {
+
+class SBSymbolContext
+{
+public:
+ SBSymbolContext ();
+
+ SBSymbolContext (const lldb::SBSymbolContext& rhs);
+
+ ~SBSymbolContext ();
+
+ bool
+ IsValid () const;
+
+ const lldb::SBSymbolContext &
+ operator = (const lldb::SBSymbolContext &rhs);
+
+ lldb::SBModule GetModule ();
+ lldb::SBCompileUnit GetCompileUnit ();
+ lldb::SBFunction GetFunction ();
+ lldb::SBBlock GetBlock ();
+ lldb::SBLineEntry GetLineEntry ();
+ lldb::SBSymbol GetSymbol ();
+
+ void SetModule (lldb::SBModule module);
+ void SetCompileUnit (lldb::SBCompileUnit compile_unit);
+ void SetFunction (lldb::SBFunction function);
+ void SetBlock (lldb::SBBlock block);
+ void SetLineEntry (lldb::SBLineEntry line_entry);
+ void SetSymbol (lldb::SBSymbol symbol);
+
+ SBSymbolContext
+ GetParentOfInlinedScope (const SBAddress &curr_frame_pc,
+ SBAddress &parent_frame_addr) const;
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+protected:
+ friend class SBAddress;
+ friend class SBFrame;
+ friend class SBModule;
+ friend class SBThread;
+ friend class SBTarget;
+ friend class SBSymbolContextList;
+
+ lldb_private::SymbolContext*
+ operator->() const;
+
+ lldb_private::SymbolContext&
+ operator*();
+
+ lldb_private::SymbolContext&
+ ref();
+
+ const lldb_private::SymbolContext&
+ operator*() const;
+
+ lldb_private::SymbolContext *
+ get() const;
+
+ SBSymbolContext (const lldb_private::SymbolContext *sc_ptr);
+
+ void
+ SetSymbolContext (const lldb_private::SymbolContext *sc_ptr);
+
+private:
+ std::unique_ptr<lldb_private::SymbolContext> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSymbolContext_h_
diff --git a/include/lldb/API/SBSymbolContextList.h b/include/lldb/API/SBSymbolContextList.h
new file mode 100644
index 000000000000..6cc78e472c6f
--- /dev/null
+++ b/include/lldb/API/SBSymbolContextList.h
@@ -0,0 +1,69 @@
+//===-- SBSymbolContextList.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBSymbolContextList_h_
+#define LLDB_SBSymbolContextList_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBSymbolContext.h"
+
+namespace lldb {
+
+class SBSymbolContextList
+{
+public:
+ SBSymbolContextList ();
+
+ SBSymbolContextList (const lldb::SBSymbolContextList& rhs);
+
+ ~SBSymbolContextList ();
+
+ const lldb::SBSymbolContextList &
+ operator = (const lldb::SBSymbolContextList &rhs);
+
+ bool
+ IsValid () const;
+
+ uint32_t
+ GetSize() const;
+
+ lldb::SBSymbolContext
+ GetContextAtIndex (uint32_t idx);
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ void
+ Append (lldb::SBSymbolContext &sc);
+
+ void
+ Append (lldb::SBSymbolContextList &sc_list);
+
+ void
+ Clear();
+
+protected:
+
+ friend class SBModule;
+ friend class SBTarget;
+
+ lldb_private::SymbolContextList*
+ operator->() const;
+
+ lldb_private::SymbolContextList&
+ operator*() const;
+
+private:
+ std::unique_ptr<lldb_private::SymbolContextList> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBSymbolContextList_h_
diff --git a/include/lldb/API/SBTarget.h b/include/lldb/API/SBTarget.h
new file mode 100644
index 000000000000..15aeed4b600c
--- /dev/null
+++ b/include/lldb/API/SBTarget.h
@@ -0,0 +1,828 @@
+//===-- SBTarget.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTarget_h_
+#define LLDB_SBTarget_h_
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBFileSpecList.h"
+#include "lldb/API/SBSymbolContextList.h"
+#include "lldb/API/SBType.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/API/SBWatchpoint.h"
+
+namespace lldb {
+
+class SBLaunchInfo
+{
+public:
+ SBLaunchInfo (const char **argv);
+
+ ~SBLaunchInfo();
+
+ uint32_t
+ GetUserID();
+
+ uint32_t
+ GetGroupID();
+
+ bool
+ UserIDIsValid ();
+
+ bool
+ GroupIDIsValid ();
+
+ void
+ SetUserID (uint32_t uid);
+
+ void
+ SetGroupID (uint32_t gid);
+
+ uint32_t
+ GetNumArguments ();
+
+ const char *
+ GetArgumentAtIndex (uint32_t idx);
+
+ void
+ SetArguments (const char **argv, bool append);
+
+ uint32_t
+ GetNumEnvironmentEntries ();
+
+ const char *
+ GetEnvironmentEntryAtIndex (uint32_t idx);
+
+ void
+ SetEnvironmentEntries (const char **envp, bool append);
+
+ void
+ Clear ();
+
+ const char *
+ GetWorkingDirectory () const;
+
+ void
+ SetWorkingDirectory (const char *working_dir);
+
+ uint32_t
+ GetLaunchFlags ();
+
+ void
+ SetLaunchFlags (uint32_t flags);
+
+ const char *
+ GetProcessPluginName ();
+
+ void
+ SetProcessPluginName (const char *plugin_name);
+
+ const char *
+ GetShell ();
+
+ void
+ SetShell (const char * path);
+
+ uint32_t
+ GetResumeCount ();
+
+ void
+ SetResumeCount (uint32_t c);
+
+ bool
+ AddCloseFileAction (int fd);
+
+ bool
+ AddDuplicateFileAction (int fd, int dup_fd);
+
+ bool
+ AddOpenFileAction (int fd, const char *path, bool read, bool write);
+
+ bool
+ AddSuppressFileAction (int fd, bool read, bool write);
+
+protected:
+ friend class SBTarget;
+
+ lldb_private::ProcessLaunchInfo &
+ ref ();
+
+ ProcessLaunchInfoSP m_opaque_sp;
+};
+
+class SBAttachInfo
+{
+public:
+ SBAttachInfo ();
+
+ SBAttachInfo (lldb::pid_t pid);
+
+ SBAttachInfo (const char *path, bool wait_for);
+
+ SBAttachInfo (const SBAttachInfo &rhs);
+
+ ~SBAttachInfo();
+
+ SBAttachInfo &
+ operator = (const SBAttachInfo &rhs);
+
+ lldb::pid_t
+ GetProcessID ();
+
+ void
+ SetProcessID (lldb::pid_t pid);
+
+ void
+ SetExecutable (const char *path);
+
+ void
+ SetExecutable (lldb::SBFileSpec exe_file);
+
+ bool
+ GetWaitForLaunch ();
+
+ void
+ SetWaitForLaunch (bool b);
+
+ bool
+ GetIgnoreExisting ();
+
+ void
+ SetIgnoreExisting (bool b);
+
+ uint32_t
+ GetResumeCount ();
+
+ void
+ SetResumeCount (uint32_t c);
+
+ const char *
+ GetProcessPluginName ();
+
+ void
+ SetProcessPluginName (const char *plugin_name);
+
+ uint32_t
+ GetUserID();
+
+ uint32_t
+ GetGroupID();
+
+ bool
+ UserIDIsValid ();
+
+ bool
+ GroupIDIsValid ();
+
+ void
+ SetUserID (uint32_t uid);
+
+ void
+ SetGroupID (uint32_t gid);
+
+ uint32_t
+ GetEffectiveUserID();
+
+ uint32_t
+ GetEffectiveGroupID();
+
+ bool
+ EffectiveUserIDIsValid ();
+
+ bool
+ EffectiveGroupIDIsValid ();
+
+ void
+ SetEffectiveUserID (uint32_t uid);
+
+ void
+ SetEffectiveGroupID (uint32_t gid);
+
+ lldb::pid_t
+ GetParentProcessID ();
+
+ void
+ SetParentProcessID (lldb::pid_t pid);
+
+ bool
+ ParentProcessIDIsValid();
+
+
+protected:
+ friend class SBTarget;
+
+ lldb_private::ProcessAttachInfo &
+ ref ();
+
+ ProcessAttachInfoSP m_opaque_sp;
+};
+
+class SBTarget
+{
+public:
+ //------------------------------------------------------------------
+ // Broadcaster bits.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitBreakpointChanged = (1 << 0),
+ eBroadcastBitModulesLoaded = (1 << 1),
+ eBroadcastBitModulesUnloaded = (1 << 2),
+ eBroadcastBitWatchpointChanged = (1 << 3),
+ eBroadcastBitSymbolsLoaded = (1 << 4)
+ };
+
+ //------------------------------------------------------------------
+ // Constructors
+ //------------------------------------------------------------------
+ SBTarget ();
+
+ SBTarget (const lldb::SBTarget& rhs);
+
+ SBTarget (const lldb::TargetSP& target_sp);
+
+ const lldb::SBTarget&
+ operator = (const lldb::SBTarget& rhs);
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~SBTarget();
+
+ bool
+ IsValid() const;
+
+ static const char *
+ GetBroadcasterClassName ();
+
+ lldb::SBProcess
+ GetProcess ();
+
+ //------------------------------------------------------------------
+ /// Launch a new process.
+ ///
+ /// Launch a new process by spawning a new process using the
+ /// target object's executable module's file as the file to launch.
+ /// Arguments are given in \a argv, and the environment variables
+ /// are in \a envp. Standard input and output files can be
+ /// optionally re-directed to \a stdin_path, \a stdout_path, and
+ /// \a stderr_path.
+ ///
+ /// @param[in] listener
+ /// An optional listener that will receive all process events.
+ /// If \a listener is valid then \a listener will listen to all
+ /// process events. If not valid, then this target's debugger
+ /// (SBTarget::GetDebugger()) will listen to all process events.
+ ///
+ /// @param[in] argv
+ /// The argument array.
+ ///
+ /// @param[in] envp
+ /// The environment array.
+ ///
+ /// @param[in] launch_flags
+ /// Flags to modify the launch (@see lldb::LaunchFlags)
+ ///
+ /// @param[in] stdin_path
+ /// The path to use when re-directing the STDIN of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stdout_path
+ /// The path to use when re-directing the STDOUT of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stderr_path
+ /// The path to use when re-directing the STDERR of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] working_directory
+ /// The working directory to have the child process run in
+ ///
+ /// @param[in] launch_flags
+ /// Some launch options specified by logical OR'ing
+ /// lldb::LaunchFlags enumeration values together.
+ ///
+ /// @param[in] stop_at_endtry
+ /// If false do not stop the inferior at the entry point.
+ ///
+ /// @param[out]
+ /// An error object. Contains the reason if there is some failure.
+ ///
+ /// @return
+ /// A process object for the newly created process.
+ //------------------------------------------------------------------
+ lldb::SBProcess
+ Launch (SBListener &listener,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_directory,
+ uint32_t launch_flags, // See LaunchFlags
+ bool stop_at_entry,
+ lldb::SBError& error);
+
+
+ //------------------------------------------------------------------
+ /// Launch a new process with sensible defaults.
+ ///
+ /// @param[in] argv
+ /// The argument array.
+ ///
+ /// @param[in] envp
+ /// The environment array.
+ ///
+ /// @param[in] working_directory
+ /// The working directory to have the child process run in
+ ///
+ /// Default: listener
+ /// Set to the target's debugger (SBTarget::GetDebugger())
+ ///
+ /// Default: launch_flags
+ /// Empty launch flags
+ ///
+ /// Default: stdin_path
+ /// Default: stdout_path
+ /// Default: stderr_path
+ /// A pseudo terminal will be used.
+ ///
+ /// @return
+ /// A process object for the newly created process.
+ //------------------------------------------------------------------
+ SBProcess
+ LaunchSimple (const char **argv,
+ const char **envp,
+ const char *working_directory);
+
+ SBProcess
+ Launch (SBLaunchInfo &launch_info, SBError& error);
+
+ SBProcess
+ LoadCore (const char *core_file);
+
+ SBProcess
+ Attach (SBAttachInfo &attach_info, SBError& error);
+
+ //------------------------------------------------------------------
+ /// Attach to process with pid.
+ ///
+ /// @param[in] listener
+ /// An optional listener that will receive all process events.
+ /// If \a listener is valid then \a listener will listen to all
+ /// process events. If not valid, then this target's debugger
+ /// (SBTarget::GetDebugger()) will listen to all process events.
+ ///
+ /// @param[in] pid
+ /// The process ID to attach to.
+ ///
+ /// @param[out]
+ /// An error explaining what went wrong if attach fails.
+ ///
+ /// @return
+ /// A process object for the attached process.
+ //------------------------------------------------------------------
+ lldb::SBProcess
+ AttachToProcessWithID (SBListener &listener,
+ lldb::pid_t pid,
+ lldb::SBError& error);
+
+#if defined(__APPLE__)
+ // We need to keep this around for a build or two since Xcode links
+ // to the 32 bit version of this function. We will take it out soon.
+ lldb::SBProcess
+ AttachToProcessWithID (SBListener &listener,
+ ::pid_t pid, // 32 bit int process ID
+ lldb::SBError& error); // DEPRECATED
+#endif
+ //------------------------------------------------------------------
+ /// Attach to process with name.
+ ///
+ /// @param[in] listener
+ /// An optional listener that will receive all process events.
+ /// If \a listener is valid then \a listener will listen to all
+ /// process events. If not valid, then this target's debugger
+ /// (SBTarget::GetDebugger()) will listen to all process events.
+ ///
+ /// @param[in] name
+ /// Basename of process to attach to.
+ ///
+ /// @param[in] wait_for
+ /// If true wait for a new instance of 'name' to be launched.
+ ///
+ /// @param[out]
+ /// An error explaining what went wrong if attach fails.
+ ///
+ /// @return
+ /// A process object for the attached process.
+ //------------------------------------------------------------------
+ lldb::SBProcess
+ AttachToProcessWithName (SBListener &listener,
+ const char *name,
+ bool wait_for,
+ lldb::SBError& error);
+
+ //------------------------------------------------------------------
+ /// Connect to a remote debug server with url.
+ ///
+ /// @param[in] listener
+ /// An optional listener that will receive all process events.
+ /// If \a listener is valid then \a listener will listen to all
+ /// process events. If not valid, then this target's debugger
+ /// (SBTarget::GetDebugger()) will listen to all process events.
+ ///
+ /// @param[in] url
+ /// The url to connect to, e.g., 'connect://localhost:12345'.
+ ///
+ /// @param[in] plugin_name
+ /// The plugin name to be used; can be NULL.
+ ///
+ /// @param[out]
+ /// An error explaining what went wrong if the connect fails.
+ ///
+ /// @return
+ /// A process object for the connected process.
+ //------------------------------------------------------------------
+ lldb::SBProcess
+ ConnectRemote (SBListener &listener,
+ const char *url,
+ const char *plugin_name,
+ SBError& error);
+
+ lldb::SBFileSpec
+ GetExecutable ();
+
+ bool
+ AddModule (lldb::SBModule &module);
+
+ lldb::SBModule
+ AddModule (const char *path,
+ const char *triple,
+ const char *uuid);
+
+ lldb::SBModule
+ AddModule (const char *path,
+ const char *triple,
+ const char *uuid_cstr,
+ const char *symfile);
+
+ lldb::SBModule
+ AddModule (const SBModuleSpec &module_spec);
+
+ uint32_t
+ GetNumModules () const;
+
+ lldb::SBModule
+ GetModuleAtIndex (uint32_t idx);
+
+ bool
+ RemoveModule (lldb::SBModule module);
+
+ lldb::SBDebugger
+ GetDebugger() const;
+
+ lldb::SBModule
+ FindModule (const lldb::SBFileSpec &file_spec);
+
+ lldb::ByteOrder
+ GetByteOrder ();
+
+ uint32_t
+ GetAddressByteSize();
+
+ const char *
+ GetTriple ();
+
+ //------------------------------------------------------------------
+ /// Set the base load address for a module section.
+ ///
+ /// @param[in] section
+ /// The section whose base load address will be set within this
+ /// target.
+ ///
+ /// @param[in] section_base_addr
+ /// The base address for the section.
+ ///
+ /// @return
+ /// An error to indicate success, fail, and any reason for
+ /// failure.
+ //------------------------------------------------------------------
+ lldb::SBError
+ SetSectionLoadAddress (lldb::SBSection section,
+ lldb::addr_t section_base_addr);
+
+ //------------------------------------------------------------------
+ /// Clear the base load address for a module section.
+ ///
+ /// @param[in] section
+ /// The section whose base load address will be cleared within
+ /// this target.
+ ///
+ /// @return
+ /// An error to indicate success, fail, and any reason for
+ /// failure.
+ //------------------------------------------------------------------
+ lldb::SBError
+ ClearSectionLoadAddress (lldb::SBSection section);
+
+ //------------------------------------------------------------------
+ /// Slide all file addresses for all module sections so that \a module
+ /// appears to loaded at these slide addresses.
+ ///
+ /// When you need all sections within a module to be loaded at a
+ /// rigid slide from the addresses found in the module object file,
+ /// this function will allow you to easily and quickly slide all
+ /// module sections.
+ ///
+ /// @param[in] module
+ /// The module to load.
+ ///
+ /// @param[in] sections_offset
+ /// An offset that will be applied to all section file addresses
+ /// (the virtual addresses found in the object file itself).
+ ///
+ /// @return
+ /// An error to indicate success, fail, and any reason for
+ /// failure.
+ //------------------------------------------------------------------
+ lldb::SBError
+ SetModuleLoadAddress (lldb::SBModule module,
+ int64_t sections_offset);
+
+
+ //------------------------------------------------------------------
+ /// The the section base load addresses for all sections in a module.
+ ///
+ /// @param[in] module
+ /// The module to unload.
+ ///
+ /// @return
+ /// An error to indicate success, fail, and any reason for
+ /// failure.
+ //------------------------------------------------------------------
+ lldb::SBError
+ ClearModuleLoadAddress (lldb::SBModule module);
+
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// @param[in] name
+ /// The name of the function we are looking for.
+ ///
+ /// @param[in] name_type_mask
+ /// A logical OR of one or more FunctionNameType enum bits that
+ /// indicate what kind of names should be used when doing the
+ /// lookup. Bits include fully qualified names, base names,
+ /// C++ methods, or ObjC selectors.
+ /// See FunctionNameType for more details.
+ ///
+ /// @return
+ /// A lldb::SBSymbolContextList that gets filled in with all of
+ /// the symbol contexts for all the matches.
+ //------------------------------------------------------------------
+ lldb::SBSymbolContextList
+ FindFunctions (const char *name,
+ uint32_t name_type_mask = lldb::eFunctionNameTypeAny);
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by name.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a max_matches.
+ ///
+ /// @return
+ /// A list of matched variables in an SBValueList.
+ //------------------------------------------------------------------
+ lldb::SBValueList
+ FindGlobalVariables (const char *name,
+ uint32_t max_matches);
+
+ //------------------------------------------------------------------
+ /// Find the first global (or static) variable by name.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @return
+ /// An SBValue that gets filled in with the found variable (if any).
+ //------------------------------------------------------------------
+ lldb::SBValue
+ FindFirstGlobalVariable (const char* name);
+
+ void
+ Clear ();
+
+ lldb::SBAddress
+ ResolveLoadAddress (lldb::addr_t vm_addr);
+
+ SBSymbolContext
+ ResolveSymbolContextForAddress (const SBAddress& addr,
+ uint32_t resolve_scope);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByLocation (const char *file, uint32_t line);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByLocation (const lldb::SBFileSpec &file_spec, uint32_t line);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByName (const char *symbol_name, const char *module_name = NULL);
+
+ // This version uses name_type_mask = eFunctionNameTypeAuto
+ lldb::SBBreakpoint
+ BreakpointCreateByName (const char *symbol_name,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByName (const char *symbol_name,
+ uint32_t name_type_mask, // Logical OR one or more FunctionNameType enum bits
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByNames (const char *symbol_name[],
+ uint32_t num_names,
+ uint32_t name_type_mask, // Logical OR one or more FunctionNameType enum bits
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name = NULL);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByRegex (const char *symbol_name_regex,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list);
+
+ lldb::SBBreakpoint
+ BreakpointCreateBySourceRegex (const char *source_regex,
+ const lldb::SBFileSpec &source_file,
+ const char *module_name = NULL);
+
+ lldb::SBBreakpoint
+ BreakpointCreateBySourceRegex (const char *source_regex,
+ const SBFileSpecList &module_list,
+ const lldb::SBFileSpecList &source_file);
+
+ lldb::SBBreakpoint
+ BreakpointCreateForException (lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp);
+
+ lldb::SBBreakpoint
+ BreakpointCreateByAddress (addr_t address);
+
+ uint32_t
+ GetNumBreakpoints () const;
+
+ lldb::SBBreakpoint
+ GetBreakpointAtIndex (uint32_t idx) const;
+
+ bool
+ BreakpointDelete (break_id_t break_id);
+
+ lldb::SBBreakpoint
+ FindBreakpointByID (break_id_t break_id);
+
+ bool
+ EnableAllBreakpoints ();
+
+ bool
+ DisableAllBreakpoints ();
+
+ bool
+ DeleteAllBreakpoints ();
+
+ uint32_t
+ GetNumWatchpoints () const;
+
+ lldb::SBWatchpoint
+ GetWatchpointAtIndex (uint32_t idx) const;
+
+ bool
+ DeleteWatchpoint (lldb::watch_id_t watch_id);
+
+ lldb::SBWatchpoint
+ FindWatchpointByID (lldb::watch_id_t watch_id);
+
+ lldb::SBWatchpoint
+ WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, SBError& error);
+
+ bool
+ EnableAllWatchpoints ();
+
+ bool
+ DisableAllWatchpoints ();
+
+ bool
+ DeleteAllWatchpoints ();
+
+ lldb::SBBroadcaster
+ GetBroadcaster () const;
+
+ lldb::SBType
+ FindFirstType (const char* type);
+
+ lldb::SBTypeList
+ FindTypes (const char* type);
+
+ lldb::SBType
+ GetBasicType(lldb::BasicType type);
+
+ SBSourceManager
+ GetSourceManager();
+
+ lldb::SBInstructionList
+ ReadInstructions (lldb::SBAddress base_addr, uint32_t count);
+
+ lldb::SBInstructionList
+ ReadInstructions (lldb::SBAddress base_addr, uint32_t count, const char *flavor_string);
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size);
+
+ // The "WithFlavor" is necessary to keep SWIG from getting confused about overloaded arguments when
+ // using the buf + size -> Python Object magic.
+
+ lldb::SBInstructionList
+ GetInstructionsWithFlavor (lldb::SBAddress base_addr, const char *flavor_string, const void *buf, size_t size);
+
+ lldb::SBInstructionList
+ GetInstructions (lldb::addr_t base_addr, const void *buf, size_t size);
+
+ lldb::SBInstructionList
+ GetInstructionsWithFlavor (lldb::addr_t base_addr, const char *flavor_string, const void *buf, size_t size);
+
+ lldb::SBSymbolContextList
+ FindSymbols (const char *name,
+ lldb::SymbolType type = eSymbolTypeAny);
+
+ bool
+ operator == (const lldb::SBTarget &rhs) const;
+
+ bool
+ operator != (const lldb::SBTarget &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level);
+
+ lldb::SBValue
+ EvaluateExpression (const char *expr, const SBExpressionOptions &options);
+
+ lldb::addr_t
+ GetStackRedZoneSize();
+
+protected:
+ friend class SBAddress;
+ friend class SBBlock;
+ friend class SBDebugger;
+ friend class SBFunction;
+ friend class SBInstruction;
+ friend class SBModule;
+ friend class SBProcess;
+ friend class SBSection;
+ friend class SBSourceManager;
+ friend class SBSymbol;
+ friend class SBValue;
+
+ //------------------------------------------------------------------
+ // Constructors are private, use static Target::Create function to
+ // create an instance of this class.
+ //------------------------------------------------------------------
+
+ lldb::TargetSP
+ GetSP () const;
+
+ void
+ SetSP (const lldb::TargetSP& target_sp);
+
+
+private:
+ //------------------------------------------------------------------
+ // For Target only
+ //------------------------------------------------------------------
+
+ lldb::TargetSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBTarget_h_
diff --git a/include/lldb/API/SBThread.h b/include/lldb/API/SBThread.h
new file mode 100644
index 000000000000..9645f925035e
--- /dev/null
+++ b/include/lldb/API/SBThread.h
@@ -0,0 +1,220 @@
+//===-- SBThread.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBThread_h_
+#define LLDB_SBThread_h_
+
+#include "lldb/API/SBDefines.h"
+
+#include <stdio.h>
+
+namespace lldb {
+
+class SBFrame;
+
+class SBThread
+{
+public:
+ enum
+ {
+ eBroadcastBitStackChanged = (1 << 0),
+ eBroadcastBitThreadSuspended = (1 << 1),
+ eBroadcastBitThreadResumed = (1 << 2),
+ eBroadcastBitSelectedFrameChanged = (1 << 3),
+ eBroadcastBitThreadSelected = (1 << 4)
+ };
+
+ static const char *
+ GetBroadcasterClassName ();
+
+ SBThread ();
+
+ SBThread (const lldb::SBThread &thread);
+
+ SBThread (const lldb::ThreadSP& lldb_object_sp);
+
+ ~SBThread();
+
+ bool
+ IsValid() const;
+
+ void
+ Clear ();
+
+ lldb::StopReason
+ GetStopReason();
+
+ /// Get the number of words associated with the stop reason.
+ /// See also GetStopReasonDataAtIndex().
+ size_t
+ GetStopReasonDataCount();
+
+ //--------------------------------------------------------------------------
+ /// Get information associated with a stop reason.
+ ///
+ /// Breakpoint stop reasons will have data that consists of pairs of
+ /// breakpoint IDs followed by the breakpoint location IDs (they always come
+ /// in pairs).
+ ///
+ /// Stop Reason Count Data Type
+ /// ======================== ===== =========================================
+ /// eStopReasonNone 0
+ /// eStopReasonTrace 0
+ /// eStopReasonBreakpoint N duple: {breakpoint id, location id}
+ /// eStopReasonWatchpoint 1 watchpoint id
+ /// eStopReasonSignal 1 unix signal number
+ /// eStopReasonException N exception data
+ /// eStopReasonExec 0
+ /// eStopReasonPlanComplete 0
+ //--------------------------------------------------------------------------
+ uint64_t
+ GetStopReasonDataAtIndex(uint32_t idx);
+
+ size_t
+ GetStopDescription (char *dst, size_t dst_len);
+
+ SBValue
+ GetStopReturnValue ();
+
+ lldb::tid_t
+ GetThreadID () const;
+
+ uint32_t
+ GetIndexID () const;
+
+ const char *
+ GetName () const;
+
+ const char *
+ GetQueueName() const;
+
+ void
+ StepOver (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
+ StepInto (lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
+ StepInto (const char *target_name, lldb::RunMode stop_other_threads = lldb::eOnlyDuringStepping);
+
+ void
+ StepOut ();
+
+ void
+ StepOutOfFrame (lldb::SBFrame &frame);
+
+ void
+ StepInstruction(bool step_over);
+
+ SBError
+ StepOverUntil (lldb::SBFrame &frame,
+ lldb::SBFileSpec &file_spec,
+ uint32_t line);
+
+ void
+ RunToAddress (lldb::addr_t addr);
+
+ SBError
+ ReturnFromFrame (SBFrame &frame, SBValue &return_value);
+
+ //--------------------------------------------------------------------------
+ /// LLDB currently supports process centric debugging which means when any
+ /// thread in a process stops, all other threads are stopped. The Suspend()
+ /// call here tells our process to suspend a thread and not let it run when
+ /// the other threads in a process are allowed to run. So when
+ /// SBProcess::Continue() is called, any threads that aren't suspended will
+ /// be allowed to run. If any of the SBThread functions for stepping are
+ /// called (StepOver, StepInto, StepOut, StepInstruction, RunToAddres), the
+ /// thread will not be allowed to run and these funtions will simply return.
+ ///
+ /// Eventually we plan to add support for thread centric debugging where
+ /// each thread is controlled individually and each thread would broadcast
+ /// its state, but we haven't implemented this yet.
+ ///
+ /// Likewise the SBThread::Resume() call will again allow the thread to run
+ /// when the process is continued.
+ ///
+ /// Suspend() and Resume() functions are not currently reference counted, if
+ /// anyone has the need for them to be reference counted, please let us
+ /// know.
+ //--------------------------------------------------------------------------
+ bool
+ Suspend();
+
+ bool
+ Resume ();
+
+ bool
+ IsSuspended();
+
+ bool
+ IsStopped();
+
+ uint32_t
+ GetNumFrames ();
+
+ lldb::SBFrame
+ GetFrameAtIndex (uint32_t idx);
+
+ lldb::SBFrame
+ GetSelectedFrame ();
+
+ lldb::SBFrame
+ SetSelectedFrame (uint32_t frame_idx);
+
+ static bool
+ EventIsThreadEvent (const SBEvent &event);
+
+ static SBFrame
+ GetStackFrameFromEvent (const SBEvent &event);
+
+ static SBThread
+ GetThreadFromEvent (const SBEvent &event);
+
+ lldb::SBProcess
+ GetProcess ();
+
+ const lldb::SBThread &
+ operator = (const lldb::SBThread &rhs);
+
+ bool
+ operator == (const lldb::SBThread &rhs) const;
+
+ bool
+ operator != (const lldb::SBThread &rhs) const;
+
+ bool
+ GetDescription (lldb::SBStream &description) const;
+
+ bool
+ GetStatus (lldb::SBStream &status) const;
+
+protected:
+ friend class SBBreakpoint;
+ friend class SBBreakpointLocation;
+ friend class SBFrame;
+ friend class SBProcess;
+ friend class SBDebugger;
+ friend class SBValue;
+
+ void
+ SetThread (const lldb::ThreadSP& lldb_object_sp);
+
+#ifndef SWIG
+ SBError
+ ResumeNewPlan (lldb_private::ExecutionContext &exe_ctx, lldb_private::ThreadPlan *new_plan);
+#endif
+
+private:
+ lldb::ExecutionContextRefSP m_opaque_sp;
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBThread_h_
diff --git a/include/lldb/API/SBType.h b/include/lldb/API/SBType.h
new file mode 100644
index 000000000000..3729b2f84b90
--- /dev/null
+++ b/include/lldb/API/SBType.h
@@ -0,0 +1,244 @@
+//===-- SBType.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBType_h_
+#define LLDB_SBType_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBTypeList;
+
+class SBTypeMember
+{
+public:
+ SBTypeMember ();
+
+ SBTypeMember (const lldb::SBTypeMember& rhs);
+
+ ~SBTypeMember();
+
+ lldb::SBTypeMember&
+ operator = (const lldb::SBTypeMember& rhs);
+
+ bool
+ IsValid() const;
+
+ const char *
+ GetName ();
+
+ lldb::SBType
+ GetType ();
+
+ uint64_t
+ GetOffsetInBytes();
+
+ uint64_t
+ GetOffsetInBits();
+
+ bool
+ IsBitfield();
+
+ uint32_t
+ GetBitfieldSizeInBits();
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+protected:
+ friend class SBType;
+
+ void
+ reset (lldb_private::TypeMemberImpl *);
+
+ lldb_private::TypeMemberImpl &
+ ref ();
+
+ const lldb_private::TypeMemberImpl &
+ ref () const;
+
+ std::unique_ptr<lldb_private::TypeMemberImpl> m_opaque_ap;
+};
+
+class SBType
+{
+public:
+
+ SBType();
+
+ SBType (const lldb::SBType &rhs);
+
+ ~SBType ();
+
+ bool
+ IsValid() const;
+
+ uint64_t
+ GetByteSize();
+
+ bool
+ IsPointerType();
+
+ bool
+ IsReferenceType();
+
+ bool
+ IsFunctionType ();
+
+ bool
+ IsPolymorphicClass ();
+
+ lldb::SBType
+ GetPointerType();
+
+ lldb::SBType
+ GetPointeeType();
+
+ lldb::SBType
+ GetReferenceType();
+
+ lldb::SBType
+ GetDereferencedType();
+
+ lldb::SBType
+ GetUnqualifiedType();
+
+ lldb::SBType
+ GetCanonicalType();
+ // Get the "lldb::BasicType" enumeration for a type. If a type is not a basic
+ // type eBasicTypeInvalid will be returned
+ lldb::BasicType
+ GetBasicType();
+
+ // The call below confusing and should really be renamed to "CreateBasicType"
+ lldb::SBType
+ GetBasicType(lldb::BasicType type);
+
+ uint32_t
+ GetNumberOfFields ();
+
+ uint32_t
+ GetNumberOfDirectBaseClasses ();
+
+ uint32_t
+ GetNumberOfVirtualBaseClasses ();
+
+ lldb::SBTypeMember
+ GetFieldAtIndex (uint32_t idx);
+
+ lldb::SBTypeMember
+ GetDirectBaseClassAtIndex (uint32_t idx);
+
+ lldb::SBTypeMember
+ GetVirtualBaseClassAtIndex (uint32_t idx);
+
+ uint32_t
+ GetNumberOfTemplateArguments ();
+
+ lldb::SBType
+ GetTemplateArgumentType (uint32_t idx);
+
+ lldb::TemplateArgumentKind
+ GetTemplateArgumentKind (uint32_t idx);
+
+ lldb::SBType
+ GetFunctionReturnType ();
+
+ lldb::SBTypeList
+ GetFunctionArgumentTypes ();
+
+ const char*
+ GetName();
+
+ lldb::TypeClass
+ GetTypeClass ();
+
+ bool
+ IsTypeComplete ();
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBType &
+ operator = (const lldb::SBType &rhs);
+
+ bool
+ operator == (lldb::SBType &rhs);
+
+ bool
+ operator != (lldb::SBType &rhs);
+
+protected:
+
+ lldb_private::TypeImpl &
+ ref ();
+
+ const lldb_private::TypeImpl &
+ ref () const;
+
+ lldb::TypeImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeImplSP &type_impl_sp);
+
+ lldb::TypeImplSP m_opaque_sp;
+
+ friend class SBFunction;
+ friend class SBModule;
+ friend class SBTarget;
+ friend class SBTypeNameSpecifier;
+ friend class SBTypeMember;
+ friend class SBTypeList;
+ friend class SBValue;
+
+ SBType (const lldb_private::ClangASTType &);
+ SBType (const lldb::TypeSP &);
+ SBType (const lldb::TypeImplSP &);
+
+};
+
+class SBTypeList
+{
+public:
+ SBTypeList();
+
+ SBTypeList(const lldb::SBTypeList& rhs);
+
+ ~SBTypeList();
+
+ lldb::SBTypeList&
+ operator = (const lldb::SBTypeList& rhs);
+
+ bool
+ IsValid();
+
+ void
+ Append (lldb::SBType type);
+
+ lldb::SBType
+ GetTypeAtIndex (uint32_t index);
+
+ uint32_t
+ GetSize();
+
+
+private:
+ std::unique_ptr<lldb_private::TypeListImpl> m_opaque_ap;
+ friend class SBModule;
+ friend class SBCompileUnit;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBType_h_
diff --git a/include/lldb/API/SBTypeCategory.h b/include/lldb/API/SBTypeCategory.h
new file mode 100644
index 000000000000..f123e931e17d
--- /dev/null
+++ b/include/lldb/API/SBTypeCategory.h
@@ -0,0 +1,168 @@
+//===-- SBTypeCategory.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeCategory_h_
+#define LLDB_SBTypeCategory_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+ class SBTypeCategory
+ {
+ public:
+
+ SBTypeCategory();
+
+ SBTypeCategory (const lldb::SBTypeCategory &rhs);
+
+ ~SBTypeCategory ();
+
+ bool
+ IsValid() const;
+
+ bool
+ GetEnabled ();
+
+ void
+ SetEnabled (bool);
+
+ const char*
+ GetName();
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ uint32_t
+ GetNumFormats ();
+
+ uint32_t
+ GetNumSummaries ();
+
+ uint32_t
+ GetNumFilters ();
+
+#ifndef LLDB_DISABLE_PYTHON
+ uint32_t
+ GetNumSynthetics ();
+#endif
+
+ SBTypeNameSpecifier
+ GetTypeNameSpecifierForFilterAtIndex (uint32_t);
+
+ SBTypeNameSpecifier
+ GetTypeNameSpecifierForFormatAtIndex (uint32_t);
+
+ SBTypeNameSpecifier
+ GetTypeNameSpecifierForSummaryAtIndex (uint32_t);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeNameSpecifier
+ GetTypeNameSpecifierForSyntheticAtIndex (uint32_t);
+#endif
+
+ SBTypeFilter
+ GetFilterForType (SBTypeNameSpecifier);
+
+ SBTypeFormat
+ GetFormatForType (SBTypeNameSpecifier);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSummary
+ GetSummaryForType (SBTypeNameSpecifier);
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSynthetic
+ GetSyntheticForType (SBTypeNameSpecifier);
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeFilter
+ GetFilterAtIndex (uint32_t);
+#endif
+
+ SBTypeFormat
+ GetFormatAtIndex (uint32_t);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSummary
+ GetSummaryAtIndex (uint32_t);
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ SBTypeSynthetic
+ GetSyntheticAtIndex (uint32_t);
+#endif
+
+ bool
+ AddTypeFormat (SBTypeNameSpecifier,
+ SBTypeFormat);
+
+ bool
+ DeleteTypeFormat (SBTypeNameSpecifier);
+
+#ifndef LLDB_DISABLE_PYTHON
+ bool
+ AddTypeSummary (SBTypeNameSpecifier,
+ SBTypeSummary);
+#endif
+
+ bool
+ DeleteTypeSummary (SBTypeNameSpecifier);
+
+ bool
+ AddTypeFilter (SBTypeNameSpecifier,
+ SBTypeFilter);
+
+ bool
+ DeleteTypeFilter (SBTypeNameSpecifier);
+
+#ifndef LLDB_DISABLE_PYTHON
+ bool
+ AddTypeSynthetic (SBTypeNameSpecifier,
+ SBTypeSynthetic);
+
+ bool
+ DeleteTypeSynthetic (SBTypeNameSpecifier);
+#endif
+
+ lldb::SBTypeCategory &
+ operator = (const lldb::SBTypeCategory &rhs);
+
+ bool
+ operator == (lldb::SBTypeCategory &rhs);
+
+ bool
+ operator != (lldb::SBTypeCategory &rhs);
+
+ protected:
+ friend class SBDebugger;
+
+ lldb::TypeCategoryImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeCategoryImplSP &typecategory_impl_sp);
+
+ TypeCategoryImplSP m_opaque_sp;
+
+ SBTypeCategory (const lldb::TypeCategoryImplSP &);
+
+ SBTypeCategory (const char*);
+
+ bool
+ IsDefaultCategory();
+
+ };
+
+} // namespace lldb
+
+#endif // LLDB_SBTypeCategory_h_
diff --git a/include/lldb/API/SBTypeFilter.h b/include/lldb/API/SBTypeFilter.h
new file mode 100644
index 000000000000..016954943e28
--- /dev/null
+++ b/include/lldb/API/SBTypeFilter.h
@@ -0,0 +1,92 @@
+//===-- SBTypeFilter.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeFilter_h_
+#define LLDB_SBTypeFilter_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+ class SBTypeFilter
+ {
+ public:
+
+ SBTypeFilter();
+
+ SBTypeFilter (uint32_t options); // see lldb::eTypeOption values
+
+ SBTypeFilter (const lldb::SBTypeFilter &rhs);
+
+ ~SBTypeFilter ();
+
+ bool
+ IsValid() const;
+
+ uint32_t
+ GetNumberOfExpressionPaths ();
+
+ const char*
+ GetExpressionPathAtIndex (uint32_t i);
+
+ bool
+ ReplaceExpressionPathAtIndex (uint32_t i, const char* item);
+
+ void
+ AppendExpressionPath (const char* item);
+
+ void
+ Clear();
+
+ uint32_t
+ GetOptions();
+
+ void
+ SetOptions (uint32_t);
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBTypeFilter &
+ operator = (const lldb::SBTypeFilter &rhs);
+
+ bool
+ IsEqualTo (lldb::SBTypeFilter &rhs);
+
+ bool
+ operator == (lldb::SBTypeFilter &rhs);
+
+ bool
+ operator != (lldb::SBTypeFilter &rhs);
+
+ protected:
+ friend class SBDebugger;
+ friend class SBTypeCategory;
+ friend class SBValue;
+
+ lldb::TypeFilterImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeFilterImplSP &typefilter_impl_sp);
+
+ lldb::TypeFilterImplSP m_opaque_sp;
+
+ SBTypeFilter (const lldb::TypeFilterImplSP &);
+
+ bool
+ CopyOnWrite_Impl();
+
+ };
+
+
+} // namespace lldb
+
+#endif // LLDB_SBTypeFilter_h_
diff --git a/include/lldb/API/SBTypeFormat.h b/include/lldb/API/SBTypeFormat.h
new file mode 100644
index 000000000000..cd6345fbe6fa
--- /dev/null
+++ b/include/lldb/API/SBTypeFormat.h
@@ -0,0 +1,84 @@
+//===-- SBTypeFormat.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeFormat_h_
+#define LLDB_SBTypeFormat_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBTypeFormat
+{
+public:
+
+ SBTypeFormat();
+
+ SBTypeFormat (lldb::Format format,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ SBTypeFormat (const lldb::SBTypeFormat &rhs);
+
+ ~SBTypeFormat ();
+
+ bool
+ IsValid() const;
+
+ lldb::Format
+ GetFormat ();
+
+ uint32_t
+ GetOptions();
+
+ void
+ SetFormat (lldb::Format);
+
+ void
+ SetOptions (uint32_t);
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBTypeFormat &
+ operator = (const lldb::SBTypeFormat &rhs);
+
+ bool
+ IsEqualTo (lldb::SBTypeFormat &rhs);
+
+ bool
+ operator == (lldb::SBTypeFormat &rhs);
+
+ bool
+ operator != (lldb::SBTypeFormat &rhs);
+
+protected:
+ friend class SBDebugger;
+ friend class SBTypeCategory;
+ friend class SBValue;
+
+ lldb::TypeFormatImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeFormatImplSP &typeformat_impl_sp);
+
+ lldb::TypeFormatImplSP m_opaque_sp;
+
+ SBTypeFormat (const lldb::TypeFormatImplSP &);
+
+ bool
+ CopyOnWrite_Impl();
+
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBTypeFormat_h_
diff --git a/include/lldb/API/SBTypeNameSpecifier.h b/include/lldb/API/SBTypeNameSpecifier.h
new file mode 100644
index 000000000000..19d1988aa0c5
--- /dev/null
+++ b/include/lldb/API/SBTypeNameSpecifier.h
@@ -0,0 +1,77 @@
+//===-- SBTypeNameSpecifier.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeNameSpecifier_h_
+#define LLDB_SBTypeNameSpecifier_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+ class SBTypeNameSpecifier
+ {
+ public:
+
+ SBTypeNameSpecifier();
+
+ SBTypeNameSpecifier (const char* name,
+ bool is_regex = false);
+
+ SBTypeNameSpecifier (SBType type);
+
+ SBTypeNameSpecifier (const lldb::SBTypeNameSpecifier &rhs);
+
+ ~SBTypeNameSpecifier ();
+
+ bool
+ IsValid() const;
+
+ const char*
+ GetName();
+
+ SBType
+ GetType ();
+
+ bool
+ IsRegex();
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBTypeNameSpecifier &
+ operator = (const lldb::SBTypeNameSpecifier &rhs);
+
+ bool
+ IsEqualTo (lldb::SBTypeNameSpecifier &rhs);
+
+ bool
+ operator == (lldb::SBTypeNameSpecifier &rhs);
+
+ bool
+ operator != (lldb::SBTypeNameSpecifier &rhs);
+
+ protected:
+ friend class SBDebugger;
+ friend class SBTypeCategory;
+
+ lldb::TypeNameSpecifierImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeNameSpecifierImplSP &type_namespec_sp);
+
+ lldb::TypeNameSpecifierImplSP m_opaque_sp;
+
+ SBTypeNameSpecifier (const lldb::TypeNameSpecifierImplSP &);
+ };
+
+} // namespace lldb
+
+#endif // LLDB_SBTypeNameSpecifier_h_
diff --git a/include/lldb/API/SBTypeSummary.h b/include/lldb/API/SBTypeSummary.h
new file mode 100644
index 000000000000..67a8607511cc
--- /dev/null
+++ b/include/lldb/API/SBTypeSummary.h
@@ -0,0 +1,115 @@
+//===-- SBTypeSummary.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeSummary_h_
+#define LLDB_SBTypeSummary_h_
+
+#include "lldb/API/SBDefines.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+
+namespace lldb {
+
+ class SBTypeSummary
+ {
+ public:
+
+ SBTypeSummary();
+
+ static SBTypeSummary
+ CreateWithSummaryString (const char* data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ static SBTypeSummary
+ CreateWithFunctionName (const char* data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ static SBTypeSummary
+ CreateWithScriptCode (const char* data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ SBTypeSummary (const lldb::SBTypeSummary &rhs);
+
+ ~SBTypeSummary ();
+
+ bool
+ IsValid() const;
+
+ bool
+ IsFunctionCode();
+
+ bool
+ IsFunctionName();
+
+ bool
+ IsSummaryString();
+
+ const char*
+ GetData ();
+
+ void
+ SetSummaryString (const char* data);
+
+ void
+ SetFunctionName (const char* data);
+
+ void
+ SetFunctionCode (const char* data);
+
+ uint32_t
+ GetOptions ();
+
+ void
+ SetOptions (uint32_t);
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBTypeSummary &
+ operator = (const lldb::SBTypeSummary &rhs);
+
+ bool
+ IsEqualTo (lldb::SBTypeSummary &rhs);
+
+ bool
+ operator == (lldb::SBTypeSummary &rhs);
+
+ bool
+ operator != (lldb::SBTypeSummary &rhs);
+
+ protected:
+ friend class SBDebugger;
+ friend class SBTypeCategory;
+ friend class SBValue;
+
+ lldb::TypeSummaryImplSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::TypeSummaryImplSP &typefilter_impl_sp);
+
+ lldb::TypeSummaryImplSP m_opaque_sp;
+
+ SBTypeSummary (const lldb::TypeSummaryImplSP &);
+
+ bool
+ CopyOnWrite_Impl();
+
+ bool
+ ChangeSummaryType (bool want_script);
+
+ };
+
+
+} // namespace lldb
+
+#endif // LLDB_DISABLE_PYTHON
+
+#endif // LLDB_SBTypeSummary_h_
diff --git a/include/lldb/API/SBTypeSynthetic.h b/include/lldb/API/SBTypeSynthetic.h
new file mode 100644
index 000000000000..e77cbfef598c
--- /dev/null
+++ b/include/lldb/API/SBTypeSynthetic.h
@@ -0,0 +1,102 @@
+//===-- SBTypeSynthetic.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBTypeSynthetic_h_
+#define LLDB_SBTypeSynthetic_h_
+
+#include "lldb/API/SBDefines.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+
+namespace lldb {
+
+ class SBTypeSynthetic
+ {
+ public:
+
+ SBTypeSynthetic();
+
+ static SBTypeSynthetic
+ CreateWithClassName (const char* data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ static SBTypeSynthetic
+ CreateWithScriptCode (const char* data,
+ uint32_t options = 0); // see lldb::eTypeOption values
+
+ SBTypeSynthetic (const lldb::SBTypeSynthetic &rhs);
+
+ ~SBTypeSynthetic ();
+
+ bool
+ IsValid() const;
+
+ bool
+ IsClassCode();
+
+ bool
+ IsClassName();
+
+ const char*
+ GetData ();
+
+ void
+ SetClassName (const char* data);
+
+ void
+ SetClassCode (const char* data);
+
+ uint32_t
+ GetOptions ();
+
+ void
+ SetOptions (uint32_t);
+
+ bool
+ GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level);
+
+ lldb::SBTypeSynthetic &
+ operator = (const lldb::SBTypeSynthetic &rhs);
+
+ bool
+ IsEqualTo (lldb::SBTypeSynthetic &rhs);
+
+ bool
+ operator == (lldb::SBTypeSynthetic &rhs);
+
+ bool
+ operator != (lldb::SBTypeSynthetic &rhs);
+
+ protected:
+ friend class SBDebugger;
+ friend class SBTypeCategory;
+ friend class SBValue;
+
+ lldb::ScriptedSyntheticChildrenSP
+ GetSP ();
+
+ void
+ SetSP (const lldb::ScriptedSyntheticChildrenSP &typefilter_impl_sp);
+
+ lldb::ScriptedSyntheticChildrenSP m_opaque_sp;
+
+ SBTypeSynthetic (const lldb::ScriptedSyntheticChildrenSP &);
+
+ bool
+ CopyOnWrite_Impl();
+
+ };
+
+
+} // namespace lldb
+
+#endif // LLDB_DISABLE_PYTHON
+
+#endif // LLDB_SBTypeSynthetic_h_
diff --git a/include/lldb/API/SBValue.h b/include/lldb/API/SBValue.h
new file mode 100644
index 000000000000..2b9a344b9300
--- /dev/null
+++ b/include/lldb/API/SBValue.h
@@ -0,0 +1,488 @@
+//===-- SBValue.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBValue_h_
+#define LLDB_SBValue_h_
+
+#include "lldb/API/SBData.h"
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBType.h"
+
+class ValueImpl;
+class ValueLocker;
+
+namespace lldb {
+
+class SBValue
+{
+friend class ValueLocker;
+
+public:
+ SBValue ();
+
+ SBValue (const lldb::SBValue &rhs);
+
+ lldb::SBValue &
+ operator =(const lldb::SBValue &rhs);
+
+ ~SBValue ();
+
+ bool
+ IsValid();
+
+ void
+ Clear();
+
+ SBError
+ GetError();
+
+ lldb::user_id_t
+ GetID ();
+
+ const char *
+ GetName();
+
+ const char *
+ GetTypeName ();
+
+ size_t
+ GetByteSize ();
+
+ bool
+ IsInScope ();
+
+ lldb::Format
+ GetFormat ();
+
+ void
+ SetFormat (lldb::Format format);
+
+ const char *
+ GetValue ();
+
+ int64_t
+ GetValueAsSigned (lldb::SBError& error, int64_t fail_value=0);
+
+ uint64_t
+ GetValueAsUnsigned (lldb::SBError& error, uint64_t fail_value=0);
+
+ int64_t
+ GetValueAsSigned(int64_t fail_value=0);
+
+ uint64_t
+ GetValueAsUnsigned(uint64_t fail_value=0);
+
+ ValueType
+ GetValueType ();
+
+ bool
+ GetValueDidChange ();
+
+ const char *
+ GetSummary ();
+
+ const char *
+ GetObjectDescription ();
+
+ lldb::SBValue
+ GetDynamicValue (lldb::DynamicValueType use_dynamic);
+
+ lldb::SBValue
+ GetStaticValue ();
+
+ lldb::SBValue
+ GetNonSyntheticValue ();
+
+ lldb::DynamicValueType
+ GetPreferDynamicValue ();
+
+ void
+ SetPreferDynamicValue (lldb::DynamicValueType use_dynamic);
+
+ bool
+ GetPreferSyntheticValue ();
+
+ void
+ SetPreferSyntheticValue (bool use_synthetic);
+
+ bool
+ IsDynamic ();
+
+ bool
+ IsSynthetic ();
+
+ const char *
+ GetLocation ();
+
+ // Deprecated - use the one that takes SBError&
+ bool
+ SetValueFromCString (const char *value_str);
+
+ bool
+ SetValueFromCString (const char *value_str, lldb::SBError& error);
+
+ lldb::SBTypeFormat
+ GetTypeFormat ();
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::SBTypeSummary
+ GetTypeSummary ();
+#endif
+
+ lldb::SBTypeFilter
+ GetTypeFilter ();
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::SBTypeSynthetic
+ GetTypeSynthetic ();
+#endif
+
+ lldb::SBValue
+ GetChildAtIndex (uint32_t idx);
+
+ lldb::SBValue
+ CreateChildAtOffset (const char *name, uint32_t offset, lldb::SBType type);
+
+ lldb::SBValue
+ Cast (lldb::SBType type);
+
+ lldb::SBValue
+ CreateValueFromExpression (const char *name, const char* expression);
+
+ lldb::SBValue
+ CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options);
+
+ lldb::SBValue
+ CreateValueFromAddress (const char* name,
+ lldb::addr_t address,
+ lldb::SBType type);
+
+ // this has no address! GetAddress() and GetLoadAddress() as well as AddressOf()
+ // on the return of this call all return invalid
+ lldb::SBValue
+ CreateValueFromData (const char* name,
+ lldb::SBData data,
+ lldb::SBType type);
+
+ //------------------------------------------------------------------
+ /// Get a child value by index from a value.
+ ///
+ /// Structs, unions, classes, arrays and and pointers have child
+ /// values that can be access by index.
+ ///
+ /// Structs and unions access child members using a zero based index
+ /// for each child member. For
+ ///
+ /// Classes reserve the first indexes for base classes that have
+ /// members (empty base classes are omitted), and all members of the
+ /// current class will then follow the base classes.
+ ///
+ /// Pointers differ depending on what they point to. If the pointer
+ /// points to a simple type, the child at index zero
+ /// is the only child value available, unless \a synthetic_allowed
+ /// is \b true, in which case the pointer will be used as an array
+ /// and can create 'synthetic' child values using positive or
+ /// negative indexes. If the pointer points to an aggregate type
+ /// (an array, class, union, struct), then the pointee is
+ /// transparently skipped and any children are going to be the indexes
+ /// of the child values within the aggregate type. For example if
+ /// we have a 'Point' type and we have a SBValue that contains a
+ /// pointer to a 'Point' type, then the child at index zero will be
+ /// the 'x' member, and the child at index 1 will be the 'y' member
+ /// (the child at index zero won't be a 'Point' instance).
+ ///
+ /// Arrays have a preset number of children that can be accessed by
+ /// index and will returns invalid child values for indexes that are
+ /// out of bounds unless the \a synthetic_allowed is \b true. In this
+ /// case the array can create 'synthetic' child values for indexes
+ /// that aren't in the array bounds using positive or negative
+ /// indexes.
+ ///
+ /// @param[in] idx
+ /// The index of the child value to get
+ ///
+ /// @param[in] use_dynamic
+ /// An enumeration that specifies wether to get dynamic values,
+ /// and also if the target can be run to figure out the dynamic
+ /// type of the child value.
+ ///
+ /// @param[in] synthetic_allowed
+ /// If \b true, then allow child values to be created by index
+ /// for pointers and arrays for indexes that normally wouldn't
+ /// be allowed.
+ ///
+ /// @return
+ /// A new SBValue object that represents the child member value.
+ //------------------------------------------------------------------
+ lldb::SBValue
+ GetChildAtIndex (uint32_t idx,
+ lldb::DynamicValueType use_dynamic,
+ bool can_create_synthetic);
+
+ // Matches children of this object only and will match base classes and
+ // member names if this is a clang typed object.
+ uint32_t
+ GetIndexOfChildWithName (const char *name);
+
+ // Matches child members of this object and child members of any base
+ // classes.
+ lldb::SBValue
+ GetChildMemberWithName (const char *name);
+
+ // Matches child members of this object and child members of any base
+ // classes.
+ lldb::SBValue
+ GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dynamic);
+
+ // Expands nested expressions like .a->b[0].c[1]->d
+ lldb::SBValue
+ GetValueForExpressionPath(const char* expr_path);
+
+ lldb::SBValue
+ AddressOf();
+
+ lldb::addr_t
+ GetLoadAddress();
+
+ lldb::SBAddress
+ GetAddress();
+
+ //------------------------------------------------------------------
+ /// Get an SBData wrapping what this SBValue points to.
+ ///
+ /// This method will dereference the current SBValue, if its
+ /// data type is a T* or T[], and extract item_count elements
+ /// of type T from it, copying their contents in an SBData.
+ ///
+ /// @param[in] item_idx
+ /// The index of the first item to retrieve. For an array
+ /// this is equivalent to array[item_idx], for a pointer
+ /// to *(pointer + item_idx). In either case, the measurement
+ /// unit for item_idx is the sizeof(T) rather than the byte
+ ///
+ /// @param[in] item_count
+ /// How many items should be copied into the output. By default
+ /// only one item is copied, but more can be asked for.
+ ///
+ /// @return
+ /// An SBData with the contents of the copied items, on success.
+ /// An empty SBData otherwise.
+ //------------------------------------------------------------------
+ lldb::SBData
+ GetPointeeData (uint32_t item_idx = 0,
+ uint32_t item_count = 1);
+
+ //------------------------------------------------------------------
+ /// Get an SBData wrapping the contents of this SBValue.
+ ///
+ /// This method will read the contents of this object in memory
+ /// and copy them into an SBData for future use.
+ ///
+ /// @return
+ /// An SBData with the contents of this SBValue, on success.
+ /// An empty SBData otherwise.
+ //------------------------------------------------------------------
+ lldb::SBData
+ GetData ();
+
+ bool
+ SetData (lldb::SBData &data, lldb::SBError& error);
+
+ lldb::SBDeclaration
+ GetDeclaration ();
+
+ //------------------------------------------------------------------
+ /// Find out if a SBValue might have children.
+ ///
+ /// This call is much more efficient than GetNumChildren() as it
+ /// doesn't need to complete the underlying type. This is designed
+ /// to be used in a UI environment in order to detect if the
+ /// disclosure triangle should be displayed or not.
+ ///
+ /// This function returns true for class, union, structure,
+ /// pointers, references, arrays and more. Again, it does so without
+ /// doing any expensive type completion.
+ ///
+ /// @return
+ /// Returns \b true if the SBValue might have children, or \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool
+ MightHaveChildren ();
+
+ uint32_t
+ GetNumChildren ();
+
+ void *
+ GetOpaqueType();
+
+ lldb::SBTarget
+ GetTarget();
+
+ lldb::SBProcess
+ GetProcess();
+
+ lldb::SBThread
+ GetThread();
+
+ lldb::SBFrame
+ GetFrame();
+
+ lldb::SBValue
+ Dereference ();
+
+ bool
+ TypeIsPointerType ();
+
+ lldb::SBType
+ GetType();
+
+ bool
+ GetDescription (lldb::SBStream &description);
+
+ bool
+ GetExpressionPath (lldb::SBStream &description);
+
+ bool
+ GetExpressionPath (lldb::SBStream &description,
+ bool qualify_cxx_base_classes);
+
+ SBValue (const lldb::ValueObjectSP &value_sp);
+
+ //------------------------------------------------------------------
+ /// Watch this value if it resides in memory.
+ ///
+ /// Sets a watchpoint on the value.
+ ///
+ /// @param[in] resolve_location
+ /// Resolve the location of this value once and watch its address.
+ /// This value must currently be set to \b true as watching all
+ /// locations of a variable or a variable path is not yet supported,
+ /// though we plan to support it in the future.
+ ///
+ /// @param[in] read
+ /// Stop when this value is accessed.
+ ///
+ /// @param[in] write
+ /// Stop when this value is modified
+ ///
+ /// @param[out]
+ /// An error object. Contains the reason if there is some failure.
+ ///
+ /// @return
+ /// An SBWatchpoint object. This object might not be valid upon
+ /// return due to a value not being contained in memory, too
+ /// large, or watchpoint resources are not available or all in
+ /// use.
+ //------------------------------------------------------------------
+ lldb::SBWatchpoint
+ Watch (bool resolve_location, bool read, bool write, SBError &error);
+
+ // Backward compatibility fix in the interim.
+ lldb::SBWatchpoint
+ Watch (bool resolve_location, bool read, bool write);
+
+ //------------------------------------------------------------------
+ /// Watch this value that this value points to in memory
+ ///
+ /// Sets a watchpoint on the value.
+ ///
+ /// @param[in] resolve_location
+ /// Resolve the location of this value once and watch its address.
+ /// This value must currently be set to \b true as watching all
+ /// locations of a variable or a variable path is not yet supported,
+ /// though we plan to support it in the future.
+ ///
+ /// @param[in] read
+ /// Stop when this value is accessed.
+ ///
+ /// @param[in] write
+ /// Stop when this value is modified
+ ///
+ /// @param[out]
+ /// An error object. Contains the reason if there is some failure.
+ ///
+ /// @return
+ /// An SBWatchpoint object. This object might not be valid upon
+ /// return due to a value not being contained in memory, too
+ /// large, or watchpoint resources are not available or all in
+ /// use.
+ //------------------------------------------------------------------
+ lldb::SBWatchpoint
+ WatchPointee (bool resolve_location, bool read, bool write, SBError &error);
+
+ //------------------------------------------------------------------
+ /// Same as the protected version of GetSP that takes a locker, except that we make the
+ /// locker locally in the function. Since the Target API mutex is recursive, and the
+ /// StopLocker is a read lock, you can call this function even if you are already
+ /// holding the two above-mentioned locks.
+ ///
+ /// @return
+ /// A ValueObjectSP of the best kind (static, dynamic or synthetic) we
+ /// can cons up, in accordance with the SBValue's settings.
+ //------------------------------------------------------------------
+ lldb::ValueObjectSP
+ GetSP () const;
+
+protected:
+ friend class SBBlock;
+ friend class SBFrame;
+ friend class SBTarget;
+ friend class SBThread;
+ friend class SBValueList;
+
+ //------------------------------------------------------------------
+ /// Get the appropriate ValueObjectSP from this SBValue, consulting the
+ /// use_dynamic and use_synthetic options passed in to SetSP when the
+ /// SBValue's contents were set. Since this often requires examining memory,
+ /// and maybe even running code, it needs to acquire the Target API and Process StopLock.
+ /// Those are held in an opaque class ValueLocker which is currently local to SBValue.cpp.
+ /// So you don't have to get these yourself just default construct a ValueLocker, and pass it into this.
+ /// If we need to make a ValueLocker and use it in some other .cpp file, we'll have to move it to
+ /// ValueObject.h/cpp or somewhere else convenient. We haven't needed to so far.
+ ///
+ /// @param[in] value_locker
+ /// An object that will hold the Target API, and Process RunLocks, and
+ /// auto-destroy them when it goes out of scope. Currently this is only useful in
+ /// SBValue.cpp.
+ ///
+ /// @return
+ /// A ValueObjectSP of the best kind (static, dynamic or synthetic) we
+ /// can cons up, in accordance with the SBValue's settings.
+ //------------------------------------------------------------------
+ lldb::ValueObjectSP
+ GetSP (ValueLocker &value_locker) const;
+
+ // these calls do the right thing WRT adjusting their settings according to the target's preferences
+ void
+ SetSP (const lldb::ValueObjectSP &sp);
+
+ void
+ SetSP (const lldb::ValueObjectSP &sp, bool use_synthetic);
+
+ void
+ SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic);
+
+ void
+ SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic);
+
+ void
+ SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic, const char *name);
+
+private:
+ typedef std::shared_ptr<ValueImpl> ValueImplSP;
+ ValueImplSP m_opaque_sp;
+
+ void
+ SetSP (ValueImplSP impl_sp);
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBValue_h_
diff --git a/include/lldb/API/SBValueList.h b/include/lldb/API/SBValueList.h
new file mode 100644
index 000000000000..b9a6aedea3cb
--- /dev/null
+++ b/include/lldb/API/SBValueList.h
@@ -0,0 +1,93 @@
+//===-- SBValueList.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBValueList_h_
+#define LLDB_SBValueList_h_
+
+#include "lldb/API/SBDefines.h"
+
+class ValueListImpl;
+
+namespace lldb {
+
+class SBValueList
+{
+public:
+
+ SBValueList ();
+
+ SBValueList (const lldb::SBValueList &rhs);
+
+ ~SBValueList();
+
+ bool
+ IsValid() const;
+
+ void
+ Clear();
+
+ void
+ Append (const lldb::SBValue &val_obj);
+
+ void
+ Append (const lldb::SBValueList& value_list);
+
+ uint32_t
+ GetSize() const;
+
+ lldb::SBValue
+ GetValueAtIndex (uint32_t idx) const;
+
+ lldb::SBValue
+ FindValueObjectByUID (lldb::user_id_t uid);
+
+ const lldb::SBValueList &
+ operator = (const lldb::SBValueList &rhs);
+
+protected:
+
+ // only useful for visualizing the pointer or comparing two SBValueLists
+ // to see if they are backed by the same underlying Impl.
+ void *
+ opaque_ptr ();
+
+private:
+ friend class SBFrame;
+
+ SBValueList (const ValueListImpl *lldb_object_ptr);
+
+ void
+ Append (lldb::ValueObjectSP& val_obj_sp);
+
+ void
+ CreateIfNeeded ();
+
+ ValueListImpl *
+ operator -> ();
+
+ ValueListImpl &
+ operator* ();
+
+ const ValueListImpl *
+ operator -> () const;
+
+ const ValueListImpl &
+ operator* () const;
+
+
+ ValueListImpl &
+ ref ();
+
+ std::unique_ptr<ValueListImpl> m_opaque_ap;
+};
+
+
+} // namespace lldb
+
+#endif // LLDB_SBValueList_h_
diff --git a/include/lldb/API/SBWatchpoint.h b/include/lldb/API/SBWatchpoint.h
new file mode 100644
index 000000000000..9bf51fd1ad05
--- /dev/null
+++ b/include/lldb/API/SBWatchpoint.h
@@ -0,0 +1,104 @@
+//===-- SBWatchpoint.h ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SBWatchpoint_h_
+#define LLDB_SBWatchpoint_h_
+
+#include "lldb/API/SBDefines.h"
+
+namespace lldb {
+
+class SBWatchpoint
+{
+public:
+
+ SBWatchpoint ();
+
+ SBWatchpoint (const lldb::SBWatchpoint &rhs);
+
+ SBWatchpoint (const lldb::WatchpointSP &wp_sp);
+
+ ~SBWatchpoint ();
+
+ const lldb::SBWatchpoint &
+ operator = (const lldb::SBWatchpoint &rhs);
+
+ bool
+ IsValid() const;
+
+ SBError
+ GetError();
+
+ watch_id_t
+ GetID ();
+
+ /// With -1 representing an invalid hardware index.
+ int32_t
+ GetHardwareIndex ();
+
+ lldb::addr_t
+ GetWatchAddress ();
+
+ size_t
+ GetWatchSize();
+
+ void
+ SetEnabled(bool enabled);
+
+ bool
+ IsEnabled ();
+
+ uint32_t
+ GetHitCount ();
+
+ uint32_t
+ GetIgnoreCount ();
+
+ void
+ SetIgnoreCount (uint32_t n);
+
+ const char *
+ GetCondition ();
+
+ void
+ SetCondition (const char *condition);
+
+ bool
+ GetDescription (lldb::SBStream &description, DescriptionLevel level);
+
+ void
+ Clear ();
+
+ lldb::WatchpointSP
+ GetSP () const;
+
+ void
+ SetSP (const lldb::WatchpointSP &sp);
+
+ static bool
+ EventIsWatchpointEvent (const lldb::SBEvent &event);
+
+ static lldb::WatchpointEventType
+ GetWatchpointEventTypeFromEvent (const lldb::SBEvent& event);
+
+ static lldb::SBWatchpoint
+ GetWatchpointFromEvent (const lldb::SBEvent& event);
+
+private:
+ friend class SBTarget;
+ friend class SBValue;
+
+
+ lldb::WatchpointSP m_opaque_sp;
+
+};
+
+} // namespace lldb
+
+#endif // LLDB_SBWatchpoint_h_
diff --git a/include/lldb/Breakpoint/Breakpoint.h b/include/lldb/Breakpoint/Breakpoint.h
new file mode 100644
index 000000000000..bd11a1c91e21
--- /dev/null
+++ b/include/lldb/Breakpoint/Breakpoint.h
@@ -0,0 +1,630 @@
+//===-- Breakpoint.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_Breakpoint_h_
+#define liblldb_Breakpoint_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocationList.h"
+#include "lldb/Breakpoint/BreakpointOptions.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/Stoppoint.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Breakpoint Breakpoint.h "lldb/Breakpoint/Breakpoint.h"
+/// @brief Class that manages logical breakpoint setting.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// A breakpoint has four main parts, a filter, a resolver, the list of breakpoint
+/// locations that have been determined for the filter/resolver pair, and finally
+/// a set of options for the breakpoint.
+///
+/// \b Filter:
+/// This is an object derived from SearchFilter. It manages the search
+/// for breakpoint location matches through the symbols in the module list of the target
+/// that owns it. It also filters out locations based on whatever logic it wants.
+///
+/// \b Resolver:
+/// This is an object derived from BreakpointResolver. It provides a
+/// callback to the filter that will find breakpoint locations. How it does this is
+/// determined by what kind of resolver it is.
+///
+/// The Breakpoint class also provides constructors for the common breakpoint cases
+/// which make the appropriate filter and resolver for you.
+///
+/// \b Location List:
+/// This stores the breakpoint locations that have been determined
+/// to date. For a given breakpoint, there will be only one location with a given
+/// address. Adding a location at an already taken address will just return the location
+/// already at that address. Locations can be looked up by ID, or by address.
+///
+/// \b Options:
+/// This includes:
+/// \b Enabled/Disabled
+/// \b Ignore Count
+/// \b Callback
+/// \b Condition
+/// Note, these options can be set on the breakpoint, and they can also be set on the
+/// individual locations. The options set on the breakpoint take precedence over the
+/// options set on the individual location.
+/// So for instance disabling the breakpoint will cause NONE of the locations to get hit.
+/// But if the breakpoint is enabled, then the location's enabled state will be checked
+/// to determine whether to insert that breakpoint location.
+/// Similarly, if the breakpoint condition says "stop", we won't check the location's condition.
+/// But if the breakpoint condition says "continue", then we will check the location for whether
+/// to actually stop or not.
+/// One subtle point worth observing here is that you don't actually stop at a Breakpoint, you
+/// always stop at one of its locations. So the "should stop" tests are done by the location,
+/// not by the breakpoint.
+//----------------------------------------------------------------------
+class Breakpoint:
+ public std::enable_shared_from_this<Breakpoint>,
+ public Stoppoint
+{
+public:
+
+ static const ConstString &
+ GetEventIdentifier ();
+
+
+ //------------------------------------------------------------------
+ /// An enum specifying the match style for breakpoint settings. At
+ /// present only used for function name style breakpoints.
+ //------------------------------------------------------------------
+ typedef enum
+ {
+ Exact,
+ Regexp,
+ Glob
+ } MatchType;
+
+ class BreakpointEventData :
+ public EventData
+ {
+ public:
+
+ static const ConstString &
+ GetFlavorString ();
+
+ virtual const ConstString &
+ GetFlavor () const;
+
+ BreakpointEventData (lldb::BreakpointEventType sub_type,
+ const lldb::BreakpointSP &new_breakpoint_sp);
+
+ virtual
+ ~BreakpointEventData();
+
+ lldb::BreakpointEventType
+ GetBreakpointEventType () const;
+
+ lldb::BreakpointSP &
+ GetBreakpoint ();
+
+ BreakpointLocationCollection &
+ GetBreakpointLocationCollection()
+ {
+ return m_locations;
+ }
+
+
+ virtual void
+ Dump (Stream *s) const;
+
+ static lldb::BreakpointEventType
+ GetBreakpointEventTypeFromEvent (const lldb::EventSP &event_sp);
+
+ static lldb::BreakpointSP
+ GetBreakpointFromEvent (const lldb::EventSP &event_sp);
+
+ static lldb::BreakpointLocationSP
+ GetBreakpointLocationAtIndexFromEvent (const lldb::EventSP &event_sp, uint32_t loc_idx);
+
+ static size_t
+ GetNumBreakpointLocationsFromEvent (const lldb::EventSP &event_sp);
+
+ static const BreakpointEventData *
+ GetEventDataFromEvent (const Event *event_sp);
+
+ private:
+
+ lldb::BreakpointEventType m_breakpoint_event;
+ lldb::BreakpointSP m_new_breakpoint_sp;
+ BreakpointLocationCollection m_locations;
+
+ DISALLOW_COPY_AND_ASSIGN (BreakpointEventData);
+ };
+
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is not virtual since there should be no reason to subclass
+ /// breakpoints. The varieties of breakpoints are specified instead by
+ /// providing different resolvers & filters.
+ //------------------------------------------------------------------
+ ~Breakpoint();
+
+ //------------------------------------------------------------------
+ // Methods
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Tell whether this breakpoint is an "internal" breakpoint.
+ /// @return
+ /// Returns \b true if this is an internal breakpoint, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsInternal () const;
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s);
+
+ //------------------------------------------------------------------
+ // The next set of methods provide ways to tell the breakpoint to update
+ // it's location list - usually done when modules appear or disappear.
+ //------------------------------------------------------------------
+
+
+ //------------------------------------------------------------------
+ /// Tell this breakpoint to clear all its breakpoint sites. Done
+ /// when the process holding the breakpoint sites is destroyed.
+ //------------------------------------------------------------------
+ void
+ ClearAllBreakpointSites ();
+
+ //------------------------------------------------------------------
+ /// Tell this breakpoint to scan it's target's module list and resolve any
+ /// new locations that match the breakpoint's specifications.
+ //------------------------------------------------------------------
+ void
+ ResolveBreakpoint ();
+
+ //------------------------------------------------------------------
+ /// Tell this breakpoint to scan a given module list and resolve any
+ /// new locations that match the breakpoint's specifications.
+ ///
+ /// @param[in] changed_modules
+ /// The list of modules to look in for new locations.
+ //------------------------------------------------------------------
+ void
+ ResolveBreakpointInModules (ModuleList &changed_modules);
+
+
+ //------------------------------------------------------------------
+ /// Like ResolveBreakpointInModules, but allows for "unload" events, in
+ /// which case we will remove any locations that are in modules that got
+ /// unloaded.
+ ///
+ /// @param[in] changedModules
+ /// The list of modules to look in for new locations.
+ /// @param[in] load_event
+ /// If \b true then the modules were loaded, if \b false, unloaded.
+ /// @param[in] delete_locations
+ /// If \b true then the modules were unloaded delete any locations in the changed modules.
+ //------------------------------------------------------------------
+ void
+ ModulesChanged (ModuleList &changed_modules,
+ bool load_event,
+ bool delete_locations = false);
+
+
+ //------------------------------------------------------------------
+ /// Tells the breakpoint the old module \a old_module_sp has been
+ /// replaced by new_module_sp (usually because the underlying file has been
+ /// rebuilt, and the old version is gone.)
+ ///
+ /// @param[in] old_module_sp
+ /// The old module that is going away.
+ /// @param[in] new_module_sp
+ /// The new module that is replacing it.
+ //------------------------------------------------------------------
+ void
+ ModuleReplaced (lldb::ModuleSP old_module_sp, lldb::ModuleSP new_module_sp);
+
+ //------------------------------------------------------------------
+ // The next set of methods provide access to the breakpoint locations
+ // for this breakpoint.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Add a location to the breakpoint's location list. This is only meant
+ /// to be called by the breakpoint's resolver. FIXME: how do I ensure that?
+ ///
+ /// @param[in] addr
+ /// The Address specifying the new location.
+ /// @param[out] new_location
+ /// Set to \b true if a new location was created, to \b false if there
+ /// already was a location at this Address.
+ /// @return
+ /// Returns a pointer to the new location.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ AddLocation (const Address &addr,
+ bool *new_location = NULL);
+
+ //------------------------------------------------------------------
+ /// Find a breakpoint location by Address.
+ ///
+ /// @param[in] addr
+ /// The Address specifying the location.
+ /// @return
+ /// Returns a shared pointer to the location at \a addr. The pointer
+ /// in the shared pointer will be NULL if there is no location at that address.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ FindLocationByAddress (const Address &addr);
+
+ //------------------------------------------------------------------
+ /// Find a breakpoint location ID by Address.
+ ///
+ /// @param[in] addr
+ /// The Address specifying the location.
+ /// @return
+ /// Returns the UID of the location at \a addr, or \b LLDB_INVALID_ID if
+ /// there is no breakpoint location at that address.
+ //------------------------------------------------------------------
+ lldb::break_id_t
+ FindLocationIDByAddress (const Address &addr);
+
+ //------------------------------------------------------------------
+ /// Find a breakpoint location for a given breakpoint location ID.
+ ///
+ /// @param[in] bp_loc_id
+ /// The ID specifying the location.
+ /// @return
+ /// Returns a shared pointer to the location with ID \a bp_loc_id. The pointer
+ /// in the shared pointer will be NULL if there is no location with that ID.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ FindLocationByID (lldb::break_id_t bp_loc_id);
+
+ //------------------------------------------------------------------
+ /// Get breakpoint locations by index.
+ ///
+ /// @param[in] index
+ /// The location index.
+ ///
+ /// @return
+ /// Returns a shared pointer to the location with index \a
+ /// index. The shared pointer might contain NULL if \a index is
+ /// greater than then number of actual locations.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ GetLocationAtIndex (size_t index);
+
+ //------------------------------------------------------------------
+ // The next section deals with various breakpoint options.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// If \a enable is \b true, enable the breakpoint, if \b false disable it.
+ //------------------------------------------------------------------
+ void
+ SetEnabled (bool enable);
+
+ //------------------------------------------------------------------
+ /// Check the Enable/Disable state.
+ /// @return
+ /// \b true if the breakpoint is enabled, \b false if disabled.
+ //------------------------------------------------------------------
+ bool
+ IsEnabled ();
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint to ignore the next \a count breakpoint hits.
+ /// @param[in] count
+ /// The number of breakpoint hits to ignore.
+ //------------------------------------------------------------------
+ void
+ SetIgnoreCount (uint32_t count);
+
+ //------------------------------------------------------------------
+ /// Return the current ignore count/
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ uint32_t
+ GetIgnoreCount () const;
+
+ //------------------------------------------------------------------
+ /// Return the current hit count for all locations.
+ /// @return
+ /// The current hit count for all locations.
+ //------------------------------------------------------------------
+ uint32_t
+ GetHitCount () const;
+
+
+ //------------------------------------------------------------------
+ /// If \a one_shot is \b true, breakpoint will be deleted on first hit.
+ //------------------------------------------------------------------
+ void
+ SetOneShot (bool one_shot);
+
+ //------------------------------------------------------------------
+ /// Check the OneShot state.
+ /// @return
+ /// \b true if the breakpoint is one shot, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsOneShot () const;
+
+ //------------------------------------------------------------------
+ /// Set the valid thread to be checked when the breakpoint is hit.
+ /// @param[in] thread_id
+ /// If this thread hits the breakpoint, we stop, otherwise not.
+ //------------------------------------------------------------------
+ void
+ SetThreadID (lldb::tid_t thread_id);
+
+ //------------------------------------------------------------------
+ /// Return the current stop thread value.
+ /// @return
+ /// The thread id for which the breakpoint hit will stop, LLDB_INVALID_THREAD_ID for all threads.
+ //------------------------------------------------------------------
+ lldb::tid_t
+ GetThreadID () const;
+
+ void
+ SetThreadIndex (uint32_t index);
+
+ uint32_t
+ GetThreadIndex() const;
+
+ void
+ SetThreadName (const char *thread_name);
+
+ const char *
+ GetThreadName () const;
+
+ void
+ SetQueueName (const char *queue_name);
+
+ const char *
+ GetQueueName () const;
+
+ //------------------------------------------------------------------
+ /// Set the callback action invoked when the breakpoint is hit.
+ ///
+ /// @param[in] callback
+ /// The method that will get called when the breakpoint is hit.
+ /// @param[in] baton
+ /// A void * pointer that will get passed back to the callback function.
+ /// @param[in] is_synchronous
+ /// If \b true the callback will be run on the private event thread
+ /// before the stop event gets reported. If false, the callback will get
+ /// handled on the public event thead after the stop has been posted.
+ ///
+ /// @return
+ /// \b true if the process should stop when you hit the breakpoint.
+ /// \b false if it should continue.
+ //------------------------------------------------------------------
+ void
+ SetCallback (BreakpointHitCallback callback,
+ void *baton,
+ bool is_synchronous = false);
+
+ void
+ SetCallback (BreakpointHitCallback callback,
+ const lldb::BatonSP &callback_baton_sp,
+ bool is_synchronous = false);
+
+ void
+ ClearCallback ();
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint's condition.
+ ///
+ /// @param[in] condition
+ /// The condition expression to evaluate when the breakpoint is hit.
+ /// Pass in NULL to clear the condition.
+ //------------------------------------------------------------------
+ void SetCondition (const char *condition);
+
+ //------------------------------------------------------------------
+ /// Return a pointer to the text of the condition expression.
+ ///
+ /// @return
+ /// A pointer to the condition expression text, or NULL if no
+ // condition has been set.
+ //------------------------------------------------------------------
+ const char *GetConditionText () const;
+
+ //------------------------------------------------------------------
+ // The next section are various utility functions.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Return the number of breakpoint locations that have resolved to
+ /// actual breakpoint sites.
+ ///
+ /// @return
+ /// The number locations resolved breakpoint sites.
+ //------------------------------------------------------------------
+ size_t
+ GetNumResolvedLocations() const;
+
+ //------------------------------------------------------------------
+ /// Return the number of breakpoint locations.
+ ///
+ /// @return
+ /// The number breakpoint locations.
+ //------------------------------------------------------------------
+ size_t
+ GetNumLocations() const;
+
+ //------------------------------------------------------------------
+ /// Put a description of this breakpoint into the stream \a s.
+ ///
+ /// @param[in] s
+ /// Stream into which to dump the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations = false);
+
+ //------------------------------------------------------------------
+ /// Set the "kind" description for a breakpoint. If the breakpoint is hit
+ /// the stop info will show this "kind" description instead of the breakpoint
+ /// number. Mostly useful for internal breakpoints, where the breakpoint number
+ /// doesn't have meaning to the user.
+ ///
+ /// @param[in] kind
+ /// New "kind" description.
+ //------------------------------------------------------------------
+ void
+ SetBreakpointKind (const char *kind)
+ {
+ m_kind_description.assign (kind);
+ }
+
+ //------------------------------------------------------------------
+ /// Return the "kind" description for a breakpoint.
+ ///
+ /// @return
+ /// The breakpoint kind, or NULL if none is set.
+ //------------------------------------------------------------------
+ const char *GetBreakpointKind () const
+ {
+ return m_kind_description.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Accessor for the breakpoint Target.
+ /// @return
+ /// This breakpoint's Target.
+ //------------------------------------------------------------------
+ Target &
+ GetTarget ();
+
+ const Target &
+ GetTarget () const;
+
+ void
+ GetResolverDescription (Stream *s);
+
+ //------------------------------------------------------------------
+ /// Find breakpoint locations which match the (filename, line_number) description.
+ /// The breakpoint location collection is to be filled with the matching locations.
+ /// It should be initialized with 0 size by the API client.
+ ///
+ /// @return
+ /// True if there is a match
+ ///
+ /// The locations which match the filename and line_number in loc_coll. If its
+ /// size is 0 and true is returned, it means the breakpoint fully matches the
+ /// description.
+ //------------------------------------------------------------------
+ bool GetMatchingFileLine(const ConstString &filename, uint32_t line_number,
+ BreakpointLocationCollection &loc_coll);
+
+ void
+ GetFilterDescription (Stream *s);
+
+ //------------------------------------------------------------------
+ /// Returns the BreakpointOptions structure set at the breakpoint level.
+ ///
+ /// Meant to be used by the BreakpointLocation class.
+ ///
+ /// @return
+ /// A pointer to this breakpoint's BreakpointOptions.
+ //------------------------------------------------------------------
+ BreakpointOptions *
+ GetOptions ();
+
+
+ //------------------------------------------------------------------
+ /// Invoke the callback action when the breakpoint is hit.
+ ///
+ /// Meant to be used by the BreakpointLocation class.
+ ///
+ /// @param[in] context
+ /// Described the breakpoint event.
+ ///
+ /// @param[in] bp_loc_id
+ /// Which breakpoint location hit this breakpoint.
+ ///
+ /// @return
+ /// \b true if the target should stop at this breakpoint and \b false not.
+ //------------------------------------------------------------------
+ bool
+ InvokeCallback (StoppointCallbackContext *context,
+ lldb::break_id_t bp_loc_id);
+
+protected:
+ friend class Target;
+ //------------------------------------------------------------------
+ // Protected Methods
+ //------------------------------------------------------------------
+
+
+ //------------------------------------------------------------------
+ /// Constructors and Destructors
+ /// Only the Target can make a breakpoint, and it owns the breakpoint lifespans.
+ /// The constructor takes a filter and a resolver. Up in Target there are convenience
+ /// variants that make breakpoints for some common cases.
+ //------------------------------------------------------------------
+ // This is the generic constructor
+ Breakpoint(Target &target, lldb::SearchFilterSP &filter_sp, lldb::BreakpointResolverSP &resolver_sp);
+
+ friend class BreakpointLocation; // To call the following two when determining whether to stop.
+
+ void
+ DecrementIgnoreCount();
+
+ // BreakpointLocation::IgnoreCountShouldStop & Breakpoint::IgnoreCountShouldStop can only be called once per stop,
+ // and BreakpointLocation::IgnoreCountShouldStop should be tested first, and if it returns false we should
+ // continue, otherwise we should test Breakpoint::IgnoreCountShouldStop.
+
+ bool
+ IgnoreCountShouldStop ();
+
+private:
+ //------------------------------------------------------------------
+ // For Breakpoint only
+ //------------------------------------------------------------------
+ bool m_being_created;
+ Target &m_target; // The target that holds this breakpoint.
+ lldb::SearchFilterSP m_filter_sp; // The filter that constrains the breakpoint's domain.
+ lldb::BreakpointResolverSP m_resolver_sp; // The resolver that defines this breakpoint.
+ BreakpointOptions m_options; // Settable breakpoint options
+ BreakpointLocationList m_locations; // The list of locations currently found for this breakpoint.
+ std::string m_kind_description;
+
+ void
+ SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind);
+
+ void
+ SendBreakpointChangedEvent (BreakpointEventData *data);
+
+ DISALLOW_COPY_AND_ASSIGN(Breakpoint);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Breakpoint_h_
diff --git a/include/lldb/Breakpoint/BreakpointID.h b/include/lldb/Breakpoint/BreakpointID.h
new file mode 100644
index 000000000000..9e352100b9e1
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointID.h
@@ -0,0 +1,117 @@
+//===-- BreakpointID.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_BreakpointID_h_
+#define liblldb_BreakpointID_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// class BreakpointID
+//----------------------------------------------------------------------
+
+class BreakpointID
+{
+public:
+
+ BreakpointID (lldb::break_id_t bp_id = LLDB_INVALID_BREAK_ID,
+ lldb::break_id_t loc_id = LLDB_INVALID_BREAK_ID);
+
+ virtual
+ ~BreakpointID ();
+
+ lldb::break_id_t
+ GetBreakpointID ()
+ {
+ return m_break_id;
+ }
+
+ lldb::break_id_t
+ GetLocationID ()
+ {
+ return m_location_id;
+ }
+
+ void
+ SetID (lldb::break_id_t bp_id, lldb::break_id_t loc_id)
+ {
+ m_break_id = bp_id;
+ m_location_id = loc_id;
+ }
+
+ void
+ SetBreakpointID (lldb::break_id_t bp_id)
+ {
+ m_break_id = bp_id;
+ }
+
+ void
+ SetBreakpointLocationID (lldb::break_id_t loc_id)
+ {
+ m_location_id = loc_id;
+ }
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ static bool
+ IsRangeIdentifier (const char *str);
+
+ static bool
+ IsValidIDExpression (const char *str);
+
+ static const char *g_range_specifiers[];
+
+ //------------------------------------------------------------------
+ /// Takes an input string containing the description of a breakpoint or breakpoint and location
+ /// and returns the breakpoint ID and the breakpoint location id.
+ ///
+ /// @param[in] input
+ /// A string containing JUST the breakpoint description.
+ /// @param[out] break_id
+ /// This is the break id.
+ /// @param[out] break_loc_id
+ /// This is breakpoint location id, or LLDB_INVALID_BREAK_ID is no location was specified.
+ /// @return
+ /// \b true if the call was able to extract a breakpoint location from the string. \b false otherwise.
+ //------------------------------------------------------------------
+ static bool
+ ParseCanonicalReference (const char *input, lldb::break_id_t *break_id, lldb::break_id_t *break_loc_id);
+
+
+ //------------------------------------------------------------------
+ /// Takes a breakpoint ID and the breakpoint location id and returns
+ /// a string containing the canonical description for the breakpoint
+ /// or breakpoint location.
+ ///
+ /// @param[out] break_id
+ /// This is the break id.
+ ///
+ /// @param[out] break_loc_id
+ /// This is breakpoint location id, or LLDB_INVALID_BREAK_ID is no
+ /// location is to be specified.
+ //------------------------------------------------------------------
+ static void
+ GetCanonicalReference (Stream *s, lldb::break_id_t break_id, lldb::break_id_t break_loc_id);
+
+protected:
+ lldb::break_id_t m_break_id;
+ lldb::break_id_t m_location_id;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointID_h_
diff --git a/include/lldb/Breakpoint/BreakpointIDList.h b/include/lldb/Breakpoint/BreakpointIDList.h
new file mode 100644
index 000000000000..c9fcef0a783c
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointIDList.h
@@ -0,0 +1,82 @@
+//===-- BreakpointIDList.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_BreakpointIDList_h_
+#define liblldb_BreakpointIDList_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// class BreakpointIDList
+//----------------------------------------------------------------------
+
+
+class BreakpointIDList
+{
+public:
+ typedef std::vector<BreakpointID> BreakpointIDArray;
+
+ BreakpointIDList ();
+
+ virtual
+ ~BreakpointIDList ();
+
+ size_t
+ GetSize();
+
+ BreakpointID &
+ GetBreakpointIDAtIndex (size_t index);
+
+ bool
+ RemoveBreakpointIDAtIndex (size_t index);
+
+ void
+ Clear();
+
+ bool
+ AddBreakpointID (BreakpointID bp_id);
+
+ bool
+ AddBreakpointID (const char *bp_id);
+
+ bool
+ FindBreakpointID (BreakpointID &bp_id, size_t *position);
+
+ bool
+ FindBreakpointID (const char *bp_id, size_t *position);
+
+ void
+ InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result);
+
+ static bool
+ StringContainsIDRangeExpression (const char *in_string, size_t *range_start_len, size_t *range_end_pos);
+
+ static void
+ FindAndReplaceIDRanges (Args &old_args, Target *target, CommandReturnObject &result, Args &new_args);
+
+private:
+ BreakpointIDArray m_breakpoint_ids;
+ BreakpointID m_invalid_id;
+
+ DISALLOW_COPY_AND_ASSIGN(BreakpointIDList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointIDList_h_
diff --git a/include/lldb/Breakpoint/BreakpointList.h b/include/lldb/Breakpoint/BreakpointList.h
new file mode 100644
index 000000000000..97eb2b46bc0c
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointList.h
@@ -0,0 +1,193 @@
+//===-- BreakpointList.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_BreakpointList_h_
+#define liblldb_BreakpointList_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointList BreakpointList.h "lldb/Breakpoint/BreakpointList.h"
+/// @brief This class manages a list of breakpoints.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// Allows adding and removing breakpoints and find by ID and index.
+//----------------------------------------------------------------------
+
+class BreakpointList
+{
+public:
+ BreakpointList (bool is_internal);
+
+ ~BreakpointList();
+
+ //------------------------------------------------------------------
+ /// Add the breakpoint \a bp_sp to the list.
+ ///
+ /// @param[in] bp_sp
+ /// Shared pointer to the breakpoint that will get added to the list.
+ ///
+ /// @result
+ /// Returns breakpoint id.
+ //------------------------------------------------------------------
+ lldb::break_id_t
+ Add (lldb::BreakpointSP& bp_sp, bool notify);
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint with id \a breakID.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointSP
+ FindBreakpointByID (lldb::break_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint with id \a breakID. Const version.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointSP
+ FindBreakpointByID (lldb::break_id_t breakID) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint with index \a i.
+ ///
+ /// @param[in] i
+ /// The breakpoint index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointSP
+ GetBreakpointAtIndex (size_t i);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint with index \a i, const version
+ ///
+ /// @param[in] i
+ /// The breakpoint index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointSP
+ GetBreakpointAtIndex (size_t i) const;
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in this breakpoint list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_breakpoints.size();
+ }
+
+ //------------------------------------------------------------------
+ /// Removes the breakpoint given by \b breakID from this list.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint index to remove.
+ ///
+ /// @result
+ /// \b true if the breakpoint \a breakID was in the list.
+ //------------------------------------------------------------------
+ bool
+ Remove (lldb::break_id_t breakID, bool notify);
+
+ void
+ SetEnabledAll (bool enabled);
+
+ //------------------------------------------------------------------
+ /// Removes all the breakpoints from this list.
+ //------------------------------------------------------------------
+ void
+ RemoveAll (bool notify);
+
+ //------------------------------------------------------------------
+ /// Tell all the breakpoints to update themselves due to a change in the
+ /// modules in \a module_list. \a added says whether the module was loaded
+ /// or unloaded.
+ ///
+ /// @param[in] module_list
+ /// The module list that has changed.
+ ///
+ /// @param[in] added
+ /// \b true if the modules are loaded, \b false if unloaded.
+ //------------------------------------------------------------------
+ void
+ UpdateBreakpoints (ModuleList &module_list, bool added);
+
+ void
+ UpdateBreakpointsWhenModuleIsReplaced (lldb::ModuleSP old_module_sp, lldb::ModuleSP new_module_sp);
+
+ void
+ ClearAllBreakpointSites ();
+
+ //------------------------------------------------------------------
+ /// Sets the passed in Locker to hold the Breakpoint List mutex.
+ ///
+ /// @param[in] locker
+ /// The locker object that is set.
+ //------------------------------------------------------------------
+ void
+ GetListMutex (lldb_private::Mutex::Locker &locker);
+
+protected:
+ typedef std::list<lldb::BreakpointSP> bp_collection;
+
+ bp_collection::iterator
+ GetBreakpointIDIterator(lldb::break_id_t breakID);
+
+ bp_collection::const_iterator
+ GetBreakpointIDConstIterator(lldb::break_id_t breakID) const;
+
+ mutable Mutex m_mutex;
+ bp_collection m_breakpoints; // The breakpoint list, currently a list.
+ lldb::break_id_t m_next_break_id;
+ bool m_is_internal;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (BreakpointList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointList_h_
diff --git a/include/lldb/Breakpoint/BreakpointLocation.h b/include/lldb/Breakpoint/BreakpointLocation.h
new file mode 100644
index 000000000000..9ab0a79c6844
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointLocation.h
@@ -0,0 +1,401 @@
+//===-- BreakpointLocation.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_BreakpointLocation_h_
+#define liblldb_BreakpointLocation_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/StoppointLocation.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointLocation BreakpointLocation.h "lldb/Breakpoint/BreakpointLocation.h"
+/// @brief Class that manages one unique (by address) instance of a logical breakpoint.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// A breakpoint location is defined by the breakpoint that produces it,
+/// and the address that resulted in this particular instantiation.
+/// Each breakpoint location also may have a breakpoint site if its
+/// address has been loaded into the program.
+/// Finally it has a settable options object.
+///
+/// FIXME: Should we also store some fingerprint for the location, so
+/// we can map one location to the "equivalent location" on rerun? This
+/// would be useful if you've set options on the locations.
+//----------------------------------------------------------------------
+
+class BreakpointLocation :
+ public std::enable_shared_from_this<BreakpointLocation>,
+ public StoppointLocation
+{
+public:
+
+ ~BreakpointLocation ();
+
+ //------------------------------------------------------------------
+ /// Gets the load address for this breakpoint location
+ /// @return
+ /// Returns breakpoint location load address, \b
+ /// LLDB_INVALID_ADDRESS if not yet set.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetLoadAddress () const;
+
+ //------------------------------------------------------------------
+ /// Gets the Address for this breakpoint location
+ /// @return
+ /// Returns breakpoint location Address.
+ //------------------------------------------------------------------
+ Address &
+ GetAddress ();
+ //------------------------------------------------------------------
+ /// Gets the Breakpoint that created this breakpoint location
+ /// @return
+ /// Returns the owning breakpoint.
+ //------------------------------------------------------------------
+ Breakpoint &
+ GetBreakpoint ();
+
+ //------------------------------------------------------------------
+ /// Determines whether we should stop due to a hit at this
+ /// breakpoint location.
+ ///
+ /// Side Effects: This may evaluate the breakpoint condition, and
+ /// run the callback. So this command may do a considerable amount
+ /// of work.
+ ///
+ /// @return
+ /// \b true if this breakpoint location thinks we should stop,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldStop (StoppointCallbackContext *context);
+
+ //------------------------------------------------------------------
+ // The next section deals with various breakpoint options.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// If \a enable is \b true, enable the breakpoint, if \b false
+ /// disable it.
+ //------------------------------------------------------------------
+ void
+ SetEnabled(bool enabled);
+
+ //------------------------------------------------------------------
+ /// Check the Enable/Disable state.
+ ///
+ /// @return
+ /// \b true if the breakpoint is enabled, \b false if disabled.
+ //------------------------------------------------------------------
+ bool
+ IsEnabled () const;
+
+ //------------------------------------------------------------------
+ /// Return the current Ignore Count.
+ ///
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ uint32_t
+ GetIgnoreCount ();
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint to ignore the next \a count breakpoint hits.
+ ///
+ /// @param[in] count
+ /// The number of breakpoint hits to ignore.
+ //------------------------------------------------------------------
+ void
+ SetIgnoreCount (uint32_t n);
+
+ //------------------------------------------------------------------
+ /// Set the callback action invoked when the breakpoint is hit.
+ ///
+ /// The callback will return a bool indicating whether the target
+ /// should stop at this breakpoint or not.
+ ///
+ /// @param[in] callback
+ /// The method that will get called when the breakpoint is hit.
+ ///
+ /// @param[in] callback_baton_sp
+ /// A shared pointer to a Baton that provides the void * needed
+ /// for the callback.
+ ///
+ /// @see lldb_private::Baton
+ //------------------------------------------------------------------
+ void
+ SetCallback (BreakpointHitCallback callback,
+ const lldb::BatonSP &callback_baton_sp,
+ bool is_synchronous);
+
+ void
+ SetCallback (BreakpointHitCallback callback,
+ void *baton,
+ bool is_synchronous);
+
+ void
+ ClearCallback ();
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint location's condition.
+ ///
+ /// @param[in] condition
+ /// The condition expression to evaluate when the breakpoint is hit.
+ //------------------------------------------------------------------
+ void
+ SetCondition (const char *condition);
+
+ //------------------------------------------------------------------
+ /// Return a pointer to the text of the condition expression.
+ ///
+ /// @return
+ /// A pointer to the condition expression text, or NULL if no
+ // condition has been set.
+ //------------------------------------------------------------------
+ const char *
+ GetConditionText (size_t *hash = NULL) const;
+
+ bool
+ ConditionSaysStop (ExecutionContext &exe_ctx, Error &error);
+
+
+ //------------------------------------------------------------------
+ /// Set the valid thread to be checked when the breakpoint is hit.
+ ///
+ /// @param[in] thread_id
+ /// If this thread hits the breakpoint, we stop, otherwise not.
+ //------------------------------------------------------------------
+ void
+ SetThreadID (lldb::tid_t thread_id);
+
+ lldb::tid_t
+ GetThreadID ();
+
+ void
+ SetThreadIndex (uint32_t index);
+
+ uint32_t
+ GetThreadIndex() const;
+
+ void
+ SetThreadName (const char *thread_name);
+
+ const char *
+ GetThreadName () const;
+
+ void
+ SetQueueName (const char *queue_name);
+
+ const char *
+ GetQueueName () const;
+
+ //------------------------------------------------------------------
+ // The next section deals with this location's breakpoint sites.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Try to resolve the breakpoint site for this location.
+ ///
+ /// @return
+ /// \b true if we were successful at setting a breakpoint site,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveBreakpointSite ();
+
+ //------------------------------------------------------------------
+ /// Clear this breakpoint location's breakpoint site - for instance
+ /// when disabling the breakpoint.
+ ///
+ /// @return
+ /// \b true if there was a breakpoint site to be cleared, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ ClearBreakpointSite ();
+
+ //------------------------------------------------------------------
+ /// Return whether this breakpoint location has a breakpoint site.
+ /// @return
+ /// \b true if there was a breakpoint site for this breakpoint
+ /// location, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsResolved () const;
+
+ lldb::BreakpointSiteSP
+ GetBreakpointSite() const;
+
+ //------------------------------------------------------------------
+ // The next section are generic report functions.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Print a description of this breakpoint location to the stream
+ /// \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Use this to set location specific breakpoint options.
+ ///
+ /// It will create a copy of the containing breakpoint's options if
+ /// that hasn't been done already
+ ///
+ /// @return
+ /// A pointer to the breakpoint options.
+ //------------------------------------------------------------------
+ BreakpointOptions *
+ GetLocationOptions ();
+
+ //------------------------------------------------------------------
+ /// Use this to access breakpoint options from this breakpoint location.
+ /// This will point to the owning breakpoint's options unless options have
+ /// been set specifically on this location.
+ ///
+ /// @return
+ /// A pointer to the containing breakpoint's options if this
+ /// location doesn't have its own copy.
+ //------------------------------------------------------------------
+ const BreakpointOptions *
+ GetOptionsNoCreate () const;
+
+ bool
+ ValidForThisThread (Thread *thread);
+
+
+ //------------------------------------------------------------------
+ /// Invoke the callback action when the breakpoint is hit.
+ ///
+ /// Meant to be used by the BreakpointLocation class.
+ ///
+ /// @param[in] context
+ /// Described the breakpoint event.
+ ///
+ /// @param[in] bp_loc_id
+ /// Which breakpoint location hit this breakpoint.
+ ///
+ /// @return
+ /// \b true if the target should stop at this breakpoint and \b
+ /// false not.
+ //------------------------------------------------------------------
+ bool
+ InvokeCallback (StoppointCallbackContext *context);
+
+protected:
+ friend class BreakpointLocationList;
+ friend class CommandObjectBreakpointCommandAdd;
+ friend class Process;
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint site for this location to \a bp_site_sp.
+ ///
+ /// @param[in] bp_site_sp
+ /// The breakpoint site we are setting for this location.
+ ///
+ /// @return
+ /// \b true if we were successful at setting the breakpoint site,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetBreakpointSite (lldb::BreakpointSiteSP& bp_site_sp);
+
+ void
+ DecrementIgnoreCount();
+
+ bool
+ IgnoreCountShouldStop();
+
+private:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //
+ // Only the Breakpoint can make breakpoint locations, and it owns
+ // them.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Constructor.
+ ///
+ /// @param[in] owner
+ /// A back pointer to the breakpoint that owns this location.
+ ///
+ /// @param[in] addr
+ /// The Address defining this location.
+ ///
+ /// @param[in] tid
+ /// The thread for which this breakpoint location is valid, or
+ /// LLDB_INVALID_THREAD_ID if it is valid for all threads.
+ ///
+ /// @param[in] hardware
+ /// \b true if a hardware breakpoint is requested.
+ //------------------------------------------------------------------
+
+ BreakpointLocation (lldb::break_id_t bid,
+ Breakpoint &owner,
+ const Address &addr,
+ lldb::tid_t tid = LLDB_INVALID_THREAD_ID,
+ bool hardware = false);
+
+ //------------------------------------------------------------------
+ // Data members:
+ //------------------------------------------------------------------
+ bool m_being_created;
+ Address m_address; ///< The address defining this location.
+ Breakpoint &m_owner; ///< The breakpoint that produced this object.
+ std::unique_ptr<BreakpointOptions> m_options_ap; ///< Breakpoint options pointer, NULL if we're using our breakpoint's options.
+ lldb::BreakpointSiteSP m_bp_site_sp; ///< Our breakpoint site (it may be shared by more than one location.)
+ ClangUserExpression::ClangUserExpressionSP m_user_expression_sp; ///< The compiled expression to use in testing our condition.
+ Mutex m_condition_mutex; ///< Guards parsing and evaluation of the condition, which could be evaluated by multiple processes.
+ size_t m_condition_hash; ///< For testing whether the condition source code changed.
+
+ void
+ SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind);
+
+ DISALLOW_COPY_AND_ASSIGN (BreakpointLocation);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocation_h_
diff --git a/include/lldb/Breakpoint/BreakpointLocationCollection.h b/include/lldb/Breakpoint/BreakpointLocationCollection.h
new file mode 100644
index 000000000000..7f6a659323be
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointLocationCollection.h
@@ -0,0 +1,209 @@
+//===-- BreakpointLocationCollection.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_BreakpointLocationCollection_h_
+#define liblldb_BreakpointLocationCollection_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class BreakpointLocationCollection
+{
+public:
+ BreakpointLocationCollection();
+
+ ~BreakpointLocationCollection();
+
+ //------------------------------------------------------------------
+ /// Add the breakpoint \a bp_loc_sp to the list.
+ ///
+ /// @param[in] bp_sp
+ /// Shared pointer to the breakpoint location that will get added
+ /// to the list.
+ ///
+ /// @result
+ /// Returns breakpoint location id.
+ //------------------------------------------------------------------
+ void
+ Add (const lldb::BreakpointLocationSP& bp_loc_sp);
+
+ //------------------------------------------------------------------
+ /// Removes the breakpoint location given by \b breakID from this
+ /// list.
+ ///
+ /// @param[in] break_id
+ /// The breakpoint index to remove.
+ ///
+ /// @param[in] break_loc_id
+ /// The breakpoint location index in break_id to remove.
+ ///
+ /// @result
+ /// \b true if the breakpoint was in the list.
+ //------------------------------------------------------------------
+ bool
+ Remove (lldb::break_id_t break_id, lldb::break_id_t break_loc_id);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with id \a
+ /// breakID.
+ ///
+ /// @param[in] break_id
+ /// The breakpoint ID to seek for.
+ ///
+ /// @param[in] break_loc_id
+ /// The breakpoint location ID in \a break_id to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with id \a
+ /// breakID, const version.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint location ID to seek for.
+ ///
+ /// @param[in] break_loc_id
+ /// The breakpoint location ID in \a break_id to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointLocationSP
+ FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with index
+ /// \a i.
+ ///
+ /// @param[in] i
+ /// The breakpoint location index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ GetByIndex (size_t i);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with index
+ /// \a i, const version.
+ ///
+ /// @param[in] i
+ /// The breakpoint location index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointLocationSP
+ GetByIndex (size_t i) const;
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in this breakpoint location list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const { return m_break_loc_collection.size(); }
+
+ //------------------------------------------------------------------
+ /// Enquires of all the breakpoint locations in this list whether
+ /// we should stop at a hit at \a breakID.
+ ///
+ /// @param[in] context
+ /// This contains the information about this stop.
+ ///
+ /// @param[in] breakID
+ /// This break ID that we hit.
+ ///
+ /// @return
+ /// \b true if we should stop, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldStop (StoppointCallbackContext *context);
+
+ //------------------------------------------------------------------
+ /// Print a description of the breakpoint locations in this list
+ /// to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ //------------------------------------------------------------------
+ /// Check whether this collection of breakpoint locations have any
+ /// thread specifiers, and if yes, is \a thread_id contained in any
+ /// of these specifiers.
+ ///
+ /// @param[in] thread
+ /// The thread against which to test.
+ ///
+ /// return
+ /// \b true if the collection contains at least one location that
+ /// would be valid for this thread, false otherwise.
+ //------------------------------------------------------------------
+ bool ValidForThisThread (Thread *thread);
+
+ //------------------------------------------------------------------
+ /// Tell whether ALL the breakpoints in the location collection are internal.
+ ///
+ /// @result
+ /// \b true if all breakpoint locations are owned by internal breakpoints,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool IsInternal() const;
+
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from BreakpointLocationCollection can see
+ // and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For BreakpointLocationCollection only
+ //------------------------------------------------------------------
+
+ typedef std::vector<lldb::BreakpointLocationSP> collection;
+
+ collection::iterator
+ GetIDPairIterator(lldb::break_id_t break_id, lldb::break_id_t break_loc_id);
+
+ collection::const_iterator
+ GetIDPairConstIterator(lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const;
+
+ collection m_break_loc_collection;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocationCollection_h_
diff --git a/include/lldb/Breakpoint/BreakpointLocationList.h b/include/lldb/Breakpoint/BreakpointLocationList.h
new file mode 100644
index 000000000000..1cba23d9118e
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointLocationList.h
@@ -0,0 +1,269 @@
+//===-- BreakpointLocationList.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_BreakpointLocationList_h_
+#define liblldb_BreakpointLocationList_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <map>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointLocationList BreakpointLocationList.h "lldb/Breakpoint/BreakpointLocationList.h"
+/// @brief This class is used by Breakpoint to manage a list of breakpoint locations,
+// each breakpoint location in the list
+/// has a unique ID, and is unique by Address as well.
+//----------------------------------------------------------------------
+
+class BreakpointLocationList
+{
+// Only Breakpoints can make the location list, or add elements to it.
+// This is not just some random collection of locations. Rather, the act of adding the location
+// to this list sets its ID, and implicitly all the locations have the same breakpoint ID as
+// well. If you need a generic container for breakpoint locations, use BreakpointLocationCollection.
+friend class Breakpoint;
+
+public:
+ virtual
+ ~BreakpointLocationList();
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location at address
+ /// \a addr - const version.
+ ///
+ /// @param[in] addr
+ /// The address to look for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointLocationSP
+ FindByAddress (const Address &addr) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with id
+ /// \a breakID, const version.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint location ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ FindByID (lldb::break_id_t breakID) const;
+
+ //------------------------------------------------------------------
+ /// Returns the breakpoint location id to the breakpoint location
+ /// at address \a addr.
+ ///
+ /// @param[in] addr
+ /// The address to match.
+ ///
+ /// @result
+ /// The ID of the breakpoint location, or LLDB_INVALID_BREAK_ID.
+ //------------------------------------------------------------------
+ lldb::break_id_t
+ FindIDByAddress (const Address &addr);
+
+ //------------------------------------------------------------------
+ /// Returns a breakpoint location list of the breakpoint locations
+ /// in the module \a module. This list is allocated, and owned by
+ /// the caller.
+ ///
+ /// @param[in] module
+ /// The module to seek in.
+ ///
+ /// @param[in]
+ /// A breakpoint collection that gets any breakpoint locations
+ /// that match \a module appended to.
+ ///
+ /// @result
+ /// The number of matches
+ //------------------------------------------------------------------
+ size_t
+ FindInModule (Module *module,
+ BreakpointLocationCollection& bp_loc_list);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with
+ /// index \a i.
+ ///
+ /// @param[in] i
+ /// The breakpoint location index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ GetByIndex (size_t i);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint location with index
+ /// \a i, const version.
+ ///
+ /// @param[in] i
+ /// The breakpoint location index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint. May contain a NULL
+ /// pointer if the breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointLocationSP
+ GetByIndex (size_t i) const;
+
+ //------------------------------------------------------------------
+ /// Removes all the locations in this list from their breakpoint site
+ /// owners list.
+ //------------------------------------------------------------------
+ void
+ ClearAllBreakpointSites ();
+
+ //------------------------------------------------------------------
+ /// Tells all the breakopint locations in this list to attempt to
+ /// resolve any possible breakpoint sites.
+ //------------------------------------------------------------------
+ void
+ ResolveAllBreakpointSites ();
+
+ //------------------------------------------------------------------
+ /// Returns the number of breakpoint locations in this list with
+ /// resolved breakpoints.
+ ///
+ /// @result
+ /// Number of qualifying breakpoint locations.
+ //------------------------------------------------------------------
+ size_t
+ GetNumResolvedLocations() const;
+
+ //------------------------------------------------------------------
+ /// Returns the number hit count of all locations in this list.
+ ///
+ /// @result
+ /// Hit count of all locations in this list.
+ //------------------------------------------------------------------
+ uint32_t
+ GetHitCount () const;
+
+ //------------------------------------------------------------------
+ /// Enquires of the breakpoint location in this list with ID \a
+ /// breakID whether we should stop.
+ ///
+ /// @param[in] context
+ /// This contains the information about this stop.
+ ///
+ /// @param[in] breakID
+ /// This break ID that we hit.
+ ///
+ /// @return
+ /// \b true if we should stop, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldStop (StoppointCallbackContext *context,
+ lldb::break_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in this breakpoint location list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const
+ {
+ return m_locations.size();
+ }
+
+ //------------------------------------------------------------------
+ /// Print a description of the breakpoint locations in this list to
+ /// the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+protected:
+
+ //------------------------------------------------------------------
+ /// This is the standard constructor.
+ ///
+ /// It creates an empty breakpoint location list. It is protected
+ /// here because only Breakpoints are allowed to create the
+ /// breakpoint location list.
+ //------------------------------------------------------------------
+ BreakpointLocationList(Breakpoint &owner);
+
+ //------------------------------------------------------------------
+ /// Add the breakpoint \a bp_loc_sp to the list.
+ ///
+ /// @param[in] bp_sp
+ /// Shared pointer to the breakpoint location that will get
+ /// added to the list.
+ ///
+ /// @result
+ /// Returns breakpoint location id.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ Create (const Address &addr);
+
+ void
+ StartRecordingNewLocations(BreakpointLocationCollection &new_locations);
+
+ void
+ StopRecordingNewLocations();
+
+ lldb::BreakpointLocationSP
+ AddLocation (const Address &addr,
+ bool *new_location = NULL);
+
+ bool
+ RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp);
+
+ typedef std::vector<lldb::BreakpointLocationSP> collection;
+ typedef std::map<lldb_private::Address,
+ lldb::BreakpointLocationSP,
+ Address::ModulePointerAndOffsetLessThanFunctionObject> addr_map;
+
+ Breakpoint &m_owner;
+ collection m_locations;
+ addr_map m_address_to_location;
+ mutable Mutex m_mutex;
+ lldb::break_id_t m_next_id;
+ BreakpointLocationCollection *m_new_location_recorder;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointLocationList_h_
diff --git a/include/lldb/Breakpoint/BreakpointOptions.h b/include/lldb/Breakpoint/BreakpointOptions.h
new file mode 100644
index 000000000000..728f5932fa06
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointOptions.h
@@ -0,0 +1,358 @@
+//===-- BreakpointOptions.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_BreakpointOptions_h_
+#define liblldb_BreakpointOptions_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Baton.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointOptions BreakpointOptions.h "lldb/Breakpoint/BreakpointOptions.h"
+/// @brief Class that manages the options on a breakpoint or breakpoint location.
+//----------------------------------------------------------------------
+
+class BreakpointOptions
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ //------------------------------------------------------------------
+ /// Default constructor. The breakpoint is enabled, and has no condition,
+ /// callback, ignore count, etc...
+ //------------------------------------------------------------------
+ BreakpointOptions();
+ BreakpointOptions(const BreakpointOptions& rhs);
+
+ static BreakpointOptions *
+ CopyOptionsNoCallback (BreakpointOptions &rhs);
+ //------------------------------------------------------------------
+ /// This constructor allows you to specify all the breakpoint options.
+ ///
+ /// @param[in] condition
+ /// The expression which if it evaluates to \b true if we are to stop
+ ///
+ /// @param[in] callback
+ /// This is the plugin for some code that gets run, returns \b true if we are to stop.
+ ///
+ /// @param[in] baton
+ /// Client data that will get passed to the callback.
+ ///
+ /// @param[in] enabled
+ /// Is this breakpoint enabled.
+ ///
+ /// @param[in] ignore
+ /// How many breakpoint hits we should ignore before stopping.
+ ///
+ /// @param[in] thread_id
+ /// Only stop if \a thread_id hits the breakpoint.
+ //------------------------------------------------------------------
+ BreakpointOptions(void *condition,
+ BreakpointHitCallback callback,
+ void *baton,
+ bool enabled = true,
+ int32_t ignore = 0,
+ lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID,
+ bool one_shot = false);
+
+ virtual ~BreakpointOptions();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const BreakpointOptions&
+ operator=(const BreakpointOptions& rhs);
+
+ //------------------------------------------------------------------
+ // Callbacks
+ //
+ // Breakpoint callbacks come in two forms, synchronous and asynchronous. Synchronous callbacks will get
+ // run before any of the thread plans are consulted, and if they return false the target will continue
+ // "under the radar" of the thread plans. There are a couple of restrictions to synchronous callbacks:
+ // 1) They should NOT resume the target themselves. Just return false if you want the target to restart.
+ // 2) Breakpoints with synchronous callbacks can't have conditions (or rather, they can have them, but they
+ // won't do anything. Ditto with ignore counts, etc... You are supposed to control that all through the
+ // callback.
+ // Asynchronous callbacks get run as part of the "ShouldStop" logic in the thread plan. The logic there is:
+ // a) If the breakpoint is thread specific and not for this thread, continue w/o running the callback.
+ // b) If the ignore count says we shouldn't stop, then ditto.
+ // c) If the condition says we shouldn't stop, then ditto.
+ // d) Otherwise, the callback will get run, and if it returns true we will stop, and if false we won't.
+ // The asynchronous callback can run the target itself, but at present that should be the last action the
+ // callback does. We will relax this condition at some point, but it will take a bit of plumbing to get
+ // that to work.
+ //
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Adds a callback to the breakpoint option set.
+ ///
+ /// @param[in] callback
+ /// The function to be called when the breakpoint gets hit.
+ ///
+ /// @param[in] baton_sp
+ /// A baton which will get passed back to the callback when it is invoked.
+ ///
+ /// @param[in] synchronous
+ /// Whether this is a synchronous or asynchronous callback. See discussion above.
+ //------------------------------------------------------------------
+ void SetCallback (BreakpointHitCallback callback, const lldb::BatonSP &baton_sp, bool synchronous = false);
+
+
+ //------------------------------------------------------------------
+ /// Remove the callback from this option set.
+ //------------------------------------------------------------------
+ void ClearCallback ();
+
+ // The rest of these functions are meant to be used only within the breakpoint handling mechanism.
+
+ //------------------------------------------------------------------
+ /// Use this function to invoke the callback for a specific stop.
+ ///
+ /// @param[in] context
+ /// The context in which the callback is to be invoked. This includes the stop event, the
+ /// execution context of the stop (since you might hit the same breakpoint on multiple threads) and
+ /// whether we are currently executing synchronous or asynchronous callbacks.
+ ///
+ /// @param[in] break_id
+ /// The breakpoint ID that owns this option set.
+ ///
+ /// @param[in] break_loc_id
+ /// The breakpoint location ID that owns this option set.
+ ///
+ /// @return
+ /// The callback return value.
+ //------------------------------------------------------------------
+ bool InvokeCallback (StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+
+ //------------------------------------------------------------------
+ /// Used in InvokeCallback to tell whether it is the right time to run this kind of callback.
+ ///
+ /// @return
+ /// The synchronicity of our callback.
+ //------------------------------------------------------------------
+ bool IsCallbackSynchronous () {
+ return m_callback_is_synchronous;
+ }
+
+ //------------------------------------------------------------------
+ /// Fetch the baton from the callback.
+ ///
+ /// @return
+ /// The baton.
+ //------------------------------------------------------------------
+ Baton *GetBaton ();
+
+ //------------------------------------------------------------------
+ /// Fetch a const version of the baton from the callback.
+ ///
+ /// @return
+ /// The baton.
+ //------------------------------------------------------------------
+ const Baton *GetBaton () const;
+
+ //------------------------------------------------------------------
+ // Condition
+ //------------------------------------------------------------------
+ //------------------------------------------------------------------
+ /// Set the breakpoint option's condition.
+ ///
+ /// @param[in] condition
+ /// The condition expression to evaluate when the breakpoint is hit.
+ //------------------------------------------------------------------
+ void SetCondition (const char *condition);
+
+ //------------------------------------------------------------------
+ /// Return a pointer to the text of the condition expression.
+ ///
+ /// @return
+ /// A pointer to the condition expression text, or NULL if no
+ // condition has been set.
+ //------------------------------------------------------------------
+ const char *GetConditionText (size_t *hash = NULL) const;
+
+ //------------------------------------------------------------------
+ // Enabled/Ignore Count
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Check the Enable/Disable state.
+ /// @return
+ /// \b true if the breakpoint is enabled, \b false if disabled.
+ //------------------------------------------------------------------
+ bool
+ IsEnabled () const
+ {
+ return m_enabled;
+ }
+
+ //------------------------------------------------------------------
+ /// If \a enable is \b true, enable the breakpoint, if \b false disable it.
+ //------------------------------------------------------------------
+ void
+ SetEnabled (bool enabled)
+ {
+ m_enabled = enabled;
+ }
+
+ //------------------------------------------------------------------
+ /// Check the One-shot state.
+ /// @return
+ /// \b true if the breakpoint is one-shot, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsOneShot () const
+ {
+ return m_one_shot;
+ }
+
+ //------------------------------------------------------------------
+ /// If \a enable is \b true, enable the breakpoint, if \b false disable it.
+ //------------------------------------------------------------------
+ void
+ SetOneShot (bool one_shot)
+ {
+ m_one_shot = one_shot;
+ }
+
+ //------------------------------------------------------------------
+ /// Set the breakpoint to ignore the next \a count breakpoint hits.
+ /// @param[in] count
+ /// The number of breakpoint hits to ignore.
+ //------------------------------------------------------------------
+
+ void
+ SetIgnoreCount (uint32_t n)
+ {
+ m_ignore_count = n;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the current Ignore Count.
+ /// @return
+ /// The number of breakpoint hits to be ignored.
+ //------------------------------------------------------------------
+ uint32_t
+ GetIgnoreCount () const
+ {
+ return m_ignore_count;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the current thread spec for this option. This will return NULL if the no thread
+ /// specifications have been set for this Option yet.
+ /// @return
+ /// The thread specification pointer for this option, or NULL if none has
+ /// been set yet.
+ //------------------------------------------------------------------
+ const ThreadSpec *
+ GetThreadSpecNoCreate () const;
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the ThreadSpec for this option, creating it.
+ /// if it hasn't been created already. This API is used for setting the
+ /// ThreadSpec items for this option.
+ //------------------------------------------------------------------
+ ThreadSpec *
+ GetThreadSpec ();
+
+ void
+ SetThreadID(lldb::tid_t thread_id);
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ //------------------------------------------------------------------
+ /// Returns true if the breakpoint option has a callback set.
+ //------------------------------------------------------------------
+ bool
+ HasCallback();
+
+ //------------------------------------------------------------------
+ /// This is the default empty callback.
+ /// @return
+ /// The thread id for which the breakpoint hit will stop,
+ /// LLDB_INVALID_THREAD_ID for all threads.
+ //------------------------------------------------------------------
+ static bool
+ NullCallback (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+
+ struct CommandData
+ {
+ CommandData () :
+ user_source(),
+ script_source(),
+ stop_on_error(true)
+ {
+ }
+
+ ~CommandData ()
+ {
+ }
+
+ StringList user_source;
+ std::string script_source;
+ bool stop_on_error;
+ };
+
+ class CommandBaton : public Baton
+ {
+ public:
+ CommandBaton (CommandData *data) :
+ Baton (data)
+ {
+ }
+
+ virtual
+ ~CommandBaton ()
+ {
+ delete ((CommandData *)m_data);
+ m_data = NULL;
+ }
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ };
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from BreakpointOptions can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For BreakpointOptions only
+ //------------------------------------------------------------------
+ BreakpointHitCallback m_callback; // This is the callback function pointer
+ lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback
+ bool m_callback_is_synchronous;
+ bool m_enabled;
+ bool m_one_shot;
+ uint32_t m_ignore_count; // Number of times to ignore this breakpoint
+ std::unique_ptr<ThreadSpec> m_thread_spec_ap; // Thread for which this breakpoint will take
+ std::string m_condition_text; // The condition to test.
+ size_t m_condition_text_hash; // Its hash, so that locations know when the condition is updated.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointOptions_h_
diff --git a/include/lldb/Breakpoint/BreakpointResolver.h b/include/lldb/Breakpoint/BreakpointResolver.h
new file mode 100644
index 000000000000..3db3795453e8
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointResolver.h
@@ -0,0 +1,147 @@
+//===-- BreakpointResolver.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_BreakpointResolver_h_
+#define liblldb_BreakpointResolver_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/ConstString.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointResolver BreakpointResolver.h "lldb/Breakpoint/BreakpointResolver.h"
+/// @brief This class works with SearchFilter to resolve logical breakpoints to their
+/// of concrete breakpoint locations.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// The BreakpointResolver is a Searcher. In that protocol,
+/// the SearchFilter asks the question "At what depth of the symbol context
+/// descent do you want your callback to get called?" of the filter. The resolver
+/// answers this question (in the GetDepth method) and provides the resolution callback.
+/// Each Breakpoint has a BreakpointResolver, and it calls either ResolveBreakpoint
+/// or ResolveBreakpointInModules to tell it to look for new breakpoint locations.
+//----------------------------------------------------------------------
+
+class BreakpointResolver :
+ public Searcher
+{
+public:
+ //------------------------------------------------------------------
+ /// The breakpoint resolver need to have a breakpoint for "ResolveBreakpoint
+ /// to make sense. It can be constructed without a breakpoint, but you have to
+ /// call SetBreakpoint before ResolveBreakpoint.
+ ///
+ /// @param[in] bkpt
+ /// The breakpoint that owns this resolver.
+ /// @param[in] resolverType
+ /// The concrete breakpoint resolver type for this breakpoint.
+ ///
+ /// @result
+ /// Returns breakpoint location id.
+ //------------------------------------------------------------------
+ BreakpointResolver (Breakpoint *bkpt, unsigned char resolverType);
+
+ //------------------------------------------------------------------
+ /// The Destructor is virtual, all significant breakpoint resolvers derive
+ /// from this class.
+ //------------------------------------------------------------------
+ virtual
+ ~BreakpointResolver ();
+
+ //------------------------------------------------------------------
+ /// This sets the breakpoint for this resolver.
+ ///
+ /// @param[in] bkpt
+ /// The breakpoint that owns this resolver.
+ //------------------------------------------------------------------
+ void
+ SetBreakpoint (Breakpoint *bkpt);
+
+ //------------------------------------------------------------------
+ /// In response to this method the resolver scans all the modules in the breakpoint's
+ /// target, and adds any new locations it finds.
+ ///
+ /// @param[in] filter
+ /// The filter that will manage the search for this resolver.
+ //------------------------------------------------------------------
+ virtual void
+ ResolveBreakpoint (SearchFilter &filter);
+
+ //------------------------------------------------------------------
+ /// In response to this method the resolver scans the modules in the module list
+ /// \a modules, and adds any new locations it finds.
+ ///
+ /// @param[in] filter
+ /// The filter that will manage the search for this resolver.
+ //------------------------------------------------------------------
+ virtual void
+ ResolveBreakpointInModules (SearchFilter &filter,
+ ModuleList &modules);
+
+ //------------------------------------------------------------------
+ /// Prints a canonical description for the breakpoint to the stream \a s.
+ ///
+ /// @param[in] s
+ /// Stream to which the output is copied.
+ //------------------------------------------------------------------
+ virtual void
+ GetDescription (Stream *s) = 0;
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ virtual void
+ Dump (Stream *s) const = 0;
+
+ //------------------------------------------------------------------
+ /// An enumeration for keeping track of the concrete subclass that
+ /// is actually instantiated. Values of this enumeration are kept in the
+ /// BreakpointResolver's SubclassID field. They are used for concrete type
+ /// identification.
+ enum ResolverTy {
+ FileLineResolver, // This is an instance of BreakpointResolverFileLine
+ AddressResolver, // This is an instance of BreakpointResolverAddress
+ NameResolver, // This is an instance of BreakpointResolverName
+ FileRegexResolver,
+ ExceptionResolver
+ };
+
+ //------------------------------------------------------------------
+ /// getResolverID - Return an ID for the concrete type of this object. This
+ /// is used to implement the LLVM classof checks. This should not be used
+ /// for any other purpose, as the values may change as LLDB evolves.
+ unsigned getResolverID() const {
+ return SubclassID;
+ }
+
+protected:
+ Breakpoint *m_breakpoint; // This is the breakpoint we add locations to.
+
+private:
+ // Subclass identifier (for llvm isa/dyn_cast)
+ const unsigned char SubclassID;
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolver);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolver_h_
diff --git a/include/lldb/Breakpoint/BreakpointResolverAddress.h b/include/lldb/Breakpoint/BreakpointResolverAddress.h
new file mode 100644
index 000000000000..4ca4a405957e
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointResolverAddress.h
@@ -0,0 +1,74 @@
+//===-- BreakpointResolverAddress.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_BreakpointResolverAddress_h_
+#define liblldb_BreakpointResolverAddress_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointResolverAddress BreakpointResolverAddress.h "lldb/Breakpoint/BreakpointResolverAddress.h"
+/// @brief This class sets breakpoints on a given Address. This breakpoint only takes
+/// once, and then it won't attempt to reset itself.
+//----------------------------------------------------------------------
+
+class BreakpointResolverAddress:
+ public BreakpointResolver
+{
+public:
+ BreakpointResolverAddress (Breakpoint *bkpt,
+ const Address &addr);
+
+ virtual
+ ~BreakpointResolverAddress ();
+
+ virtual void
+ ResolveBreakpoint (SearchFilter &filter);
+
+ virtual void
+ ResolveBreakpointInModules (SearchFilter &filter,
+ ModuleList &modules);
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+ virtual void
+ Dump (Stream *s) const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const BreakpointResolverAddress *) { return true; }
+ static inline bool classof(const BreakpointResolver *V) {
+ return V->getResolverID() == BreakpointResolver::AddressResolver;
+ }
+
+protected:
+ Address m_addr;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverAddress);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverAddress_h_
diff --git a/include/lldb/Breakpoint/BreakpointResolverFileLine.h b/include/lldb/Breakpoint/BreakpointResolverFileLine.h
new file mode 100644
index 000000000000..cc1633ce1705
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointResolverFileLine.h
@@ -0,0 +1,74 @@
+//===-- BreakpointResolverFileLine.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_BreakpointResolverFileLine_h_
+#define liblldb_BreakpointResolverFileLine_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointResolverFileLine BreakpointResolverFileLine.h "lldb/Breakpoint/BreakpointResolverFileLine.h"
+/// @brief This class sets breakpoints by file and line. Optionally, it will look for inlined
+/// instances of the file and line specification.
+//----------------------------------------------------------------------
+
+class BreakpointResolverFileLine :
+ public BreakpointResolver
+{
+public:
+ BreakpointResolverFileLine (Breakpoint *bkpt,
+ const FileSpec &resolver,
+ uint32_t line_no,
+ bool check_inlines,
+ bool skip_prologue);
+
+ virtual
+ ~BreakpointResolverFileLine ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+ virtual void
+ Dump (Stream *s) const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const BreakpointResolverFileLine *) { return true; }
+ static inline bool classof(const BreakpointResolver *V) {
+ return V->getResolverID() == BreakpointResolver::FileLineResolver;
+ }
+
+protected:
+ friend class Breakpoint;
+ FileSpec m_file_spec; // This is the file spec we are looking for.
+ uint32_t m_line_number; // This is the line number that we are looking for.
+ bool m_inlines; // This determines whether the resolver looks for inlined functions or not.
+ bool m_skip_prologue;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileLine);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverFileLine_h_
diff --git a/include/lldb/Breakpoint/BreakpointResolverFileRegex.h b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
new file mode 100644
index 000000000000..f1c2b1409e92
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointResolverFileRegex.h
@@ -0,0 +1,68 @@
+//===-- BreakpointResolverFileRegex.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_BreakpointResolverFileRegex_h_
+#define liblldb_BreakpointResolverFileRegex_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointResolverFileRegex BreakpointResolverFileRegex.h "lldb/Breakpoint/BreakpointResolverFileRegex.h"
+/// @brief This class sets breakpoints by file and line. Optionally, it will look for inlined
+/// instances of the file and line specification.
+//----------------------------------------------------------------------
+
+class BreakpointResolverFileRegex :
+ public BreakpointResolver
+{
+public:
+ BreakpointResolverFileRegex (Breakpoint *bkpt,
+ RegularExpression &regex);
+
+ virtual
+ ~BreakpointResolverFileRegex ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+ virtual void
+ Dump (Stream *s) const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const BreakpointResolverFileRegex *) { return true; }
+ static inline bool classof(const BreakpointResolver *V) {
+ return V->getResolverID() == BreakpointResolver::FileRegexResolver;
+ }
+
+protected:
+ friend class Breakpoint;
+ RegularExpression m_regex; // This is the line expression that we are looking for.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverFileRegex);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverFileRegex_h_
diff --git a/include/lldb/Breakpoint/BreakpointResolverName.h b/include/lldb/Breakpoint/BreakpointResolverName.h
new file mode 100644
index 000000000000..f481aa9c5338
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointResolverName.h
@@ -0,0 +1,122 @@
+//===-- BreakpointResolverName.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_BreakpointResolverName_h_
+#define liblldb_BreakpointResolverName_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointResolverName BreakpointResolverName.h "lldb/Breakpoint/BreakpointResolverName.h"
+/// @brief This class sets breakpoints on a given function name, either by exact match
+/// or by regular expression.
+//----------------------------------------------------------------------
+
+class BreakpointResolverName:
+ public BreakpointResolver
+{
+public:
+
+ BreakpointResolverName (Breakpoint *bkpt,
+ const char *name,
+ uint32_t name_type_mask,
+ Breakpoint::MatchType type,
+ bool skip_prologue);
+
+ // This one takes an array of names. It is always MatchType = Exact.
+ BreakpointResolverName (Breakpoint *bkpt,
+ const char *names[],
+ size_t num_names,
+ uint32_t name_type_mask,
+ bool skip_prologue);
+
+ // This one takes a C++ array of names. It is always MatchType = Exact.
+ BreakpointResolverName (Breakpoint *bkpt,
+ std::vector<std::string> names,
+ uint32_t name_type_mask,
+ bool skip_prologue);
+
+ // Creates a function breakpoint by regular expression. Takes over control of the lifespan of func_regex.
+ BreakpointResolverName (Breakpoint *bkpt,
+ RegularExpression &func_regex,
+ bool skip_prologue);
+
+ BreakpointResolverName (Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type,
+ bool skip_prologue);
+
+ virtual
+ ~BreakpointResolverName ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+ virtual void
+ Dump (Stream *s) const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const BreakpointResolverName *) { return true; }
+ static inline bool classof(const BreakpointResolver *V) {
+ return V->getResolverID() == BreakpointResolver::NameResolver;
+ }
+
+protected:
+ struct LookupInfo
+ {
+ ConstString name;
+ ConstString lookup_name;
+ uint32_t name_type_mask; // See FunctionNameType
+ bool match_name_after_lookup;
+
+ LookupInfo () :
+ name(),
+ lookup_name(),
+ name_type_mask (0),
+ match_name_after_lookup (false)
+ {
+ }
+
+ void
+ Prune (SymbolContextList &sc_list,
+ size_t start_idx) const;
+ };
+ std::vector<LookupInfo> m_lookups;
+ ConstString m_class_name;
+ RegularExpression m_regex;
+ Breakpoint::MatchType m_match_type;
+ bool m_skip_prologue;
+
+ void
+ AddNameLookup (const ConstString &name, uint32_t name_type_mask);
+private:
+ DISALLOW_COPY_AND_ASSIGN(BreakpointResolverName);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointResolverName_h_
diff --git a/include/lldb/Breakpoint/BreakpointSite.h b/include/lldb/Breakpoint/BreakpointSite.h
new file mode 100644
index 000000000000..271a23c2e451
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointSite.h
@@ -0,0 +1,295 @@
+//===-- BreakpointSite.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_BreakpointSite_h_
+#define liblldb_BreakpointSite_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Breakpoint/StoppointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointSite BreakpointSite.h "lldb/Breakpoint/BreakpointSite.h"
+/// @brief Class that manages the actual breakpoint that will be inserted
+/// into the running program.
+///
+/// The BreakpointSite class handles the physical breakpoint that is
+/// actually inserted in the target program. As such, it is also the
+/// one that gets hit, when the program stops. It keeps a list of all
+/// BreakpointLocations that share this phsyical site. When the
+/// breakpoint is hit, all the locations are informed by the breakpoint
+/// site. Breakpoint sites are owned by the process.
+//----------------------------------------------------------------------
+
+class BreakpointSite :
+ public std::enable_shared_from_this<BreakpointSite>,
+ public StoppointLocation
+{
+public:
+
+ enum Type
+ {
+ eSoftware, // Breakpoint opcode has been written to memory and m_saved_opcode
+ // and m_trap_opcode contain the saved and written opcode.
+ eHardware, // Breakpoint site is set as a hardware breakpoint
+ eExternal // Breakpoint site is managed by an external debug nub or
+ // debug interface where memory reads trasparently will not
+ // display any breakpoint opcodes.
+ };
+
+ virtual ~BreakpointSite ();
+
+ //----------------------------------------------------------------------
+ // This section manages the breakpoint traps
+ //----------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Returns the Opcode Bytes for this breakpoint
+ //------------------------------------------------------------------
+ uint8_t *
+ GetTrapOpcodeBytes ();
+
+ //------------------------------------------------------------------
+ /// Returns the Opcode Bytes for this breakpoint - const version
+ //------------------------------------------------------------------
+ const uint8_t *
+ GetTrapOpcodeBytes () const;
+
+ //------------------------------------------------------------------
+ /// Get the size of the trap opcode for this address
+ //------------------------------------------------------------------
+ size_t
+ GetTrapOpcodeMaxByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Sets the trap opcode
+ //------------------------------------------------------------------
+ bool
+ SetTrapOpcode (const uint8_t *trap_opcode,
+ uint32_t trap_opcode_size);
+
+ //------------------------------------------------------------------
+ /// Gets the original instruction bytes that were overwritten by the trap
+ //------------------------------------------------------------------
+ uint8_t *
+ GetSavedOpcodeBytes ();
+
+ //------------------------------------------------------------------
+ /// Gets the original instruction bytes that were overwritten by the trap const version
+ //------------------------------------------------------------------
+ const uint8_t *
+ GetSavedOpcodeBytes () const;
+
+ //------------------------------------------------------------------
+ /// Says whether \a addr and size \a size intersects with the address \a intersect_addr
+ //------------------------------------------------------------------
+ bool
+ IntersectsRange (lldb::addr_t addr,
+ size_t size,
+ lldb::addr_t *intersect_addr,
+ size_t *intersect_size,
+ size_t *opcode_offset) const;
+
+ //------------------------------------------------------------------
+ /// Tells whether the current breakpoint site is enabled or not
+ ///
+ /// This is a low-level enable bit for the breakpoint sites. If a
+ /// breakpoint site has no enabled owners, it should just get
+ /// removed. This enable/disable is for the low-level target code
+ /// to enable and disable breakpoint sites when single stepping,
+ /// etc.
+ //------------------------------------------------------------------
+ bool
+ IsEnabled () const;
+
+ //------------------------------------------------------------------
+ /// Sets whether the current breakpoint site is enabled or not
+ ///
+ /// @param[in] enabled
+ /// \b true if the breakoint is enabled, \b false otherwise.
+ //------------------------------------------------------------------
+ void
+ SetEnabled (bool enabled);
+
+ //------------------------------------------------------------------
+ /// Enquires of the breakpoint locations that produced this breakpoint site whether
+ /// we should stop at this location.
+ ///
+ /// @param[in] context
+ /// This contains the information about this stop.
+ ///
+ /// @return
+ /// \b true if we should stop, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ShouldStop (StoppointCallbackContext *context);
+
+ //------------------------------------------------------------------
+ /// Standard Dump method
+ ///
+ /// @param[in] context
+ /// The stream to dump this output.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// The "Owners" are the breakpoint locations that share this
+ /// breakpoint site. The method adds the \a owner to this breakpoint
+ /// site's owner list.
+ ///
+ /// @param[in] context
+ /// \a owner is the Breakpoint Location to add.
+ //------------------------------------------------------------------
+ void
+ AddOwner (const lldb::BreakpointLocationSP &owner);
+
+ //------------------------------------------------------------------
+ /// This method returns the number of breakpoint locations currently
+ /// located at this breakpoint site.
+ ///
+ /// @return
+ /// The number of owners.
+ //------------------------------------------------------------------
+ size_t
+ GetNumberOfOwners ();
+
+ //------------------------------------------------------------------
+ /// This method returns the the breakpoint location at index \a index
+ /// located at this breakpoint site. The owners are listed ordinally
+ /// from 0 to GetNumberOfOwners() - 1 so you can use this method to iterate
+ /// over the owners
+ ///
+ /// @param[in] index
+ /// The index in the list of owners for which you wish the owner location.
+ /// @return
+ /// A shared pointer to the breakpoint location at that index.
+ //------------------------------------------------------------------
+ lldb::BreakpointLocationSP
+ GetOwnerAtIndex (size_t idx);
+
+ //------------------------------------------------------------------
+ /// Check whether the owners of this breakpoint site have any
+ /// thread specifiers, and if yes, is \a thread contained in any
+ /// of these specifiers.
+ ///
+ /// @param[in] thread
+ /// The thread against which to test.
+ ///
+ /// return
+ /// \b true if the collection contains at least one location that
+ /// would be valid for this thread, false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ValidForThisThread (Thread *thread);
+
+
+ //------------------------------------------------------------------
+ /// Print a description of this breakpoint site to the stream \a s.
+ /// GetDescription tells you about the breakpoint site's owners.
+ /// Use BreakpointSite::Dump(Stream *) to get information about the
+ /// breakpoint site itself.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ //------------------------------------------------------------------
+ /// Tell whether a breakpoint has a location at this site.
+ ///
+ /// @param[in] bp_id
+ /// The breakpoint id to query.
+ ///
+ /// @result
+ /// \b true if bp_id has a location that is at this site,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsBreakpointAtThisSite (lldb::break_id_t bp_id);
+
+ //------------------------------------------------------------------
+ /// Tell whether ALL the breakpoints in the location collection are internal.
+ ///
+ /// @result
+ /// \b true if all breakpoint locations are owned by internal breakpoints,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsInternal () const;
+
+ BreakpointSite::Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ void
+ SetType (BreakpointSite::Type type)
+ {
+ m_type = type;
+ }
+
+private:
+ friend class Process;
+
+ //------------------------------------------------------------------
+ /// The method removes the owner at \a break_loc_id from this breakpoint list.
+ ///
+ /// @param[in] context
+ /// \a break_loc_id is the Breakpoint Location to remove.
+ //------------------------------------------------------------------
+ size_t
+ RemoveOwner (lldb::break_id_t break_id,
+ lldb::break_id_t break_loc_id);
+
+ BreakpointSite::Type m_type;///< The type of this breakpoint site.
+ uint8_t m_saved_opcode[8]; ///< The saved opcode bytes if this breakpoint site uses trap opcodes.
+ uint8_t m_trap_opcode[8]; ///< The opcode that was used to create the breakpoint if it is a software breakpoint site.
+ bool m_enabled; ///< Boolean indicating if this breakpoint site enabled or not.
+
+ // Consider adding an optimization where if there is only one
+ // owner, we don't store a list. The usual case will be only one owner...
+ BreakpointLocationCollection m_owners; ///< This has the BreakpointLocations that share this breakpoint site.
+
+ static lldb::break_id_t
+ GetNextID();
+
+ // Only the Process can create breakpoint sites in
+ // Process::CreateBreakpointSite (lldb::BreakpointLocationSP &, bool).
+ BreakpointSite (BreakpointSiteList *list,
+ const lldb::BreakpointLocationSP& owner,
+ lldb::addr_t m_addr,
+ bool use_hardware);
+
+ DISALLOW_COPY_AND_ASSIGN(BreakpointSite);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointSite_h_
diff --git a/include/lldb/Breakpoint/BreakpointSiteList.h b/include/lldb/Breakpoint/BreakpointSiteList.h
new file mode 100644
index 000000000000..0d4dafc4baab
--- /dev/null
+++ b/include/lldb/Breakpoint/BreakpointSiteList.h
@@ -0,0 +1,216 @@
+//===-- BreakpointSiteList.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_BreakpointSiteList_h_
+#define liblldb_BreakpointSiteList_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class BreakpointSiteList BreakpointSiteList.h "lldb/Breakpoint/BreakpointSiteList.h"
+/// @brief Class that manages lists of BreakpointSite shared pointers.
+//----------------------------------------------------------------------
+class BreakpointSiteList
+{
+// At present Process directly accesses the map of BreakpointSites so it can
+// do quick lookups into the map (using GetMap).
+// FIXME: Find a better interface for this.
+friend class Process;
+
+public:
+ //------------------------------------------------------------------
+ /// Default constructor makes an empty list.
+ //------------------------------------------------------------------
+ BreakpointSiteList();
+
+ //------------------------------------------------------------------
+ /// Destructor, currently does nothing.
+ //------------------------------------------------------------------
+ ~BreakpointSiteList();
+
+ //------------------------------------------------------------------
+ /// Add a BreakpointSite to the list.
+ ///
+ /// @param[in] bp_site_sp
+ /// A shared pointer to a breakpoint site being added to the list.
+ ///
+ /// @return
+ /// The ID of the BreakpointSite in the list.
+ //------------------------------------------------------------------
+ lldb::break_id_t
+ Add (const lldb::BreakpointSiteSP& bp_site_sp);
+
+ //------------------------------------------------------------------
+ /// Standard Dump routine, doesn't do anything at present.
+ /// @param[in] s
+ /// Stream into which to dump the description.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint site at address
+ /// \a addr.
+ ///
+ /// @param[in] addr
+ /// The address to look for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint site. May contain a NULL
+ /// pointer if no breakpoint site exists with a matching address.
+ //------------------------------------------------------------------
+ lldb::BreakpointSiteSP
+ FindByAddress (lldb::addr_t addr);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint site with id \a breakID.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint site ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint site. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::BreakpointSiteSP
+ FindByID (lldb::break_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the breakpoint site with id \a breakID - const version.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint site ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the breakpoint site. May contain a NULL pointer if the
+ /// breakpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::BreakpointSiteSP
+ FindByID (lldb::break_id_t breakID) const;
+
+ //------------------------------------------------------------------
+ /// Returns the breakpoint site id to the breakpoint site at address \a addr.
+ ///
+ /// @param[in] addr
+ /// The address to match.
+ ///
+ /// @result
+ /// The ID of the breakpoint site, or LLDB_INVALID_BREAK_ID.
+ //------------------------------------------------------------------
+ lldb::break_id_t
+ FindIDByAddress (lldb::addr_t addr);
+
+ //------------------------------------------------------------------
+ /// Returns whether the breakpoint site \a bp_site_id has \a bp_id
+ // as one of its owners.
+ ///
+ /// @param[in] bp_site_id
+ /// The breakpoint site id to query.
+ ///
+ /// @param[in] bp_id
+ /// The breakpoint id to look for in \a bp_site_id.
+ ///
+ /// @result
+ /// True if \a bp_site_id exists in the site list AND \a bp_id is one of the
+ /// owners of that site.
+ //------------------------------------------------------------------
+ bool
+ BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id);
+
+ void
+ ForEach (std::function <void(BreakpointSite *)> const &callback);
+
+ //------------------------------------------------------------------
+ /// Removes the breakpoint site given by \b breakID from this list.
+ ///
+ /// @param[in] breakID
+ /// The breakpoint site index to remove.
+ ///
+ /// @result
+ /// \b true if the breakpoint site \a breakID was in the list.
+ //------------------------------------------------------------------
+ bool
+ Remove (lldb::break_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Removes the breakpoint site at address \a addr from this list.
+ ///
+ /// @param[in] addr
+ /// The address from which to remove a breakpoint site.
+ ///
+ /// @result
+ /// \b true if \a addr had a breakpoint site to remove from the list.
+ //------------------------------------------------------------------
+ bool
+ RemoveByAddress (lldb::addr_t addr);
+
+ bool
+ FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const;
+
+ typedef void (*BreakpointSiteSPMapFunc) (lldb::BreakpointSiteSP &bp, void *baton);
+
+ //------------------------------------------------------------------
+ /// Enquires of the breakpoint site on in this list with ID \a breakID whether
+ /// we should stop for the breakpoint or not.
+ ///
+ /// @param[in] context
+ /// This contains the information about this stop.
+ ///
+ /// @param[in] breakID
+ /// This break ID that we hit.
+ ///
+ /// @return
+ /// \b true if we should stop, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldStop (StoppointCallbackContext *context, lldb::break_id_t breakID);
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in the list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_bp_site_list.size();
+ }
+
+ bool
+ IsEmpty() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_bp_site_list.empty();
+ }
+protected:
+ typedef std::map<lldb::addr_t, lldb::BreakpointSiteSP> collection;
+
+ collection::iterator
+ GetIDIterator(lldb::break_id_t breakID);
+
+ collection::const_iterator
+ GetIDConstIterator(lldb::break_id_t breakID) const;
+
+ mutable Mutex m_mutex;
+ collection m_bp_site_list; // The breakpoint site list.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_BreakpointSiteList_h_
diff --git a/include/lldb/Breakpoint/Stoppoint.h b/include/lldb/Breakpoint/Stoppoint.h
new file mode 100644
index 000000000000..c294830f15ec
--- /dev/null
+++ b/include/lldb/Breakpoint/Stoppoint.h
@@ -0,0 +1,63 @@
+//===-- Stoppoint.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_Stoppoint_h_
+#define liblldb_Stoppoint_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+
+namespace lldb_private {
+
+class Stoppoint
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Stoppoint();
+
+ virtual
+ ~Stoppoint();
+
+ //------------------------------------------------------------------
+ // Methods
+ //------------------------------------------------------------------
+ virtual void
+ Dump (Stream *) = 0;
+
+ virtual bool
+ IsEnabled () = 0;
+
+ virtual void
+ SetEnabled (bool enable) = 0;
+
+ lldb::break_id_t
+ GetID () const;
+
+ void
+ SetID (lldb::break_id_t bid);
+
+protected:
+ lldb::break_id_t m_bid;
+
+private:
+ //------------------------------------------------------------------
+ // For Stoppoint only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Stoppoint);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Stoppoint_h_
diff --git a/include/lldb/Breakpoint/StoppointCallbackContext.h b/include/lldb/Breakpoint/StoppointCallbackContext.h
new file mode 100644
index 000000000000..78327e291340
--- /dev/null
+++ b/include/lldb/Breakpoint/StoppointCallbackContext.h
@@ -0,0 +1,58 @@
+//===-- StoppointCallbackContext.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_StoppointCallbackContext_h_
+#define liblldb_StoppointCallbackContext_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class StoppointCallbackContext StoppointCallbackContext.h "lldb/Breakpoint/StoppointCallbackContext.h"
+/// @brief Class holds the information that a breakpoint callback needs to evaluate this stop.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// When we hit a breakpoint we need to package up whatever information is needed
+/// to evaluate breakpoint commands and conditions. This class is the container of
+/// that information.
+//----------------------------------------------------------------------
+
+class StoppointCallbackContext
+{
+public:
+ StoppointCallbackContext();
+
+ StoppointCallbackContext(Event *event, const ExecutionContext &exe_ctx, bool synchronously = false);
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the event, process and thread to NULL, and the frame index to an
+ /// invalid value.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Event *event; // This is the event, the callback can modify this to indicate
+ // the meaning of the breakpoint hit
+ ExecutionContextRef exe_ctx_ref; // This tells us where we have stopped, what thread.
+ bool is_synchronous; // Is the callback being executed synchronously with the breakpoint,
+ // or asynchronously as the event is retrieved?
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StoppointCallbackContext_h_
diff --git a/include/lldb/Breakpoint/StoppointLocation.h b/include/lldb/Breakpoint/StoppointLocation.h
new file mode 100644
index 000000000000..ccedc511951d
--- /dev/null
+++ b/include/lldb/Breakpoint/StoppointLocation.h
@@ -0,0 +1,147 @@
+//===-- StoppointLocation.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_StoppointLocation_h_
+#define liblldb_StoppointLocation_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+// #include "lldb/Breakpoint/BreakpointOptions.h"
+
+namespace lldb_private {
+
+class StoppointLocation
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StoppointLocation (lldb::break_id_t bid,
+ lldb::addr_t m_addr,
+ bool hardware);
+
+ StoppointLocation (lldb::break_id_t bid,
+ lldb::addr_t m_addr,
+ uint32_t byte_size,
+ bool hardware);
+
+ virtual
+ ~StoppointLocation ();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ // Methods
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetLoadAddress() const
+ {
+ return m_addr;
+ }
+
+ virtual void
+ SetLoadAddress (lldb::addr_t addr)
+ {
+ m_addr = addr;
+ }
+
+ uint32_t
+ GetByteSize () const
+ {
+ return m_byte_size;
+ }
+
+ uint32_t
+ GetHitCount () const
+ {
+ return m_hit_count;
+ }
+
+ uint32_t
+ GetHardwareIndex () const
+ {
+ return m_hw_index;
+ }
+
+
+ bool
+ HardwarePreferred () const
+ {
+ return m_hw_preferred;
+ }
+
+ virtual bool
+ IsHardware () const
+ {
+ return m_hw_index != LLDB_INVALID_INDEX32;
+ }
+
+
+ virtual bool
+ ShouldStop (StoppointCallbackContext *context)
+ {
+ return true;
+ }
+
+ virtual void
+ Dump (Stream *stream) const
+ {
+ }
+
+ void
+ SetHardwareIndex (uint32_t index)
+ {
+ m_hw_index = index;
+ }
+
+
+ lldb::break_id_t
+ GetID () const
+ {
+ return m_loc_id;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StoppointLocation can see and modify these
+ //------------------------------------------------------------------
+ lldb::break_id_t m_loc_id; // Stoppoint location ID
+ lldb::addr_t m_addr; // The load address of this stop point. The base Stoppoint doesn't
+ // store a full Address since that's not needed for the breakpoint sites.
+ bool m_hw_preferred; // 1 if this point has been requested to be set using hardware (which may fail due to lack of resources)
+ uint32_t m_hw_index; // The hardware resource index for this breakpoint/watchpoint
+ uint32_t m_byte_size; // The size in bytes of stop location. e.g. the length of the trap opcode for
+ // software breakpoints, or the optional length in bytes for
+ // hardware breakpoints, or the length of the watchpoint.
+ uint32_t m_hit_count; // Number of times this breakpoint/watchpoint has been hit
+
+ // If you override this, be sure to call the base class to increment the internal counter.
+ void
+ IncrementHitCount ()
+ {
+ ++m_hit_count;
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For StoppointLocation only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN(StoppointLocation);
+ StoppointLocation(); // Disallow default constructor
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StoppointLocation_h_
diff --git a/include/lldb/Breakpoint/Watchpoint.h b/include/lldb/Breakpoint/Watchpoint.h
new file mode 100644
index 000000000000..5dbed03d5406
--- /dev/null
+++ b/include/lldb/Breakpoint/Watchpoint.h
@@ -0,0 +1,252 @@
+//===-- Watchpoint.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_Watchpoint_h_
+#define liblldb_Watchpoint_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Breakpoint/WatchpointOptions.h"
+#include "lldb/Breakpoint/StoppointLocation.h"
+
+namespace lldb_private {
+
+class Watchpoint :
+ public std::enable_shared_from_this<Watchpoint>,
+ public StoppointLocation
+{
+public:
+
+ class WatchpointEventData :
+ public EventData
+ {
+ public:
+
+ static const ConstString &
+ GetFlavorString ();
+
+ virtual const ConstString &
+ GetFlavor () const;
+
+ WatchpointEventData (lldb::WatchpointEventType sub_type,
+ const lldb::WatchpointSP &new_watchpoint_sp);
+
+ virtual
+ ~WatchpointEventData();
+
+ lldb::WatchpointEventType
+ GetWatchpointEventType () const;
+
+ lldb::WatchpointSP &
+ GetWatchpoint ();
+
+ virtual void
+ Dump (Stream *s) const;
+
+ static lldb::WatchpointEventType
+ GetWatchpointEventTypeFromEvent (const lldb::EventSP &event_sp);
+
+ static lldb::WatchpointSP
+ GetWatchpointFromEvent (const lldb::EventSP &event_sp);
+
+ static const WatchpointEventData *
+ GetEventDataFromEvent (const Event *event_sp);
+
+ private:
+
+ lldb::WatchpointEventType m_watchpoint_event;
+ lldb::WatchpointSP m_new_watchpoint_sp;
+
+ DISALLOW_COPY_AND_ASSIGN (WatchpointEventData);
+ };
+
+ Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const ClangASTType *type, bool hardware = true);
+ ~Watchpoint ();
+
+ void
+ IncrementFalseAlarmsAndReviseHitCount();
+
+ bool
+ IsEnabled () const;
+
+ void
+ SetEnabled (bool enabled, bool notify = true);
+
+ virtual bool
+ IsHardware () const;
+
+ virtual bool
+ ShouldStop (StoppointCallbackContext *context);
+
+ bool WatchpointRead () const;
+ bool WatchpointWrite () const;
+ uint32_t GetIgnoreCount () const;
+ void SetIgnoreCount (uint32_t n);
+ void SetWatchpointType (uint32_t type, bool notify = true);
+ void SetDeclInfo (const std::string &str);
+ std::string GetWatchSpec();
+ void SetWatchSpec (const std::string &str);
+
+ // Snapshot management interface.
+ bool IsWatchVariable() const;
+ void SetWatchVariable(bool val);
+ bool CaptureWatchedValue (const ExecutionContext &exe_ctx);
+
+ void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ void Dump (Stream *s) const;
+ void DumpSnapshots (Stream *s, const char * prefix = NULL) const;
+ void DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const;
+ Target &GetTarget() { return m_target; }
+ const Error &GetError() { return m_error; }
+
+ //------------------------------------------------------------------
+ /// Returns the WatchpointOptions structure set for this watchpoint.
+ ///
+ /// @return
+ /// A pointer to this watchpoint's WatchpointOptions.
+ //------------------------------------------------------------------
+ WatchpointOptions *
+ GetOptions () { return &m_options; }
+
+ //------------------------------------------------------------------
+ /// Set the callback action invoked when the watchpoint is hit.
+ ///
+ /// @param[in] callback
+ /// The method that will get called when the watchpoint is hit.
+ /// @param[in] callback_baton
+ /// A void * pointer that will get passed back to the callback function.
+ /// @param[in] is_synchronous
+ /// If \b true the callback will be run on the private event thread
+ /// before the stop event gets reported. If false, the callback will get
+ /// handled on the public event thead after the stop has been posted.
+ ///
+ /// @return
+ /// \b true if the process should stop when you hit the watchpoint.
+ /// \b false if it should continue.
+ //------------------------------------------------------------------
+ void
+ SetCallback (WatchpointHitCallback callback,
+ void *callback_baton,
+ bool is_synchronous = false);
+
+ void
+ SetCallback (WatchpointHitCallback callback,
+ const lldb::BatonSP &callback_baton_sp,
+ bool is_synchronous = false);
+
+ void ClearCallback();
+
+ //------------------------------------------------------------------
+ /// Invoke the callback action when the watchpoint is hit.
+ ///
+ /// @param[in] context
+ /// Described the watchpoint event.
+ ///
+ /// @return
+ /// \b true if the target should stop at this watchpoint and \b false not.
+ //------------------------------------------------------------------
+ bool
+ InvokeCallback (StoppointCallbackContext *context);
+
+ //------------------------------------------------------------------
+ // Condition
+ //------------------------------------------------------------------
+ //------------------------------------------------------------------
+ /// Set the watchpoint's condition.
+ ///
+ /// @param[in] condition
+ /// The condition expression to evaluate when the watchpoint is hit.
+ /// Pass in NULL to clear the condition.
+ //------------------------------------------------------------------
+ void SetCondition (const char *condition);
+
+ //------------------------------------------------------------------
+ /// Return a pointer to the text of the condition expression.
+ ///
+ /// @return
+ /// A pointer to the condition expression text, or NULL if no
+ // condition has been set.
+ //------------------------------------------------------------------
+ const char *GetConditionText () const;
+
+ void
+ TurnOnEphemeralMode();
+
+ void
+ TurnOffEphemeralMode();
+
+ bool
+ IsDisabledDuringEphemeralMode();
+
+ const ClangASTType &
+ GetClangASTType()
+ {
+ return m_type;
+ }
+
+
+private:
+ friend class Target;
+ friend class WatchpointList;
+
+ void ResetHitCount() { m_hit_count = 0; }
+
+ Target &m_target;
+ bool m_enabled; // Is this watchpoint enabled
+ bool m_is_hardware; // Is this a hardware watchpoint
+ bool m_is_watch_variable; // True if set via 'watchpoint set variable'.
+ bool m_is_ephemeral; // True if the watchpoint is in the ephemeral mode, meaning that it is
+ // undergoing a pair of temporary disable/enable actions to avoid recursively
+ // triggering further watchpoint events.
+ uint32_t m_disabled_count; // Keep track of the count that the watchpoint is disabled while in ephemeral mode.
+ // At the end of the ephemeral mode when the watchpoint is to be enabled agian,
+ // we check the count, if it is more than 1, it means the user-supplied actions
+ // actually want the watchpoint to be disabled!
+ uint32_t m_watch_read:1, // 1 if we stop when the watched data is read from
+ m_watch_write:1, // 1 if we stop when the watched data is written to
+ m_watch_was_read:1, // Set to 1 when watchpoint is hit for a read access
+ m_watch_was_written:1; // Set to 1 when watchpoint is hit for a write access
+ uint32_t m_ignore_count; // Number of times to ignore this watchpoint
+ uint32_t m_false_alarms; // Number of false alarms.
+ std::string m_decl_str; // Declaration information, if any.
+ std::string m_watch_spec_str; // Spec for the watchpoint.
+ lldb::ValueObjectSP m_old_value_sp;
+ lldb::ValueObjectSP m_new_value_sp;
+ ClangASTType m_type;
+ Error m_error; // An error object describing errors associated with this watchpoint.
+ WatchpointOptions m_options; // Settable watchpoint options, which is a delegate to handle
+ // the callback machinery.
+ bool m_being_created;
+
+ std::unique_ptr<ClangUserExpression> m_condition_ap; // The condition to test.
+
+ void SetID(lldb::watch_id_t id) { m_loc_id = id; }
+
+ void
+ SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind);
+
+ void
+ SendWatchpointChangedEvent (WatchpointEventData *data);
+
+ DISALLOW_COPY_AND_ASSIGN (Watchpoint);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Watchpoint_h_
diff --git a/include/lldb/Breakpoint/WatchpointList.h b/include/lldb/Breakpoint/WatchpointList.h
new file mode 100644
index 000000000000..d16cb25e3b7d
--- /dev/null
+++ b/include/lldb/Breakpoint/WatchpointList.h
@@ -0,0 +1,276 @@
+//===-- WatchpointList.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_WatchpointList_h_
+#define liblldb_WatchpointList_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class WatchpointList WatchpointList.h "lldb/Breakpoint/WatchpointList.h"
+/// @brief This class is used by Watchpoint to manage a list of watchpoints,
+// each watchpoint in the list has a unique ID, and is unique by Address as
+// well.
+//----------------------------------------------------------------------
+
+class WatchpointList
+{
+// Only Target can make the watchpoint list, or add elements to it.
+// This is not just some random collection of watchpoints. Rather, the act of
+// adding the watchpoint to this list sets its ID.
+friend class Watchpoint;
+friend class Target;
+
+public:
+ //------------------------------------------------------------------
+ /// Default constructor makes an empty list.
+ //------------------------------------------------------------------
+ WatchpointList();
+
+ //------------------------------------------------------------------
+ /// Destructor, currently does nothing.
+ //------------------------------------------------------------------
+ ~WatchpointList();
+
+ //------------------------------------------------------------------
+ /// Add a Watchpoint to the list.
+ ///
+ /// @param[in] wp_sp
+ /// A shared pointer to a watchpoint being added to the list.
+ ///
+ /// @return
+ /// The ID of the Watchpoint in the list.
+ //------------------------------------------------------------------
+ lldb::watch_id_t
+ Add (const lldb::WatchpointSP& wp_sp, bool notify);
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Dump with lldb::DescriptionLevel.
+ //------------------------------------------------------------------
+ void
+ DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the watchpoint at address
+ /// \a addr -
+ /// const version.
+ ///
+ /// @param[in] addr
+ /// The address to look for.
+ ///
+ /// @result
+ /// A shared pointer to the watchpoint. May contain a NULL
+ /// pointer if the watchpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::WatchpointSP
+ FindByAddress (lldb::addr_t addr) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the watchpoint with watchpoint spec
+ /// \a spec -
+ /// const version.
+ ///
+ /// @param[in] spec
+ /// The watchpoint spec to look for.
+ ///
+ /// @result
+ /// A shared pointer to the watchpoint. May contain a NULL
+ /// pointer if the watchpoint doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::WatchpointSP
+ FindBySpec (std::string spec) const;
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the watchpoint with id
+ /// \a watchID, const
+ /// version.
+ ///
+ /// @param[in] watchID
+ /// The watchpoint location ID to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the watchpoint. May contain a NULL
+ /// pointer if the watchpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::WatchpointSP
+ FindByID (lldb::watch_id_t watchID) const;
+
+ //------------------------------------------------------------------
+ /// Returns the watchpoint id to the watchpoint
+ /// at address \a addr.
+ ///
+ /// @param[in] addr
+ /// The address to match.
+ ///
+ /// @result
+ /// The ID of the watchpoint, or LLDB_INVALID_WATCH_ID.
+ //------------------------------------------------------------------
+ lldb::watch_id_t
+ FindIDByAddress (lldb::addr_t addr);
+
+ //------------------------------------------------------------------
+ /// Returns the watchpoint id to the watchpoint
+ /// with watchpoint spec \a spec.
+ ///
+ /// @param[in] spec
+ /// The watchpoint spec to match.
+ ///
+ /// @result
+ /// The ID of the watchpoint, or LLDB_INVALID_WATCH_ID.
+ //------------------------------------------------------------------
+ lldb::watch_id_t
+ FindIDBySpec (std::string spec);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the watchpoint with index \a i.
+ ///
+ /// @param[in] i
+ /// The watchpoint index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the watchpoint. May contain a NULL pointer if
+ /// the watchpoint doesn't exist.
+ //------------------------------------------------------------------
+ lldb::WatchpointSP
+ GetByIndex (uint32_t i);
+
+ //------------------------------------------------------------------
+ /// Returns a shared pointer to the watchpoint with index \a i, const
+ /// version.
+ ///
+ /// @param[in] i
+ /// The watchpoint index to seek for.
+ ///
+ /// @result
+ /// A shared pointer to the watchpoint. May contain a NULL pointer if
+ /// the watchpoint location doesn't exist.
+ //------------------------------------------------------------------
+ const lldb::WatchpointSP
+ GetByIndex (uint32_t i) const;
+
+ //------------------------------------------------------------------
+ /// Removes the watchpoint given by \b watchID from this list.
+ ///
+ /// @param[in] watchID
+ /// The watchpoint ID to remove.
+ ///
+ /// @result
+ /// \b true if the watchpoint \a watchID was in the list.
+ //------------------------------------------------------------------
+ bool
+ Remove (lldb::watch_id_t watchID, bool notify);
+
+ //------------------------------------------------------------------
+ /// Returns the number hit count of all watchpoints in this list.
+ ///
+ /// @result
+ /// Hit count of all watchpoints in this list.
+ //------------------------------------------------------------------
+ uint32_t
+ GetHitCount () const;
+
+ //------------------------------------------------------------------
+ /// Enquires of the watchpoint in this list with ID \a watchID whether we
+ /// should stop.
+ ///
+ /// @param[in] context
+ /// This contains the information about this stop.
+ ///
+ /// @param[in] watchID
+ /// This watch ID that we hit.
+ ///
+ /// @return
+ /// \b true if we should stop, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldStop (StoppointCallbackContext *context,
+ lldb::watch_id_t watchID);
+
+ //------------------------------------------------------------------
+ /// Returns the number of elements in this watchpoint list.
+ ///
+ /// @result
+ /// The number of elements.
+ //------------------------------------------------------------------
+ size_t
+ GetSize() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_watchpoints.size();
+ }
+
+ //------------------------------------------------------------------
+ /// Print a description of the watchpoints in this list to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The description level that indicates the detail level to
+ /// provide.
+ ///
+ /// @see lldb::DescriptionLevel
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ void
+ SetEnabledAll (bool enabled);
+
+ void
+ RemoveAll (bool notify);
+
+ //------------------------------------------------------------------
+ /// Sets the passed in Locker to hold the Watchpoint List mutex.
+ ///
+ /// @param[in] locker
+ /// The locker object that is set.
+ //------------------------------------------------------------------
+ void
+ GetListMutex (lldb_private::Mutex::Locker &locker);
+
+protected:
+ typedef std::list<lldb::WatchpointSP> wp_collection;
+ typedef std::vector<lldb::watch_id_t> id_vector;
+
+ id_vector
+ GetWatchpointIDs() const;
+
+ wp_collection::iterator
+ GetIDIterator(lldb::watch_id_t watchID);
+
+ wp_collection::const_iterator
+ GetIDConstIterator(lldb::watch_id_t watchID) const;
+
+ wp_collection m_watchpoints;
+ mutable Mutex m_mutex;
+
+ lldb::watch_id_t m_next_wp_id;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_WatchpointList_h_
diff --git a/include/lldb/Breakpoint/WatchpointOptions.h b/include/lldb/Breakpoint/WatchpointOptions.h
new file mode 100644
index 000000000000..64c65f92b44f
--- /dev/null
+++ b/include/lldb/Breakpoint/WatchpointOptions.h
@@ -0,0 +1,255 @@
+//===-- WatchpointOptions.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_WatchpointOptions_h_
+#define liblldb_WatchpointOptions_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Baton.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class WatchpointOptions WatchpointOptions.h "lldb/Breakpoint/WatchpointOptions.h"
+/// @brief Class that manages the options on a watchpoint.
+//----------------------------------------------------------------------
+
+class WatchpointOptions
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ //------------------------------------------------------------------
+ /// Default constructor. The watchpoint is enabled, and has no condition,
+ /// callback, ignore count, etc...
+ //------------------------------------------------------------------
+ WatchpointOptions();
+ WatchpointOptions(const WatchpointOptions& rhs);
+
+ static WatchpointOptions *
+ CopyOptionsNoCallback (WatchpointOptions &rhs);
+ //------------------------------------------------------------------
+ /// This constructor allows you to specify all the watchpoint options.
+ ///
+ /// @param[in] callback
+ /// This is the plugin for some code that gets run, returns \b true if we are to stop.
+ ///
+ /// @param[in] baton
+ /// Client data that will get passed to the callback.
+ ///
+ /// @param[in] thread_id
+ /// Only stop if \a thread_id hits the watchpoint.
+ //------------------------------------------------------------------
+ WatchpointOptions(WatchpointHitCallback callback,
+ void *baton,
+ lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID);
+
+ virtual ~WatchpointOptions();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const WatchpointOptions&
+ operator=(const WatchpointOptions& rhs);
+
+ //------------------------------------------------------------------
+ // Callbacks
+ //
+ // Watchpoint callbacks come in two forms, synchronous and asynchronous. Synchronous callbacks will get
+ // run before any of the thread plans are consulted, and if they return false the target will continue
+ // "under the radar" of the thread plans. There are a couple of restrictions to synchronous callbacks:
+ // 1) They should NOT resume the target themselves. Just return false if you want the target to restart.
+ // 2) Watchpoints with synchronous callbacks can't have conditions (or rather, they can have them, but they
+ // won't do anything. Ditto with ignore counts, etc... You are supposed to control that all through the
+ // callback.
+ // Asynchronous callbacks get run as part of the "ShouldStop" logic in the thread plan. The logic there is:
+ // a) If the watchpoint is thread specific and not for this thread, continue w/o running the callback.
+ // b) If the ignore count says we shouldn't stop, then ditto.
+ // c) If the condition says we shouldn't stop, then ditto.
+ // d) Otherwise, the callback will get run, and if it returns true we will stop, and if false we won't.
+ // The asynchronous callback can run the target itself, but at present that should be the last action the
+ // callback does. We will relax this condition at some point, but it will take a bit of plumbing to get
+ // that to work.
+ //
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Adds a callback to the watchpoint option set.
+ ///
+ /// @param[in] callback
+ /// The function to be called when the watchpoint gets hit.
+ ///
+ /// @param[in] baton_sp
+ /// A baton which will get passed back to the callback when it is invoked.
+ ///
+ /// @param[in] synchronous
+ /// Whether this is a synchronous or asynchronous callback. See discussion above.
+ //------------------------------------------------------------------
+ void SetCallback (WatchpointHitCallback callback, const lldb::BatonSP &baton_sp, bool synchronous = false);
+
+
+ //------------------------------------------------------------------
+ /// Remove the callback from this option set.
+ //------------------------------------------------------------------
+ void ClearCallback ();
+
+ // The rest of these functions are meant to be used only within the watchpoint handling mechanism.
+
+ //------------------------------------------------------------------
+ /// Use this function to invoke the callback for a specific stop.
+ ///
+ /// @param[in] context
+ /// The context in which the callback is to be invoked. This includes the stop event, the
+ /// execution context of the stop (since you might hit the same watchpoint on multiple threads) and
+ /// whether we are currently executing synchronous or asynchronous callbacks.
+ ///
+ /// @param[in] watch_id
+ /// The watchpoint ID that owns this option set.
+ ///
+ /// @return
+ /// The callback return value.
+ //------------------------------------------------------------------
+ bool InvokeCallback (StoppointCallbackContext *context, lldb::user_id_t watch_id);
+
+ //------------------------------------------------------------------
+ /// Used in InvokeCallback to tell whether it is the right time to run this kind of callback.
+ ///
+ /// @return
+ /// The synchronicity of our callback.
+ //------------------------------------------------------------------
+ bool IsCallbackSynchronous () {
+ return m_callback_is_synchronous;
+ }
+
+ //------------------------------------------------------------------
+ /// Fetch the baton from the callback.
+ ///
+ /// @return
+ /// The baton.
+ //------------------------------------------------------------------
+ Baton *GetBaton ();
+
+ //------------------------------------------------------------------
+ /// Fetch a const version of the baton from the callback.
+ ///
+ /// @return
+ /// The baton.
+ //------------------------------------------------------------------
+ const Baton *GetBaton () const;
+
+ //------------------------------------------------------------------
+ /// Return the current thread spec for this option. This will return NULL if the no thread
+ /// specifications have been set for this Option yet.
+ /// @return
+ /// The thread specification pointer for this option, or NULL if none has
+ /// been set yet.
+ //------------------------------------------------------------------
+ const ThreadSpec *
+ GetThreadSpecNoCreate () const;
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the ThreadSpec for this option, creating it.
+ /// if it hasn't been created already. This API is used for setting the
+ /// ThreadSpec items for this option.
+ //------------------------------------------------------------------
+ ThreadSpec *
+ GetThreadSpec ();
+
+ void
+ SetThreadID(lldb::tid_t thread_id);
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ //------------------------------------------------------------------
+ /// Get description for callback only.
+ //------------------------------------------------------------------
+ void
+ GetCallbackDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ //------------------------------------------------------------------
+ /// Returns true if the watchpoint option has a callback set.
+ //------------------------------------------------------------------
+ bool
+ HasCallback();
+
+ //------------------------------------------------------------------
+ /// This is the default empty callback.
+ /// @return
+ /// The thread id for which the watchpoint hit will stop,
+ /// LLDB_INVALID_THREAD_ID for all threads.
+ //------------------------------------------------------------------
+ static bool
+ NullCallback (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id);
+
+
+ struct CommandData
+ {
+ CommandData () :
+ user_source(),
+ script_source(),
+ stop_on_error(true)
+ {
+ }
+
+ ~CommandData ()
+ {
+ }
+
+ StringList user_source;
+ std::string script_source;
+ bool stop_on_error;
+ };
+
+ class CommandBaton : public Baton
+ {
+ public:
+ CommandBaton (CommandData *data) :
+ Baton (data)
+ {
+ }
+
+ virtual
+ ~CommandBaton ()
+ {
+ delete ((CommandData *)m_data);
+ m_data = NULL;
+ }
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ };
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from WatchpointOptions can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For WatchpointOptions only
+ //------------------------------------------------------------------
+ WatchpointHitCallback m_callback; // This is the callback function pointer
+ lldb::BatonSP m_callback_baton_sp; // This is the client data for the callback
+ bool m_callback_is_synchronous;
+ std::unique_ptr<ThreadSpec> m_thread_spec_ap; // Thread for which this watchpoint will take
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_WatchpointOptions_h_
diff --git a/include/lldb/Core/Address.h b/include/lldb/Core/Address.h
new file mode 100644
index 000000000000..60cd4a86bd4a
--- /dev/null
+++ b/include/lldb/Core/Address.h
@@ -0,0 +1,570 @@
+//===-- Address.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_Address_h_
+#define liblldb_Address_h_
+
+// C Includes
+// C++ Includes
+#include <atomic>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Address Address.h "lldb/Core/Address.h"
+/// @brief A section + offset based address class.
+///
+/// The Address class allows addresses to be relative to a section
+/// that can move during runtime due to images (executables, shared
+/// libraries, bundles, frameworks) being loaded at different
+/// addresses than the addresses found in the object file that
+/// represents them on disk. There are currently two types of addresses
+/// for a section:
+/// @li file addresses
+/// @li load addresses
+///
+/// File addresses represent the virtual addresses that are in the "on
+/// disk" object files. These virtual addresses are converted to be
+/// relative to unique sections scoped to the object file so that
+/// when/if the addresses slide when the images are loaded/unloaded
+/// in memory, we can easily track these changes without having to
+/// update every object (compile unit ranges, line tables, function
+/// address ranges, lexical block and inlined subroutine address
+/// ranges, global and static variables) each time an image is loaded or
+/// unloaded.
+///
+/// Load addresses represent the virtual addresses where each section
+/// ends up getting loaded at runtime. Before executing a program, it
+/// is common for all of the load addresses to be unresolved. When a
+/// DynamicLoader plug-in receives notification that shared libraries
+/// have been loaded/unloaded, the load addresses of the main executable
+/// and any images (shared libraries) will be resolved/unresolved. When
+/// this happens, breakpoints that are in one of these sections can be
+/// set/cleared.
+//----------------------------------------------------------------------
+class Address
+{
+public:
+ //------------------------------------------------------------------
+ /// Dump styles allow the Address::Dump(Stream *,DumpStyle) const
+ /// function to display Address contents in a variety of ways.
+ //------------------------------------------------------------------
+ typedef enum {
+ DumpStyleInvalid, ///< Invalid dump style
+ DumpStyleSectionNameOffset, ///< Display as the section name + offset.
+ ///< \code
+ /// // address for printf in libSystem.B.dylib as a section name + offset
+ /// libSystem.B.dylib.__TEXT.__text + 0x0005cfdf
+ /// \endcode
+ DumpStyleSectionPointerOffset, ///< Display as the section pointer + offset (debug output).
+ ///< \code
+ /// // address for printf in libSystem.B.dylib as a section pointer + offset
+ /// (lldb::Section *)0x35cc50 + 0x000000000005cfdf \endcode
+ DumpStyleFileAddress, ///< Display as the file address (if any).
+ ///< \code
+ /// // address for printf in libSystem.B.dylib as a file address
+ /// 0x000000000005dcff \endcode
+ DumpStyleModuleWithFileAddress, ///< Display as the file address with the module name prepended (if any).
+ ///< \code
+ /// // address for printf in libSystem.B.dylib as a file address
+ /// libSystem.B.dylib[0x000000000005dcff] \endcode
+ DumpStyleLoadAddress, ///< Display as the load address (if resolved).
+ ///< \code
+ /// // address for printf in libSystem.B.dylib as a load address
+ /// 0x00007fff8306bcff \endcode
+ DumpStyleResolvedDescription, ///< Display the details about what an address resolves to. This can
+ ///< be anything from a symbol context summary (module, function/symbol,
+ ///< and file and line), to information about what the pointer points to
+ ///< if the address is in a section (section of pointers, c strings, etc).
+ DumpStyleResolvedDescriptionNoModule,
+ DumpStyleDetailedSymbolContext, ///< Detailed symbol context information for an address for all symbol
+ ///< context members.
+ DumpStyleResolvedPointerDescription ///< Dereference a pointer at the current address and then lookup the
+ ///< dereferenced address using DumpStyleResolvedDescription
+ } DumpStyle;
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize with a invalid section (NULL) and an invalid
+ /// offset (LLDB_INVALID_ADDRESS).
+ //------------------------------------------------------------------
+ Address () :
+ m_section_wp (),
+ m_offset (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Makes a copy of the another Address object \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const Address object reference to copy.
+ //------------------------------------------------------------------
+ Address (const Address& rhs) :
+ m_section_wp (rhs.m_section_wp),
+ m_offset(rhs.m_offset.load())
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Construct with a section pointer and offset.
+ ///
+ /// Initialize the address with the supplied \a section and \a
+ /// offset.
+ ///
+ /// @param[in] section
+ /// A section pointer to a valid lldb::Section, or NULL if the
+ /// address doesn't have a section or will get resolved later.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes into \a section.
+ //------------------------------------------------------------------
+ Address (const lldb::SectionSP &section_sp, lldb::addr_t offset) :
+ m_section_wp (), // Don't init with section_sp in case section_sp is invalid (the weak_ptr will throw)
+ m_offset (offset)
+ {
+ if (section_sp)
+ m_section_wp = section_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Construct with a virtual address and section list.
+ ///
+ /// Initialize and resolve the address with the supplied virtual
+ /// address \a file_addr.
+ ///
+ /// @param[in] file_addr
+ /// A virtual file address.
+ ///
+ /// @param[in] section_list
+ /// A list of sections, one of which may contain the \a file_addr.
+ //------------------------------------------------------------------
+ Address (lldb::addr_t file_addr, const SectionList * section_list);
+
+ Address (lldb::addr_t abs_addr);
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Copies the address value from another Address object \a rhs
+ /// into \a this object.
+ ///
+ /// @param[in] rhs
+ /// A const Address object reference to copy.
+ ///
+ /// @return
+ /// A const Address object reference to \a this.
+ //------------------------------------------------------------------
+#ifndef SWIG
+ const Address&
+ operator= (const Address& rhs);
+#endif
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the section to an invalid value (NULL) and an invalid
+ /// offset (LLDB_INVALID_ADDRESS).
+ //------------------------------------------------------------------
+ void
+ Clear ()
+ {
+ m_section_wp.reset();
+ m_offset = LLDB_INVALID_ADDRESS;
+ }
+
+ //------------------------------------------------------------------
+ /// Compare two Address objects.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const Address object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const Address object reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ static int
+ CompareFileAddress (const Address& lhs, const Address& rhs);
+
+ static int
+ CompareLoadAddress (const Address& lhs, const Address& rhs, Target *target);
+
+ static int
+ CompareModulePointerAndOffset (const Address& lhs, const Address& rhs);
+
+ // For use with std::map, std::multi_map
+ class ModulePointerAndOffsetLessThanFunctionObject
+ {
+ public:
+ ModulePointerAndOffsetLessThanFunctionObject () {}
+
+ bool
+ operator() (const Address& a, const Address& b) const
+ {
+ return Address::CompareModulePointerAndOffset(a, b) < 0;
+ }
+ };
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s. There are many ways to display a section
+ /// offset based address, and \a style lets the user choose.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] style
+ /// The display style for the address.
+ ///
+ /// @param[in] fallback_style
+ /// The display style for the address.
+ ///
+ /// @return
+ /// Returns \b true if the address was able to be displayed.
+ /// File and load addresses may be unresolved and it may not be
+ /// possible to display a valid value, \b false will be returned
+ /// in such cases.
+ ///
+ /// @see Address::DumpStyle
+ //------------------------------------------------------------------
+ bool
+ Dump (Stream *s,
+ ExecutionContextScope *exe_scope,
+ DumpStyle style,
+ DumpStyle fallback_style = DumpStyleInvalid,
+ uint32_t addr_byte_size = UINT32_MAX) const;
+
+ lldb::AddressClass
+ GetAddressClass () const;
+
+ //------------------------------------------------------------------
+ /// Get the file address.
+ ///
+ /// If an address comes from a file on disk that has section
+ /// relative addresses, then it has a virtual address that is
+ /// relative to unique section in the object file.
+ ///
+ /// @return
+ /// The valid file virtual address, or LLDB_INVALID_ADDRESS if
+ /// the address doesn't have a file virtual address (image is
+ /// from memory only with no representation on disk).
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetFileAddress () const;
+
+ //------------------------------------------------------------------
+ /// Get the load address.
+ ///
+ /// If an address comes from a file on disk that has section
+ /// relative addresses, then it has a virtual address that is
+ /// relative to unique section in the object file. Sections get
+ /// resolved at runtime by DynamicLoader plug-ins as images
+ /// (executables and shared libraries) get loaded/unloaded. If a
+ /// section is loaded, then the load address can be resolved.
+ ///
+ /// @return
+ /// The valid load virtual address, or LLDB_INVALID_ADDRESS if
+ /// the address is currently not loaded.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetLoadAddress (Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Get the load address as a callable code load address.
+ ///
+ /// This function will first resolve its address to a load address.
+ /// Then, if the address turns out to be in code address, return the
+ /// load address that would be required to call or return to. The
+ /// address might have extra bits set (bit zero will be set to Thumb
+ /// functions for an ARM target) that are required when changing the
+ /// program counter to setting a return address.
+ ///
+ /// @return
+ /// The valid load virtual address, or LLDB_INVALID_ADDRESS if
+ /// the address is currently not loaded.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetCallableLoadAddress (Target *target, bool is_indirect = false) const;
+
+ //------------------------------------------------------------------
+ /// Get the load address as an opcode load address.
+ ///
+ /// This function will first resolve its address to a load address.
+ /// Then, if the address turns out to be in code address, return the
+ /// load address for a an opcode. This address object might have
+ /// extra bits set (bit zero will be set to Thumb functions for an
+ /// ARM target) that are required for changing the program counter
+ /// and this function will remove any bits that are intended for
+ /// these special purposes. The result of this function can be used
+ /// to safely write a software breakpoint trap to memory.
+ ///
+ /// @return
+ /// The valid load virtual address with extra callable bits
+ /// removed, or LLDB_INVALID_ADDRESS if the address is currently
+ /// not loaded.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetOpcodeLoadAddress (Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Get the section relative offset value.
+ ///
+ /// @return
+ /// The current offset, or LLDB_INVALID_ADDRESS if this address
+ /// doesn't contain a valid offset.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetOffset () const { return m_offset; }
+
+ //------------------------------------------------------------------
+ /// Check if an address is section offset.
+ ///
+ /// When converting a virtual file or load address into a section
+ /// offset based address, we often need to know if, given a section
+ /// list, if the address was able to be converted to section offset.
+ /// This function returns true if the current value contained in
+ /// this object is section offset based.
+ ///
+ /// @return
+ /// Returns \b true if the address has a valid section and
+ /// offset, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsSectionOffset() const
+ {
+ return IsValid() && (GetSection().get() != NULL);
+ }
+
+ //------------------------------------------------------------------
+ /// Check if the object state is valid.
+ ///
+ /// A valid Address object contains either a section pointer and
+ /// and offset (for section offset based addresses), or just a valid
+ /// offset (for absolute addresses that have no section).
+ ///
+ /// @return
+ /// Returns \b true if the the offset is valid, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid() const
+ {
+ return m_offset != LLDB_INVALID_ADDRESS;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //------------------------------------------------------------------
+ /// Resolve a file virtual address using a section list.
+ ///
+ /// Given a list of sections, attempt to resolve \a addr as a
+ /// an offset into one of the file sections.
+ ///
+ /// @return
+ /// Returns \b true if \a addr was able to be resolved, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveAddressUsingFileSections (lldb::addr_t addr, const SectionList *sections);
+
+ //------------------------------------------------------------------
+ /// Set the address to represent \a load_addr.
+ ///
+ /// The address will attempt to find a loaded section within
+ /// \a target that contains \a load_addr. If successful, this
+ /// address object will have a valid section and offset. Else this
+ /// address object will have no section (NULL) and the offset will
+ /// be \a load_addr.
+ ///
+ /// @param[in] load_addr
+ /// A load address from a current process.
+ ///
+ /// @param[in] target
+ /// The target to use when trying resolve the address into
+ /// a section + offset. The Target's SectionLoadList object
+ /// is used to resolve the address.
+ ///
+ /// @return
+ /// Returns \b true if the load address was resolved to be
+ /// section/offset, \b false otherwise. It is often ok for an
+ /// address no not resolve to a section in a module, this often
+ /// happens for JIT'ed code, or any load addresses on the stack
+ /// or heap.
+ //------------------------------------------------------------------
+ bool
+ SetLoadAddress (lldb::addr_t load_addr, Target *target);
+
+ bool
+ SetOpcodeLoadAddress (lldb::addr_t load_addr, Target *target);
+
+ bool
+ SetCallableLoadAddress (lldb::addr_t load_addr, Target *target);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the module for this address.
+ ///
+ /// @return
+ /// Returns the Module pointer that this address is an offset
+ /// in, or NULL if this address doesn't belong in a module, or
+ /// isn't resolved yet.
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetModule () const;
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the section.
+ ///
+ /// @return
+ /// Returns the const lldb::Section pointer that this address is an
+ /// offset in, or NULL if this address is absolute.
+ //------------------------------------------------------------------
+ lldb::SectionSP
+ GetSection () const { return m_section_wp.lock(); }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the offset.
+ ///
+ /// @param[in] offset
+ /// A new offset value for this object.
+ ///
+ /// @return
+ /// Returns \b true if the offset changed, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetOffset (lldb::addr_t offset)
+ {
+ bool changed = m_offset != offset;
+ m_offset = offset;
+ return changed;
+ }
+
+ void
+ SetRawAddress (lldb::addr_t addr)
+ {
+ m_section_wp.reset();
+ m_offset = addr;
+ }
+
+ bool
+ Slide (int64_t offset)
+ {
+ if (m_offset != LLDB_INVALID_ADDRESS)
+ {
+ m_offset += offset;
+ return true;
+ }
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the section.
+ ///
+ /// @param[in] section
+ /// A new lldb::Section pointer to use as the section base. Can
+ /// be NULL for absolute addresses that are not relative to
+ /// any section.
+ //------------------------------------------------------------------
+ void
+ SetSection (const lldb::SectionSP &section_sp)
+ {
+ m_section_wp = section_sp;
+ }
+
+ void
+ ClearSection ()
+ {
+ m_section_wp.reset();
+ }
+ //------------------------------------------------------------------
+ /// Reconstruct a symbol context from an address.
+ ///
+ /// This class doesn't inherit from SymbolContextScope because many
+ /// address objects have short lifespans. Address objects that are
+ /// section offset can reconstruct their symbol context by looking
+ /// up the address in the module found in the section.
+ ///
+ /// @see SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ //------------------------------------------------------------------
+ uint32_t
+ CalculateSymbolContext (SymbolContext *sc,
+ uint32_t resolve_scope = lldb::eSymbolContextEverything) const;
+
+ lldb::ModuleSP
+ CalculateSymbolContextModule () const;
+
+ CompileUnit *
+ CalculateSymbolContextCompileUnit () const;
+
+ Function *
+ CalculateSymbolContextFunction () const;
+
+ Block *
+ CalculateSymbolContextBlock () const;
+
+ Symbol *
+ CalculateSymbolContextSymbol () const;
+
+ bool
+ CalculateSymbolContextLineEntry (LineEntry &line_entry) const;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ lldb::SectionWP m_section_wp; ///< The section for the address, can be NULL.
+ std::atomic<lldb::addr_t> m_offset; ///< Offset into section if \a m_section_wp is valid...
+};
+
+
+//----------------------------------------------------------------------
+// NOTE: Be careful using this operator. It can correctly compare two
+// addresses from the same Module correctly. It can't compare two
+// addresses from different modules in any meaningful way, but it will
+// compare the module pointers.
+//
+// To sum things up:
+// - works great for addresses within the same module
+// - it works for addresses across multiple modules, but don't expect the
+// address results to make much sense
+//
+// This basically lets Address objects be used in ordered collection
+// classes.
+//----------------------------------------------------------------------
+bool operator< (const Address& lhs, const Address& rhs);
+bool operator> (const Address& lhs, const Address& rhs);
+
+
+
+bool operator== (const Address& lhs, const Address& rhs);
+bool operator!= (const Address& lhs, const Address& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_Address_h_
diff --git a/include/lldb/Core/AddressRange.h b/include/lldb/Core/AddressRange.h
new file mode 100644
index 000000000000..bd3ab2ab5da5
--- /dev/null
+++ b/include/lldb/Core/AddressRange.h
@@ -0,0 +1,284 @@
+//===-- AddressRange.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_AddressRange_h_
+#define liblldb_AddressRange_h_
+
+#include "lldb/Core/Address.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class AddressRange AddressRange.h "lldb/Core/AddressRange.h"
+/// @brief A section + offset based address range class.
+//----------------------------------------------------------------------
+class AddressRange
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize with a invalid section (NULL), an invalid
+ /// offset (LLDB_INVALID_ADDRESS), and zero byte size.
+ //------------------------------------------------------------------
+ AddressRange ();
+
+ //------------------------------------------------------------------
+ /// Construct with a section pointer, offset, and byte_size.
+ ///
+ /// Initialize the address with the supplied \a section, \a
+ /// offset and \a byte_size.
+ ///
+ /// @param[in] section
+ /// A section pointer to a valid lldb::Section, or NULL if the
+ /// address doesn't have a section or will get resolved later.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes into \a section.
+ ///
+ /// @param[in] byte_size
+ /// The size in bytes of the address range.
+ //------------------------------------------------------------------
+ AddressRange (const lldb::SectionSP &section, lldb::addr_t offset, lldb::addr_t byte_size);
+
+ //------------------------------------------------------------------
+ /// Construct with a virtual address, section list and byte size.
+ ///
+ /// Initialize and resolve the address with the supplied virtual
+ /// address \a file_addr, and byte size \a byte_size.
+ ///
+ /// @param[in] file_addr
+ /// A virtual address.
+ ///
+ /// @param[in] byte_size
+ /// The size in bytes of the address range.
+ ///
+ /// @param[in] section_list
+ /// A list of sections, one of which may contain the \a vaddr.
+ //------------------------------------------------------------------
+ AddressRange (lldb::addr_t file_addr, lldb::addr_t byte_size, const SectionList *section_list = NULL);
+
+ //------------------------------------------------------------------
+ /// Construct with a Address object address and byte size.
+ ///
+ /// Initialize by copying the section offset address in \a so_addr,
+ /// and setting the byte size to \a byte_size.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object.
+ ///
+ /// @param[in] byte_size
+ /// The size in bytes of the address range.
+ //------------------------------------------------------------------
+ AddressRange (const Address& so_addr, lldb::addr_t byte_size);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ ~AddressRange ();
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the section to an invalid value (NULL), an invalid offset
+ /// (LLDB_INVALID_ADDRESS) and a zero byte size.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Check if a section offset address is contained in this range.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object reference.
+ ///
+ /// @return
+ /// Returns \b true if \a so_addr is contained in this range,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+// bool
+// Contains (const Address &so_addr) const;
+
+ //------------------------------------------------------------------
+ /// Check if a section offset address is contained in this range.
+ ///
+ /// @param[in] so_addr_ptr
+ /// A section offset address object pointer.
+ ///
+ /// @return
+ /// Returns \b true if \a so_addr is contained in this range,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+// bool
+// Contains (const Address *so_addr_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Check if a section offset \a so_addr when represented as a file
+ /// address is contained within this object's file address range.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object reference.
+ ///
+ /// @return
+ /// Returns \b true if both \a this and \a so_addr have
+ /// resolvable file address values and \a so_addr is contained
+ /// in the address range, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ContainsFileAddress (const Address &so_addr) const;
+
+ //------------------------------------------------------------------
+ /// Check if the resolved file address \a file_addr is contained
+ /// within this object's file address range.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object reference.
+ ///
+ /// @return
+ /// Returns \b true if both \a this has a resolvable file
+ /// address value and \a so_addr is contained in the address
+ /// range, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ContainsFileAddress (lldb::addr_t file_addr) const;
+
+ //------------------------------------------------------------------
+ /// Check if a section offset \a so_addr when represented as a load
+ /// address is contained within this object's load address range.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object reference.
+ ///
+ /// @return
+ /// Returns \b true if both \a this and \a so_addr have
+ /// resolvable load address values and \a so_addr is contained
+ /// in the address range, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ContainsLoadAddress (const Address &so_addr, Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Check if the resolved load address \a load_addr is contained
+ /// within this object's load address range.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object reference.
+ ///
+ /// @return
+ /// Returns \b true if both \a this has a resolvable load
+ /// address value and \a so_addr is contained in the address
+ /// range, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ContainsLoadAddress (lldb::addr_t load_addr, Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s. There are many ways to display a section
+ /// offset based address range, and \a style lets the user choose
+ /// how the base address gets displayed.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] style
+ /// The display style for the address.
+ ///
+ /// @return
+ /// Returns \b true if the address was able to be displayed.
+ /// File and load addresses may be unresolved and it may not be
+ /// possible to display a valid value, \b false will be returned
+ /// in such cases.
+ ///
+ /// @see Address::DumpStyle
+ //------------------------------------------------------------------
+ bool
+ Dump (Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style = Address::DumpStyleInvalid) const;
+
+ //------------------------------------------------------------------
+ /// Dump a debug description of this object to a Stream.
+ ///
+ /// Dump a debug description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// The debug description contains verbose internal state such
+ /// and pointer values, reference counts, etc.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ DumpDebug (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the base address of the range.
+ ///
+ /// @return
+ /// A reference to the base address object.
+ //------------------------------------------------------------------
+ Address &
+ GetBaseAddress() { return m_base_addr; }
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the base address of the range.
+ ///
+ /// @return
+ /// A const reference to the base address object.
+ //------------------------------------------------------------------
+ const Address &
+ GetBaseAddress() const { return m_base_addr; }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the byte size of this range.
+ ///
+ /// @return
+ /// The size in bytes of this address range.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetByteSize () const { return m_byte_size; }
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const {
+ // Noting special for the memory size of a single AddressRange object,
+ // it is just the size of itself.
+ return sizeof(AddressRange);
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the byte size of this range.
+ ///
+ /// @param[in] byte_size
+ /// The new size in bytes of this address range.
+ //------------------------------------------------------------------
+ void
+ SetByteSize (lldb::addr_t byte_size) { m_byte_size = byte_size; }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Address m_base_addr; ///< The section offset base address of this range.
+ lldb::addr_t m_byte_size; ///< The size in bytes of this address range.
+};
+
+//bool operator== (const AddressRange& lhs, const AddressRange& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_AddressRange_h_
diff --git a/include/lldb/Core/AddressResolver.h b/include/lldb/Core/AddressResolver.h
new file mode 100644
index 000000000000..e5fe276e3fb1
--- /dev/null
+++ b/include/lldb/Core/AddressResolver.h
@@ -0,0 +1,89 @@
+//===-- AddressResolver.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_AddressResolver_h_
+#define liblldb_AddressResolver_h_
+
+#include <vector>
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/ConstString.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class AddressResolver AddressResolver.h "lldb/Core/AddressResolver.h"
+/// @brief This class works with SearchFilter to resolve function names and
+/// source file locations to their concrete addresses.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// The AddressResolver is a Searcher. In that protocol,
+/// the SearchFilter asks the question "At what depth of the symbol context
+/// descent do you want your callback to get called?" of the filter. The resolver
+/// answers this question (in the GetDepth method) and provides the resolution callback.
+//----------------------------------------------------------------------
+
+class AddressResolver :
+ public Searcher
+{
+public:
+
+ typedef enum
+ {
+ Exact,
+ Regexp,
+ Glob
+ } MatchType;
+
+
+ AddressResolver ();
+
+ virtual
+ ~AddressResolver ();
+
+ virtual void
+ ResolveAddress (SearchFilter &filter);
+
+ virtual void
+ ResolveAddressInModules (SearchFilter &filter,
+ ModuleList &modules);
+
+ virtual void
+ GetDescription (Stream *s) = 0;
+
+ std::vector<AddressRange> &
+ GetAddressRanges ();
+
+ size_t
+ GetNumberOfAddresses ();
+
+ AddressRange &
+ GetAddressRangeAtIndex (size_t idx);
+
+protected:
+
+ std::vector<AddressRange> m_address_ranges;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(AddressResolver);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_AddressResolver_h_
diff --git a/include/lldb/Core/AddressResolverFileLine.h b/include/lldb/Core/AddressResolverFileLine.h
new file mode 100644
index 000000000000..ddeb0e0301d2
--- /dev/null
+++ b/include/lldb/Core/AddressResolverFileLine.h
@@ -0,0 +1,59 @@
+//===-- AddressResolverFileLine.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_AddressResolverFileLine_h_
+#define liblldb_AddressResolverFileLine_h_
+
+// Project includes
+#include "lldb/Core/AddressResolver.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class AddressResolverFileLine AddressResolverFileLine.h "lldb/Core/AddressResolverFileLine.h"
+/// @brief This class finds address for source file and line. Optionally, it will look for inlined
+/// instances of the file and line specification.
+//----------------------------------------------------------------------
+
+class AddressResolverFileLine :
+ public AddressResolver
+{
+public:
+
+ AddressResolverFileLine (const FileSpec &resolver,
+ uint32_t line_no,
+ bool check_inlines);
+
+ virtual
+ ~AddressResolverFileLine ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+protected:
+ FileSpec m_file_spec; // This is the file spec we are looking for.
+ uint32_t m_line_number; // This is the line number that we are looking for.
+ bool m_inlines; // This determines whether the resolver looks for inlined functions or not.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(AddressResolverFileLine);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_AddressResolverFileLine_h_
diff --git a/include/lldb/Core/AddressResolverName.h b/include/lldb/Core/AddressResolverName.h
new file mode 100644
index 000000000000..afde675a89bb
--- /dev/null
+++ b/include/lldb/Core/AddressResolverName.h
@@ -0,0 +1,68 @@
+//===-- AddressResolverName.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_AddressResolverName_h_
+#define liblldb_AddressResolverName_h_
+
+// Project includes
+
+#include "lldb/Core/AddressResolver.h"
+#include "lldb/Core/RegularExpression.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class AddressResolverName AddressResolverName.h "lldb/Core/AddressResolverName.h"
+/// @brief This class finds addresses for a given function name, either by exact match
+/// or by regular expression.
+//----------------------------------------------------------------------
+
+class AddressResolverName:
+ public AddressResolver
+{
+public:
+
+ AddressResolverName (const char *func_name,
+ AddressResolver::MatchType type = Exact);
+
+ // Creates a function breakpoint by regular expression. Takes over control of the lifespan of func_regex.
+ AddressResolverName (RegularExpression &func_regex);
+
+ AddressResolverName (const char *class_name,
+ const char *method,
+ AddressResolver::MatchType type);
+
+ virtual
+ ~AddressResolverName ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+protected:
+ ConstString m_func_name;
+ ConstString m_class_name; // FIXME: Not used yet. The idea would be to stop on methods of this class.
+ RegularExpression m_regex;
+ AddressResolver::MatchType m_match_type;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(AddressResolverName);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_AddressResolverName_h_
diff --git a/include/lldb/Core/ArchSpec.h b/include/lldb/Core/ArchSpec.h
new file mode 100644
index 000000000000..3bfa96be0cee
--- /dev/null
+++ b/include/lldb/Core/ArchSpec.h
@@ -0,0 +1,422 @@
+//===-- ArchSpec.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_ArchSpec_h_
+#define liblldb_ArchSpec_h_
+
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lldb_private {
+
+struct CoreDefinition;
+
+//----------------------------------------------------------------------
+/// @class ArchSpec ArchSpec.h "lldb/Core/ArchSpec.h"
+/// @brief An architecture specification class.
+///
+/// A class designed to be created from a cpu type and subtype, a
+/// string representation, or an llvm::Triple. Keeping all of the
+/// conversions of strings to architecture enumeration values confined
+/// to this class allows new architecture support to be added easily.
+//----------------------------------------------------------------------
+class ArchSpec
+{
+public:
+ enum Core
+ {
+ eCore_arm_generic,
+ eCore_arm_armv4,
+ eCore_arm_armv4t,
+ eCore_arm_armv5,
+ eCore_arm_armv5e,
+ eCore_arm_armv5t,
+ eCore_arm_armv6,
+ eCore_arm_armv7,
+ eCore_arm_armv7f,
+ eCore_arm_armv7s,
+ eCore_arm_armv7k,
+ eCore_arm_armv7m,
+ eCore_arm_armv7em,
+ eCore_arm_xscale,
+ eCore_thumb,
+ eCore_thumbv4t,
+ eCore_thumbv5,
+ eCore_thumbv5e,
+ eCore_thumbv6,
+ eCore_thumbv7,
+ eCore_thumbv7f,
+ eCore_thumbv7s,
+ eCore_thumbv7k,
+ eCore_thumbv7m,
+ eCore_thumbv7em,
+
+ eCore_ppc_generic,
+ eCore_ppc_ppc601,
+ eCore_ppc_ppc602,
+ eCore_ppc_ppc603,
+ eCore_ppc_ppc603e,
+ eCore_ppc_ppc603ev,
+ eCore_ppc_ppc604,
+ eCore_ppc_ppc604e,
+ eCore_ppc_ppc620,
+ eCore_ppc_ppc750,
+ eCore_ppc_ppc7400,
+ eCore_ppc_ppc7450,
+ eCore_ppc_ppc970,
+
+ eCore_ppc64_generic,
+ eCore_ppc64_ppc970_64,
+
+ eCore_sparc_generic,
+
+ eCore_sparc9_generic,
+
+ eCore_x86_32_i386,
+ eCore_x86_32_i486,
+ eCore_x86_32_i486sx,
+
+ eCore_x86_64_x86_64,
+ eCore_uknownMach32,
+ eCore_uknownMach64,
+ kNumCores,
+
+ kCore_invalid,
+ // The following constants are used for wildcard matching only
+ kCore_any,
+ kCore_arm_any,
+ kCore_ppc_any,
+ kCore_ppc64_any,
+ kCore_x86_32_any,
+
+ kCore_arm_first = eCore_arm_generic,
+ kCore_arm_last = eCore_arm_xscale,
+
+ kCore_thumb_first = eCore_thumb,
+ kCore_thumb_last = eCore_thumbv7em,
+
+ kCore_ppc_first = eCore_ppc_generic,
+ kCore_ppc_last = eCore_ppc_ppc970,
+
+ kCore_ppc64_first = eCore_ppc64_generic,
+ kCore_ppc64_last = eCore_ppc64_ppc970_64,
+
+ kCore_x86_32_first = eCore_x86_32_i386,
+ kCore_x86_32_last = eCore_x86_32_i486sx
+ };
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Default constructor that initializes the object with invalid
+ /// cpu type and subtype values.
+ //------------------------------------------------------------------
+ ArchSpec ();
+
+ //------------------------------------------------------------------
+ /// Constructor over triple.
+ ///
+ /// Constructs an ArchSpec with properties consistent with the given
+ /// Triple.
+ //------------------------------------------------------------------
+ explicit
+ ArchSpec (const llvm::Triple &triple);
+ explicit
+ ArchSpec (const char *triple_cstr);
+ explicit
+ ArchSpec (const char *triple_cstr, Platform *platform);
+ //------------------------------------------------------------------
+ /// Constructor over architecture name.
+ ///
+ /// Constructs an ArchSpec with properties consistent with the given
+ /// object type and architecture name.
+ //------------------------------------------------------------------
+ explicit
+ ArchSpec (ArchitectureType arch_type,
+ uint32_t cpu_type,
+ uint32_t cpu_subtype);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~ArchSpec ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// @param[in] rhs another ArchSpec object to copy.
+ ///
+ /// @return A const reference to this object.
+ //------------------------------------------------------------------
+ const ArchSpec&
+ operator= (const ArchSpec& rhs);
+
+ static size_t
+ AutoComplete (const char *name,
+ StringList &matches);
+
+ //------------------------------------------------------------------
+ /// Returns a static string representing the current architecture.
+ ///
+ /// @return A static string correcponding to the current
+ /// architecture.
+ //------------------------------------------------------------------
+ const char *
+ GetArchitectureName () const;
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clears the object state back to a default invalid state.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Returns the size in bytes of an address of the current
+ /// architecture.
+ ///
+ /// @return The byte size of an address of the current architecture.
+ //------------------------------------------------------------------
+ uint32_t
+ GetAddressByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Returns a machine family for the current architecture.
+ ///
+ /// @return An LLVM arch type.
+ //------------------------------------------------------------------
+ llvm::Triple::ArchType
+ GetMachine () const;
+
+ //------------------------------------------------------------------
+ /// Tests if this ArchSpec is valid.
+ ///
+ /// @return True if the current architecture is valid, false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid () const
+ {
+ return m_core >= eCore_arm_generic && m_core < kNumCores;
+ }
+
+ bool
+ TripleVendorWasSpecified() const
+ {
+ return !m_triple.getVendorName().empty();
+ }
+
+ bool
+ TripleOSWasSpecified() const
+ {
+ return !m_triple.getOSName().empty();
+ }
+
+ //------------------------------------------------------------------
+ /// Sets this ArchSpec according to the given architecture name.
+ ///
+ /// The architecture name can be one of the generic system default
+ /// values:
+ ///
+ /// @li \c LLDB_ARCH_DEFAULT - The arch the current system defaults
+ /// to when a program is launched without any extra
+ /// attributes or settings.
+ /// @li \c LLDB_ARCH_DEFAULT_32BIT - The default host architecture
+ /// for 32 bit (if any).
+ /// @li \c LLDB_ARCH_DEFAULT_64BIT - The default host architecture
+ /// for 64 bit (if any).
+ ///
+ /// Alternatively, if the object type of this ArchSpec has been
+ /// configured, a concrete architecture can be specified to set
+ /// the CPU type ("x86_64" for example).
+ ///
+ /// Finally, an encoded object and archetecture format is accepted.
+ /// The format contains an object type (like "macho" or "elf"),
+ /// followed by a platform dependent encoding of CPU type and
+ /// subtype. For example:
+ ///
+ /// "macho" : Specifies an object type of MachO.
+ /// "macho-16-6" : MachO specific encoding for ARMv6.
+ /// "elf-43 : ELF specific encoding for Sparc V9.
+ ///
+ /// @param[in] arch_name The name of an architecture.
+ ///
+ /// @return True if @p arch_name was successfully translated, false
+ /// otherwise.
+ //------------------------------------------------------------------
+// bool
+// SetArchitecture (const llvm::StringRef& arch_name);
+//
+// bool
+// SetArchitecture (const char *arch_name);
+
+ //------------------------------------------------------------------
+ /// Change the architecture object type and CPU type.
+ ///
+ /// @param[in] arch_type The object type of this ArchSpec.
+ ///
+ /// @param[in] cpu The required CPU type.
+ ///
+ /// @return True if the object and CPU type were sucessfully set.
+ //------------------------------------------------------------------
+ bool
+ SetArchitecture (ArchitectureType arch_type,
+ uint32_t cpu,
+ uint32_t sub);
+
+ //------------------------------------------------------------------
+ /// Returns the byte order for the architecture specification.
+ ///
+ /// @return The endian enumeration for the current endianness of
+ /// the architecture specification
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetByteOrder () const;
+
+ //------------------------------------------------------------------
+ /// Sets this ArchSpec's byte order.
+ ///
+ /// In the common case there is no need to call this method as the
+ /// byte order can almost always be determined by the architecture.
+ /// However, many CPU's are bi-endian (ARM, Alpha, PowerPC, etc)
+ /// and the default/assumed byte order may be incorrect.
+ //------------------------------------------------------------------
+ void
+ SetByteOrder (lldb::ByteOrder byte_order)
+ {
+ m_byte_order = byte_order;
+ }
+
+ uint32_t
+ GetMinimumOpcodeByteSize() const;
+
+ uint32_t
+ GetMaximumOpcodeByteSize() const;
+
+ Core
+ GetCore () const
+ {
+ return m_core;
+ }
+
+ uint32_t
+ GetMachOCPUType () const;
+
+ uint32_t
+ GetMachOCPUSubType () const;
+
+ //------------------------------------------------------------------
+ /// Architecture tripple accessor.
+ ///
+ /// @return A triple describing this ArchSpec.
+ //------------------------------------------------------------------
+ llvm::Triple &
+ GetTriple ()
+ {
+ return m_triple;
+ }
+
+ //------------------------------------------------------------------
+ /// Architecture tripple accessor.
+ ///
+ /// @return A triple describing this ArchSpec.
+ //------------------------------------------------------------------
+ const llvm::Triple &
+ GetTriple () const
+ {
+ return m_triple;
+ }
+
+ //------------------------------------------------------------------
+ /// Architecture tripple setter.
+ ///
+ /// Configures this ArchSpec according to the given triple. If the
+ /// triple has unknown components in all of the vendor, OS, and
+ /// the optional environment field (i.e. "i386-unknown-unknown")
+ /// then default values are taken from the host. Architecture and
+ /// environment components are used to further resolve the CPU type
+ /// and subtype, endian characteristics, etc.
+ ///
+ /// @return A triple describing this ArchSpec.
+ //------------------------------------------------------------------
+ bool
+ SetTriple (const llvm::Triple &triple);
+
+ bool
+ SetTriple (const char *triple_cstr);
+
+ bool
+ SetTriple (const char *triple_cstr,
+ Platform *platform);
+
+ //------------------------------------------------------------------
+ /// Returns the default endianness of the architecture.
+ ///
+ /// @return The endian enumeration for the default endianness of
+ /// the architecture.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetDefaultEndian () const;
+
+ //------------------------------------------------------------------
+ /// Compare an ArchSpec to another ArchSpec, requiring an exact cpu
+ /// type match between them.
+ /// e.g. armv7s is not an exact match with armv7 - this would return false
+ ///
+ /// @return true if the two ArchSpecs match.
+ //------------------------------------------------------------------
+ bool
+ IsExactMatch (const ArchSpec& rhs) const;
+
+ //------------------------------------------------------------------
+ /// Compare an ArchSpec to another ArchSpec, requiring a compatible
+ /// cpu type match between them.
+ /// e.g. armv7s is compatible with armv7 - this method would return true
+ ///
+ /// @return true if the two ArchSpecs are compatible
+ //------------------------------------------------------------------
+ bool
+ IsCompatibleMatch (const ArchSpec& rhs) const;
+
+protected:
+ bool
+ IsEqualTo (const ArchSpec& rhs, bool exact_match) const;
+
+ llvm::Triple m_triple;
+ Core m_core;
+ lldb::ByteOrder m_byte_order;
+
+ // Called when m_def or m_entry are changed. Fills in all remaining
+ // members with default values.
+ void
+ CoreUpdated (bool update_triple);
+};
+
+//------------------------------------------------------------------
+/// @fn bool operator< (const ArchSpec& lhs, const ArchSpec& rhs)
+/// @brief Less than operator.
+///
+/// Tests two ArchSpec objects to see if \a lhs is less than \a
+/// rhs.
+///
+/// @param[in] lhs The Left Hand Side ArchSpec object to compare.
+/// @param[in] rhs The Left Hand Side ArchSpec object to compare.
+///
+/// @return true if \a lhs is less than \a rhs
+//------------------------------------------------------------------
+bool operator< (const ArchSpec& lhs, const ArchSpec& rhs);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_ArchSpec_h_
diff --git a/include/lldb/Core/Baton.h b/include/lldb/Core/Baton.h
new file mode 100644
index 000000000000..627e7203a4ac
--- /dev/null
+++ b/include/lldb/Core/Baton.h
@@ -0,0 +1,62 @@
+//===-- Baton.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Baton_h_
+#define lldb_Baton_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Baton Baton.h "lldb/Core/Baton.h"
+/// @brief A class designed to wrap callback batons so they can cleanup
+/// any acquired resources
+///
+/// This class is designed to be used by any objects that have a
+/// callback function that takes a baton where the baton might need to
+/// free/delete/close itself.
+///
+/// The default behavior is to not free anything. Subclasses can
+/// free any needed resources in their destructors.
+//----------------------------------------------------------------------
+class Baton
+{
+public:
+ explicit Baton(void *p) :
+ m_data (p)
+ {
+ }
+
+ virtual
+ ~Baton()
+ {
+ // The default destructor for a baton does NOT attempt to clean up
+ // anything in m_baton
+ }
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ void *m_data; // Leave baton public for easy access
+
+private:
+ //------------------------------------------------------------------
+ // For Baton only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Baton);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_Baton_h_
diff --git a/include/lldb/Core/Broadcaster.h b/include/lldb/Core/Broadcaster.h
new file mode 100644
index 000000000000..64b12ca8a938
--- /dev/null
+++ b/include/lldb/Core/Broadcaster.h
@@ -0,0 +1,475 @@
+//===-- Broadcaster.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_Broadcaster_h_
+#define liblldb_Broadcaster_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+//#include "lldb/Core/Flags.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Listener.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// lldb::BroadcastEventSpec
+//
+// This class is used to specify a kind of event to register for. The Debugger
+// maintains a list of BroadcastEventSpec's and when it is made
+//----------------------------------------------------------------------
+class BroadcastEventSpec
+{
+public:
+ BroadcastEventSpec (const ConstString &broadcaster_class, uint32_t event_bits) :
+ m_broadcaster_class (broadcaster_class),
+ m_event_bits (event_bits)
+ {
+ }
+
+ BroadcastEventSpec (const BroadcastEventSpec &rhs);
+
+ ~BroadcastEventSpec() {}
+
+ const ConstString &GetBroadcasterClass() const
+ {
+ return m_broadcaster_class;
+ }
+
+ uint32_t GetEventBits () const
+ {
+ return m_event_bits;
+ }
+
+ // Tell whether this BroadcastEventSpec is contained in in_spec.
+ // That is:
+ // (a) the two spec's share the same broadcaster class
+ // (b) the event bits of this spec are wholly contained in those of in_spec.
+ bool IsContainedIn (BroadcastEventSpec in_spec) const
+ {
+ if (m_broadcaster_class != in_spec.GetBroadcasterClass())
+ return false;
+ uint32_t in_bits = in_spec.GetEventBits();
+ if (in_bits == m_event_bits)
+ return true;
+ else
+ {
+ if ((m_event_bits & in_bits) != 0
+ && (m_event_bits & ~in_bits) == 0)
+ return true;
+ }
+ return false;
+ }
+
+ bool operator< (const BroadcastEventSpec &rhs) const;
+ const BroadcastEventSpec &operator= (const BroadcastEventSpec &rhs);
+
+private:
+ ConstString m_broadcaster_class;
+ uint32_t m_event_bits;
+};
+
+class BroadcasterManager
+{
+public:
+ friend class Listener;
+
+ BroadcasterManager ();
+
+ ~BroadcasterManager () {}
+
+ uint32_t
+ RegisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec);
+
+ bool
+ UnregisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec);
+
+ Listener *
+ GetListenerForEventSpec (BroadcastEventSpec event_spec) const;
+
+ void
+ SignUpListenersForBroadcaster (Broadcaster &broadcaster);
+
+ void
+ RemoveListener (Listener &Listener);
+
+protected:
+ void Clear();
+
+private:
+ typedef std::pair<BroadcastEventSpec, Listener *> event_listener_key;
+ typedef std::map<BroadcastEventSpec, Listener *> collection;
+ typedef std::set<Listener *> listener_collection;
+ collection m_event_map;
+ listener_collection m_listeners;
+
+ Mutex m_manager_mutex;
+
+ // A couple of comparator classes for find_if:
+
+ class BroadcasterClassMatches
+ {
+ public:
+ BroadcasterClassMatches (const ConstString &broadcaster_class) :
+ m_broadcaster_class (broadcaster_class)
+ {
+ }
+
+ ~BroadcasterClassMatches () {}
+
+ bool operator() (const event_listener_key input) const
+ {
+ return (input.first.GetBroadcasterClass() == m_broadcaster_class);
+ }
+
+ private:
+ ConstString m_broadcaster_class;
+ };
+
+ class BroadcastEventSpecMatches
+ {
+ public:
+ BroadcastEventSpecMatches (BroadcastEventSpec broadcaster_spec) :
+ m_broadcaster_spec (broadcaster_spec)
+ {
+ }
+
+ ~BroadcastEventSpecMatches () {}
+
+ bool operator() (const event_listener_key input) const
+ {
+ return (input.first.IsContainedIn (m_broadcaster_spec));
+ }
+
+ private:
+ BroadcastEventSpec m_broadcaster_spec;
+ };
+
+ class ListenerMatchesAndSharedBits
+ {
+ public:
+ ListenerMatchesAndSharedBits (BroadcastEventSpec broadcaster_spec,
+ const Listener &listener) :
+ m_broadcaster_spec (broadcaster_spec),
+ m_listener (&listener)
+ {
+ }
+
+ ~ListenerMatchesAndSharedBits () {}
+
+ bool operator() (const event_listener_key input) const
+ {
+ return (input.first.GetBroadcasterClass() == m_broadcaster_spec.GetBroadcasterClass()
+ && (input.first.GetEventBits() & m_broadcaster_spec.GetEventBits()) != 0
+ && input.second == m_listener);
+ }
+
+ private:
+ BroadcastEventSpec m_broadcaster_spec;
+ const Listener *m_listener;
+ };
+
+ class ListenerMatches
+ {
+ public:
+ ListenerMatches (const Listener &in_listener) :
+ m_listener (&in_listener)
+ {
+ }
+
+ ~ListenerMatches() {}
+
+ bool operator () (const event_listener_key input) const
+ {
+ if (input.second == m_listener)
+ return true;
+ else
+ return false;
+ }
+
+ private:
+ const Listener *m_listener;
+
+ };
+
+};
+
+//----------------------------------------------------------------------
+/// @class Broadcaster Broadcaster.h "lldb/Core/Broadcaster.h"
+/// @brief An event broadcasting class.
+///
+/// The Broadcaster class is designed to be subclassed by objects that
+/// wish to vend events in a multi-threaded environment. Broadcaster
+/// objects can each vend 32 events. Each event is represented by a bit
+/// in a 32 bit value and these bits can be set:
+/// @see Broadcaster::SetEventBits(uint32_t)
+/// or cleared:
+/// @see Broadcaster::ResetEventBits(uint32_t)
+/// When an event gets set the Broadcaster object will notify the
+/// Listener object that is listening for the event (if there is one).
+///
+/// Subclasses should provide broadcast bit definitions for any events
+/// they vend, typically using an enumeration:
+/// \code
+/// class Foo : public Broadcaster
+/// {
+/// public:
+/// //----------------------------------------------------------
+/// // Broadcaster event bits definitions.
+/// //----------------------------------------------------------
+/// enum
+/// {
+/// eBroadcastBitStateChanged = (1 << 0),
+/// eBroadcastBitInterrupt = (1 << 1),
+/// eBroadcastBitSTDOUT = (1 << 2),
+/// eBroadcastBitSTDERR = (1 << 3),
+/// eBroadcastBitProfileData = (1 << 4)
+/// };
+/// \endcode
+//----------------------------------------------------------------------
+class Broadcaster
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with a broadcaster with a name.
+ ///
+ /// @param[in] name
+ /// A NULL terminated C string that contains the name of the
+ /// broadcaster object.
+ //------------------------------------------------------------------
+ Broadcaster (BroadcasterManager *manager, const char *name);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class gets subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~Broadcaster();
+
+ void
+ CheckInWithManager ();
+
+ //------------------------------------------------------------------
+ /// Broadcast an event which has no associated data.
+ ///
+ /// @param[in] event_type
+ /// The element from the enum defining this broadcaster's events
+ /// that is being broadcast.
+ ///
+ /// @param[in] event_data
+ /// User event data that will be owned by the lldb::Event that
+ /// is created internally.
+ ///
+ /// @param[in] unique
+ /// If true, then only add an event of this type if there isn't
+ /// one already in the queue.
+ ///
+ //------------------------------------------------------------------
+ void
+ BroadcastEvent (lldb::EventSP &event_sp);
+
+ void
+ BroadcastEventIfUnique (lldb::EventSP &event_sp);
+
+ void
+ BroadcastEvent (uint32_t event_type, EventData *event_data = NULL);
+
+ void
+ BroadcastEventIfUnique (uint32_t event_type, EventData *event_data = NULL);
+
+ void
+ Clear();
+
+ virtual void
+ AddInitialEventsToListener (Listener *listener, uint32_t requested_events);
+
+ //------------------------------------------------------------------
+ /// Listen for any events specified by \a event_mask.
+ ///
+ /// Only one listener can listen to each event bit in a given
+ /// Broadcaster. Once a listener has acquired an event bit, no
+ /// other broadcaster will have access to it until it is
+ /// relinquished by the first listener that gets it. The actual
+ /// event bits that get acquired by \a listener may be different
+ /// from what is requested in \a event_mask, and to track this the
+ /// actual event bits that are acquired get returned.
+ ///
+ /// @param[in] listener
+ /// The Listener object that wants to monitor the events that
+ /// get broadcast by this object.
+ ///
+ /// @param[in] event_mask
+ /// A bit mask that indicates which events the listener is
+ /// asking to monitor.
+ ///
+ /// @return
+ /// The actual event bits that were acquired by \a listener.
+ //------------------------------------------------------------------
+ uint32_t
+ AddListener (Listener* listener, uint32_t event_mask);
+
+ //------------------------------------------------------------------
+ /// Get the NULL terminated C string name of this Broadcaster
+ /// object.
+ ///
+ /// @return
+ /// The NULL terminated C string name of this Broadcaster.
+ //------------------------------------------------------------------
+ const ConstString &
+ GetBroadcasterName ();
+
+
+ //------------------------------------------------------------------
+ /// Get the event name(s) for one or more event bits.
+ ///
+ /// @param[in] event_mask
+ /// A bit mask that indicates which events to get names for.
+ ///
+ /// @return
+ /// The NULL terminated C string name of this Broadcaster.
+ //------------------------------------------------------------------
+ bool
+ GetEventNames (Stream &s, const uint32_t event_mask, bool prefix_with_broadcaster_name) const;
+
+ //------------------------------------------------------------------
+ /// Set the name for an event bit.
+ ///
+ /// @param[in] event_mask
+ /// A bit mask that indicates which events the listener is
+ /// asking to monitor.
+ ///
+ /// @return
+ /// The NULL terminated C string name of this Broadcaster.
+ //------------------------------------------------------------------
+ void
+ SetEventName (uint32_t event_mask, const char *name)
+ {
+ m_event_names[event_mask] = name;
+ }
+
+ const char *
+ GetEventName (uint32_t event_mask) const
+ {
+ event_names_map::const_iterator pos = m_event_names.find (event_mask);
+ if (pos != m_event_names.end())
+ return pos->second.c_str();
+ return NULL;
+ }
+
+ bool
+ EventTypeHasListeners (uint32_t event_type);
+
+ //------------------------------------------------------------------
+ /// Removes a Listener from this broadcasters list and frees the
+ /// event bits specified by \a event_mask that were previously
+ /// acquired by \a listener (assuming \a listener was listening to
+ /// this object) for other listener objects to use.
+ ///
+ /// @param[in] listener
+ /// A Listener object that previously called AddListener.
+ ///
+ /// @param[in] event_mask
+ /// The event bits \a listener wishes to relinquish.
+ ///
+ /// @return
+ /// \b True if the listener was listening to this broadcaster
+ /// and was removed, \b false otherwise.
+ ///
+ /// @see uint32_t Broadcaster::AddListener (Listener*, uint32_t)
+ //------------------------------------------------------------------
+ bool
+ RemoveListener (Listener* listener, uint32_t event_mask = UINT32_MAX);
+
+ //------------------------------------------------------------------
+ /// Provides a simple mechanism to temporarily redirect events from
+ /// broadcaster. When you call this function passing in a listener and
+ /// event type mask, all events from the broadcaster matching the mask
+ /// will now go to the hijacking listener.
+ /// Only one hijack can occur at a time. If we need more than this we
+ /// will have to implement a Listener stack.
+ ///
+ /// @param[in] listener
+ /// A Listener object. You do not need to call StartListeningForEvents
+ /// for this broadcaster (that would fail anyway since the event bits
+ /// would most likely be taken by the listener(s) you are usurping.
+ ///
+ /// @param[in] event_mask
+ /// The event bits \a listener wishes to hijack.
+ ///
+ /// @return
+ /// \b True if the event mask could be hijacked, \b false otherwise.
+ ///
+ /// @see uint32_t Broadcaster::AddListener (Listener*, uint32_t)
+ //------------------------------------------------------------------
+ bool
+ HijackBroadcaster (Listener *listener, uint32_t event_mask = UINT32_MAX);
+
+ bool
+ IsHijackedForEvent (uint32_t event_mask)
+ {
+ if (m_hijacking_listeners.size() > 0)
+ return (event_mask & m_hijacking_masks.back()) != 0;
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Restore the state of the Broadcaster from a previous hijack attempt.
+ ///
+ //------------------------------------------------------------------
+ void
+ RestoreBroadcaster ();
+
+ // This needs to be filled in if you are going to register the broadcaster with the broadcaster
+ // manager and do broadcaster class matching.
+ // FIXME: Probably should make a ManagedBroadcaster subclass with all the bits needed to work
+ // with the BroadcasterManager, so that it is clearer how to add one.
+ virtual ConstString &GetBroadcasterClass() const;
+
+ BroadcasterManager *GetManager();
+
+protected:
+
+
+ void
+ PrivateBroadcastEvent (lldb::EventSP &event_sp, bool unique);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Broadcaster can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector< std::pair<Listener*,uint32_t> > collection;
+ typedef std::map<uint32_t, std::string> event_names_map;
+ // Prefix the name of our member variables with "m_broadcaster_"
+ // since this is a class that gets subclassed.
+ const ConstString m_broadcaster_name; ///< The name of this broadcaster object.
+ event_names_map m_event_names; ///< Optionally define event names for readability and logging for each event bit
+ collection m_listeners; ///< A list of Listener / event_mask pairs that are listening to this broadcaster.
+ Mutex m_listeners_mutex; ///< A mutex that protects \a m_listeners.
+ std::vector<Listener *> m_hijacking_listeners; // A simple mechanism to intercept events from a broadcaster
+ std::vector<uint32_t> m_hijacking_masks; // At some point we may want to have a stack or Listener
+ // collections, but for now this is just for private hijacking.
+ BroadcasterManager *m_manager;
+
+private:
+ //------------------------------------------------------------------
+ // For Broadcaster only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Broadcaster);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Broadcaster_h_
diff --git a/include/lldb/Core/ClangForward.h b/include/lldb/Core/ClangForward.h
new file mode 100644
index 000000000000..0b3f13a16602
--- /dev/null
+++ b/include/lldb/Core/ClangForward.h
@@ -0,0 +1,136 @@
+//===-- ClangForward.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_ClangForward_h_
+#define liblldb_ClangForward_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#if defined(__cplusplus)
+
+namespace clang
+{
+ namespace Builtin
+ {
+ class Context;
+ }
+
+ class Action;
+ class ASTConsumer;
+ class ASTContext;
+ class ASTRecordLayout;
+ class AddrLabelExpr;
+ class AnalyzerOptions;
+ class BinaryOperator;
+ class ClassTemplateDecl;
+ class ClassTemplateSpecializationDecl;
+ class CodeGenOptions;
+ class CodeGenerator;
+ class CompilerInstance;
+ class CompoundStmt;
+ class CXXBaseSpecifier;
+ class CXXBoolLiteralExpr;
+ class CXXFunctionalCastExpr;
+ class CXXMethodDecl;
+ class CXXNamedCastExpr;
+ class CXXRecordDecl;
+ class CXXThisExpr;
+ class CharacterLiteral;
+ class CompoundAssignOperator;
+ class Decl;
+ class DeclarationName;
+ class DeclaratorDecl;
+ class DeclContext;
+ class DeclRefExpr;
+ class DeclStmt;
+ class DependencyOutputOptions;
+ class Diagnostic;
+ class DiagnosticConsumer;
+ class DiagnosticsEngine;
+ class DiagnosticOptions;
+ class EnumDecl;
+ class Expr;
+ class ExternalASTSource;
+ class ExtVectorElementExpr;
+ class FieldDecl;
+ class FileManager;
+ class FileSystemOptions;
+ class FloatingLiteral;
+ class FrontendOptions;
+ class FunctionDecl;
+ class FunctionTemplateDecl;
+ class FunctionTemplateSpecializationInfo;
+ class GotoStmt;
+ class HeaderSearchOptions;
+ class IdentifierTable;
+ class IntegerLiteral;
+ class LabelStmt;
+ class LangOptions;
+ class MemberExpr;
+ class NamedDecl;
+ class NamespaceDecl;
+ class NonTypeTemplateParmDecl;
+ class ObjCEncodeExpr;
+ class ObjCImplicitSetterGetterRefExpr;
+ class ObjCInterfaceDecl;
+ class ObjCIvarDecl;
+ class ObjCIvarRefExpr;
+ class ObjCMessageExpr;
+ class ObjCMethodDecl;
+ class ObjCPropertyRefExpr;
+ class ObjCProtocolDecl;
+ class ObjCProtocolExpr;
+ class ObjCSelectorExpr;
+ class ObjCSuperExpr;
+ class ParenExpr;
+ class ParmVarDecl;
+ class PredefinedExpr;
+ class PreprocessorOptions;
+ class PreprocessorOutputOptions;
+ class QualType;
+ class QualifiedNameType;
+ class RecordDecl;
+ class SelectorTable;
+ class SizeOfAlignOfExpr;
+ class SourceLocation;
+ class SourceManager;
+ class Stmt;
+ class StmtIteratorBase;
+ class StringLiteral;
+ class TagDecl;
+ class TargetInfo;
+ class TargetOptions;
+ class TemplateArgument;
+ class TemplateDecl;
+ class TemplateParameterList;
+ class TemplateTemplateParmDecl;
+ class TemplateTypeParmDecl;
+ class TextDiagnosticBuffer;
+ class TranslationUnitDecl;
+ class Type;
+ class TypeDecl;
+ class TypedefDecl;
+ class TypesCompatibleExpr;
+ class UnaryOperator;
+ class ValueDecl;
+ class VarDecl;
+ struct PrintingPolicy;
+}
+
+namespace llvm
+{
+ class LLVMContext;
+ class ExecutionEngine;
+}
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_ClangForward_h_
diff --git a/include/lldb/Core/Communication.h b/include/lldb/Core/Communication.h
new file mode 100644
index 000000000000..98d4dfd011b8
--- /dev/null
+++ b/include/lldb/Core/Communication.h
@@ -0,0 +1,413 @@
+//===-- Communication.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_Communication_h_
+#define liblldb_Communication_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Communication Communication.h "lldb/Core/Communication.h"
+/// @brief An abstract communications class.
+///
+/// Communication is an class that handles data communication
+/// between two data sources. It uses a Connection class to do the
+/// real communication. This approach has a couple of advantages: it
+/// allows a single instance of this class to be used even though its
+/// connection can change. Connections could negotiate for different
+/// connections based on abilities like starting with Bluetooth and
+/// negotiating up to WiFi if available. It also allows this class to be
+/// subclassed by any interfaces that don't want to give bytes but want
+/// to validate and give out packets. This can be done by overriding:
+///
+/// AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast);
+///
+/// Communication inherits from Broadcaster which means it can be
+/// used in conjunction with Listener to wait for multiple broadcaster
+/// objects and multiple events from each of those objects.
+/// Communication defines a set of pre-defined event bits (see
+/// enumerations definitions that start with "eBroadcastBit" below).
+///
+/// There are two modes in which communications can occur:
+/// @li single-threaded
+/// @li multi-threaded
+///
+/// In single-threaded mode, all reads and writes happen synchronously
+/// on the calling thread.
+///
+/// In multi-threaded mode, a read thread is spawned that continually
+/// reads data and caches any received bytes. To start the read thread
+/// clients call:
+///
+/// bool Communication::StartReadThread (Error *);
+///
+/// If true is returned a read thead has been spawned that will
+/// continually execute a call to the pure virtual DoRead function:
+///
+/// size_t Communication::ReadFromConnection (void *, size_t, uint32_t);
+///
+/// When bytes are received the data gets cached in \a m_bytes and this
+/// class will broadcast a \b eBroadcastBitReadThreadGotBytes event.
+/// Clients that want packet based communication should override
+/// AppendBytesToCache. The subclasses can choose to call the
+/// built in AppendBytesToCache with the \a broadcast parameter set to
+/// false. This will cause the \b eBroadcastBitReadThreadGotBytes event
+/// not get broadcast, and then the subclass can post a \b
+/// eBroadcastBitPacketAvailable event when a full packet of data has
+/// been received.
+///
+/// If the connection is disconnected a \b eBroadcastBitDisconnected
+/// event gets broadcast. If the read thread exits a \b
+/// eBroadcastBitReadThreadDidExit event will be broadcast. Clients
+/// can also post a \b eBroadcastBitReadThreadShouldExit event to this
+/// object which will cause the read thread to exit.
+//----------------------------------------------------------------------
+class Communication : public Broadcaster
+{
+public:
+ enum {
+ eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost.
+ eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available.
+ eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients.
+ eBroadcastBitReadThreadShouldExit = (1 << 3), ///< Sent by clients that need to cancel the read thread.
+ eBroadcastBitPacketAvailable = (1 << 4), ///< Sent when data received makes a complete packet.
+ kLoUserBroadcastBit = (1 << 16),///< Subclasses can used bits 31:16 for any needed events.
+ kHiUserBroadcastBit = (1 << 31),
+ eAllEventBits = 0xffffffff
+ };
+
+ typedef void (*ReadThreadBytesReceived) (void *baton, const void *src, size_t src_len);
+
+
+ //------------------------------------------------------------------
+ /// Construct the Communication object with the specified name for
+ /// the Broadcaster that this object inherits from.
+ ///
+ /// @param[in] broadcaster_name
+ /// The name of the broadcaster object. This name should be as
+ /// complete as possible to uniquely identify this object. The
+ /// broadcaster name can be updated after the connect function
+ /// is called.
+ //------------------------------------------------------------------
+ Communication(const char * broadcaster_name);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class gets subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~Communication();
+
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Connect using the current connection by passing \a url to its
+ /// connect function.
+ /// string.
+ ///
+ /// @param[in] url
+ /// A string that contains all information needed by the
+ /// subclass to connect to another client.
+ ///
+ /// @return
+ /// \b True if the connect succeeded, \b false otherwise. The
+ /// internal error object should be filled in with an
+ /// appropriate value based on the result of this function.
+ ///
+ /// @see Error& Communication::GetError ();
+ /// @see bool Connection::Connect (const char *url);
+ //------------------------------------------------------------------
+ lldb::ConnectionStatus
+ Connect (const char *url, Error *error_ptr);
+
+ //------------------------------------------------------------------
+ /// Disconnect the communications connection if one is currently
+ /// connected.
+ ///
+ /// @return
+ /// \b True if the disconnect succeeded, \b false otherwise. The
+ /// internal error object should be filled in with an
+ /// appropriate value based on the result of this function.
+ ///
+ /// @see Error& Communication::GetError ();
+ /// @see bool Connection::Disconnect ();
+ //------------------------------------------------------------------
+ lldb::ConnectionStatus
+ Disconnect (Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Check if the connection is valid.
+ ///
+ /// @return
+ /// \b True if this object is currently connected, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsConnected () const;
+
+ bool
+ HasConnection () const;
+
+ lldb_private::Connection *
+ GetConnection ()
+ {
+ return m_connection_sp.get();
+ }
+ //------------------------------------------------------------------
+ /// Read bytes from the current connection.
+ ///
+ /// If no read thread is running, this function call the
+ /// connection's Connection::Read(...) function to get any available.
+ ///
+ /// If a read thread has been started, this function will check for
+ /// any cached bytes that have already been read and return any
+ /// currently available bytes. If no bytes are cached, it will wait
+ /// for the bytes to become available by listening for the \a
+ /// eBroadcastBitReadThreadGotBytes event. If this function consumes
+ /// all of the bytes in the cache, it will reset the
+ /// \a eBroadcastBitReadThreadGotBytes event bit.
+ ///
+ /// @param[in] dst
+ /// A destination buffer that must be at least \a dst_len bytes
+ /// long.
+ ///
+ /// @param[in] dst_len
+ /// The number of bytes to attempt to read, and also the max
+ /// number of bytes that can be placed into \a dst.
+ ///
+ /// @param[in] timeout_usec
+ /// A timeout value in micro-seconds.
+ ///
+ /// @return
+ /// The number of bytes actually read.
+ ///
+ /// @see size_t Connection::Read (void *, size_t);
+ //------------------------------------------------------------------
+ size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+
+ //------------------------------------------------------------------
+ /// The actual write function that attempts to write to the
+ /// communications protocol.
+ ///
+ /// Subclasses must override this function.
+ ///
+ /// @param[in] src
+ /// A source buffer that must be at least \a src_len bytes
+ /// long.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes to attempt to write, and also the
+ /// number of bytes are currently available in \a src.
+ ///
+ /// @return
+ /// The number of bytes actually Written.
+ //------------------------------------------------------------------
+ size_t
+ Write (const void *src,
+ size_t src_len,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+
+ //------------------------------------------------------------------
+ /// Sets the connection that it to be used by this class.
+ ///
+ /// By making a communication class that uses different connections
+ /// it allows a single communication interface to negotiate and
+ /// change its connection without any interruption to the client.
+ /// It also allows the Communication class to be subclassed for
+ /// packet based communication.
+ ///
+ /// @param[in] connection
+ /// A connection that this class will own and destroy.
+ ///
+ /// @see
+ /// class Connection
+ //------------------------------------------------------------------
+ void
+ SetConnection (Connection *connection);
+
+ //------------------------------------------------------------------
+ /// Starts a read thread whose sole purpose it to read bytes from
+ /// the current connection. This function will call connection's
+ /// read function:
+ ///
+ /// size_t Connection::Read (void *, size_t);
+ ///
+ /// When bytes are read and cached, this function will call:
+ ///
+ /// Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast);
+ ///
+ /// Subclasses should override this function if they wish to override
+ /// the default action of caching the bytes and broadcasting a \b
+ /// eBroadcastBitReadThreadGotBytes event.
+ ///
+ /// @return
+ /// \b True if the read thread was successfully started, \b
+ /// false otherwise.
+ ///
+ /// @see size_t Connection::Read (void *, size_t);
+ /// @see void Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast);
+ //------------------------------------------------------------------
+ virtual bool
+ StartReadThread (Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Stops the read thread by cancelling it.
+ ///
+ /// @return
+ /// \b True if the read thread was successfully canceled, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ StopReadThread (Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Checks if there is a currently running read thread.
+ ///
+ /// @return
+ /// \b True if the read thread is running, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ReadThreadIsRunning ();
+
+ //------------------------------------------------------------------
+ /// The static read thread function. This function will call
+ /// the "DoRead" function continuously and wait for data to become
+ /// avaialble. When data is received it will append the available
+ /// data to the internal cache and broadcast a
+ /// \b eBroadcastBitReadThreadGotBytes event.
+ ///
+ /// @param[in] comm_ptr
+ /// A pointer to an instance of this class.
+ ///
+ /// @return
+ /// \b NULL.
+ ///
+ /// @see void Communication::ReadThreadGotBytes (const uint8_t *, size_t);
+ //------------------------------------------------------------------
+ static lldb::thread_result_t
+ ReadThread (lldb::thread_arg_t comm_ptr);
+
+ void
+ SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback,
+ void *callback_baton);
+
+ static const char *
+ ConnectionStatusAsCString (lldb::ConnectionStatus status);
+
+ bool
+ GetCloseOnEOF () const
+ {
+ return m_close_on_eof;
+ }
+
+ void
+ SetCloseOnEOF (bool b)
+ {
+ m_close_on_eof = b;
+ }
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For Communication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Communication);
+
+
+protected:
+ lldb::ConnectionSP m_connection_sp; ///< The connection that is current in use by this communications class.
+ lldb::thread_t m_read_thread; ///< The read thread handle in case we need to cancel the thread.
+ bool m_read_thread_enabled;
+ std::string m_bytes; ///< A buffer to cache bytes read in the ReadThread function.
+ Mutex m_bytes_mutex; ///< A mutex to protect multi-threaded access to the cached bytes.
+ Mutex m_write_mutex; ///< Don't let multiple threads write at the same time...
+ ReadThreadBytesReceived m_callback;
+ void *m_callback_baton;
+ bool m_close_on_eof;
+
+ size_t
+ ReadFromConnection (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+ //------------------------------------------------------------------
+ /// Append new bytes that get read from the read thread into the
+ /// internal object byte cache. This will cause a \b
+ /// eBroadcastBitReadThreadGotBytes event to be broadcast if \a
+ /// broadcast is true.
+ ///
+ /// Subclasses can override this function in order to inspect the
+ /// received data and check if a packet is available.
+ ///
+ /// Subclasses can also still call this function from the
+ /// overridden method to allow the caching to correctly happen and
+ /// suppress the broadcasting of the \a eBroadcastBitReadThreadGotBytes
+ /// event by setting \a broadcast to false.
+ ///
+ /// @param[in] src
+ /// A source buffer that must be at least \a src_len bytes
+ /// long.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes to append to the cache.
+ //------------------------------------------------------------------
+ virtual void
+ AppendBytesToCache (const uint8_t *src, size_t src_len, bool broadcast, lldb::ConnectionStatus status);
+
+ //------------------------------------------------------------------
+ /// Get any available bytes from our data cache. If this call
+ /// empties the data cache, the \b eBroadcastBitReadThreadGotBytes event
+ /// will be reset to signify no more bytes are available.
+ ///
+ /// @param[in] dst
+ /// A destination buffer that must be at least \a dst_len bytes
+ /// long.
+ ///
+ /// @param[in] dst_len
+ /// The number of bytes to attempt to read from the cache,
+ /// and also the max number of bytes that can be placed into
+ /// \a dst.
+ ///
+ /// @return
+ /// The number of bytes extracted from the data cache.
+ //------------------------------------------------------------------
+ size_t
+ GetCachedBytes (void *dst, size_t dst_len);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Communication_h_
diff --git a/include/lldb/Core/Connection.h b/include/lldb/Core/Connection.h
new file mode 100644
index 000000000000..dde3c4b1022c
--- /dev/null
+++ b/include/lldb/Core/Connection.h
@@ -0,0 +1,162 @@
+//===-- Connection.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_Connection_h_
+#define liblldb_Connection_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Connection Connection.h "lldb/Core/Connection.h"
+/// @brief A communication connection class.
+///
+/// A class that implements that actual communication functions for
+/// connecting/disconnecting, reading/writing, and waiting for bytes
+/// to become available from a two way communication connection.
+///
+/// This class is designed to only do very simple communication
+/// functions. Instances can be instantiated and given to a
+/// Communication class to perform communications where clients can
+/// listen for broadcasts, and perform other higher level communications.
+//----------------------------------------------------------------------
+class Connection
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ //------------------------------------------------------------------
+ Connection ();
+
+ //------------------------------------------------------------------
+ /// Virtual destructor since this class gets subclassed and handed
+ /// to a Communication object.
+ //------------------------------------------------------------------
+ virtual
+ ~Connection ();
+
+ //------------------------------------------------------------------
+ /// Connect using the connect string \a url.
+ ///
+ /// @param[in] url
+ /// A string that contains all information needed by the
+ /// subclass to connect to another client.
+ ///
+ /// @param[out] error_ptr
+ /// A pointer to an error object that should be given an
+ /// approriate error value if this method returns false. This
+ /// value can be NULL if the error value should be ignored.
+ ///
+ /// @return
+ /// \b True if the connect succeeded, \b false otherwise. The
+ /// internal error object should be filled in with an
+ /// appropriate value based on the result of this function.
+ ///
+ /// @see Error& Communication::GetError ();
+ //------------------------------------------------------------------
+ virtual lldb::ConnectionStatus
+ Connect (const char *url, Error *error_ptr) = 0;
+
+ //------------------------------------------------------------------
+ /// Disconnect the communications connection if one is currently
+ /// connected.
+ ///
+ /// @param[out] error_ptr
+ /// A pointer to an error object that should be given an
+ /// approriate error value if this method returns false. This
+ /// value can be NULL if the error value should be ignored.
+ ///
+ /// @return
+ /// \b True if the disconnect succeeded, \b false otherwise. The
+ /// internal error object should be filled in with an
+ /// appropriate value based on the result of this function.
+ ///
+ /// @see Error& Communication::GetError ();
+ //------------------------------------------------------------------
+ virtual lldb::ConnectionStatus
+ Disconnect (Error *error_ptr) = 0;
+
+ //------------------------------------------------------------------
+ /// Check if the connection is valid.
+ ///
+ /// @return
+ /// \b True if this object is currently connected, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ IsConnected () const = 0;
+
+ //------------------------------------------------------------------
+ /// The read function that attempts to read from the connection.
+ ///
+ /// @param[in] dst
+ /// A destination buffer that must be at least \a dst_len bytes
+ /// long.
+ ///
+ /// @param[in] dst_len
+ /// The number of bytes to attempt to read, and also the max
+ /// number of bytes that can be placed into \a dst.
+ ///
+ /// @param[out] error_ptr
+ /// A pointer to an error object that should be given an
+ /// approriate error value if this method returns zero. This
+ /// value can be NULL if the error value should be ignored.
+ ///
+ /// @return
+ /// The number of bytes actually read.
+ ///
+ /// @see size_t Communication::Read (void *, size_t, uint32_t);
+ //------------------------------------------------------------------
+ virtual size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr) = 0;
+
+ //------------------------------------------------------------------
+ /// The actual write function that attempts to write to the
+ /// communications protocol.
+ ///
+ /// Subclasses must override this function.
+ ///
+ /// @param[in] src
+ /// A source buffer that must be at least \a src_len bytes
+ /// long.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes to attempt to write, and also the
+ /// number of bytes are currently available in \a src.
+ ///
+ /// @param[out] error_ptr
+ /// A pointer to an error object that should be given an
+ /// approriate error value if this method returns zero. This
+ /// value can be NULL if the error value should be ignored.
+ ///
+ /// @return
+ /// The number of bytes actually Written.
+ //------------------------------------------------------------------
+ virtual size_t
+ Write (const void *buffer, size_t length, lldb::ConnectionStatus &status, Error *error_ptr) = 0;
+
+private:
+ //------------------------------------------------------------------
+ // For Connection only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Connection);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Connection_h_
diff --git a/include/lldb/Core/ConnectionFileDescriptor.h b/include/lldb/Core/ConnectionFileDescriptor.h
new file mode 100644
index 000000000000..fe704d4cadf7
--- /dev/null
+++ b/include/lldb/Core/ConnectionFileDescriptor.h
@@ -0,0 +1,139 @@
+//===-- ConnectionFileDescriptor.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_ConnectionFileDescriptor_h_
+#define liblldb_ConnectionFileDescriptor_h_
+
+// C Includes
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Connection.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/SocketAddress.h"
+
+namespace lldb_private {
+
+class ConnectionFileDescriptor :
+ public Connection
+{
+public:
+
+ ConnectionFileDescriptor ();
+
+ ConnectionFileDescriptor (int fd, bool owns_fd);
+
+ virtual
+ ~ConnectionFileDescriptor ();
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb::ConnectionStatus
+ Connect (const char *s, Error *error_ptr);
+
+ virtual lldb::ConnectionStatus
+ Disconnect (Error *error_ptr);
+
+ virtual size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+
+ virtual size_t
+ Write (const void *src,
+ size_t src_len,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+
+ // If the read file descriptor is a socket, then return
+ // the port number that is being used by the socket.
+ in_port_t
+ GetReadPort () const;
+
+ // If the write file descriptor is a socket, then return
+ // the port number that is being used by the socket.
+ in_port_t
+ GetWritePort () const;
+
+protected:
+
+ void
+ OpenCommandPipe ();
+
+ void
+ CloseCommandPipe ();
+
+ lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ SocketListen (uint16_t listen_port_num, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ ConnectTCP (const char *host_and_port, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ ConnectUDP (const char *args, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ NamedSocketAccept (const char *socket_name, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ NamedSocketConnect (const char *socket_name, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ Close (int& fd, Error *error);
+
+ typedef enum
+ {
+ eFDTypeFile, // Other FD requireing read/write
+ eFDTypeSocket, // Socket requiring send/recv
+ eFDTypeSocketUDP // Unconnected UDP socket requiring sendto/recvfrom
+ } FDType;
+
+ int m_fd_send;
+ int m_fd_recv;
+ FDType m_fd_send_type;
+ FDType m_fd_recv_type;
+ SocketAddress m_udp_send_sockaddr;
+ bool m_should_close_fd; // True if this class should close the file descriptor when it goes away.
+ uint32_t m_socket_timeout_usec;
+ int m_pipe_read; // A pipe that we select on the reading end of along with
+ int m_pipe_write; // m_fd_recv so we can force ourselves out of the select.
+ Mutex m_mutex;
+ bool m_shutting_down; // This marks that we are shutting down so if we get woken up from BytesAvailable
+ // to disconnect, we won't try to read again.
+
+ static in_port_t
+ GetSocketPort (int fd);
+
+ static int
+ GetSocketOption(int fd, int level, int option_name, int &option_value);
+
+ static int
+ SetSocketOption(int fd, int level, int option_name, int option_value);
+
+ bool
+ SetSocketReceiveTimeout (uint32_t timeout_usec);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ConnectionFileDescriptor);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ConnectionFileDescriptor_h_
diff --git a/include/lldb/Core/ConnectionMachPort.h b/include/lldb/Core/ConnectionMachPort.h
new file mode 100644
index 000000000000..5613e7ee8008
--- /dev/null
+++ b/include/lldb/Core/ConnectionMachPort.h
@@ -0,0 +1,92 @@
+//===-- ConnectionMachPort.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#if defined(__APPLE__)
+
+#ifndef liblldb_ConnectionMachPort_h_
+#define liblldb_ConnectionMachPort_h_
+
+// C Includes
+#include <mach/mach.h>
+
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Connection.h"
+
+class ConnectionMachPort :
+ public lldb_private::Connection
+{
+public:
+ ConnectionMachPort ();
+
+ virtual
+ ~ConnectionMachPort ();
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, lldb_private::Error *error_ptr);
+
+ virtual lldb::ConnectionStatus
+ Connect (const char *s, lldb_private::Error *error_ptr);
+
+ virtual lldb::ConnectionStatus
+ Disconnect (lldb_private::Error *error_ptr);
+
+ virtual size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ lldb_private::Error *error_ptr);
+
+ virtual size_t
+ Write (const void *src,
+ size_t src_len,
+ lldb::ConnectionStatus &status,
+ lldb_private::Error *error_ptr);
+
+ lldb::ConnectionStatus
+ BootstrapCheckIn (const char *port_name,
+ lldb_private::Error *error_ptr);
+
+ lldb::ConnectionStatus
+ BootstrapLookup (const char *port_name,
+ lldb_private::Error *error_ptr);
+
+ struct PayloadType
+ {
+ uint32_t command;
+ uint32_t data_length;
+ uint8_t data[32];
+ };
+
+ kern_return_t
+ Send (const PayloadType &payload);
+
+ kern_return_t
+ Receive (PayloadType &payload);
+
+
+protected:
+ mach_port_t m_task;
+ mach_port_t m_port;
+
+private:
+
+
+ DISALLOW_COPY_AND_ASSIGN (ConnectionMachPort);
+};
+
+#endif // liblldb_ConnectionMachPort_h_
+
+#endif // #if defined(__APPLE__)
diff --git a/include/lldb/Core/ConnectionSharedMemory.h b/include/lldb/Core/ConnectionSharedMemory.h
new file mode 100644
index 000000000000..0f9cdcb8a92d
--- /dev/null
+++ b/include/lldb/Core/ConnectionSharedMemory.h
@@ -0,0 +1,70 @@
+//===-- ConnectionSharedMemory.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_ConnectionSharedMemory_h_
+#define liblldb_ConnectionSharedMemory_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Connection.h"
+#include "lldb/Core/DataBufferMemoryMap.h"
+
+namespace lldb_private {
+
+class ConnectionSharedMemory :
+ public Connection
+{
+public:
+
+ ConnectionSharedMemory ();
+
+ virtual
+ ~ConnectionSharedMemory ();
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb::ConnectionStatus
+ BytesAvailable (uint32_t timeout_usec, Error *error_ptr);
+
+ virtual lldb::ConnectionStatus
+ Connect (const char *s, Error *error_ptr);
+
+ virtual lldb::ConnectionStatus
+ Disconnect (Error *error_ptr);
+
+ virtual size_t
+ Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ lldb::ConnectionStatus &status,
+ Error *error_ptr);
+
+ virtual size_t
+ Write (const void *src, size_t src_len, lldb::ConnectionStatus &status, Error *error_ptr);
+
+ lldb::ConnectionStatus
+ Open (bool create, const char *name, size_t size, Error *error_ptr);
+
+protected:
+
+ std::string m_name;
+ int m_fd; // One buffer that contains all we need
+ DataBufferMemoryMap m_mmap;
+private:
+ DISALLOW_COPY_AND_ASSIGN (ConnectionSharedMemory);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ConnectionSharedMemory_h_
diff --git a/include/lldb/Core/ConstString.h b/include/lldb/Core/ConstString.h
new file mode 100644
index 000000000000..e692d3b96e5d
--- /dev/null
+++ b/include/lldb/Core/ConstString.h
@@ -0,0 +1,507 @@
+//===-- ConstString.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_ConstString_h_
+#define liblldb_ConstString_h_
+#if defined(__cplusplus)
+
+#include <assert.h>
+
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/StringRef.h"
+
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ConstString ConstString.h "lldb/Core/ConstString.h"
+/// @brief A uniqued constant string class.
+///
+/// Provides an efficient way to store strings as uniqued strings. After
+/// the strings are uniqued, finding strings that are equal to one
+/// another is very fast as just the pointers need to be compared. It
+/// also allows for many common strings from many different sources to
+/// be shared to keep the memory footprint low.
+///
+/// No reference counting is done on strings that are added to the
+/// string pool, once strings are added they are in the string pool for
+/// the life of the program.
+//----------------------------------------------------------------------
+class ConstString
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ ///
+ /// Initializes the string to an empty string.
+ //------------------------------------------------------------------
+ ConstString ():
+ m_string (NULL)
+ {
+ }
+
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Copies the string value in \a rhs into this object.
+ ///
+ /// @param[in] rhs
+ /// Another string object to copy.
+ //------------------------------------------------------------------
+ ConstString (const ConstString& rhs) :
+ m_string (rhs.m_string)
+ {
+ }
+
+ explicit ConstString (const llvm::StringRef &s);
+
+ //------------------------------------------------------------------
+ /// Construct with C String value
+ ///
+ /// Constructs this object with a C string by looking to see if the
+ /// C string already exists in the global string pool. If it doesn't
+ /// exist, it is added to the string pool.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ //------------------------------------------------------------------
+ explicit ConstString (const char *cstr);
+
+ //------------------------------------------------------------------
+ /// Construct with C String value with max length
+ ///
+ /// Constructs this object with a C string with a length. If
+ /// \a max_cstr_len is greater than the actual length of the string,
+ /// the string length will be truncated. This allows substrings to
+ /// be created without the need to NULL terminate the string as it
+ /// is passed into this function.
+ ///
+ /// @param[in] cstr
+ /// A pointer to the first character in the C string. The C
+ /// string can be NULL terminated in a buffer that contains
+ /// more characters than the length of the stirng, or the
+ /// string can be part of another string and a new substring
+ /// can be created.
+ ///
+ /// @param[in] max_cstr_len
+ /// The max length of \a cstr. If the string length of \a cstr
+ /// is less than \a max_cstr_len, then the string will be
+ /// truncated. If the string length of \a cstr is greater than
+ /// \a max_cstr_len, then only max_cstr_len bytes will be used
+ /// from \a cstr.
+ //------------------------------------------------------------------
+ explicit ConstString (const char *cstr, size_t max_cstr_len);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// Since constant string values are currently not reference counted,
+ /// there isn't much to do here.
+ //------------------------------------------------------------------
+ ~ConstString ()
+ {
+ }
+
+
+ //----------------------------------------------------------------------
+ /// C string equality binary predicate function object for ConstString
+ /// objects.
+ //----------------------------------------------------------------------
+ struct StringIsEqual
+ {
+ //--------------------------------------------------------------
+ /// C equality test.
+ ///
+ /// Two C strings are equal when they are contained in ConstString
+ /// objects when their pointer values are equal to each other.
+ ///
+ /// @return
+ /// Returns \b true if the C string in \a lhs is equal to
+ /// the C string value in \a rhs, \b false otherwise.
+ //--------------------------------------------------------------
+ bool operator()(const char* lhs, const char* rhs) const
+ {
+ return lhs == rhs;
+ }
+ };
+
+ //------------------------------------------------------------------
+ /// Convert to bool operator.
+ ///
+ /// This allows code to check a ConstString object to see if it
+ /// contains a valid string using code such as:
+ ///
+ /// @code
+ /// ConstString str(...);
+ /// if (str)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// /b True this object contains a valid non-empty C string, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ operator bool() const
+ {
+ return m_string && m_string[0];
+ }
+
+ //------------------------------------------------------------------
+ /// Assignment operator
+ ///
+ /// Assigns the string in this object with the value from \a rhs.
+ ///
+ /// @param[in] rhs
+ /// Another string object to copy into this object.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const ConstString&
+ operator = (const ConstString& rhs)
+ {
+ m_string = rhs.m_string;
+ return *this;
+ }
+
+ //------------------------------------------------------------------
+ /// Equal to operator
+ ///
+ /// Returns true if this string is equal to the string in \a rhs.
+ /// This operation is very fast as it results in a pointer
+ /// comparison since all strings are in a uniqued in a global string
+ /// pool.
+ ///
+ /// @param[in] rhs
+ /// Another string object to compare this object to.
+ ///
+ /// @return
+ /// @li \b true if this object is equal to \a rhs.
+ /// @li \b false if this object is not equal to \a rhs.
+ //------------------------------------------------------------------
+ bool
+ operator == (const ConstString& rhs) const
+ {
+ // We can do a pointer compare to compare these strings since they
+ // must come from the same pool in order to be equal.
+ return m_string == rhs.m_string;
+ }
+
+ //------------------------------------------------------------------
+ /// Not equal to operator
+ ///
+ /// Returns true if this string is not equal to the string in \a rhs.
+ /// This operation is very fast as it results in a pointer
+ /// comparison since all strings are in a uniqued in a global string
+ /// pool.
+ ///
+ /// @param[in] rhs
+ /// Another string object to compare this object to.
+ ///
+ /// @return
+ /// @li \b true if this object is not equal to \a rhs.
+ /// @li \b false if this object is equal to \a rhs.
+ //------------------------------------------------------------------
+ bool
+ operator != (const ConstString& rhs) const
+ {
+ return m_string != rhs.m_string;
+ }
+
+ bool
+ operator < (const ConstString& rhs) const;
+
+ //------------------------------------------------------------------
+ /// Get the string value as a C string.
+ ///
+ /// Get the value of the contained string as a NULL terminated C
+ /// string value.
+ ///
+ /// If \a value_if_empty is NULL, then NULL will be returned.
+ ///
+ /// @return
+ /// Returns \a value_if_empty if the string is empty, otherwise
+ /// the C string value contained in this object.
+ //------------------------------------------------------------------
+ const char *
+ AsCString(const char *value_if_empty = NULL) const
+ {
+ if (m_string == NULL)
+ return value_if_empty;
+ return m_string;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the string value as a llvm::StringRef
+ ///
+ /// @return
+ /// Returns a new llvm::StringRef object filled in with the
+ /// needed data.
+ //------------------------------------------------------------------
+ llvm::StringRef
+ GetStringRef () const
+ {
+ return llvm::StringRef (m_string, GetLength());
+ }
+
+ //------------------------------------------------------------------
+ /// Get the string value as a C string.
+ ///
+ /// Get the value of the contained string as a NULL terminated C
+ /// string value. Similar to the ConstString::AsCString() function,
+ /// yet this function will always return NULL if the string is not
+ /// valid. So this function is a direct accessor to the string
+ /// pointer value.
+ ///
+ /// @return
+ /// Returns NULL the string is invalid, otherwise the C string
+ /// value contained in this object.
+ //------------------------------------------------------------------
+ const char *
+ GetCString () const
+ {
+ return m_string;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Get the length in bytes of string value.
+ ///
+ /// The string pool stores the length of the string, so we can avoid
+ /// calling strlen() on the pointer value with this function.
+ ///
+ /// @return
+ /// Returns the number of bytes that this string occupies in
+ /// memory, not including the NULL termination byte.
+ //------------------------------------------------------------------
+ size_t
+ GetLength () const;
+
+ //------------------------------------------------------------------
+ /// Clear this object's state.
+ ///
+ /// Clear any contained string and reset the value to the an empty
+ /// string value.
+ //------------------------------------------------------------------
+ void
+ Clear ()
+ {
+ m_string = NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Compare two string objects.
+ ///
+ /// Compares the C string values contained in \a lhs and \a rhs and
+ /// returns an integer result.
+ ///
+ /// NOTE: only call this function when you want a true string
+ /// comparision. If you want string equality use the, use the ==
+ /// operator as it is much more efficient. Also if you want string
+ /// inequality, use the != operator for the same reasons.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const ConstString object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const ConstString object reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ static int
+ Compare (const ConstString& lhs, const ConstString& rhs);
+
+ //------------------------------------------------------------------
+ /// Dump the object description to a stream.
+ ///
+ /// Dump the string value to the stream \a s. If the contained string
+ /// is empty, print \a value_if_empty to the stream instead. If
+ /// \a value_if_empty is NULL, then nothing will be dumped to the
+ /// stream.
+ ///
+ /// @param[in] s
+ /// The stream that will be used to dump the object description.
+ ///
+ /// @param[in] value_if_empty
+ /// The value to dump if the string is empty. If NULL, nothing
+ /// will be output to the stream.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, const char *value_if_empty = NULL) const;
+
+ //------------------------------------------------------------------
+ /// Dump the object debug description to a stream.
+ ///
+ /// @param[in] s
+ /// The stream that will be used to dump the object description.
+ //------------------------------------------------------------------
+ void
+ DumpDebug (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Test for empty string.
+ ///
+ /// @return
+ /// @li \b true if the contained string is empty.
+ /// @li \b false if the contained string is not empty.
+ //------------------------------------------------------------------
+ bool
+ IsEmpty () const
+ {
+ return m_string == NULL || m_string[0] == '\0';
+ }
+
+ //------------------------------------------------------------------
+ /// Set the C string value.
+ ///
+ /// Set the string value in the object by uniquing the \a cstr
+ /// string value in our global string pool.
+ ///
+ /// If the C string already exists in the global string pool, it
+ /// finds the current entry and returns the existing value. If it
+ /// doesn't exist, it is added to the string pool.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ //------------------------------------------------------------------
+ void
+ SetCString (const char *cstr);
+
+ void
+ SetString (const llvm::StringRef &s);
+
+ //------------------------------------------------------------------
+ /// Set the C string value and its mangled counterpart.
+ ///
+ /// Object files and debug sybmols often use mangled string to
+ /// represent the linkage name for a symbol, function or global.
+ /// The string pool can efficiently store these values and their
+ /// counterparts so when we run into another instance of a mangled
+ /// name, we can avoid calling the name demangler over and over on
+ /// the same strings and then trying to unique them.
+ ///
+ /// @param[in] demangled
+ /// The demangled C string to correlate with the \a mangled
+ /// name.
+ ///
+ /// @param[in] mangled
+ /// The already uniqued mangled ConstString to correlate the
+ /// soon to be uniqued version of \a demangled.
+ //------------------------------------------------------------------
+ void
+ SetCStringWithMangledCounterpart (const char *demangled,
+ const ConstString &mangled);
+
+ //------------------------------------------------------------------
+ /// Retrieve the mangled or demangled counterpart for a mangled
+ /// or demangled ConstString.
+ ///
+ /// Object files and debug sybmols often use mangled string to
+ /// represent the linkage name for a symbol, function or global.
+ /// The string pool can efficiently store these values and their
+ /// counterparts so when we run into another instance of a mangled
+ /// name, we can avoid calling the name demangler over and over on
+ /// the same strings and then trying to unique them.
+ ///
+ /// @param[in] counterpart
+ /// A reference to a ConstString object that might get filled in
+ /// with the demangled/mangled counterpart.
+ ///
+ /// @return
+ /// /b True if \a counterpart was filled in with the counterpart
+ /// /b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetMangledCounterpart (ConstString &counterpart) const;
+
+ //------------------------------------------------------------------
+ /// Set the C string value with length.
+ ///
+ /// Set the string value in the object by uniquing \a cstr_len bytes
+ /// starting at the \a cstr string value in our global string pool.
+ /// If trim is true, then \a cstr_len indicates a maximum length of
+ /// the CString and if the actual length of the string is less, then
+ /// it will be trimmed.
+ ///
+ /// If the C string already exists in the global string pool, it
+ /// finds the current entry and returns the existing value. If it
+ /// doesn't exist, it is added to the string pool.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string to add to the string pool.
+ ///
+ /// @param[in] cstr_len
+ /// The maximum length of the C string.
+ //------------------------------------------------------------------
+ void
+ SetCStringWithLength (const char *cstr, size_t cstr_len);
+
+ //------------------------------------------------------------------
+ /// Set the C string value with the minimum length between
+ /// \a fixed_cstr_len and the actual length of the C string. This
+ /// can be used for data structures that have a fixed length to
+ /// store a C string where the string might not be NULL terminated
+ /// if the string takes the entire buffer.
+ //------------------------------------------------------------------
+ void
+ SetTrimmedCStringWithLength (const char *cstr, size_t fixed_cstr_len);
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Return the size in bytes that this object takes in memory. This
+ /// returns the size in bytes of this object, which does not include
+ /// any the shared string values it may refer to.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const
+ {
+ return sizeof(ConstString);
+ }
+
+
+ //------------------------------------------------------------------
+ /// Get the size in bytes of the current global string pool.
+ ///
+ /// Reports the the size in bytes of all shared C string values,
+ /// containers and any other values as a byte size for the
+ /// entire string pool.
+ ///
+ /// @return
+ /// The number of bytes that the global string pool occupies
+ /// in memory.
+ //------------------------------------------------------------------
+ static size_t
+ StaticMemorySize ();
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ const char *m_string;
+};
+
+//------------------------------------------------------------------
+/// Stream the string value \a str to the stream \a s
+//------------------------------------------------------------------
+Stream& operator << (Stream& s, const ConstString& str);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_ConstString_h_
diff --git a/include/lldb/Core/DataBuffer.h b/include/lldb/Core/DataBuffer.h
new file mode 100644
index 000000000000..e64245dead3d
--- /dev/null
+++ b/include/lldb/Core/DataBuffer.h
@@ -0,0 +1,94 @@
+//===-- DataBuffer.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_DataBuffer_h_
+#define liblldb_DataBuffer_h_
+#if defined(__cplusplus)
+
+#include <stdint.h>
+#include <string.h>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DataBuffer DataBuffer.h "lldb/Core/DataBuffer.h"
+/// @brief A pure virtual protocol class for abstracted data buffers.
+///
+/// DataBuffer is an abtract class that gets packaged into a shared pointer
+/// that can use to implement various ways to store data (on the heap,
+/// memory mapped, cached inferior memory). It gets used by DataExtractor
+/// so many DataExtractor objects can share the same data and sub-ranges
+/// of that shared data, and the last object that contains a reference
+/// to the shared data will free it.
+///
+/// Subclasses can implement as many different constructors or member
+/// functions that allow data to be stored in the object's buffer prior
+/// to handing the shared data to clients that use these buffers.
+///
+/// All subclasses must override all of the pure virtual functions as
+/// they are used by clients to access the data. Having a common
+/// interface allows different ways of storing data, yet using it in
+/// one common way.
+///
+/// This class currently expects all data to be available without any
+/// extra calls being made, but we can modify it to optionally get
+/// data on demand with some extra function calls to load the data
+/// before it gets accessed.
+//----------------------------------------------------------------------
+class DataBuffer
+{
+public:
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// The destructor is virtual as other classes will inherit from
+ /// this class and be downcast to the DataBuffer pure virtual
+ /// interface. The virtual destructor ensures that destructing the
+ /// base class will destruct the class that inherited from it
+ /// correctly.
+ //------------------------------------------------------------------
+ virtual
+ ~DataBuffer()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Get a pointer to the data.
+ ///
+ /// @return
+ /// A pointer to the bytes owned by this object, or NULL if the
+ /// object contains no bytes.
+ //------------------------------------------------------------------
+ virtual uint8_t *
+ GetBytes () = 0;
+
+ //------------------------------------------------------------------
+ /// Get a const pointer to the data.
+ ///
+ /// @return
+ /// A const pointer to the bytes owned by this object, or NULL
+ /// if the object contains no bytes.
+ //------------------------------------------------------------------
+ virtual const uint8_t *
+ GetBytes () const = 0;
+
+ //------------------------------------------------------------------
+ /// Get the number of bytes in the data buffer.
+ ///
+ /// @return
+ /// The number of bytes this object currently contains.
+ //------------------------------------------------------------------
+ virtual lldb::offset_t
+ GetByteSize() const = 0;
+};
+
+} // namespace lldb_private
+
+#endif /// #if defined(__cplusplus)
+#endif /// lldb_DataBuffer_h_
diff --git a/include/lldb/Core/DataBufferHeap.h b/include/lldb/Core/DataBufferHeap.h
new file mode 100644
index 000000000000..dac9a28befb9
--- /dev/null
+++ b/include/lldb/Core/DataBufferHeap.h
@@ -0,0 +1,139 @@
+//===-- DataBufferHeap.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_DataBufferHeap_h_
+#define liblldb_DataBufferHeap_h_
+#if defined(__cplusplus)
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataBuffer.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DataBufferHeap DataBufferHeap.h "lldb/Core/DataBufferHeap.h"
+/// @brief A subclass of DataBuffer that stores a data buffer on the heap.
+///
+/// This class keeps its data in a heap based buffer that is owned by
+/// the object. This class is best used to store chunks of data that
+/// are created or read from sources that can't intelligently and lazily
+/// fault new data pages in. Large amounts of data that comes from files
+/// should probably use the DataBufferMemoryMap class.
+//----------------------------------------------------------------------
+class DataBufferHeap : public DataBuffer
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ ///
+ /// Initializes the heap based buffer with no bytes.
+ //------------------------------------------------------------------
+ DataBufferHeap ();
+
+ //------------------------------------------------------------------
+ /// Construct with size \a n and fill with \a ch.
+ ///
+ /// Initialize this class with \a n bytes and fills the buffer with
+ /// \a ch.
+ ///
+ /// @param[in] n
+ /// The number of bytes that heap based buffer should contain.
+ ///
+ /// @param[in] ch
+ /// The character to use when filling the buffer initially.
+ //------------------------------------------------------------------
+ DataBufferHeap (lldb::offset_t n, uint8_t ch);
+
+ //------------------------------------------------------------------
+ /// Construct by making a copy of \a src_len bytes from \a src.
+ ///
+ /// @param[in] src
+ /// A pointer to the data to copy.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes in \a src to copy.
+ //------------------------------------------------------------------
+ DataBufferHeap (const void *src, lldb::offset_t src_len);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Virtual destructor since this class inherits from a pure virtual
+ /// base class #DataBuffer.
+ //------------------------------------------------------------------
+ virtual
+ ~DataBufferHeap();
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetBytes()
+ //------------------------------------------------------------------
+ virtual uint8_t *
+ GetBytes ();
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetBytes() const
+ //------------------------------------------------------------------
+ virtual const uint8_t *
+ GetBytes () const;
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetByteSize() const
+ //------------------------------------------------------------------
+ virtual lldb::offset_t
+ GetByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Set the number of bytes in the data buffer.
+ ///
+ /// Sets the number of bytes that this object should be able to
+ /// contain. This can be used prior to copying data into the buffer.
+ ///
+ /// @param[in] byte_size
+ /// The new size in bytes that this data buffer should attempt
+ /// to resize itself to.
+ ///
+ /// @return
+ /// The size in bytes after that this heap buffer was
+ /// successfully resized to.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ SetByteSize (lldb::offset_t byte_size);
+
+ //------------------------------------------------------------------
+ /// Makes a copy of the \a src_len bytes in \a src.
+ ///
+ /// Copies the data in \a src into an internal buffer.
+ ///
+ /// @param[in] src
+ /// A pointer to the data to copy.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes in \a src to copy.
+ //------------------------------------------------------------------
+ void
+ CopyData (const void *src, lldb::offset_t src_len);
+
+ void
+ Clear();
+
+private:
+ //------------------------------------------------------------------
+ // This object uses a std::vector<uint8_t> to store its data. This
+ // takes care of free the data when the object is deleted.
+ //------------------------------------------------------------------
+ typedef std::vector<uint8_t> buffer_t; ///< Buffer type
+ buffer_t m_data; ///< The heap based buffer where data is stored
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_DataBufferHeap_h_
diff --git a/include/lldb/Core/DataBufferMemoryMap.h b/include/lldb/Core/DataBufferMemoryMap.h
new file mode 100644
index 000000000000..d4a448a5df52
--- /dev/null
+++ b/include/lldb/Core/DataBufferMemoryMap.h
@@ -0,0 +1,160 @@
+//===-- DataBufferMemoryMap.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_DataBufferMemoryMap_h_
+#define liblldb_DataBufferMemoryMap_h_
+#if defined(__cplusplus)
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+#include <string>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DataBufferMemoryMap DataBufferMemoryMap.h "lldb/Core/DataBufferMemoryMap.h"
+/// @brief A subclass of DataBuffer that memory maps data.
+///
+/// This class memory maps data and stores any needed data for the
+/// memory mapping in its internal state. Memory map requests are not
+/// required to have any alignment or size constraints, this class will
+/// work around any host OS issues regarding such things.
+///
+/// This class is designed to allow pages to be faulted in as needed and
+/// works well data from large files that won't be accessed all at once.
+//----------------------------------------------------------------------
+class DataBufferMemoryMap : public DataBuffer
+{
+public:
+ //------------------------------------------------------------------
+ /// Default Constructor
+ //------------------------------------------------------------------
+ DataBufferMemoryMap ();
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Virtual destructor since this class inherits from a pure virtual
+ /// base class #DataBuffer.
+ //------------------------------------------------------------------
+ virtual
+ ~DataBufferMemoryMap ();
+
+ //------------------------------------------------------------------
+ /// Reverts this object to an empty state by unmapping any memory
+ /// that is currently owned.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetBytes()
+ //------------------------------------------------------------------
+ virtual uint8_t *
+ GetBytes ();
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetBytes() const
+ //------------------------------------------------------------------
+ virtual const uint8_t *
+ GetBytes () const;
+
+ //------------------------------------------------------------------
+ /// @copydoc DataBuffer::GetByteSize() const
+ //------------------------------------------------------------------
+ virtual lldb::offset_t
+ GetByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Error get accessor.
+ ///
+ /// @return
+ /// A const reference to Error object in case memory mapping
+ /// fails.
+ //------------------------------------------------------------------
+ const Error &
+ GetError() const;
+
+ //------------------------------------------------------------------
+ /// Memory map all or part of a file.
+ ///
+ /// Memory map \a length bytes from \a file starting \a offset
+ /// bytes into the file. If \a length is set to \c SIZE_MAX,
+ /// then map as many bytes as possible.
+ ///
+ /// @param[in] file
+ /// The file specification from which to map data.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes from the beginning of the file where
+ /// memory mapping should begin.
+ ///
+ /// @param[in] length
+ /// The size in bytes that should be mapped starting \a offset
+ /// bytes into the file. If \a length is \c SIZE_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// The number of bytes mapped starting from the \a offset.
+ //------------------------------------------------------------------
+ size_t
+ MemoryMapFromFileSpec (const FileSpec* file,
+ lldb::offset_t offset = 0,
+ lldb::offset_t length = SIZE_MAX,
+ bool writeable = false);
+
+ //------------------------------------------------------------------
+ /// Memory map all or part of a file.
+ ///
+ /// Memory map \a length bytes from an opened file descriptor \a fd
+ /// starting \a offset bytes into the file. If \a length is set to
+ /// \c SIZE_MAX, then map as many bytes as possible.
+ ///
+ /// @param[in] fd
+ /// The posix file descriptor for an already opened file
+ /// from which to map data.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes from the beginning of the file where
+ /// memory mapping should begin.
+ ///
+ /// @param[in] length
+ /// The size in bytes that should be mapped starting \a offset
+ /// bytes into the file. If \a length is \c SIZE_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// The number of bytes mapped starting from the \a offset.
+ //------------------------------------------------------------------
+ size_t
+ MemoryMapFromFileDescriptor (int fd,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ bool write,
+ bool fd_is_file);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DataBufferMemoryMap can see and modify these
+ //------------------------------------------------------------------
+ uint8_t * m_mmap_addr; ///< The actual pointer that was returned from \c mmap()
+ size_t m_mmap_size; ///< The actual number of bytes that were mapped when \c mmap() was called
+ uint8_t *m_data; ///< The data the user requested somewhere within the memory mapped data.
+ lldb::offset_t m_size; ///< The size of the data the user got when data was requested
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DataBufferMemoryMap);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_DataBufferMemoryMap_h_
diff --git a/include/lldb/Core/DataEncoder.h b/include/lldb/Core/DataEncoder.h
new file mode 100644
index 000000000000..658cce0d2b4b
--- /dev/null
+++ b/include/lldb/Core/DataEncoder.h
@@ -0,0 +1,459 @@
+//===-- DataEncoder.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_DataEncoder_h_
+#define liblldb_DataEncoder_h_
+
+#if defined (__cplusplus)
+
+#include "lldb/lldb-private.h"
+#include <limits.h>
+#include <stdint.h>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DataEncoder DataEncoder.h "lldb/Core/DataEncoder.h"
+/// @brief An binary data encoding class.
+///
+/// DataEncoder is a class that can encode binary data (swapping if needed)
+/// to a data buffer. The data buffer can be caller owned, or can be
+/// shared data that can be shared between multiple DataEncoder or
+/// DataEncoder instances.
+///
+/// @see DataBuffer
+//----------------------------------------------------------------------
+class DataEncoder
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize all members to a default empty state.
+ //------------------------------------------------------------------
+ DataEncoder ();
+
+ //------------------------------------------------------------------
+ /// Construct with a buffer that is owned by the caller.
+ ///
+ /// This constructor allows us to use data that is owned by the
+ /// caller. The data must stay around as long as this object is
+ /// valid.
+ ///
+ /// @param[in] data
+ /// A pointer to caller owned data.
+ ///
+ /// @param[in] data_length
+ /// The length in bytes of \a data.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @param[in] addr_size
+ /// A new address byte size value.
+ //------------------------------------------------------------------
+ DataEncoder (void* data, uint32_t data_length, lldb::ByteOrder byte_order, uint8_t addr_size);
+
+ //------------------------------------------------------------------
+ /// Construct with shared data.
+ ///
+ /// Copies the data shared pointer which adds a reference to the
+ /// contained in \a data_sp. The shared data reference is reference
+ /// counted to ensure the data lives as long as anyone still has a
+ /// valid shared pointer to the data in \a data_sp.
+ ///
+ /// @param[in] data_sp
+ /// A shared pointer to data.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @param[in] addr_size
+ /// A new address byte size value.
+ //------------------------------------------------------------------
+ DataEncoder (const lldb::DataBufferSP& data_sp, lldb::ByteOrder byte_order, uint8_t addr_size);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// If this object contains a valid shared data reference, the
+ /// reference count on the data will be decremented, and if zero,
+ /// the data will be freed.
+ //------------------------------------------------------------------
+ ~DataEncoder ();
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clears the object contents back to a default invalid state, and
+ /// release any references to shared data that this object may
+ /// contain.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Get the current address size.
+ ///
+ /// Return the size in bytes of any address values this object will
+ /// extract.
+ ///
+ /// @return
+ /// The size in bytes of address values that will be extracted.
+ //------------------------------------------------------------------
+ uint8_t
+ GetAddressByteSize () const
+ {
+ return m_addr_size;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Get the number of bytes contained in this object.
+ ///
+ /// @return
+ /// The total number of bytes of data this object refers to.
+ //------------------------------------------------------------------
+ size_t
+ GetByteSize () const
+ {
+ return m_end - m_start;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the data end pointer.
+ ///
+ /// @return
+ /// Returns a pointer to the next byte contained in this
+ /// object's data, or NULL of there is no data in this object.
+ //------------------------------------------------------------------
+ uint8_t *
+ GetDataEnd ()
+ {
+ return m_end;
+ }
+
+ const uint8_t *
+ GetDataEnd () const
+ {
+ return m_end;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the shared data offset.
+ ///
+ /// Get the offset of the first byte of data in the shared data (if
+ /// any).
+ ///
+ /// @return
+ /// If this object contains shared data, this function returns
+ /// the offset in bytes into that shared data, zero otherwise.
+ //------------------------------------------------------------------
+ size_t
+ GetSharedDataOffset () const;
+
+
+ //------------------------------------------------------------------
+ /// Get the current byte order value.
+ ///
+ /// @return
+ /// The current byte order value from this object's internal
+ /// state.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetByteOrder() const
+ {
+ return m_byte_order;
+ }
+
+ //------------------------------------------------------------------
+ /// Get a the data start pointer.
+ ///
+ /// @return
+ /// Returns a pointer to the first byte contained in this
+ /// object's data, or NULL of there is no data in this object.
+ //------------------------------------------------------------------
+ uint8_t *
+ GetDataStart ()
+ {
+ return m_start;
+ }
+
+ const uint8_t *
+ GetDataStart () const
+ {
+ return m_start;
+ }
+
+ //------------------------------------------------------------------
+ /// Encode unsigned integer values into the data at \a offset.
+ ///
+ /// @param[in] offset
+ /// The offset within the contained data at which to put the
+ /// data.
+ ///
+ /// @param[in] value
+ /// The value to encode into the data.
+ ///
+ /// @return
+ /// The next offset in the bytes of this data if the data
+ /// was successfully encoded, UINT32_MAX if the encoding failed.
+ //------------------------------------------------------------------
+ uint32_t
+ PutU8 (uint32_t offset, uint8_t value);
+
+ uint32_t
+ PutU16 (uint32_t offset, uint16_t value);
+
+ uint32_t
+ PutU32 (uint32_t offset, uint32_t value);
+
+ uint32_t
+ PutU64 (uint32_t offset, uint64_t value);
+
+ //------------------------------------------------------------------
+ /// Encode an unsigned integer of size \a byte_size to \a offset.
+ ///
+ /// Encode a single integer value at \a offset and return the offset
+ /// that follows the newly encoded integer when the data is successfully
+ /// encoded into the existing data. There must be enough room in the
+ /// data, else UINT32_MAX will be returned to indicate that encoding
+ /// failed.
+ ///
+ /// @param[in] offset
+ /// The offset within the contained data at which to put the
+ /// encoded integer.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to encode.
+ ///
+ /// @param[in] value
+ /// The integer value to write. The least significate bytes of
+ /// the integer value will be written if the size is less than
+ /// 8 bytes.
+ ///
+ /// @return
+ /// The next offset in the bytes of this data if the integer
+ /// was successfully encoded, UINT32_MAX if the encoding failed.
+ //------------------------------------------------------------------
+ uint32_t
+ PutMaxU64 (uint32_t offset, uint32_t byte_size, uint64_t value);
+
+ //------------------------------------------------------------------
+ /// Encode an arbitrary number of bytes.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes into the contained data at which to
+ /// start encoding.
+ ///
+ /// @param[int] src
+ /// The buffer that contains the the bytes to encode.
+ ///
+ /// @param[in] src_len
+ /// The number of bytes to encode.
+ ///
+ /// @return
+ /// The next valid offset within data if the put operation
+ /// was successful, else UINT32_MAX to indicate the put failed.
+ //------------------------------------------------------------------
+ uint32_t
+ PutData (uint32_t offset,
+ const void *src,
+ uint32_t src_len);
+
+ //------------------------------------------------------------------
+ /// Encode an address in the existing buffer at \a offset bytes into
+ /// the buffer.
+ ///
+ /// Encode a single address (honoring the m_addr_size member) to
+ /// the data and return the next offset where subsequent data would
+ /// go.
+ /// pointed to by \a offset_ptr. The size of the extracted address
+ /// comes from the \a m_addr_size member variable and should be
+ /// set correctly prior to extracting any address values.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The next valid offset within data if the put operation
+ /// was successful, else UINT32_MAX to indicate the put failed.
+ //------------------------------------------------------------------
+ uint32_t
+ PutAddress (uint32_t offset, lldb::addr_t addr);
+
+ //------------------------------------------------------------------
+ /// Put a C string to \a offset.
+ ///
+ /// Encodes a C string into the existing data including the
+ /// terminating
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// A pointer to the C string value in the data. If the offset
+ /// pointed to by \a offset_ptr is out of bounds, or if the
+ /// offset plus the length of the C string is out of bounds,
+ /// NULL will be returned.
+ //------------------------------------------------------------------
+ uint32_t
+ PutCString (uint32_t offset_ptr, const char *cstr);
+
+ lldb::DataBufferSP &
+ GetSharedDataBuffer ()
+ {
+ return m_data_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Set the address byte size.
+ ///
+ /// Set the size in bytes that will be used when extracting any
+ /// address and pointer values from data contained in this object.
+ ///
+ /// @param[in] addr_size
+ /// The size in bytes to use when extracting addresses.
+ //------------------------------------------------------------------
+ void
+ SetAddressByteSize (uint8_t addr_size)
+ {
+ m_addr_size = addr_size;
+ }
+
+ //------------------------------------------------------------------
+ /// Set data with a buffer that is caller owned.
+ ///
+ /// Use data that is owned by the caller when extracting values.
+ /// The data must stay around as long as this object, or any object
+ /// that copies a subset of this object's data, is valid. If \a
+ /// bytes is NULL, or \a length is zero, this object will contain
+ /// no data.
+ ///
+ /// @param[in] bytes
+ /// A pointer to caller owned data.
+ ///
+ /// @param[in] length
+ /// The length in bytes of \a bytes.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @return
+ /// The number of bytes that this object now contains.
+ //------------------------------------------------------------------
+ uint32_t
+ SetData (const void *bytes, uint32_t length, lldb::ByteOrder byte_order);
+
+ //------------------------------------------------------------------
+ /// Adopt a subset of shared data in \a data_sp.
+ ///
+ /// Copies the data shared pointer which adds a reference to the
+ /// contained in \a data_sp. The shared data reference is reference
+ /// counted to ensure the data lives as long as anyone still has a
+ /// valid shared pointer to the data in \a data_sp. The byte order
+ /// and address byte size settings remain the same. If
+ /// \a offset is not a valid offset in \a data_sp, then no reference
+ /// to the shared data will be added. If there are not \a length
+ /// bytes available in \a data starting at \a offset, the length
+ /// will be truncated to contains as many bytes as possible.
+ ///
+ /// @param[in] data_sp
+ /// A shared pointer to data.
+ ///
+ /// @param[in] offset
+ /// The offset into \a data_sp at which the subset starts.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the subset of \a data_sp.
+ ///
+ /// @return
+ /// The number of bytes that this object now contains.
+ //------------------------------------------------------------------
+ uint32_t
+ SetData (const lldb::DataBufferSP& data_sp, uint32_t offset = 0, uint32_t length = UINT32_MAX);
+
+ //------------------------------------------------------------------
+ /// Set the byte_order value.
+ ///
+ /// Sets the byte order of the data to extract. Extracted values
+ /// will be swapped if necessary when decoding.
+ ///
+ /// @param[in] byte_order
+ /// The byte order value to use when extracting data.
+ //------------------------------------------------------------------
+ void
+ SetByteOrder (lldb::ByteOrder byte_order)
+ {
+ m_byte_order = byte_order;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Test the validity of \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset into the data in this
+ /// object, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ValidOffset (uint32_t offset) const
+ {
+ return offset < GetByteSize();
+ }
+
+ //------------------------------------------------------------------
+ /// Test the availability of \a length bytes of data from \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset and there are \a
+ /// length bytes available at that offset, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ValidOffsetForDataOfSize (uint32_t offset, uint32_t length) const
+ {
+ return length <= BytesLeft (offset);
+ }
+
+ uint32_t
+ BytesLeft (uint32_t offset) const
+ {
+ const uint32_t size = GetByteSize();
+ if (size > offset)
+ return size - offset;
+ return 0;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ uint8_t *m_start; ///< A pointer to the first byte of data.
+ uint8_t *m_end; ///< A pointer to the byte that is past the end of the data.
+ lldb::ByteOrder m_byte_order; ///< The byte order of the data we are extracting from.
+ uint8_t m_addr_size; ///< The address size to use when extracting pointers or addresses
+ mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multilple instances
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (DataEncoder);
+
+};
+
+} // namespace lldb_private
+
+#endif // #if defined (__cplusplus)
+#endif // #ifndef liblldb_DataEncoder_h_
diff --git a/include/lldb/Core/DataExtractor.h b/include/lldb/Core/DataExtractor.h
new file mode 100644
index 000000000000..a8593043cb15
--- /dev/null
+++ b/include/lldb/Core/DataExtractor.h
@@ -0,0 +1,1298 @@
+//===-- DataExtractor.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_DataExtractor_h_
+#define liblldb_DataExtractor_h_
+#if defined (__cplusplus)
+
+
+#include "lldb/lldb-private.h"
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DataExtractor DataExtractor.h "lldb/Core/DataExtractor.h"
+/// @brief An data extractor class.
+///
+/// DataExtractor is a class that can extract data (swapping if needed)
+/// from a data buffer. The data buffer can be caller owned, or can be
+/// shared data that can be shared between multiple DataExtractor
+/// instances. Multiple DataExtractor objects can share the same data,
+/// yet extract values in different address sizes and byte order modes.
+/// Each object can have a unique position in the shared data and extract
+/// data from different offsets.
+///
+/// @see DataBuffer
+//----------------------------------------------------------------------
+class DataExtractor
+{
+public:
+ //------------------------------------------------------------------
+ /// @typedef DataExtractor::Type
+ /// @brief Type enumerations used in the dump routines.
+ /// @see DataExtractor::Dump()
+ /// @see DataExtractor::DumpRawHexBytes()
+ //------------------------------------------------------------------
+ typedef enum
+ {
+ TypeUInt8, ///< Format output as unsigned 8 bit integers
+ TypeChar, ///< Format output as characters
+ TypeUInt16, ///< Format output as unsigned 16 bit integers
+ TypeUInt32, ///< Format output as unsigned 32 bit integers
+ TypeUInt64, ///< Format output as unsigned 64 bit integers
+ TypePointer, ///< Format output as pointers
+ TypeULEB128, ///< Format output as ULEB128 numbers
+ TypeSLEB128 ///< Format output as SLEB128 numbers
+ } Type;
+
+ static void
+ DumpHexBytes (Stream *s,
+ const void *src,
+ size_t src_len,
+ uint32_t bytes_per_line,
+ lldb::addr_t base_addr); // Pass LLDB_INVALID_ADDRESS to not show address at start of line
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize all members to a default empty state.
+ //------------------------------------------------------------------
+ DataExtractor ();
+
+ //------------------------------------------------------------------
+ /// Construct with a buffer that is owned by the caller.
+ ///
+ /// This constructor allows us to use data that is owned by the
+ /// caller. The data must stay around as long as this object is
+ /// valid.
+ ///
+ /// @param[in] data
+ /// A pointer to caller owned data.
+ ///
+ /// @param[in] data_length
+ /// The length in bytes of \a data.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @param[in] addr_size
+ /// A new address byte size value.
+ //------------------------------------------------------------------
+ DataExtractor (const void* data, lldb::offset_t data_length, lldb::ByteOrder byte_order, uint32_t addr_size);
+
+ //------------------------------------------------------------------
+ /// Construct with shared data.
+ ///
+ /// Copies the data shared pointer which adds a reference to the
+ /// contained in \a data_sp. The shared data reference is reference
+ /// counted to ensure the data lives as long as anyone still has a
+ /// valid shared pointer to the data in \a data_sp.
+ ///
+ /// @param[in] data_sp
+ /// A shared pointer to data.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @param[in] addr_size
+ /// A new address byte size value.
+ //------------------------------------------------------------------
+ DataExtractor (const lldb::DataBufferSP& data_sp, lldb::ByteOrder byte_order, uint32_t addr_size);
+
+ //------------------------------------------------------------------
+ /// Construct with a subset of \a data.
+ ///
+ /// Initialize this object with a subset of the data bytes in \a
+ /// data. If \a data contains shared data, then a reference to the
+ /// shared data will be added to ensure the shared data stays around
+ /// as long as any objects have references to the shared data. The
+ /// byte order value and the address size settings are copied from \a
+ /// data. If \a offset is not a valid offset in \a data, then no
+ /// reference to the shared data will be added. If there are not
+ /// \a length bytes available in \a data starting at \a offset,
+ /// the length will be truncated to contain as many bytes as
+ /// possible.
+ ///
+ /// @param[in] data
+ /// Another DataExtractor object that contains data.
+ ///
+ /// @param[in] offset
+ /// The offset into \a data at which the subset starts.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the subset of data.
+ //------------------------------------------------------------------
+ DataExtractor (const DataExtractor& data, lldb::offset_t offset, lldb::offset_t length);
+
+ DataExtractor (const DataExtractor& rhs);
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Copies all data, byte order and address size settings from \a rhs into
+ /// this object. If \a rhs contains shared data, a reference to that
+ /// shared data will be added.
+ ///
+ /// @param[in] rhs
+ /// Another DataExtractor object to copy.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const DataExtractor&
+ operator= (const DataExtractor& rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// If this object contains a valid shared data reference, the
+ /// reference count on the data will be decremented, and if zero,
+ /// the data will be freed.
+ //------------------------------------------------------------------
+ ~DataExtractor ();
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clears the object contents back to a default invalid state, and
+ /// release any references to shared data that this object may
+ /// contain.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Dumps the binary data as \a type objects to stream \a s (or to
+ /// Log() if \a s is NULL) starting \a offset bytes into the data
+ /// and stopping after dumping \a length bytes. The offset into the
+ /// data is displayed at the beginning of each line and can be
+ /// offset by base address \a base_addr. \a num_per_line objects
+ /// will be displayed on each line.
+ ///
+ /// @param[in] s
+ /// The stream to dump the output to. If NULL the output will
+ /// be dumped to Log().
+ ///
+ /// @param[in] offset
+ /// The offset into the data at which to start dumping.
+ ///
+ /// @param[in] length
+ /// The number of bytes to dump.
+ ///
+ /// @param[in] base_addr
+ /// The base address that gets added to the offset displayed on
+ /// each line.
+ ///
+ /// @param[in] num_per_line
+ /// The number of \a type objects to display on each line.
+ ///
+ /// @param[in] type
+ /// The type of objects to use when dumping data from this
+ /// object. See DataExtractor::Type.
+ ///
+ /// @param[in] type_format
+ /// The optional format to use for the \a type objects. If this
+ /// is NULL, the default format for the \a type will be used.
+ ///
+ /// @return
+ /// The offset at which dumping ended.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ PutToLog (Log *log,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ uint64_t base_addr,
+ uint32_t num_per_line,
+ Type type,
+ const char *type_format = NULL) const;
+
+ //------------------------------------------------------------------
+ /// Dumps \a item_count objects into the stream \a s.
+ ///
+ /// Dumps \a item_count objects using \a item_format, each of which
+ /// are \a item_byte_size bytes long starting at offset \a offset
+ /// bytes into the contained data, into the stream \a s. \a
+ /// num_per_line objects will be dumped on each line before a new
+ /// line will be output. If \a base_addr is a valid address, then
+ /// each new line of output will be prededed by the address value
+ /// plus appropriate offset, and a colon and space. Bitfield values
+ /// can be dumped by calling this function multiple times with the
+ /// same start offset, format and size, yet differing \a
+ /// item_bit_size and \a item_bit_offset values.
+ ///
+ /// @param[in] s
+ /// The stream to dump the output to. This value can not be NULL.
+ ///
+ /// @param[in] offset
+ /// The offset into the data at which to start dumping.
+ ///
+ /// @param[in] item_format
+ /// The format to use when dumping each item.
+ ///
+ /// @param[in] item_byte_size
+ /// The byte size of each item.
+ ///
+ /// @param[in] item_count
+ /// The number of items to dump.
+ ///
+ /// @param[in] num_per_line
+ /// The number of items to display on each line.
+ ///
+ /// @param[in] base_addr
+ /// The base address that gets added to the offset displayed on
+ /// each line if the value is valid. Is \a base_addr is
+ /// LLDB_INVALID_ADDRESS then no address values will be prepended
+ /// to any lines.
+ ///
+ /// @param[in] item_bit_size
+ /// If the value to display is a bitfield, this value should
+ /// be the number of bits that the bitfield item has within the
+ /// item's byte size value. This function will need to be called
+ /// multiple times with identical \a offset and \a item_byte_size
+ /// values in order to display multiple bitfield values that
+ /// exist within the same integer value. If the items being
+ /// displayed are not bitfields, this value should be zero.
+ ///
+ /// @param[in] item_bit_offset
+ /// If the value to display is a bitfield, this value should
+ /// be the offset in bits, or shift right amount, that the
+ /// bitfield item occupies within the item's byte size value.
+ /// This function will need to be called multiple times with
+ /// identical \a offset and \a item_byte_size values in order
+ /// to display multiple bitfield values that exist within the
+ /// same integer value. If the items being displayed are not
+ /// bitfields, this value should be zero.
+ ///
+ /// @return
+ /// The offset at which dumping ended.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ Dump (Stream *s,
+ lldb::offset_t offset,
+ lldb::Format item_format,
+ size_t item_byte_size,
+ size_t item_count,
+ size_t num_per_line,
+ uint64_t base_addr,
+ uint32_t item_bit_size,
+ uint32_t item_bit_offset,
+ ExecutionContextScope *exe_scope = NULL) const;
+
+ //------------------------------------------------------------------
+ /// Dump a UUID value at \a offset.
+ ///
+ /// Dump a UUID starting at \a offset bytes into this object's data.
+ /// If the stream \a s is NULL, the output will be sent to Log().
+ ///
+ /// @param[in] s
+ /// The stream to dump the output to. If NULL the output will
+ /// be dumped to Log().
+ ///
+ /// @param[in] offset
+ /// The offset into the data at which to extract and dump a
+ /// UUID value.
+ //------------------------------------------------------------------
+ void
+ DumpUUID (Stream *s, lldb::offset_t offset) const;
+
+ //------------------------------------------------------------------
+ /// Extract an arbitrary number of bytes in the specified byte
+ /// order.
+ ///
+ /// Attemps to extract \a length bytes starting at \a offset bytes
+ /// into this data in the requested byte order (\a dst_byte_order)
+ /// and place the results in \a dst. \a dst must be at least \a
+ /// length bytes long.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes into the contained data at which to
+ /// start extracting.
+ ///
+ /// @param[in] length
+ /// The number of bytes to extract.
+ ///
+ /// @param[in] dst_byte_order
+ /// A byte order of the data that we want when the value in
+ /// copied to \a dst.
+ ///
+ /// @param[out] dst
+ /// The buffer that will receive the extracted value if there
+ /// are enough bytes available in the current data.
+ ///
+ /// @return
+ /// The number of bytes that were extracted which will be \a
+ /// length when the value is successfully extracted, or zero
+ /// if there aren't enough bytes at the specified offset.
+ //------------------------------------------------------------------
+ size_t
+ ExtractBytes (lldb::offset_t offset, lldb::offset_t length, lldb::ByteOrder dst_byte_order, void *dst) const;
+
+ //------------------------------------------------------------------
+ /// Extract an address from \a *offset_ptr.
+ ///
+ /// Extract a single address from the data and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted address
+ /// comes from the \a m_addr_size member variable and should be
+ /// set correctly prior to extracting any address values.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted address value.
+ //------------------------------------------------------------------
+ uint64_t
+ GetAddress (lldb::offset_t *offset_ptr) const;
+
+ uint64_t
+ GetAddress_unchecked (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Get the current address size.
+ ///
+ /// Return the size in bytes of any address values this object will
+ /// extract.
+ ///
+ /// @return
+ /// The size in bytes of address values that will be extracted.
+ //------------------------------------------------------------------
+ uint32_t
+ GetAddressByteSize () const
+ {
+ return m_addr_size;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the number of bytes contained in this object.
+ ///
+ /// @return
+ /// The total number of bytes of data this object refers to.
+ //------------------------------------------------------------------
+ uint64_t
+ GetByteSize () const
+ {
+ return m_end - m_start;
+ }
+
+ //------------------------------------------------------------------
+ /// Extract a C string from \a *offset_ptr.
+ ///
+ /// Returns a pointer to a C String from the data at the offset
+ /// pointed to by \a offset_ptr. A variable length NULL terminated C
+ /// string will be extracted and the \a offset_ptr will be
+ /// updated with the offset of the byte that follows the NULL
+ /// terminator byte.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// A pointer to the C string value in the data. If the offset
+ /// pointed to by \a offset_ptr is out of bounds, or if the
+ /// offset plus the length of the C string is out of bounds,
+ /// NULL will be returned.
+ //------------------------------------------------------------------
+ const char *
+ GetCStr (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract a C string from \a *offset_ptr with field size \a len.
+ ///
+ /// Returns a pointer to a C String from the data at the offset
+ /// pointed to by \a offset_ptr, with a field length of \a len.
+ /// A NULL terminated C string will be extracted and the \a offset_ptr
+ /// will be updated with the offset of the byte that follows the fixed
+ /// length field.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// A pointer to the C string value in the data. If the offset
+ /// pointed to by \a offset_ptr is out of bounds, or if the
+ /// offset plus the length of the field is out of bounds, or if
+ /// the field does not contain a NULL terminator byte, NULL will
+ /// be returned.
+ const char *
+ GetCStr (lldb::offset_t *offset_ptr, lldb::offset_t len) const;
+
+ //------------------------------------------------------------------
+ /// Extract \a length bytes from \a *offset_ptr.
+ ///
+ /// Returns a pointer to a bytes in this object's data at the offset
+ /// pointed to by \a offset_ptr. If \a length is zero or too large,
+ /// then the offset pointed to by \a offset_ptr will not be updated
+ /// and NULL will be returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] length
+ /// The optional length of a string to extract. If the value is
+ /// zero, a NULL terminated C string will be extracted.
+ ///
+ /// @return
+ /// A pointer to the bytes in this object's data if the offset
+ /// and length are valid, or NULL otherwise.
+ //------------------------------------------------------------------
+ const void*
+ GetData (lldb::offset_t *offset_ptr, lldb::offset_t length) const
+ {
+ const uint8_t *ptr = PeekData (*offset_ptr, length);
+ if (ptr)
+ *offset_ptr += length;
+ return ptr;
+ }
+
+ //------------------------------------------------------------------
+ /// Copy \a dst_len bytes from \a *offset_ptr and ensure the copied
+ /// data is treated as a value that can be swapped to match the
+ /// specified byte order.
+ ///
+ /// For values that are larger than the supported integer sizes,
+ /// this function can be used to extract data in a specified byte
+ /// order. It can also be used to copy a smaller integer value from
+ /// to a larger value. The extra bytes left over will be padded
+ /// correctly according to the byte order of this object and the
+ /// \a dst_byte_order. This can be very handy when say copying a
+ /// partial data value into a register.
+ ///
+ /// @param[in] src_offset
+ /// The offset into this data from which to start copying an
+ /// endian entity
+ ///
+ /// @param[in] src_len
+ /// The length of the endian data to copy from this object
+ /// into the \a dst object
+ ///
+ /// @param[out] dst
+ /// The buffer where to place the endian data. The data might
+ /// need to be byte swapped (and appropriately padded with
+ /// zeroes if \a src_len != \a dst_len) if \a dst_byte_order
+ /// does not match the byte order in this object.
+ ///
+ /// @param[in] dst_len
+ /// The length number of bytes that the endian value will
+ /// occupy is \a dst.
+ ///
+ /// @param[in] byte_order
+ /// The byte order that the endian value should be in the \a dst
+ /// buffer.
+ ///
+ /// @return
+ /// Returns the number of bytes that were copied, or zero if
+ /// anything goes wrong.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ CopyByteOrderedData (lldb::offset_t src_offset,
+ lldb::offset_t src_len,
+ void *dst,
+ lldb::offset_t dst_len,
+ lldb::ByteOrder dst_byte_order) const;
+
+ //------------------------------------------------------------------
+ /// Get the data end pointer.
+ ///
+ /// @return
+ /// Returns a pointer to the next byte contained in this
+ /// object's data, or NULL of there is no data in this object.
+ //------------------------------------------------------------------
+ const uint8_t *
+ GetDataEnd () const
+ {
+ return m_end;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the shared data offset.
+ ///
+ /// Get the offset of the first byte of data in the shared data (if
+ /// any).
+ ///
+ /// @return
+ /// If this object contains shared data, this function returns
+ /// the offset in bytes into that shared data, zero otherwise.
+ //------------------------------------------------------------------
+ size_t
+ GetSharedDataOffset () const;
+
+ //------------------------------------------------------------------
+ /// Get a the data start pointer.
+ ///
+ /// @return
+ /// Returns a pointer to the first byte contained in this
+ /// object's data, or NULL of there is no data in this object.
+ //------------------------------------------------------------------
+ const uint8_t *
+ GetDataStart () const
+ {
+ return m_start;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Extract a float from \a *offset_ptr.
+ ///
+ /// Extract a single float value.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The floating value that was extracted, or zero on failure.
+ //------------------------------------------------------------------
+ float
+ GetFloat (lldb::offset_t *offset_ptr) const;
+
+ double
+ GetDouble (lldb::offset_t *offset_ptr) const;
+
+ long double
+ GetLongDouble (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract a GNU encoded pointer value from \a *offset_ptr.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] eh_ptr_enc
+ /// The GNU pointer encoding type.
+ ///
+ /// @param[in] pc_rel_addr
+ /// The PC relative address to use when the encoding is
+ /// \c DW_GNU_EH_PE_pcrel.
+ ///
+ /// @param[in] text_addr
+ /// The text (code) relative address to use when the encoding is
+ /// \c DW_GNU_EH_PE_textrel.
+ ///
+ /// @param[in] data_addr
+ /// The data relative address to use when the encoding is
+ /// \c DW_GNU_EH_PE_datarel.
+ ///
+ /// @return
+ /// The extracted GNU encoded pointer value.
+ //------------------------------------------------------------------
+ uint64_t
+ GetGNUEHPointer (lldb::offset_t *offset_ptr,
+ uint32_t eh_ptr_enc,
+ lldb::addr_t pc_rel_addr,
+ lldb::addr_t text_addr,
+ lldb::addr_t data_addr);
+
+ //------------------------------------------------------------------
+ /// Extract an integer of size \a byte_size from \a *offset_ptr.
+ ///
+ /// Extract a single integer value and update the offset pointed to
+ /// by \a offset_ptr. The size of the extracted integer is specified
+ /// by the \a byte_size argument. \a byte_size should have a value
+ /// >= 1 and <= 4 since the return value is only 32 bits wide. Any
+ /// \a byte_size values less than 1 or greater than 4 will result in
+ /// nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to extract.
+ ///
+ /// @return
+ /// The integer value that was extracted, or zero on failure.
+ //------------------------------------------------------------------
+ uint32_t
+ GetMaxU32 (lldb::offset_t *offset_ptr, size_t byte_size) const;
+
+ //------------------------------------------------------------------
+ /// Extract an unsigned integer of size \a byte_size from \a
+ /// *offset_ptr.
+ ///
+ /// Extract a single unsigned integer value and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted integer
+ /// is specified by the \a byte_size argument. \a byte_size should
+ /// have a value greater than or equal to one and less than or equal
+ /// to eight since the return value is 64 bits wide. Any
+ /// \a byte_size values less than 1 or greater than 8 will result in
+ /// nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to extract.
+ ///
+ /// @return
+ /// The unsigned integer value that was extracted, or zero on
+ /// failure.
+ //------------------------------------------------------------------
+ uint64_t
+ GetMaxU64 (lldb::offset_t *offset_ptr, size_t byte_size) const;
+
+ uint64_t
+ GetMaxU64_unchecked (lldb::offset_t *offset_ptr, size_t byte_size) const;
+
+ //------------------------------------------------------------------
+ /// Extract an signed integer of size \a byte_size from \a *offset_ptr.
+ ///
+ /// Extract a single signed integer value (sign extending if required)
+ /// and update the offset pointed to by \a offset_ptr. The size of
+ /// the extracted integer is specified by the \a byte_size argument.
+ /// \a byte_size should have a value greater than or equal to one
+ /// and less than or equal to eight since the return value is 64
+ /// bits wide. Any \a byte_size values less than 1 or greater than
+ /// 8 will result in nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to extract.
+ ///
+ /// @return
+ /// The sign extended signed integer value that was extracted,
+ /// or zero on failure.
+ //------------------------------------------------------------------
+ int64_t
+ GetMaxS64 (lldb::offset_t *offset_ptr, size_t size) const;
+
+ //------------------------------------------------------------------
+ /// Extract an unsigned integer of size \a byte_size from \a
+ /// *offset_ptr, then extract the bitfield from this value if
+ /// \a bitfield_bit_size is non-zero.
+ ///
+ /// Extract a single unsigned integer value and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted integer
+ /// is specified by the \a byte_size argument. \a byte_size should
+ /// have a value greater than or equal to one and less than or equal
+ /// to 8 since the return value is 64 bits wide. Any
+ /// \a byte_size values less than 1 or greater than 8 will result in
+ /// nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to extract.
+ ///
+ /// @param[in] bitfield_bit_size
+ /// The size in bits of the bitfield value to extract, or zero
+ /// to just extract the entire integer value.
+ ///
+ /// @param[in] bitfield_bit_offset
+ /// The bit offset of the bitfield value in the extracted
+ /// integer (the number of bits to shift the integer to the
+ /// right).
+ ///
+ /// @return
+ /// The unsigned bitfield integer value that was extracted, or
+ /// zero on failure.
+ //------------------------------------------------------------------
+ uint64_t
+ GetMaxU64Bitfield (lldb::offset_t *offset_ptr,
+ size_t size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset) const;
+
+ //------------------------------------------------------------------
+ /// Extract an signed integer of size \a byte_size from \a
+ /// *offset_ptr, then extract and signe extend the bitfield from
+ /// this value if \a bitfield_bit_size is non-zero.
+ ///
+ /// Extract a single signed integer value (sign extending if required)
+ /// and update the offset pointed to by \a offset_ptr. The size of
+ /// the extracted integer is specified by the \a byte_size argument.
+ /// \a byte_size should have a value greater than or equal to one
+ /// and less than or equal to eight since the return value is 64
+ /// bits wide. Any \a byte_size values less than 1 or greater than
+ /// 8 will result in nothing being extracted, and zero being returned.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[in] byte_size
+ /// The size in bytes of the integer to extract.
+ ///
+ /// @param[in] bitfield_bit_size
+ /// The size in bits of the bitfield value to extract, or zero
+ /// to just extract the entire integer value.
+ ///
+ /// @param[in] bitfield_bit_offset
+ /// The bit offset of the bitfield value in the extracted
+ /// integer (the number of bits to shift the integer to the
+ /// right).
+ ///
+ /// @return
+ /// The signed bitfield integer value that was extracted, or
+ /// zero on failure.
+ //------------------------------------------------------------------
+ int64_t
+ GetMaxS64Bitfield (lldb::offset_t *offset_ptr,
+ size_t size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset) const;
+
+ //------------------------------------------------------------------
+ /// Extract an pointer from \a *offset_ptr.
+ ///
+ /// Extract a single pointer from the data and update the offset
+ /// pointed to by \a offset_ptr. The size of the extracted pointer
+ /// comes from the \a m_addr_size member variable and should be
+ /// set correctly prior to extracting any pointer values.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted pointer value as a 64 integer.
+ //------------------------------------------------------------------
+ uint64_t
+ GetPointer (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Get the current byte order value.
+ ///
+ /// @return
+ /// The current byte order value from this object's internal
+ /// state.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetByteOrder() const
+ {
+ return m_byte_order;
+ }
+
+ //------------------------------------------------------------------
+ /// Extract a uint8_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint8_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and advance the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted uint8_t value.
+ //------------------------------------------------------------------
+ uint8_t
+ GetU8 ( lldb::offset_t *offset_ptr) const;
+
+ uint8_t
+ GetU8_unchecked (lldb::offset_t *offset_ptr) const
+ {
+ uint8_t val = m_start[*offset_ptr];
+ *offset_ptr += 1;
+ return val;
+ }
+
+ uint16_t
+ GetU16_unchecked (lldb::offset_t *offset_ptr) const;
+
+ uint32_t
+ GetU32_unchecked (lldb::offset_t *offset_ptr) const;
+
+ uint64_t
+ GetU64_unchecked (lldb::offset_t *offset_ptr) const;
+ //------------------------------------------------------------------
+ /// Extract \a count uint8_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint8_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint8_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint8_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ //------------------------------------------------------------------
+ void *
+ GetU8 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
+
+ //------------------------------------------------------------------
+ /// Extract a uint16_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint16_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted uint16_t value.
+ //------------------------------------------------------------------
+ uint16_t
+ GetU16 (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract \a count uint16_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint16_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint16_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint16_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ //------------------------------------------------------------------
+ void *
+ GetU16 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
+
+ //------------------------------------------------------------------
+ /// Extract a uint32_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint32_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted uint32_t value.
+ //------------------------------------------------------------------
+ uint32_t
+ GetU32 (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract \a count uint32_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint32_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint32_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint32_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ //------------------------------------------------------------------
+ void *
+ GetU32 (lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
+
+ //------------------------------------------------------------------
+ /// Extract a uint64_t value from \a *offset_ptr.
+ ///
+ /// Extract a single uint64_t from the binary data at the offset
+ /// pointed to by \a offset_ptr, and update the offset on success.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted uint64_t value.
+ //------------------------------------------------------------------
+ uint64_t
+ GetU64 (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract \a count uint64_t values from \a *offset_ptr.
+ ///
+ /// Extract \a count uint64_t values from the binary data at the
+ /// offset pointed to by \a offset_ptr, and advance the offset on
+ /// success. The extracted values are copied into \a dst.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @param[out] dst
+ /// A buffer to copy \a count uint64_t values into. \a dst must
+ /// be large enough to hold all requested data.
+ ///
+ /// @param[in] count
+ /// The number of uint64_t values to extract.
+ ///
+ /// @return
+ /// \a dst if all values were properly extracted and copied,
+ /// NULL otherise.
+ //------------------------------------------------------------------
+ void *
+ GetU64 ( lldb::offset_t *offset_ptr, void *dst, uint32_t count) const;
+
+ //------------------------------------------------------------------
+ /// Extract a signed LEB128 value from \a *offset_ptr.
+ ///
+ /// Extracts an signed LEB128 number from this object's data
+ /// starting at the offset pointed to by \a offset_ptr. The offset
+ /// pointed to by \a offset_ptr will be updated with the offset of
+ /// the byte following the last extracted byte.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted signed integer value.
+ //------------------------------------------------------------------
+ int64_t
+ GetSLEB128 (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Extract a unsigned LEB128 value from \a *offset_ptr.
+ ///
+ /// Extracts an unsigned LEB128 number from this object's data
+ /// starting at the offset pointed to by \a offset_ptr. The offset
+ /// pointed to by \a offset_ptr will be updated with the offset of
+ /// the byte following the last extracted byte.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ /// The extracted unsigned integer value.
+ //------------------------------------------------------------------
+ uint64_t
+ GetULEB128 (lldb::offset_t *offset_ptr) const;
+
+ lldb::DataBufferSP &
+ GetSharedDataBuffer ()
+ {
+ return m_data_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Peek at a C string at \a offset.
+ ///
+ /// Peeks at a string in the contained data. No verification is done
+ /// to make sure the entire string lies within the bounds of this
+ /// object's data, only \a offset is verified to be a valid offset.
+ ///
+ /// @param[in] offset
+ /// An offset into the data.
+ ///
+ /// @return
+ /// A non-NULL C string pointer if \a offset is a valid offset,
+ /// NULL otherwise.
+ //------------------------------------------------------------------
+ const char *
+ PeekCStr (lldb::offset_t offset) const;
+
+ //------------------------------------------------------------------
+ /// Peek at a bytes at \a offset.
+ ///
+ /// Returns a pointer to \a length bytes at \a offset as long as
+ /// there are \a length bytes available starting at \a offset.
+ ///
+ /// @return
+ /// A non-NULL data pointer if \a offset is a valid offset and
+ /// there are \a length bytes available at that offset, NULL
+ /// otherwise.
+ //------------------------------------------------------------------
+ const uint8_t*
+ PeekData (lldb::offset_t offset, lldb::offset_t length) const
+ {
+ if (length > 0 && ValidOffsetForDataOfSize(offset, length))
+ return m_start + offset;
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Set the address byte size.
+ ///
+ /// Set the size in bytes that will be used when extracting any
+ /// address and pointer values from data contained in this object.
+ ///
+ /// @param[in] addr_size
+ /// The size in bytes to use when extracting addresses.
+ //------------------------------------------------------------------
+ void
+ SetAddressByteSize (uint32_t addr_size)
+ {
+ m_addr_size = addr_size;
+ }
+
+ //------------------------------------------------------------------
+ /// Set data with a buffer that is caller owned.
+ ///
+ /// Use data that is owned by the caller when extracting values.
+ /// The data must stay around as long as this object, or any object
+ /// that copies a subset of this object's data, is valid. If \a
+ /// bytes is NULL, or \a length is zero, this object will contain
+ /// no data.
+ ///
+ /// @param[in] bytes
+ /// A pointer to caller owned data.
+ ///
+ /// @param[in] length
+ /// The length in bytes of \a bytes.
+ ///
+ /// @param[in] byte_order
+ /// A byte order of the data that we are extracting from.
+ ///
+ /// @return
+ /// The number of bytes that this object now contains.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ SetData (const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order);
+
+ //------------------------------------------------------------------
+ /// Adopt a subset of \a data.
+ ///
+ /// Set this object's data to be a subset of the data bytes in \a
+ /// data. If \a data contains shared data, then a reference to the
+ /// shared data will be added to ensure the shared data stays around
+ /// as long as any objects have references to the shared data. The
+ /// byte order and the address size settings are copied from \a
+ /// data. If \a offset is not a valid offset in \a data, then no
+ /// reference to the shared data will be added. If there are not
+ /// \a length bytes available in \a data starting at \a offset,
+ /// the length will be truncated to contains as many bytes as
+ /// possible.
+ ///
+ /// @param[in] data
+ /// Another DataExtractor object that contains data.
+ ///
+ /// @param[in] offset
+ /// The offset into \a data at which the subset starts.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the subset of \a data.
+ ///
+ /// @return
+ /// The number of bytes that this object now contains.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ SetData (const DataExtractor& data, lldb::offset_t offset, lldb::offset_t length);
+
+ //------------------------------------------------------------------
+ /// Adopt a subset of shared data in \a data_sp.
+ ///
+ /// Copies the data shared pointer which adds a reference to the
+ /// contained in \a data_sp. The shared data reference is reference
+ /// counted to ensure the data lives as long as anyone still has a
+ /// valid shared pointer to the data in \a data_sp. The byte order
+ /// and address byte size settings remain the same. If
+ /// \a offset is not a valid offset in \a data_sp, then no reference
+ /// to the shared data will be added. If there are not \a length
+ /// bytes available in \a data starting at \a offset, the length
+ /// will be truncated to contains as many bytes as possible.
+ ///
+ /// @param[in] data_sp
+ /// A shared pointer to data.
+ ///
+ /// @param[in] offset
+ /// The offset into \a data_sp at which the subset starts.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the subset of \a data_sp.
+ ///
+ /// @return
+ /// The number of bytes that this object now contains.
+ //------------------------------------------------------------------
+ lldb::offset_t
+ SetData (const lldb::DataBufferSP& data_sp, lldb::offset_t offset = 0, lldb::offset_t length = LLDB_INVALID_OFFSET);
+
+ //------------------------------------------------------------------
+ /// Set the byte_order value.
+ ///
+ /// Sets the byte order of the data to extract. Extracted values
+ /// will be swapped if necessary when decoding.
+ ///
+ /// @param[in] byte_order
+ /// The byte order value to use when extracting data.
+ //------------------------------------------------------------------
+ void
+ SetByteOrder (lldb::ByteOrder byte_order)
+ {
+ m_byte_order = byte_order;
+ }
+
+ //------------------------------------------------------------------
+ /// Skip an LEB128 number at \a *offset_ptr.
+ ///
+ /// Skips a LEB128 number (signed or unsigned) from this object's
+ /// data starting at the offset pointed to by \a offset_ptr. The
+ /// offset pointed to by \a offset_ptr will be updated with the
+ /// offset of the byte following the last extracted byte.
+ ///
+ /// @param[in,out] offset_ptr
+ /// A pointer to an offset within the data that will be advanced
+ /// by the appropriate number of bytes if the value is extracted
+ /// correctly. If the offset is out of bounds or there are not
+ /// enough bytes to extract this value, the offset will be left
+ /// unmodified.
+ ///
+ /// @return
+ // The number of bytes consumed during the extraction.
+ //------------------------------------------------------------------
+ uint32_t
+ Skip_LEB128 (lldb::offset_t *offset_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Test the validity of \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset into the data in this
+ /// object, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ValidOffset (lldb::offset_t offset) const
+ {
+ return offset < GetByteSize();
+ }
+
+ //------------------------------------------------------------------
+ /// Test the availability of \a length bytes of data from \a offset.
+ ///
+ /// @return
+ /// \b true if \a offset is a valid offset and there are \a
+ /// length bytes available at that offset, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ValidOffsetForDataOfSize (lldb::offset_t offset, lldb::offset_t length) const
+ {
+ return length <= BytesLeft (offset);
+ }
+
+ size_t
+ Copy (DataExtractor& dest_data) const;
+
+ bool
+ Append (DataExtractor& rhs);
+
+ bool
+ Append (void* bytes, lldb::offset_t length);
+
+ lldb::offset_t
+ BytesLeft (lldb::offset_t offset) const
+ {
+ const lldb::offset_t size = GetByteSize();
+ if (size > offset)
+ return size - offset;
+ return 0;
+ }
+
+protected:
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ const uint8_t * m_start; ///< A pointer to the first byte of data.
+ const uint8_t * m_end; ///< A pointer to the byte that is past the end of the data.
+ lldb::ByteOrder m_byte_order; ///< The byte order of the data we are extracting from.
+ uint32_t m_addr_size; ///< The address size to use when extracting pointers or addresses
+ mutable lldb::DataBufferSP m_data_sp; ///< The shared pointer to data that can be shared among multilple instances
+};
+
+} // namespace lldb_private
+
+#endif // #if defined (__cplusplus)
+#endif // #ifndef liblldb_DataExtractor_h_
diff --git a/include/lldb/Core/Debugger.h b/include/lldb/Core/Debugger.h
new file mode 100644
index 000000000000..bed93fe02528
--- /dev/null
+++ b/include/lldb/Core/Debugger.h
@@ -0,0 +1,397 @@
+//===-- Debugger.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_Debugger_h_
+#define liblldb_Debugger_h_
+#if defined(__cplusplus)
+
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <stack>
+
+#include "lldb/lldb-public.h"
+
+#include "lldb/API/SBDefines.h"
+
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/InputReaderStack.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/Terminal.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/TargetList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Debugger Debugger.h "lldb/Core/Debugger.h"
+/// @brief A class to manage flag bits.
+///
+/// Provides a global root objects for the debugger core.
+//----------------------------------------------------------------------
+
+
+class Debugger :
+ public std::enable_shared_from_this<Debugger>,
+ public UserID,
+ public Properties,
+ public BroadcasterManager
+{
+friend class SourceManager; // For GetSourceFileCache.
+
+public:
+
+ static lldb::DebuggerSP
+ CreateInstance (lldb::LogOutputCallback log_callback = NULL, void *baton = NULL);
+
+ static lldb::TargetSP
+ FindTargetWithProcessID (lldb::pid_t pid);
+
+ static lldb::TargetSP
+ FindTargetWithProcess (Process *process);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static void
+ SettingsInitialize ();
+
+ static void
+ SettingsTerminate ();
+
+ static void
+ Destroy (lldb::DebuggerSP &debugger_sp);
+
+ virtual
+ ~Debugger ();
+
+ void Clear();
+
+ bool
+ GetAsyncExecution ();
+
+ void
+ SetAsyncExecution (bool async);
+
+ File &
+ GetInputFile ()
+ {
+ return m_input_file.GetFile();
+ }
+
+ File &
+ GetOutputFile ()
+ {
+ return m_output_file.GetFile();
+ }
+
+ File &
+ GetErrorFile ()
+ {
+ return m_error_file.GetFile();
+ }
+
+ void
+ SetInputFileHandle (FILE *fh, bool tranfer_ownership);
+
+ void
+ SetOutputFileHandle (FILE *fh, bool tranfer_ownership);
+
+ void
+ SetErrorFileHandle (FILE *fh, bool tranfer_ownership);
+
+ void
+ SaveInputTerminalState();
+
+ void
+ RestoreInputTerminalState();
+
+ Stream&
+ GetOutputStream ()
+ {
+ return m_output_file;
+ }
+
+ Stream&
+ GetErrorStream ()
+ {
+ return m_error_file;
+ }
+
+ lldb::StreamSP
+ GetAsyncOutputStream ();
+
+ lldb::StreamSP
+ GetAsyncErrorStream ();
+
+ CommandInterpreter &
+ GetCommandInterpreter ()
+ {
+ assert (m_command_interpreter_ap.get());
+ return *m_command_interpreter_ap;
+ }
+
+ Listener &
+ GetListener ()
+ {
+ return m_listener;
+ }
+
+ // This returns the Debugger's scratch source manager. It won't be able to look up files in debug
+ // information, but it can look up files by absolute path and display them to you.
+ // To get the target's source manager, call GetSourceManager on the target instead.
+ SourceManager &
+ GetSourceManager ();
+
+public:
+
+ lldb::TargetSP
+ GetSelectedTarget ()
+ {
+ return m_target_list.GetSelectedTarget ();
+ }
+
+ ExecutionContext
+ GetSelectedExecutionContext();
+ //------------------------------------------------------------------
+ /// Get accessor for the target list.
+ ///
+ /// The target list is part of the global debugger object. This
+ /// the single debugger shared instance to control where targets
+ /// get created and to allow for tracking and searching for targets
+ /// based on certain criteria.
+ ///
+ /// @return
+ /// A global shared target list.
+ //------------------------------------------------------------------
+ TargetList &
+ GetTargetList ()
+ {
+ return m_target_list;
+ }
+
+ PlatformList &
+ GetPlatformList ()
+ {
+ return m_platform_list;
+ }
+
+ void
+ DispatchInputInterrupt ();
+
+ void
+ DispatchInputEndOfFile ();
+
+ void
+ DispatchInput (const char *bytes, size_t bytes_len);
+
+ void
+ WriteToDefaultReader (const char *bytes, size_t bytes_len);
+
+ void
+ PushInputReader (const lldb::InputReaderSP& reader_sp);
+
+ bool
+ PopInputReader (const lldb::InputReaderSP& reader_sp);
+
+ void
+ NotifyTopInputReader (lldb::InputReaderAction notification);
+
+ bool
+ InputReaderIsTopReader (const lldb::InputReaderSP& reader_sp);
+
+ static lldb::DebuggerSP
+ FindDebuggerWithID (lldb::user_id_t id);
+
+ static lldb::DebuggerSP
+ FindDebuggerWithInstanceName (const ConstString &instance_name);
+
+ static size_t
+ GetNumDebuggers();
+
+ static lldb::DebuggerSP
+ GetDebuggerAtIndex (size_t index);
+
+ static bool
+ FormatPrompt (const char *format,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s,
+ ValueObject* valobj = NULL);
+
+
+ void
+ CleanUpInputReaders ();
+
+ static int
+ TestDebuggerRefCount ();
+
+ bool
+ GetCloseInputOnEOF () const;
+
+ void
+ SetCloseInputOnEOF (bool b);
+
+ bool
+ EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream);
+
+ void
+ SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton);
+
+
+ //----------------------------------------------------------------------
+ // Properties Functions
+ //----------------------------------------------------------------------
+ enum StopDisassemblyType
+ {
+ eStopDisassemblyTypeNever = 0,
+ eStopDisassemblyTypeNoSource,
+ eStopDisassemblyTypeAlways
+ };
+
+ virtual Error
+ SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *property_path,
+ const char *value);
+
+ bool
+ GetAutoConfirm () const;
+
+ const char *
+ GetFrameFormat() const;
+
+ const char *
+ GetThreadFormat() const;
+
+ lldb::ScriptLanguage
+ GetScriptLanguage() const;
+
+ bool
+ SetScriptLanguage (lldb::ScriptLanguage script_lang);
+
+ uint32_t
+ GetTerminalWidth () const;
+
+ bool
+ SetTerminalWidth (uint32_t term_width);
+
+ const char *
+ GetPrompt() const;
+
+ void
+ SetPrompt(const char *p);
+
+ bool
+ GetUseExternalEditor () const;
+
+ bool
+ SetUseExternalEditor (bool use_external_editor_p);
+
+ bool
+ GetUseColor () const;
+
+ bool
+ SetUseColor (bool use_color);
+
+ uint32_t
+ GetStopSourceLineCount (bool before) const;
+
+ StopDisassemblyType
+ GetStopDisassemblyDisplay () const;
+
+ uint32_t
+ GetDisassemblyLineCount () const;
+
+ bool
+ GetNotifyVoid () const;
+
+
+ const ConstString &
+ GetInstanceName()
+ {
+ return m_instance_name;
+ }
+
+ typedef bool (*LLDBCommandPluginInit) (lldb::SBDebugger& debugger);
+
+ bool
+ LoadPlugin (const FileSpec& spec, Error& error);
+
+protected:
+
+ static void
+ DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len);
+
+ lldb::InputReaderSP
+ GetCurrentInputReader ();
+
+ void
+ ActivateInputReader (const lldb::InputReaderSP &reader_sp);
+
+ bool
+ CheckIfTopInputReaderIsDone ();
+
+ SourceManager::SourceFileCache &
+ GetSourceFileCache ()
+ {
+ return m_source_file_cache;
+ }
+ Communication m_input_comm;
+ StreamFile m_input_file;
+ StreamFile m_output_file;
+ StreamFile m_error_file;
+ TerminalState m_terminal_state;
+ TargetList m_target_list;
+ PlatformList m_platform_list;
+ Listener m_listener;
+ std::unique_ptr<SourceManager> m_source_manager_ap; // This is a scratch source manager that we return if we have no targets.
+ SourceManager::SourceFileCache m_source_file_cache; // All the source managers for targets created in this debugger used this shared
+ // source file cache.
+ std::unique_ptr<CommandInterpreter> m_command_interpreter_ap;
+
+ InputReaderStack m_input_reader_stack;
+ std::string m_input_reader_data;
+ typedef std::map<std::string, lldb::StreamWP> LogStreamMap;
+ LogStreamMap m_log_streams;
+ lldb::StreamSP m_log_callback_stream_sp;
+ ConstString m_instance_name;
+ typedef std::vector<lldb::DynamicLibrarySP> LoadedPluginsList;
+ LoadedPluginsList m_loaded_plugins;
+
+ void
+ InstanceInitialize ();
+
+private:
+
+ // Use Debugger::CreateInstance() to get a shared pointer to a new
+ // debugger object
+ Debugger (lldb::LogOutputCallback m_log_callback, void *baton);
+
+ DISALLOW_COPY_AND_ASSIGN (Debugger);
+
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Debugger_h_
diff --git a/include/lldb/Core/Disassembler.h b/include/lldb/Core/Disassembler.h
new file mode 100644
index 000000000000..d6e90071dc5b
--- /dev/null
+++ b/include/lldb/Core/Disassembler.h
@@ -0,0 +1,422 @@
+//===-- Disassembler.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_Disassembler_h_
+#define liblldb_Disassembler_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Opcode.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class Instruction
+{
+public:
+ Instruction (const Address &address,
+ lldb::AddressClass addr_class = lldb::eAddressClassInvalid);
+
+ virtual
+ ~Instruction();
+
+ const Address &
+ GetAddress () const
+ {
+ return m_address;
+ }
+
+ const char *
+ GetMnemonic (const ExecutionContext* exe_ctx)
+ {
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+ return m_opcode_name.c_str();
+ }
+ const char *
+ GetOperands (const ExecutionContext* exe_ctx)
+ {
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+ return m_mnemonics.c_str();
+ }
+
+ const char *
+ GetComment (const ExecutionContext* exe_ctx)
+ {
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+ return m_comment.c_str();
+ }
+
+ virtual void
+ CalculateMnemonicOperandsAndComment (const ExecutionContext* exe_ctx) = 0;
+
+ lldb::AddressClass
+ GetAddressClass ();
+
+ void
+ SetAddress (const Address &addr)
+ {
+ // Invalidate the address class to lazily discover
+ // it if we need to.
+ m_address_class = lldb::eAddressClassInvalid;
+ m_address = addr;
+ }
+
+ virtual void
+ Dump (Stream *s,
+ uint32_t max_opcode_byte_size,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx);
+
+ virtual bool
+ DoesBranch () = 0;
+
+ virtual size_t
+ Decode (const Disassembler &disassembler,
+ const DataExtractor& data,
+ lldb::offset_t data_offset) = 0;
+
+ virtual void
+ SetDescription (const char *) {} // May be overridden in sub-classes that have descriptions.
+
+ lldb::OptionValueSP
+ ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type data_type);
+
+ lldb::OptionValueSP
+ ReadDictionary (FILE *in_file, Stream *out_stream);
+
+ bool
+ DumpEmulation (const ArchSpec &arch);
+
+ virtual bool
+ TestEmulation (Stream *stream, const char *test_file_name);
+
+ bool
+ Emulate (const ArchSpec &arch,
+ uint32_t evaluate_options,
+ void *baton,
+ EmulateInstruction::ReadMemoryCallback read_mem_callback,
+ EmulateInstruction::WriteMemoryCallback write_mem_calback,
+ EmulateInstruction::ReadRegisterCallback read_reg_callback,
+ EmulateInstruction::WriteRegisterCallback write_reg_callback);
+
+ const Opcode &
+ GetOpcode () const
+ {
+ return m_opcode;
+ }
+
+ uint32_t
+ GetData (DataExtractor &data);
+
+protected:
+ Address m_address; // The section offset address of this instruction
+ // We include an address class in the Instruction class to
+ // allow the instruction specify the eAddressClassCodeAlternateISA
+ // (currently used for thumb), and also to specify data (eAddressClassData).
+ // The usual value will be eAddressClassCode, but often when
+ // disassembling memory, you might run into data. This can
+ // help us to disassemble appropriately.
+private:
+ lldb::AddressClass m_address_class; // Use GetAddressClass () accessor function!
+protected:
+ Opcode m_opcode; // The opcode for this instruction
+ std::string m_opcode_name;
+ std::string m_mnemonics;
+ std::string m_comment;
+ bool m_calculated_strings;
+
+ void
+ CalculateMnemonicOperandsAndCommentIfNeeded (const ExecutionContext* exe_ctx)
+ {
+ if (!m_calculated_strings)
+ {
+ m_calculated_strings = true;
+ CalculateMnemonicOperandsAndComment(exe_ctx);
+ }
+ }
+};
+
+
+class InstructionList
+{
+public:
+ InstructionList();
+ ~InstructionList();
+
+ size_t
+ GetSize() const;
+
+ uint32_t
+ GetMaxOpcocdeByteSize () const;
+
+ lldb::InstructionSP
+ GetInstructionAtIndex (size_t idx) const;
+
+ uint32_t
+ GetIndexOfNextBranchInstruction(uint32_t start) const;
+
+ uint32_t
+ GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target);
+
+ void
+ Clear();
+
+ void
+ Append (lldb::InstructionSP &inst_sp);
+
+ void
+ Dump (Stream *s,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx);
+
+private:
+ typedef std::vector<lldb::InstructionSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_instructions;
+};
+
+class PseudoInstruction :
+ public Instruction
+{
+public:
+
+ PseudoInstruction ();
+
+ virtual
+ ~PseudoInstruction ();
+
+ virtual bool
+ DoesBranch ();
+
+ virtual void
+ CalculateMnemonicOperandsAndComment (const ExecutionContext* exe_ctx)
+ {
+ // TODO: fill this in and put opcode name into Instruction::m_opcode_name,
+ // mnemonic into Instruction::m_mnemonics, and any comment into
+ // Instruction::m_comment
+ }
+
+ virtual size_t
+ Decode (const Disassembler &disassembler,
+ const DataExtractor &data,
+ lldb::offset_t data_offset);
+
+ void
+ SetOpcode (size_t opcode_size, void *opcode_data);
+
+ virtual void
+ SetDescription (const char *description);
+
+protected:
+ std::string m_description;
+
+ DISALLOW_COPY_AND_ASSIGN (PseudoInstruction);
+};
+
+class Disassembler :
+ public std::enable_shared_from_this<Disassembler>,
+ public PluginInterface
+{
+public:
+
+ enum
+ {
+ eOptionNone = 0u,
+ eOptionShowBytes = (1u << 0),
+ eOptionRawOuput = (1u << 1),
+ eOptionMarkPCSourceLine = (1u << 2), // Mark the source line that contains the current PC (mixed mode only)
+ eOptionMarkPCAddress = (1u << 3) // Mark the disassembly line the contains the PC
+ };
+
+ enum HexImmediateStyle
+ {
+ eHexStyleC,
+ eHexStyleAsm,
+ };
+
+ // FindPlugin should be lax about the flavor string (it is too annoying to have various internal uses of the
+ // disassembler fail because the global flavor string gets set wrong. Instead, if you get a flavor string you
+ // don't understand, use the default. Folks who care to check can use the FlavorValidForArchSpec method on the
+ // disassembler they got back.
+ static lldb::DisassemblerSP
+ FindPlugin (const ArchSpec &arch, const char *flavor, const char *plugin_name);
+
+ // This version will use the value in the Target settings if flavor is NULL;
+ static lldb::DisassemblerSP
+ FindPluginForTarget(const lldb::TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name);
+
+ static lldb::DisassemblerSP
+ DisassembleRange (const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &disasm_range);
+
+ static lldb::DisassemblerSP
+ DisassembleBytes (const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const Address &start,
+ const void *bytes,
+ size_t length,
+ uint32_t max_num_instructions,
+ bool data_from_file);
+
+ static bool
+ Disassemble (Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &range,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ static bool
+ Disassemble (Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const Address &start,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ static size_t
+ Disassemble (Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ SymbolContextList &sc_list,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ static bool
+ Disassemble (Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const ConstString &name,
+ Module *module,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ static bool
+ Disassemble (Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Disassembler(const ArchSpec &arch, const char *flavor);
+ virtual ~Disassembler();
+
+ typedef const char * (*SummaryCallback)(const Instruction& inst, ExecutionContext *exe_context, void *user_data);
+
+ static bool
+ PrintInstructions (Disassembler *disasm_ptr,
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm);
+
+ size_t
+ ParseInstructions (const ExecutionContext *exe_ctx,
+ const AddressRange &range,
+ Stream *error_strm_ptr,
+ bool prefer_file_cache);
+
+ size_t
+ ParseInstructions (const ExecutionContext *exe_ctx,
+ const Address &range,
+ uint32_t num_instructions,
+ bool prefer_file_cache);
+
+ virtual size_t
+ DecodeInstructions (const Address &base_addr,
+ const DataExtractor& data,
+ lldb::offset_t data_offset,
+ size_t num_instructions,
+ bool append,
+ bool data_from_file) = 0;
+
+ InstructionList &
+ GetInstructionList ();
+
+ const InstructionList &
+ GetInstructionList () const;
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ const char *
+ GetFlavor () const
+ {
+ return m_flavor.c_str();
+ }
+
+ virtual bool
+ FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor) = 0;
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Disassembler can see and modify these
+ //------------------------------------------------------------------
+ const ArchSpec m_arch;
+ InstructionList m_instruction_list;
+ lldb::addr_t m_base_addr;
+ std::string m_flavor;
+
+private:
+ //------------------------------------------------------------------
+ // For Disassembler only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Disassembler);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Disassembler_h_
diff --git a/include/lldb/Core/EmulateInstruction.h b/include/lldb/Core/EmulateInstruction.h
new file mode 100644
index 000000000000..08b97e424913
--- /dev/null
+++ b/include/lldb/Core/EmulateInstruction.h
@@ -0,0 +1,641 @@
+//===-- EmulateInstruction.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulateInstruction_h_
+#define lldb_EmulateInstruction_h_
+
+#include <string>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/Opcode.h"
+#include "lldb/Core/RegisterValue.h"
+
+//----------------------------------------------------------------------
+/// @class EmulateInstruction EmulateInstruction.h "lldb/Core/EmulateInstruction.h"
+/// @brief A class that allows emulation of CPU opcodes.
+///
+/// This class is a plug-in interface that is accessed through the
+/// standard static FindPlugin function call in the EmulateInstruction
+/// class. The FindPlugin takes a target triple and returns a new object
+/// if there is a plug-in that supports the architecture and OS. Four
+/// callbacks and a baton are provided. The four callbacks are read
+/// register, write register, read memory and write memory.
+///
+/// This class is currently designed for these main use cases:
+/// - Auto generation of Call Frame Information (CFI) from assembly code
+/// - Predicting single step breakpoint locations
+/// - Emulating instructions for breakpoint traps
+///
+/// Objects can be asked to read an instruction which will cause a call
+/// to the read register callback to get the PC, followed by a read
+/// memory call to read the opcode. If ReadInstruction () returns true,
+/// then a call to EmulateInstruction::EvaluateInstruction () can be
+/// made. At this point the EmulateInstruction subclass will use all of
+/// the callbacks to emulate an instruction.
+///
+/// Clients that provide the callbacks can either do the read/write
+/// registers/memory to actually emulate the instruction on a real or
+/// virtual CPU, or watch for the EmulateInstruction::Context which
+/// is context for the read/write register/memory which explains why
+/// the callback is being called. Examples of a context are:
+/// "pushing register 3 onto the stack at offset -12", or "adjusting
+/// stack pointer by -16". This extra context allows the generation of
+/// CFI information from assembly code without having to actually do
+/// the read/write register/memory.
+///
+/// Clients must be prepared that not all instructions for an
+/// Instruction Set Architecture (ISA) will be emulated.
+///
+/// Subclasses at the very least should implement the instructions that
+/// save and restore registers onto the stack and adjustment to the stack
+/// pointer. By just implementing a few instructions for an ISA that are
+/// the typical prologue opcodes, you can then generate CFI using a
+/// class that will soon be available.
+///
+/// Implementing all of the instructions that affect the PC can then
+/// allow single step prediction support.
+///
+/// Implementing all of the instructions allows for emulation of opcodes
+/// for breakpoint traps and will pave the way for "thread centric"
+/// debugging. The current debugging model is "process centric" where
+/// all threads must be stopped when any thread is stopped; when
+/// hitting software breakpoints we must disable the breakpoint by
+/// restoring the original breakpoint opcde, single stepping and
+/// restoring the breakpoint trap. If all threads were allowed to run
+/// then other threads could miss the breakpoint.
+///
+/// This class centralizes the code that usually is done in separate
+/// code paths in a debugger (single step prediction, finding save
+/// restore locations of registers for unwinding stack frame variables)
+/// and emulating the intruction is just a bonus.
+//----------------------------------------------------------------------
+
+namespace lldb_private {
+
+class EmulateInstruction :
+ public PluginInterface
+{
+public:
+
+ static EmulateInstruction*
+ FindPlugin (const ArchSpec &arch,
+ InstructionType supported_inst_type,
+ const char *plugin_name);
+
+ enum ContextType
+ {
+ eContextInvalid = 0,
+ // Read an instruciton opcode from memory
+ eContextReadOpcode,
+
+ // Usually used for writing a register value whose source value is an
+ // immediate
+ eContextImmediate,
+
+ // Exclusively used when saving a register to the stack as part of the
+ // prologue
+ eContextPushRegisterOnStack,
+
+ // Exclusively used when restoring a register off the stack as part of
+ // the epilogue
+ eContextPopRegisterOffStack,
+
+ // Add or subtract a value from the stack
+ eContextAdjustStackPointer,
+
+ // Adjust the frame pointer for the current frame
+ eContextSetFramePointer,
+
+ // Add or subtract a value from a base address register (other than SP)
+ eContextAdjustBaseRegister,
+
+ // Add or subtract a value from the PC or store a value to the PC.
+ eContextAdjustPC,
+
+ // Used in WriteRegister callbacks to indicate where the
+ eContextRegisterPlusOffset,
+
+ // Used in WriteMemory callback to indicate where the data came from
+ eContextRegisterStore,
+
+ eContextRegisterLoad,
+
+ // Used when performing a PC-relative branch where the
+ eContextRelativeBranchImmediate,
+
+ // Used when performing an absolute branch where the
+ eContextAbsoluteBranchRegister,
+
+ // Used when performing a supervisor call to an operating system to
+ // provide a service:
+ eContextSupervisorCall,
+
+ // Used when performing a MemU operation to read the PC-relative offset
+ // from an address.
+ eContextTableBranchReadMemory,
+
+ // Used when random bits are written into a register
+ eContextWriteRegisterRandomBits,
+
+ // Used when random bits are written to memory
+ eContextWriteMemoryRandomBits,
+
+ eContextArithmetic,
+
+ eContextAdvancePC,
+
+ eContextReturnFromException
+ };
+
+ enum InfoType {
+ eInfoTypeRegisterPlusOffset,
+ eInfoTypeRegisterPlusIndirectOffset,
+ eInfoTypeRegisterToRegisterPlusOffset,
+ eInfoTypeRegisterToRegisterPlusIndirectOffset,
+ eInfoTypeRegisterRegisterOperands,
+ eInfoTypeOffset,
+ eInfoTypeRegister,
+ eInfoTypeImmediate,
+ eInfoTypeImmediateSigned,
+ eInfoTypeAddress,
+ eInfoTypeISAAndImmediate,
+ eInfoTypeISAAndImmediateSigned,
+ eInfoTypeISA,
+ eInfoTypeNoArgs
+ } InfoType;
+
+ struct Context
+ {
+ ContextType type;
+ enum InfoType info_type;
+ union
+ {
+ struct RegisterPlusOffset
+ {
+ RegisterInfo reg; // base register
+ int64_t signed_offset; // signed offset added to base register
+ } RegisterPlusOffset;
+
+ struct RegisterPlusIndirectOffset
+ {
+ RegisterInfo base_reg; // base register number
+ RegisterInfo offset_reg; // offset register kind
+ } RegisterPlusIndirectOffset;
+
+ struct RegisterToRegisterPlusOffset
+ {
+ RegisterInfo data_reg; // source/target register for data
+ RegisterInfo base_reg; // base register for address calculation
+ int64_t offset; // offset for address calculation
+ } RegisterToRegisterPlusOffset;
+
+ struct RegisterToRegisterPlusIndirectOffset
+ {
+ RegisterInfo base_reg; // base register for address calculation
+ RegisterInfo offset_reg; // offset register for address calculation
+ RegisterInfo data_reg; // source/target register for data
+ } RegisterToRegisterPlusIndirectOffset;
+
+ struct RegisterRegisterOperands
+ {
+ RegisterInfo operand1; // register containing first operand for binary op
+ RegisterInfo operand2; // register containing second operand for binary op
+ } RegisterRegisterOperands;
+
+ int64_t signed_offset; // signed offset by which to adjust self (for registers only)
+
+ RegisterInfo reg; // plain register
+
+ uint64_t unsigned_immediate;// unsigned immediate value
+ int64_t signed_immediate; // signed immediate value
+
+ lldb::addr_t address; // direct address
+
+ struct ISAAndImmediate
+ {
+ uint32_t isa;
+ uint32_t unsigned_data32; // immdiate data
+ } ISAAndImmediate;
+
+ struct ISAAndImmediateSigned
+ {
+ uint32_t isa;
+ int32_t signed_data32; // signed immdiate data
+ } ISAAndImmediateSigned;
+
+ uint32_t isa;
+
+ } info;
+
+ Context () :
+ type (eContextInvalid),
+ info_type (eInfoTypeNoArgs)
+ {
+ }
+
+ void
+ SetRegisterPlusOffset (RegisterInfo base_reg,
+ int64_t signed_offset)
+ {
+ info_type = eInfoTypeRegisterPlusOffset;
+ info.RegisterPlusOffset.reg = base_reg;
+ info.RegisterPlusOffset.signed_offset = signed_offset;
+ }
+
+ void
+ SetRegisterPlusIndirectOffset (RegisterInfo base_reg,
+ RegisterInfo offset_reg)
+ {
+ info_type = eInfoTypeRegisterPlusIndirectOffset;
+ info.RegisterPlusIndirectOffset.base_reg = base_reg;
+ info.RegisterPlusIndirectOffset.offset_reg = offset_reg;
+ }
+
+ void
+ SetRegisterToRegisterPlusOffset (RegisterInfo data_reg,
+ RegisterInfo base_reg,
+ int64_t offset)
+ {
+ info_type = eInfoTypeRegisterToRegisterPlusOffset;
+ info.RegisterToRegisterPlusOffset.data_reg = data_reg;
+ info.RegisterToRegisterPlusOffset.base_reg = base_reg;
+ info.RegisterToRegisterPlusOffset.offset = offset;
+ }
+
+ void
+ SetRegisterToRegisterPlusIndirectOffset (RegisterInfo base_reg,
+ RegisterInfo offset_reg,
+ RegisterInfo data_reg)
+ {
+ info_type = eInfoTypeRegisterToRegisterPlusIndirectOffset;
+ info.RegisterToRegisterPlusIndirectOffset.base_reg = base_reg;
+ info.RegisterToRegisterPlusIndirectOffset.offset_reg = offset_reg;
+ info.RegisterToRegisterPlusIndirectOffset.data_reg = data_reg;
+ }
+
+ void
+ SetRegisterRegisterOperands (RegisterInfo op1_reg,
+ RegisterInfo op2_reg)
+ {
+ info_type = eInfoTypeRegisterRegisterOperands;
+ info.RegisterRegisterOperands.operand1 = op1_reg;
+ info.RegisterRegisterOperands.operand2 = op2_reg;
+ }
+
+ void
+ SetOffset (int64_t signed_offset)
+ {
+ info_type = eInfoTypeOffset;
+ info.signed_offset = signed_offset;
+ }
+
+ void
+ SetRegister (RegisterInfo reg)
+ {
+ info_type = eInfoTypeRegister;
+ info.reg = reg;
+ }
+
+ void
+ SetImmediate (uint64_t immediate)
+ {
+ info_type = eInfoTypeImmediate;
+ info.unsigned_immediate = immediate;
+ }
+
+ void
+ SetImmediateSigned (int64_t signed_immediate)
+ {
+ info_type = eInfoTypeImmediateSigned;
+ info.signed_immediate = signed_immediate;
+ }
+
+ void
+ SetAddress (lldb::addr_t address)
+ {
+ info_type = eInfoTypeAddress;
+ info.address = address;
+ }
+ void
+ SetISAAndImmediate (uint32_t isa, uint32_t data)
+ {
+ info_type = eInfoTypeISAAndImmediate;
+ info.ISAAndImmediate.isa = isa;
+ info.ISAAndImmediate.unsigned_data32 = data;
+ }
+
+ void
+ SetISAAndImmediateSigned (uint32_t isa, int32_t data)
+ {
+ info_type = eInfoTypeISAAndImmediateSigned;
+ info.ISAAndImmediateSigned.isa = isa;
+ info.ISAAndImmediateSigned.signed_data32 = data;
+ }
+
+ void
+ SetISA (uint32_t isa)
+ {
+ info_type = eInfoTypeISA;
+ info.isa = isa;
+ }
+
+ void
+ SetNoArgs ()
+ {
+ info_type = eInfoTypeNoArgs;
+ }
+
+ void
+ Dump (Stream &s,
+ EmulateInstruction *instruction) const;
+
+ };
+
+ typedef size_t (*ReadMemoryCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ typedef size_t (*WriteMemoryCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ typedef bool (*ReadRegisterCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+ typedef bool (*WriteRegisterCallback) (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ EmulateInstruction (const ArchSpec &arch);
+
+ virtual ~EmulateInstruction()
+ {
+ }
+ //----------------------------------------------------------------------
+ // Mandatory overrides
+ //----------------------------------------------------------------------
+ virtual bool
+ SupportsEmulatingIntructionsOfType (InstructionType inst_type) = 0;
+
+ virtual bool
+ SetTargetTriple (const ArchSpec &arch) = 0;
+
+ virtual bool
+ ReadInstruction () = 0;
+
+ virtual bool
+ EvaluateInstruction (uint32_t evaluate_options) = 0;
+
+ virtual bool
+ TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data) = 0;
+
+ virtual bool
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info) = 0;
+
+ //----------------------------------------------------------------------
+ // Optional overrides
+ //----------------------------------------------------------------------
+ virtual bool
+ SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target);
+
+ virtual bool
+ CreateFunctionEntryUnwind (UnwindPlan &unwind_plan);
+
+ static const char *
+ TranslateRegister (uint32_t reg_kind, uint32_t reg_num, std::string &reg_name);
+
+ //----------------------------------------------------------------------
+ // RegisterInfo variants
+ //----------------------------------------------------------------------
+ bool
+ ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue& reg_value);
+
+ uint64_t
+ ReadRegisterUnsigned (const RegisterInfo *reg_info,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteRegister (const Context &context,
+ const RegisterInfo *ref_info,
+ const RegisterValue& reg_value);
+
+ bool
+ WriteRegisterUnsigned (const Context &context,
+ const RegisterInfo *reg_info,
+ uint64_t reg_value);
+
+ //----------------------------------------------------------------------
+ // Register kind and number variants
+ //----------------------------------------------------------------------
+ bool
+ ReadRegister (uint32_t reg_kind,
+ uint32_t reg_num,
+ RegisterValue& reg_value);
+
+ bool
+ WriteRegister (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ const RegisterValue& reg_value);
+
+ uint64_t
+ ReadRegisterUnsigned (uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteRegisterUnsigned (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t reg_value);
+
+
+ size_t
+ ReadMemory (const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len);
+
+ uint64_t
+ ReadMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ size_t byte_size,
+ uint64_t fail_value,
+ bool *success_ptr);
+
+ bool
+ WriteMemory (const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len);
+
+ bool
+ WriteMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ uint64_t uval,
+ size_t uval_byte_size);
+
+ uint32_t
+ GetAddressByteSize () const
+ {
+ return m_arch.GetAddressByteSize();
+ }
+
+ lldb::ByteOrder
+ GetByteOrder () const
+ {
+ return m_arch.GetByteOrder();
+ }
+
+ const Opcode &
+ GetOpcode () const
+ {
+ return m_opcode;
+ }
+
+ lldb::addr_t
+ GetAddress () const
+ {
+ return m_addr;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+
+ static size_t
+ ReadMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+
+ static bool
+ WriteRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ static size_t
+ ReadMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value);
+
+
+ static bool
+ WriteRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value);
+
+ void
+ SetBaton (void *baton);
+
+ void
+ SetCallbacks (ReadMemoryCallback read_mem_callback,
+ WriteMemoryCallback write_mem_callback,
+ ReadRegisterCallback read_reg_callback,
+ WriteRegisterCallback write_reg_callback);
+
+ void
+ SetReadMemCallback (ReadMemoryCallback read_mem_callback);
+
+ void
+ SetWriteMemCallback (WriteMemoryCallback write_mem_callback);
+
+ void
+ SetReadRegCallback (ReadRegisterCallback read_reg_callback);
+
+ void
+ SetWriteRegCallback (WriteRegisterCallback write_reg_callback);
+
+ static bool
+ GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
+ uint32_t &reg_kind,
+ uint32_t &reg_num);
+
+ static uint32_t
+ GetInternalRegisterNumber (RegisterContext *reg_ctx,
+ const RegisterInfo &reg_info);
+
+protected:
+ ArchSpec m_arch;
+ void * m_baton;
+ ReadMemoryCallback m_read_mem_callback;
+ WriteMemoryCallback m_write_mem_callback;
+ ReadRegisterCallback m_read_reg_callback;
+ WriteRegisterCallback m_write_reg_callback;
+ lldb::addr_t m_addr;
+ Opcode m_opcode;
+
+
+private:
+ //------------------------------------------------------------------
+ // For EmulateInstruction only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (EmulateInstruction);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_EmulateInstruction_h_
diff --git a/include/lldb/Core/Error.h b/include/lldb/Core/Error.h
new file mode 100644
index 000000000000..9e45d5f555d6
--- /dev/null
+++ b/include/lldb/Core/Error.h
@@ -0,0 +1,312 @@
+//===-- Error.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DCError_h__
+#define __DCError_h__
+#if defined(__cplusplus)
+
+#if defined (__APPLE__)
+#include <mach/mach.h>
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class Log;
+
+//----------------------------------------------------------------------
+/// @class Error Error.h "lldb/Core/Error.h"
+/// @brief An error handling class.
+///
+/// This class is designed to be able to hold any error code that can be
+/// encountered on a given platform. The errors are stored as a value
+/// of type Error::ValueType. This value should be large enough to hold
+/// any and all errors that the class supports. Each error has an
+/// associated type that is of type lldb::ErrorType. New types
+/// can be added to support new error types, and architecture specific
+/// types can be enabled. In the future we may wish to switch to a
+/// registration mechanism where new error types can be registered at
+/// runtime instead of a hard coded scheme.
+///
+/// All errors in this class also know how to generate a string
+/// representation of themselves for printing results and error codes.
+/// The string value will be fetched on demand and its string value will
+/// be cached until the error is cleared of the value of the error
+/// changes.
+//----------------------------------------------------------------------
+class Error
+{
+public:
+ //------------------------------------------------------------------
+ /// Every error value that this object can contain needs to be able
+ /// to fit into ValueType.
+ //------------------------------------------------------------------
+ typedef uint32_t ValueType;
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize the error object with a generic success value.
+ ///
+ /// @param[in] err
+ /// An error code.
+ ///
+ /// @param[in] type
+ /// The type for \a err.
+ //------------------------------------------------------------------
+ Error ();
+
+ explicit
+ Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric);
+
+ explicit
+ Error (const char* err_str);
+
+ Error (const Error &rhs);
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// @param[in] err
+ /// An error code.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const Error&
+ operator = (const Error& rhs);
+
+
+ //------------------------------------------------------------------
+ /// Assignment operator from a kern_return_t.
+ ///
+ /// Sets the type to \c MachKernel and the error code to \a err.
+ ///
+ /// @param[in] err
+ /// A mach error code.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const Error&
+ operator = (uint32_t err);
+
+ ~Error();
+
+ //------------------------------------------------------------------
+ /// Get the error string associated with the current error.
+ //
+ /// Gets the error value as a NULL terminated C string. The error
+ /// string will be fetched and cached on demand. The error string
+ /// will be retrieved from a callback that is appropriate for the
+ /// type of the error and will be cached until the error value is
+ /// changed or cleared.
+ ///
+ /// @return
+ /// The error as a NULL terminated C string value if the error
+ /// is valid and is able to be converted to a string value,
+ /// NULL otherwise.
+ //------------------------------------------------------------------
+ const char *
+ AsCString (const char *default_error_str = "unknown error") const;
+
+ //------------------------------------------------------------------
+ /// Clear the object state.
+ ///
+ /// Reverts the state of this object to contain a generic success
+ /// value and frees any cached error string value.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Test for error condition.
+ ///
+ /// @return
+ /// \b true if this object contains an error, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ Fail () const;
+
+ //------------------------------------------------------------------
+ /// Access the error value.
+ ///
+ /// @return
+ /// The error value.
+ //------------------------------------------------------------------
+ ValueType
+ GetError () const;
+
+ //------------------------------------------------------------------
+ /// Access the error type.
+ ///
+ /// @return
+ /// The error type enumeration value.
+ //------------------------------------------------------------------
+ lldb::ErrorType
+ GetType () const;
+
+ //------------------------------------------------------------------
+ /// Log an error to Log().
+ ///
+ /// Log the error given a formatted string \a format. If the this
+ /// object contains an error code, update the error string to
+ /// contain the prefix "error: ", followed by the formatted string,
+ /// followed by the error value and any string that describes the
+ /// error value. This allows more context to be given to an error
+ /// string that remains cached in this object. Logging always occurs
+ /// even when the error code contains a non-error value.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Variable arguments that are needed for the printf style
+ /// format string \a format.
+ //------------------------------------------------------------------
+ void
+ PutToLog (Log *log, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ //------------------------------------------------------------------
+ /// Log an error to Log() if the error value is an error.
+ ///
+ /// Log the error given a formatted string \a format only if the
+ /// error value in this object describes an error condition. If the
+ /// this object contains an error, update the error string to
+ /// contain the prefix "error: " followed by the formatted string,
+ /// followed by the error value and any string that describes the
+ /// error value. This allows more context to be given to an error
+ /// string that remains cached in this object.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Variable arguments that are needed for the printf style
+ /// format string \a format.
+ //------------------------------------------------------------------
+ void
+ LogIfError (Log *log, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ //------------------------------------------------------------------
+ /// Set accessor from a kern_return_t.
+ ///
+ /// Set accesssor for the error value to \a err and the error type
+ /// to \c MachKernel.
+ ///
+ /// @param[in] err
+ /// A mach error code.
+ //------------------------------------------------------------------
+ void
+ SetMachError (uint32_t err);
+
+ //------------------------------------------------------------------
+ /// Set accesssor with an error value and type.
+ ///
+ /// Set accesssor for the error value to \a err and the error type
+ /// to \a type.
+ ///
+ /// @param[in] err
+ /// A mach error code.
+ ///
+ /// @param[in] type
+ /// The type for \a err.
+ //------------------------------------------------------------------
+ void
+ SetError (ValueType err, lldb::ErrorType type);
+
+ //------------------------------------------------------------------
+ /// Set the current error to errno.
+ ///
+ /// Update the error value to be \c errno and update the type to
+ /// be \c Error::POSIX.
+ //------------------------------------------------------------------
+ void
+ SetErrorToErrno ();
+
+ //------------------------------------------------------------------
+ /// Set the current error to a generic error.
+ ///
+ /// Update the error value to be \c LLDB_GENERIC_ERROR and update the
+ /// type to be \c Error::Generic.
+ //------------------------------------------------------------------
+ void
+ SetErrorToGenericError ();
+
+ //------------------------------------------------------------------
+ /// Set the current error string to \a err_str.
+ ///
+ /// Set accessor for the error string value for a generic errors,
+ /// or to supply additional details above and beyond the standard
+ /// error strings that the standard type callbacks typically
+ /// provide. This allows custom strings to be supplied as an
+ /// error explanation. The error string value will remain until the
+ /// error value is cleared or a new error value/type is assigned.
+ ///
+ /// @param err_str
+ /// The new custom error string to copy and cache.
+ //------------------------------------------------------------------
+ void
+ SetErrorString (const char *err_str);
+
+ //------------------------------------------------------------------
+ /// Set the current error string to a formatted error string.
+ ///
+ /// @param format
+ /// A printf style format string
+ //------------------------------------------------------------------
+ int
+ SetErrorStringWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ int
+ SetErrorStringWithVarArg (const char *format, va_list args);
+
+ //------------------------------------------------------------------
+ /// Test for success condition.
+ ///
+ /// Returns true if the error code in this object is considered a
+ /// successful return value.
+ ///
+ /// @return
+ /// \b true if this object contains an value that describes
+ /// success (non-erro), \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Success () const;
+
+ //------------------------------------------------------------------
+ /// Test for a failure due to a generic interrupt.
+ ///
+ /// Returns true if the error code in this object was caused by an interrupt.
+ /// At present only supports Posix EINTR.
+ ///
+ /// @return
+ /// \b true if this object contains an value that describes
+ /// failure due to interrupt, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ WasInterrupted() const;
+
+protected:
+ //------------------------------------------------------------------
+ /// Member variables
+ //------------------------------------------------------------------
+ ValueType m_code; ///< Error code as an integer value.
+ lldb::ErrorType m_type; ///< The type of the above error code.
+ mutable std::string m_string; ///< A string representation of the error code.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef __DCError_h__
diff --git a/include/lldb/Core/Event.h b/include/lldb/Core/Event.h
new file mode 100644
index 000000000000..1c3eec0359c3
--- /dev/null
+++ b/include/lldb/Core/Event.h
@@ -0,0 +1,217 @@
+//===-- Event.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_Event_h_
+#define liblldb_Event_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Host/Predicate.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// lldb::EventData
+//----------------------------------------------------------------------
+class EventData
+{
+ friend class Event;
+
+public:
+ EventData ();
+
+ virtual
+ ~EventData();
+
+ virtual const ConstString &
+ GetFlavor () const = 0;
+
+ virtual void
+ Dump (Stream *s) const;
+
+private:
+ virtual void
+ DoOnRemoval (Event *event_ptr)
+ {
+ }
+
+ DISALLOW_COPY_AND_ASSIGN (EventData);
+
+};
+
+//----------------------------------------------------------------------
+// lldb::EventDataBytes
+//----------------------------------------------------------------------
+class EventDataBytes : public EventData
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors
+ //------------------------------------------------------------------
+ EventDataBytes ();
+
+ EventDataBytes (const char *cstr);
+
+ EventDataBytes (const void *src, size_t src_len);
+
+ virtual
+ ~EventDataBytes();
+
+ //------------------------------------------------------------------
+ // Member functions
+ //------------------------------------------------------------------
+ virtual const ConstString &
+ GetFlavor () const;
+
+ virtual void
+ Dump (Stream *s) const;
+
+ const void *
+ GetBytes() const;
+
+ size_t
+ GetByteSize() const;
+
+ void
+ SetBytes (const void *src, size_t src_len);
+
+ void
+ SwapBytes (std::string &new_bytes);
+
+ void
+ SetBytesFromCString (const char *cstr);
+
+ //------------------------------------------------------------------
+ // Static functions
+ //------------------------------------------------------------------
+ static const EventDataBytes *
+ GetEventDataFromEvent (const Event *event_ptr);
+
+ static const void *
+ GetBytesFromEvent (const Event *event_ptr);
+
+ static size_t
+ GetByteSizeFromEvent (const Event *event_ptr);
+
+ static const ConstString &
+ GetFlavorString ();
+
+private:
+ std::string m_bytes;
+
+ DISALLOW_COPY_AND_ASSIGN (EventDataBytes);
+
+};
+
+//----------------------------------------------------------------------
+// lldb::Event
+//----------------------------------------------------------------------
+class Event
+{
+ friend class Broadcaster;
+ friend class Listener;
+ friend class EventData;
+
+public:
+
+ Event (Broadcaster *broadcaster, uint32_t event_type, EventData *data = NULL);
+
+ Event (uint32_t event_type, EventData *data = NULL);
+
+ ~Event ();
+
+ void
+ Dump (Stream *s) const;
+
+ EventData *
+ GetData ()
+ {
+ return m_data_ap.get();
+ }
+
+ const EventData *
+ GetData () const
+ {
+ return m_data_ap.get();
+ }
+
+ void
+ SetData (EventData *new_data)
+ {
+ m_data_ap.reset (new_data);
+ }
+
+ uint32_t
+ GetType () const
+ {
+ return m_type;
+ }
+
+ void
+ SetType (uint32_t new_type)
+ {
+ m_type = new_type;
+ }
+
+ Broadcaster *
+ GetBroadcaster () const
+ {
+ return m_broadcaster;
+ }
+
+ bool
+ BroadcasterIs (Broadcaster *broadcaster)
+ {
+ return broadcaster == m_broadcaster;
+ }
+
+ void
+ Clear()
+ {
+ m_data_ap.reset();
+ }
+
+
+private:
+ // This is only called by Listener when it pops an event off the queue for
+ // the listener. It calls the Event Data's DoOnRemoval() method, which is
+ // virtual and can be overridden by the specific data classes.
+
+ void
+ DoOnRemoval ();
+
+ // Called by Broadcaster::BroadcastEvent prior to letting all the listeners
+ // know about it update the contained broadcaster so that events can be
+ // popped off one queue and re-broadcast to others.
+ void
+ SetBroadcaster (Broadcaster *broadcaster)
+ {
+ m_broadcaster = broadcaster;
+ }
+
+
+ Broadcaster * m_broadcaster; // The broadcaster that sent this event
+ uint32_t m_type; // The bit describing this event
+ std::unique_ptr<EventData> m_data_ap; // User specific data for this event
+
+
+ DISALLOW_COPY_AND_ASSIGN (Event);
+ Event(); // Disallow default constructor
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Event_h_
diff --git a/include/lldb/Core/FileLineResolver.h b/include/lldb/Core/FileLineResolver.h
new file mode 100644
index 000000000000..e1928f1b063d
--- /dev/null
+++ b/include/lldb/Core/FileLineResolver.h
@@ -0,0 +1,81 @@
+//===-- FileLineResolver.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_FileLineResolver_h_
+#define liblldb_FileLineResolver_h_
+
+// Project includes
+#include "lldb/Core/AddressResolver.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class FileLineResolver FileLineResolver.h "lldb/Core/FileLineResolver.h"
+/// @brief This class finds address for source file and line. Optionally, it will look for inlined
+/// instances of the file and line specification.
+//----------------------------------------------------------------------
+
+class FileLineResolver :
+ public Searcher
+{
+public:
+ FileLineResolver () :
+ m_file_spec(),
+ m_line_number(UINT32_MAX), // Set this to zero for all lines in a file
+ m_sc_list (),
+ m_inlines (true)
+ {
+ }
+
+ FileLineResolver (const FileSpec &resolver,
+ uint32_t line_no,
+ bool check_inlines);
+
+ virtual
+ ~FileLineResolver ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing);
+
+ virtual Searcher::Depth
+ GetDepth ();
+
+ virtual void
+ GetDescription (Stream *s);
+
+ const SymbolContextList &
+ GetFileLineMatches()
+ {
+ return m_sc_list;
+ }
+
+ void
+ Clear();
+
+ void
+ Reset (const FileSpec &file_spec,
+ uint32_t line,
+ bool check_inlines);
+protected:
+ FileSpec m_file_spec; // This is the file spec we are looking for.
+ uint32_t m_line_number; // This is the line number that we are looking for.
+ SymbolContextList m_sc_list;
+ bool m_inlines; // This determines whether the resolver looks for inlined functions or not.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(FileLineResolver);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_FileLineResolver_h_
diff --git a/include/lldb/Core/FileSpecList.h b/include/lldb/Core/FileSpecList.h
new file mode 100644
index 000000000000..f94bdae83c01
--- /dev/null
+++ b/include/lldb/Core/FileSpecList.h
@@ -0,0 +1,243 @@
+//===-- FileSpecList.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_FileSpecList_h_
+#define liblldb_FileSpecList_h_
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+#include <vector>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class FileSpecList FileSpecList.h "lldb/Core/FileSpecList.h"
+/// @brief A file collection class.
+///
+/// A class that contains a mutable list of FileSpec objects.
+//----------------------------------------------------------------------
+class FileSpecList
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize this object with an empty file list.
+ //------------------------------------------------------------------
+ FileSpecList ();
+
+ //------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// Initialize this object with a copy of the file list from \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const reference to another file list object.
+ //------------------------------------------------------------------
+ FileSpecList (const FileSpecList &rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~FileSpecList ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Replace the file list in this object with the file list from
+ /// \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A file list object to copy.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const FileSpecList&
+ operator= (const FileSpecList &rhs);
+
+ //------------------------------------------------------------------
+ /// Append a FileSpec object to the list.
+ ///
+ /// Appends \a file to the end of the file list.
+ ///
+ /// @param[in] file
+ /// A new file to append to this file list.
+ //------------------------------------------------------------------
+ void
+ Append (const FileSpec &file);
+
+ //------------------------------------------------------------------
+ /// Append a FileSpec object if unique.
+ ///
+ /// Appends \a file to the end of the file list if it doesn't
+ /// already exist in the file list.
+ ///
+ /// @param[in] file
+ /// A new file to append to this file list.
+ ///
+ /// @return
+ /// \b true if the file was appended, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ AppendIfUnique (const FileSpec &file);
+
+ //------------------------------------------------------------------
+ /// Clears the file list.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Dumps the file list to the supplied stream pointer "s".
+ ///
+ /// @param[in] s
+ /// The stream that will be used to dump the object description.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, const char *separator_cstr = "\n") const;
+
+ //------------------------------------------------------------------
+ /// Find a file index.
+ ///
+ /// Find the index of the file in the file spec list that matches
+ /// \a file starting \a idx entries into the file spec list.
+ ///
+ /// @param[in] idx
+ /// An index into the file list.
+ ///
+ /// @param[in] file
+ /// The file specification to search for.
+ ///
+ /// @param[in] full
+ /// Should FileSpec::Equal be called with "full" true or false.
+ ///
+ /// @return
+ /// The index of the file that matches \a file if it is found,
+ /// else UINT32_MAX is returned.
+ //------------------------------------------------------------------
+ size_t
+ FindFileIndex (size_t idx, const FileSpec &file, bool full) const;
+
+ //------------------------------------------------------------------
+ /// Get file at index.
+ ///
+ /// Gets a file from the file list. If \a idx is not a valid index,
+ /// an empty FileSpec object will be returned. The file objects
+ /// that are returned can be tested using
+ /// FileSpec::operator void*().
+ ///
+ /// @param[in] idx
+ /// An index into the file list.
+ ///
+ /// @return
+ /// A copy of the FileSpec object at index \a idx. If \a idx
+ /// is out of range, then an empty FileSpec object will be
+ /// returned.
+ //------------------------------------------------------------------
+ const FileSpec &
+ GetFileSpecAtIndex (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Get file specification pointer at index.
+ ///
+ /// Gets a file from the file list. The file objects that are
+ /// returned can be tested using FileSpec::operator void*().
+ ///
+ /// @param[in] idx
+ /// An index into the file list.
+ ///
+ /// @return
+ /// A pointer to a contained FileSpec object at index \a idx.
+ /// If \a idx is out of range, then an NULL is returned.
+ //------------------------------------------------------------------
+ const FileSpec *
+ GetFileSpecPointerAtIndex (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Return the size in bytes that this object takes in memory. This
+ /// returns the size in bytes of this object, not any shared string
+ /// values it may refer to.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ bool
+ IsEmpty() const
+ {
+ return m_files.empty();
+ }
+
+ //------------------------------------------------------------------
+ /// Get the number of files in the file list.
+ ///
+ /// @return
+ /// The number of files in the file spec list.
+ //------------------------------------------------------------------
+ size_t
+ GetSize () const;
+
+ bool
+ Insert (size_t idx, const FileSpec &file)
+ {
+ if (idx < m_files.size())
+ {
+ m_files.insert(m_files.begin() + idx, file);
+ return true;
+ }
+ else if (idx == m_files.size())
+ {
+ m_files.push_back(file);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ Replace (size_t idx, const FileSpec &file)
+ {
+ if (idx < m_files.size())
+ {
+ m_files[idx] = file;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ Remove (size_t idx)
+ {
+ if (idx < m_files.size())
+ {
+ m_files.erase(m_files.begin() + idx);
+ return true;
+ }
+ return false;
+ }
+
+ static size_t GetFilesMatchingPartialPath (const char *path, bool dir_okay, FileSpecList &matches);
+
+protected:
+ typedef std::vector<FileSpec> collection; ///< The collection type for the file list.
+ collection m_files; ///< A collection of FileSpec objects.
+};
+
+} // namespace lldb_private
+
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_FileSpecList_h_
diff --git a/include/lldb/Core/Flags.h b/include/lldb/Core/Flags.h
new file mode 100644
index 000000000000..233f098ead23
--- /dev/null
+++ b/include/lldb/Core/Flags.h
@@ -0,0 +1,253 @@
+//===-- Flags.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_Flags_h_
+#define liblldb_Flags_h_
+#if defined(__cplusplus)
+
+
+#include <stdint.h>
+#include <unistd.h>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Flags Flags.h "lldb/Core/Flags.h"
+/// @brief A class to manage flags.
+///
+/// The Flags class managed flag bits and allows testing and
+/// modification of individual or multiple flag bits.
+//----------------------------------------------------------------------
+class Flags
+{
+public:
+ //----------------------------------------------------------------------
+ /// The value type for flags is a 32 bit unsigned integer type.
+ //----------------------------------------------------------------------
+ typedef uint32_t ValueType;
+
+ //----------------------------------------------------------------------
+ /// Construct with initial flag bit values.
+ ///
+ /// Constructs this object with \a mask as the initial value for all
+ /// of the flags.
+ ///
+ /// @param[in] mask
+ /// The initial value for all flags.
+ //----------------------------------------------------------------------
+ Flags (ValueType flags = 0) :
+ m_flags (flags)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// Construct and copy the flags from \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const Flags object reference to copy.
+ //----------------------------------------------------------------------
+ Flags (const Flags& rhs) :
+ m_flags(rhs.m_flags)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ /// Destructor.
+ //----------------------------------------------------------------------
+ ~Flags ()
+ {
+ }
+
+ //----------------------------------------------------------------------
+ /// Get accessor for all flags.
+ ///
+ /// @return
+ /// Returns all of the flags as a Flags::ValueType.
+ //----------------------------------------------------------------------
+ ValueType
+ Get () const
+ {
+ return m_flags;
+ }
+
+ //----------------------------------------------------------------------
+ /// Return the number of flags that can be represented in this
+ /// object.
+ ///
+ /// @return
+ /// The maximum number bits in this flag object.
+ //----------------------------------------------------------------------
+ size_t
+ GetBitSize() const
+ {
+ return sizeof (ValueType) * 8;
+ }
+
+ //----------------------------------------------------------------------
+ /// Set accessor for all flags.
+ ///
+ /// @param[in] flags
+ /// The bits with which to replace all of the current flags.
+ //----------------------------------------------------------------------
+ void
+ Reset (ValueType flags)
+ {
+ m_flags = flags;
+ }
+
+ //----------------------------------------------------------------------
+ /// Clear one or more flags.
+ ///
+ /// @param[in] mask
+ /// A bitfield containing one or more flags.
+ ///
+ /// @return
+ /// The new flags after clearing all bits from \a mask.
+ //----------------------------------------------------------------------
+ ValueType
+ Clear (ValueType mask = ~(ValueType)0)
+ {
+ m_flags &= ~mask;
+ return m_flags;
+ }
+
+
+ //----------------------------------------------------------------------
+ /// Set one or more flags by logical OR'ing \a mask with the current
+ /// flags.
+ ///
+ /// @param[in] mask
+ /// A bitfield containing one or more flags.
+ ///
+ /// @return
+ /// The new flags after setting all bits from \a mask.
+ //----------------------------------------------------------------------
+ ValueType
+ Set (ValueType mask)
+ {
+ m_flags |= mask;
+ return m_flags;
+ }
+
+
+ //----------------------------------------------------------------------
+ /// Test if all bits in \a mask are 1 in the current flags
+ ///
+ /// @return
+ /// \b true if all flags in \a mask are 1, \b false
+ /// otherwise.
+ //----------------------------------------------------------------------
+ bool
+ AllSet (ValueType mask) const
+ {
+ return (m_flags & mask) == mask;
+ }
+
+ //----------------------------------------------------------------------
+ /// Test one or more flags.
+ ///
+ /// @return
+ /// \b true if any flags in \a mask are 1, \b false
+ /// otherwise.
+ //----------------------------------------------------------------------
+ bool
+ AnySet (ValueType mask) const
+ {
+ return (m_flags & mask) != 0;
+ }
+
+ //----------------------------------------------------------------------
+ /// Test a single flag bit.
+ ///
+ /// @return
+ /// \b true if \a bit is set, \b false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ Test (ValueType bit) const
+ {
+ return (m_flags & bit) != 0;
+ }
+
+ //----------------------------------------------------------------------
+ /// Test if all bits in \a mask are clear.
+ ///
+ /// @return
+ /// \b true if \b all flags in \a mask are clear, \b false
+ /// otherwise.
+ //----------------------------------------------------------------------
+ bool
+ AllClear (ValueType mask) const
+ {
+ return (m_flags & mask) == 0;
+ }
+
+ bool
+ AnyClear (ValueType mask) const
+ {
+ return (m_flags & mask) != mask;
+ }
+
+ //----------------------------------------------------------------------
+ /// Test a single flag bit to see if it is clear (zero).
+ ///
+ /// @return
+ /// \b true if \a bit is 0, \b false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ IsClear (ValueType bit) const
+ {
+ return (m_flags & bit) == 0;
+ }
+
+ //----------------------------------------------------------------------
+ /// Get the number of zero bits in \a m_flags.
+ ///
+ /// @return
+ /// The number of bits that are set to 0 in the current flags.
+ //----------------------------------------------------------------------
+ size_t
+ ClearCount () const
+ {
+ size_t count = 0;
+ for (ValueType shift = 0; shift < sizeof(ValueType)*8; ++shift)
+ {
+ if ((m_flags & (1u << shift)) == 0)
+ ++count;
+ }
+ return count;
+ }
+
+ //----------------------------------------------------------------------
+ /// Get the number of one bits in \a m_flags.
+ ///
+ /// @return
+ /// The number of bits that are set to 1 in the current flags.
+ //----------------------------------------------------------------------
+ size_t
+ SetCount () const
+ {
+ size_t count = 0;
+ for (ValueType mask = m_flags; mask; mask >>= 1)
+ {
+ if (mask & 1u)
+ ++count;
+ }
+ return count;
+ }
+
+protected:
+ ValueType m_flags; ///< The flags.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Flags_h_
diff --git a/include/lldb/Core/History.h b/include/lldb/Core/History.h
new file mode 100644
index 000000000000..b3626882f843
--- /dev/null
+++ b/include/lldb/Core/History.h
@@ -0,0 +1,177 @@
+//===-- History.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_History_h_
+#define lldb_History_h_
+
+// C Includes
+#include <stdint.h>
+
+// C++ Includes
+#include <stack>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class HistorySource History.h "lldb/Core/History.h"
+/// @brief A class that defines history events.
+//----------------------------------------------------------------------
+
+class HistorySource
+{
+public:
+ typedef const void * HistoryEvent;
+
+ HistorySource () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_events ()
+ {
+ }
+
+ virtual
+ ~HistorySource()
+ {
+ }
+
+ // Create a new history event. Subclasses should use any data or members
+ // in the subclass of this class to produce a history event and push it
+ // onto the end of the history stack.
+
+ virtual HistoryEvent
+ CreateHistoryEvent () = 0;
+
+ virtual void
+ DeleteHistoryEvent (HistoryEvent event) = 0;
+
+ virtual void
+ DumpHistoryEvent (Stream &strm, HistoryEvent event) = 0;
+
+ virtual size_t
+ GetHistoryEventCount() = 0;
+
+ virtual HistoryEvent
+ GetHistoryEventAtIndex (uint32_t idx) = 0;
+
+ virtual HistoryEvent
+ GetCurrentHistoryEvent () = 0;
+
+ // Return 0 when lhs == rhs, 1 if lhs > rhs, or -1 if lhs < rhs.
+ virtual int
+ CompareHistoryEvents (const HistoryEvent lhs,
+ const HistoryEvent rhs) = 0;
+
+ virtual bool
+ IsCurrentHistoryEvent (const HistoryEvent event) = 0;
+
+private:
+ typedef std::stack<HistoryEvent> collection;
+
+ Mutex m_mutex;
+ collection m_events;
+
+ DISALLOW_COPY_AND_ASSIGN (HistorySource);
+
+};
+
+//----------------------------------------------------------------------
+/// @class HistorySourceUInt History.h "lldb/Core/History.h"
+/// @brief A class that defines history events that are represented by
+/// unsigned integers.
+///
+/// Any history event that is defined by a unique monotonically
+/// increasing unsigned integer
+//----------------------------------------------------------------------
+
+class HistorySourceUInt : public HistorySource
+{
+ HistorySourceUInt (const char *id_name, uintptr_t start_value = 0u) :
+ HistorySource(),
+ m_name (id_name),
+ m_curr_id (start_value)
+ {
+ }
+
+ virtual
+ ~HistorySourceUInt()
+ {
+ }
+
+ // Create a new history event. Subclasses should use any data or members
+ // in the subclass of this class to produce a history event and push it
+ // onto the end of the history stack.
+
+ virtual HistoryEvent
+ CreateHistoryEvent ()
+ {
+ ++m_curr_id;
+ return (HistoryEvent)m_curr_id;
+ }
+
+ virtual void
+ DeleteHistoryEvent (HistoryEvent event)
+ {
+ // Nothing to delete, the event contains the integer
+ }
+
+ virtual void
+ DumpHistoryEvent (Stream &strm, HistoryEvent event);
+
+ virtual size_t
+ GetHistoryEventCount()
+ {
+ return m_curr_id;
+ }
+
+ virtual HistoryEvent
+ GetHistoryEventAtIndex (uint32_t idx)
+ {
+ return (HistoryEvent)((uintptr_t)idx);
+ }
+
+ virtual HistoryEvent
+ GetCurrentHistoryEvent ()
+ {
+ return (HistoryEvent)m_curr_id;
+ }
+
+ // Return 0 when lhs == rhs, 1 if lhs > rhs, or -1 if lhs < rhs.
+ virtual int
+ CompareHistoryEvents (const HistoryEvent lhs,
+ const HistoryEvent rhs)
+ {
+ uintptr_t lhs_uint = (uintptr_t)lhs;
+ uintptr_t rhs_uint = (uintptr_t)rhs;
+ if (lhs_uint < rhs_uint)
+ return -1;
+ if (lhs_uint > rhs_uint)
+ return +1;
+ return 0;
+ }
+
+ virtual bool
+ IsCurrentHistoryEvent (const HistoryEvent event)
+ {
+ return (uintptr_t)event == m_curr_id;
+ }
+
+protected:
+ std::string m_name; // The name of the history unsigned integer
+ uintptr_t m_curr_id; // The current value of the history unsigned unteger
+};
+
+
+} // namespace lldb_private
+
+#endif // lldb_History_h_
diff --git a/include/lldb/Core/IOStreamMacros.h b/include/lldb/Core/IOStreamMacros.h
new file mode 100644
index 000000000000..cc4eeb0e050f
--- /dev/null
+++ b/include/lldb/Core/IOStreamMacros.h
@@ -0,0 +1,38 @@
+//===-- IOStreamMacros.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_IOStreamMacros_h_
+#define liblldb_IOStreamMacros_h_
+#if defined(__cplusplus)
+
+#include <iomanip>
+
+#define RAW_HEXBASE std::setfill('0') << std::hex << std::right
+#define HEXBASE '0' << 'x' << RAW_HEXBASE
+#define RAWHEX8(x) RAW_HEXBASE << std::setw(2) << ((uint32_t)(x))
+#define RAWHEX16 RAW_HEXBASE << std::setw(4)
+#define RAWHEX32 RAW_HEXBASE << std::setw(8)
+#define RAWHEX64 RAW_HEXBASE << std::setw(16)
+#define HEX8(x) HEXBASE << std::setw(2) << ((uint32_t)(x))
+#define HEX16 HEXBASE << std::setw(4)
+#define HEX32 HEXBASE << std::setw(8)
+#define HEX64 HEXBASE << std::setw(16)
+#define RAW_HEX(x) RAW_HEXBASE << std::setw(sizeof(x)*2) << (x)
+#define HEX(x) HEXBASE << std::setw(sizeof(x)*2) << (x)
+#define HEX_SIZE(x, sz) HEXBASE << std::setw((sz)) << (x)
+#define STRING_WIDTH(w) std::setfill(' ') << std::setw(w)
+#define LEFT_STRING_WIDTH(s, w) std::left << std::setfill(' ') << std::setw(w) << (s) << std::right
+#define DECIMAL std::dec << std::setfill(' ')
+#define DECIMAL_WIDTH(w) DECIMAL << std::setw(w)
+//#define FLOAT(n, d) std::setfill(' ') << std::setw((n)+(d)+1) << std::setprecision(d) << std::showpoint << std::fixed
+#define INDENT_WITH_SPACES(iword_idx) std::setfill(' ') << std::setw((iword_idx)) << ""
+#define INDENT_WITH_TABS(iword_idx) std::setfill('\t') << std::setw((iword_idx)) << ""
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_IOStreamMacros_h_
diff --git a/include/lldb/Core/InputReader.h b/include/lldb/Core/InputReader.h
new file mode 100644
index 000000000000..fa86e9a39e2b
--- /dev/null
+++ b/include/lldb/Core/InputReader.h
@@ -0,0 +1,274 @@
+//===-- InputReader.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_InputReader_h_
+#define liblldb_InputReader_h_
+
+#include <string.h>
+
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Host/Predicate.h"
+
+
+namespace lldb_private {
+
+class InputReader
+{
+public:
+
+ typedef size_t (*Callback) (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ struct HandlerData
+ {
+ InputReader& reader;
+ const char *bytes;
+ size_t bytes_len;
+ void* baton;
+
+ HandlerData(InputReader& r,
+ const char* b,
+ size_t l,
+ void* t) :
+ reader(r),
+ bytes(b),
+ bytes_len(l),
+ baton(t)
+ {
+ }
+
+ lldb::StreamSP
+ GetOutStream();
+
+ bool
+ GetBatchMode();
+ };
+
+ struct InitializationParameters
+ {
+ private:
+ void* m_baton;
+ lldb::InputReaderGranularity m_token_size;
+ char* m_end_token;
+ char* m_prompt;
+ bool m_echo;
+ bool m_save_user_input;
+ public:
+ InitializationParameters() :
+ m_baton(NULL),
+ m_token_size(lldb::eInputReaderGranularityLine),
+ m_echo(true),
+ m_save_user_input(false)
+ {
+ SetEndToken("DONE");
+ SetPrompt("> ");
+ }
+
+ InitializationParameters&
+ SetEcho(bool e)
+ {
+ m_echo = e;
+ return *this;
+ }
+
+ InitializationParameters&
+ SetSaveUserInput(bool s)
+ {
+ m_save_user_input = s;
+ return *this;
+ }
+
+ InitializationParameters&
+ SetBaton(void* b)
+ {
+ m_baton = b;
+ return *this;
+ }
+
+ InitializationParameters&
+ SetGranularity(lldb::InputReaderGranularity g)
+ {
+ m_token_size = g;
+ return *this;
+ }
+
+ InitializationParameters&
+ SetEndToken(const char* e)
+ {
+ m_end_token = new char[strlen(e)+1];
+ ::strcpy(m_end_token,e);
+ return *this;
+ }
+
+ InitializationParameters&
+ SetPrompt(const char* p)
+ {
+ m_prompt = new char[strlen(p)+1];
+ ::strcpy(m_prompt,p);
+ return *this;
+ }
+
+ friend class InputReaderEZ;
+
+ };
+
+ InputReader (Debugger &debugger);
+
+ virtual
+ ~InputReader ();
+
+ virtual Error
+ Initialize (Callback callback,
+ void *baton,
+ lldb::InputReaderGranularity token_size,
+ const char *end_token,
+ const char *prompt,
+ bool echo);
+
+ virtual Error Initialize(void* baton,
+ lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+ const char* end_token = "DONE",
+ const char *prompt = "> ",
+ bool echo = true)
+ {
+ return Error("unimplemented");
+ }
+
+ virtual Error
+ Initialize(InitializationParameters& params)
+ {
+ return Error("unimplemented");
+ }
+
+ // to use these handlers instead of the Callback function, you must subclass
+ // InputReaderEZ, and redefine the handlers for the events you care about
+ virtual void
+ ActivateHandler(HandlerData&) {}
+
+ virtual void
+ DeactivateHandler(HandlerData&) {}
+
+ virtual void
+ ReactivateHandler(HandlerData&) {}
+
+ virtual void
+ AsynchronousOutputWrittenHandler(HandlerData&) {}
+
+ virtual void
+ GotTokenHandler(HandlerData&) {}
+
+ virtual void
+ InterruptHandler(HandlerData&) {}
+
+ virtual void
+ EOFHandler(HandlerData&) {}
+
+ virtual void
+ DoneHandler(HandlerData&) {}
+
+ bool
+ IsDone () const
+ {
+ return m_done;
+ }
+
+ void
+ SetIsDone (bool b)
+ {
+ m_done = b;
+ }
+
+ lldb::InputReaderGranularity
+ GetGranularity () const
+ {
+ return m_granularity;
+ }
+
+ bool
+ GetEcho () const
+ {
+ return m_echo;
+ }
+
+ StringList&
+ GetUserInput()
+ {
+ return m_user_input;
+ }
+
+ virtual bool
+ GetSaveUserInput()
+ {
+ return false;
+ }
+
+ // Subclasses _can_ override this function to get input as it comes in
+ // without any granularity
+ virtual size_t
+ HandleRawBytes (const char *bytes, size_t bytes_len);
+
+ Debugger &
+ GetDebugger()
+ {
+ return m_debugger;
+ }
+
+ bool
+ IsActive () const
+ {
+ return m_active;
+ }
+
+ const char *
+ GetPrompt () const;
+
+ void
+ RefreshPrompt();
+
+ // If you want to read from an input reader synchronously, then just initialize the
+ // reader and then call WaitOnReaderIsDone, which will return when the reader is popped.
+ void
+ WaitOnReaderIsDone ();
+
+ static const char *
+ GranularityAsCString (lldb::InputReaderGranularity granularity);
+
+protected:
+ friend class Debugger;
+
+ void
+ Notify (lldb::InputReaderAction notification);
+
+ Debugger &m_debugger;
+ Callback m_callback;
+ void *m_callback_baton;
+ std::string m_end_token;
+ std::string m_prompt;
+ lldb::InputReaderGranularity m_granularity;
+ bool m_done;
+ bool m_echo;
+ bool m_active;
+ Predicate<bool> m_reader_done;
+ StringList m_user_input;
+ bool m_save_user_input;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (InputReader);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_InputReader_h_
diff --git a/include/lldb/Core/InputReaderEZ.h b/include/lldb/Core/InputReaderEZ.h
new file mode 100644
index 000000000000..85561b6f0a9e
--- /dev/null
+++ b/include/lldb/Core/InputReaderEZ.h
@@ -0,0 +1,87 @@
+//===-- InputReaderEZ.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_InputReaderEZ_h_
+#define liblldb_InputReaderEZ_h_
+
+#include "lldb/Core/InputReader.h"
+
+namespace lldb_private {
+
+class InputReaderEZ : public InputReader
+{
+
+private:
+
+ static size_t Callback_Impl(void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+public:
+
+ InputReaderEZ (Debugger &debugger) :
+ InputReader(debugger)
+ {}
+
+ virtual
+ ~InputReaderEZ ();
+
+ using InputReader::Initialize;
+ virtual Error
+ Initialize(void* baton,
+ lldb::InputReaderGranularity token_size = lldb::eInputReaderGranularityLine,
+ const char* end_token = "DONE",
+ const char *prompt = "> ",
+ bool echo = true);
+
+ virtual Error
+ Initialize(InitializationParameters& params);
+
+ virtual void
+ ActivateHandler(HandlerData&) {}
+
+ virtual void
+ DeactivateHandler(HandlerData&) {}
+
+ virtual void
+ ReactivateHandler(HandlerData&) {}
+
+ virtual void
+ AsynchronousOutputWrittenHandler(HandlerData&) {}
+
+ virtual void
+ GotTokenHandler(HandlerData&) {}
+
+ virtual void
+ InterruptHandler(HandlerData&) {}
+
+ virtual void
+ EOFHandler(HandlerData&) {}
+
+ virtual void
+ DoneHandler(HandlerData&) {}
+
+ virtual bool
+ GetSaveUserInput()
+ {
+ return m_save_user_input;
+ }
+
+protected:
+ friend class Debugger;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (InputReaderEZ);
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_InputReaderEZ_h_
diff --git a/include/lldb/Core/InputReaderStack.h b/include/lldb/Core/InputReaderStack.h
new file mode 100644
index 000000000000..a73b97cad571
--- /dev/null
+++ b/include/lldb/Core/InputReaderStack.h
@@ -0,0 +1,58 @@
+//===-- InputReaderStack.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_InputReaderStack_h_
+#define liblldb_InputReaderStack_h_
+
+#include <stack>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class InputReaderStack
+{
+public:
+
+ InputReaderStack ();
+
+ ~InputReaderStack ();
+
+ size_t
+ GetSize () const;
+
+ void
+ Push (const lldb::InputReaderSP& reader_sp);
+
+ bool
+ IsEmpty () const;
+
+ lldb::InputReaderSP
+ Top ();
+
+ void
+ Pop ();
+
+ Mutex &
+ GetStackMutex ();
+
+protected:
+
+ std::stack<lldb::InputReaderSP> m_input_readers;
+ mutable Mutex m_input_readers_mutex;
+
+private:
+
+ DISALLOW_COPY_AND_ASSIGN (InputReaderStack);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_InputReaderStack_h_
diff --git a/include/lldb/Core/Language.h b/include/lldb/Core/Language.h
new file mode 100644
index 000000000000..670c6aa695e1
--- /dev/null
+++ b/include/lldb/Core/Language.h
@@ -0,0 +1,117 @@
+//===-- Language.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_Language_h_
+#define liblldb_Language_h_
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Language Language.h "lldb/Core/Language.h"
+/// @brief Encapsulates the programming language for an lldb object.
+///
+/// Languages are represented by an enumeration value.
+///
+/// The enumeration values used when describing the programming language
+/// are the same values as the latest DWARF specification.
+//----------------------------------------------------------------------
+class Language
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with optional language enumeration.
+ //------------------------------------------------------------------
+ Language(lldb::LanguageType language = lldb::eLanguageTypeUnknown);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~Language();
+
+ //------------------------------------------------------------------
+ /// Get the language value as a NULL termianted C string.
+ ///
+ /// @return
+ /// The C string representation of the language. The returned
+ /// string does not need to be freed as it comes from constant
+ /// strings. NULL can be returned when the language is set to
+ /// a value that doesn't match of of the lldb::LanguageType
+ /// enumerations.
+ //------------------------------------------------------------------
+ const char *
+ AsCString (lldb::DescriptionLevel level = lldb::eDescriptionLevelBrief) const;
+
+ void
+ Clear();
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ //------------------------------------------------------------------
+ /// Dump the language value to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the language description.
+ //------------------------------------------------------------------
+ void
+ Dump(Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the language.
+ ///
+ /// @return
+ /// The enumeration value that describes the programming
+ /// language that an object is associated with.
+ //------------------------------------------------------------------
+ virtual lldb::LanguageType
+ GetLanguage() const;
+
+ //------------------------------------------------------------------
+ /// Set accessor for the language.
+ ///
+ /// @param[in] language
+ /// The new enumeration value that describes the programming
+ /// language that an object is associated with.
+ //------------------------------------------------------------------
+ void
+ SetLanguage(lldb::LanguageType language);
+
+ //------------------------------------------------------------------
+ /// Set accessor for the language.
+ ///
+ /// @param[in] language_cstr
+ /// The language name as a C string.
+ //------------------------------------------------------------------
+ bool
+ SetLanguageFromCString(const char *language_cstr);
+
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::LanguageType m_language; ///< The programming language enumeration value.
+ ///< The enumeration values are the same as the
+ ///< latest DWARF specification.
+};
+
+//--------------------------------------------------------------
+/// Stream the language enumeration as a string object to a
+/// Stream.
+//--------------------------------------------------------------
+Stream& operator << (Stream& s, const Language& language);
+
+} // namespace lldb_private
+
+#endif // liblldb_Language_h_
diff --git a/include/lldb/Core/Listener.h b/include/lldb/Core/Listener.h
new file mode 100644
index 000000000000..a12a65d705db
--- /dev/null
+++ b/include/lldb/Core/Listener.h
@@ -0,0 +1,194 @@
+//===-- Listener.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_Select_h_
+#define liblldb_Select_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Core/Event.h"
+
+namespace lldb_private {
+
+class Listener
+{
+public:
+ typedef bool (*HandleBroadcastCallback) (lldb::EventSP &event_sp, void *baton);
+
+ friend class Broadcaster;
+ friend class BroadcasterManager;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Listener (const char *name);
+
+ ~Listener ();
+
+ void
+ AddEvent (lldb::EventSP &event);
+
+ void
+ Clear ();
+
+ const char *
+ GetName ()
+ {
+ return m_name.c_str();
+ }
+
+ uint32_t
+ StartListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec);
+
+ bool
+ StopListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec);
+
+ uint32_t
+ StartListeningForEvents (Broadcaster* broadcaster,
+ uint32_t event_mask);
+
+ uint32_t
+ StartListeningForEvents (Broadcaster* broadcaster,
+ uint32_t event_mask,
+ HandleBroadcastCallback callback,
+ void *callback_user_data);
+
+ bool
+ StopListeningForEvents (Broadcaster* broadcaster,
+ uint32_t event_mask);
+
+ // Returns true if an event was recieved, false if we timed out.
+ bool
+ WaitForEvent (const TimeValue *timeout,
+ lldb::EventSP &event_sp);
+
+ bool
+ WaitForEventForBroadcaster (const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ lldb::EventSP &event_sp);
+
+ bool
+ WaitForEventForBroadcasterWithType (const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ uint32_t event_type_mask,
+ lldb::EventSP &event_sp);
+
+ Event *
+ PeekAtNextEvent ();
+
+ Event *
+ PeekAtNextEventForBroadcaster (Broadcaster *broadcaster);
+
+ Event *
+ PeekAtNextEventForBroadcasterWithType (Broadcaster *broadcaster,
+ uint32_t event_type_mask);
+
+ bool
+ GetNextEvent (lldb::EventSP &event_sp);
+
+ bool
+ GetNextEventForBroadcaster (Broadcaster *broadcaster,
+ lldb::EventSP &event_sp);
+
+ bool
+ GetNextEventForBroadcasterWithType (Broadcaster *broadcaster,
+ uint32_t event_type_mask,
+ lldb::EventSP &event_sp);
+
+ size_t
+ HandleBroadcastEvent (lldb::EventSP &event_sp);
+
+private:
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Listener can see and modify these
+ //------------------------------------------------------------------
+ struct BroadcasterInfo
+ {
+ BroadcasterInfo(uint32_t mask, HandleBroadcastCallback cb = NULL, void *ud = NULL) :
+ event_mask (mask),
+ callback (cb),
+ callback_user_data (ud)
+ {
+ }
+
+ uint32_t event_mask;
+ HandleBroadcastCallback callback;
+ void *callback_user_data;
+ };
+
+ typedef std::multimap<Broadcaster*, BroadcasterInfo> broadcaster_collection;
+ typedef std::list<lldb::EventSP> event_collection;
+ typedef std::vector<BroadcasterManager *> broadcaster_manager_collection;
+
+ bool
+ FindNextEventInternal (Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *sources, // NULL for any event
+ uint32_t num_sources,
+ uint32_t event_type_mask,
+ lldb::EventSP &event_sp,
+ bool remove);
+
+ bool
+ GetNextEventInternal (Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *sources, // NULL for any event
+ uint32_t num_sources,
+ uint32_t event_type_mask,
+ lldb::EventSP &event_sp);
+
+ bool
+ WaitForEventsInternal (const TimeValue *timeout,
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *sources, // NULL for any event
+ uint32_t num_sources,
+ uint32_t event_type_mask,
+ lldb::EventSP &event_sp);
+
+ std::string m_name;
+ broadcaster_collection m_broadcasters;
+ Mutex m_broadcasters_mutex; // Protects m_broadcasters
+ event_collection m_events;
+ Mutex m_events_mutex; // Protects m_broadcasters and m_events
+ Predicate<bool> m_cond_wait;
+ broadcaster_manager_collection m_broadcaster_managers;
+
+ void
+ BroadcasterWillDestruct (Broadcaster *);
+
+ void
+ BroadcasterManagerWillDestruct (BroadcasterManager *manager);
+
+
+// broadcaster_collection::iterator
+// FindBroadcasterWithMask (Broadcaster *broadcaster,
+// uint32_t event_mask,
+// bool exact);
+
+ //------------------------------------------------------------------
+ // For Listener only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (Listener);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Select_h_
diff --git a/include/lldb/Core/Log.h b/include/lldb/Core/Log.h
new file mode 100644
index 000000000000..ced6f2565d9a
--- /dev/null
+++ b/include/lldb/Core/Log.h
@@ -0,0 +1,236 @@
+//===-- Log.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_Log_h_
+#define liblldb_Log_h_
+
+// C Includes
+#include <stdbool.h>
+#include <stdint.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/PluginInterface.h"
+
+//----------------------------------------------------------------------
+// Logging types
+//----------------------------------------------------------------------
+#define LLDB_LOG_FLAG_STDOUT (1u << 0)
+#define LLDB_LOG_FLAG_STDERR (1u << 1)
+#define LLDB_LOG_FLAG_FATAL (1u << 2)
+#define LLDB_LOG_FLAG_ERROR (1u << 3)
+#define LLDB_LOG_FLAG_WARNING (1u << 4)
+#define LLDB_LOG_FLAG_DEBUG (1u << 5)
+#define LLDB_LOG_FLAG_VERBOSE (1u << 6)
+
+//----------------------------------------------------------------------
+// Logging Options
+//----------------------------------------------------------------------
+#define LLDB_LOG_OPTION_THREADSAFE (1u << 0)
+#define LLDB_LOG_OPTION_VERBOSE (1u << 1)
+#define LLDB_LOG_OPTION_DEBUG (1u << 2)
+#define LLDB_LOG_OPTION_PREPEND_SEQUENCE (1u << 3)
+#define LLDB_LOG_OPTION_PREPEND_TIMESTAMP (1u << 4)
+#define LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD (1u << 5)
+#define LLDB_LOG_OPTION_PREPEND_THREAD_NAME (1U << 6)
+#define LLDB_LOG_OPTION_BACKTRACE (1U << 7)
+
+//----------------------------------------------------------------------
+// Logging Functions
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class Log
+{
+public:
+
+ //------------------------------------------------------------------
+ // Callback definitions for abstracted plug-in log access.
+ //------------------------------------------------------------------
+ typedef void (*DisableCallback) (const char **categories, Stream *feedback_strm);
+ typedef Log * (*EnableCallback) (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char **categories,
+ Stream *feedback_strm);
+ typedef void (*ListCategoriesCallback) (Stream *strm);
+
+ struct Callbacks
+ {
+ DisableCallback disable;
+ EnableCallback enable;
+ ListCategoriesCallback list_categories;
+ };
+
+ //------------------------------------------------------------------
+ // Static accessors for logging channels
+ //------------------------------------------------------------------
+ static void
+ RegisterLogChannel (const ConstString &channel,
+ const Log::Callbacks &log_callbacks);
+
+ static bool
+ UnregisterLogChannel (const ConstString &channel);
+
+ static bool
+ GetLogChannelCallbacks (const ConstString &channel,
+ Log::Callbacks &log_callbacks);
+
+
+ static void
+ EnableAllLogChannels (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char **categories,
+ Stream *feedback_strm);
+
+ static void
+ DisableAllLogChannels (Stream *feedback_strm);
+
+ static void
+ ListAllLogChannels (Stream *strm);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------------
+ // Auto completion
+ //------------------------------------------------------------------
+ static void
+ AutoCompleteChannelName (const char *channel_name,
+ StringList &matches);
+
+ //------------------------------------------------------------------
+ // Member functions
+ //------------------------------------------------------------------
+ Log ();
+
+ Log (const lldb::StreamSP &stream_sp);
+
+ ~Log ();
+
+ void
+ PutCString (const char *cstr);
+
+ void
+ Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ VAPrintf (const char *format, va_list args);
+
+ void
+ PrintfWithFlags( uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ void
+ LogIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+
+ void
+ Debug (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ DebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ Error (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ FatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
+
+ void
+ Verbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ Warning (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ WarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ Flags &
+ GetOptions();
+
+ const Flags &
+ GetOptions() const;
+
+ Flags &
+ GetMask();
+
+ const Flags &
+ GetMask() const;
+
+ bool
+ GetVerbose() const;
+
+ bool
+ GetDebug() const;
+
+ void
+ SetStream (const lldb::StreamSP &stream_sp)
+ {
+ m_stream_sp = stream_sp;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::StreamSP m_stream_sp;
+ Flags m_options;
+ Flags m_mask_bits;
+
+ void
+ PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (Log);
+};
+
+
+class LogChannel : public PluginInterface
+{
+public:
+ LogChannel ();
+
+ virtual
+ ~LogChannel ();
+
+ static lldb::LogChannelSP
+ FindPlugin (const char *plugin_name);
+
+ // categories is a an array of chars that ends with a NULL element.
+ virtual void
+ Disable (const char **categories, Stream *feedback_strm) = 0;
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories) = 0;// The categories to enable within this logging stream, if empty, enable default set
+
+ virtual void
+ ListCategories (Stream *strm) = 0;
+
+protected:
+ std::unique_ptr<Log> m_log_ap;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (LogChannel);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Log_H_
diff --git a/include/lldb/Core/Mangled.h b/include/lldb/Core/Mangled.h
new file mode 100644
index 000000000000..8732dc00270c
--- /dev/null
+++ b/include/lldb/Core/Mangled.h
@@ -0,0 +1,306 @@
+//===-- Mangled.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_Mangled_h_
+#define liblldb_Mangled_h_
+#if defined(__cplusplus)
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include <vector>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Mangled Mangled.h "lldb/Core/Mangled.h"
+/// @brief A class that handles mangled names.
+///
+/// Designed to handle mangled names. The demangled version of any names
+/// will be computed when the demangled name is accessed through the
+/// Demangled() acccessor. This class can also tokenize the demangled
+/// version of the name for powerful searches. Functions and symbols
+/// could make instances of this class for their mangled names. Uniqued
+/// string pools are used for the mangled, demangled, and token string
+/// values to allow for faster comparisons and for efficient memory use.
+//----------------------------------------------------------------------
+class Mangled
+{
+public:
+
+ enum NamePreference
+ {
+ ePreferMangled,
+ ePreferDemangled
+ };
+
+ //----------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize with both mangled and demangled names empty.
+ //----------------------------------------------------------------------
+ Mangled ();
+
+ //----------------------------------------------------------------------
+ /// Construct with name.
+ ///
+ /// Constructor with an optional string and a boolean indicating if it is
+ /// the mangled version.
+ ///
+ /// @param[in] name
+ /// The already const name to copy into this object.
+ ///
+ /// @param[in] is_mangled
+ /// If \b true then \a name is a mangled name, if \b false then
+ /// \a name is demangled.
+ //----------------------------------------------------------------------
+ explicit
+ Mangled (const ConstString &name, bool is_mangled);
+
+ //----------------------------------------------------------------------
+ /// Construct with name.
+ ///
+ /// Constructor with an optional string and auto-detect if \a name is
+ /// mangled or not.
+ ///
+ /// @param[in] name
+ /// The already const name to copy into this object.
+ //----------------------------------------------------------------------
+ explicit
+ Mangled (const ConstString &name);
+
+ //----------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// Releases its ref counts on the mangled and demangled strings that
+ /// live in the global string pool.
+ //----------------------------------------------------------------------
+ ~Mangled ();
+
+ //----------------------------------------------------------------------
+ /// Convert to pointer operator.
+ ///
+ /// This allows code to check a Mangled object to see if it contains
+ /// a valid mangled name using code such as:
+ ///
+ /// @code
+ /// Mangled mangled(...);
+ /// if (mangled)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// A pointer to this object if either the mangled or unmangled
+ /// name is set, NULL otherwise.
+ //----------------------------------------------------------------------
+ operator
+ void*() const;
+
+ //----------------------------------------------------------------------
+ /// Logical NOT operator.
+ ///
+ /// This allows code to check a Mangled object to see if it contains
+ /// an empty mangled name using code such as:
+ ///
+ /// @code
+ /// Mangled mangled(...);
+ /// if (!mangled)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// Returns \b true if the object has an empty mangled and
+ /// unmangled name, \b false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ operator!() const;
+
+ //----------------------------------------------------------------------
+ /// Clear the mangled and demangled values.
+ //----------------------------------------------------------------------
+ void
+ Clear ();
+
+ //----------------------------------------------------------------------
+ /// Compare the mangled string values
+ ///
+ /// Compares the Mangled::GetName() string in \a lhs and \a rhs.
+ ///
+ /// @param[in] lhs
+ /// A const reference to the Left Hand Side object to compare.
+ ///
+ /// @param[in] rhs
+ /// A const reference to the Right Hand Side object to compare.
+ ///
+ /// @return
+ /// @li -1 if \a lhs is less than \a rhs
+ /// @li 0 if \a lhs is equal to \a rhs
+ /// @li 1 if \a lhs is greater than \a rhs
+ //----------------------------------------------------------------------
+ static int
+ Compare (const Mangled& lhs, const Mangled& rhs);
+
+ //----------------------------------------------------------------------
+ /// Dump a description of this object to a Stream \a s.
+ ///
+ /// Dump a Mangled object to stream \a s. We don't force our
+ /// demangled name to be computed currently (we don't use the accessor).
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //----------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //----------------------------------------------------------------------
+ /// Dump a debug description of this object to a Stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //----------------------------------------------------------------------
+ void
+ DumpDebug (Stream *s) const;
+
+ //----------------------------------------------------------------------
+ /// Demangled name get accessor.
+ ///
+ /// @return
+ /// A const reference to the demangled name string object.
+ //----------------------------------------------------------------------
+ const ConstString&
+ GetDemangledName () const;
+
+ void
+ SetDemangledName (const ConstString &name)
+ {
+ m_demangled = name;
+ }
+
+ void
+ SetMangledName (const ConstString &name)
+ {
+ m_mangled = name;
+ }
+
+ //----------------------------------------------------------------------
+ /// Mangled name get accessor.
+ ///
+ /// @return
+ /// A reference to the mangled name string object.
+ //----------------------------------------------------------------------
+ ConstString&
+ GetMangledName ()
+ {
+ return m_mangled;
+ }
+
+ //----------------------------------------------------------------------
+ /// Mangled name get accessor.
+ ///
+ /// @return
+ /// A const reference to the mangled name string object.
+ //----------------------------------------------------------------------
+ const ConstString&
+ GetMangledName () const
+ {
+ return m_mangled;
+ }
+
+ //----------------------------------------------------------------------
+ /// Best name get accessor.
+ ///
+ /// @param[in] preference
+ /// Which name would you prefer to get?
+ ///
+ /// @return
+ /// A const reference to the the preferred name string object if this
+ /// object has a valid name of that kind, else a const reference to the
+ /// other name is returned.
+ //----------------------------------------------------------------------
+ const ConstString&
+ GetName (NamePreference preference = ePreferDemangled) const;
+
+ //----------------------------------------------------------------------
+ /// Check if "name" matches either the mangled or demangled name.
+ ///
+ /// @param[in] name
+ /// A name to match against both strings.
+ ///
+ /// @return
+ /// \b True if \a name matches either name, \b false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ NameMatches (const ConstString &name) const
+ {
+ if (m_mangled == name)
+ return true;
+ return GetDemangledName () == name;
+ }
+
+ bool
+ NameMatches (const RegularExpression& regex) const;
+
+ //----------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Return the size in bytes that this object takes in memory. This
+ /// returns the size in bytes of this object, not any shared string
+ /// values it may refer to.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //----------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //----------------------------------------------------------------------
+ /// Set the string value in this object.
+ ///
+ /// If \a is_mangled is \b true, then the mangled named is set to \a
+ /// name, else the demangled name is set to \a name.
+ ///
+ /// @param[in] name
+ /// The already const version of the name for this object.
+ ///
+ /// @param[in] is_mangled
+ /// If \b true then \a name is a mangled name, if \b false then
+ /// \a name is demangled.
+ //----------------------------------------------------------------------
+ void
+ SetValue (const ConstString &name, bool is_mangled);
+
+ //----------------------------------------------------------------------
+ /// Set the string value in this object.
+ ///
+ /// This version auto detects if the string is mangled by inspecting the
+ /// string value and looking for common mangling prefixes.
+ ///
+ /// @param[in] name
+ /// The already const version of the name for this object.
+ //----------------------------------------------------------------------
+ void
+ SetValue (const ConstString &name);
+
+private:
+ //----------------------------------------------------------------------
+ /// Mangled member variables.
+ //----------------------------------------------------------------------
+ ConstString m_mangled; ///< The mangled version of the name
+ mutable ConstString m_demangled; ///< Mutable so we can get it on demand with a const version of this object
+};
+
+
+Stream& operator << (Stream& s, const Mangled& obj);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Mangled_h_
diff --git a/include/lldb/Core/MappedHash.h b/include/lldb/Core/MappedHash.h
new file mode 100644
index 000000000000..80d249d4cc9e
--- /dev/null
+++ b/include/lldb/Core/MappedHash.h
@@ -0,0 +1,552 @@
+//
+// MappedHash.h
+//
+
+#ifndef liblldb_MappedHash_h_
+#define liblldb_MappedHash_h_
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <map>
+#include <vector>
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+
+class MappedHash
+{
+public:
+
+ enum HashFunctionType
+ {
+ eHashFunctionDJB = 0u // Daniel J Bernstein hash function that is also used by the ELF GNU_HASH sections
+ };
+
+
+ static uint32_t
+ HashStringUsingDJB (const char *s)
+ {
+ uint32_t h = 5381;
+
+ for (unsigned char c = *s; c; c = *++s)
+ h = ((h << 5) + h) + c;
+
+ return h;
+ }
+
+ static uint32_t
+ HashString (uint32_t hash_function, const char *s)
+ {
+ switch (hash_function)
+ {
+ case MappedHash::eHashFunctionDJB:
+ return HashStringUsingDJB (s);
+
+ default:
+ break;
+ }
+ assert (!"Invalid hash function index");
+ return 0;
+ }
+
+
+ static const uint32_t HASH_MAGIC = 0x48415348u;
+ static const uint32_t HASH_CIGAM = 0x48534148u;
+
+ template <typename T>
+ struct Header
+ {
+ typedef T HeaderData;
+
+ uint32_t magic; // HASH_MAGIC or HASH_CIGAM magic value to allow endian detection
+ uint16_t version; // Version number
+ uint16_t hash_function; // The hash function enumeration that was used
+ uint32_t bucket_count; // The number of buckets in this hash table
+ uint32_t hashes_count; // The total number of unique hash values and hash data offsets in this table
+ uint32_t header_data_len; // The size in bytes of the "header_data" template member below
+ HeaderData header_data; //
+
+ Header () :
+ magic (HASH_MAGIC),
+ version (1),
+ hash_function (eHashFunctionDJB),
+ bucket_count (0),
+ hashes_count (0),
+ header_data_len (sizeof(T)),
+ header_data ()
+ {
+ }
+
+ virtual
+ ~Header()
+ {
+ }
+
+ size_t
+ GetByteSize() const
+ {
+ return sizeof(magic) +
+ sizeof(version) +
+ sizeof(hash_function) +
+ sizeof(bucket_count) +
+ sizeof(hashes_count) +
+ sizeof(header_data_len) +
+ header_data_len;
+ }
+
+ virtual size_t
+ GetByteSize (const HeaderData &header_data) = 0;
+
+ void
+ SetHeaderDataByteSize (uint32_t header_data_byte_size)
+ {
+ header_data_len = header_data_byte_size;
+ }
+
+ void
+ Dump (lldb_private::Stream &s)
+ {
+ s.Printf ("header.magic = 0x%8.8x\n", magic);
+ s.Printf ("header.version = 0x%4.4x\n", version);
+ s.Printf ("header.hash_function = 0x%4.4x\n", hash_function);
+ s.Printf ("header.bucket_count = 0x%8.8x %u\n", bucket_count, bucket_count);
+ s.Printf ("header.hashes_count = 0x%8.8x %u\n", hashes_count, hashes_count);
+ s.Printf ("header.header_data_len = 0x%8.8x %u\n", header_data_len, header_data_len);
+ }
+
+ virtual lldb::offset_t
+ Read (lldb_private::DataExtractor &data, lldb::offset_t offset)
+ {
+ if (data.ValidOffsetForDataOfSize (offset,
+ sizeof (magic) +
+ sizeof (version) +
+ sizeof (hash_function) +
+ sizeof (bucket_count) +
+ sizeof (hashes_count) +
+ sizeof (header_data_len)))
+ {
+ magic = data.GetU32 (&offset);
+ if (magic != HASH_MAGIC)
+ {
+ if (magic == HASH_CIGAM)
+ {
+ switch (data.GetByteOrder())
+ {
+ case lldb::eByteOrderBig:
+ data.SetByteOrder(lldb::eByteOrderLittle);
+ break;
+ case lldb::eByteOrderLittle:
+ data.SetByteOrder(lldb::eByteOrderBig);
+ break;
+ default:
+ return LLDB_INVALID_OFFSET;
+ }
+ }
+ else
+ {
+ // Magic bytes didn't match
+ version = 0;
+ return LLDB_INVALID_OFFSET;
+ }
+ }
+
+ version = data.GetU16 (&offset);
+ if (version != 1)
+ {
+ // Unsupported version
+ return LLDB_INVALID_OFFSET;
+ }
+ hash_function = data.GetU16 (&offset);
+ if (hash_function == 4)
+ hash_function = 0; // Deal with pre-release version of this table...
+ bucket_count = data.GetU32 (&offset);
+ hashes_count = data.GetU32 (&offset);
+ header_data_len = data.GetU32 (&offset);
+ return offset;
+ }
+ return LLDB_INVALID_OFFSET;
+ }
+//
+// // Returns a buffer that contains a serialized version of this table
+// // that must be freed with free().
+// virtual void *
+// Write (int fd);
+ };
+
+ template <typename __KeyType, class __HeaderDataType, class __ValueType>
+ class ExportTable
+ {
+ public:
+ typedef __HeaderDataType HeaderDataType;
+ typedef Header<HeaderDataType> HeaderType;
+ typedef __KeyType KeyType;
+ typedef __ValueType ValueType;
+
+ struct Entry
+ {
+ uint32_t hash;
+ KeyType key;
+ ValueType value;
+ };
+
+ typedef std::vector<ValueType> ValueArrayType;
+
+ typedef std::map<KeyType, ValueArrayType> HashData;
+ // Map a name hash to one or more name infos
+ typedef std::map<uint32_t, HashData> HashToHashData;
+
+ virtual KeyType
+ GetKeyForStringType (const char *cstr) const = 0;
+
+ virtual size_t
+ GetByteSize (const HashData &key_to_key_values) = 0;
+
+ virtual bool
+ WriteHashData (const HashData &hash_data,
+ lldb_private::Stream &ostrm) = 0;
+//
+ void
+ AddEntry (const char *cstr, const ValueType &value)
+ {
+ Entry entry;
+ entry.hash = MappedHash::HashString (eHashFunctionDJB, cstr);
+ entry.key = GetKeyForStringType (cstr);
+ entry.value = value;
+ m_entries.push_back (entry);
+ }
+
+ void
+ Save (const HeaderDataType &header_data,
+ lldb_private::Stream &ostrm)
+ {
+ if (m_entries.empty())
+ return;
+
+ const uint32_t num_entries = m_entries.size();
+ uint32_t i = 0;
+
+ HeaderType header;
+
+ header.magic = HASH_MAGIC;
+ header.version = 1;
+ header.hash_function = eHashFunctionDJB;
+ header.bucket_count = 0;
+ header.hashes_count = 0;
+ header.prologue_length = header_data.GetByteSize();
+
+ // We need to figure out the number of unique hashes first before we can
+ // calculate the number of buckets we want to use.
+ typedef std::vector<uint32_t> hash_coll;
+ hash_coll unique_hashes;
+ unique_hashes.resize (num_entries);
+ for (i=0; i<num_entries; ++i)
+ unique_hashes[i] = m_entries[i].hash;
+ std::sort (unique_hashes.begin(), unique_hashes.end());
+ hash_coll::iterator pos = std::unique (unique_hashes.begin(), unique_hashes.end());
+ const size_t num_unique_hashes = std::distance (unique_hashes.begin(), pos);
+
+ if (num_unique_hashes > 1024)
+ header.bucket_count = num_unique_hashes/4;
+ else if (num_unique_hashes > 16)
+ header.bucket_count = num_unique_hashes/2;
+ else
+ header.bucket_count = num_unique_hashes;
+ if (header.bucket_count == 0)
+ header.bucket_count = 1;
+
+
+ std::vector<HashToHashData> hash_buckets;
+ std::vector<uint32_t> hash_indexes (header.bucket_count, 0);
+ std::vector<uint32_t> hash_values;
+ std::vector<uint32_t> hash_offsets;
+ hash_buckets.resize (header.bucket_count);
+ uint32_t bucket_entry_empties = 0;
+ //StreamString hash_file_data(Stream::eBinary, dwarf->GetObjectFile()->GetAddressByteSize(), dwarf->GetObjectFile()->GetByteSize());
+
+ // Push all of the hashes into their buckets and create all bucket
+ // entries all populated with data.
+ for (i=0; i<num_entries; ++i)
+ {
+ const uint32_t hash = m_entries[i].hash;
+ const uint32_t bucket_idx = hash % header.bucket_count;
+ const uint32_t strp_offset = m_entries[i].str_offset;
+ const uint32_t die_offset = m_entries[i].die_offset;
+ hash_buckets[bucket_idx][hash][strp_offset].push_back(die_offset);
+ }
+
+ // Now for each bucket we write the bucket value which is the
+ // number of hashes and the hash index encoded into a single
+ // 32 bit unsigned integer.
+ for (i=0; i<header.bucket_count; ++i)
+ {
+ HashToHashData &bucket_entry = hash_buckets[i];
+
+ if (bucket_entry.empty())
+ {
+ // Empty bucket
+ ++bucket_entry_empties;
+ hash_indexes[i] = UINT32_MAX;
+ }
+ else
+ {
+ const uint32_t hash_value_index = hash_values.size();
+ uint32_t hash_count = 0;
+ typename HashToHashData::const_iterator pos, end = bucket_entry.end();
+ for (pos = bucket_entry.begin(); pos != end; ++pos)
+ {
+ hash_values.push_back (pos->first);
+ hash_offsets.push_back (GetByteSize (pos->second));
+ ++hash_count;
+ }
+
+ hash_indexes[i] = hash_value_index;
+ }
+ }
+ header.hashes_count = hash_values.size();
+
+ // Write the header out now that we have the hash_count
+ header.Write (ostrm);
+
+ // Now for each bucket we write the start index of the hashes
+ // for the current bucket, or UINT32_MAX if the bucket is empty
+ for (i=0; i<header.bucket_count; ++i)
+ {
+ ostrm.PutHex32(hash_indexes[i]);
+ }
+
+ // Now we need to write out all of the hash values
+ for (i=0; i<header.hashes_count; ++i)
+ {
+ ostrm.PutHex32(hash_values[i]);
+ }
+
+ // Now we need to write out all of the hash data offsets,
+ // there is an offset for each hash in the hashes array
+ // that was written out above
+ for (i=0; i<header.hashes_count; ++i)
+ {
+ ostrm.PutHex32(hash_offsets[i]);
+ }
+
+ // Now we write the data for each hash and verify we got the offset
+ // correct above...
+ for (i=0; i<header.bucket_count; ++i)
+ {
+ HashToHashData &bucket_entry = hash_buckets[i];
+
+ typename HashToHashData::const_iterator pos, end = bucket_entry.end();
+ for (pos = bucket_entry.begin(); pos != end; ++pos)
+ {
+ if (!bucket_entry.empty())
+ {
+ WriteHashData (pos->second);
+ }
+ }
+ }
+ }
+ protected:
+ typedef std::vector<Entry> collection;
+ collection m_entries;
+ };
+ // A class for reading and using a saved hash table from a block of data
+ // in memory
+ template <typename __KeyType, class __HeaderType, class __HashData>
+ class MemoryTable
+ {
+ public:
+ typedef __HeaderType HeaderType;
+ typedef __KeyType KeyType;
+ typedef __HashData HashData;
+
+ enum Result
+ {
+ eResultKeyMatch = 0u, // The entry was found, key matched and "pair" was filled in successfully
+ eResultKeyMismatch = 1u, // Bucket hash data collision, but key didn't match
+ eResultEndOfHashData = 2u, // The chain of items for this hash data in this bucket is terminated, search no more
+ eResultError = 3u // Error parsing the hash data, abort
+ };
+
+ struct Pair
+ {
+ KeyType key;
+ HashData value;
+ };
+
+ MemoryTable (lldb_private::DataExtractor &data) :
+ m_header (),
+ m_hash_indexes (NULL),
+ m_hash_values (NULL),
+ m_hash_offsets (NULL)
+ {
+ lldb::offset_t offset = m_header.Read (data, 0);
+ if (offset != LLDB_INVALID_OFFSET && IsValid ())
+ {
+ m_hash_indexes = (uint32_t *)data.GetData (&offset, m_header.bucket_count * sizeof(uint32_t));
+ m_hash_values = (uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t));
+ m_hash_offsets = (uint32_t *)data.GetData (&offset, m_header.hashes_count * sizeof(uint32_t));
+ }
+ }
+
+ virtual
+ ~MemoryTable ()
+ {
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_header.version == 1 &&
+ m_header.hash_function == eHashFunctionDJB &&
+ m_header.bucket_count > 0 &&
+ m_header.hashes_count > 0;
+ }
+
+ uint32_t
+ GetHashIndex (uint32_t bucket_idx) const
+ {
+ if (m_hash_indexes && bucket_idx < m_header.bucket_count)
+ return m_hash_indexes[bucket_idx];
+ return UINT32_MAX;
+ }
+
+ uint32_t
+ GetHashValue (uint32_t hash_idx) const
+ {
+ if (m_hash_values && hash_idx < m_header.hashes_count)
+ return m_hash_values[hash_idx];
+ return UINT32_MAX;
+ }
+
+ uint32_t
+ GetHashDataOffset (uint32_t hash_idx) const
+ {
+ if (m_hash_offsets && hash_idx < m_header.hashes_count)
+ return m_hash_offsets[hash_idx];
+ return UINT32_MAX;
+ }
+
+ bool
+ Find (const char *name, Pair &pair) const
+ {
+ if (IsValid ())
+ {
+ const uint32_t bucket_count = m_header.bucket_count;
+ const uint32_t hash_count = m_header.hashes_count;
+ const uint32_t hash_value = MappedHash::HashString (m_header.hash_function, name);
+ const uint32_t bucket_idx = hash_value % bucket_count;
+ uint32_t hash_idx = GetHashIndex (bucket_idx);
+ if (hash_idx < hash_count)
+ {
+ for (; hash_idx < hash_count; ++hash_idx)
+ {
+ const uint32_t curr_hash_value = GetHashValue (hash_idx);
+ if (curr_hash_value == hash_value)
+ {
+ lldb::offset_t hash_data_offset = GetHashDataOffset (hash_idx);
+ while (hash_data_offset != UINT32_MAX)
+ {
+ const lldb::offset_t prev_hash_data_offset = hash_data_offset;
+ Result hash_result = GetHashDataForName (name, &hash_data_offset, pair);
+ // Check the result of getting our hash data
+ switch (hash_result)
+ {
+ case eResultKeyMatch:
+ return true;
+
+ case eResultKeyMismatch:
+ if (prev_hash_data_offset == hash_data_offset)
+ return false;
+ break;
+
+ case eResultEndOfHashData:
+ // The last HashData for this key has been reached, stop searching
+ return false;
+ case eResultError:
+ // Error parsing the hash data, abort
+ return false;
+ }
+ }
+ }
+ if ((curr_hash_value % bucket_count) != bucket_idx)
+ break;
+ }
+ }
+ }
+ return false;
+ }
+
+ // This method must be implemented in any subclasses.
+ // The KeyType is user specified and must somehow result in a string
+ // value. For example, the KeyType might be a string offset in a string
+ // table and subclasses can store their string table as a member of the
+ // subclass and return a valie "const char *" given a "key". The value
+ // could also be a C string pointer, in which case just returning "key"
+ // will suffice.
+
+ virtual const char *
+ GetStringForKeyType (KeyType key) const = 0;
+
+ virtual bool
+ ReadHashData (uint32_t hash_data_offset,
+ HashData &hash_data) const = 0;
+
+ // This method must be implemented in any subclasses and it must try to
+ // read one "Pair" at the offset pointed to by the "hash_data_offset_ptr"
+ // parameter. This offset should be updated as bytes are consumed and
+ // a value "Result" enum should be returned. If the "name" matches the
+ // full name for the "pair.key" (which must be filled in by this call),
+ // then the HashData in the pair ("pair.value") should be extracted and
+ // filled in and "eResultKeyMatch" should be returned. If "name" doesn't
+ // match this string for the key, then "eResultKeyMismatch" should be
+ // returned and all data for the current HashData must be consumed or
+ // skipped and the "hash_data_offset_ptr" offset needs to be updated to
+ // point to the next HashData. If the end of the HashData objects for
+ // a given hash value have been reached, then "eResultEndOfHashData"
+ // should be returned. If anything else goes wrong during parsing,
+ // return "eResultError" and the corresponding "Find()" function will
+ // be canceled and return false.
+
+ virtual Result
+ GetHashDataForName (const char *name,
+ lldb::offset_t* hash_data_offset_ptr,
+ Pair &pair) const = 0;
+
+ const HeaderType &
+ GetHeader()
+ {
+ return m_header;
+ }
+
+
+ void
+ ForEach (std::function <bool(const HashData &hash_data)> const &callback) const
+ {
+ const size_t num_hash_offsets = m_header.hashes_count;
+ for (size_t i=0; i<num_hash_offsets; ++i)
+ {
+ uint32_t hash_data_offset = GetHashDataOffset (i);
+ if (hash_data_offset != UINT32_MAX)
+ {
+ HashData hash_data;
+ if (ReadHashData (hash_data_offset, hash_data))
+ {
+ // If the callback returns false, then we are done and should stop
+ if (callback(hash_data) == false)
+ return;
+ }
+ }
+ }
+ }
+
+ protected:
+ // Implementation agnostic information
+ HeaderType m_header;
+ uint32_t *m_hash_indexes;
+ uint32_t *m_hash_values;
+ uint32_t *m_hash_offsets;
+ };
+
+};
+
+#endif // #ifndef liblldb_MappedHash_h_
diff --git a/include/lldb/Core/Module.h b/include/lldb/Core/Module.h
new file mode 100644
index 000000000000..9c135529f453
--- /dev/null
+++ b/include/lldb/Core/Module.h
@@ -0,0 +1,1085 @@
+//===-- Module.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_Module_h_
+#define liblldb_Module_h_
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Target/PathMappingList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Module Module.h "lldb/Core/Module.h"
+/// @brief A class that describes an executable image and its associated
+/// object and symbol files.
+///
+/// The module is designed to be able to select a single slice of an
+/// executable image as it would appear on disk and during program
+/// execution.
+///
+/// Modules control when and if information is parsed according to which
+/// accessors are called. For example the object file (ObjectFile)
+/// representation will only be parsed if the object file is requested
+/// using the Module::GetObjectFile() is called. The debug symbols
+/// will only be parsed if the symbol vendor (SymbolVendor) is
+/// requested using the Module::GetSymbolVendor() is called.
+///
+/// The module will parse more detailed information as more queries are
+/// made.
+//----------------------------------------------------------------------
+class Module :
+ public std::enable_shared_from_this<Module>,
+ public SymbolContextScope
+{
+public:
+ // Static functions that can track the lifetime of module objects.
+ // This is handy because we might have Module objects that are in
+ // shared pointers that aren't in the global module list (from
+ // ModuleList). If this is the case we need to know about it.
+ // The modules in the global list maintained by these functions
+ // can be viewed using the "target modules list" command using the
+ // "--global" (-g for short).
+ static size_t
+ GetNumberAllocatedModules ();
+
+ static Module *
+ GetAllocatedModuleAtIndex (size_t idx);
+
+ static Mutex *
+ GetAllocationModuleCollectionMutex();
+
+ //------------------------------------------------------------------
+ /// Construct with file specification and architecture.
+ ///
+ /// Clients that wish to share modules with other targets should
+ /// use ModuleList::GetSharedModule().
+ ///
+ /// @param[in] file_spec
+ /// The file specification for the on disk repesentation of
+ /// this executable image.
+ ///
+ /// @param[in] arch
+ /// The architecture to set as the current architecture in
+ /// this module.
+ ///
+ /// @param[in] object_name
+ /// The name of an object in a module used to extract a module
+ /// within a module (.a files and modules that contain multiple
+ /// architectures).
+ ///
+ /// @param[in] object_offset
+ /// The offset within an existing module used to extract a
+ /// module within a module (.a files and modules that contain
+ /// multiple architectures).
+ //------------------------------------------------------------------
+ Module (const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const ConstString *object_name = NULL,
+ off_t object_offset = 0,
+ const TimeValue *object_mod_time_ptr = NULL);
+
+ Module (const ModuleSpec &module_spec);
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ virtual
+ ~Module ();
+
+ bool
+ MatchesModuleSpec (const ModuleSpec &module_ref);
+
+ //------------------------------------------------------------------
+ /// Set the load address for all sections in a module to be the
+ /// file address plus \a slide.
+ ///
+ /// Many times a module will be loaded in a target with a constant
+ /// offset applied to all top level sections. This function can
+ /// set the load address for all top level sections to be the
+ /// section file address + offset.
+ ///
+ /// @param[in] target
+ /// The target in which to apply the section load addresses.
+ ///
+ /// @param[in] offset
+ /// The offset to apply to all file addresses for all top
+ /// level sections in the object file as each section load
+ /// address is being set.
+ ///
+ /// @param[out] changed
+ /// If any section load addresses were changed in \a target,
+ /// then \a changed will be set to \b true. Else \a changed
+ /// will be set to false. This allows this function to be
+ /// called multiple times on the same module for the same
+ /// target. If the module hasn't moved, then \a changed will
+ /// be false and no module updated notification will need to
+ /// be sent out.
+ ///
+ /// @return
+ /// /b True if any sections were successfully loaded in \a target,
+ /// /b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetLoadAddress (Target &target,
+ lldb::addr_t offset,
+ bool &changed);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext (SymbolContext* sc);
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ();
+
+ void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level = lldb::eDescriptionLevelFull);
+
+ //------------------------------------------------------------------
+ /// Get the module path and object name.
+ ///
+ /// Modules can refer to object files. In this case the specification
+ /// is simple and would return the path to the file:
+ ///
+ /// "/usr/lib/foo.dylib"
+ ///
+ /// Modules can be .o files inside of a BSD archive (.a file). In
+ /// this case, the object specification will look like:
+ ///
+ /// "/usr/lib/foo.a(bar.o)"
+ ///
+ /// There are many places where logging wants to log this fully
+ /// qualified specification, so we centralize this functionality
+ /// here.
+ ///
+ /// @return
+ /// The object path + object name if there is one.
+ //------------------------------------------------------------------
+ std::string
+ GetSpecificationDescription () const;
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s. The dumped content will be only what has
+ /// been loaded or parsed up to this point at which this function
+ /// is called, so this is a good way to see what has been parsed
+ /// in a module.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext (Stream *s);
+
+
+ //------------------------------------------------------------------
+ /// Find a symbol in the object file's symbol table.
+ ///
+ /// @param[in] name
+ /// The name of the symbol that we are looking for.
+ ///
+ /// @param[in] symbol_type
+ /// If set to eSymbolTypeAny, find a symbol of any type that
+ /// has a name that matches \a name. If set to any other valid
+ /// SymbolType enumeration value, then search only for
+ /// symbols that match \a symbol_type.
+ ///
+ /// @return
+ /// Returns a valid symbol pointer if a symbol was found,
+ /// NULL otherwise.
+ //------------------------------------------------------------------
+ const Symbol *
+ FindFirstSymbolWithNameAndType (const ConstString &name,
+ lldb::SymbolType symbol_type = lldb::eSymbolTypeAny);
+
+ size_t
+ FindSymbolsWithNameAndType (const ConstString &name,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list);
+
+ size_t
+ FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list);
+
+ //------------------------------------------------------------------
+ /// Find a funciton symbols in the object file's symbol table.
+ ///
+ /// @param[in] name
+ /// The name of the symbol that we are looking for.
+ ///
+ /// @param[in] name_type_mask
+ /// A mask that has one or more bitwise OR'ed values from the
+ /// lldb::FunctionNameType enumeration type that indicate what
+ /// kind of names we are looking for.
+ ///
+ /// @param[out] sc_list
+ /// A list to append any matching symbol contexts to.
+ ///
+ /// @return
+ /// The number of symbol contexts that were added to \a sc_list
+ //------------------------------------------------------------------
+ size_t
+ FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Find compile units by partial or full path.
+ ///
+ /// Finds all compile units that match \a path in all of the modules
+ /// and returns the results in \a sc_list.
+ ///
+ /// @param[in] path
+ /// The name of the function we are looking for.
+ ///
+ /// @param[in] append
+ /// If \b true, then append any compile units that were found
+ /// to \a sc_list. If \b false, then the \a sc_list is cleared
+ /// and the contents of \a sc_list are replaced.
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets filled in with all of the
+ /// matches.
+ ///
+ /// @return
+ /// The number of matches added to \a sc_list.
+ //------------------------------------------------------------------
+ size_t
+ FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list);
+
+
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// If the function is an inlined function, it will have a block,
+ /// representing the inlined function, and the function will be the
+ /// containing function. If it is not inlined, then the block will
+ /// be NULL.
+ ///
+ /// @param[in] name
+ /// The name of the compile unit we are looking for.
+ ///
+ /// @param[in] namespace_decl
+ /// If valid, a namespace to search in.
+ ///
+ /// @param[in] name_type_mask
+ /// A bit mask of bits that indicate what kind of names should
+ /// be used when doing the lookup. Bits include fully qualified
+ /// names, base names, C++ methods, or ObjC selectors.
+ /// See FunctionNameType for more details.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a sc_list, else
+ /// matches replace the contents of \a sc_list.
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets filled in with all of the
+ /// matches.
+ ///
+ /// @return
+ /// The number of matches added to \a sc_list.
+ //------------------------------------------------------------------
+ size_t
+ FindFunctions (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool symbols_ok,
+ bool inlines_ok,
+ bool append,
+ SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Find functions by name.
+ ///
+ /// If the function is an inlined function, it will have a block,
+ /// representing the inlined function, and the function will be the
+ /// containing function. If it is not inlined, then the block will
+ /// be NULL.
+ ///
+ /// @param[in] regex
+ /// A regular expression to use when matching the name.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a sc_list, else
+ /// matches replace the contents of \a sc_list.
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets filled in with all of the
+ /// matches.
+ ///
+ /// @return
+ /// The number of matches added to \a sc_list.
+ //------------------------------------------------------------------
+ size_t
+ FindFunctions (const RegularExpression& regex,
+ bool symbols_ok,
+ bool inlines_ok,
+ bool append,
+ SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by name.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @param[in] namespace_decl
+ /// If valid, a namespace to search in.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a
+ /// variable_list, else matches replace the contents of
+ /// \a variable_list.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a
+ /// max_matches. Specify UINT32_MAX to get all possible matches.
+ ///
+ /// @param[in] variable_list
+ /// A list of variables that gets the matches appended to (if
+ /// \a append it \b true), or replace (if \a append is \b false).
+ ///
+ /// @return
+ /// The number of matches added to \a variable_list.
+ //------------------------------------------------------------------
+ size_t
+ FindGlobalVariables (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list);
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by regular exression.
+ ///
+ /// @param[in] regex
+ /// A regular expression to use when matching the name.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a
+ /// variable_list, else matches replace the contents of
+ /// \a variable_list.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a
+ /// max_matches. Specify UINT32_MAX to get all possible matches.
+ ///
+ /// @param[in] variable_list
+ /// A list of variables that gets the matches appended to (if
+ /// \a append it \b true), or replace (if \a append is \b false).
+ ///
+ /// @return
+ /// The number of matches added to \a variable_list.
+ //------------------------------------------------------------------
+ size_t
+ FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list);
+
+ //------------------------------------------------------------------
+ /// Find types by name.
+ ///
+ /// Type lookups in modules go through the SymbolVendor (which will
+ /// use one or more SymbolFile subclasses). The SymbolFile needs to
+ /// be able to lookup types by basename and not the fully qualified
+ /// typename. This allows the type accelerator tables to stay small,
+ /// even with heavily templatized C++. The type search will then
+ /// narrow down the search results. If "exact_match" is true, then
+ /// the type search will only match exact type name matches. If
+ /// "exact_match" is false, the type will match as long as the base
+ /// typename matches and as long as any immediate containing
+ /// namespaces/class scopes that are specified match. So to search
+ /// for a type "d" in "b::c", the name "b::c::d" can be specified
+ /// and it will match any class/namespace "b" which contains a
+ /// class/namespace "c" which contains type "d". We do this to
+ /// allow users to not always have to specify complete scoping on
+ /// all expressions, but it also allows for exact matching when
+ /// required.
+ ///
+ /// @param[in] sc
+ /// A symbol context that scopes where to extract a type list
+ /// from.
+ ///
+ /// @param[in] type_name
+ /// The name of the type we are looking for that is a fully
+ /// or partially qualfieid type name.
+ ///
+ /// @param[in] exact_match
+ /// If \b true, \a type_name is fully qualifed and must match
+ /// exactly. If \b false, \a type_name is a partially qualfied
+ /// name where the leading namespaces or classes can be
+ /// omitted to make finding types that a user may type
+ /// easier.
+ ///
+ /// @param[out] type_list
+ /// A type list gets populated with any matches.
+ ///
+ /// @return
+ /// The number of matches added to \a type_list.
+ //------------------------------------------------------------------
+ size_t
+ FindTypes (const SymbolContext& sc,
+ const ConstString &type_name,
+ bool exact_match,
+ size_t max_matches,
+ TypeList& types);
+
+ lldb::TypeSP
+ FindFirstType (const SymbolContext& sc,
+ const ConstString &type_name,
+ bool exact_match);
+
+ //------------------------------------------------------------------
+ /// Find types by name that are in a namespace. This function is
+ /// used by the expression parser when searches need to happen in
+ /// an exact namespace scope.
+ ///
+ /// @param[in] sc
+ /// A symbol context that scopes where to extract a type list
+ /// from.
+ ///
+ /// @param[in] type_name
+ /// The name of a type within a namespace that should not include
+ /// any qualifying namespaces (just a type basename).
+ ///
+ /// @param[in] namespace_decl
+ /// The namespace declaration that this type must exist in.
+ ///
+ /// @param[out] type_list
+ /// A type list gets populated with any matches.
+ ///
+ /// @return
+ /// The number of matches added to \a type_list.
+ //------------------------------------------------------------------
+ size_t
+ FindTypesInNamespace (const SymbolContext& sc,
+ const ConstString &type_name,
+ const ClangNamespaceDecl *namespace_decl,
+ size_t max_matches,
+ TypeList& type_list);
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module architecture.
+ ///
+ /// @return
+ /// A const reference to the architecture object.
+ //------------------------------------------------------------------
+ const ArchSpec&
+ GetArchitecture () const;
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module file specification.
+ ///
+ /// This function returns the file for the module on the host system
+ /// that is running LLDB. This can differ from the path on the
+ /// platform since we might be doing remote debugging.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ const FileSpec &
+ GetFileSpec () const
+ {
+ return m_file;
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the module platform file specification.
+ ///
+ /// Platform file refers to the path of the module as it is known on
+ /// the remote system on which it is being debugged. For local
+ /// debugging this is always the same as Module::GetFileSpec(). But
+ /// remote debugging might mention a file "/usr/lib/liba.dylib"
+ /// which might be locally downloaded and cached. In this case the
+ /// platform file could be something like:
+ /// "/tmp/lldb/platform-cache/remote.host.computer/usr/lib/liba.dylib"
+ /// The file could also be cached in a local developer kit directory.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ const FileSpec &
+ GetPlatformFileSpec () const
+ {
+ if (m_platform_file)
+ return m_platform_file;
+ return m_file;
+ }
+
+ void
+ SetPlatformFileSpec (const FileSpec &file)
+ {
+ m_platform_file = file;
+ }
+
+ const FileSpec &
+ GetSymbolFileFileSpec () const
+ {
+ return m_symfile_spec;
+ }
+
+ void
+ SetSymbolFileFileSpec (const FileSpec &file);
+
+ const TimeValue &
+ GetModificationTime () const
+ {
+ return m_mod_time;
+ }
+
+ const TimeValue &
+ GetObjectModificationTime () const
+ {
+ return m_object_mod_time;
+ }
+
+ void
+ SetObjectModificationTime (const TimeValue &mod_time)
+ {
+ m_mod_time = mod_time;
+ }
+
+ //------------------------------------------------------------------
+ /// Tells whether this module is capable of being the main executable
+ /// for a process.
+ ///
+ /// @return
+ /// \b true if it is, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsExecutable ();
+
+ //------------------------------------------------------------------
+ /// Tells whether this module has been loaded in the target passed in.
+ /// This call doesn't distinguish between whether the module is loaded
+ /// by the dynamic loader, or by a "target module add" type call.
+ ///
+ /// @param[in] target
+ /// The target to check whether this is loaded in.
+ ///
+ /// @return
+ /// \b true if it is, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsLoadedInTarget (Target *target);
+
+ bool
+ LoadScriptingResourceInTarget (Target *target,
+ Error& error,
+ Stream* feedback_stream = NULL);
+
+ //------------------------------------------------------------------
+ /// Get the number of compile units for this module.
+ ///
+ /// @return
+ /// The number of compile units that the symbol vendor plug-in
+ /// finds.
+ //------------------------------------------------------------------
+ size_t
+ GetNumCompileUnits();
+
+ lldb::CompUnitSP
+ GetCompileUnitAtIndex (size_t idx);
+
+ const ConstString &
+ GetObjectName() const;
+
+ uint64_t
+ GetObjectOffset() const
+ {
+ return m_object_offset;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the object file representation for the current architecture.
+ ///
+ /// If the object file has not been located or parsed yet, this
+ /// function will find the best ObjectFile plug-in that can parse
+ /// Module::m_file.
+ ///
+ /// @return
+ /// If Module::m_file does not exist, or no plug-in was found
+ /// that can parse the file, or the object file doesn't contain
+ /// the current architecture in Module::m_arch, NULL will be
+ /// returned, else a valid object file interface will be
+ /// returned. The returned pointer is owned by this object and
+ /// remains valid as long as the object is around.
+ //------------------------------------------------------------------
+ virtual ObjectFile *
+ GetObjectFile ();
+
+ //------------------------------------------------------------------
+ /// Get the unified section list for the module. This is the section
+ /// list created by the module's object file and any debug info and
+ /// symbol files created by the symbol vendor.
+ ///
+ /// If the symbol vendor has not been loaded yet, this function
+ /// will return the section list for the object file.
+ ///
+ /// @return
+ /// Unified module section list.
+ //------------------------------------------------------------------
+ virtual SectionList *
+ GetSectionList ();
+
+ uint32_t
+ GetVersion (uint32_t *versions, uint32_t num_versions);
+
+ // Load an object file from memory.
+ ObjectFile *
+ GetMemoryObjectFile (const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr,
+ Error &error);
+ //------------------------------------------------------------------
+ /// Get the symbol vendor interface for the current architecture.
+ ///
+ /// If the symbol vendor file has not been located yet, this
+ /// function will find the best SymbolVendor plug-in that can
+ /// use the current object file.
+ ///
+ /// @return
+ /// If this module does not have a valid object file, or no
+ /// plug-in can be found that can use the object file, NULL will
+ /// be returned, else a valid symbol vendor plug-in interface
+ /// will be returned. The returned pointer is owned by this
+ /// object and remains valid as long as the object is around.
+ //------------------------------------------------------------------
+ virtual SymbolVendor*
+ GetSymbolVendor(bool can_create = true,
+ lldb_private::Stream *feedback_strm = NULL);
+
+ //------------------------------------------------------------------
+ /// Get accessor the type list for this module.
+ ///
+ /// @return
+ /// A valid type list pointer, or NULL if there is no valid
+ /// symbol vendor for this module.
+ //------------------------------------------------------------------
+ TypeList*
+ GetTypeList ();
+
+ //------------------------------------------------------------------
+ /// Get a pointer to the UUID value contained in this object.
+ ///
+ /// If the executable image file doesn't not have a UUID value built
+ /// into the file format, an MD5 checksum of the entire file, or
+ /// slice of the file for the current architecture should be used.
+ ///
+ /// @return
+ /// A const pointer to the internal copy of the UUID value in
+ /// this module if this module has a valid UUID value, NULL
+ /// otherwise.
+ //------------------------------------------------------------------
+ const lldb_private::UUID &
+ GetUUID ();
+
+ //------------------------------------------------------------------
+ /// A debugging function that will cause everything in a module to
+ /// be parsed.
+ ///
+ /// All compile units will be pasred, along with all globals and
+ /// static variables and all functions for those compile units.
+ /// All types, scopes, local variables, static variables, global
+ /// variables, and line tables will be parsed. This can be used
+ /// prior to dumping a module to see a complete list of the
+ /// resuling debug information that gets parsed, or as a debug
+ /// function to ensure that the module can consume all of the
+ /// debug data the symbol vendor provides.
+ //------------------------------------------------------------------
+ void
+ ParseAllDebugSymbols();
+
+ bool
+ ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr);
+
+ uint32_t
+ ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc);
+
+ //------------------------------------------------------------------
+ /// Resolve items in the symbol context for a given file and line.
+ ///
+ /// Tries to resolve \a file_path and \a line to a list of matching
+ /// symbol contexts.
+ ///
+ /// The line table entries contains addresses that can be used to
+ /// further resolve the values in each match: the function, block,
+ /// symbol. Care should be taken to minimize the amount of
+ /// information that is requested to only what is needed --
+ /// typically the module, compile unit, line table and line table
+ /// entry are sufficient.
+ ///
+ /// @param[in] file_path
+ /// A path to a source file to match. If \a file_path does not
+ /// specify a directory, then this query will match all files
+ /// whose base filename matches. If \a file_path does specify
+ /// a directory, the fullpath to the file must match.
+ ///
+ /// @param[in] line
+ /// The source line to match, or zero if just the compile unit
+ /// should be resolved.
+ ///
+ /// @param[in] check_inlines
+ /// Check for inline file and line number matches. This option
+ /// should be used sparingly as it will cause all line tables
+ /// for every compile unit to be parsed and searched for
+ /// matching inline file entries.
+ ///
+ /// @param[in] resolve_scope
+ /// The scope that should be resolved (see
+ /// SymbolContext::Scope).
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets matching symbols contexts
+ /// appended to.
+ ///
+ /// @return
+ /// The number of matches that were added to \a sc_list.
+ ///
+ /// @see SymbolContext::Scope
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextForFilePath (const char *file_path, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Resolve items in the symbol context for a given file and line.
+ ///
+ /// Tries to resolve \a file_spec and \a line to a list of matching
+ /// symbol contexts.
+ ///
+ /// The line table entries contains addresses that can be used to
+ /// further resolve the values in each match: the function, block,
+ /// symbol. Care should be taken to minimize the amount of
+ /// information that is requested to only what is needed --
+ /// typically the module, compile unit, line table and line table
+ /// entry are sufficient.
+ ///
+ /// @param[in] file_spec
+ /// A file spec to a source file to match. If \a file_path does
+ /// not specify a directory, then this query will match all
+ /// files whose base filename matches. If \a file_path does
+ /// specify a directory, the fullpath to the file must match.
+ ///
+ /// @param[in] line
+ /// The source line to match, or zero if just the compile unit
+ /// should be resolved.
+ ///
+ /// @param[in] check_inlines
+ /// Check for inline file and line number matches. This option
+ /// should be used sparingly as it will cause all line tables
+ /// for every compile unit to be parsed and searched for
+ /// matching inline file entries.
+ ///
+ /// @param[in] resolve_scope
+ /// The scope that should be resolved (see
+ /// SymbolContext::Scope).
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets filled in with all of the
+ /// matches.
+ ///
+ /// @return
+ /// A integer that contains SymbolContext::Scope bits set for
+ /// each item that was successfully resolved.
+ ///
+ /// @see SymbolContext::Scope
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list);
+
+
+ void
+ SetFileSpecAndObjectName (const FileSpec &file,
+ const ConstString &object_name);
+
+ bool
+ GetIsDynamicLinkEditor () const
+ {
+ return m_is_dynamic_loader_module;
+ }
+
+ void
+ SetIsDynamicLinkEditor (bool b)
+ {
+ m_is_dynamic_loader_module = b;
+ }
+
+ ClangASTContext &
+ GetClangASTContext ();
+
+ // Special error functions that can do printf style formatting that will prepend the message with
+ // something appropriate for this module (like the architecture, path and object name (if any)).
+ // This centralizes code so that everyone doesn't need to format their error and log messages on
+ // their own and keeps the output a bit more consistent.
+ void
+ LogMessage (Log *log, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ void
+ LogMessageVerboseBacktrace (Log *log, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ void
+ ReportWarning (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ ReportError (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ // Only report an error once when the module is first detected to be modified
+ // so we don't spam the console with many messages.
+ void
+ ReportErrorIfModifyDetected (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ //------------------------------------------------------------------
+ // Return true if the file backing this module has changed since the
+ // module was originally created since we saved the intial file
+ // modification time when the module first gets created.
+ //------------------------------------------------------------------
+ bool
+ FileHasChanged () const;
+
+ //------------------------------------------------------------------
+ // SymbolVendor, SymbolFile and ObjectFile member objects should
+ // lock the module mutex to avoid deadlocks.
+ //------------------------------------------------------------------
+ Mutex &
+ GetMutex () const
+ {
+ return m_mutex;
+ }
+
+ PathMappingList &
+ GetSourceMappingList ()
+ {
+ return m_source_mappings;
+ }
+
+ const PathMappingList &
+ GetSourceMappingList () const
+ {
+ return m_source_mappings;
+ }
+
+ //------------------------------------------------------------------
+ /// Finds a source file given a file spec using the module source
+ /// path remappings (if any).
+ ///
+ /// Tries to resolve \a orig_spec by checking the module source path
+ /// remappings. It makes sure the file exists, so this call can be
+ /// expensive if the remappings are on a network file system, so
+ /// use this function sparingly (not in a tight debug info parsing
+ /// loop).
+ ///
+ /// @param[in] orig_spec
+ /// The original source file path to try and remap.
+ ///
+ /// @param[out] new_spec
+ /// The newly remapped filespec that is guaranteed to exist.
+ ///
+ /// @return
+ /// /b true if \a orig_spec was successfully located and
+ /// \a new_spec is filled in with an existing file spec,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const;
+
+ //------------------------------------------------------------------
+ /// Remaps a source file given \a path into \a new_path.
+ ///
+ /// Remaps \a path if any source remappings match. This function
+ /// does NOT stat the file system so it can be used in tight loops
+ /// where debug info is being parsed.
+ ///
+ /// @param[in] path
+ /// The original source file path to try and remap.
+ ///
+ /// @param[out] new_path
+ /// The newly remapped filespec that is may or may not exist.
+ ///
+ /// @return
+ /// /b true if \a path was successfully located and \a new_path
+ /// is filled in with a new source path, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ RemapSourceFile (const char *path, std::string &new_path) const;
+
+
+ //------------------------------------------------------------------
+ /// Prepare to do a function name lookup.
+ ///
+ /// Looking up functions by name can be a tricky thing. LLDB requires
+ /// that accelerator tables contain full names for functions as well
+ /// as function basenames which include functions, class methods and
+ /// class functions. When the user requests that an action use a
+ /// function by name, we are sometimes asked to automatically figure
+ /// out what a name could possibly map to. A user might request a
+ /// breakpoint be set on "count". If no options are supplied to limit
+ /// the scope of where to search for count, we will by default match
+ /// any function names named "count", all class and instance methods
+ /// named "count" (no matter what the namespace or contained context)
+ /// and any selectors named "count". If a user specifies "a::b" we
+ /// will search for the basename "b", and then prune the results that
+ /// don't match "a::b" (note that "c::a::b" and "d::e::a::b" will
+ /// match a query of "a::b".
+ ///
+ /// @param[in] name
+ /// The user supplied name to use in the lookup
+ ///
+ /// @param[in] name_type_mask
+ /// The mask of bits from lldb::FunctionNameType enumerations
+ /// that tell us what kind of name we are looking for.
+ ///
+ /// @param[out] lookup_name
+ /// The actual name that will be used when calling
+ /// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols()
+ ///
+ /// @param[out] lookup_name_type_mask
+ /// The actual name mask that should be used in the calls to
+ /// SymbolVendor::FindFunctions() or Symtab::FindFunctionSymbols()
+ ///
+ /// @param[out] match_name_after_lookup
+ /// A boolean that indicates if we need to iterate through any
+ /// match results obtained from SymbolVendor::FindFunctions() or
+ /// Symtab::FindFunctionSymbols() to see if the name contains
+ /// \a name. For example if \a name is "a::b", this function will
+ /// return a \a lookup_name of "b", with \a match_name_after_lookup
+ /// set to true to indicate any matches will need to be checked
+ /// to make sure they contain \a name.
+ //------------------------------------------------------------------
+ static void
+ PrepareForFunctionNameLookup (const ConstString &name,
+ uint32_t name_type_mask,
+ ConstString &lookup_name,
+ uint32_t &lookup_name_type_mask,
+ bool &match_name_after_lookup);
+
+protected:
+ //------------------------------------------------------------------
+ // Member Variables
+ //------------------------------------------------------------------
+ mutable Mutex m_mutex; ///< A mutex to keep this object happy in multi-threaded environments.
+ TimeValue m_mod_time; ///< The modification time for this module when it was created.
+ ArchSpec m_arch; ///< The architecture for this module.
+ lldb_private::UUID m_uuid; ///< Each module is assumed to have a unique identifier to help match it up to debug symbols.
+ FileSpec m_file; ///< The file representation on disk for this module (if there is one).
+ FileSpec m_platform_file;///< The path to the module on the platform on which it is being debugged
+ FileSpec m_symfile_spec; ///< If this path is valid, then this is the file that _will_ be used as the symbol file for this module
+ ConstString m_object_name; ///< The name an object within this module that is selected, or empty of the module is represented by \a m_file.
+ uint64_t m_object_offset;
+ TimeValue m_object_mod_time;
+ lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file parser for this module as it may or may not be shared with the SymbolFile
+ std::unique_ptr<SymbolVendor> m_symfile_ap; ///< A pointer to the symbol vendor for this module.
+ ClangASTContext m_ast; ///< The AST context for this module.
+ PathMappingList m_source_mappings; ///< Module specific source remappings for when you have debug info for a module that doesn't match where the sources currently are
+ std::unique_ptr<lldb_private::SectionList> m_sections_ap; ///< Unified section list for module that is used by the ObjectFile and and ObjectFile instances for the debug info
+
+ bool m_did_load_objfile:1,
+ m_did_load_symbol_vendor:1,
+ m_did_parse_uuid:1,
+ m_did_init_ast:1,
+ m_is_dynamic_loader_module:1;
+ mutable bool m_file_has_changed:1,
+ m_first_file_changed_log:1; /// See if the module was modified after it was initially opened.
+
+ //------------------------------------------------------------------
+ /// Resolve a file or load virtual address.
+ ///
+ /// Tries to resolve \a vm_addr as a file address (if \a
+ /// vm_addr_is_file_addr is true) or as a load address if \a
+ /// vm_addr_is_file_addr is false) in the symbol vendor.
+ /// \a resolve_scope indicates what clients wish to resolve
+ /// and can be used to limit the scope of what is parsed.
+ ///
+ /// @param[in] vm_addr
+ /// The load virtual address to resolve.
+ ///
+ /// @param[in] vm_addr_is_file_addr
+ /// If \b true, \a vm_addr is a file address, else \a vm_addr
+ /// if a load address.
+ ///
+ /// @param[in] resolve_scope
+ /// The scope that should be resolved (see
+ /// SymbolContext::Scope).
+ ///
+ /// @param[out] so_addr
+ /// The section offset based address that got resolved if
+ /// any bits are returned.
+ ///
+ /// @param[out] sc
+ // The symbol context that has objects filled in. Each bit
+ /// in the \a resolve_scope pertains to a member in the \a sc.
+ ///
+ /// @return
+ /// A integer that contains SymbolContext::Scope bits set for
+ /// each item that was successfully resolved.
+ ///
+ /// @see SymbolContext::Scope
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextForAddress (lldb::addr_t vm_addr,
+ bool vm_addr_is_file_addr,
+ uint32_t resolve_scope,
+ Address& so_addr,
+ SymbolContext& sc);
+
+ void
+ SymbolIndicesToSymbolContextList (Symtab *symtab,
+ std::vector<uint32_t> &symbol_indexes,
+ SymbolContextList &sc_list);
+
+ bool
+ SetArchitecture (const ArchSpec &new_arch);
+
+ SectionList *
+ GetUnifiedSectionList();
+
+ friend class ModuleList;
+ friend class ObjectFile;
+ friend class SymbolFile;
+
+private:
+
+ size_t
+ FindTypes_Impl (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ TypeList& types);
+
+
+ DISALLOW_COPY_AND_ASSIGN (Module);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Module_h_
diff --git a/include/lldb/Core/ModuleChild.h b/include/lldb/Core/ModuleChild.h
new file mode 100644
index 000000000000..d2a6fb0c3bc1
--- /dev/null
+++ b/include/lldb/Core/ModuleChild.h
@@ -0,0 +1,90 @@
+//===-- ModuleChild.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_ModuleChild_h_
+#define liblldb_ModuleChild_h_
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ModuleChild ModuleChild.h "lldb/Core/ModuleChild.h"
+/// @brief A mix in class that contains a pointer back to the module
+/// that owns the object which inherits from it.
+//----------------------------------------------------------------------
+class ModuleChild
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with owning module.
+ ///
+ /// @param[in] module
+ /// The module that owns the object that inherits from this
+ /// class.
+ //------------------------------------------------------------------
+ ModuleChild (const lldb::ModuleSP &module_sp);
+
+ //------------------------------------------------------------------
+ /// Copy constructor.
+ ///
+ /// @param[in] rhs
+ /// A const ModuleChild class reference to copy.
+ //------------------------------------------------------------------
+ ModuleChild (const ModuleChild& rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~ModuleChild();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// @param[in] rhs
+ /// A const ModuleChild class reference to copy.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const ModuleChild&
+ operator= (const ModuleChild& rhs);
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the module pointer.
+ ///
+ /// @return
+ /// A const pointer to the module that owns the object that
+ /// inherits from this class.
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetModule () const;
+
+ //------------------------------------------------------------------
+ /// Set accessor for the module pointer.
+ ///
+ /// @param[in] module
+ /// A new module that owns the object that inherits from this
+ /// class.
+ //------------------------------------------------------------------
+ void
+ SetModule (const lldb::ModuleSP &module_sp);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::ModuleWP m_module_wp; ///< The Module that owns the object that inherits
+ ///< from this class.
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_ModuleChild_h_
diff --git a/include/lldb/Core/ModuleList.h b/include/lldb/Core/ModuleList.h
new file mode 100644
index 000000000000..1198e4196481
--- /dev/null
+++ b/include/lldb/Core/ModuleList.h
@@ -0,0 +1,556 @@
+//===-- ModuleList.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_ModuleList_h_
+#define liblldb_ModuleList_h_
+
+#include <vector>
+#include <list>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ModuleList ModuleList.h "lldb/Core/ModuleList.h"
+/// @brief A collection class for Module objects.
+///
+/// Modules in the module collection class are stored as reference
+/// counted shared pointers to Module objects.
+//----------------------------------------------------------------------
+class ModuleList
+{
+public:
+
+ class Notifier
+ {
+ public:
+ virtual void
+ ModuleAdded (const ModuleList& module_list, const lldb::ModuleSP& module_sp) = 0;
+ virtual void
+ ModuleRemoved (const ModuleList& module_list, const lldb::ModuleSP& module_sp) = 0;
+ virtual void
+ ModuleUpdated (const ModuleList& module_list, const lldb::ModuleSP& old_module_sp,
+ const lldb::ModuleSP& new_module_sp) = 0;
+ virtual void
+ WillClearList (const ModuleList& module_list) = 0;
+
+ virtual
+ ~Notifier ()
+ {}
+ };
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Creates an empty list of Module objects.
+ //------------------------------------------------------------------
+ ModuleList ();
+
+ //------------------------------------------------------------------
+ /// Copy Constructor.
+ ///
+ /// Creates a new module list object with a copy of the modules from
+ /// \a rhs.
+ ///
+ /// @param[in] rhs
+ /// Another module list object.
+ //------------------------------------------------------------------
+ ModuleList (const ModuleList& rhs);
+
+ ModuleList (ModuleList::Notifier* notifier);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~ModuleList ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Copies the module list from \a rhs into this list.
+ ///
+ /// @param[in] rhs
+ /// Another module list object.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const ModuleList&
+ operator= (const ModuleList& rhs);
+
+ //------------------------------------------------------------------
+ /// Append a module to the module list.
+ ///
+ /// Appends the module to the collection.
+ ///
+ /// @param[in] module_sp
+ /// A shared pointer to a module to add to this collection.
+ //------------------------------------------------------------------
+ void
+ Append (const lldb::ModuleSP &module_sp);
+
+ //------------------------------------------------------------------
+ /// Append a module to the module list and remove any equivalent
+ /// modules. Equivalent modules are ones whose file, platform file
+ /// and architecture matches.
+ ///
+ /// Replaces the module to the collection.
+ ///
+ /// @param[in] module_sp
+ /// A shared pointer to a module to replace in this collection.
+ //------------------------------------------------------------------
+ void
+ ReplaceEquivalent (const lldb::ModuleSP &module_sp);
+
+ bool
+ AppendIfNeeded (const lldb::ModuleSP &module_sp);
+
+ void
+ Append (const ModuleList& module_list);
+
+ bool
+ AppendIfNeeded (const ModuleList& module_list);
+
+ bool
+ ReplaceModule (const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp);
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Clears the list of modules and releases a reference to each
+ /// module object and if the reference count goes to zero, the
+ /// module will be deleted.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Clears the list of modules and releases a reference to each
+ /// module object and if the reference count goes to zero, the
+ /// module will be deleted. Also relese all memory that might be
+ /// held by any collection classes (like std::vector)
+ //------------------------------------------------------------------
+ void
+ Destroy();
+ //------------------------------------------------------------------
+ /// Dump the description of each module contained in this list.
+ ///
+ /// Dump the description of each module contained in this list to
+ /// the supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @see Module::Dump(Stream *) const
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ void
+ LogUUIDAndPaths (Log *log, const char *prefix_cstr);
+
+ Mutex &
+ GetMutex () const
+ {
+ return m_modules_mutex;
+ }
+
+ size_t
+ GetIndexForModule (const Module *module) const;
+
+ //------------------------------------------------------------------
+ /// Get the module shared pointer for the module at index \a idx.
+ ///
+ /// @param[in] idx
+ /// An index into this module collection.
+ ///
+ /// @return
+ /// A shared pointer to a Module which can contain NULL if
+ /// \a idx is out of range.
+ ///
+ /// @see ModuleList::GetSize()
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetModuleAtIndex (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Get the module shared pointer for the module at index \a idx without
+ /// acquiring the ModuleList mutex. This MUST already have been
+ /// acquired with ModuleList::GetMutex and locked for this call to be safe.
+ ///
+ /// @param[in] idx
+ /// An index into this module collection.
+ ///
+ /// @return
+ /// A shared pointer to a Module which can contain NULL if
+ /// \a idx is out of range.
+ ///
+ /// @see ModuleList::GetSize()
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetModuleAtIndexUnlocked (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Get the module pointer for the module at index \a idx.
+ ///
+ /// @param[in] idx
+ /// An index into this module collection.
+ ///
+ /// @return
+ /// A pointer to a Module which can by NULL if \a idx is out
+ /// of range.
+ ///
+ /// @see ModuleList::GetSize()
+ //------------------------------------------------------------------
+ Module*
+ GetModulePointerAtIndex (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Get the module pointer for the module at index \a idx without
+ /// acquiring the ModuleList mutex. This MUST already have been
+ /// acquired with ModuleList::GetMutex and locked for this call to be safe.
+ ///
+ /// @param[in] idx
+ /// An index into this module collection.
+ ///
+ /// @return
+ /// A pointer to a Module which can by NULL if \a idx is out
+ /// of range.
+ ///
+ /// @see ModuleList::GetSize()
+ //------------------------------------------------------------------
+ Module*
+ GetModulePointerAtIndexUnlocked (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Find compile units by partial or full path.
+ ///
+ /// Finds all compile units that match \a path in all of the modules
+ /// and returns the results in \a sc_list.
+ ///
+ /// @param[in] path
+ /// The name of the compile unit we are looking for.
+ ///
+ /// @param[in] append
+ /// If \b true, then append any compile units that were found
+ /// to \a sc_list. If \b false, then the \a sc_list is cleared
+ /// and the contents of \a sc_list are replaced.
+ ///
+ /// @param[out] sc_list
+ /// A symbol context list that gets filled in with all of the
+ /// matches.
+ ///
+ /// @return
+ /// The number of matches added to \a sc_list.
+ //------------------------------------------------------------------
+ size_t
+ FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list) const;
+
+ //------------------------------------------------------------------
+ /// @see Module::FindFunctions ()
+ //------------------------------------------------------------------
+ size_t
+ FindFunctions (const ConstString &name,
+ uint32_t name_type_mask,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList &sc_list) const;
+
+ //------------------------------------------------------------------
+ /// @see Module::FindFunctionSymbols ()
+ //------------------------------------------------------------------
+ size_t
+ FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list);
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by name.
+ ///
+ /// @param[in] name
+ /// The name of the global or static variable we are looking
+ /// for.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a
+ /// variable_list, else matches replace the contents of
+ /// \a variable_list.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a
+ /// max_matches. Specify UINT32_MAX to get all possible matches.
+ ///
+ /// @param[in] variable_list
+ /// A list of variables that gets the matches appended to (if
+ /// \a append it \b true), or replace (if \a append is \b false).
+ ///
+ /// @return
+ /// The number of matches added to \a variable_list.
+ //------------------------------------------------------------------
+ size_t
+ FindGlobalVariables (const ConstString &name,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const;
+
+ //------------------------------------------------------------------
+ /// Find global and static variables by regular exression.
+ ///
+ /// @param[in] regex
+ /// A regular expression to use when matching the name.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a
+ /// variable_list, else matches replace the contents of
+ /// \a variable_list.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a
+ /// max_matches. Specify UINT32_MAX to get all possible matches.
+ ///
+ /// @param[in] variable_list
+ /// A list of variables that gets the matches appended to (if
+ /// \a append it \b true), or replace (if \a append is \b false).
+ ///
+ /// @return
+ /// The number of matches added to \a variable_list.
+ //------------------------------------------------------------------
+ size_t
+ FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const;
+
+ //------------------------------------------------------------------
+ /// Finds the first module whose file specification matches \a
+ /// file_spec.
+ ///
+ /// @param[in] file_spec_ptr
+ /// A file specification object to match against the Module's
+ /// file specifications. If \a file_spec does not have
+ /// directory information, matches will occur by matching only
+ /// the basename of any modules in this list. If this value is
+ /// NULL, then file specifications won't be compared when
+ /// searching for matching modules.
+ ///
+ /// @param[in] arch_ptr
+ /// The architecture to search for if non-NULL. If this value
+ /// is NULL no architecture matching will be performed.
+ ///
+ /// @param[in] uuid_ptr
+ /// The uuid to search for if non-NULL. If this value is NULL
+ /// no uuid matching will be performed.
+ ///
+ /// @param[in] object_name
+ /// An optional object name that must match as well. This value
+ /// can be NULL.
+ ///
+ /// @param[out] matching_module_list
+ /// A module list that gets filled in with any modules that
+ /// match the search criteria.
+ ///
+ /// @return
+ /// The number of matching modules found by the search.
+ //------------------------------------------------------------------
+ size_t
+ FindModules (const ModuleSpec &module_spec,
+ ModuleList& matching_module_list) const;
+
+ lldb::ModuleSP
+ FindModule (const Module *module_ptr) const;
+
+ //------------------------------------------------------------------
+ // Find a module by UUID
+ //
+ // The UUID value for a module is extracted from the ObjectFile and
+ // is the MD5 checksum, or a smarter object file equivalent, so
+ // finding modules by UUID values is very efficient and accurate.
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ FindModule (const UUID &uuid) const;
+
+ lldb::ModuleSP
+ FindFirstModule (const ModuleSpec &module_spec) const;
+
+ size_t
+ FindSymbolsWithNameAndType (const ConstString &name,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append = false) const;
+
+ size_t
+ FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append = false) const;
+
+ //------------------------------------------------------------------
+ /// Find types by name.
+ ///
+ /// @param[in] sc
+ /// A symbol context that scopes where to extract a type list
+ /// from.
+ ///
+ /// @param[in] name
+ /// The name of the type we are looking for.
+ ///
+ /// @param[in] append
+ /// If \b true, any matches will be appended to \a
+ /// variable_list, else matches replace the contents of
+ /// \a variable_list.
+ ///
+ /// @param[in] max_matches
+ /// Allow the number of matches to be limited to \a
+ /// max_matches. Specify UINT32_MAX to get all possible matches.
+ ///
+ /// @param[in] encoding
+ /// Limit the search to specific types, or get all types if
+ /// set to Type::invalid.
+ ///
+ /// @param[in] udt_name
+ /// If the encoding is a user defined type, specify the name
+ /// of the user defined type ("struct", "union", "class", etc).
+ ///
+ /// @param[out] type_list
+ /// A type list gets populated with any matches.
+ ///
+ /// @return
+ /// The number of matches added to \a type_list.
+ //------------------------------------------------------------------
+ size_t
+ FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ bool name_is_fully_qualified,
+ size_t max_matches,
+ TypeList& types) const;
+
+ bool
+ FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const;
+
+ bool
+ Remove (const lldb::ModuleSP &module_sp);
+
+ size_t
+ Remove (ModuleList &module_list);
+
+ bool
+ RemoveIfOrphaned (const Module *module_ptr);
+
+ size_t
+ RemoveOrphans (bool mandatory);
+
+ bool
+ ResolveFileAddress (lldb::addr_t vm_addr,
+ Address& so_addr) const;
+
+ //------------------------------------------------------------------
+ /// @copydoc Module::ResolveSymbolContextForAddress (const Address &,uint32_t,SymbolContext&)
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextForAddress (const Address& so_addr,
+ uint32_t resolve_scope,
+ SymbolContext& sc) const;
+
+ //------------------------------------------------------------------
+ /// @copydoc Module::ResolveSymbolContextForFilePath (const char *,uint32_t,bool,uint32_t,SymbolContextList&)
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextForFilePath (const char *file_path,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list) const;
+
+ //------------------------------------------------------------------
+ /// @copydoc Module::ResolveSymbolContextsForFileSpec (const FileSpec &,uint32_t,bool,uint32_t,SymbolContextList&)
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContextsForFileSpec (const FileSpec &file_spec,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list) const;
+
+ //------------------------------------------------------------------
+ /// Gets the size of the module list.
+ ///
+ /// @return
+ /// The number of modules in the module list.
+ //------------------------------------------------------------------
+ size_t
+ GetSize () const;
+
+ bool
+ LoadScriptingResourcesInTarget (Target *target,
+ std::list<Error>& errors,
+ Stream* feedback_stream = NULL,
+ bool continue_on_error = true);
+
+ static bool
+ ModuleIsInCache (const Module *module_ptr);
+
+ static Error
+ GetSharedModule (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr,
+ bool always_create = false);
+
+ static bool
+ RemoveSharedModule (lldb::ModuleSP &module_sp);
+
+ static size_t
+ FindSharedModules (const ModuleSpec &module_spec,
+ ModuleList &matching_module_list);
+
+ static size_t
+ RemoveOrphanSharedModules (bool mandatory);
+
+ static bool
+ RemoveSharedModuleIfOrphaned (const Module *module_ptr);
+
+protected:
+ //------------------------------------------------------------------
+ // Class typedefs.
+ //------------------------------------------------------------------
+ typedef std::vector<lldb::ModuleSP> collection; ///< The module collection type.
+
+ void
+ AppendImpl (const lldb::ModuleSP &module_sp, bool use_notifier = true);
+
+ bool
+ RemoveImpl (const lldb::ModuleSP &module_sp, bool use_notifier = true);
+
+ collection::iterator
+ RemoveImpl (collection::iterator pos, bool use_notifier = true);
+
+ void
+ ClearImpl (bool use_notifier = true);
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ collection m_modules; ///< The collection of modules.
+ mutable Mutex m_modules_mutex;
+
+ Notifier* m_notifier;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ModuleList_h_
diff --git a/include/lldb/Core/ModuleSpec.h b/include/lldb/Core/ModuleSpec.h
new file mode 100644
index 000000000000..10e1ea9f17a9
--- /dev/null
+++ b/include/lldb/Core/ModuleSpec.h
@@ -0,0 +1,594 @@
+//===-- ModuleSpec.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_ModuleSpec_h_
+#define liblldb_ModuleSpec_h_
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Target/PathMappingList.h"
+
+namespace lldb_private {
+
+class ModuleSpec
+{
+public:
+ ModuleSpec () :
+ m_file (),
+ m_platform_file (),
+ m_symbol_file (),
+ m_arch (),
+ m_uuid (),
+ m_object_name (),
+ m_object_offset (0),
+ m_object_mod_time (),
+ m_source_mappings ()
+ {
+ }
+
+ ModuleSpec (const FileSpec &file_spec) :
+ m_file (file_spec),
+ m_platform_file (),
+ m_symbol_file (),
+ m_arch (),
+ m_uuid (),
+ m_object_name (),
+ m_object_offset (0),
+ m_object_mod_time (),
+ m_source_mappings ()
+ {
+ }
+
+ ModuleSpec (const FileSpec &file_spec, const ArchSpec &arch) :
+ m_file (file_spec),
+ m_platform_file (),
+ m_symbol_file (),
+ m_arch (arch),
+ m_uuid (),
+ m_object_name (),
+ m_object_offset (0),
+ m_object_mod_time (),
+ m_source_mappings ()
+ {
+ }
+
+ ModuleSpec (const ModuleSpec &rhs) :
+ m_file (rhs.m_file),
+ m_platform_file (rhs.m_platform_file),
+ m_symbol_file (rhs.m_symbol_file),
+ m_arch (rhs.m_arch),
+ m_uuid (rhs.m_uuid),
+ m_object_name (rhs.m_object_name),
+ m_object_offset (rhs.m_object_offset),
+ m_object_mod_time (rhs.m_object_mod_time),
+ m_source_mappings (rhs.m_source_mappings)
+ {
+ }
+
+ ModuleSpec &
+ operator = (const ModuleSpec &rhs)
+ {
+ if (this != &rhs)
+ {
+ m_file = rhs.m_file;
+ m_platform_file = rhs.m_platform_file;
+ m_symbol_file = rhs.m_symbol_file;
+ m_arch = rhs.m_arch;
+ m_uuid = rhs.m_uuid;
+ m_object_name = rhs.m_object_name;
+ m_object_offset = rhs.m_object_offset;
+ m_object_mod_time = rhs.m_object_mod_time;
+ m_source_mappings = rhs.m_source_mappings;
+ }
+ return *this;
+ }
+
+ FileSpec *
+ GetFileSpecPtr ()
+ {
+ if (m_file)
+ return &m_file;
+ return NULL;
+ }
+
+ const FileSpec *
+ GetFileSpecPtr () const
+ {
+ if (m_file)
+ return &m_file;
+ return NULL;
+ }
+
+ FileSpec &
+ GetFileSpec ()
+ {
+ return m_file;
+ }
+ const FileSpec &
+ GetFileSpec () const
+ {
+ return m_file;
+ }
+
+ FileSpec *
+ GetPlatformFileSpecPtr ()
+ {
+ if (m_platform_file)
+ return &m_platform_file;
+ return NULL;
+ }
+
+ const FileSpec *
+ GetPlatformFileSpecPtr () const
+ {
+ if (m_platform_file)
+ return &m_platform_file;
+ return NULL;
+ }
+
+ FileSpec &
+ GetPlatformFileSpec ()
+ {
+ return m_platform_file;
+ }
+
+ const FileSpec &
+ GetPlatformFileSpec () const
+ {
+ return m_platform_file;
+ }
+
+ FileSpec *
+ GetSymbolFileSpecPtr ()
+ {
+ if (m_symbol_file)
+ return &m_symbol_file;
+ return NULL;
+ }
+
+ const FileSpec *
+ GetSymbolFileSpecPtr () const
+ {
+ if (m_symbol_file)
+ return &m_symbol_file;
+ return NULL;
+ }
+
+ FileSpec &
+ GetSymbolFileSpec ()
+ {
+ return m_symbol_file;
+ }
+
+ const FileSpec &
+ GetSymbolFileSpec () const
+ {
+ return m_symbol_file;
+ }
+
+
+ ArchSpec *
+ GetArchitecturePtr ()
+ {
+ if (m_arch.IsValid())
+ return &m_arch;
+ return NULL;
+ }
+
+ const ArchSpec *
+ GetArchitecturePtr () const
+ {
+ if (m_arch.IsValid())
+ return &m_arch;
+ return NULL;
+ }
+
+ ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ UUID *
+ GetUUIDPtr ()
+ {
+ if (m_uuid.IsValid())
+ return &m_uuid;
+ return NULL;
+ }
+
+ const UUID *
+ GetUUIDPtr () const
+ {
+ if (m_uuid.IsValid())
+ return &m_uuid;
+ return NULL;
+ }
+
+ UUID &
+ GetUUID ()
+ {
+ return m_uuid;
+ }
+
+ const UUID &
+ GetUUID () const
+ {
+ return m_uuid;
+ }
+
+ ConstString &
+ GetObjectName ()
+ {
+ return m_object_name;
+ }
+
+ const ConstString &
+ GetObjectName () const
+ {
+ return m_object_name;
+ }
+
+ uint64_t
+ GetObjectOffset () const
+ {
+ return m_object_offset;
+ }
+
+ void
+ SetObjectOffset (uint64_t object_offset)
+ {
+ m_object_offset = object_offset;
+ }
+
+ TimeValue &
+ GetObjectModificationTime ()
+ {
+ return m_object_mod_time;
+ }
+
+ const TimeValue &
+ GetObjectModificationTime () const
+ {
+ return m_object_mod_time;
+ }
+
+ PathMappingList &
+ GetSourceMappingList () const
+ {
+ return m_source_mappings;
+ }
+
+ void
+ Clear ()
+ {
+ m_file.Clear();
+ m_platform_file.Clear();
+ m_symbol_file.Clear();
+ m_arch.Clear();
+ m_uuid.Clear();
+ m_object_name.Clear();
+ m_object_offset = 0;
+ m_source_mappings.Clear(false);
+ m_object_mod_time.Clear();
+ }
+
+
+ operator bool () const
+ {
+ if (m_file)
+ return true;
+ if (m_platform_file)
+ return true;
+ if (m_symbol_file)
+ return true;
+ if (m_arch.IsValid())
+ return true;
+ if (m_uuid.IsValid())
+ return true;
+ if (m_object_name)
+ return true;
+ if (m_object_mod_time.IsValid())
+ return true;
+ return false;
+ }
+
+ void
+ Dump (Stream &strm)
+ {
+ bool dumped_something = false;
+ if (m_file)
+ {
+ strm.PutCString("file = '");
+ strm << m_file;
+ strm.PutCString("'");
+ dumped_something = true;
+ }
+ if (m_platform_file)
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.PutCString("platform_file = '");
+ strm << m_platform_file;
+ strm.PutCString("'");
+ dumped_something = true;
+ }
+ if (m_symbol_file)
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.PutCString("symbol_file = '");
+ strm << m_symbol_file;
+ strm.PutCString("'");
+ dumped_something = true;
+ }
+ if (m_arch.IsValid())
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.Printf("arch = %s", m_arch.GetTriple().str().c_str());
+ dumped_something = true;
+ }
+ if (m_uuid.IsValid())
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.PutCString("uuid = ");
+ m_uuid.Dump(&strm);
+ dumped_something = true;
+ }
+ if (m_object_name)
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.Printf("object_name = %s", m_object_name.GetCString());
+ dumped_something = true;
+ }
+ if (m_object_offset > 0)
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.Printf("object_offset = 0x%" PRIx64, m_object_offset);
+ dumped_something = true;
+ }
+ if (m_object_mod_time.IsValid())
+ {
+ if (dumped_something)
+ strm.PutCString(", ");
+ strm.Printf("object_mod_time = 0x%" PRIx64, m_object_mod_time.GetAsSecondsSinceJan1_1970());
+ dumped_something = true;
+ }
+ }
+
+ bool
+ Matches (const ModuleSpec &match_module_spec, bool exact_arch_match) const
+ {
+ if (match_module_spec.GetUUIDPtr() && match_module_spec.GetUUID() != GetUUID())
+ return false;
+ if (match_module_spec.GetObjectName() && match_module_spec.GetObjectName() != GetObjectName())
+ return false;
+ if (match_module_spec.GetFileSpecPtr())
+ {
+ const FileSpec &fspec = match_module_spec.GetFileSpec();
+ if (!FileSpec::Equal(fspec, GetFileSpec(), fspec.GetDirectory().IsEmpty() == false))
+ return false;
+ }
+ if (match_module_spec.GetPlatformFileSpecPtr())
+ {
+ const FileSpec &fspec = match_module_spec.GetPlatformFileSpec();
+ if (!FileSpec::Equal(fspec, GetPlatformFileSpec(), fspec.GetDirectory().IsEmpty() == false))
+ return false;
+
+ }
+ if (match_module_spec.GetSymbolFileSpecPtr())
+ {
+ const FileSpec &fspec = match_module_spec.GetSymbolFileSpec();
+ if (!FileSpec::Equal(fspec, GetSymbolFileSpec(), fspec.GetDirectory().IsEmpty() == false))
+ return false;
+
+ }
+ if (match_module_spec.GetArchitecturePtr())
+ {
+ if (exact_arch_match)
+ {
+ if (!GetArchitecture().IsExactMatch(match_module_spec.GetArchitecture()))
+ return false;
+ }
+ else
+ {
+ if (!GetArchitecture().IsCompatibleMatch(match_module_spec.GetArchitecture()))
+ return false;
+ }
+ }
+ return true;
+ }
+
+protected:
+ FileSpec m_file;
+ FileSpec m_platform_file;
+ FileSpec m_symbol_file;
+ ArchSpec m_arch;
+ UUID m_uuid;
+ ConstString m_object_name;
+ uint64_t m_object_offset;
+ TimeValue m_object_mod_time;
+ mutable PathMappingList m_source_mappings;
+};
+
+class ModuleSpecList
+{
+public:
+ ModuleSpecList () :
+ m_specs(),
+ m_mutex(Mutex::eMutexTypeRecursive)
+ {
+ }
+
+ ModuleSpecList (const ModuleSpecList &rhs) :
+ m_specs(),
+ m_mutex(Mutex::eMutexTypeRecursive)
+ {
+ Mutex::Locker lhs_locker(m_mutex);
+ Mutex::Locker rhs_locker(rhs.m_mutex);
+ m_specs = rhs.m_specs;
+ }
+
+ ~ModuleSpecList ()
+ {
+ }
+
+ ModuleSpecList &
+ operator = (const ModuleSpecList &rhs)
+ {
+ if (this != &rhs)
+ {
+ Mutex::Locker lhs_locker(m_mutex);
+ Mutex::Locker rhs_locker(rhs.m_mutex);
+ m_specs = rhs.m_specs;
+ }
+ return *this;
+ }
+
+ size_t
+ GetSize() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_specs.size();
+ }
+
+ void
+ Clear ()
+ {
+ Mutex::Locker locker(m_mutex);
+ m_specs.clear();
+ }
+
+ void
+ Append (const ModuleSpec &spec)
+ {
+ Mutex::Locker locker(m_mutex);
+ m_specs.push_back (spec);
+ }
+
+ void
+ Append (const ModuleSpecList &rhs)
+ {
+ Mutex::Locker lhs_locker(m_mutex);
+ Mutex::Locker rhs_locker(rhs.m_mutex);
+ m_specs.insert(m_specs.end(), rhs.m_specs.begin(), rhs.m_specs.end());
+ }
+
+ // The index "i" must be valid and this can't be used in
+ // multi-threaded code as no mutex lock is taken.
+ ModuleSpec &
+ GetModuleSpecRefAtIndex (size_t i)
+ {
+ return m_specs[i];
+ }
+ bool
+ GetModuleSpecAtIndex (size_t i, ModuleSpec &module_spec) const
+ {
+ Mutex::Locker locker(m_mutex);
+ if (i < m_specs.size())
+ {
+ module_spec = m_specs[i];
+ return true;
+ }
+ module_spec.Clear();
+ return false;
+ }
+
+
+ bool
+ FindMatchingModuleSpec (const ModuleSpec &module_spec, ModuleSpec &match_module_spec) const
+ {
+ Mutex::Locker locker(m_mutex);
+ bool exact_arch_match = true;
+ for (auto spec: m_specs)
+ {
+ if (spec.Matches(module_spec, exact_arch_match))
+ {
+ match_module_spec = spec;
+ return true;
+ }
+ }
+
+ // If there was an architecture, retry with a compatible arch
+ if (module_spec.GetArchitecturePtr())
+ {
+ exact_arch_match = false;
+ for (auto spec: m_specs)
+ {
+ if (spec.Matches(module_spec, exact_arch_match))
+ {
+ match_module_spec = spec;
+ return true;
+ }
+ }
+ }
+ match_module_spec.Clear();
+ return false;
+ }
+
+ size_t
+ FindMatchingModuleSpecs (const ModuleSpec &module_spec, ModuleSpecList &matching_list) const
+ {
+ Mutex::Locker locker(m_mutex);
+ bool exact_arch_match = true;
+ const size_t initial_match_count = matching_list.GetSize();
+ for (auto spec: m_specs)
+ {
+ if (spec.Matches(module_spec, exact_arch_match))
+ matching_list.Append (spec);
+ }
+
+ // If there was an architecture, retry with a compatible arch if no matches were found
+ if (module_spec.GetArchitecturePtr() && (initial_match_count == matching_list.GetSize()))
+ {
+ exact_arch_match = false;
+ for (auto spec: m_specs)
+ {
+ if (spec.Matches(module_spec, exact_arch_match))
+ matching_list.Append (spec);
+ }
+ }
+ return matching_list.GetSize() - initial_match_count;
+ }
+
+ void
+ Dump (Stream &strm)
+ {
+ Mutex::Locker locker(m_mutex);
+ uint32_t idx = 0;
+ for (auto spec: m_specs)
+ {
+ strm.Printf("[%u] ", idx);
+ spec.Dump (strm);
+ strm.EOL();
+ ++idx;
+ }
+ }
+
+protected:
+ typedef std::vector<ModuleSpec> collection; ///< The module collection type.
+ collection m_specs; ///< The collection of modules.
+ mutable Mutex m_mutex;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ModuleSpec_h_
diff --git a/include/lldb/Core/Opcode.h b/include/lldb/Core/Opcode.h
new file mode 100644
index 000000000000..c07193b62059
--- /dev/null
+++ b/include/lldb/Core/Opcode.h
@@ -0,0 +1,270 @@
+//===-- Opcode.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Opcode_h
+#define lldb_Opcode_h
+
+// C Includes
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+
+namespace lldb
+{
+ class SBInstruction;
+}
+
+namespace lldb_private {
+
+ class Opcode
+ {
+ public:
+ enum Type
+ {
+ eTypeInvalid,
+ eType8,
+ eType16,
+ eType16_2, // a 32-bit Thumb instruction, made up of two words
+ eType32,
+ eType64,
+ eTypeBytes
+ };
+
+ Opcode () : m_type (eTypeInvalid)
+ {
+ }
+
+ Opcode (uint8_t inst) : m_type (eType8)
+ {
+ m_data.inst8 = inst;
+ }
+
+ Opcode (uint16_t inst) : m_type (eType16)
+ {
+ m_data.inst16 = inst;
+ }
+
+ Opcode (uint32_t inst) : m_type (eType32)
+ {
+ m_data.inst32 = inst;
+ }
+
+ Opcode (uint64_t inst) : m_type (eType64)
+ {
+ m_data.inst64 = inst;
+ }
+
+ Opcode (uint8_t *bytes, size_t length)
+ {
+ SetOpcodeBytes (bytes, length);
+ }
+
+ void
+ Clear()
+ {
+ m_type = Opcode::eTypeInvalid;
+ }
+ Opcode::Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ uint8_t
+ GetOpcode8 (uint8_t invalid_opcode = UINT8_MAX) const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return m_data.inst8;
+ case Opcode::eType16: break;
+ case Opcode::eType16_2: break;
+ case Opcode::eType32: break;
+ case Opcode::eType64: break;
+ case Opcode::eTypeBytes: break;
+ break;
+ }
+ return invalid_opcode;
+ }
+
+ uint16_t
+ GetOpcode16 (uint16_t invalid_opcode = UINT16_MAX) const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return m_data.inst8;
+ case Opcode::eType16: return m_data.inst16;
+ case Opcode::eType16_2: break;
+ case Opcode::eType32: break;
+ case Opcode::eType64: break;
+ case Opcode::eTypeBytes: break;
+ }
+ return invalid_opcode;
+ }
+
+ uint32_t
+ GetOpcode32 (uint32_t invalid_opcode = UINT32_MAX) const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return m_data.inst8;
+ case Opcode::eType16: return m_data.inst16;
+ case Opcode::eType16_2: // passthrough
+ case Opcode::eType32: return m_data.inst32;
+ case Opcode::eType64: break;
+ case Opcode::eTypeBytes: break;
+ }
+ return invalid_opcode;
+ }
+
+ uint64_t
+ GetOpcode64 (uint64_t invalid_opcode = UINT64_MAX) const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return m_data.inst8;
+ case Opcode::eType16: return m_data.inst16;
+ case Opcode::eType16_2: // passthrough
+ case Opcode::eType32: return m_data.inst32;
+ case Opcode::eType64: return m_data.inst64;
+ case Opcode::eTypeBytes: break;
+ }
+ return invalid_opcode;
+ }
+
+ void
+ SetOpcode8 (uint8_t inst)
+ {
+ m_type = eType8;
+ m_data.inst8 = inst;
+ }
+
+ void
+ SetOpcode16 (uint16_t inst)
+ {
+ m_type = eType16;
+ m_data.inst16 = inst;
+ }
+
+ void
+ SetOpcode16_2 (uint32_t inst)
+ {
+ m_type = eType16_2;
+ m_data.inst32 = inst;
+ }
+
+ void
+ SetOpcode32 (uint32_t inst)
+ {
+ m_type = eType32;
+ m_data.inst32 = inst;
+ }
+
+ void
+ SetOpcode64 (uint64_t inst)
+ {
+ m_type = eType64;
+ m_data.inst64 = inst;
+ }
+
+ void
+ SetOpcodeBytes (const void *bytes, size_t length)
+ {
+ if (bytes && length > 0)
+ {
+ m_type = eTypeBytes;
+ m_data.inst.length = length;
+ assert (length < sizeof (m_data.inst.bytes));
+ memcpy (m_data.inst.bytes, bytes, length);
+ }
+ else
+ {
+ m_type = eTypeInvalid;
+ m_data.inst.length = 0;
+ }
+ }
+
+ int
+ Dump (Stream *s, uint32_t min_byte_width);
+
+ const void *
+ GetOpcodeBytes () const
+ {
+ if (m_type == Opcode::eTypeBytes)
+ return m_data.inst.bytes;
+ return NULL;
+ }
+
+ uint32_t
+ GetByteSize () const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return sizeof(m_data.inst8);
+ case Opcode::eType16: return sizeof(m_data.inst16);
+ case Opcode::eType16_2: // passthrough
+ case Opcode::eType32: return sizeof(m_data.inst32);
+ case Opcode::eType64: return sizeof(m_data.inst64);
+ case Opcode::eTypeBytes: return m_data.inst.length;
+ }
+ return 0;
+ }
+
+ // Get the opcode exactly as it would be laid out in memory.
+ uint32_t
+ GetData (DataExtractor &data) const;
+
+ protected:
+
+ friend class lldb::SBInstruction;
+
+ const void *
+ GetOpcodeDataBytes () const
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8: return &m_data.inst8;
+ case Opcode::eType16: return &m_data.inst16;
+ case Opcode::eType16_2: // passthrough
+ case Opcode::eType32: return &m_data.inst32;
+ case Opcode::eType64: return &m_data.inst64;
+ case Opcode::eTypeBytes: return m_data.inst.bytes;
+ }
+ return NULL;
+ }
+
+ lldb::ByteOrder
+ GetDataByteOrder () const;
+
+ Opcode::Type m_type;
+ union
+ {
+ uint8_t inst8;
+ uint16_t inst16;
+ uint32_t inst32;
+ uint64_t inst64;
+ struct
+ {
+ uint8_t bytes[16]; // This must be big enough to handle any opcode for any supported target.
+ uint8_t length;
+ } inst;
+ } m_data;
+ };
+
+} // namespace lldb_private
+
+#endif // lldb_Opcode_h
diff --git a/include/lldb/Core/PluginInterface.h b/include/lldb/Core/PluginInterface.h
new file mode 100644
index 000000000000..19371ca98601
--- /dev/null
+++ b/include/lldb/Core/PluginInterface.h
@@ -0,0 +1,37 @@
+//===-- PluginInterface.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_PluginInterface_h_
+#define liblldb_PluginInterface_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class PluginInterface
+{
+public:
+ virtual
+ ~PluginInterface () {}
+
+ virtual ConstString
+ GetPluginName() = 0;
+
+ virtual uint32_t
+ GetPluginVersion() = 0;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_PluginInterface_h_
diff --git a/include/lldb/Core/PluginManager.h b/include/lldb/Core/PluginManager.h
new file mode 100644
index 000000000000..91f8fbb997f9
--- /dev/null
+++ b/include/lldb/Core/PluginManager.h
@@ -0,0 +1,352 @@
+//===-- PluginManager.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_PluginManager_h_
+#define liblldb_PluginManager_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private {
+
+class PluginManager
+{
+public:
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ //------------------------------------------------------------------
+ // ABI
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ ABICreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (ABICreateInstance create_callback);
+
+ static ABICreateInstance
+ GetABICreateCallbackAtIndex (uint32_t idx);
+
+ static ABICreateInstance
+ GetABICreateCallbackForPluginName (const ConstString &name);
+
+
+ //------------------------------------------------------------------
+ // Disassembler
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ DisassemblerCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (DisassemblerCreateInstance create_callback);
+
+ static DisassemblerCreateInstance
+ GetDisassemblerCreateCallbackAtIndex (uint32_t idx);
+
+ static DisassemblerCreateInstance
+ GetDisassemblerCreateCallbackForPluginName (const ConstString &name);
+
+
+ //------------------------------------------------------------------
+ // DynamicLoader
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback = NULL);
+
+ static bool
+ UnregisterPlugin (DynamicLoaderCreateInstance create_callback);
+
+ static DynamicLoaderCreateInstance
+ GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx);
+
+ static DynamicLoaderCreateInstance
+ GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
+ // EmulateInstruction
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ EmulateInstructionCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (EmulateInstructionCreateInstance create_callback);
+
+ static EmulateInstructionCreateInstance
+ GetEmulateInstructionCreateCallbackAtIndex (uint32_t idx);
+
+ static EmulateInstructionCreateInstance
+ GetEmulateInstructionCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
+ // OperatingSystem
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ OperatingSystemCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (OperatingSystemCreateInstance create_callback);
+
+ static OperatingSystemCreateInstance
+ GetOperatingSystemCreateCallbackAtIndex (uint32_t idx);
+
+ static OperatingSystemCreateInstance
+ GetOperatingSystemCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
+ // LanguageRuntime
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ LanguageRuntimeCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (LanguageRuntimeCreateInstance create_callback);
+
+ static LanguageRuntimeCreateInstance
+ GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx);
+
+ static LanguageRuntimeCreateInstance
+ GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name);
+
+
+ //------------------------------------------------------------------
+ // ObjectFile
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectFileCreateInstance create_callback,
+ ObjectFileCreateMemoryInstance create_memory_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications);
+
+ static bool
+ UnregisterPlugin (ObjectFileCreateInstance create_callback);
+
+ static ObjectFileCreateInstance
+ GetObjectFileCreateCallbackAtIndex (uint32_t idx);
+
+ static ObjectFileCreateMemoryInstance
+ GetObjectFileCreateMemoryCallbackAtIndex (uint32_t idx);
+
+ static ObjectFileGetModuleSpecifications
+ GetObjectFileGetModuleSpecificationsCallbackAtIndex (uint32_t idx);
+
+ static ObjectFileCreateInstance
+ GetObjectFileCreateCallbackForPluginName (const ConstString &name);
+
+ static ObjectFileCreateMemoryInstance
+ GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name);
+
+
+ //------------------------------------------------------------------
+ // ObjectContainer
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications);
+
+ static bool
+ UnregisterPlugin (ObjectContainerCreateInstance create_callback);
+
+ static ObjectContainerCreateInstance
+ GetObjectContainerCreateCallbackAtIndex (uint32_t idx);
+
+ static ObjectContainerCreateInstance
+ GetObjectContainerCreateCallbackForPluginName (const ConstString &name);
+
+ static ObjectFileGetModuleSpecifications
+ GetObjectContainerGetModuleSpecificationsCallbackAtIndex (uint32_t idx);
+
+ //------------------------------------------------------------------
+ // LogChannel
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ LogChannelCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (LogChannelCreateInstance create_callback);
+
+ static LogChannelCreateInstance
+ GetLogChannelCreateCallbackAtIndex (uint32_t idx);
+
+ static LogChannelCreateInstance
+ GetLogChannelCreateCallbackForPluginName (const ConstString &name);
+
+ static const char *
+ GetLogChannelCreateNameAtIndex (uint32_t idx);
+
+ //------------------------------------------------------------------
+ // Platform
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ PlatformCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback = NULL);
+
+ static bool
+ UnregisterPlugin (PlatformCreateInstance create_callback);
+
+ static PlatformCreateInstance
+ GetPlatformCreateCallbackAtIndex (uint32_t idx);
+
+ static PlatformCreateInstance
+ GetPlatformCreateCallbackForPluginName (const ConstString &name);
+
+ static const char *
+ GetPlatformPluginNameAtIndex (uint32_t idx);
+
+ static const char *
+ GetPlatformPluginDescriptionAtIndex (uint32_t idx);
+
+ static size_t
+ AutoCompletePlatformName (const char *partial_name,
+ StringList &matches);
+ //------------------------------------------------------------------
+ // Process
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ ProcessCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback = NULL);
+
+ static bool
+ UnregisterPlugin (ProcessCreateInstance create_callback);
+
+ static ProcessCreateInstance
+ GetProcessCreateCallbackAtIndex (uint32_t idx);
+
+ static ProcessCreateInstance
+ GetProcessCreateCallbackForPluginName (const ConstString &name);
+
+ static const char *
+ GetProcessPluginNameAtIndex (uint32_t idx);
+
+ static const char *
+ GetProcessPluginDescriptionAtIndex (uint32_t idx);
+
+ //------------------------------------------------------------------
+ // SymbolFile
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ SymbolFileCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (SymbolFileCreateInstance create_callback);
+
+ static SymbolFileCreateInstance
+ GetSymbolFileCreateCallbackAtIndex (uint32_t idx);
+
+ static SymbolFileCreateInstance
+ GetSymbolFileCreateCallbackForPluginName (const ConstString &name);
+
+
+ //------------------------------------------------------------------
+ // SymbolVendor
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (SymbolVendorCreateInstance create_callback);
+
+ static SymbolVendorCreateInstance
+ GetSymbolVendorCreateCallbackAtIndex (uint32_t idx);
+
+ static SymbolVendorCreateInstance
+ GetSymbolVendorCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
+ // UnwindAssembly
+ //------------------------------------------------------------------
+ static bool
+ RegisterPlugin (const ConstString &name,
+ const char *description,
+ UnwindAssemblyCreateInstance create_callback);
+
+ static bool
+ UnregisterPlugin (UnwindAssemblyCreateInstance create_callback);
+
+ static UnwindAssemblyCreateInstance
+ GetUnwindAssemblyCreateCallbackAtIndex (uint32_t idx);
+
+ static UnwindAssemblyCreateInstance
+ GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &name);
+
+ //------------------------------------------------------------------
+ // Some plug-ins might register a DebuggerInitializeCallback
+ // callback when registering the plug-in. After a new Debugger
+ // instance is created, this DebuggerInitialize function will get
+ // called. This allows plug-ins to install Properties and do any
+ // other initialization that requires a debugger instance.
+ //------------------------------------------------------------------
+ static void
+ DebuggerInitialize (Debugger &debugger);
+
+ static lldb::OptionValuePropertiesSP
+ GetSettingForDynamicLoaderPlugin (Debugger &debugger,
+ const ConstString &setting_name);
+
+ static bool
+ CreateSettingForDynamicLoaderPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property);
+
+ static lldb::OptionValuePropertiesSP
+ GetSettingForPlatformPlugin (Debugger &debugger,
+ const ConstString &setting_name);
+
+ static bool
+ CreateSettingForPlatformPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property);
+
+ static lldb::OptionValuePropertiesSP
+ GetSettingForProcessPlugin (Debugger &debugger,
+ const ConstString &setting_name);
+
+ static bool
+ CreateSettingForProcessPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property);
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_PluginManager_h_
diff --git a/include/lldb/Core/RangeMap.h b/include/lldb/Core/RangeMap.h
new file mode 100644
index 000000000000..ee42467c18bf
--- /dev/null
+++ b/include/lldb/Core/RangeMap.h
@@ -0,0 +1,1543 @@
+//===-- RangeMap.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_RangeMap_h_
+#define liblldb_RangeMap_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/SmallVector.h"
+
+// Uncomment to make sure all Range objects are sorted when needed
+//#define ASSERT_RANGEMAP_ARE_SORTED
+
+namespace lldb_private {
+
+
+ //----------------------------------------------------------------------
+ // Templatized classes for dealing with generic ranges and also
+ // collections of ranges, or collections of ranges that have associated
+ // data.
+ //----------------------------------------------------------------------
+
+ //----------------------------------------------------------------------
+ // A simple range class where you get to define the type of the range
+ // base "B", and the type used for the range byte size "S".
+ //----------------------------------------------------------------------
+ template <typename B, typename S>
+ struct Range
+ {
+ typedef B BaseType;
+ typedef S SizeType;
+
+ BaseType base;
+ SizeType size;
+
+ Range () :
+ base (0),
+ size (0)
+ {
+ }
+
+ Range (BaseType b, SizeType s) :
+ base (b),
+ size (s)
+ {
+ }
+
+ void
+ Clear (BaseType b = 0)
+ {
+ base = b;
+ size = 0;
+ }
+
+ // Set the start value for the range, and keep the same size
+ BaseType
+ GetRangeBase () const
+ {
+ return base;
+ }
+
+ void
+ SetRangeBase (BaseType b)
+ {
+ base = b;
+ }
+
+ void
+ Slide (BaseType slide)
+ {
+ base += slide;
+ }
+
+ BaseType
+ GetRangeEnd () const
+ {
+ return base + size;
+ }
+
+ void
+ SetRangeEnd (BaseType end)
+ {
+ if (end > base)
+ size = end - base;
+ else
+ size = 0;
+ }
+
+ SizeType
+ GetByteSize () const
+ {
+ return size;
+ }
+
+ void
+ SetByteSize (SizeType s)
+ {
+ size = s;
+ }
+
+ bool
+ IsValid() const
+ {
+ return size > 0;
+ }
+
+ bool
+ Contains (BaseType r) const
+ {
+ return (GetRangeBase() <= r) && (r < GetRangeEnd());
+ }
+
+ bool
+ ContainsEndInclusive (BaseType r) const
+ {
+ return (GetRangeBase() <= r) && (r <= GetRangeEnd());
+ }
+
+ bool
+ Contains (const Range& range) const
+ {
+ return Contains(range.GetRangeBase()) && ContainsEndInclusive(range.GetRangeEnd());
+ }
+
+ bool
+ Overlap (const Range &rhs) const
+ {
+ const BaseType lhs_base = this->GetRangeBase();
+ const BaseType rhs_base = rhs.GetRangeBase();
+ const BaseType lhs_end = this->GetRangeEnd();
+ const BaseType rhs_end = rhs.GetRangeEnd();
+ bool result = (lhs_base <= rhs_end) && (lhs_end >= rhs_base);
+ return result;
+ }
+
+ bool
+ operator < (const Range &rhs) const
+ {
+ if (base == rhs.base)
+ return size < rhs.size;
+ return base < rhs.base;
+ }
+
+ bool
+ operator == (const Range &rhs) const
+ {
+ return base == rhs.base && size == rhs.size;
+ }
+
+ bool
+ operator != (const Range &rhs) const
+ {
+ return base != rhs.base || size != rhs.size;
+ }
+ };
+
+ //----------------------------------------------------------------------
+ // A range array class where you get to define the type of the ranges
+ // that the collection contains.
+ //----------------------------------------------------------------------
+
+ template <typename B, typename S, unsigned N>
+ class RangeArray
+ {
+ public:
+ typedef B BaseType;
+ typedef S SizeType;
+ typedef Range<B,S> Entry;
+ typedef llvm::SmallVector<Entry, N> Collection;
+
+ RangeArray () :
+ m_entries ()
+ {
+ }
+
+ ~RangeArray()
+ {
+ }
+
+ void
+ Append (const Entry &entry)
+ {
+ m_entries.push_back (entry);
+ }
+
+ bool
+ RemoveEntrtAtIndex (uint32_t idx)
+ {
+ if (idx < m_entries.size())
+ {
+ m_entries.erase (m_entries.begin() + idx);
+ return true;
+ }
+ return false;
+ }
+
+ void
+ Sort ()
+ {
+ if (m_entries.size() > 1)
+ std::stable_sort (m_entries.begin(), m_entries.end());
+ }
+
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ bool
+ IsSorted () const
+ {
+ typename Collection::const_iterator pos, end, prev;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && *pos < *prev)
+ return false;
+ }
+ return true;
+ }
+#endif
+ void
+ CombineConsecutiveRanges ()
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ // Can't combine if ranges if we have zero or one range
+ if (m_entries.size() > 1)
+ {
+ // The list should be sorted prior to calling this function
+ typename Collection::iterator pos;
+ typename Collection::iterator end;
+ typename Collection::iterator prev;
+ bool can_combine = false;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->Overlap(*pos))
+ {
+ can_combine = true;
+ break;
+ }
+ }
+
+ // We we can combine at least one entry, then we make a new collection
+ // and populate it accordingly, and then swap it into place.
+ if (can_combine)
+ {
+ Collection minimal_ranges;
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->Overlap(*pos))
+ minimal_ranges.back().SetRangeEnd (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
+ else
+ minimal_ranges.push_back (*pos);
+ }
+ // Use the swap technique in case our new vector is much smaller.
+ // We must swap when using the STL because std::vector objects never
+ // release or reduce the memory once it has been allocated/reserved.
+ m_entries.swap (minimal_ranges);
+ }
+ }
+ }
+
+
+ BaseType
+ GetMinRangeBase (BaseType fail_value) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (m_entries.empty())
+ return fail_value;
+ // m_entries must be sorted, so if we aren't empty, we grab the
+ // first range's base
+ return m_entries.front().GetRangeBase();
+ }
+
+ BaseType
+ GetMaxRangeEnd (BaseType fail_value) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (m_entries.empty())
+ return fail_value;
+ // m_entries must be sorted, so if we aren't empty, we grab the
+ // last range's end
+ return m_entries.back().GetRangeEnd();
+ }
+
+ void
+ Slide (BaseType slide)
+ {
+ typename Collection::iterator pos, end;
+ for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
+ pos->Slide (slide);
+ }
+
+ void
+ Clear ()
+ {
+ m_entries.clear();
+ }
+
+ bool
+ IsEmpty () const
+ {
+ return m_entries.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_entries.size();
+ }
+
+ const Entry *
+ GetEntryAtIndex (size_t i) const
+ {
+ if (i<m_entries.size())
+ return &m_entries[i];
+ return NULL;
+ }
+
+ // Clients must ensure that "i" is a valid index prior to calling this function
+ const Entry &
+ GetEntryRef (size_t i) const
+ {
+ return m_entries[i];
+ }
+
+ Entry *
+ Back()
+ {
+ if (m_entries.empty())
+ return NULL;
+ return &m_entries.back();
+ }
+
+ const Entry *
+ Back() const
+ {
+ if (m_entries.empty())
+ return NULL;
+ return &m_entries.back();
+ }
+
+ static bool
+ BaseLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.GetRangeBase() < rhs.GetRangeBase();
+ }
+
+ uint32_t
+ FindEntryIndexThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return std::distance (begin, pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ return std::distance (begin, pos);
+ }
+ }
+ return UINT32_MAX;
+ }
+
+ const Entry *
+ FindEntryThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ const Entry *
+ FindEntryThatContains (const Entry &range) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan);
+
+ if (pos != end && pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ protected:
+ Collection m_entries;
+ };
+
+ template <typename B, typename S>
+ class RangeVector
+ {
+ public:
+ typedef B BaseType;
+ typedef S SizeType;
+ typedef Range<B,S> Entry;
+ typedef std::vector<Entry> Collection;
+
+ RangeVector () :
+ m_entries ()
+ {
+ }
+
+ ~RangeVector()
+ {
+ }
+
+ void
+ Append (const Entry &entry)
+ {
+ m_entries.push_back (entry);
+ }
+
+ bool
+ RemoveEntrtAtIndex (uint32_t idx)
+ {
+ if (idx < m_entries.size())
+ {
+ m_entries.erase (m_entries.begin() + idx);
+ return true;
+ }
+ return false;
+ }
+
+ void
+ Sort ()
+ {
+ if (m_entries.size() > 1)
+ std::stable_sort (m_entries.begin(), m_entries.end());
+ }
+
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ bool
+ IsSorted () const
+ {
+ typename Collection::const_iterator pos, end, prev;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && *pos < *prev)
+ return false;
+ }
+ return true;
+ }
+#endif
+ void
+ CombineConsecutiveRanges ()
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ // Can't combine if ranges if we have zero or one range
+ if (m_entries.size() > 1)
+ {
+ // The list should be sorted prior to calling this function
+ typename Collection::iterator pos;
+ typename Collection::iterator end;
+ typename Collection::iterator prev;
+ bool can_combine = false;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->Overlap(*pos))
+ {
+ can_combine = true;
+ break;
+ }
+ }
+
+ // We we can combine at least one entry, then we make a new collection
+ // and populate it accordingly, and then swap it into place.
+ if (can_combine)
+ {
+ Collection minimal_ranges;
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->Overlap(*pos))
+ minimal_ranges.back().SetRangeEnd (std::max<BaseType>(prev->GetRangeEnd(), pos->GetRangeEnd()));
+ else
+ minimal_ranges.push_back (*pos);
+ }
+ // Use the swap technique in case our new vector is much smaller.
+ // We must swap when using the STL because std::vector objects never
+ // release or reduce the memory once it has been allocated/reserved.
+ m_entries.swap (minimal_ranges);
+ }
+ }
+ }
+
+
+ BaseType
+ GetMinRangeBase (BaseType fail_value) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (m_entries.empty())
+ return fail_value;
+ // m_entries must be sorted, so if we aren't empty, we grab the
+ // first range's base
+ return m_entries.front().GetRangeBase();
+ }
+
+ BaseType
+ GetMaxRangeEnd (BaseType fail_value) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (m_entries.empty())
+ return fail_value;
+ // m_entries must be sorted, so if we aren't empty, we grab the
+ // last range's end
+ return m_entries.back().GetRangeEnd();
+ }
+
+ void
+ Slide (BaseType slide)
+ {
+ typename Collection::iterator pos, end;
+ for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
+ pos->Slide (slide);
+ }
+
+ void
+ Clear ()
+ {
+ m_entries.clear();
+ }
+
+ void
+ Reserve (typename Collection::size_type size)
+ {
+ m_entries.resize (size);
+ }
+
+ bool
+ IsEmpty () const
+ {
+ return m_entries.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_entries.size();
+ }
+
+ const Entry *
+ GetEntryAtIndex (size_t i) const
+ {
+ if (i<m_entries.size())
+ return &m_entries[i];
+ return NULL;
+ }
+
+ // Clients must ensure that "i" is a valid index prior to calling this function
+ const Entry &
+ GetEntryRef (size_t i) const
+ {
+ return m_entries[i];
+ }
+
+ Entry *
+ Back()
+ {
+ if (m_entries.empty())
+ return NULL;
+ return &m_entries.back();
+ }
+
+ const Entry *
+ Back() const
+ {
+ if (m_entries.empty())
+ return NULL;
+ return &m_entries.back();
+ }
+
+ static bool
+ BaseLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.GetRangeBase() < rhs.GetRangeBase();
+ }
+
+ uint32_t
+ FindEntryIndexThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return std::distance (begin, pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ return std::distance (begin, pos);
+ }
+ }
+ return UINT32_MAX;
+ }
+
+ const Entry *
+ FindEntryThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ const Entry *
+ FindEntryThatContains (const Entry &range) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if (!m_entries.empty())
+ {
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan);
+
+ if (pos != end && pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ protected:
+ Collection m_entries;
+ };
+
+ //----------------------------------------------------------------------
+ // A simple range with data class where you get to define the type of
+ // the range base "B", the type used for the range byte size "S", and
+ // the type for the associated data "T".
+ //----------------------------------------------------------------------
+ template <typename B, typename S, typename T>
+ struct RangeData : public Range<B,S>
+ {
+ typedef T DataType;
+
+ DataType data;
+
+ RangeData () :
+ Range<B,S> (),
+ data ()
+ {
+ }
+
+ RangeData (B base, S size) :
+ Range<B,S> (base, size),
+ data ()
+ {
+ }
+
+ RangeData (B base, S size, DataType d) :
+ Range<B,S> (base, size),
+ data (d)
+ {
+ }
+
+ bool
+ operator < (const RangeData &rhs) const
+ {
+ if (this->base == rhs.base)
+ {
+ if (this->size == rhs.size)
+ return this->data < rhs.data;
+ else
+ return this->size < rhs.size;
+ }
+ return this->base < rhs.base;
+ }
+
+ bool
+ operator == (const RangeData &rhs) const
+ {
+ return this->GetRangeBase() == rhs.GetRangeBase() &&
+ this->GetByteSize() == rhs.GetByteSize() &&
+ this->data == rhs.data;
+ }
+
+ bool
+ operator != (const RangeData &rhs) const
+ {
+ return this->GetRangeBase() != rhs.GetRangeBase() ||
+ this->GetByteSize() != rhs.GetByteSize() ||
+ this->data != rhs.data;
+ }
+ };
+
+ template <typename B, typename S, typename T, unsigned N>
+ class RangeDataArray
+ {
+ public:
+ typedef RangeData<B,S,T> Entry;
+ typedef llvm::SmallVector<Entry, N> Collection;
+
+
+ RangeDataArray ()
+ {
+ }
+
+ ~RangeDataArray()
+ {
+ }
+
+ void
+ Append (const Entry &entry)
+ {
+ m_entries.push_back (entry);
+ }
+
+ void
+ Sort ()
+ {
+ if (m_entries.size() > 1)
+ std::stable_sort (m_entries.begin(), m_entries.end());
+ }
+
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ bool
+ IsSorted () const
+ {
+ typename Collection::const_iterator pos, end, prev;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && *pos < *prev)
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ void
+ CombineConsecutiveEntriesWithEqualData ()
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ typename Collection::iterator pos;
+ typename Collection::iterator end;
+ typename Collection::iterator prev;
+ bool can_combine = false;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->data == pos->data)
+ {
+ can_combine = true;
+ break;
+ }
+ }
+
+ // We we can combine at least one entry, then we make a new collection
+ // and populate it accordingly, and then swap it into place.
+ if (can_combine)
+ {
+ Collection minimal_ranges;
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->data == pos->data)
+ minimal_ranges.back().SetRangeEnd (pos->GetRangeEnd());
+ else
+ minimal_ranges.push_back (*pos);
+ }
+ // Use the swap technique in case our new vector is much smaller.
+ // We must swap when using the STL because std::vector objects never
+ // release or reduce the memory once it has been allocated/reserved.
+ m_entries.swap (minimal_ranges);
+ }
+ }
+
+ void
+ Clear ()
+ {
+ m_entries.clear();
+ }
+
+ bool
+ IsEmpty () const
+ {
+ return m_entries.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_entries.size();
+ }
+
+ const Entry *
+ GetEntryAtIndex (size_t i) const
+ {
+ if (i<m_entries.size())
+ return &m_entries[i];
+ return NULL;
+ }
+
+ // Clients must ensure that "i" is a valid index prior to calling this function
+ const Entry &
+ GetEntryRef (size_t i) const
+ {
+ return m_entries[i];
+ }
+
+ static bool
+ BaseLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.GetRangeBase() < rhs.GetRangeBase();
+ }
+
+ uint32_t
+ FindEntryIndexThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return std::distance (begin, pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ return std::distance (begin, pos);
+ }
+ }
+ return UINT32_MAX;
+ }
+
+ Entry *
+ FindEntryThatContains (B addr)
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry;
+ entry.SetRangeBase(addr);
+ entry.SetByteSize(1);
+ typename Collection::iterator begin = m_entries.begin();
+ typename Collection::iterator end = m_entries.end();
+ typename Collection::iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+ const Entry *
+ FindEntryThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry;
+ entry.SetRangeBase(addr);
+ entry.SetByteSize(1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ const Entry *
+ FindEntryThatContains (const Entry &range) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan);
+
+ if (pos != end && pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ Entry *
+ Back()
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ const Entry *
+ Back() const
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ protected:
+ Collection m_entries;
+ };
+
+ // Same as RangeDataArray, but uses std::vector as to not
+ // require static storage of N items in the class itself
+ template <typename B, typename S, typename T>
+ class RangeDataVector
+ {
+ public:
+ typedef RangeData<B,S,T> Entry;
+ typedef std::vector<Entry> Collection;
+
+ RangeDataVector ()
+ {
+ }
+
+ ~RangeDataVector()
+ {
+ }
+
+ void
+ Append (const Entry &entry)
+ {
+ m_entries.push_back (entry);
+ }
+
+ void
+ Sort ()
+ {
+ if (m_entries.size() > 1)
+ std::stable_sort (m_entries.begin(), m_entries.end());
+ }
+
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ bool
+ IsSorted () const
+ {
+ typename Collection::const_iterator pos, end, prev;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && *pos < *prev)
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ void
+ CombineConsecutiveEntriesWithEqualData ()
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ typename Collection::iterator pos;
+ typename Collection::iterator end;
+ typename Collection::iterator prev;
+ bool can_combine = false;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->data == pos->data)
+ {
+ can_combine = true;
+ break;
+ }
+ }
+
+ // We we can combine at least one entry, then we make a new collection
+ // and populate it accordingly, and then swap it into place.
+ if (can_combine)
+ {
+ Collection minimal_ranges;
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && prev->data == pos->data)
+ minimal_ranges.back().SetRangeEnd (pos->GetRangeEnd());
+ else
+ minimal_ranges.push_back (*pos);
+ }
+ // Use the swap technique in case our new vector is much smaller.
+ // We must swap when using the STL because std::vector objects never
+ // release or reduce the memory once it has been allocated/reserved.
+ m_entries.swap (minimal_ranges);
+ }
+ }
+
+ // Calculate the byte size of ranges with zero byte sizes by finding
+ // the next entry with a base address > the current base address
+ void
+ CalculateSizesOfZeroByteSizeRanges ()
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ typename Collection::iterator pos;
+ typename Collection::iterator end;
+ typename Collection::iterator next;
+ for (pos = m_entries.begin(), end = m_entries.end(); pos != end; ++pos)
+ {
+ if (pos->GetByteSize() == 0)
+ {
+ // Watch out for multiple entries with same address and make sure
+ // we find an entry that is greater than the current base address
+ // before we use that for the size
+ auto curr_base = pos->GetRangeBase();
+ for (next = pos + 1; next != end; ++next)
+ {
+ auto next_base = next->GetRangeBase();
+ if (next_base > curr_base)
+ {
+ pos->SetByteSize (next_base - curr_base);
+ break;
+ }
+ }
+ }
+ }
+
+ }
+
+ void
+ Clear ()
+ {
+ m_entries.clear();
+ }
+
+ void
+ Reserve (typename Collection::size_type size)
+ {
+ m_entries.resize (size);
+ }
+
+ bool
+ IsEmpty () const
+ {
+ return m_entries.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_entries.size();
+ }
+
+ const Entry *
+ GetEntryAtIndex (size_t i) const
+ {
+ if (i<m_entries.size())
+ return &m_entries[i];
+ return NULL;
+ }
+
+ // Clients must ensure that "i" is a valid index prior to calling this function
+ const Entry &
+ GetEntryRef (size_t i) const
+ {
+ return m_entries[i];
+ }
+
+ static bool
+ BaseLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.GetRangeBase() < rhs.GetRangeBase();
+ }
+
+ uint32_t
+ FindEntryIndexThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry (addr, 1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return std::distance (begin, pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ return std::distance (begin, pos);
+ }
+ }
+ return UINT32_MAX;
+ }
+
+ Entry *
+ FindEntryThatContains (B addr)
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry;
+ entry.SetRangeBase(addr);
+ entry.SetByteSize(1);
+ typename Collection::iterator begin = m_entries.begin();
+ typename Collection::iterator end = m_entries.end();
+ typename Collection::iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+ const Entry *
+ FindEntryThatContains (B addr) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry;
+ entry.SetRangeBase(addr);
+ entry.SetByteSize(1);
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end && pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(addr))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ const Entry *
+ FindEntryThatContains (const Entry &range) const
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ typename Collection::const_iterator begin = m_entries.begin();
+ typename Collection::const_iterator end = m_entries.end();
+ typename Collection::const_iterator pos = std::lower_bound (begin, end, range, BaseLessThan);
+
+ if (pos != end && pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ else if (pos != begin)
+ {
+ --pos;
+ if (pos->Contains(range))
+ {
+ return &(*pos);
+ }
+ }
+ }
+ return NULL;
+ }
+
+ Entry *
+ Back()
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ const Entry *
+ Back() const
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ protected:
+ Collection m_entries;
+ };
+
+
+ //----------------------------------------------------------------------
+ // A simple range with data class where you get to define the type of
+ // the range base "B", the type used for the range byte size "S", and
+ // the type for the associated data "T".
+ //----------------------------------------------------------------------
+ template <typename B, typename T>
+ struct AddressData
+ {
+ typedef B BaseType;
+ typedef T DataType;
+
+ BaseType addr;
+ DataType data;
+
+ AddressData () :
+ addr (),
+ data ()
+ {
+ }
+
+ AddressData (B a, DataType d) :
+ addr (a),
+ data (d)
+ {
+ }
+
+ bool
+ operator < (const AddressData &rhs) const
+ {
+ if (this->addr == rhs.addr)
+ return this->data < rhs.data;
+ return this->addr < rhs.addr;
+ }
+
+ bool
+ operator == (const AddressData &rhs) const
+ {
+ return this->addr == rhs.addr &&
+ this->data == rhs.data;
+ }
+
+ bool
+ operator != (const AddressData &rhs) const
+ {
+ return this->addr != rhs.addr ||
+ this->data == rhs.data;
+ }
+ };
+
+
+ template <typename B, typename T, unsigned N>
+ class AddressDataArray
+ {
+ public:
+ typedef AddressData<B,T> Entry;
+ typedef llvm::SmallVector<Entry, N> Collection;
+
+
+ AddressDataArray ()
+ {
+ }
+
+ ~AddressDataArray()
+ {
+ }
+
+ void
+ Append (const Entry &entry)
+ {
+ m_entries.push_back (entry);
+ }
+
+ void
+ Sort ()
+ {
+ if (m_entries.size() > 1)
+ std::stable_sort (m_entries.begin(), m_entries.end());
+ }
+
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ bool
+ IsSorted () const
+ {
+ typename Collection::const_iterator pos, end, prev;
+ // First we determine if we can combine any of the Entry objects so we
+ // don't end up allocating and making a new collection for no reason
+ for (pos = m_entries.begin(), end = m_entries.end(), prev = end; pos != end; prev = pos++)
+ {
+ if (prev != end && *pos < *prev)
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ void
+ Clear ()
+ {
+ m_entries.clear();
+ }
+
+ bool
+ IsEmpty () const
+ {
+ return m_entries.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_entries.size();
+ }
+
+ const Entry *
+ GetEntryAtIndex (size_t i) const
+ {
+ if (i<m_entries.size())
+ return &m_entries[i];
+ return NULL;
+ }
+
+ // Clients must ensure that "i" is a valid index prior to calling this function
+ const Entry &
+ GetEntryRef (size_t i) const
+ {
+ return m_entries[i];
+ }
+
+ static bool
+ BaseLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.addr < rhs.addr;
+ }
+
+ Entry *
+ FindEntry (B addr, bool exact_match_only)
+ {
+#ifdef ASSERT_RANGEMAP_ARE_SORTED
+ assert (IsSorted());
+#endif
+ if ( !m_entries.empty() )
+ {
+ Entry entry;
+ entry.addr = addr;
+ typename Collection::iterator begin = m_entries.begin();
+ typename Collection::iterator end = m_entries.end();
+ typename Collection::iterator pos = std::lower_bound (begin, end, entry, BaseLessThan);
+
+ if (pos != end)
+ {
+ if (pos->addr == addr || !exact_match_only)
+ return &(*pos);
+ }
+ }
+ return NULL;
+ }
+
+ const Entry *
+ FindNextEntry (const Entry *entry)
+ {
+ if (entry >= &*m_entries.begin() && entry + 1 < &*m_entries.end())
+ return entry + 1;
+ return NULL;
+ }
+
+ Entry *
+ Back()
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ const Entry *
+ Back() const
+ {
+ if (!m_entries.empty())
+ return &m_entries.back();
+ return NULL;
+ }
+
+ protected:
+ Collection m_entries;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_RangeMap_h_
diff --git a/include/lldb/Core/RegisterValue.h b/include/lldb/Core/RegisterValue.h
new file mode 100644
index 000000000000..cf29cea46d36
--- /dev/null
+++ b/include/lldb/Core/RegisterValue.h
@@ -0,0 +1,406 @@
+//===-- RegisterValue.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterValue_h
+#define lldb_RegisterValue_h
+
+// C Includes
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Endian.h"
+
+//#define ENABLE_128_BIT_SUPPORT 1
+namespace lldb_private {
+
+ class RegisterValue
+ {
+ public:
+ enum
+ {
+ kMaxRegisterByteSize = 32u
+ };
+ enum Type
+ {
+ eTypeInvalid,
+ eTypeUInt8,
+ eTypeUInt16,
+ eTypeUInt32,
+ eTypeUInt64,
+#if defined (ENABLE_128_BIT_SUPPORT)
+ eTypeUInt128,
+#endif
+ eTypeFloat,
+ eTypeDouble,
+ eTypeLongDouble,
+ eTypeBytes
+ };
+
+ RegisterValue () :
+ m_type (eTypeInvalid)
+ {
+ }
+
+ explicit
+ RegisterValue (uint8_t inst) :
+ m_type (eTypeUInt8)
+ {
+ m_data.uint8 = inst;
+ }
+
+ explicit
+ RegisterValue (uint16_t inst) :
+ m_type (eTypeUInt16)
+ {
+ m_data.uint16 = inst;
+ }
+
+ explicit
+ RegisterValue (uint32_t inst) :
+ m_type (eTypeUInt32)
+ {
+ m_data.uint32 = inst;
+ }
+
+ explicit
+ RegisterValue (uint64_t inst) :
+ m_type (eTypeUInt64)
+ {
+ m_data.uint64 = inst;
+ }
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ explicit
+ RegisterValue (__uint128_t inst) :
+ m_type (eTypeUInt128)
+ {
+ m_data.uint128 = inst;
+ }
+#endif
+ explicit
+ RegisterValue (float value) :
+ m_type (eTypeFloat)
+ {
+ m_data.ieee_float = value;
+ }
+
+ explicit
+ RegisterValue (double value) :
+ m_type (eTypeDouble)
+ {
+ m_data.ieee_double = value;
+ }
+
+ explicit
+ RegisterValue (long double value) :
+ m_type (eTypeLongDouble)
+ {
+ m_data.ieee_long_double = value;
+ }
+
+ explicit
+ RegisterValue (uint8_t *bytes, size_t length, lldb::ByteOrder byte_order)
+ {
+ SetBytes (bytes, length, byte_order);
+ }
+
+ RegisterValue::Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ bool
+ CopyValue (const RegisterValue &rhs);
+
+ void
+ SetType (RegisterValue::Type type)
+ {
+ m_type = type;
+ }
+
+ RegisterValue::Type
+ SetType (const RegisterInfo *reg_info);
+
+ bool
+ GetData (DataExtractor &data) const;
+
+ // Copy the register value from this object into a buffer in "dst"
+ // and obey the "dst_byte_order" when copying the data. Also watch out
+ // in case "dst_len" is longer or shorter than the register value
+ // described by "reg_info" and only copy the least significant bytes
+ // of the register value, or pad the destination with zeroes if the
+ // register byte size is shorter that "dst_len" (all while correctly
+ // abiding the "dst_byte_order"). Returns the number of bytes copied
+ // into "dst".
+ uint32_t
+ GetAsMemoryData (const RegisterInfo *reg_info,
+ void *dst,
+ uint32_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const;
+
+ uint32_t
+ SetFromMemoryData (const RegisterInfo *reg_info,
+ const void *src,
+ uint32_t src_len,
+ lldb::ByteOrder src_byte_order,
+ Error &error);
+
+ bool
+ GetScalarValue (Scalar &scalar) const;
+
+ uint8_t
+ GetAsUInt8 (uint8_t fail_value = UINT8_MAX, bool *success_ptr = NULL) const
+ {
+ if (m_type == eTypeUInt8)
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return m_data.uint8;
+ }
+ if (success_ptr)
+ *success_ptr = true;
+ return fail_value;
+ }
+
+ uint16_t
+ GetAsUInt16 (uint16_t fail_value = UINT16_MAX, bool *success_ptr = NULL) const;
+
+ uint32_t
+ GetAsUInt32 (uint32_t fail_value = UINT32_MAX, bool *success_ptr = NULL) const;
+
+ uint64_t
+ GetAsUInt64 (uint64_t fail_value = UINT64_MAX, bool *success_ptr = NULL) const;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ __uint128_t
+ GetAsUInt128 (__uint128_t fail_value = ~((__uint128_t)0), bool *success_ptr = NULL) const;
+#endif
+
+ float
+ GetAsFloat (float fail_value = 0.0f, bool *success_ptr = NULL) const;
+
+ double
+ GetAsDouble (double fail_value = 0.0, bool *success_ptr = NULL) const;
+
+ long double
+ GetAsLongDouble (long double fail_value = 0.0, bool *success_ptr = NULL) const;
+
+ void
+ SetValueToInvalid ()
+ {
+ m_type = eTypeInvalid;
+ }
+
+ bool
+ ClearBit (uint32_t bit);
+
+ bool
+ SetBit (uint32_t bit);
+
+ bool
+ operator == (const RegisterValue &rhs) const;
+
+ bool
+ operator != (const RegisterValue &rhs) const;
+
+ void
+ operator = (uint8_t uint)
+ {
+ m_type = eTypeUInt8;
+ m_data.uint8 = uint;
+ }
+
+ void
+ operator = (uint16_t uint)
+ {
+ m_type = eTypeUInt16;
+ m_data.uint16 = uint;
+ }
+
+ void
+ operator = (uint32_t uint)
+ {
+ m_type = eTypeUInt32;
+ m_data.uint32 = uint;
+ }
+
+ void
+ operator = (uint64_t uint)
+ {
+ m_type = eTypeUInt64;
+ m_data.uint64 = uint;
+ }
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ void
+ operator = (__uint128_t uint)
+ {
+ m_type = eTypeUInt128;
+ m_data.uint128 = uint;
+ }
+#endif
+ void
+ operator = (float f)
+ {
+ m_type = eTypeFloat;
+ m_data.ieee_float = f;
+ }
+
+ void
+ operator = (double f)
+ {
+ m_type = eTypeDouble;
+ m_data.ieee_double = f;
+ }
+
+ void
+ operator = (long double f)
+ {
+ m_type = eTypeLongDouble;
+ m_data.ieee_long_double = f;
+ }
+
+ void
+ SetUInt8 (uint8_t uint)
+ {
+ m_type = eTypeUInt8;
+ m_data.uint8 = uint;
+ }
+
+ void
+ SetUInt16 (uint16_t uint)
+ {
+ m_type = eTypeUInt16;
+ m_data.uint16 = uint;
+ }
+
+ void
+ SetUInt32 (uint32_t uint, Type t = eTypeUInt32)
+ {
+ m_type = t;
+ m_data.uint32 = uint;
+ }
+
+ void
+ SetUInt64 (uint64_t uint, Type t = eTypeUInt64)
+ {
+ m_type = t;
+ m_data.uint64 = uint;
+ }
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ void
+ SetUInt128 (__uint128_t uint)
+ {
+ m_type = eTypeUInt128;
+ m_data.uint128 = uint;
+ }
+#endif
+ bool
+ SetUInt (uint64_t uint, uint32_t byte_size);
+
+ void
+ SetFloat (float f)
+ {
+ m_type = eTypeFloat;
+ m_data.ieee_float = f;
+ }
+
+ void
+ SetDouble (double f)
+ {
+ m_type = eTypeDouble;
+ m_data.ieee_double = f;
+ }
+
+ void
+ SetLongDouble (long double f)
+ {
+ m_type = eTypeLongDouble;
+ m_data.ieee_long_double = f;
+ }
+
+ void
+ SetBytes (const void *bytes, size_t length, lldb::ByteOrder byte_order);
+
+ bool
+ SignExtend (uint32_t sign_bitpos);
+
+ Error
+ SetValueFromCString (const RegisterInfo *reg_info,
+ const char *value_str);
+
+ Error
+ SetValueFromData (const RegisterInfo *reg_info,
+ DataExtractor &data,
+ lldb::offset_t offset,
+ bool partial_data_ok);
+
+ // The default value of 0 for reg_name_right_align_at means no alignment at all.
+ bool
+ Dump (Stream *s,
+ const RegisterInfo *reg_info,
+ bool prefix_with_name,
+ bool prefix_with_alt_name,
+ lldb::Format format,
+ uint32_t reg_name_right_align_at = 0) const;
+
+ void *
+ GetBytes ();
+
+ const void *
+ GetBytes () const;
+
+ lldb::ByteOrder
+ GetByteOrder () const
+ {
+ if (m_type == eTypeBytes)
+ return m_data.buffer.byte_order;
+ return lldb::endian::InlHostByteOrder();
+ }
+
+ uint32_t
+ GetByteSize () const;
+
+ void
+ Clear();
+
+ protected:
+
+ RegisterValue::Type m_type;
+ union
+ {
+ uint8_t uint8;
+ uint16_t uint16;
+ uint32_t uint32;
+ uint64_t uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ __uint128_t uint128;
+#endif
+ float ieee_float;
+ double ieee_double;
+ long double ieee_long_double;
+ struct
+ {
+ uint8_t bytes[kMaxRegisterByteSize]; // This must be big enough to hold any register for any supported target.
+ uint8_t length;
+ lldb::ByteOrder byte_order;
+ } buffer;
+ } m_data;
+ };
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterValue_h
diff --git a/include/lldb/Core/RegularExpression.h b/include/lldb/Core/RegularExpression.h
new file mode 100644
index 000000000000..eeeb914bfa90
--- /dev/null
+++ b/include/lldb/Core/RegularExpression.h
@@ -0,0 +1,253 @@
+//===-- RegularExpression.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_DBRegex_h_
+#define liblldb_DBRegex_h_
+#if defined(__cplusplus)
+
+#include <regex.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace llvm
+{
+ class StringRef;
+}
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class RegularExpression RegularExpression.h "lldb/Core/RegularExpression.h"
+/// @brief A C++ wrapper class for regex.
+///
+/// This regular expression class wraps the posix regex functions
+/// \c regcomp(), \c regerror(), \c regexec(), and \c regfree() from
+/// the header file in \c /usr/include/regex\.h.
+//----------------------------------------------------------------------
+class RegularExpression
+{
+public:
+ class Match
+ {
+ public:
+ Match (uint32_t max_matches) :
+ m_matches ()
+ {
+ if (max_matches > 0)
+ m_matches.resize(max_matches + 1);
+ }
+
+ void
+ Clear()
+ {
+ const size_t num_matches = m_matches.size();
+ regmatch_t invalid_match = { -1, -1 };
+ for (size_t i=0; i<num_matches; ++i)
+ m_matches[i] = invalid_match;
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_matches.size();
+ }
+
+ regmatch_t *
+ GetData ()
+ {
+ if (m_matches.empty())
+ return NULL;
+ return m_matches.data();
+ }
+
+ bool
+ GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const;
+
+ bool
+ GetMatchAtIndex (const char* s, uint32_t idx, llvm::StringRef& match_str) const;
+
+ bool
+ GetMatchSpanningIndices (const char* s, uint32_t idx1, uint32_t idx2, llvm::StringRef& match_str) const;
+
+ protected:
+
+ std::vector<regmatch_t> m_matches; ///< Where parenthesized subexpressions results are stored
+ };
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// The default constructor that initializes the object state such
+ /// that it contains no compiled regular expression.
+ //------------------------------------------------------------------
+ RegularExpression ();
+
+ //------------------------------------------------------------------
+ /// Constructor that takes a regulare expression with flags.
+ ///
+ /// Constructor that compiles \a re using \a flags and stores the
+ /// resulting compiled regular expression into this object.
+ ///
+ /// @param[in] re
+ /// A c string that represents the regular expression to
+ /// compile.
+ ///
+ /// @param[in] flags
+ /// Flags that are passed the the \c regcomp() function.
+ //------------------------------------------------------------------
+ explicit
+ RegularExpression (const char* re, int flags);
+
+ // This one uses flags = REG_EXTENDED.
+ explicit
+ RegularExpression (const char* re);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Any previosuly compiled regular expression contained in this
+ /// object will be freed.
+ //------------------------------------------------------------------
+ ~RegularExpression ();
+
+ RegularExpression (const RegularExpression &rhs);
+
+ const RegularExpression & operator=(const RegularExpression &rhs);
+
+ //------------------------------------------------------------------
+ /// Compile a regular expression.
+ ///
+ /// Compile a regular expression using the supplied regular
+ /// expression text and flags. The compied regular expression lives
+ /// in this object so that it can be readily used for regular
+ /// expression matches. Execute() can be called after the regular
+ /// expression is compiled. Any previosuly compiled regular
+ /// expression contained in this object will be freed.
+ ///
+ /// @param[in] re
+ /// A NULL terminated C string that represents the regular
+ /// expression to compile.
+ ///
+ /// @param[in] flags
+ /// Flags that are passed the the \c regcomp() function.
+ ///
+ /// @return
+ /// \b true if the regular expression compiles successfully,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Compile (const char* re);
+
+ bool
+ Compile (const char* re, int flags);
+
+ //------------------------------------------------------------------
+ /// Executes a regular expression.
+ ///
+ /// Execute a regular expression match using the compiled regular
+ /// expression that is already in this object against the match
+ /// string \a s. If any parens are used for regular expression
+ /// matches \a match_count should indicate the number of regmatch_t
+ /// values that are present in \a match_ptr. The regular expression
+ /// will be executed using the \a execute_flags
+ ///
+ /// @param[in] string
+ /// The string to match against the compile regular expression.
+ ///
+ /// @param[in] match
+ /// A pointer to a RegularExpression::Match structure that was
+ /// properly initialized with the desired number of maximum
+ /// matches, or NULL if no parenthesized matching is needed.
+ ///
+ /// @param[in] execute_flags
+ /// Flags to pass to the \c regexec() function.
+ ///
+ /// @return
+ /// \b true if \a string matches the compiled regular
+ /// expression, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Execute (const char* string, Match *match = NULL, int execute_flags = 0) const;
+
+ size_t
+ GetErrorAsCString (char *err_str, size_t err_str_max_len) const;
+
+ //------------------------------------------------------------------
+ /// Free the compiled regular expression.
+ ///
+ /// If this object contains a valid compiled regular expression,
+ /// this function will free any resources it was consuming.
+ //------------------------------------------------------------------
+ void
+ Free ();
+
+ //------------------------------------------------------------------
+ /// Access the regular expression text.
+ ///
+ /// Returns the text that was used to compile the current regular
+ /// expression.
+ ///
+ /// @return
+ /// The NULL terminated C string that was used to compile the
+ /// current regular expression
+ //------------------------------------------------------------------
+ const char*
+ GetText () const;
+
+ int
+ GetCompileFlags () const
+ {
+ return m_compile_flags;
+ }
+
+ //------------------------------------------------------------------
+ /// Test if valid.
+ ///
+ /// Test if this object contains a valid regular expression.
+ ///
+ /// @return
+ /// \b true if the regular expression compiled and is ready
+ /// for execution, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid () const;
+
+ void
+ Clear ()
+ {
+ Free();
+ m_re.clear();
+ m_compile_flags = 0;
+ m_comp_err = 1;
+ }
+
+ int
+ GetErrorCode() const
+ {
+ return m_comp_err;
+ }
+
+ bool
+ operator < (const RegularExpression& rhs) const;
+
+private:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ std::string m_re; ///< A copy of the original regular expression text
+ int m_comp_err; ///< Error code for the regular expression compilation
+ regex_t m_preg; ///< The compiled regular expression
+ int m_compile_flags; ///< Stores the flags from the last compile.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_DBRegex_h_
diff --git a/include/lldb/Core/STLUtils.h b/include/lldb/Core/STLUtils.h
new file mode 100644
index 000000000000..9321e057a397
--- /dev/null
+++ b/include/lldb/Core/STLUtils.h
@@ -0,0 +1,94 @@
+//===-- STLUtils.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_STLUtils_h_
+#define liblldb_STLUtils_h_
+#if defined(__cplusplus)
+
+#include <string.h>
+
+#include <map>
+#include <ostream>
+#include <vector>
+
+//----------------------------------------------------------------------
+// C string less than compare function object
+//----------------------------------------------------------------------
+struct CStringCompareFunctionObject
+{
+ bool operator() (const char* s1, const char* s2) const
+ {
+ return strcmp(s1, s2) < 0;
+ }
+};
+
+
+//----------------------------------------------------------------------
+// C string equality function object (binary predicate).
+//----------------------------------------------------------------------
+struct CStringEqualBinaryPredicate
+{
+ bool operator()(const char* s1, const char* s2) const
+ {
+ return strcmp(s1, s2) == 0;
+ }
+};
+
+
+//----------------------------------------------------------------------
+// Templated type for finding an entry in a std::map<F,S> whose value
+// is equal to something
+//----------------------------------------------------------------------
+template <class F, class S>
+class ValueEquals
+{
+private:
+ S second_value;
+
+public:
+ ValueEquals (const S& val) : second_value(val)
+ {}
+ // Compare the second item
+ bool operator() (std::pair<const F, S> elem)
+ {
+ return elem.second == second_value;
+ }
+};
+
+template <class T>
+inline void PrintAllCollectionElements (std::ostream &s, const T& coll, const char* header_cstr=NULL, const char* separator_cstr=" ")
+{
+ typename T::const_iterator pos;
+
+ if (header_cstr)
+ s << header_cstr;
+ for (pos=coll.begin(); pos!=coll.end(); ++pos) {
+ s << *pos << separator_cstr;
+ }
+ s << std::endl;
+}
+
+// The function object below can be used to delete a STL container that
+// contains C++ object pointers.
+//
+// Usage: std::for_each(vector.begin(), vector.end(), for_each_delete());
+
+struct for_each_cplusplus_delete
+{
+ template <typename T>
+ void operator()(T *ptr){ delete ptr;}
+};
+
+typedef std::vector<std::string> STLStringArray;
+typedef std::vector<const char *> CStringArray;
+
+
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_STLUtils_h_
diff --git a/include/lldb/Core/Scalar.h b/include/lldb/Core/Scalar.h
new file mode 100644
index 000000000000..821a0fb1ae21
--- /dev/null
+++ b/include/lldb/Core/Scalar.h
@@ -0,0 +1,341 @@
+//===-- Scalar.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_Scalar_h_
+#define liblldb_Scalar_h_
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A class designed to hold onto values and their corresponding types.
+// Operators are defined and Scalar objects will correctly promote
+// their types and values before performing these operations. Type
+// promotion currently follows the ANSI C type promotion rules.
+//----------------------------------------------------------------------
+class Scalar
+{
+public:
+ enum Type
+ {
+ e_void = 0,
+ e_sint,
+ e_uint,
+ e_slong,
+ e_ulong,
+ e_slonglong,
+ e_ulonglong,
+ e_float,
+ e_double,
+ e_long_double
+ };
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Scalar();
+ Scalar(int v) : m_type(e_sint), m_data() { m_data.sint = v; }
+ Scalar(unsigned int v) : m_type(e_uint), m_data() { m_data.uint = v; }
+ Scalar(long v) : m_type(e_slong), m_data() { m_data.slong = v; }
+ Scalar(unsigned long v) : m_type(e_ulong), m_data() { m_data.ulong = v; }
+ Scalar(long long v) : m_type(e_slonglong), m_data() { m_data.slonglong = v; }
+ Scalar(unsigned long long v): m_type(e_ulonglong), m_data() { m_data.ulonglong = v; }
+ Scalar(float v) : m_type(e_float), m_data() { m_data.flt = v; }
+ Scalar(double v) : m_type(e_double), m_data() { m_data.dbl = v; }
+ Scalar(long double v) : m_type(e_long_double), m_data() { m_data.ldbl = v; }
+ Scalar(const Scalar& rhs);
+ //Scalar(const RegisterValue& reg_value);
+ virtual ~Scalar();
+
+ bool
+ SignExtend (uint32_t bit_pos);
+
+ bool
+ ExtractBitfield (uint32_t bit_size,
+ uint32_t bit_offset);
+
+ size_t
+ GetByteSize() const;
+
+ static size_t
+ GetMaxByteSize()
+ {
+ return sizeof(ValueData);
+ }
+
+ bool
+ GetData (DataExtractor &data, size_t limit_byte_size = UINT32_MAX) const;
+
+ size_t
+ GetAsMemoryData (void *dst,
+ size_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const;
+
+ bool
+ IsZero() const;
+
+ void
+ Clear() { m_type = e_void; m_data.ulonglong = 0; }
+
+ const char *
+ GetTypeAsCString() const;
+
+ void
+ GetValue (Stream *s, bool show_type) const;
+
+ bool
+ IsValid() const
+ {
+ return (m_type >= e_sint) && (m_type <= e_long_double);
+ }
+
+ bool
+ Promote(Scalar::Type type);
+
+ bool
+ Cast (Scalar::Type type);
+
+ bool
+ MakeSigned ();
+
+ static const char *
+ GetValueTypeAsCString (Scalar::Type value_type);
+
+ static Scalar::Type
+ GetValueTypeForSignedIntegerWithByteSize (size_t byte_size);
+
+ static Scalar::Type
+ GetValueTypeForUnsignedIntegerWithByteSize (size_t byte_size);
+
+ static Scalar::Type
+ GetValueTypeForFloatWithByteSize (size_t byte_size);
+
+ //----------------------------------------------------------------------
+ // All operators can benefits from the implicit conversions that will
+ // happen automagically by the compiler, so no temporary objects will
+ // need to be created. As a result, we currently don't need a variety of
+ // overloaded set value accessors.
+ //----------------------------------------------------------------------
+ Scalar& operator= (const int i);
+ Scalar& operator= (unsigned int v);
+ Scalar& operator= (long v);
+ Scalar& operator= (unsigned long v);
+ Scalar& operator= (long long v);
+ Scalar& operator= (unsigned long long v);
+ Scalar& operator= (float v);
+ Scalar& operator= (double v);
+ Scalar& operator= (long double v);
+ Scalar& operator= (const Scalar& rhs); // Assignment operator
+ Scalar& operator+= (const Scalar& rhs);
+ Scalar& operator<<= (const Scalar& rhs); // Shift left
+ Scalar& operator>>= (const Scalar& rhs); // Shift right (arithmetic)
+ Scalar& operator&= (const Scalar& rhs);
+
+ //----------------------------------------------------------------------
+ // Shifts the current value to the right without maintaining the current
+ // sign of the value (if it is signed).
+ //----------------------------------------------------------------------
+ bool
+ ShiftRightLogical(const Scalar& rhs); // Returns true on success
+
+ //----------------------------------------------------------------------
+ // Takes the absolute value of the current value if it is signed, else
+ // the value remains unchanged.
+ // Returns false if the contained value has a void type.
+ //----------------------------------------------------------------------
+ bool
+ AbsoluteValue(); // Returns true on success
+ //----------------------------------------------------------------------
+ // Negates the current value (even for unsigned values).
+ // Returns false if the contained value has a void type.
+ //----------------------------------------------------------------------
+ bool
+ UnaryNegate(); // Returns true on success
+ //----------------------------------------------------------------------
+ // Inverts all bits in the current value as long as it isn't void or
+ // a float/double/long double type.
+ // Returns false if the contained value has a void/float/double/long
+ // double type, else the value is inverted and true is returned.
+ //----------------------------------------------------------------------
+ bool
+ OnesComplement(); // Returns true on success
+
+ //----------------------------------------------------------------------
+ // Access the type of the current value.
+ //----------------------------------------------------------------------
+ Scalar::Type
+ GetType() const { return m_type; }
+
+ //----------------------------------------------------------------------
+ // Returns a casted value of the current contained data without
+ // modifying the current value. FAIL_VALUE will be returned if the type
+ // of the value is void or invalid.
+ //----------------------------------------------------------------------
+ int
+ SInt(int fail_value = 0) const;
+
+ // Return the raw unsigned integer without any casting or conversion
+ unsigned int
+ RawUInt () const;
+
+ // Return the raw unsigned long without any casting or conversion
+ unsigned long
+ RawULong () const;
+
+ // Return the raw unsigned long long without any casting or conversion
+ unsigned long long
+ RawULongLong () const;
+
+ unsigned int
+ UInt(unsigned int fail_value = 0) const;
+
+ long
+ SLong(long fail_value = 0) const;
+
+ unsigned long
+ ULong(unsigned long fail_value = 0) const;
+
+ long long
+ SLongLong(long long fail_value = 0) const;
+
+ unsigned long long
+ ULongLong(unsigned long long fail_value = 0) const;
+
+ float
+ Float(float fail_value = 0.0f) const;
+
+ double
+ Double(double fail_value = 0.0) const;
+
+ long double
+ LongDouble(long double fail_value = 0.0) const;
+
+ uint64_t
+ GetRawBits64 (uint64_t fail_value) const;
+
+ Error
+ SetValueFromCString (const char *s, lldb::Encoding encoding, size_t byte_size);
+
+ Error
+ SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t byte_size);
+
+ static bool
+ UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
+ return uval64 <= max;
+ }
+
+ static bool
+ SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
+ const int64_t min = ~(max);
+ return min <= sval64 && sval64 <= max;
+ }
+
+protected:
+ typedef int sint_t;
+ typedef unsigned int uint_t;
+ typedef long slong_t;
+ typedef unsigned long ulong_t;
+ typedef long long slonglong_t;
+ typedef unsigned long long ulonglong_t;
+ typedef float float_t;
+ typedef double double_t;
+ typedef long double long_double_t;
+
+ union ValueData
+ {
+ int sint;
+ unsigned int uint;
+ long slong;
+ unsigned long ulong;
+ long long slonglong;
+ unsigned long long ulonglong;
+ float flt;
+ double dbl;
+ long double ldbl;
+ };
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Scalar can see and modify these
+ //------------------------------------------------------------------
+ Scalar::Type m_type;
+ ValueData m_data;
+
+private:
+ friend const Scalar operator+ (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator- (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator/ (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator* (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator& (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator| (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator% (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator^ (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator<< (const Scalar& lhs, const Scalar& rhs);
+ friend const Scalar operator>> (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator== (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator!= (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator< (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator<= (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator> (const Scalar& lhs, const Scalar& rhs);
+ friend bool operator>= (const Scalar& lhs, const Scalar& rhs);
+
+};
+
+//----------------------------------------------------------------------
+// Split out the operators into a format where the compiler will be able
+// to implicitly convert numbers into Scalar objects.
+//
+// This allows code like:
+// Scalar two(2);
+// Scalar four = two * 2;
+// Scalar eight = 2 * four; // This would cause an error if the
+// // operator* was implemented as a
+// // member function.
+// SEE:
+// Item 19 of "Effective C++ Second Edition" by Scott Meyers
+// Differentiate among members functions, non-member functions, and
+// friend functions
+//----------------------------------------------------------------------
+const Scalar operator+ (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator- (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator/ (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator* (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator& (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator| (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator% (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator^ (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator<< (const Scalar& lhs, const Scalar& rhs);
+const Scalar operator>> (const Scalar& lhs, const Scalar& rhs);
+bool operator== (const Scalar& lhs, const Scalar& rhs);
+bool operator!= (const Scalar& lhs, const Scalar& rhs);
+bool operator< (const Scalar& lhs, const Scalar& rhs);
+bool operator<= (const Scalar& lhs, const Scalar& rhs);
+bool operator> (const Scalar& lhs, const Scalar& rhs);
+bool operator>= (const Scalar& lhs, const Scalar& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_Scalar_h_
diff --git a/include/lldb/Core/SearchFilter.h b/include/lldb/Core/SearchFilter.h
new file mode 100644
index 000000000000..57f1b9c1a0a5
--- /dev/null
+++ b/include/lldb/Core/SearchFilter.h
@@ -0,0 +1,447 @@
+//===-- SearchFilter.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_SearchFilter_h_
+#define liblldb_SearchFilter_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/FileSpecList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Searcher SearchFilter.h "lldb/Core/SearchFilter.h"
+/// @brief Class that is driven by the SearchFilter to search the
+/// SymbolContext space of the target program.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// Provides the callback and search depth for the SearchFilter search.
+//----------------------------------------------------------------------
+
+class Searcher
+{
+public:
+ typedef enum {
+ eCallbackReturnStop = 0, // Stop the iteration
+ eCallbackReturnContinue, // Continue the iteration
+ eCallbackReturnPop // Pop one level up and continue iterating
+ } CallbackReturn;
+
+ typedef enum {
+ eDepthTarget,
+ eDepthModule,
+ eDepthCompUnit,
+ eDepthFunction,
+ eDepthBlock,
+ eDepthAddress
+ } Depth;
+
+ Searcher ();
+
+ virtual ~Searcher ();
+
+ virtual CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete) = 0;
+
+ virtual Depth
+ GetDepth () = 0;
+
+ //------------------------------------------------------------------
+ /// Prints a canonical description for the searcher to the stream \a s.
+ ///
+ /// @param[in] s
+ /// Stream to which the output is copied.
+ //------------------------------------------------------------------
+ virtual void
+ GetDescription(Stream *s);
+};
+
+//----------------------------------------------------------------------
+/// @class SearchFilter SearchFilter.h "lldb/Core/SearchFilter.h"
+/// @brief Class descends through the SymbolContext space of the target,
+/// applying a filter at each stage till it reaches the depth specified by
+/// the GetDepth method of the searcher, and calls its callback at that point.
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+/// General Outline:
+/// Provides the callback and search depth for the SearchFilter search.
+///
+/// The search is done by cooperation between the search filter and the searcher.
+/// The search filter does the heavy work of recursing through the SymbolContext
+/// space of the target program's symbol space. The Searcher specifies the depth
+/// at which it wants its callback to be invoked. Note that since the resolution
+/// of the Searcher may be greater than that of the SearchFilter, before the
+/// Searcher qualifies an address it should pass it to "AddressPasses."
+/// The default implementation is "Everything Passes."
+//----------------------------------------------------------------------
+
+class SearchFilter
+{
+public:
+
+ //------------------------------------------------------------------
+ /// The basic constructor takes a Target, which gives the space to search.
+ ///
+ /// @param[in] target
+ /// The Target that provides the module list to search.
+ //------------------------------------------------------------------
+ SearchFilter (const lldb::TargetSP &target_sp);
+
+ SearchFilter (const SearchFilter& rhs);
+
+ virtual
+ ~SearchFilter ();
+
+ const SearchFilter&
+ operator=(const SearchFilter& rhs);
+
+ //------------------------------------------------------------------
+ /// Call this method with a file spec to see if that spec passes the filter.
+ ///
+ /// @param[in] spec
+ /// The file spec to check against the filter.
+ /// @return
+ /// \b true if \a spec passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ModulePasses (const FileSpec &spec);
+
+ //------------------------------------------------------------------
+ /// Call this method with a Module to see if that module passes the filter.
+ ///
+ /// @param[in] module
+ /// The Module to check against the filter.
+ ///
+ /// @return
+ /// \b true if \a module passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ModulePasses (const lldb::ModuleSP &module_sp);
+
+ //------------------------------------------------------------------
+ /// Call this method with a Address to see if \a address passes the filter.
+ ///
+ /// @param[in] addr
+ /// The address to check against the filter.
+ ///
+ /// @return
+ /// \b true if \a address passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ AddressPasses (Address &addr);
+
+ //------------------------------------------------------------------
+ /// Call this method with a FileSpec to see if \a file spec passes the filter
+ /// as the name of a compilation unit.
+ ///
+ /// @param[in] fileSpec
+ /// The file spec to check against the filter.
+ ///
+ /// @return
+ /// \b true if \a file spec passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ CompUnitPasses (FileSpec &fileSpec);
+
+ //------------------------------------------------------------------
+ /// Call this method with a CompileUnit to see if \a comp unit passes the filter.
+ ///
+ /// @param[in] compUnit
+ /// The CompileUnit to check against the filter.
+ ///
+ /// @return
+ /// \b true if \a Comp Unit passes, and \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ CompUnitPasses (CompileUnit &compUnit);
+
+ //------------------------------------------------------------------
+ /// Call this method to do the search using the Searcher.
+ ///
+ /// @param[in] searcher
+ /// The searcher to drive with this search.
+ ///
+ //------------------------------------------------------------------
+ virtual void
+ Search (Searcher &searcher);
+
+ //------------------------------------------------------------------
+ /// Call this method to do the search using the Searcher in the module list
+ /// \a modules.
+ ///
+ /// @param[in] searcher
+ /// The searcher to drive with this search.
+ ///
+ /// @param[in] modules
+ /// The module list within which to restrict the search.
+ ///
+ //------------------------------------------------------------------
+ virtual void
+ SearchInModuleList (Searcher &searcher, ModuleList &modules);
+
+ //------------------------------------------------------------------
+ /// This determines which items are REQUIRED for the filter to pass.
+ /// For instance, if you are filtering by Compilation Unit, obviously
+ /// symbols that have no compilation unit can't pass So return eSymbolContextCU
+ /// and search callbacks can then short cut the search to avoid looking at
+ /// things that obviously won't pass.
+ ///
+ /// @return
+ /// The required elements for the search, which is an or'ed together
+ /// set of lldb:SearchContextItem enum's.
+ ///
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetFilterRequiredItems ();
+
+ //------------------------------------------------------------------
+ /// Prints a canonical description for the search filter to the stream \a s.
+ ///
+ /// @param[in] s
+ /// Stream to which the output is copied.
+ //------------------------------------------------------------------
+ virtual void
+ GetDescription(Stream *s);
+
+ //------------------------------------------------------------------
+ /// Standard "Dump" method. At present it does nothing.
+ //------------------------------------------------------------------
+ virtual void
+ Dump (Stream *s) const;
+
+protected:
+
+ // These are utility functions to assist with the search iteration. They are used by the
+ // default Search method.
+
+ Searcher::CallbackReturn
+ DoModuleIteration (const SymbolContext &context,
+ Searcher &searcher);
+
+ Searcher::CallbackReturn
+ DoModuleIteration (const lldb::ModuleSP& module_sp,
+ Searcher &searcher);
+
+ Searcher::CallbackReturn
+ DoCUIteration (const lldb::ModuleSP& module_sp,
+ const SymbolContext &context,
+ Searcher &searcher);
+
+ Searcher::CallbackReturn
+ DoFunctionIteration (Function *function,
+ const SymbolContext &context,
+ Searcher &searcher);
+
+ lldb::TargetSP m_target_sp; // Every filter has to be associated with a target for
+ // now since you need a starting place for the search.
+};
+
+//----------------------------------------------------------------------
+/// @class SearchFilterForNonModuleSpecificSearches SearchFilter.h "lldb/Core/SearchFilter.h"
+/// @brief This is a SearchFilter that searches through all modules. It also consults the Target::ModuleIsExcludedForNonModuleSpecificSearches.
+//----------------------------------------------------------------------
+class SearchFilterForNonModuleSpecificSearches :
+ public SearchFilter
+{
+public:
+ SearchFilterForNonModuleSpecificSearches (const lldb::TargetSP &targetSP) : SearchFilter(targetSP) {}
+ ~SearchFilterForNonModuleSpecificSearches () {}
+
+ virtual bool
+ ModulePasses (const FileSpec &module_spec);
+
+ virtual bool
+ ModulePasses (const lldb::ModuleSP &module_sp);
+};
+
+//----------------------------------------------------------------------
+/// @class SearchFilterByModule SearchFilter.h "lldb/Core/SearchFilter.h"
+/// @brief This is a SearchFilter that restricts the search to a given module.
+//----------------------------------------------------------------------
+
+class SearchFilterByModule :
+ public SearchFilter
+{
+public:
+
+ //------------------------------------------------------------------
+ /// The basic constructor takes a Target, which gives the space to search,
+ /// and the module to restrict the search to.
+ ///
+ /// @param[in] target
+ /// The Target that provides the module list to search.
+ ///
+ /// @param[in] module
+ /// The Module that limits the search.
+ //------------------------------------------------------------------
+ SearchFilterByModule (const lldb::TargetSP &targetSP,
+ const FileSpec &module);
+
+ SearchFilterByModule (const SearchFilterByModule& rhs);
+
+ virtual
+ ~SearchFilterByModule ();
+
+ const SearchFilterByModule&
+ operator=(const SearchFilterByModule& rhs);
+
+ virtual bool
+ ModulePasses (const lldb::ModuleSP &module_sp);
+
+ virtual bool
+ ModulePasses (const FileSpec &spec);
+
+ virtual bool
+ AddressPasses (Address &address);
+
+ virtual bool
+ CompUnitPasses (FileSpec &fileSpec);
+
+ virtual bool
+ CompUnitPasses (CompileUnit &compUnit);
+
+ virtual void
+ GetDescription(Stream *s);
+
+ virtual uint32_t
+ GetFilterRequiredItems ();
+
+ virtual void
+ Dump (Stream *s) const;
+
+ virtual void
+ Search (Searcher &searcher);
+
+private:
+ FileSpec m_module_spec;
+};
+
+class SearchFilterByModuleList :
+ public SearchFilter
+{
+public:
+
+ //------------------------------------------------------------------
+ /// The basic constructor takes a Target, which gives the space to search,
+ /// and the module list to restrict the search to.
+ ///
+ /// @param[in] target
+ /// The Target that provides the module list to search.
+ ///
+ /// @param[in] module
+ /// The Module that limits the search.
+ //------------------------------------------------------------------
+ SearchFilterByModuleList (const lldb::TargetSP &targetSP,
+ const FileSpecList &module_list);
+
+ SearchFilterByModuleList (const SearchFilterByModuleList& rhs);
+
+ virtual
+ ~SearchFilterByModuleList ();
+
+ const SearchFilterByModuleList&
+ operator=(const SearchFilterByModuleList& rhs);
+
+ virtual bool
+ ModulePasses (const lldb::ModuleSP &module_sp);
+
+ virtual bool
+ ModulePasses (const FileSpec &spec);
+
+ virtual bool
+ AddressPasses (Address &address);
+
+ virtual bool
+ CompUnitPasses (FileSpec &fileSpec);
+
+ virtual bool
+ CompUnitPasses (CompileUnit &compUnit);
+
+ virtual void
+ GetDescription(Stream *s);
+
+ virtual uint32_t
+ GetFilterRequiredItems ();
+
+ virtual void
+ Dump (Stream *s) const;
+
+ virtual void
+ Search (Searcher &searcher);
+
+private:
+ FileSpecList m_module_spec_list;
+};
+
+class SearchFilterByModuleListAndCU :
+ public SearchFilterByModuleList
+{
+public:
+
+ //------------------------------------------------------------------
+ /// The basic constructor takes a Target, which gives the space to search,
+ /// and the module list to restrict the search to.
+ ///
+ /// @param[in] target
+ /// The Target that provides the module list to search.
+ ///
+ /// @param[in] module
+ /// The Module that limits the search.
+ //------------------------------------------------------------------
+ SearchFilterByModuleListAndCU (const lldb::TargetSP &targetSP,
+ const FileSpecList &module_list,
+ const FileSpecList &cu_list);
+
+ SearchFilterByModuleListAndCU (const SearchFilterByModuleListAndCU& rhs);
+
+ virtual
+ ~SearchFilterByModuleListAndCU ();
+
+ const SearchFilterByModuleListAndCU&
+ operator=(const SearchFilterByModuleListAndCU& rhs);
+
+ virtual bool
+ AddressPasses (Address &address);
+
+ virtual bool
+ CompUnitPasses (FileSpec &fileSpec);
+
+ virtual bool
+ CompUnitPasses (CompileUnit &compUnit);
+
+ virtual void
+ GetDescription(Stream *s);
+
+ virtual uint32_t
+ GetFilterRequiredItems ();
+
+ virtual void
+ Dump (Stream *s) const;
+
+ virtual void
+ Search (Searcher &searcher);
+
+private:
+ FileSpecList m_module_spec_list;
+ FileSpecList m_cu_spec_list;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_SearchFilter_h_
diff --git a/include/lldb/Core/Section.h b/include/lldb/Core/Section.h
new file mode 100644
index 000000000000..437eaf59b9c4
--- /dev/null
+++ b/include/lldb/Core/Section.h
@@ -0,0 +1,313 @@
+//===-- Section.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_Section_h_
+#define liblldb_Section_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/VMRange.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include <limits.h>
+
+namespace lldb_private {
+
+class SectionList
+{
+public:
+ typedef std::vector<lldb::SectionSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ SectionList();
+
+ ~SectionList();
+
+ SectionList &
+ operator =(const SectionList& rhs);
+
+ size_t
+ AddSection (const lldb::SectionSP& section_sp);
+
+ size_t
+ AddUniqueSection (const lldb::SectionSP& section_sp);
+
+ size_t
+ FindSectionIndex (const Section* sect);
+
+ bool
+ ContainsSection(lldb::user_id_t sect_id) const;
+
+ void
+ Dump (Stream *s, Target *target, bool show_header, uint32_t depth) const;
+
+ lldb::SectionSP
+ FindSectionByName (const ConstString &section_dstr) const;
+
+ lldb::SectionSP
+ FindSectionByID (lldb::user_id_t sect_id) const;
+
+ lldb::SectionSP
+ FindSectionByType (lldb::SectionType sect_type, bool check_children, size_t start_idx = 0) const;
+
+ lldb::SectionSP
+ FindSectionContainingFileAddress (lldb::addr_t addr, uint32_t depth = UINT32_MAX) const;
+
+ bool
+ GetSectionData (const DataExtractor& module_data, DataExtractor& section_data) const;
+
+ // Get the number of sections in this list only
+ size_t
+ GetSize () const
+ {
+ return m_sections.size();
+ }
+
+ // Get the number of sections in this list, and any contained child sections
+ size_t
+ GetNumSections (uint32_t depth) const;
+
+ bool
+ ReplaceSection (lldb::user_id_t sect_id, const lldb::SectionSP& section_sp, uint32_t depth = UINT32_MAX);
+
+ // Warning, this can be slow as it's removing items from a std::vector.
+ bool
+ DeleteSection (size_t idx);
+
+ lldb::SectionSP
+ GetSectionAtIndex (size_t idx) const;
+
+ size_t
+ Slide (lldb::addr_t slide_amount, bool slide_children);
+
+ void
+ Clear ()
+ {
+ m_sections.clear();
+ }
+
+protected:
+ collection m_sections;
+};
+
+
+class Section :
+ public std::enable_shared_from_this<Section>,
+ public ModuleChild,
+ public UserID,
+ public Flags
+{
+public:
+ // Create a root section (one that has no parent)
+ Section (const lldb::ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ lldb::user_id_t sect_id,
+ const ConstString &name,
+ lldb::SectionType sect_type,
+ lldb::addr_t file_vm_addr,
+ lldb::addr_t vm_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags);
+
+ // Create a section that is a child of parent_section_sp
+ Section (const lldb::SectionSP &parent_section_sp, // NULL for top level sections, non-NULL for child sections
+ const lldb::ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ lldb::user_id_t sect_id,
+ const ConstString &name,
+ lldb::SectionType sect_type,
+ lldb::addr_t file_vm_addr,
+ lldb::addr_t vm_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags);
+
+ ~Section ();
+
+ static int
+ Compare (const Section& a, const Section& b);
+
+ bool
+ ContainsFileAddress (lldb::addr_t vm_addr) const;
+
+ SectionList&
+ GetChildren ()
+ {
+ return m_children;
+ }
+
+ const SectionList&
+ GetChildren () const
+ {
+ return m_children;
+ }
+
+ void
+ Dump (Stream *s, Target *target, uint32_t depth) const;
+
+ void
+ DumpName (Stream *s) const;
+
+ lldb::addr_t
+ GetLoadBaseAddress (Target *target) const;
+
+ bool
+ ResolveContainedAddress (lldb::addr_t offset, Address &so_addr) const;
+
+ lldb::offset_t
+ GetFileOffset () const
+ {
+ return m_file_offset;
+ }
+
+ void
+ SetFileOffset (lldb::offset_t file_offset)
+ {
+ m_file_offset = file_offset;
+ }
+
+ lldb::offset_t
+ GetFileSize () const
+ {
+ return m_file_size;
+ }
+
+ void
+ SetFileSize (lldb::offset_t file_size)
+ {
+ m_file_size = file_size;
+ }
+
+ lldb::addr_t
+ GetFileAddress () const;
+
+ bool
+ SetFileAddress (lldb::addr_t file_addr);
+
+ lldb::addr_t
+ GetOffset () const;
+
+
+ lldb::addr_t
+ GetByteSize () const
+ {
+ return m_byte_size;
+ }
+
+ void
+ SetByteSize (lldb::addr_t byte_size)
+ {
+ m_byte_size = byte_size;
+ }
+
+ bool
+ IsFake() const
+ {
+ return m_fake;
+ }
+
+ void
+ SetIsFake(bool fake)
+ {
+ m_fake = fake;
+ }
+
+ bool
+ IsEncrypted () const
+ {
+ return m_encrypted;
+ }
+
+ void
+ SetIsEncrypted (bool b)
+ {
+ m_encrypted = b;
+ }
+
+ bool
+ IsDescendant (const Section *section);
+
+ const ConstString&
+ GetName () const
+ {
+ return m_name;
+ }
+
+ bool
+ Slide (lldb::addr_t slide_amount, bool slide_children);
+
+
+ lldb::SectionType
+ GetType () const
+ {
+ return m_type;
+ }
+
+ lldb::SectionSP
+ GetParent () const
+ {
+ return m_parent_wp.lock();
+ }
+
+ bool
+ IsThreadSpecific () const
+ {
+ return m_thread_specific;
+ }
+
+ void
+ SetIsThreadSpecific (bool b)
+ {
+ m_thread_specific = b;
+ }
+
+ ObjectFile *
+ GetObjectFile ()
+ {
+ return m_obj_file;
+ }
+ const ObjectFile *
+ GetObjectFile () const
+ {
+ return m_obj_file;
+ }
+
+
+protected:
+
+ ObjectFile *m_obj_file; // The object file that data for this section should be read from
+ lldb::SectionType m_type; // The type of this section
+ lldb::SectionWP m_parent_wp; // Weak pointer to parent section
+ ConstString m_name; // Name of this section
+ lldb::addr_t m_file_addr; // The absolute file virtual address range of this section if m_parent == NULL,
+ // offset from parent file virtual address if m_parent != NULL
+ lldb::addr_t m_byte_size; // Size in bytes that this section will occupy in memory at runtime
+ lldb::offset_t m_file_offset; // Object file offset (if any)
+ lldb::offset_t m_file_size; // Object file size (can be smaller than m_byte_size for zero filled sections...)
+ SectionList m_children; // Child sections
+ bool m_fake:1, // If true, then this section only can contain the address if one of its
+ // children contains an address. This allows for gaps between the children
+ // that are contained in the address range for this section, but do not produce
+ // hits unless the children contain the address.
+ m_encrypted:1, // Set to true if the contents are encrypted
+ m_thread_specific:1;// This section is thread specific
+private:
+ DISALLOW_COPY_AND_ASSIGN (Section);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Section_h_
diff --git a/include/lldb/Core/SourceManager.h b/include/lldb/Core/SourceManager.h
new file mode 100644
index 000000000000..b850df774bac
--- /dev/null
+++ b/include/lldb/Core/SourceManager.h
@@ -0,0 +1,196 @@
+//===-- SourceManager.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_SourceManager_h_
+#define liblldb_SourceManager_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private {
+
+class SourceManager
+{
+public:
+#ifndef SWIG
+
+ class File
+ {
+ friend bool operator== (const SourceManager::File &lhs, const SourceManager::File &rhs);
+ public:
+
+ File (const FileSpec &file_spec, Target *target);
+ ~File();
+
+ size_t
+ DisplaySourceLines (uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ Stream *s);
+ void
+ FindLinesMatchingRegex (RegularExpression& regex,
+ uint32_t start_line,
+ uint32_t end_line,
+ std::vector<uint32_t> &match_lines);
+
+ bool
+ GetLine (uint32_t line_no, std::string &buffer);
+
+ uint32_t
+ GetLineOffset (uint32_t line);
+
+ bool
+ LineIsValid (uint32_t line);
+
+ bool
+ FileSpecMatches (const FileSpec &file_spec);
+
+ const FileSpec &
+ GetFileSpec ()
+ {
+ return m_file_spec;
+ }
+
+ uint32_t
+ GetSourceMapModificationID() const
+ {
+ return m_source_map_mod_id;
+ }
+
+ protected:
+
+ bool
+ CalculateLineOffsets (uint32_t line = UINT32_MAX);
+
+ FileSpec m_file_spec_orig; // The original file spec that was used (can be different from m_file_spec)
+ FileSpec m_file_spec; // The actualy file spec being used (if the target has source mappings, this might be different from m_file_spec_orig)
+ TimeValue m_mod_time; // Keep the modification time that this file data is valid for
+ uint32_t m_source_map_mod_id; // If the target uses path remappings, be sure to clear our notion of a source file if the path modification ID changes
+ lldb::DataBufferSP m_data_sp;
+ typedef std::vector<uint32_t> LineOffsets;
+ LineOffsets m_offsets;
+ };
+
+#endif // SWIG
+
+ typedef std::shared_ptr<File> FileSP;
+
+#ifndef SWIG
+
+ // The SourceFileCache class separates the source manager from the cache of source files, so the
+ // cache can be stored in the Debugger, but the source managers can be per target.
+ class SourceFileCache
+ {
+ public:
+ SourceFileCache () {}
+ ~SourceFileCache() {}
+
+ void AddSourceFile (const FileSP &file_sp);
+ FileSP FindSourceFile (const FileSpec &file_spec) const;
+
+ protected:
+ typedef std::map <FileSpec, FileSP> FileCache;
+ FileCache m_file_cache;
+ };
+#endif
+
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ // A source manager can be made with a non-null target, in which case it can use the path remappings to find
+ // source files that are not in their build locations. With no target it won't be able to do this.
+ SourceManager (const lldb::DebuggerSP &debugger_sp);
+ SourceManager (const lldb::TargetSP &target_sp);
+
+ ~SourceManager();
+
+
+ FileSP
+ GetLastFile ()
+ {
+ return m_last_file_sp;
+ }
+
+ size_t
+ DisplaySourceLinesWithLineNumbers (const FileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs = NULL);
+
+ // This variant uses the last file we visited.
+ size_t
+ DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line,
+ uint32_t count,
+ uint32_t curr_line,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs = NULL);
+
+ size_t
+ DisplayMoreWithLineNumbers (Stream *s,
+ uint32_t count,
+ bool reverse,
+ const SymbolContextList *bp_locs = NULL);
+
+ bool
+ SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line);
+
+ bool
+ GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line);
+
+ bool
+ DefaultFileAndLineSet ()
+ {
+ return (m_last_file_sp.get() != NULL);
+ }
+
+ void
+ FindLinesMatchingRegex (FileSpec &file_spec,
+ RegularExpression& regex,
+ uint32_t start_line,
+ uint32_t end_line,
+ std::vector<uint32_t> &match_lines);
+
+protected:
+
+ FileSP
+ GetFile (const FileSpec &file_spec);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from SourceManager can see and modify these
+ //------------------------------------------------------------------
+ FileSP m_last_file_sp;
+ uint32_t m_last_line;
+ uint32_t m_last_count;
+ bool m_default_set;
+ lldb::TargetWP m_target_wp;
+ lldb::DebuggerWP m_debugger_wp;
+
+private:
+ //------------------------------------------------------------------
+ // For SourceManager only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (SourceManager);
+};
+
+bool operator== (const SourceManager::File &lhs, const SourceManager::File &rhs);
+} // namespace lldb_private
+
+#endif // liblldb_SourceManager_h_
diff --git a/include/lldb/Core/State.h b/include/lldb/Core/State.h
new file mode 100644
index 000000000000..8057b3e0584c
--- /dev/null
+++ b/include/lldb/Core/State.h
@@ -0,0 +1,78 @@
+//===-- State.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_State_h_
+#define liblldb_State_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//------------------------------------------------------------------
+/// Converts a StateType to a C string.
+///
+/// @param[in] state
+/// The StateType object to convert.
+///
+/// @return
+/// A NULL terminated C string that describes \a state. The
+/// returned string comes from constant string buffers and does
+/// not need to be freed.
+//------------------------------------------------------------------
+const char *
+StateAsCString (lldb::StateType state);
+
+//------------------------------------------------------------------
+/// Check if a state represents a state where the process or thread
+/// is running.
+///
+/// @param[in] state
+/// The StateType enumeration value
+///
+/// @return
+/// \b true if the state represents a process or thread state
+/// where the process or thread is running, \b false otherwise.
+//------------------------------------------------------------------
+bool
+StateIsRunningState (lldb::StateType state);
+
+//------------------------------------------------------------------
+/// Check if a state represents a state where the process or thread
+/// is stopped. Stopped can mean stopped when the process is still
+/// around, or stopped when the process has exited or doesn't exist
+/// yet. The \a must_exist argument tells us which of these cases is
+/// desired.
+///
+/// @param[in] state
+/// The StateType enumeration value
+///
+/// @param[in] must_exist
+/// A boolean that indicates the thread must also be alive
+/// so states like unloaded or exited won't return true.
+///
+/// @return
+/// \b true if the state represents a process or thread state
+/// where the process or thread is stopped. If \a must_exist is
+/// \b true, then the process can't be exited or unloaded,
+/// otherwise exited and unloaded or other states where the
+/// process no longer exists are considered to be stopped.
+//------------------------------------------------------------------
+bool
+StateIsStoppedState (lldb::StateType state, bool must_exist);
+
+const char *
+GetPermissionsAsCString (uint32_t permissions);
+
+} // namespace lldb_private
+
+#endif // liblldb_State_h_
diff --git a/include/lldb/Core/Stream.h b/include/lldb/Core/Stream.h
new file mode 100644
index 000000000000..0fd4aac041a9
--- /dev/null
+++ b/include/lldb/Core/Stream.h
@@ -0,0 +1,612 @@
+//===-- Stream.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_Stream_h_
+#define liblldb_Stream_h_
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Flags.h"
+#include <stdarg.h>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Stream Stream.h "lldb/Core/Stream.h"
+/// @brief A stream class that can stream formatted output to a file.
+//----------------------------------------------------------------------
+class Stream
+{
+public:
+ //------------------------------------------------------------------
+ /// \a m_flags bit values.
+ //------------------------------------------------------------------
+ enum
+ {
+ eVerbose = (1 << 0), ///< If set, verbose logging is enabled
+ eDebug = (1 << 1), ///< If set, debug logging is enabled
+ eAddPrefix = (1 << 2), ///< Add number prefixes for binary, octal and hex when eBinary is clear
+ eBinary = (1 << 3) ///< Get and put data as binary instead of as the default string mode.
+ };
+
+ //------------------------------------------------------------------
+ /// Construct with flags and address size and byte order.
+ ///
+ /// Construct with dump flags \a flags and the default address
+ /// size. \a flags can be any of the above enumeration logical OR'ed
+ /// together.
+ //------------------------------------------------------------------
+ Stream (uint32_t flags,
+ uint32_t addr_size,
+ lldb::ByteOrder byte_order);
+
+ //------------------------------------------------------------------
+ /// Construct a default Stream, not binary, host byte order and
+ /// host addr size.
+ ///
+ //------------------------------------------------------------------
+ Stream ();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual
+ ~Stream ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these methods
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Flush the stream.
+ ///
+ /// Subclasses should flush the stream to make any output appear
+ /// if the stream has any buffering.
+ //------------------------------------------------------------------
+ virtual void
+ Flush () = 0;
+
+ //------------------------------------------------------------------
+ /// Output character bytes to the stream.
+ ///
+ /// Appends \a src_len characters from the buffer \a src to the
+ /// stream.
+ ///
+ /// @param[in] src
+ /// A buffer containing at least \a src_len bytes of data.
+ ///
+ /// @param[in] src_len
+ /// A number of bytes to append to the stream.
+ ///
+ /// @return
+ /// The number of bytes that were appended to the stream.
+ //------------------------------------------------------------------
+ virtual size_t
+ Write (const void *src, size_t src_len) = 0;
+
+ //------------------------------------------------------------------
+ // Member functions
+ //------------------------------------------------------------------
+ size_t
+ PutChar (char ch);
+
+ //------------------------------------------------------------------
+ /// Set the byte_order value.
+ ///
+ /// Sets the byte order of the data to extract. Extracted values
+ /// will be swapped if necessary when decoding.
+ ///
+ /// @param[in] byte_order
+ /// The byte order value to use when extracting data.
+ ///
+ /// @return
+ /// The old byte order value.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ SetByteOrder (lldb::ByteOrder byte_order);
+
+ //------------------------------------------------------------------
+ /// Format a C string from a printf style format and variable
+ /// arguments and encode and append the resulting C string as hex
+ /// bytes.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Any additional arguments needed for the printf format string.
+ ///
+ /// @return
+ /// The number of bytes that were appended to the stream.
+ //------------------------------------------------------------------
+ size_t
+ PrintfAsRawHex8 (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ //------------------------------------------------------------------
+ /// Format a C string from a printf style format and variable
+ /// arguments and encode and append the resulting C string as hex
+ /// bytes.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Any additional arguments needed for the printf format string.
+ ///
+ /// @return
+ /// The number of bytes that were appended to the stream.
+ //------------------------------------------------------------------
+ size_t
+ PutHex8 (uint8_t uvalue);
+
+ size_t
+ PutNHex8 (size_t n, uint8_t uvalue);
+
+ size_t
+ PutHex16 (uint16_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutHex32 (uint32_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutHex64 (uint64_t uvalue,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutMaxHex64 (uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+ size_t
+ PutFloat (float f,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutDouble (double d,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutLongDouble (long double ld,
+ lldb::ByteOrder byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutPointer (void *ptr);
+
+ // Append \a src_len bytes from \a src to the stream as hex characters
+ // (two ascii characters per byte of input data)
+ size_t
+ PutBytesAsRawHex8 (const void *src,
+ size_t src_len,
+ lldb::ByteOrder src_byte_order = lldb::eByteOrderInvalid,
+ lldb::ByteOrder dst_byte_order = lldb::eByteOrderInvalid);
+
+ // Append \a src_len bytes from \a s to the stream as binary data.
+ size_t
+ PutRawBytes (const void *s,
+ size_t src_len,
+ lldb::ByteOrder src_byte_order = lldb::eByteOrderInvalid,
+ lldb::ByteOrder dst_byte_order = lldb::eByteOrderInvalid);
+
+ size_t
+ PutCStringAsRawHex8 (const char *s);
+
+ //------------------------------------------------------------------
+ /// Output a NULL terminated C string \a cstr to the stream \a s.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (const char *cstr);
+
+ //------------------------------------------------------------------
+ /// Output a pointer value \a p to the stream \a s.
+ ///
+ /// @param[in] p
+ /// A void pointer.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (void *p);
+
+ //------------------------------------------------------------------
+ /// Output a character \a ch to the stream \a s.
+ ///
+ /// @param[in] ch
+ /// A printable character value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (char ch);
+
+ //------------------------------------------------------------------
+ /// Output a uint8_t \a uval to the stream \a s.
+ ///
+ /// @param[in] uval
+ /// A uint8_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (uint8_t uval);
+
+ //------------------------------------------------------------------
+ /// Output a uint16_t \a uval to the stream \a s.
+ ///
+ /// @param[in] uval
+ /// A uint16_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (uint16_t uval);
+
+ //------------------------------------------------------------------
+ /// Output a uint32_t \a uval to the stream \a s.
+ ///
+ /// @param[in] uval
+ /// A uint32_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (uint32_t uval);
+
+ //------------------------------------------------------------------
+ /// Output a uint64_t \a uval to the stream \a s.
+ ///
+ /// @param[in] uval
+ /// A uint64_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (uint64_t uval);
+
+ //------------------------------------------------------------------
+ /// Output a int8_t \a sval to the stream \a s.
+ ///
+ /// @param[in] sval
+ /// A int8_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (int8_t sval);
+
+ //------------------------------------------------------------------
+ /// Output a int16_t \a sval to the stream \a s.
+ ///
+ /// @param[in] sval
+ /// A int16_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (int16_t sval);
+
+ //------------------------------------------------------------------
+ /// Output a int32_t \a sval to the stream \a s.
+ ///
+ /// @param[in] sval
+ /// A int32_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (int32_t sval);
+
+ //------------------------------------------------------------------
+ /// Output a int64_t \a sval to the stream \a s.
+ ///
+ /// @param[in] sval
+ /// A int64_t value.
+ ///
+ /// @return
+ /// A reference to this class so multiple things can be streamed
+ /// in one statement.
+ //------------------------------------------------------------------
+ Stream&
+ operator<< (int64_t sval);
+
+ //------------------------------------------------------------------
+ /// Output an address value to this stream.
+ ///
+ /// Put an address \a addr out to the stream with optional \a prefix
+ /// and \a suffix strings.
+ ///
+ /// @param[in] addr
+ /// An address value.
+ ///
+ /// @param[in] addr_size
+ /// Size in bytes of the address, used for formatting.
+ ///
+ /// @param[in] prefix
+ /// A prefix C string. If NULL, no prefix will be output.
+ ///
+ /// @param[in] suffix
+ /// A suffix C string. If NULL, no suffix will be output.
+ //------------------------------------------------------------------
+ void
+ Address (uint64_t addr, uint32_t addr_size, const char *prefix = NULL, const char *suffix = NULL);
+
+ //------------------------------------------------------------------
+ /// Output an address range to this stream.
+ ///
+ /// Put an address range \a lo_addr - \a hi_addr out to the stream
+ /// with optional \a prefix and \a suffix strings.
+ ///
+ /// @param[in] lo_addr
+ /// The start address of the address range.
+ ///
+ /// @param[in] hi_addr
+ /// The end address of the address range.
+ ///
+ /// @param[in] addr_size
+ /// Size in bytes of the address, used for formatting.
+ ///
+ /// @param[in] prefix
+ /// A prefix C string. If NULL, no prefix will be output.
+ ///
+ /// @param[in] suffix
+ /// A suffix C string. If NULL, no suffix will be output.
+ //------------------------------------------------------------------
+ void
+ AddressRange(uint64_t lo_addr, uint64_t hi_addr, uint32_t addr_size, const char *prefix = NULL, const char *suffix = NULL);
+
+ //------------------------------------------------------------------
+ /// Output a C string to the stream.
+ ///
+ /// Print a C string \a cstr to the stream.
+ ///
+ /// @param[in] cstr
+ /// The string to be output to the stream.
+ //------------------------------------------------------------------
+ size_t
+ PutCString (const char *cstr);
+
+ //------------------------------------------------------------------
+ /// Output and End of Line character to the stream.
+ //------------------------------------------------------------------
+ size_t
+ EOL();
+
+ //------------------------------------------------------------------
+ /// Get the address size in bytes.
+ ///
+ /// @return
+ /// The size of an address in bytes that is used when outputting
+ /// address and pointer values to the stream.
+ //------------------------------------------------------------------
+ uint32_t
+ GetAddressByteSize () const;
+
+ //------------------------------------------------------------------
+ /// Test if debug logging is enabled.
+ ///
+ /// @return
+ // \b true if the debug flag bit is set in this stream, \b
+ // false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetDebug() const;
+
+ //------------------------------------------------------------------
+ /// The flags accessor.
+ ///
+ /// @return
+ /// A reference to the Flags member variable.
+ //------------------------------------------------------------------
+ Flags&
+ GetFlags();
+
+ //------------------------------------------------------------------
+ /// The flags const accessor.
+ ///
+ /// @return
+ /// A const reference to the Flags member variable.
+ //------------------------------------------------------------------
+ const Flags&
+ GetFlags() const;
+
+ //------------------------------------------------------------------
+ //// The byte order accessor.
+ ////
+ //// @return
+ //// The byte order.
+ //------------------------------------------------------------------
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ //------------------------------------------------------------------
+ /// Get the current indentation level.
+ ///
+ /// @return
+ /// The current indentation level as an integer.
+ //------------------------------------------------------------------
+ int
+ GetIndentLevel () const;
+
+ //------------------------------------------------------------------
+ /// Test if verbose logging is enabled.
+ ///
+ /// @return
+ // \b true if the verbose flag bit is set in this stream, \b
+ // false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetVerbose() const;
+
+ //------------------------------------------------------------------
+ /// Indent the current line in the stream.
+ ///
+ /// Indent the current line using the current indentation level and
+ /// print an optional string following the idenatation spaces.
+ ///
+ /// @param[in] s
+ /// A C string to print following the indentation. If NULL, just
+ /// output the indentation characters.
+ //------------------------------------------------------------------
+ size_t
+ Indent(const char *s = NULL);
+
+ //------------------------------------------------------------------
+ /// Decrement the current indentation level.
+ //------------------------------------------------------------------
+ void
+ IndentLess (int amount = 2);
+
+ //------------------------------------------------------------------
+ /// Increment the current indentation level.
+ //------------------------------------------------------------------
+ void
+ IndentMore (int amount = 2);
+
+ //------------------------------------------------------------------
+ /// Output an offset value.
+ ///
+ /// Put an offset \a uval out to the stream using the printf format
+ /// in \a format.
+ ///
+ /// @param[in] offset
+ /// The offset value.
+ ///
+ /// @param[in] format
+ /// The printf style format to use when outputting the offset.
+ //------------------------------------------------------------------
+ void
+ Offset (uint32_t offset, const char *format = "0x%8.8x: ");
+
+ //------------------------------------------------------------------
+ /// Output printf formatted output to the stream.
+ ///
+ /// Print some formatted output to the stream.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Variable arguments that are needed for the printf style
+ /// format string \a format.
+ //------------------------------------------------------------------
+ size_t
+ Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ size_t
+ PrintfVarArg(const char *format, va_list args);
+
+ //------------------------------------------------------------------
+ /// Output a quoted C string value to the stream.
+ ///
+ /// Print a double quoted NULL terminated C string to the stream
+ /// using the printf format in \a format.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminated C string value.
+ ///
+ /// @param[in] format
+ /// The optional C string format that can be overridden.
+ //------------------------------------------------------------------
+ void
+ QuotedCString (const char *cstr, const char *format = "\"%s\"");
+
+ //------------------------------------------------------------------
+ /// Set the address size in bytes.
+ ///
+ /// @param[in] addr_size
+ /// The new size in bytes of an address to use when outputting
+ /// address and pointer values.
+ //------------------------------------------------------------------
+ void
+ SetAddressByteSize (uint32_t addr_size);
+
+ //------------------------------------------------------------------
+ /// Set the current indentation level.
+ ///
+ /// @param[in] level
+ /// The new indentation level.
+ //------------------------------------------------------------------
+ void
+ SetIndentLevel (int level);
+
+ //------------------------------------------------------------------
+ /// Output a SLEB128 number to the stream.
+ ///
+ /// Put an SLEB128 \a uval out to the stream using the printf format
+ /// in \a format.
+ ///
+ /// @param[in] uval
+ /// A uint64_t value that was extracted as a SLEB128 value.
+ ///
+ /// @param[in] format
+ /// The optional printf format that can be overridden.
+ //------------------------------------------------------------------
+ size_t
+ PutSLEB128 (int64_t uval);
+
+ //------------------------------------------------------------------
+ /// Output a ULEB128 number to the stream.
+ ///
+ /// Put an ULEB128 \a uval out to the stream using the printf format
+ /// in \a format.
+ ///
+ /// @param[in] uval
+ /// A uint64_t value that was extracted as a ULEB128 value.
+ ///
+ /// @param[in] format
+ /// The optional printf format that can be overridden.
+ //------------------------------------------------------------------
+ size_t
+ PutULEB128 (uint64_t uval);
+
+ static void
+ UnitTest(Stream *s);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Flags m_flags; ///< Dump flags.
+ uint32_t m_addr_size; ///< Size of an address in bytes.
+ lldb::ByteOrder m_byte_order; ///< Byte order to use when encoding scalar types.
+ int m_indent_level; ///< Indention level.
+
+ size_t _PutHex8 (uint8_t uvalue, bool add_prefix);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Stream_h_
+
diff --git a/include/lldb/Core/StreamAsynchronousIO.h b/include/lldb/Core/StreamAsynchronousIO.h
new file mode 100644
index 000000000000..0e3e9ee9bcf1
--- /dev/null
+++ b/include/lldb/Core/StreamAsynchronousIO.h
@@ -0,0 +1,42 @@
+//===-- StreamAsynchronousIO.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_StreamAsynchronousIO_h_
+#define liblldb_StreamAsynchronousIO_h_
+
+#include <string>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+
+namespace lldb_private {
+
+class StreamAsynchronousIO :
+ public Stream
+{
+public:
+ StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);
+
+ virtual ~StreamAsynchronousIO ();
+
+ virtual void
+ Flush ();
+
+ virtual size_t
+ Write (const void *src, size_t src_len);
+
+
+private:
+ Broadcaster &m_broadcaster;
+ uint32_t m_broadcast_event_type;
+ StreamString m_accumulated_data;
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamAsynchronousIO_h
diff --git a/include/lldb/Core/StreamBuffer.h b/include/lldb/Core/StreamBuffer.h
new file mode 100644
index 000000000000..9d25e842ecc5
--- /dev/null
+++ b/include/lldb/Core/StreamBuffer.h
@@ -0,0 +1,87 @@
+//===-- StreamBuffer.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_StreamBuffer_h_
+#define liblldb_StreamBuffer_h_
+
+#include <stdio.h>
+#include <string>
+#include "llvm/ADT/SmallVector.h"
+#include "lldb/Core/Stream.h"
+
+namespace lldb_private {
+
+template <unsigned N>
+class StreamBuffer : public Stream
+{
+public:
+ StreamBuffer () :
+ Stream (0, 4, lldb::eByteOrderBig),
+ m_packet ()
+ {
+ }
+
+
+ StreamBuffer (uint32_t flags,
+ uint32_t addr_size,
+ lldb::ByteOrder byte_order) :
+ Stream (flags, addr_size, byte_order),
+ m_packet ()
+ {
+ }
+
+ virtual
+ ~StreamBuffer ()
+ {
+ }
+
+ virtual void
+ Flush ()
+ {
+ // Nothing to do when flushing a buffer based stream...
+ }
+
+ virtual size_t
+ Write (const void *s, size_t length)
+ {
+ if (s && length)
+ m_packet.append ((const char *)s, ((const char *)s) + length);
+ return length;
+ }
+
+ void
+ Clear()
+ {
+ m_packet.clear();
+ }
+
+ // Beware, this might not be NULL terminated as you can expect from
+ // StringString as there may be random bits in the llvm::SmallVector. If
+ // you are using this class to create a C string, be sure the call PutChar ('\0')
+ // after you have created your string, or use StreamString.
+ const char *
+ GetData () const
+ {
+ return m_packet.data();
+ }
+
+ size_t
+ GetSize() const
+ {
+ return m_packet.size();
+ }
+
+protected:
+ llvm::SmallVector<char, N> m_packet;
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_StreamBuffer_h_
diff --git a/include/lldb/Core/StreamCallback.h b/include/lldb/Core/StreamCallback.h
new file mode 100644
index 000000000000..b5fb91c6ce07
--- /dev/null
+++ b/include/lldb/Core/StreamCallback.h
@@ -0,0 +1,47 @@
+//===-- StreamCallback.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_StreamCallback_h_
+#define liblldb_StreamCallback_h_
+
+#include <string>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class StreamCallback :
+ public Stream
+{
+public:
+ StreamCallback (lldb::LogOutputCallback callback, void *baton);
+
+ virtual ~StreamCallback ();
+
+ virtual void
+ Flush ();
+
+ virtual size_t
+ Write (const void *src, size_t src_len);
+
+
+private:
+ typedef std::map<lldb::tid_t, StreamString> collection;
+ lldb::LogOutputCallback m_callback;
+ void *m_baton;
+ collection m_accumulated_data;
+ Mutex m_collection_mutex;
+
+ StreamString &FindStreamForThread(lldb::tid_t cur_tid);
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamCallback_h
diff --git a/include/lldb/Core/StreamFile.h b/include/lldb/Core/StreamFile.h
new file mode 100644
index 000000000000..d032c0b21e6b
--- /dev/null
+++ b/include/lldb/Core/StreamFile.h
@@ -0,0 +1,75 @@
+//===-- StreamFile.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_StreamFile_h_
+#define liblldb_StreamFile_h_
+
+// C Includes
+// C++ Includes
+
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/File.h"
+
+namespace lldb_private {
+
+class StreamFile : public Stream
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StreamFile ();
+
+ StreamFile (uint32_t flags, uint32_t addr_size, lldb::ByteOrder byte_order);
+
+ StreamFile (int fd, bool transfer_ownership);
+
+ StreamFile (const char *path);
+
+ StreamFile (FILE *fh, bool transfer_ownership);
+
+ virtual
+ ~StreamFile();
+
+ File &
+ GetFile ()
+ {
+ return m_file;
+ }
+
+ const File &
+ GetFile () const
+ {
+ return m_file;
+ }
+
+ virtual void
+ Flush ();
+
+ virtual size_t
+ Write (const void *s, size_t length);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from StreamFile can see and modify these
+ //------------------------------------------------------------------
+ File m_file;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (StreamFile);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StreamFile_h_
diff --git a/include/lldb/Core/StreamString.h b/include/lldb/Core/StreamString.h
new file mode 100644
index 000000000000..a26ad2d16a05
--- /dev/null
+++ b/include/lldb/Core/StreamString.h
@@ -0,0 +1,64 @@
+//===-- StreamString.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_StreamString_h_
+#define liblldb_StreamString_h_
+
+#include <string>
+
+#include "lldb/Core/Stream.h"
+
+namespace lldb_private {
+
+class StreamString : public Stream
+{
+public:
+ StreamString ();
+
+ StreamString (uint32_t flags,
+ uint32_t addr_size,
+ lldb::ByteOrder byte_order);
+
+ virtual
+ ~StreamString ();
+
+ virtual void
+ Flush ();
+
+ virtual size_t
+ Write (const void *s, size_t length);
+
+ void
+ Clear();
+
+ bool
+ Empty() const;
+
+ const char *
+ GetData () const;
+
+ size_t
+ GetSize() const;
+
+ std::string &
+ GetString();
+
+ const std::string &
+ GetString() const;
+
+ void
+ FillLastLineToColumn (uint32_t column, char fill_char);
+
+protected:
+ std::string m_packet;
+
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamString_h_
diff --git a/include/lldb/Core/StreamTee.h b/include/lldb/Core/StreamTee.h
new file mode 100644
index 000000000000..e2a29a374553
--- /dev/null
+++ b/include/lldb/Core/StreamTee.h
@@ -0,0 +1,175 @@
+//===-- StreamTee.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_StreamTee_h_
+#define liblldb_StreamTee_h_
+
+#include <limits.h>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class StreamTee : public Stream
+{
+public:
+ StreamTee () :
+ Stream (),
+ m_streams_mutex (Mutex::eMutexTypeRecursive),
+ m_streams ()
+ {
+ }
+
+ StreamTee (lldb::StreamSP &stream_sp):
+ Stream (),
+ m_streams_mutex (Mutex::eMutexTypeRecursive),
+ m_streams ()
+ {
+ // No need to lock mutex during construction
+ if (stream_sp)
+ m_streams.push_back (stream_sp);
+ }
+
+
+ StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) :
+ Stream (),
+ m_streams_mutex (Mutex::eMutexTypeRecursive),
+ m_streams ()
+ {
+ // No need to lock mutex during construction
+ if (stream_sp)
+ m_streams.push_back (stream_sp);
+ if (stream_2_sp)
+ m_streams.push_back (stream_2_sp);
+ }
+
+ StreamTee (const StreamTee &rhs) :
+ Stream (rhs),
+ m_streams_mutex (Mutex::eMutexTypeRecursive),
+ m_streams() // Don't copy until we lock down "rhs"
+ {
+ Mutex::Locker locker (rhs.m_streams_mutex);
+ m_streams = rhs.m_streams;
+ }
+
+ virtual
+ ~StreamTee ()
+ {
+ }
+
+ StreamTee &
+ operator = (const StreamTee &rhs)
+ {
+ if (this != &rhs) {
+ Stream::operator=(rhs);
+ Mutex::Locker lhs_locker (m_streams_mutex);
+ Mutex::Locker rhs_locker (rhs.m_streams_mutex);
+ m_streams = rhs.m_streams;
+ }
+ return *this;
+ }
+
+ virtual void
+ Flush ()
+ {
+ Mutex::Locker locker (m_streams_mutex);
+ collection::iterator pos, end;
+ for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
+ {
+ // Allow for our collection to contain NULL streams. This allows
+ // the StreamTee to be used with hard coded indexes for clients
+ // that might want N total streams with only a few that are set
+ // to valid values.
+ Stream *strm = pos->get();
+ if (strm)
+ strm->Flush ();
+ }
+ }
+
+ virtual size_t
+ Write (const void *s, size_t length)
+ {
+ Mutex::Locker locker (m_streams_mutex);
+ if (m_streams.empty())
+ return 0;
+
+ size_t min_bytes_written = SIZE_MAX;
+ collection::iterator pos, end;
+ for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
+ {
+ // Allow for our collection to contain NULL streams. This allows
+ // the StreamTee to be used with hard coded indexes for clients
+ // that might want N total streams with only a few that are set
+ // to valid values.
+ Stream *strm = pos->get();
+ if (strm)
+ {
+ const size_t bytes_written = strm->Write (s, length);
+ if (min_bytes_written > bytes_written)
+ min_bytes_written = bytes_written;
+ }
+ }
+ if (min_bytes_written == SIZE_MAX)
+ return 0;
+ return min_bytes_written;
+ }
+
+ size_t
+ AppendStream (const lldb::StreamSP &stream_sp)
+ {
+ size_t new_idx = m_streams.size();
+ Mutex::Locker locker (m_streams_mutex);
+ m_streams.push_back (stream_sp);
+ return new_idx;
+ }
+
+ size_t
+ GetNumStreams () const
+ {
+ size_t result = 0;
+ {
+ Mutex::Locker locker (m_streams_mutex);
+ result = m_streams.size();
+ }
+ return result;
+ }
+
+ lldb::StreamSP
+ GetStreamAtIndex (uint32_t idx)
+ {
+ lldb::StreamSP stream_sp;
+ Mutex::Locker locker (m_streams_mutex);
+ if (idx < m_streams.size())
+ stream_sp = m_streams[idx];
+ return stream_sp;
+ }
+
+ void
+ SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp)
+ {
+ Mutex::Locker locker (m_streams_mutex);
+ // Resize our stream vector as necessary to fit as many streams
+ // as needed. This also allows this class to be used with hard
+ // coded indexes that can be used contain many streams, not all
+ // of which are valid.
+ if (idx >= m_streams.size())
+ m_streams.resize(idx + 1);
+ m_streams[idx] = stream_sp;
+ }
+
+
+protected:
+ typedef std::vector<lldb::StreamSP> collection;
+ mutable Mutex m_streams_mutex;
+ collection m_streams;
+};
+
+} // namespace lldb_private
+#endif // #ifndef liblldb_StreamTee_h_
diff --git a/include/lldb/Core/StringList.h b/include/lldb/Core/StringList.h
new file mode 100644
index 000000000000..5503274173cb
--- /dev/null
+++ b/include/lldb/Core/StringList.h
@@ -0,0 +1,107 @@
+//===-- StringList.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_StringList_h_
+#define liblldb_StringList_h_
+
+#include <stdint.h>
+
+#include "lldb/Core/STLUtils.h"
+#include "lldb/lldb-forward.h"
+
+namespace lldb_private {
+
+class StringList
+{
+public:
+
+ StringList ();
+
+ StringList (const char *str);
+
+ StringList (const char **strv, int strc);
+
+ virtual
+ ~StringList ();
+
+ void
+ AppendString (const std::string &s);
+
+ void
+ AppendString (const char *str);
+
+ void
+ AppendString (const char *str, size_t str_len);
+
+ void
+ AppendList (const char ** strv, int strc);
+
+ void
+ AppendList (StringList strings);
+
+ bool
+ ReadFileLines (FileSpec &input_file);
+
+ size_t
+ GetSize () const;
+
+ const char *
+ GetStringAtIndex (size_t idx) const;
+
+ void
+ Join (const char *separator, Stream &strm);
+
+ void
+ Clear ();
+
+ void
+ LongestCommonPrefix (std::string &common_prefix);
+
+ void
+ InsertStringAtIndex (size_t id, const char *str);
+
+ void
+ DeleteStringAtIndex (size_t id);
+
+ void
+ RemoveBlankLines ();
+
+ size_t
+ SplitIntoLines (const char *lines, size_t len);
+
+ std::string
+ CopyList(const char* item_preamble = NULL,
+ const char* items_sep = "\n");
+
+ StringList&
+ operator << (const char* str);
+
+ StringList&
+ operator << (StringList strings);
+
+ // This string list contains a list of valid auto completion
+ // strings, and the "s" is passed in. "matches" is filled in
+ // with zero or more string values that start with "s", and
+ // the first string to exactly match one of the string
+ // values in this collection, will have "exact_matches_idx"
+ // filled in to match the index, or "exact_matches_idx" will
+ // have SIZE_MAX
+ size_t
+ AutoComplete (const char *s,
+ StringList &matches,
+ size_t &exact_matches_idx) const;
+
+private:
+
+ STLStringArray m_strings;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StringList_h_
diff --git a/include/lldb/Core/ThreadSafeSTLMap.h b/include/lldb/Core/ThreadSafeSTLMap.h
new file mode 100644
index 000000000000..703ce481f637
--- /dev/null
+++ b/include/lldb/Core/ThreadSafeSTLMap.h
@@ -0,0 +1,184 @@
+//===-- ThreadSafeSTLMap.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_ThreadSafeSTLMap_h_
+#define liblldb_ThreadSafeSTLMap_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+template <typename _Key, typename _Tp>
+class ThreadSafeSTLMap
+{
+public:
+ typedef std::map<_Key,_Tp> collection;
+ typedef typename collection::iterator iterator;
+ typedef typename collection::const_iterator const_iterator;
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadSafeSTLMap() :
+ m_collection (),
+ m_mutex (Mutex::eMutexTypeRecursive)
+ {
+ }
+
+ ~ThreadSafeSTLMap()
+ {
+ }
+
+ bool
+ IsEmpty() const
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_collection.empty();
+ }
+
+ void
+ Clear()
+ {
+ Mutex::Locker locker(m_mutex);
+ return m_collection.clear();
+ }
+
+ size_t
+ Erase (const _Key& key)
+ {
+ Mutex::Locker locker(m_mutex);
+ return EraseNoLock (key);
+ }
+
+ size_t
+ EraseNoLock (const _Key& key)
+ {
+ return m_collection.erase (key);
+ }
+
+ bool
+ GetValueForKey (const _Key& key, _Tp &value) const
+ {
+ Mutex::Locker locker(m_mutex);
+ return GetValueForKeyNoLock (key, value);
+ }
+
+ // Call this if you have already manually locked the mutex using the
+ // GetMutex() accessor
+ bool
+ GetValueForKeyNoLock (const _Key& key, _Tp &value) const
+ {
+ const_iterator pos = m_collection.find(key);
+ if (pos != m_collection.end())
+ {
+ value = pos->second;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ GetFirstKeyForValue (const _Tp &value, _Key& key) const
+ {
+ Mutex::Locker locker(m_mutex);
+ return GetFirstKeyForValueNoLock (value, key);
+ }
+
+ bool
+ GetFirstKeyForValueNoLock (const _Tp &value, _Key& key) const
+ {
+ const_iterator pos, end = m_collection.end();
+ for (pos = m_collection.begin(); pos != end; ++pos)
+ {
+ if (pos->second == value)
+ {
+ key = pos->first;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ LowerBound (const _Key& key,
+ _Key& match_key,
+ _Tp &match_value,
+ bool decrement_if_not_equal) const
+ {
+ Mutex::Locker locker(m_mutex);
+ return LowerBoundNoLock (key, match_key, match_value, decrement_if_not_equal);
+ }
+
+ bool
+ LowerBoundNoLock (const _Key& key,
+ _Key& match_key,
+ _Tp &match_value,
+ bool decrement_if_not_equal) const
+ {
+ const_iterator pos = m_collection.lower_bound (key);
+ if (pos != m_collection.end())
+ {
+ match_key = pos->first;
+ if (decrement_if_not_equal && key != match_key && pos != m_collection.begin())
+ {
+ --pos;
+ match_key = pos->first;
+ }
+ match_value = pos->second;
+ return true;
+ }
+ return false;
+ }
+
+ iterator
+ lower_bound_unsafe (const _Key& key)
+ {
+ return m_collection.lower_bound (key);
+ }
+
+ void
+ SetValueForKey (const _Key& key, const _Tp &value)
+ {
+ Mutex::Locker locker(m_mutex);
+ SetValueForKeyNoLock (key, value);
+ }
+
+ // Call this if you have already manually locked the mutex using the
+ // GetMutex() accessor
+ void
+ SetValueForKeyNoLock (const _Key& key, const _Tp &value)
+ {
+ m_collection[key] = value;
+ }
+
+ Mutex &
+ GetMutex ()
+ {
+ return m_mutex;
+ }
+
+private:
+ collection m_collection;
+ mutable Mutex m_mutex;
+
+ //------------------------------------------------------------------
+ // For ThreadSafeSTLMap only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadSafeSTLMap);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadSafeSTLMap_h_
diff --git a/include/lldb/Core/ThreadSafeValue.h b/include/lldb/Core/ThreadSafeValue.h
new file mode 100644
index 000000000000..42a5a5c6725a
--- /dev/null
+++ b/include/lldb/Core/ThreadSafeValue.h
@@ -0,0 +1,96 @@
+//===-- ThreadSafeValue.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_ThreadSafeValue_h_
+#define liblldb_ThreadSafeValue_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+template <class T>
+class ThreadSafeValue
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadSafeValue() :
+ m_value (),
+ m_mutex (Mutex::eMutexTypeRecursive)
+ {
+ }
+
+ ThreadSafeValue(const T& value) :
+ m_value (value),
+ m_mutex (Mutex::eMutexTypeRecursive)
+ {
+ }
+
+ ~ThreadSafeValue()
+ {
+ }
+
+ T
+ GetValue () const
+ {
+ T value;
+ {
+ Mutex::Locker locker(m_mutex);
+ value = m_value;
+ }
+ return value;
+ }
+
+ // Call this if you have already manually locked the mutex using the
+ // GetMutex() accessor
+ const T&
+ GetValueNoLock () const
+ {
+ return m_value;
+ }
+
+ void
+ SetValue (const T& value)
+ {
+ Mutex::Locker locker(m_mutex);
+ m_value = value;
+ }
+
+ // Call this if you have already manually locked the mutex using the
+ // GetMutex() accessor
+ void
+ SetValueNoLock (const T& value)
+ {
+ m_value = value;
+ }
+
+ Mutex &
+ GetMutex ()
+ {
+ return m_mutex;
+ }
+
+private:
+ T m_value;
+ mutable Mutex m_mutex;
+
+ //------------------------------------------------------------------
+ // For ThreadSafeValue only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadSafeValue);
+};
+
+
+} // namespace lldb_private
+#endif // liblldb_ThreadSafeValue_h_
diff --git a/include/lldb/Core/Timer.h b/include/lldb/Core/Timer.h
new file mode 100644
index 000000000000..e354d91be442
--- /dev/null
+++ b/include/lldb/Core/Timer.h
@@ -0,0 +1,160 @@
+//===-- Timer.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_Timer_h_
+#define liblldb_Timer_h_
+#if defined(__cplusplus)
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string>
+#include "lldb/lldb-private.h"
+#include "lldb/Host/TimeValue.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Timer Timer.h "lldb/Core/Timer.h"
+/// @brief A timer class that simplifies common timing metrics.
+///
+/// A scoped timer class that allows a variety of pthread mutex
+/// objects to have a mutex locked when a Timer::Locker
+/// object is created, and unlocked when it goes out of scope or
+/// when the Timer::Locker::Reset(pthread_mutex_t *)
+/// is called. This provides an exception safe way to lock a mutex
+/// in a scope.
+//----------------------------------------------------------------------
+
+class Timer
+{
+public:
+ static void
+ Initialize ();
+
+ //--------------------------------------------------------------
+ /// Default constructor.
+ //--------------------------------------------------------------
+ Timer(const char *category, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+
+ //--------------------------------------------------------------
+ /// Desstructor
+ //--------------------------------------------------------------
+ ~Timer();
+
+ void
+ Dump ();
+
+ static void
+ SetDisplayDepth (uint32_t depth);
+
+ static void
+ SetQuiet (bool value);
+
+ static void
+ DumpCategoryTimes (Stream *s);
+
+ static void
+ ResetCategoryTimes ();
+
+protected:
+
+ void
+ ChildStarted (const TimeValue& time);
+
+ void
+ ChildStopped (const TimeValue& time);
+
+ uint64_t
+ GetTotalElapsedNanoSeconds();
+
+ uint64_t
+ GetTimerElapsedNanoSeconds();
+
+ //--------------------------------------------------------------
+ /// Member variables
+ //--------------------------------------------------------------
+ const char *m_category;
+ TimeValue m_total_start;
+ TimeValue m_timer_start;
+ uint64_t m_total_ticks; // Total running time for this timer including when other timers below this are running
+ uint64_t m_timer_ticks; // Ticks for this timer that do not include when other timers below this one are running
+ static uint32_t g_depth;
+ static uint32_t g_display_depth;
+ static FILE * g_file;
+private:
+ Timer();
+ DISALLOW_COPY_AND_ASSIGN (Timer);
+};
+
+class IntervalTimer
+{
+public:
+ IntervalTimer() :
+ m_start (TimeValue::Now())
+ {
+ }
+
+ ~IntervalTimer()
+ {
+ }
+
+ uint64_t
+ GetElapsedNanoSeconds() const
+ {
+ return TimeValue::Now() - m_start;
+ }
+
+ void
+ Reset ()
+ {
+ m_start = TimeValue::Now();
+ }
+
+ int
+ PrintfElapsed (const char *format, ...) __attribute__ ((format (printf, 2, 3)))
+ {
+ TimeValue now (TimeValue::Now());
+ const uint64_t elapsed_nsec = now - m_start;
+ const char *unit = NULL;
+ float elapsed_value;
+ if (elapsed_nsec < 1000)
+ {
+ unit = "ns";
+ elapsed_value = (float)elapsed_nsec;
+ }
+ else if (elapsed_nsec < 1000000)
+ {
+ unit = "us";
+ elapsed_value = (float)elapsed_nsec/1000.0f;
+ }
+ else if (elapsed_nsec < 1000000000)
+ {
+ unit = "ms";
+ elapsed_value = (float)elapsed_nsec/1000000.0f;
+ }
+ else
+ {
+ unit = "sec";
+ elapsed_value = (float)elapsed_nsec/1000000000.0f;
+ }
+ int result = printf ("%3.2f %s: ", elapsed_value, unit);
+ va_list args;
+ va_start (args, format);
+ result += vprintf (format, args);
+ va_end (args);
+ return result;
+ }
+protected:
+ TimeValue m_start;
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_Timer_h_
diff --git a/include/lldb/Core/UUID.h b/include/lldb/Core/UUID.h
new file mode 100644
index 000000000000..fe72b8eb0c70
--- /dev/null
+++ b/include/lldb/Core/UUID.h
@@ -0,0 +1,109 @@
+//===-- UUID.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_UUID_h_
+#define liblldb_UUID_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class UUID
+{
+public:
+ // Most UUIDs are 16 bytes, but some Linux build-ids (SHA1) are 20.
+ typedef uint8_t ValueType[20];
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ UUID ();
+ UUID (const UUID& rhs);
+ UUID (const void *uuid_bytes, uint32_t num_uuid_bytes);
+
+ ~UUID ();
+
+ const UUID&
+ operator=(const UUID& rhs);
+
+ void
+ Clear ();
+
+ void
+ Dump (Stream *s) const;
+
+ const void *
+ GetBytes() const;
+
+ size_t
+ GetByteSize();
+
+ bool
+ IsValid () const;
+
+ bool
+ SetBytes (const void *uuid_bytes, uint32_t num_uuid_bytes = 16);
+
+ std::string
+ GetAsString (const char *separator = NULL) const;
+
+ size_t
+ SetFromCString (const char *c_str, uint32_t num_uuid_bytes = 16);
+
+ // Decode as many UUID bytes (up to 16) as possible from the C string "cstr"
+ // This is used for auto completion where a partial UUID might have been
+ // typed in. It
+ //------------------------------------------------------------------
+ /// Decode as many UUID bytes (up to 16) as possible from the C
+ /// string \a cstr.
+ ///
+ /// @param[in] cstr
+ /// A NULL terminate C string that points at a UUID string value
+ /// (no leading spaces). The string must contain only hex
+ /// characters and optionally can contain the '-' sepearators.
+ ///
+ /// @param[in] uuid_bytes
+ /// A buffer of bytes that will contain a full or patially
+ /// decoded UUID.
+ ///
+ /// @param[out] end
+ /// If \a end is not NULL, it will be filled in with the a
+ /// pointer to the character after the last successfully decoded
+ /// byte.
+ ///
+ /// @return
+ /// Returns the number of bytes that were successfully decoded
+ /// which should be 16 if a full UUID value was properly decoded.
+ //------------------------------------------------------------------
+ static size_t
+ DecodeUUIDBytesFromCString (const char *cstr, ValueType &uuid_bytes, const char **end, uint32_t num_uuid_bytes = 16);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from UUID can see and modify these
+ //------------------------------------------------------------------
+ uint32_t m_num_uuid_bytes; // Should be 16 or 20
+ ValueType m_uuid;
+};
+
+bool operator == (const UUID &lhs, const UUID &rhs);
+bool operator != (const UUID &lhs, const UUID &rhs);
+bool operator < (const UUID &lhs, const UUID &rhs);
+bool operator <= (const UUID &lhs, const UUID &rhs);
+bool operator > (const UUID &lhs, const UUID &rhs);
+bool operator >= (const UUID &lhs, const UUID &rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_UUID_h_
diff --git a/include/lldb/Core/UniqueCStringMap.h b/include/lldb/Core/UniqueCStringMap.h
new file mode 100644
index 000000000000..972c0d53ea99
--- /dev/null
+++ b/include/lldb/Core/UniqueCStringMap.h
@@ -0,0 +1,361 @@
+//===-- UniqueCStringMap.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_UniqueCStringMap_h_
+#define liblldb_UniqueCStringMap_h_
+#if defined(__cplusplus)
+
+#include <assert.h>
+#include <algorithm>
+#include <vector>
+
+#include "lldb/Core/RegularExpression.h"
+
+namespace lldb_private {
+
+
+
+//----------------------------------------------------------------------
+// Templatized uniqued string map.
+//
+// This map is useful for mapping unique C string names to values of
+// type T. Each "const char *" name added must be unique for a given
+// C string value. ConstString::GetCString() can provide such strings.
+// Any other string table that has guaranteed unique values can also
+// be used.
+//----------------------------------------------------------------------
+template <typename T>
+class UniqueCStringMap
+{
+public:
+ struct Entry
+ {
+ Entry () :
+ cstring(NULL),
+ value()
+ {
+ }
+
+ Entry (const char *cstr) :
+ cstring(cstr),
+ value()
+ {
+ }
+
+ Entry (const char *cstr, const T&v) :
+ cstring(cstr),
+ value(v)
+ {
+ }
+
+ bool
+ operator < (const Entry& rhs) const
+ {
+ return cstring < rhs.cstring;
+ }
+
+ const char* cstring;
+ T value;
+ };
+
+ //------------------------------------------------------------------
+ // Call this function multiple times to add a bunch of entries to
+ // this map, then later call UniqueCStringMap<T>::Sort() before doing
+ // any searches by name.
+ //------------------------------------------------------------------
+ void
+ Append (const char *unique_cstr, const T& value)
+ {
+ m_map.push_back (typename UniqueCStringMap<T>::Entry(unique_cstr, value));
+ }
+
+ void
+ Append (const Entry &e)
+ {
+ m_map.push_back (e);
+ }
+
+ void
+ Clear ()
+ {
+ m_map.clear();
+ }
+
+ //------------------------------------------------------------------
+ // Call this function to always keep the map sorted when putting
+ // entries into the map.
+ //------------------------------------------------------------------
+ void
+ Insert (const char *unique_cstr, const T& value)
+ {
+ typename UniqueCStringMap<T>::Entry e(unique_cstr, value);
+ m_map.insert (std::upper_bound (m_map.begin(), m_map.end(), e), e);
+ }
+
+ void
+ Insert (const Entry &e)
+ {
+ m_map.insert (std::upper_bound (m_map.begin(), m_map.end(), e), e);
+ }
+
+ //------------------------------------------------------------------
+ // Get an entries by index in a variety of forms.
+ //
+ // The caller is responsible for ensuring that the collection does
+ // not change during while using the returned values.
+ //------------------------------------------------------------------
+ bool
+ GetValueAtIndex (uint32_t idx, T &value) const
+ {
+ if (idx < m_map.size())
+ {
+ value = m_map[idx].value;
+ return true;
+ }
+ return false;
+ }
+
+ const char *
+ GetCStringAtIndexUnchecked (uint32_t idx) const
+ {
+ return m_map[idx].cstring;
+ }
+
+ // Use this function if you have simple types in your map that you
+ // can easily copy when accessing values by index.
+ T
+ GetValueAtIndexUnchecked (uint32_t idx) const
+ {
+ return m_map[idx].value;
+ }
+
+ // Use this function if you have complex types in your map that you
+ // don't want to copy when accessing values by index.
+ const T &
+ GetValueRefAtIndexUnchecked (uint32_t idx) const
+ {
+ return m_map[idx].value;
+ }
+
+ const char *
+ GetCStringAtIndex (uint32_t idx) const
+ {
+ if (idx < m_map.size())
+ return m_map[idx].cstring;
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Find the value for the unique string in the map.
+ //
+ // Return the value for \a unique_cstr if one is found, return
+ // \a fail_value otherwise. This method works well for simple type
+ // T values and only if there is a sensible failure value that can
+ // be returned and that won't match any existing values.
+ //------------------------------------------------------------------
+ T
+ Find (const char *unique_cstr, T fail_value) const
+ {
+ Entry search_entry (unique_cstr);
+ const_iterator end = m_map.end();
+ const_iterator pos = std::lower_bound (m_map.begin(), end, search_entry);
+ if (pos != end)
+ {
+ if (pos->cstring == unique_cstr)
+ return pos->value;
+ }
+ return fail_value;
+ }
+ //------------------------------------------------------------------
+ // Get a pointer to the first entry that matches "name". NULL will
+ // be returned if there is no entry that matches "name".
+ //
+ // The caller is responsible for ensuring that the collection does
+ // not change during while using the returned pointer.
+ //------------------------------------------------------------------
+ const Entry *
+ FindFirstValueForName (const char *unique_cstr) const
+ {
+ Entry search_entry (unique_cstr);
+ const_iterator end = m_map.end();
+ const_iterator pos = std::lower_bound (m_map.begin(), end, search_entry);
+ if (pos != end)
+ {
+ const char *pos_cstr = pos->cstring;
+ if (pos_cstr == unique_cstr)
+ return &(*pos);
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Get a pointer to the next entry that matches "name" from a
+ // previously returned Entry pointer. NULL will be returned if there
+ // is no subsequent entry that matches "name".
+ //
+ // The caller is responsible for ensuring that the collection does
+ // not change during while using the returned pointer.
+ //------------------------------------------------------------------
+ const Entry *
+ FindNextValueForName (const Entry *entry_ptr) const
+ {
+ if (!m_map.empty())
+ {
+ const Entry *first_entry = &m_map[0];
+ const Entry *after_last_entry = first_entry + m_map.size();
+ const Entry *next_entry = entry_ptr + 1;
+ if (first_entry <= next_entry && next_entry < after_last_entry)
+ {
+ if (next_entry->cstring == entry_ptr->cstring)
+ return next_entry;
+ }
+ }
+ return NULL;
+ }
+
+ size_t
+ GetValues (const char *unique_cstr, std::vector<T> &values) const
+ {
+ const size_t start_size = values.size();
+
+ Entry search_entry (unique_cstr);
+ const_iterator pos, end = m_map.end();
+ for (pos = std::lower_bound (m_map.begin(), end, search_entry); pos != end; ++pos)
+ {
+ if (pos->cstring == unique_cstr)
+ values.push_back (pos->value);
+ else
+ break;
+ }
+
+ return values.size() - start_size;
+ }
+
+ size_t
+ GetValues (const RegularExpression& regex, std::vector<T> &values) const
+ {
+ const size_t start_size = values.size();
+
+ const_iterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; ++pos)
+ {
+ if (regex.Execute(pos->cstring))
+ values.push_back (pos->value);
+ }
+
+ return values.size() - start_size;
+ }
+
+ //------------------------------------------------------------------
+ // Get the total number of entries in this map.
+ //------------------------------------------------------------------
+ size_t
+ GetSize () const
+ {
+ return m_map.size();
+ }
+
+
+ //------------------------------------------------------------------
+ // Returns true if this map is empty.
+ //------------------------------------------------------------------
+ bool
+ IsEmpty() const
+ {
+ return m_map.empty();
+ }
+
+ //------------------------------------------------------------------
+ // Reserve memory for at least "n" entries in the map. This is
+ // useful to call when you know you will be adding a lot of entries
+ // using UniqueCStringMap::Append() (which should be followed by a
+ // call to UniqueCStringMap::Sort()) or to UniqueCStringMap::Insert().
+ //------------------------------------------------------------------
+ void
+ Reserve (size_t n)
+ {
+ m_map.reserve (n);
+ }
+
+ //------------------------------------------------------------------
+ // Sort the unsorted contents in this map. A typical code flow would
+ // be:
+ // size_t approximate_num_entries = ....
+ // UniqueCStringMap<uint32_t> my_map;
+ // my_map.Reserve (approximate_num_entries);
+ // for (...)
+ // {
+ // my_map.Append (UniqueCStringMap::Entry(GetName(...), GetValue(...)));
+ // }
+ // my_map.Sort();
+ //------------------------------------------------------------------
+ void
+ Sort ()
+ {
+ std::sort (m_map.begin(), m_map.end());
+ }
+
+ //------------------------------------------------------------------
+ // Since we are using a vector to contain our items it will always
+ // double its memory consumption as things are added to the vector,
+ // so if you intend to keep a UniqueCStringMap around and have
+ // a lot of entries in the map, you will want to call this function
+ // to create a new vector and copy _only_ the exact size needed as
+ // part of the finalization of the string map.
+ //------------------------------------------------------------------
+ void
+ SizeToFit ()
+ {
+ if (m_map.size() < m_map.capacity())
+ {
+ collection temp (m_map.begin(), m_map.end());
+ m_map.swap(temp);
+ }
+ }
+
+ size_t
+ Erase (const char *unique_cstr)
+ {
+ size_t num_removed = 0;
+ Entry search_entry (unique_cstr);
+ iterator end = m_map.end();
+ iterator begin = m_map.begin();
+ iterator lower_pos = std::lower_bound (begin, end, search_entry);
+ if (lower_pos != end)
+ {
+ if (lower_pos->cstring == unique_cstr)
+ {
+ iterator upper_pos = std::upper_bound (lower_pos, end, search_entry);
+ if (lower_pos == upper_pos)
+ {
+ m_map.erase (lower_pos);
+ num_removed = 1;
+ }
+ else
+ {
+ num_removed = std::distance (lower_pos, upper_pos);
+ m_map.erase (lower_pos, upper_pos);
+ }
+ }
+ }
+ return num_removed;
+ }
+protected:
+ typedef std::vector<Entry> collection;
+ typedef typename collection::iterator iterator;
+ typedef typename collection::const_iterator const_iterator;
+ collection m_map;
+};
+
+
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_UniqueCStringMap_h_
diff --git a/include/lldb/Core/UserID.h b/include/lldb/Core/UserID.h
new file mode 100644
index 000000000000..ea6af74759bf
--- /dev/null
+++ b/include/lldb/Core/UserID.h
@@ -0,0 +1,130 @@
+//===-- UserID.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_UserID_h_
+#define liblldb_UserID_h_
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class UserID UserID.h "lldb/Core/UserID.h"
+/// @brief A mix in class that contains a generic user ID.
+///
+/// UserID is desinged as a mix in class that can contain an integer
+/// based unique identifier for a varietly of objects in lldb.
+///
+/// The value for this identifier is chosen by each parser plug-in. A
+/// value should be chosen that makes sense for each kind of object
+/// should and allows quick access to further and more in depth parsing.
+///
+/// Symbol table entries can use this to store the original symbol table
+/// index, functions can use it to store the symbol table index or the
+/// DWARF offset.
+//----------------------------------------------------------------------
+struct UserID
+{
+ //------------------------------------------------------------------
+ /// Construct with optional user ID.
+ //------------------------------------------------------------------
+ UserID (lldb::user_id_t uid = LLDB_INVALID_UID) : m_uid(uid) {}
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~UserID ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clears the object contents back to a default invalid state.
+ //------------------------------------------------------------------
+ void
+ Clear () { m_uid = LLDB_INVALID_UID; }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the user ID.
+ ///
+ /// @return
+ /// The user ID.
+ //------------------------------------------------------------------
+ lldb::user_id_t
+ GetID () const { return m_uid; }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the user ID.
+ ///
+ /// @param[in] uid
+ /// The new user ID.
+ //------------------------------------------------------------------
+ void
+ SetID (lldb::user_id_t uid) { m_uid = uid; }
+
+ //------------------------------------------------------------------
+ /// Unary predicate function object that can search for a matching
+ /// user ID.
+ ///
+ /// Function object that can be used on any class that inherits
+ /// from UserID:
+ /// \code
+ /// iterator pos;
+ /// pos = std::find_if (coll.begin(), coll.end(), UserID::IDMatches(blockID));
+ /// \endcode
+ //------------------------------------------------------------------
+ class IDMatches
+ {
+ public:
+ //--------------------------------------------------------------
+ /// Construct with the user ID to look for.
+ //--------------------------------------------------------------
+ IDMatches (lldb::user_id_t uid) : m_uid(uid) {}
+
+ //--------------------------------------------------------------
+ /// Unary predicate function object callback.
+ //--------------------------------------------------------------
+ bool
+ operator () (const UserID& rhs) const { return m_uid == rhs.GetID(); }
+
+ private:
+ //--------------------------------------------------------------
+ // Member variables.
+ //--------------------------------------------------------------
+ const lldb::user_id_t m_uid; ///< The user ID we are looking for
+ };
+
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ lldb::user_id_t m_uid; ///< The user ID that uniquely identifies an object.
+};
+
+inline bool operator== (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() == rhs.GetID();
+}
+
+inline bool operator!= (const UserID& lhs, const UserID& rhs)
+{
+ return lhs.GetID() != rhs.GetID();
+}
+
+//--------------------------------------------------------------
+/// Stream the UserID object to a Stream.
+//--------------------------------------------------------------
+Stream& operator << (Stream& strm, const UserID& uid);
+
+} // namespace lldb_private
+
+#endif // liblldb_UserID_h_
diff --git a/include/lldb/Core/UserSettingsController.h b/include/lldb/Core/UserSettingsController.h
new file mode 100644
index 000000000000..7e72b89ad8e6
--- /dev/null
+++ b/include/lldb/Core/UserSettingsController.h
@@ -0,0 +1,98 @@
+//====-- UserSettingsController.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_UserSettingsController_h_
+#define liblldb_UserSettingsController_h_
+
+// C Includes
+// C++ Includes
+
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class Properties
+{
+public:
+ Properties () :
+ m_collection_sp ()
+ {
+ }
+
+ Properties (const lldb::OptionValuePropertiesSP &collection_sp) :
+ m_collection_sp (collection_sp)
+ {
+ }
+
+ virtual
+ ~Properties()
+ {
+ }
+
+ virtual lldb::OptionValuePropertiesSP
+ GetValueProperties () const
+ {
+ // This function is virtual in case subclasses want to lazily
+ // implement creating the properties.
+ return m_collection_sp;
+ }
+
+ virtual lldb::OptionValueSP
+ GetPropertyValue (const ExecutionContext *exe_ctx,
+ const char *property_path,
+ bool will_modify,
+ Error &error) const;
+
+ virtual Error
+ SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *property_path,
+ const char *value);
+
+ virtual Error
+ DumpPropertyValue (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ const char *property_path,
+ uint32_t dump_mask);
+
+ virtual void
+ DumpAllPropertyValues (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ uint32_t dump_mask);
+
+ virtual void
+ DumpAllDescriptions (CommandInterpreter &interpreter,
+ Stream &strm) const;
+
+ size_t
+ Apropos (const char *keyword,
+ std::vector<const Property *> &matching_properties) const;
+
+ lldb::OptionValuePropertiesSP
+ GetSubProperty (const ExecutionContext *exe_ctx,
+ const ConstString &name);
+protected:
+ lldb::OptionValuePropertiesSP m_collection_sp;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_UserSettingsController_h_
diff --git a/include/lldb/Core/VMRange.h b/include/lldb/Core/VMRange.h
new file mode 100644
index 000000000000..94c83e730e96
--- /dev/null
+++ b/include/lldb/Core/VMRange.h
@@ -0,0 +1,181 @@
+//===-- VMRange.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_VMRange_h_
+#define liblldb_VMRange_h_
+
+#include "lldb/lldb-private.h"
+#include <vector>
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A vm address range. These can represent offsets ranges or actual
+// addresses.
+//----------------------------------------------------------------------
+class VMRange
+{
+public:
+
+ typedef std::vector<VMRange> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ VMRange() :
+ m_base_addr(0),
+ m_byte_size(0)
+ {
+ }
+
+ VMRange(lldb::addr_t start_addr, lldb::addr_t end_addr) :
+ m_base_addr(start_addr),
+ m_byte_size(end_addr > start_addr ? end_addr - start_addr : 0)
+ {
+ }
+
+ ~VMRange()
+ {
+ }
+
+ void
+ Clear ()
+ {
+ m_base_addr = 0;
+ m_byte_size = 0;
+ }
+
+ // Set the start and end values
+ void
+ Reset (lldb::addr_t start_addr, lldb::addr_t end_addr)
+ {
+ SetBaseAddress (start_addr);
+ SetEndAddress (end_addr);
+ }
+
+ // Set the start value for the range, and keep the same size
+ void
+ SetBaseAddress (lldb::addr_t base_addr)
+ {
+ m_base_addr = base_addr;
+ }
+
+ void
+ SetEndAddress (lldb::addr_t end_addr)
+ {
+ const lldb::addr_t base_addr = GetBaseAddress();
+ if (end_addr > base_addr)
+ m_byte_size = end_addr - base_addr;
+ else
+ m_byte_size = 0;
+ }
+
+ lldb::addr_t
+ GetByteSize () const
+ {
+ return m_byte_size;
+ }
+
+ void
+ SetByteSize (lldb::addr_t byte_size)
+ {
+ m_byte_size = byte_size;
+ }
+
+ lldb::addr_t
+ GetBaseAddress () const
+ {
+ return m_base_addr;
+ }
+
+ lldb::addr_t
+ GetEndAddress () const
+ {
+ return GetBaseAddress() + m_byte_size;
+ }
+
+ bool
+ IsValid() const
+ {
+ return m_byte_size > 0;
+ }
+
+ bool
+ Contains (lldb::addr_t addr) const
+ {
+ return (GetBaseAddress() <= addr) && (addr < GetEndAddress());
+ }
+
+ bool
+ Contains (const VMRange& range) const
+ {
+ if (Contains(range.GetBaseAddress()))
+ {
+ lldb::addr_t range_end = range.GetEndAddress();
+ return (GetBaseAddress() <= range_end) && (range_end <= GetEndAddress());
+ }
+ return false;
+ }
+
+ void
+ Dump (Stream *s, lldb::addr_t base_addr = 0, uint32_t addr_width = 8) const;
+
+ class ValueInRangeUnaryPredicate
+ {
+ public:
+ ValueInRangeUnaryPredicate(lldb::addr_t value) :
+ _value(value)
+ {
+ }
+ bool operator()(const VMRange& range) const
+ {
+ return range.Contains(_value);
+ }
+ lldb::addr_t _value;
+ };
+
+ class RangeInRangeUnaryPredicate
+ {
+ public:
+ RangeInRangeUnaryPredicate(VMRange range) :
+ _range(range)
+ {
+ }
+ bool operator()(const VMRange& range) const
+ {
+ return range.Contains(_range);
+ }
+ const VMRange& _range;
+ };
+
+ static bool
+ ContainsValue(const VMRange::collection& coll, lldb::addr_t value);
+
+ static bool
+ ContainsRange(const VMRange::collection& coll, const VMRange& range);
+
+ // Returns a valid index into coll when a match is found, else UINT32_MAX
+ // is returned
+ static size_t
+ FindRangeIndexThatContainsValue (const VMRange::collection& coll, lldb::addr_t value);
+
+protected:
+ lldb::addr_t m_base_addr;
+ lldb::addr_t m_byte_size;
+};
+
+bool operator== (const VMRange& lhs, const VMRange& rhs);
+bool operator!= (const VMRange& lhs, const VMRange& rhs);
+bool operator< (const VMRange& lhs, const VMRange& rhs);
+bool operator<= (const VMRange& lhs, const VMRange& rhs);
+bool operator> (const VMRange& lhs, const VMRange& rhs);
+bool operator>= (const VMRange& lhs, const VMRange& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_VMRange_h_
diff --git a/include/lldb/Core/Value.h b/include/lldb/Core/Value.h
new file mode 100644
index 000000000000..5461ca73d082
--- /dev/null
+++ b/include/lldb/Core/Value.h
@@ -0,0 +1,314 @@
+//===-- Value.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_Value_h_
+#define liblldb_Value_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+namespace lldb_private {
+
+class Value
+{
+public:
+
+ // Values Less than zero are an error, greater than or equal to zero
+ // returns what the Scalar result is.
+ enum ValueType
+ {
+ // m_value contains...
+ // ============================
+ eValueTypeScalar, // raw scalar value
+ eValueTypeVector, // byte array of m_vector.length with endianness of m_vector.byte_order
+ eValueTypeFileAddress, // file address value
+ eValueTypeLoadAddress, // load address value
+ eValueTypeHostAddress // host address value (for memory in the process that is using liblldb)
+ };
+
+ enum ContextType // Type that describes Value::m_context
+ {
+ // m_context contains...
+ // ====================
+ eContextTypeInvalid, // undefined
+ eContextTypeRegisterInfo, // RegisterInfo * (can be a scalar or a vector register)
+ eContextTypeLLDBType, // lldb_private::Type *
+ eContextTypeVariable // lldb_private::Variable *
+ };
+
+ const static size_t kMaxByteSize = 32u;
+
+ struct Vector
+ {
+ // The byte array must be big enough to hold vector registers for any supported target.
+ uint8_t bytes[kMaxByteSize];
+ size_t length;
+ lldb::ByteOrder byte_order;
+
+ Vector() :
+ length(0),
+ byte_order(lldb::eByteOrderInvalid)
+ {
+ }
+
+ Vector(const Vector& vector)
+ { *this = vector;
+ }
+ const Vector&
+ operator=(const Vector& vector)
+ {
+ SetBytes(vector.bytes, vector.length, vector.byte_order);
+ return *this;
+ }
+
+ void
+ Clear ()
+ {
+ length = 0;
+ }
+
+ bool
+ SetBytes(const void *bytes, size_t length, lldb::ByteOrder byte_order)
+ {
+ this->length = length;
+ this->byte_order = byte_order;
+ if (length)
+ ::memcpy(this->bytes, bytes, length < kMaxByteSize ? length : kMaxByteSize);
+ return IsValid();
+ }
+
+ bool
+ IsValid() const
+ {
+ return (length > 0 && length < kMaxByteSize && byte_order != lldb::eByteOrderInvalid);
+ }
+ // Casts a vector, if valid, to an unsigned int of matching or largest supported size.
+ // Truncates to the beginning of the vector if required.
+ // Returns a default constructed Scalar if the Vector data is internally inconsistent.
+ Scalar
+ GetAsScalar() const
+ {
+ Scalar scalar;
+ if (IsValid())
+ {
+ if (length == 1) scalar = *(const uint8_t *)bytes;
+ else if (length == 2) scalar = *(const uint16_t *)bytes;
+ else if (length == 4) scalar = *(const uint32_t *)bytes;
+ else if (length == 8) scalar = *(const uint64_t *)bytes;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ else if (length >= 16) scalar = *(const __uint128_t *)bytes;
+#else
+ else if (length >= 16) scalar = *(const __uint64_t *)bytes;
+#endif
+ }
+ return scalar;
+ }
+ };
+
+ Value();
+ Value(const Scalar& scalar);
+ Value(const Vector& vector);
+ Value(const uint8_t *bytes, int len);
+ Value(const Value &rhs);
+
+ Value &
+ operator=(const Value &rhs);
+
+ const ClangASTType &
+ GetClangType();
+
+ void
+ SetClangType (const ClangASTType &clang_type);
+
+ ValueType
+ GetValueType() const;
+
+ AddressType
+ GetValueAddressType () const;
+
+ ContextType
+ GetContextType() const
+ {
+ return m_context_type;
+ }
+
+ void
+ SetValueType (ValueType value_type)
+ {
+ m_value_type = value_type;
+ }
+
+ void
+ ClearContext ()
+ {
+ m_context = NULL;
+ m_context_type = eContextTypeInvalid;
+ }
+
+ void
+ SetContext (ContextType context_type, void *p)
+ {
+ m_context_type = context_type;
+ m_context = p;
+ if (m_context_type == eContextTypeRegisterInfo) {
+ RegisterInfo *reg_info = GetRegisterInfo();
+ if (reg_info->encoding == lldb::eEncodingVector)
+ SetValueType(eValueTypeVector);
+ else
+ SetValueType(eValueTypeScalar);
+ }
+ }
+
+ RegisterInfo *
+ GetRegisterInfo() const;
+
+ Type *
+ GetType();
+
+ Scalar &
+ ResolveValue (ExecutionContext *exe_ctx);
+
+ const Scalar &
+ GetScalar() const
+ {
+ return m_value;
+ }
+
+ const Vector &
+ GetVector() const
+ {
+ return m_vector;
+ }
+
+ Scalar &
+ GetScalar()
+ {
+ return m_value;
+ }
+
+ Vector &
+ GetVector()
+ {
+ return m_vector;
+ }
+
+ bool
+ SetVectorBytes(const Vector& vector)
+ {
+ m_vector = vector;
+ return m_vector.IsValid();
+ }
+
+ bool
+ SetVectorBytes(uint8_t *bytes, size_t length, lldb::ByteOrder byte_order)
+ {
+ return m_vector.SetBytes(bytes, length, byte_order);
+ }
+
+ bool
+ SetScalarFromVector()
+ {
+ if (m_vector.IsValid())
+ {
+ m_value = m_vector.GetAsScalar();
+ return true;
+ }
+ return false;
+ }
+
+ void
+ ResizeData(size_t len);
+
+ bool
+ ValueOf(ExecutionContext *exe_ctx);
+
+ Variable *
+ GetVariable();
+
+ void
+ Dump (Stream* strm);
+
+ lldb::Format
+ GetValueDefaultFormat ();
+
+ uint64_t
+ GetValueByteSize (Error *error_ptr);
+
+ Error
+ GetValueAsData (ExecutionContext *exe_ctx,
+ DataExtractor &data,
+ uint32_t data_offset,
+ Module *module); // Can be NULL
+
+ static const char *
+ GetValueTypeAsCString (ValueType context_type);
+
+ static const char *
+ GetContextTypeAsCString (ContextType context_type);
+
+ bool
+ GetData (DataExtractor &data);
+
+ void
+ Clear();
+
+protected:
+ Scalar m_value;
+ Vector m_vector;
+ ClangASTType m_clang_type;
+ void * m_context;
+ ValueType m_value_type;
+ ContextType m_context_type;
+ DataBufferHeap m_data_buffer;
+};
+
+class ValueList
+{
+public:
+ ValueList () :
+ m_values()
+ {
+ }
+
+ ValueList (const ValueList &rhs);
+
+ ~ValueList ()
+ {
+ }
+
+ const ValueList & operator= (const ValueList &rhs);
+
+ // void InsertValue (Value *value, size_t idx);
+ void PushValue (const Value &value);
+
+ size_t GetSize ();
+ Value *GetValueAtIndex(size_t idx);
+ void Clear();
+
+protected:
+
+private:
+ typedef std::vector<Value> collection;
+
+ collection m_values;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Value_h_
diff --git a/include/lldb/Core/ValueObject.h b/include/lldb/Core/ValueObject.h
new file mode 100644
index 000000000000..0d965d6ccc01
--- /dev/null
+++ b/include/lldb/Core/ValueObject.h
@@ -0,0 +1,1375 @@
+//===-- ValueObject.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_ValueObject_h_
+#define liblldb_ValueObject_h_
+
+// C Includes
+// C++ Includes
+#include <initializer_list>
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Utility/SharedCluster.h"
+
+namespace lldb_private {
+
+/// ValueObject:
+///
+/// This abstract class provides an interface to a particular value, be it a register, a local or global variable,
+/// that is evaluated in some particular scope. The ValueObject also has the capibility of being the "child" of
+/// some other variable object, and in turn of having children.
+/// If a ValueObject is a root variable object - having no parent - then it must be constructed with respect to some
+/// particular ExecutionContextScope. If it is a child, it inherits the ExecutionContextScope from its parent.
+/// The ValueObject will update itself if necessary before fetching its value, summary, object description, etc.
+/// But it will always update itself in the ExecutionContextScope with which it was originally created.
+
+/// A brief note on life cycle management for ValueObjects. This is a little tricky because a ValueObject can contain
+/// various other ValueObjects - the Dynamic Value, its children, the dereference value, etc. Any one of these can be
+/// handed out as a shared pointer, but for that contained value object to be valid, the root object and potentially other
+/// of the value objects need to stay around.
+/// We solve this problem by handing out shared pointers to the Value Object and any of its dependents using a shared
+/// ClusterManager. This treats each shared pointer handed out for the entire cluster as a reference to the whole
+/// cluster. The whole cluster will stay around until the last reference is released.
+///
+/// The ValueObject mostly handle this automatically, if a value object is made with a Parent ValueObject, then it adds
+/// itself to the ClusterManager of the parent.
+
+/// It does mean that external to the ValueObjects we should only ever make available ValueObjectSP's, never ValueObjects
+/// or pointers to them. So all the "Root level" ValueObject derived constructors should be private, and
+/// should implement a Create function that new's up object and returns a Shared Pointer that it gets from the GetSP() method.
+///
+/// However, if you are making an derived ValueObject that will be contained in a parent value object, you should just
+/// hold onto a pointer to it internally, and by virtue of passing the parent ValueObject into its constructor, it will
+/// be added to the ClusterManager for the parent. Then if you ever hand out a Shared Pointer to the contained ValueObject,
+/// just do so by calling GetSP() on the contained object.
+
+class ValueObject : public UserID
+{
+public:
+
+ enum GetExpressionPathFormat
+ {
+ eGetExpressionPathFormatDereferencePointers = 1,
+ eGetExpressionPathFormatHonorPointers
+ };
+
+ enum ValueObjectRepresentationStyle
+ {
+ eValueObjectRepresentationStyleValue = 1,
+ eValueObjectRepresentationStyleSummary,
+ eValueObjectRepresentationStyleLanguageSpecific,
+ eValueObjectRepresentationStyleLocation,
+ eValueObjectRepresentationStyleChildrenCount,
+ eValueObjectRepresentationStyleType,
+ eValueObjectRepresentationStyleName,
+ eValueObjectRepresentationStyleExpressionPath
+ };
+
+ enum ExpressionPathScanEndReason
+ {
+ eExpressionPathScanEndReasonEndOfString = 1, // out of data to parse
+ eExpressionPathScanEndReasonNoSuchChild, // child element not found
+ eExpressionPathScanEndReasonEmptyRangeNotAllowed, // [] only allowed for arrays
+ eExpressionPathScanEndReasonDotInsteadOfArrow, // . used when -> should be used
+ eExpressionPathScanEndReasonArrowInsteadOfDot, // -> used when . should be used
+ eExpressionPathScanEndReasonFragileIVarNotAllowed, // ObjC ivar expansion not allowed
+ eExpressionPathScanEndReasonRangeOperatorNotAllowed, // [] not allowed by options
+ eExpressionPathScanEndReasonRangeOperatorInvalid, // [] not valid on objects other than scalars, pointers or arrays
+ eExpressionPathScanEndReasonArrayRangeOperatorMet, // [] is good for arrays, but I cannot parse it
+ eExpressionPathScanEndReasonBitfieldRangeOperatorMet, // [] is good for bitfields, but I cannot parse after it
+ eExpressionPathScanEndReasonUnexpectedSymbol, // something is malformed in the expression
+ eExpressionPathScanEndReasonTakingAddressFailed, // impossible to apply & operator
+ eExpressionPathScanEndReasonDereferencingFailed, // impossible to apply * operator
+ eExpressionPathScanEndReasonRangeOperatorExpanded, // [] was expanded into a VOList
+ eExpressionPathScanEndReasonSyntheticValueMissing, // getting the synthetic children failed
+ eExpressionPathScanEndReasonUnknown = 0xFFFF
+ };
+
+ enum ExpressionPathEndResultType
+ {
+ eExpressionPathEndResultTypePlain = 1, // anything but...
+ eExpressionPathEndResultTypeBitfield, // a bitfield
+ eExpressionPathEndResultTypeBoundedRange, // a range [low-high]
+ eExpressionPathEndResultTypeUnboundedRange, // a range []
+ eExpressionPathEndResultTypeValueObjectList, // several items in a VOList
+ eExpressionPathEndResultTypeInvalid = 0xFFFF
+ };
+
+ enum ExpressionPathAftermath
+ {
+ eExpressionPathAftermathNothing = 1, // just return it
+ eExpressionPathAftermathDereference, // dereference the target
+ eExpressionPathAftermathTakeAddress // take target's address
+ };
+
+ enum ClearUserVisibleDataItems
+ {
+ eClearUserVisibleDataItemsNothing = 1u << 0,
+ eClearUserVisibleDataItemsValue = 1u << 1,
+ eClearUserVisibleDataItemsSummary = 1u << 2,
+ eClearUserVisibleDataItemsLocation = 1u << 3,
+ eClearUserVisibleDataItemsDescription = 1u << 4,
+ eClearUserVisibleDataItemsSyntheticChildren = 1u << 5,
+ eClearUserVisibleDataItemsAllStrings = eClearUserVisibleDataItemsValue | eClearUserVisibleDataItemsSummary | eClearUserVisibleDataItemsLocation | eClearUserVisibleDataItemsDescription,
+ eClearUserVisibleDataItemsAll = 0xFFFF
+ };
+
+ struct GetValueForExpressionPathOptions
+ {
+ bool m_check_dot_vs_arrow_syntax;
+ bool m_no_fragile_ivar;
+ bool m_allow_bitfields_syntax;
+ bool m_no_synthetic_children;
+
+ GetValueForExpressionPathOptions(bool dot = false,
+ bool no_ivar = false,
+ bool bitfield = true,
+ bool no_synth = false) :
+ m_check_dot_vs_arrow_syntax(dot),
+ m_no_fragile_ivar(no_ivar),
+ m_allow_bitfields_syntax(bitfield),
+ m_no_synthetic_children(no_synth)
+ {
+ }
+
+ GetValueForExpressionPathOptions&
+ DoCheckDotVsArrowSyntax()
+ {
+ m_check_dot_vs_arrow_syntax = true;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DontCheckDotVsArrowSyntax()
+ {
+ m_check_dot_vs_arrow_syntax = false;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DoAllowFragileIVar()
+ {
+ m_no_fragile_ivar = false;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DontAllowFragileIVar()
+ {
+ m_no_fragile_ivar = true;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DoAllowBitfieldSyntax()
+ {
+ m_allow_bitfields_syntax = true;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DontAllowBitfieldSyntax()
+ {
+ m_allow_bitfields_syntax = false;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DoAllowSyntheticChildren()
+ {
+ m_no_synthetic_children = false;
+ return *this;
+ }
+
+ GetValueForExpressionPathOptions&
+ DontAllowSyntheticChildren()
+ {
+ m_no_synthetic_children = true;
+ return *this;
+ }
+
+ static const GetValueForExpressionPathOptions
+ DefaultOptions()
+ {
+ static GetValueForExpressionPathOptions g_default_options;
+
+ return g_default_options;
+ }
+
+ };
+
+ struct DumpValueObjectOptions
+ {
+ uint32_t m_max_ptr_depth;
+ uint32_t m_max_depth;
+ bool m_show_types;
+ bool m_show_location;
+ bool m_use_objc;
+ lldb::DynamicValueType m_use_dynamic;
+ bool m_use_synthetic;
+ bool m_scope_already_checked;
+ bool m_flat_output;
+ uint32_t m_omit_summary_depth;
+ bool m_ignore_cap;
+ lldb::Format m_format;
+ lldb::TypeSummaryImplSP m_summary_sp;
+ std::string m_root_valobj_name;
+ bool m_hide_root_type;
+ bool m_hide_name;
+ bool m_hide_value;
+
+ DumpValueObjectOptions() :
+ m_max_ptr_depth(0),
+ m_max_depth(UINT32_MAX),
+ m_show_types(false),
+ m_show_location(false),
+ m_use_objc(false),
+ m_use_dynamic(lldb::eNoDynamicValues),
+ m_use_synthetic(true),
+ m_scope_already_checked(false),
+ m_flat_output(false),
+ m_omit_summary_depth(0),
+ m_ignore_cap(false),
+ m_format (lldb::eFormatDefault),
+ m_summary_sp(),
+ m_root_valobj_name(),
+ m_hide_root_type(false), // provide a special compact display for "po"
+ m_hide_name(false), // provide a special compact display for "po"
+ m_hide_value(false) // provide a special compact display for "po"
+ {}
+
+ static const DumpValueObjectOptions
+ DefaultOptions()
+ {
+ static DumpValueObjectOptions g_default_options;
+
+ return g_default_options;
+ }
+
+ DumpValueObjectOptions (const DumpValueObjectOptions& rhs) :
+ m_max_ptr_depth(rhs.m_max_ptr_depth),
+ m_max_depth(rhs.m_max_depth),
+ m_show_types(rhs.m_show_types),
+ m_show_location(rhs.m_show_location),
+ m_use_objc(rhs.m_use_objc),
+ m_use_dynamic(rhs.m_use_dynamic),
+ m_use_synthetic(rhs.m_use_synthetic),
+ m_scope_already_checked(rhs.m_scope_already_checked),
+ m_flat_output(rhs.m_flat_output),
+ m_omit_summary_depth(rhs.m_omit_summary_depth),
+ m_ignore_cap(rhs.m_ignore_cap),
+ m_format(rhs.m_format),
+ m_summary_sp(rhs.m_summary_sp),
+ m_root_valobj_name(rhs.m_root_valobj_name),
+ m_hide_root_type(rhs.m_hide_root_type),
+ m_hide_name(rhs.m_hide_name),
+ m_hide_value(rhs.m_hide_value)
+ {}
+
+ DumpValueObjectOptions&
+ SetMaximumPointerDepth(uint32_t depth = 0)
+ {
+ m_max_ptr_depth = depth;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetMaximumDepth(uint32_t depth = 0)
+ {
+ m_max_depth = depth;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetShowTypes(bool show = false)
+ {
+ m_show_types = show;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetShowLocation(bool show = false)
+ {
+ m_show_location = show;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetUseObjectiveC(bool use = false)
+ {
+ m_use_objc = use;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetShowSummary(bool show = true)
+ {
+ if (show == false)
+ SetOmitSummaryDepth(UINT32_MAX);
+ else
+ SetOmitSummaryDepth(0);
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetUseDynamicType(lldb::DynamicValueType dyn = lldb::eNoDynamicValues)
+ {
+ m_use_dynamic = dyn;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetUseSyntheticValue(bool use_synthetic = true)
+ {
+ m_use_synthetic = use_synthetic;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetScopeChecked(bool check = true)
+ {
+ m_scope_already_checked = check;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetFlatOutput(bool flat = false)
+ {
+ m_flat_output = flat;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetOmitSummaryDepth(uint32_t depth = 0)
+ {
+ m_omit_summary_depth = depth;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetIgnoreCap(bool ignore = false)
+ {
+ m_ignore_cap = ignore;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetRawDisplay(bool raw = false)
+ {
+ if (raw)
+ {
+ SetUseSyntheticValue(false);
+ SetOmitSummaryDepth(UINT32_MAX);
+ SetIgnoreCap(true);
+ SetHideName(false);
+ SetHideValue(false);
+ }
+ else
+ {
+ SetUseSyntheticValue(true);
+ SetOmitSummaryDepth(0);
+ SetIgnoreCap(false);
+ SetHideName(false);
+ SetHideValue(false);
+ }
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetFormat (lldb::Format format = lldb::eFormatDefault)
+ {
+ m_format = format;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetSummary (lldb::TypeSummaryImplSP summary = lldb::TypeSummaryImplSP())
+ {
+ m_summary_sp = summary;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetRootValueObjectName (const char* name = NULL)
+ {
+ if (name)
+ m_root_valobj_name.assign(name);
+ else
+ m_root_valobj_name.clear();
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetHideRootType (bool hide_root_type = false)
+ {
+ m_hide_root_type = hide_root_type;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetHideName (bool hide_name = false)
+ {
+ m_hide_name = hide_name;
+ return *this;
+ }
+
+ DumpValueObjectOptions&
+ SetHideValue (bool hide_value = false)
+ {
+ m_hide_value = hide_value;
+ return *this;
+ }
+ };
+
+ class EvaluationPoint
+ {
+ public:
+
+ EvaluationPoint ();
+
+ EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected = false);
+
+ EvaluationPoint (const EvaluationPoint &rhs);
+
+ ~EvaluationPoint ();
+
+ const ExecutionContextRef &
+ GetExecutionContextRef() const
+ {
+ return m_exe_ctx_ref;
+ }
+
+ // Set the EvaluationPoint to the values in exe_scope,
+ // Return true if the Evaluation Point changed.
+ // Since the ExecutionContextScope is always going to be valid currently,
+ // the Updated Context will also always be valid.
+
+// bool
+// SetContext (ExecutionContextScope *exe_scope);
+
+ void
+ SetIsConstant ()
+ {
+ SetUpdated();
+ m_mod_id.SetInvalid();
+ }
+
+ bool
+ IsConstant () const
+ {
+ return !m_mod_id.IsValid();
+ }
+
+ ProcessModID
+ GetModID () const
+ {
+ return m_mod_id;
+ }
+
+ void
+ SetUpdateID (ProcessModID new_id)
+ {
+ m_mod_id = new_id;
+ }
+
+ bool
+ IsFirstEvaluation () const
+ {
+ return m_first_update;
+ }
+
+ void
+ SetNeedsUpdate ()
+ {
+ m_needs_update = true;
+ }
+
+ void
+ SetUpdated ();
+
+ bool
+ NeedsUpdating()
+ {
+ SyncWithProcessState();
+ return m_needs_update;
+ }
+
+ bool
+ IsValid ()
+ {
+ if (!m_mod_id.IsValid())
+ return false;
+ else if (SyncWithProcessState ())
+ {
+ if (!m_mod_id.IsValid())
+ return false;
+ }
+ return true;
+ }
+
+ void
+ SetInvalid ()
+ {
+ // Use the stop id to mark us as invalid, leave the thread id and the stack id around for logging and
+ // history purposes.
+ m_mod_id.SetInvalid();
+
+ // Can't update an invalid state.
+ m_needs_update = false;
+
+ }
+
+ private:
+ bool
+ SyncWithProcessState ();
+
+ ProcessModID m_mod_id; // This is the stop id when this ValueObject was last evaluated.
+ ExecutionContextRef m_exe_ctx_ref;
+ bool m_needs_update;
+ bool m_first_update;
+ };
+
+ const EvaluationPoint &
+ GetUpdatePoint () const
+ {
+ return m_update_point;
+ }
+
+ EvaluationPoint &
+ GetUpdatePoint ()
+ {
+ return m_update_point;
+ }
+
+ const ExecutionContextRef &
+ GetExecutionContextRef() const
+ {
+ return m_update_point.GetExecutionContextRef();
+ }
+
+ lldb::TargetSP
+ GetTargetSP() const
+ {
+ return m_update_point.GetExecutionContextRef().GetTargetSP();
+ }
+
+ lldb::ProcessSP
+ GetProcessSP() const
+ {
+ return m_update_point.GetExecutionContextRef().GetProcessSP();
+ }
+
+ lldb::ThreadSP
+ GetThreadSP() const
+ {
+ return m_update_point.GetExecutionContextRef().GetThreadSP();
+ }
+
+ lldb::StackFrameSP
+ GetFrameSP() const
+ {
+ return m_update_point.GetExecutionContextRef().GetFrameSP();
+ }
+
+ void
+ SetNeedsUpdate ();
+
+ virtual ~ValueObject();
+
+ ClangASTType
+ GetClangType ();
+
+ //------------------------------------------------------------------
+ // Sublasses must implement the functions below.
+ //------------------------------------------------------------------
+ virtual uint64_t
+ GetByteSize() = 0;
+
+ virtual lldb::ValueType
+ GetValueType() const = 0;
+
+ //------------------------------------------------------------------
+ // Sublasses can implement the functions below.
+ //------------------------------------------------------------------
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual lldb::LanguageType
+ GetObjectRuntimeLanguage();
+
+ virtual uint32_t
+ GetTypeInfo (ClangASTType *pointee_or_element_clang_type = NULL);
+
+ virtual bool
+ IsPointerType ();
+
+ virtual bool
+ IsArrayType ();
+
+ virtual bool
+ IsScalarType ();
+
+ virtual bool
+ IsPointerOrReferenceType ();
+
+ virtual bool
+ IsPossibleDynamicType ();
+
+ virtual bool
+ IsObjCNil ();
+
+ virtual bool
+ IsBaseClass ()
+ {
+ return false;
+ }
+
+ virtual bool
+ IsDereferenceOfParent ()
+ {
+ return false;
+ }
+
+ bool
+ IsIntegerType (bool &is_signed);
+
+ virtual bool
+ GetBaseClassPath (Stream &s);
+
+ virtual void
+ GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat = eGetExpressionPathFormatDereferencePointers);
+
+ lldb::ValueObjectSP
+ GetValueForExpressionPath(const char* expression,
+ const char** first_unparsed = NULL,
+ ExpressionPathScanEndReason* reason_to_stop = NULL,
+ ExpressionPathEndResultType* final_value_type = NULL,
+ const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(),
+ ExpressionPathAftermath* final_task_on_target = NULL);
+
+ int
+ GetValuesForExpressionPath(const char* expression,
+ lldb::ValueObjectListSP& list,
+ const char** first_unparsed = NULL,
+ ExpressionPathScanEndReason* reason_to_stop = NULL,
+ ExpressionPathEndResultType* final_value_type = NULL,
+ const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(),
+ ExpressionPathAftermath* final_task_on_target = NULL);
+
+ virtual bool
+ IsInScope ()
+ {
+ return true;
+ }
+
+ virtual off_t
+ GetByteOffset()
+ {
+ return 0;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitSize ()
+ {
+ return 0;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitOffset ()
+ {
+ return 0;
+ }
+
+ bool
+ IsBitfield ()
+ {
+ return (GetBitfieldBitSize() != 0) || (GetBitfieldBitOffset() != 0);
+ }
+
+ virtual bool
+ IsArrayItemForPointer()
+ {
+ return m_is_array_item_for_pointer;
+ }
+
+ virtual const char *
+ GetValueAsCString ();
+
+ virtual bool
+ GetValueAsCString (lldb::Format format,
+ std::string& destination);
+
+ virtual uint64_t
+ GetValueAsUnsigned (uint64_t fail_value, bool *success = NULL);
+
+ virtual bool
+ SetValueFromCString (const char *value_str, Error& error);
+
+ // Return the module associated with this value object in case the
+ // value is from an executable file and might have its data in
+ // sections of the file. This can be used for variables.
+ virtual lldb::ModuleSP
+ GetModule();
+
+ virtual ValueObject*
+ GetRoot ();
+
+ virtual bool
+ GetDeclaration (Declaration &decl);
+
+ //------------------------------------------------------------------
+ // The functions below should NOT be modified by sublasses
+ //------------------------------------------------------------------
+ const Error &
+ GetError();
+
+ const ConstString &
+ GetName() const;
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx, bool can_create);
+
+ // this will always create the children if necessary
+ lldb::ValueObjectSP
+ GetChildAtIndexPath (const std::initializer_list<size_t> &idxs,
+ size_t* index_of_error = NULL);
+
+ lldb::ValueObjectSP
+ GetChildAtIndexPath (const std::vector<size_t> &idxs,
+ size_t* index_of_error = NULL);
+
+ lldb::ValueObjectSP
+ GetChildAtIndexPath (const std::initializer_list< std::pair<size_t, bool> > &idxs,
+ size_t* index_of_error = NULL);
+
+ lldb::ValueObjectSP
+ GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs,
+ size_t* index_of_error = NULL);
+
+ virtual lldb::ValueObjectSP
+ GetChildMemberWithName (const ConstString &name, bool can_create);
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ size_t
+ GetNumChildren ();
+
+ const Value &
+ GetValue() const;
+
+ Value &
+ GetValue();
+
+ virtual bool
+ ResolveValue (Scalar &scalar);
+
+ virtual const char *
+ GetLocationAsCString ();
+
+ const char *
+ GetSummaryAsCString ();
+
+ bool
+ GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
+ std::string& destination);
+
+ const char *
+ GetObjectDescription ();
+
+ bool
+ HasSpecialPrintableRepresentation (ValueObjectRepresentationStyle val_obj_display,
+ lldb::Format custom_format);
+
+ enum PrintableRepresentationSpecialCases
+ {
+ ePrintableRepresentationSpecialCasesDisable = 0,
+ ePrintableRepresentationSpecialCasesAllow = 1,
+ ePrintableRepresentationSpecialCasesOnly = 3
+ };
+
+ bool
+ DumpPrintableRepresentation (Stream& s,
+ ValueObjectRepresentationStyle val_obj_display = eValueObjectRepresentationStyleSummary,
+ lldb::Format custom_format = lldb::eFormatInvalid,
+ PrintableRepresentationSpecialCases special = ePrintableRepresentationSpecialCasesAllow);
+ bool
+ GetValueIsValid () const;
+
+ bool
+ GetValueDidChange ();
+
+ bool
+ UpdateValueIfNeeded (bool update_format = true);
+
+ bool
+ UpdateFormatsIfNeeded();
+
+ lldb::ValueObjectSP
+ GetSP ()
+ {
+ return m_manager->GetSharedPointer(this);
+ }
+
+ void
+ SetName (const ConstString &name);
+
+ virtual lldb::addr_t
+ GetAddressOf (bool scalar_is_load_address = true,
+ AddressType *address_type = NULL);
+
+ lldb::addr_t
+ GetPointerValue (AddressType *address_type = NULL);
+
+ lldb::ValueObjectSP
+ GetSyntheticChild (const ConstString &key) const;
+
+ lldb::ValueObjectSP
+ GetSyntheticArrayMember (size_t index, bool can_create);
+
+ lldb::ValueObjectSP
+ GetSyntheticArrayMemberFromPointer (size_t index, bool can_create);
+
+ lldb::ValueObjectSP
+ GetSyntheticArrayMemberFromArray (size_t index, bool can_create);
+
+ lldb::ValueObjectSP
+ GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create);
+
+ lldb::ValueObjectSP
+ GetSyntheticExpressionPathChild(const char* expression, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ GetDynamicValue (lldb::DynamicValueType valueType);
+
+ lldb::DynamicValueType
+ GetDynamicValueType ();
+
+ virtual lldb::ValueObjectSP
+ GetStaticValue ();
+
+ virtual lldb::ValueObjectSP
+ GetNonSyntheticValue ();
+
+ lldb::ValueObjectSP
+ GetSyntheticValue (bool use_synthetic = true);
+
+ virtual bool
+ HasSyntheticValue();
+
+ virtual bool
+ IsSynthetic() { return false; }
+
+ virtual lldb::ValueObjectSP
+ CreateConstantValue (const ConstString &name);
+
+ virtual lldb::ValueObjectSP
+ Dereference (Error &error);
+
+ virtual lldb::ValueObjectSP
+ AddressOf (Error &error);
+
+ virtual lldb::addr_t
+ GetLiveAddress()
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ virtual void
+ SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS,
+ AddressType address_type = eAddressTypeLoad)
+ {
+ }
+
+ virtual lldb::ValueObjectSP
+ Cast (const ClangASTType &clang_ast_type);
+
+ virtual lldb::ValueObjectSP
+ CastPointerType (const char *name,
+ ClangASTType &ast_type);
+
+ virtual lldb::ValueObjectSP
+ CastPointerType (const char *name,
+ lldb::TypeSP &type_sp);
+
+ // The backing bits of this value object were updated, clear any
+ // descriptive string, so we know we have to refetch them
+ virtual void
+ ValueUpdated ()
+ {
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue |
+ eClearUserVisibleDataItemsSummary |
+ eClearUserVisibleDataItemsDescription);
+ }
+
+ virtual bool
+ IsDynamic ()
+ {
+ return false;
+ }
+
+ virtual SymbolContextScope *
+ GetSymbolContextScope();
+
+ static void
+ DumpValueObject (Stream &s,
+ ValueObject *valobj);
+ static void
+ DumpValueObject (Stream &s,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options);
+
+ static lldb::ValueObjectSP
+ CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx);
+
+ static lldb::ValueObjectSP
+ CreateValueObjectFromAddress (const char* name,
+ uint64_t address,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type);
+
+ static lldb::ValueObjectSP
+ CreateValueObjectFromData (const char* name,
+ DataExtractor& data,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type);
+
+ static void
+ LogValueObject (Log *log,
+ ValueObject *valobj);
+
+ static void
+ LogValueObject (Log *log,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options);
+
+
+ // returns true if this is a char* or a char[]
+ // if it is a char* and check_pointer is true,
+ // it also checks that the pointer is valid
+ bool
+ IsCStringContainer (bool check_pointer = false);
+
+ size_t
+ ReadPointedString (Stream& s,
+ Error& error,
+ uint32_t max_length = 0,
+ bool honor_array = true,
+ lldb::Format item_format = lldb::eFormatCharArray);
+
+ virtual size_t
+ GetPointeeData (DataExtractor& data,
+ uint32_t item_idx = 0,
+ uint32_t item_count = 1);
+
+ virtual uint64_t
+ GetData (DataExtractor& data);
+
+ virtual bool
+ SetData (DataExtractor &data, Error &error);
+
+ bool
+ GetIsConstant () const
+ {
+ return m_update_point.IsConstant();
+ }
+
+ void
+ SetIsConstant ()
+ {
+ m_update_point.SetIsConstant();
+ }
+
+ lldb::Format
+ GetFormat () const;
+
+ void
+ SetFormat (lldb::Format format)
+ {
+ if (format != m_format)
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+ m_format = format;
+ }
+
+ lldb::TypeSummaryImplSP
+ GetSummaryFormat()
+ {
+ UpdateFormatsIfNeeded();
+ return m_type_summary_sp;
+ }
+
+ void
+ SetSummaryFormat(lldb::TypeSummaryImplSP format)
+ {
+ m_type_summary_sp = format;
+ ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
+ }
+
+ void
+ SetValueFormat(lldb::TypeFormatImplSP format)
+ {
+ m_type_format_sp = format;
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+ }
+
+ lldb::TypeFormatImplSP
+ GetValueFormat()
+ {
+ UpdateFormatsIfNeeded();
+ return m_type_format_sp;
+ }
+
+ void
+ SetSyntheticChildren(const lldb::SyntheticChildrenSP &synth_sp)
+ {
+ if (synth_sp.get() == m_synthetic_children_sp.get())
+ return;
+ ClearUserVisibleData(eClearUserVisibleDataItemsSyntheticChildren);
+ m_synthetic_children_sp = synth_sp;
+ }
+
+ lldb::SyntheticChildrenSP
+ GetSyntheticChildren()
+ {
+ UpdateFormatsIfNeeded();
+ return m_synthetic_children_sp;
+ }
+
+ // Use GetParent for display purposes, but if you want to tell the parent to update itself
+ // then use m_parent. The ValueObjectDynamicValue's parent is not the correct parent for
+ // displaying, they are really siblings, so for display it needs to route through to its grandparent.
+ virtual ValueObject *
+ GetParent()
+ {
+ return m_parent;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ return m_parent;
+ }
+
+ ValueObject *
+ GetNonBaseClassParent();
+
+ void
+ SetAddressTypeOfChildren(AddressType at)
+ {
+ m_address_type_of_ptr_or_ref_children = at;
+ }
+
+ AddressType
+ GetAddressTypeOfChildren();
+
+ void
+ SetHasCompleteType()
+ {
+ m_did_calculate_complete_objc_class_type = true;
+ }
+
+ //------------------------------------------------------------------
+ /// Find out if a ValueObject might have children.
+ ///
+ /// This call is much more efficient than CalculateNumChildren() as
+ /// it doesn't need to complete the underlying type. This is designed
+ /// to be used in a UI environment in order to detect if the
+ /// disclosure triangle should be displayed or not.
+ ///
+ /// This function returns true for class, union, structure,
+ /// pointers, references, arrays and more. Again, it does so without
+ /// doing any expensive type completion.
+ ///
+ /// @return
+ /// Returns \b true if the ValueObject might have children, or \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ MightHaveChildren();
+
+protected:
+ typedef ClusterManager<ValueObject> ValueObjectManager;
+
+ class ChildrenManager
+ {
+ public:
+ ChildrenManager() :
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_children(),
+ m_children_count(0)
+ {}
+
+ bool
+ HasChildAtIndex (size_t idx)
+ {
+ Mutex::Locker locker(m_mutex);
+ ChildrenIterator iter = m_children.find(idx);
+ ChildrenIterator end = m_children.end();
+ return (iter != end);
+ }
+
+ ValueObject*
+ GetChildAtIndex (size_t idx)
+ {
+ Mutex::Locker locker(m_mutex);
+ ChildrenIterator iter = m_children.find(idx);
+ ChildrenIterator end = m_children.end();
+ if (iter == end)
+ return NULL;
+ else
+ return iter->second;
+ }
+
+ void
+ SetChildAtIndex (size_t idx, ValueObject* valobj)
+ {
+ ChildrenPair pair(idx,valobj); // we do not need to be mutex-protected to make a pair
+ Mutex::Locker locker(m_mutex);
+ m_children.insert(pair);
+ }
+
+ void
+ SetChildrenCount (size_t count)
+ {
+ m_children_count = count;
+ }
+
+ size_t
+ GetChildrenCount ()
+ {
+ return m_children_count;
+ }
+
+ void
+ Clear()
+ {
+ m_children_count = 0;
+ Mutex::Locker locker(m_mutex);
+ m_children.clear();
+ }
+
+ private:
+ typedef std::map<size_t, ValueObject*> ChildrenMap;
+ typedef ChildrenMap::iterator ChildrenIterator;
+ typedef ChildrenMap::value_type ChildrenPair;
+ Mutex m_mutex;
+ ChildrenMap m_children;
+ size_t m_children_count;
+ };
+
+ //------------------------------------------------------------------
+ // Classes that inherit from ValueObject can see and modify these
+ //------------------------------------------------------------------
+ ValueObject * m_parent; // The parent value object, or NULL if this has no parent
+ ValueObject * m_root; // The root of the hierarchy for this ValueObject (or NULL if never calculated)
+ EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
+ // updated. When we are asked to update the value object, we check whether
+ // the context & stop id are the same before updating.
+ ConstString m_name; // The name of this object
+ DataExtractor m_data; // A data extractor that can be used to extract the value.
+ Value m_value;
+ Error m_error; // An error object that can describe any errors that occur when updating values.
+ std::string m_value_str; // Cached value string that will get cleared if/when the value is updated.
+ std::string m_old_value_str;// Cached old value string from the last time the value was gotten
+ std::string m_location_str; // Cached location string that will get cleared if/when the value is updated.
+ std::string m_summary_str; // Cached summary string that will get cleared if/when the value is updated.
+ std::string m_object_desc_str; // Cached result of the "object printer". This differs from the summary
+ // in that the summary is consed up by us, the object_desc_string is builtin.
+
+ ClangASTType m_override_type;// If the type of the value object should be overridden, the type to impose.
+
+ ValueObjectManager *m_manager; // This object is managed by the root object (any ValueObject that gets created
+ // without a parent.) The manager gets passed through all the generations of
+ // dependent objects, and will keep the whole cluster of objects alive as long
+ // as a shared pointer to any of them has been handed out. Shared pointers to
+ // value objects must always be made with the GetSP method.
+
+ ChildrenManager m_children;
+ std::map<ConstString, ValueObject *> m_synthetic_children;
+
+ ValueObject* m_dynamic_value;
+ ValueObject* m_synthetic_value;
+ ValueObject* m_deref_valobj;
+
+ lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared pointer to this one because it is created
+ // as an independent ValueObjectConstResult, which isn't managed by us.
+
+ lldb::Format m_format;
+ lldb::Format m_last_format;
+ uint32_t m_last_format_mgr_revision;
+ lldb::TypeSummaryImplSP m_type_summary_sp;
+ lldb::TypeFormatImplSP m_type_format_sp;
+ lldb::SyntheticChildrenSP m_synthetic_children_sp;
+ ProcessModID m_user_id_of_forced_summary;
+ AddressType m_address_type_of_ptr_or_ref_children;
+
+ bool m_value_is_valid:1,
+ m_value_did_change:1,
+ m_children_count_valid:1,
+ m_old_value_valid:1,
+ m_is_deref_of_parent:1,
+ m_is_array_item_for_pointer:1,
+ m_is_bitfield_for_scalar:1,
+ m_is_child_at_offset:1,
+ m_is_getting_summary:1,
+ m_did_calculate_complete_objc_class_type:1;
+
+ friend class ClangExpressionDeclMap; // For GetValue
+ friend class ClangExpressionVariable; // For SetName
+ friend class Target; // For SetName
+ friend class ValueObjectConstResultImpl;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+
+ // Use the no-argument constructor to make a constant variable object (with no ExecutionContextScope.)
+
+ ValueObject();
+
+ // Use this constructor to create a "root variable object". The ValueObject will be locked to this context
+ // through-out its lifespan.
+
+ ValueObject (ExecutionContextScope *exe_scope,
+ AddressType child_ptr_or_ref_addr_type = eAddressTypeLoad);
+
+ // Use this constructor to create a ValueObject owned by another ValueObject. It will inherit the ExecutionContext
+ // of its parent.
+
+ ValueObject (ValueObject &parent);
+
+ ValueObjectManager *
+ GetManager()
+ {
+ return m_manager;
+ }
+
+ virtual bool
+ UpdateValue () = 0;
+
+ virtual void
+ CalculateDynamicValue (lldb::DynamicValueType use_dynamic);
+
+ virtual lldb::DynamicValueType
+ GetDynamicValueTypeImpl ()
+ {
+ return lldb::eNoDynamicValues;
+ }
+
+ virtual bool
+ HasDynamicValueTypeInfo ()
+ {
+ return false;
+ }
+
+ virtual void
+ CalculateSyntheticValue (bool use_synthetic = true);
+
+ // Should only be called by ValueObject::GetChildAtIndex()
+ // Returns a ValueObject managed by this ValueObject's manager.
+ virtual ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+ // Should only be called by ValueObject::GetNumChildren()
+ virtual size_t
+ CalculateNumChildren() = 0;
+
+ void
+ SetNumChildren (size_t num_children);
+
+ void
+ SetValueDidChange (bool value_changed);
+
+ void
+ SetValueIsValid (bool valid);
+
+ void
+ ClearUserVisibleData(uint32_t items = ValueObject::eClearUserVisibleDataItemsAllStrings);
+
+ void
+ AddSyntheticChild (const ConstString &key,
+ ValueObject *valobj);
+
+ DataExtractor &
+ GetDataExtractor ();
+
+ void
+ ClearDynamicTypeInformation ();
+
+ //------------------------------------------------------------------
+ // Sublasses must implement the functions below.
+ //------------------------------------------------------------------
+
+ virtual ClangASTType
+ GetClangTypeImpl () = 0;
+
+ const char *
+ GetLocationAsCStringImpl (const Value& value,
+ const DataExtractor& data);
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+
+ virtual ClangASTType
+ MaybeCalculateCompleteType ();
+
+ lldb::ValueObjectSP
+ GetValueForExpressionPath_Impl(const char* expression_cstr,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target);
+
+ // this method will ONLY expand [] expressions into a VOList and return
+ // the number of elements it added to the VOList
+ // it will NOT loop through expanding the follow-up of the expression_cstr
+ // for all objects in the list
+ int
+ ExpandArraySliceExpression(const char* expression_cstr,
+ const char** first_unparsed,
+ lldb::ValueObjectSP root,
+ lldb::ValueObjectListSP& list,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target);
+
+
+ DISALLOW_COPY_AND_ASSIGN (ValueObject);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObject_h_
diff --git a/include/lldb/Core/ValueObjectCast.h b/include/lldb/Core/ValueObjectCast.h
new file mode 100644
index 000000000000..1538d7a55639
--- /dev/null
+++ b/include/lldb/Core/ValueObjectCast.h
@@ -0,0 +1,87 @@
+//===-- ValueObjectDynamicValue.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_ValueObjectCast_h_
+#define liblldb_ValueObjectCast_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//---------------------------------------------------------------------------------
+// A ValueObject that represents a given value represented as a different type.
+//---------------------------------------------------------------------------------
+class ValueObjectCast : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type);
+
+ virtual
+ ~ValueObjectCast();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+ virtual ValueObject *
+ GetParent()
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ ClangASTType m_cast_type;
+
+private:
+ ValueObjectCast (ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type);
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectCast);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectCast_h_
diff --git a/include/lldb/Core/ValueObjectChild.h b/include/lldb/Core/ValueObjectChild.h
new file mode 100644
index 000000000000..780529a4af11
--- /dev/null
+++ b/include/lldb/Core/ValueObjectChild.h
@@ -0,0 +1,122 @@
+//===-- ValueObjectChild.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_ValueObjectChild_h_
+#define liblldb_ValueObjectChild_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A child of another ValueObject.
+//----------------------------------------------------------------------
+class ValueObjectChild : public ValueObject
+{
+public:
+ virtual ~ValueObjectChild();
+
+ virtual uint64_t
+ GetByteSize()
+ {
+ return m_byte_size;
+ }
+
+ virtual off_t
+ GetByteOffset()
+ {
+ return m_byte_offset;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitSize()
+ {
+ return m_bitfield_bit_size;
+ }
+
+ virtual uint32_t
+ GetBitfieldBitOffset()
+ {
+ return m_bitfield_bit_offset;
+ }
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual bool
+ IsInScope ();
+
+ virtual bool
+ IsBaseClass ()
+ {
+ return m_is_base_class;
+ }
+
+ virtual bool
+ IsDereferenceOfParent ()
+ {
+ return m_is_deref_of_parent;
+ }
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ()
+ {
+ return m_clang_type;
+ }
+
+ ClangASTType m_clang_type;
+ ConstString m_type_name;
+ uint64_t m_byte_size;
+ int32_t m_byte_offset;
+ uint8_t m_bitfield_bit_size;
+ uint8_t m_bitfield_bit_offset;
+ bool m_is_base_class;
+ bool m_is_deref_of_parent;
+
+//
+// void
+// ReadValueFromMemory (ValueObject* parent, lldb::addr_t address);
+
+protected:
+ friend class ValueObject;
+ friend class ValueObjectConstResult;
+ ValueObjectChild (ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint64_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent,
+ AddressType child_ptr_or_ref_addr_type);
+
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectChild);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectChild_h_
diff --git a/include/lldb/Core/ValueObjectConstResult.h b/include/lldb/Core/ValueObjectConstResult.h
new file mode 100644
index 000000000000..4964d0589a09
--- /dev/null
+++ b/include/lldb/Core/ValueObjectConstResult.h
@@ -0,0 +1,179 @@
+//===-- ValueObjectConstResult.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_ValueObjectConstResult_h_
+#define liblldb_ValueObjectConstResult_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Core/ValueObjectConstResultImpl.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A frozen ValueObject copied into host memory
+//----------------------------------------------------------------------
+class ValueObjectConstResult : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address = LLDB_INVALID_ADDRESS);
+
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address = LLDB_INVALID_ADDRESS);
+
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &result_data_sp,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_size,
+ lldb::addr_t address = LLDB_INVALID_ADDRESS);
+
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size);
+
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ Value &value,
+ const ConstString &name);
+
+ // When an expression fails to evaluate, we return an error
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const Error& error);
+
+ virtual ~ValueObjectConstResult();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual bool
+ IsInScope ();
+
+ void
+ SetByteSize (size_t size);
+
+ virtual lldb::ValueObjectSP
+ Dereference (Error &error);
+
+ virtual ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+ virtual lldb::ValueObjectSP
+ GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ AddressOf (Error &error);
+
+ virtual lldb::addr_t
+ GetAddressOf (bool scalar_is_load_address = true,
+ AddressType *address_type = NULL);
+
+ virtual size_t
+ GetPointeeData (DataExtractor& data,
+ uint32_t item_idx = 0,
+ uint32_t item_count = 1);
+
+ virtual lldb::addr_t
+ GetLiveAddress()
+ {
+ return m_impl.GetLiveAddress();
+ }
+
+ virtual void
+ SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS,
+ AddressType address_type = eAddressTypeLoad)
+ {
+ m_impl.SetLiveAddress(addr,
+ address_type);
+ }
+
+ virtual lldb::ValueObjectSP
+ GetDynamicValue (lldb::DynamicValueType valueType);
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ ConstString m_type_name;
+ uint64_t m_byte_size;
+
+ ValueObjectConstResultImpl m_impl;
+
+private:
+ friend class ValueObjectConstResultImpl;
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address);
+
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address);
+
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &result_data_sp,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_size,
+ lldb::addr_t address);
+
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size);
+
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Value &value,
+ const ConstString &name);
+
+ ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Error& error);
+
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectConstResult);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectConstResult_h_
diff --git a/include/lldb/Core/ValueObjectConstResultChild.h b/include/lldb/Core/ValueObjectConstResultChild.h
new file mode 100644
index 000000000000..9063276b0198
--- /dev/null
+++ b/include/lldb/Core/ValueObjectConstResultChild.h
@@ -0,0 +1,77 @@
+//===-- ValueObjectConstResultChild.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_ValueObjectConstResultChild_h_
+#define liblldb_ValueObjectConstResultChild_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResultImpl.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A child of a ValueObjectConstResult.
+//----------------------------------------------------------------------
+class ValueObjectConstResultChild : public ValueObjectChild
+{
+public:
+
+ ValueObjectConstResultChild (ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent);
+
+ virtual ~ValueObjectConstResultChild();
+
+ virtual lldb::ValueObjectSP
+ Dereference (Error &error);
+
+ virtual ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+ virtual ClangASTType
+ GetClangType ()
+ {
+ return ValueObjectChild::GetClangType();
+ }
+
+ virtual lldb::ValueObjectSP
+ GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ AddressOf (Error &error);
+
+ virtual size_t
+ GetPointeeData (DataExtractor& data,
+ uint32_t item_idx = 0,
+ uint32_t item_count = 1);
+
+protected:
+ ValueObjectConstResultImpl m_impl;
+
+private:
+ friend class ValueObject;
+ friend class ValueObjectConstResult;
+ friend class ValueObjectConstResultImpl;
+
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectConstResultChild);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectConstResultChild_h_
diff --git a/include/lldb/Core/ValueObjectConstResultImpl.h b/include/lldb/Core/ValueObjectConstResultImpl.h
new file mode 100644
index 000000000000..271b93823569
--- /dev/null
+++ b/include/lldb/Core/ValueObjectConstResultImpl.h
@@ -0,0 +1,96 @@
+//===-- ValueObjectConstResultImpl.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_ValueObjectConstResultImpl_h_
+#define liblldb_ValueObjectConstResultImpl_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A class wrapping common implementation details for operations in
+// ValueObjectConstResult ( & Child ) that may need to jump from the host
+// memory space into the target's memory space
+//----------------------------------------------------------------------
+class ValueObjectConstResultImpl
+{
+public:
+
+ ValueObjectConstResultImpl (ValueObject* valobj,
+ lldb::addr_t live_address = LLDB_INVALID_ADDRESS);
+
+ virtual
+ ~ValueObjectConstResultImpl()
+ {
+ }
+
+ lldb::ValueObjectSP
+ Dereference (Error &error);
+
+ ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+ lldb::ValueObjectSP
+ GetSyntheticChildAtOffset (uint32_t offset, const ClangASTType& type, bool can_create);
+
+ lldb::ValueObjectSP
+ AddressOf (Error &error);
+
+ bool
+ NeedsDerefOnTarget()
+ {
+ m_impl_backend->UpdateValueIfNeeded(false);
+ return (m_impl_backend->GetValue().GetValueType() == Value::eValueTypeHostAddress);
+ }
+
+ lldb::addr_t
+ GetLiveAddress()
+ {
+ return m_live_address;
+ }
+
+ void
+ SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS,
+ AddressType address_type = eAddressTypeLoad)
+ {
+ m_live_address = addr;
+ m_live_address_type = address_type;
+ }
+
+ lldb::ValueObjectSP
+ DerefOnTarget();
+
+ virtual lldb::addr_t
+ GetAddressOf (bool scalar_is_load_address = true,
+ AddressType *address_type = NULL);
+
+ virtual size_t
+ GetPointeeData (DataExtractor& data,
+ uint32_t item_idx = 0,
+ uint32_t item_count = 1);
+
+private:
+
+ ValueObject *m_impl_backend;
+ lldb::addr_t m_live_address;
+ AddressType m_live_address_type;
+ lldb::ValueObjectSP m_load_addr_backend;
+ lldb::ValueObjectSP m_address_of_backend;
+
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectConstResultImpl);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectConstResultImpl_h_
diff --git a/include/lldb/Core/ValueObjectDynamicValue.h b/include/lldb/Core/ValueObjectDynamicValue.h
new file mode 100644
index 000000000000..c0f6baade3fb
--- /dev/null
+++ b/include/lldb/Core/ValueObjectDynamicValue.h
@@ -0,0 +1,133 @@
+//===-- ValueObjectDynamicValue.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_ValueObjectDynamicValue_h_
+#define liblldb_ValueObjectDynamicValue_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/Type.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that represents memory at a given address, viewed as some
+// set lldb type.
+//----------------------------------------------------------------------
+class ValueObjectDynamicValue : public ValueObject
+{
+public:
+ virtual
+ ~ValueObjectDynamicValue();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+ virtual bool
+ IsDynamic ()
+ {
+ return true;
+ }
+
+ virtual ValueObject *
+ GetParent()
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetStaticValue ()
+ {
+ return m_parent->GetSP();
+ }
+
+ void
+ SetOwningSP (lldb::ValueObjectSP &owning_sp)
+ {
+ if (m_owning_valobj_sp == owning_sp)
+ return;
+
+ assert (m_owning_valobj_sp.get() == NULL);
+ m_owning_valobj_sp = owning_sp;
+ }
+
+ virtual bool
+ SetValueFromCString (const char *value_str, Error& error);
+
+ virtual bool
+ SetData (DataExtractor &data, Error &error);
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual lldb::DynamicValueType
+ GetDynamicValueTypeImpl ()
+ {
+ return m_use_dynamic;
+ }
+
+ virtual bool
+ HasDynamicValueTypeInfo ()
+ {
+ return true;
+ }
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ Address m_address; ///< The variable that this value object is based upon
+ TypeAndOrName m_dynamic_type_info; // We can have a type_sp or just a name
+ lldb::ValueObjectSP m_owning_valobj_sp;
+ lldb::DynamicValueType m_use_dynamic;
+
+private:
+ friend class ValueObject;
+ friend class ValueObjectConstResult;
+ ValueObjectDynamicValue (ValueObject &parent, lldb::DynamicValueType use_dynamic);
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectDynamicValue);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectDynamicValue_h_
diff --git a/include/lldb/Core/ValueObjectList.h b/include/lldb/Core/ValueObjectList.h
new file mode 100644
index 000000000000..5bfe40b2e952
--- /dev/null
+++ b/include/lldb/Core/ValueObjectList.h
@@ -0,0 +1,90 @@
+//===-- ValueObjectList.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_ValueObjectList_h_
+#define liblldb_ValueObjectList_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Target/ExecutionContextScope.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A collection of ValueObject values that
+//----------------------------------------------------------------------
+class ValueObjectList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ValueObjectList ();
+
+ ValueObjectList (const ValueObjectList &rhs);
+
+ ~ValueObjectList();
+
+ const ValueObjectList &
+ operator = (const ValueObjectList &rhs);
+
+ void
+ Append (const lldb::ValueObjectSP &val_obj_sp);
+
+ void
+ Append (const ValueObjectList &valobj_list);
+
+ lldb::ValueObjectSP
+ FindValueObjectByPointer (ValueObject *valobj);
+
+ size_t
+ GetSize () const;
+
+ void
+ Resize (size_t size);
+
+ lldb::ValueObjectSP
+ GetValueObjectAtIndex (size_t idx);
+
+ lldb::ValueObjectSP
+ RemoveValueObjectAtIndex (size_t idx);
+
+ void
+ SetValueObjectAtIndex (size_t idx,
+ const lldb::ValueObjectSP &valobj_sp);
+
+ lldb::ValueObjectSP
+ FindValueObjectByValueName (const char *name);
+
+ lldb::ValueObjectSP
+ FindValueObjectByUID (lldb::user_id_t uid);
+
+ void
+ Swap (ValueObjectList &value_object_list);
+
+protected:
+ typedef std::vector<lldb::ValueObjectSP> collection;
+ //------------------------------------------------------------------
+ // Classes that inherit from ValueObjectList can see and modify these
+ //------------------------------------------------------------------
+ collection m_value_objects;
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectList_h_
diff --git a/include/lldb/Core/ValueObjectMemory.h b/include/lldb/Core/ValueObjectMemory.h
new file mode 100644
index 000000000000..627d73eb4b27
--- /dev/null
+++ b/include/lldb/Core/ValueObjectMemory.h
@@ -0,0 +1,91 @@
+//===-- ValueObjectMemory.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_ValueObjectMemory_h_
+#define liblldb_ValueObjectMemory_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that represents memory at a given address, viewed as some
+// set lldb type.
+//----------------------------------------------------------------------
+class ValueObjectMemory : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp);
+
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type);
+
+ virtual
+ ~ValueObjectMemory();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+ virtual lldb::ModuleSP
+ GetModule();
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ Address m_address; ///< The variable that this value object is based upon
+ lldb::TypeSP m_type_sp;
+ ClangASTType m_clang_type;
+
+private:
+ ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp);
+
+ ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type);
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectMemory);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectMemory_h_
diff --git a/include/lldb/Core/ValueObjectRegister.h b/include/lldb/Core/ValueObjectRegister.h
new file mode 100644
index 000000000000..6820629f08e1
--- /dev/null
+++ b/include/lldb/Core/ValueObjectRegister.h
@@ -0,0 +1,195 @@
+//===-- ValueObjectRegister.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_ValueObjectRegister_h_
+#define liblldb_ValueObjectRegister_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that contains a root variable that may or may not
+// have children.
+//----------------------------------------------------------------------
+class ValueObjectRegisterContext : public ValueObject
+{
+public:
+
+ virtual
+ ~ValueObjectRegisterContext();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegisterSet;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ lldb::RegisterContextSP m_reg_ctx_sp;
+
+private:
+ ValueObjectRegisterContext (ValueObject &parent, lldb::RegisterContextSP &reg_ctx_sp);
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegisterContext);
+};
+
+class ValueObjectRegisterSet : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t set_idx);
+
+ virtual
+ ~ValueObjectRegisterSet();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegisterSet;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual ValueObject *
+ CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index);
+
+ virtual lldb::ValueObjectSP
+ GetChildMemberWithName (const ConstString &name, bool can_create);
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ const RegisterSet *m_reg_set;
+ uint32_t m_reg_set_idx;
+
+private:
+ friend class ValueObjectRegisterContext;
+ ValueObjectRegisterSet (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t set_idx);
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegisterSet);
+};
+
+class ValueObjectRegister : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num);
+
+ virtual
+ ~ValueObjectRegister();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual lldb::ValueType
+ GetValueType () const
+ {
+ return lldb::eValueTypeRegister;
+ }
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual bool
+ SetValueFromCString (const char *value_str, Error& error);
+
+ virtual bool
+ SetData (DataExtractor &data, Error &error);
+
+ virtual bool
+ ResolveValue (Scalar &scalar);
+
+ virtual void
+ GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat = eGetExpressionPathFormatDereferencePointers);
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ RegisterInfo m_reg_info;
+ RegisterValue m_reg_value;
+ ConstString m_type_name;
+ ClangASTType m_clang_type;
+
+private:
+ void
+ ConstructObject (uint32_t reg_num);
+
+ friend class ValueObjectRegisterSet;
+ ValueObjectRegister (ValueObject &parent, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num);
+ ValueObjectRegister (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num);
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectRegister);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectRegister_h_
diff --git a/include/lldb/Core/ValueObjectSyntheticFilter.h b/include/lldb/Core/ValueObjectSyntheticFilter.h
new file mode 100644
index 000000000000..f1d8c885c255
--- /dev/null
+++ b/include/lldb/Core/ValueObjectSyntheticFilter.h
@@ -0,0 +1,182 @@
+//===-- ValueObjectSyntheticFilter.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_ValueObjectSyntheticFilter_h_
+#define liblldb_ValueObjectSyntheticFilter_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that obtains its children from some source other than
+// real information
+// This is currently used to implement Python-based children and filters
+// but you can bind it to any source of synthetic information and have
+// it behave accordingly
+//----------------------------------------------------------------------
+class ValueObjectSynthetic : public ValueObject
+{
+public:
+ virtual
+ ~ValueObjectSynthetic();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual bool
+ MightHaveChildren();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx, bool can_create);
+
+ virtual lldb::ValueObjectSP
+ GetChildMemberWithName (const ConstString &name, bool can_create);
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual lldb::ValueObjectSP
+ GetDynamicValue (lldb::DynamicValueType valueType);
+
+ virtual bool
+ IsInScope ();
+
+ virtual bool
+ HasSyntheticValue()
+ {
+ return false;
+ }
+
+ virtual bool
+ IsSynthetic() { return true; }
+
+ virtual void
+ CalculateSyntheticValue (bool use_synthetic)
+ {
+ }
+
+ virtual bool
+ IsDynamic ()
+ {
+ if (m_parent)
+ return m_parent->IsDynamic();
+ else
+ return false;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetStaticValue ()
+ {
+ if (m_parent)
+ return m_parent->GetStaticValue();
+ else
+ return GetSP();
+ }
+
+ virtual lldb::DynamicValueType
+ GetDynamicValueType ()
+ {
+ if (m_parent)
+ return m_parent->GetDynamicValueType();
+ else
+ return lldb::eNoDynamicValues;
+ }
+
+ virtual ValueObject *
+ GetParent()
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetNonSyntheticValue ();
+
+ virtual bool
+ ResolveValue (Scalar &scalar)
+ {
+ if (m_parent)
+ return m_parent->ResolveValue(scalar);
+ return false;
+ }
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ virtual void
+ CreateSynthFilter ();
+
+ // we need to hold on to the SyntheticChildren because someone might delete the type binding while we are alive
+ lldb::SyntheticChildrenSP m_synth_sp;
+ std::unique_ptr<SyntheticChildrenFrontEnd> m_synth_filter_ap;
+
+ typedef std::map<uint32_t, ValueObject*> ByIndexMap;
+ typedef std::map<const char*, uint32_t> NameToIndexMap;
+
+ typedef ByIndexMap::iterator ByIndexIterator;
+ typedef NameToIndexMap::iterator NameToIndexIterator;
+
+ ByIndexMap m_children_byindex;
+ NameToIndexMap m_name_toindex;
+ uint32_t m_synthetic_children_count; // FIXME use the ValueObject's ChildrenManager instead of a special purpose solution
+
+ ConstString m_parent_type_name;
+
+ LazyBool m_might_have_children;
+
+private:
+ friend class ValueObject;
+ ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter);
+
+ void
+ CopyParentData ();
+
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectSynthetic);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectSyntheticFilter_h_
diff --git a/include/lldb/Core/ValueObjectVariable.h b/include/lldb/Core/ValueObjectVariable.h
new file mode 100644
index 000000000000..8a30b00f6bbd
--- /dev/null
+++ b/include/lldb/Core/ValueObjectVariable.h
@@ -0,0 +1,90 @@
+//===-- ValueObjectVariable.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_ValueObjectVariable_h_
+#define liblldb_ValueObjectVariable_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that contains a root variable that may or may not
+// have children.
+//----------------------------------------------------------------------
+class ValueObjectVariable : public ValueObject
+{
+public:
+ static lldb::ValueObjectSP
+ Create (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp);
+
+ virtual
+ ~ValueObjectVariable();
+
+ virtual uint64_t
+ GetByteSize();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual ConstString
+ GetQualifiedTypeName();
+
+ virtual size_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+ virtual lldb::ModuleSP
+ GetModule();
+
+ virtual SymbolContextScope *
+ GetSymbolContextScope();
+
+ virtual bool
+ GetDeclaration (Declaration &decl);
+
+ virtual const char *
+ GetLocationAsCString ();
+
+ virtual bool
+ SetValueFromCString (const char *value_str, Error& error);
+
+ virtual bool
+ SetData (DataExtractor &data, Error &error);
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ virtual ClangASTType
+ GetClangTypeImpl ();
+
+ lldb::VariableSP m_variable_sp; ///< The variable that this value object is based upon
+ Value m_resolved_value; ///< The value that DWARFExpression resolves this variable to before we patch it up
+
+private:
+ ValueObjectVariable (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp);
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectVariable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectVariable_h_
diff --git a/include/lldb/Core/dwarf.h b/include/lldb/Core/dwarf.h
new file mode 100644
index 000000000000..bf77125d86a8
--- /dev/null
+++ b/include/lldb/Core/dwarf.h
@@ -0,0 +1,64 @@
+//===-- dwarf.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DebugBase_dwarf_h_
+#define DebugBase_dwarf_h_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+// Get the DWARF constant defintions from llvm
+#include "llvm/Support/Dwarf.h"
+// and stuff them in our default namespace
+using namespace llvm::dwarf;
+
+typedef uint32_t dw_uleb128_t;
+typedef int32_t dw_sleb128_t;
+typedef uint16_t dw_attr_t;
+typedef uint8_t dw_form_t;
+typedef uint16_t dw_tag_t;
+typedef uint64_t dw_addr_t; // Dwarf address define that must be big enough for any addresses in the compile units that get parsed
+
+#ifdef DWARFUTILS_DWARF64
+#define DWARF_REF_ADDR_SIZE 8
+typedef uint64_t dw_offset_t; // Dwarf Debug Information Entry offset for any offset into the file
+#else
+#define DWARF_REF_ADDR_SIZE 4
+typedef uint32_t dw_offset_t; // Dwarf Debug Information Entry offset for any offset into the file
+#endif
+
+/* Constants */
+#define DW_INVALID_OFFSET (~(dw_offset_t)0)
+#define DW_INVALID_INDEX 0xFFFFFFFFul
+
+// #define DW_ADDR_none 0x0
+
+#define DW_EH_PE_MASK_ENCODING 0x0F
+
+//// The following are used only internally within lldb - don't
+//// document them in the llvm Dwarf.h header file, we won't see
+//// them in executable files anywhere.
+//// These constants fit between DW_OP_lo_user (0xe0) and DW_OP_hi_user (0xff).
+//
+//#define DW_OP_APPLE_array_ref 0xEE // first pops index, then pops array; pushes array[index]
+//#define DW_OP_APPLE_extern 0xEF // ULEB128 index of external object (i.e., an entity from the program that was used in the expression)
+#define DW_OP_APPLE_uninit 0xF0 // This is actually generated by some apple compilers in locations lists
+//#define DW_OP_APPLE_assign 0xF1 // pops value off and assigns it to second item on stack (2nd item must have assignable context)
+//#define DW_OP_APPLE_address_of 0xF2 // gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
+//#define DW_OP_APPLE_value_of 0xF3 // pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
+//#define DW_OP_APPLE_deref_type 0xF4 // gets the address of the top stack item (top item must be a variable, or a clang type)
+//#define DW_OP_APPLE_expr_local 0xF5 // ULEB128 expression local index
+//#define DW_OP_APPLE_constf 0xF6 // 1 byte float size, followed by constant float data
+//#define DW_OP_APPLE_scalar_cast 0xF7 // Cast top of stack to 2nd in stack's type leaving all items in place
+//#define DW_OP_APPLE_clang_cast 0xF8 // pointer size clang::Type * off the stack and cast top stack item to this type
+//#define DW_OP_APPLE_clear 0xFE // clears the entire expression stack, ok if the stack is empty
+//#define DW_OP_APPLE_error 0xFF // Stops expression evaluation and returns an error (no args)
+
+
+#endif // DebugBase_dwarf_h_
diff --git a/include/lldb/DataFormatters/CXXFormatterFunctions.h b/include/lldb/DataFormatters/CXXFormatterFunctions.h
new file mode 100644
index 000000000000..2f56c56810ab
--- /dev/null
+++ b/include/lldb/DataFormatters/CXXFormatterFunctions.h
@@ -0,0 +1,874 @@
+//===-- CXXFormatterFunctions.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_CXXFormatterFunctions_h_
+#define liblldb_CXXFormatterFunctions_h_
+
+#include <stdint.h>
+#include <time.h>
+
+#include "lldb/lldb-forward.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/Target/Target.h"
+
+#include "clang/AST/ASTContext.h"
+
+namespace lldb_private {
+ namespace formatters
+ {
+ bool
+ ExtractValueFromObjCExpression (ValueObject &valobj,
+ const char* target_type,
+ const char* selector,
+ uint64_t &value);
+
+ bool
+ ExtractSummaryFromObjCExpression (ValueObject &valobj,
+ const char* target_type,
+ const char* selector,
+ Stream &stream);
+
+ lldb::ValueObjectSP
+ CallSelectorOnObject (ValueObject &valobj,
+ const char* return_type,
+ const char* selector,
+ uint64_t index);
+
+ lldb::ValueObjectSP
+ CallSelectorOnObject (ValueObject &valobj,
+ const char* return_type,
+ const char* selector,
+ const char* key);
+
+ size_t
+ ExtractIndexFromString (const char* item_name);
+
+ time_t
+ GetOSXEpoch ();
+
+ bool
+ Char16StringSummaryProvider (ValueObject& valobj, Stream& stream); // char16_t* and unichar*
+
+ bool
+ Char32StringSummaryProvider (ValueObject& valobj, Stream& stream); // char32_t*
+
+ bool
+ WCharStringSummaryProvider (ValueObject& valobj, Stream& stream); // wchar_t*
+
+ bool
+ Char16SummaryProvider (ValueObject& valobj, Stream& stream); // char16_t and unichar
+
+ bool
+ Char32SummaryProvider (ValueObject& valobj, Stream& stream); // char32_t
+
+ bool
+ WCharSummaryProvider (ValueObject& valobj, Stream& stream); // wchar_t
+
+ bool
+ LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::string
+
+ bool
+ LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::wstring
+
+ bool
+ ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ SyntheticChildrenFrontEnd* ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ template<bool name_entries>
+ bool
+ NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSArraySummaryProvider (ValueObject& valobj, Stream& stream);
+
+ template<bool cf_style>
+ bool
+ NSSetSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ template<bool needs_at>
+ bool
+ NSDataSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSNumberSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ CFBagSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSDateSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSBundleSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSStringSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ NSURLSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ template <bool is_sel_ptr>
+ bool
+ ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ bool
+ RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ extern template bool
+ NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
+
+ extern template bool
+ NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
+
+ extern template bool
+ NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
+
+ extern template bool
+ NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
+
+ extern template bool
+ ObjCSELSummaryProvider<true> (ValueObject&, Stream&);
+
+ extern template bool
+ ObjCSELSummaryProvider<false> (ValueObject&, Stream&);
+
+ class NSArrayMSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ struct DataDescriptor_32
+ {
+ uint32_t _used;
+ uint32_t _priv1 : 2 ;
+ uint32_t _size : 30;
+ uint32_t _priv2 : 2;
+ uint32_t offset : 30;
+ uint32_t _priv3;
+ uint32_t _data;
+ };
+ struct DataDescriptor_64
+ {
+ uint64_t _used;
+ uint64_t _priv1 : 2 ;
+ uint64_t _size : 62;
+ uint64_t _priv2 : 2;
+ uint64_t offset : 62;
+ uint32_t _priv3;
+ uint64_t _data;
+ };
+ public:
+ NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayMSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ DataDescriptor_32 *m_data_32;
+ DataDescriptor_64 *m_data_64;
+ ClangASTType m_id_type;
+ std::vector<lldb::ValueObjectSP> m_children;
+ };
+
+ class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayISyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint8_t m_ptr_size;
+ uint64_t m_items;
+ lldb::addr_t m_data_ptr;
+ ClangASTType m_id_type;
+ std::vector<lldb::ValueObjectSP> m_children;
+ };
+
+ class NSArrayCodeRunningSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~NSArrayCodeRunningSyntheticFrontEnd ();
+ };
+
+ SyntheticChildrenFrontEnd* NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class NSDictionaryISyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ 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 ();
+ };
+
+ SyntheticChildrenFrontEnd* NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ 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 ();
+ };
+
+ SyntheticChildrenFrontEnd* NSSetSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxVectorBoolSyntheticFrontEnd (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
+ ~LibcxxVectorBoolSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint64_t m_count;
+ lldb::addr_t m_base_data_address;
+ EvaluateExpressionOptions m_options;
+ };
+
+ SyntheticChildrenFrontEnd* LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ bool
+ LibcxxContainerSummaryProvider (ValueObject& valobj, Stream& stream);
+
+ class LibstdcppVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
+
+ virtual size_t
+ CalculateNumChildren ();
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update();
+
+ virtual bool
+ MightHaveChildren ();
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name);
+
+ virtual
+ ~LibstdcppVectorBoolSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ uint64_t m_count;
+ lldb::addr_t m_base_data_address;
+ EvaluateExpressionOptions m_options;
+ };
+
+ SyntheticChildrenFrontEnd* LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibstdcppMapIteratorSyntheticFrontEnd (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
+ ~LibstdcppMapIteratorSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ lldb::addr_t m_pair_address;
+ ClangASTType m_pair_type;
+ EvaluateExpressionOptions m_options;
+ lldb::ValueObjectSP m_pair_sp;
+ };
+
+ SyntheticChildrenFrontEnd* LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class LibCxxMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibCxxMapIteratorSyntheticFrontEnd (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
+ ~LibCxxMapIteratorSyntheticFrontEnd ();
+ private:
+ ValueObject *m_pair_ptr;
+ };
+
+ SyntheticChildrenFrontEnd* LibCxxMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class VectorIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
+ ConstString item_name);
+
+ 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
+ ~VectorIteratorSyntheticFrontEnd ();
+ private:
+ ExecutionContextRef m_exe_ctx_ref;
+ ConstString m_item_name;
+ lldb::ValueObjectSP m_item_sp;
+ };
+
+ SyntheticChildrenFrontEnd* LibCxxVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ SyntheticChildrenFrontEnd* LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ class LibcxxSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd
+ {
+ public:
+ LibcxxSharedPtrSyntheticFrontEnd (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
+ ~LibcxxSharedPtrSyntheticFrontEnd ();
+ private:
+ ValueObject* m_cntrl;
+ lldb::ValueObjectSP m_count_sp;
+ lldb::ValueObjectSP m_weak_count_sp;
+ uint8_t m_ptr_size;
+ lldb::ByteOrder m_byte_order;
+ };
+
+ SyntheticChildrenFrontEnd* LibcxxSharedPtrSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ 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;
+ };
+
+ SyntheticChildrenFrontEnd* LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ 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 m_list_capping_size;
+ static const bool g_use_loop_detect = true;
+ 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;
+ };
+
+ SyntheticChildrenFrontEnd* LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ 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;
+ };
+
+ SyntheticChildrenFrontEnd* LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
+
+ } // namespace formatters
+} // namespace lldb_private
+
+#endif // liblldb_CXXFormatterFunctions_h_
diff --git a/include/lldb/DataFormatters/DataVisualization.h b/include/lldb/DataFormatters/DataVisualization.h
new file mode 100644
index 000000000000..499e0fe14d93
--- /dev/null
+++ b/include/lldb/DataFormatters/DataVisualization.h
@@ -0,0 +1,174 @@
+//===-- DataVisualization.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_DataVisualization_h_
+#define lldb_DataVisualization_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/DataFormatters/FormatManager.h"
+
+namespace lldb_private {
+
+// this class is the high-level front-end of LLDB Data Visualization
+// code in FormatManager.h/cpp is the low-level implementation of this feature
+// clients should refer to this class as the entry-point into the data formatters
+// unless they have a good reason to bypass this and go to the backend
+class DataVisualization
+{
+public:
+
+ // use this call to force the FM to consider itself updated even when there is no apparent reason for that
+ static void
+ ForceUpdate();
+
+ static uint32_t
+ GetCurrentRevision ();
+
+ class ValueFormats
+ {
+ public:
+ static lldb::TypeFormatImplSP
+ GetFormat (ValueObject& valobj, lldb::DynamicValueType use_dynamic);
+
+ static lldb::TypeFormatImplSP
+ GetFormat (const ConstString &type);
+
+ static void
+ Add (const ConstString &type, const lldb::TypeFormatImplSP &entry);
+
+ static bool
+ Delete (const ConstString &type);
+
+ static void
+ Clear ();
+
+ static void
+ LoopThrough (TypeFormatImpl::ValueCallback callback, void* callback_baton);
+
+ static size_t
+ GetCount ();
+
+ static lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierForFormatAtIndex (size_t);
+
+ static lldb::TypeFormatImplSP
+ GetFormatAtIndex (size_t);
+ };
+
+ static lldb::TypeSummaryImplSP
+ GetSummaryFormat(ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+
+ static lldb::TypeSummaryImplSP
+ GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+#ifndef LLDB_DISABLE_PYTHON
+ static lldb::SyntheticChildrenSP
+ GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp);
+#endif
+
+ static lldb::TypeFilterImplSP
+ GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+#ifndef LLDB_DISABLE_PYTHON
+ static lldb::ScriptedSyntheticChildrenSP
+ GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp);
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ static lldb::SyntheticChildrenSP
+ GetSyntheticChildren(ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+#endif
+
+ static bool
+ AnyMatches(ConstString type_name,
+ TypeCategoryImpl::FormatCategoryItems items = TypeCategoryImpl::ALL_ITEM_TYPES,
+ bool only_enabled = true,
+ const char** matching_category = NULL,
+ TypeCategoryImpl::FormatCategoryItems* matching_type = NULL);
+
+ class NamedSummaryFormats
+ {
+ public:
+ static bool
+ GetSummaryFormat (const ConstString &type, lldb::TypeSummaryImplSP &entry);
+
+ static void
+ Add (const ConstString &type, const lldb::TypeSummaryImplSP &entry);
+
+ static bool
+ Delete (const ConstString &type);
+
+ static void
+ Clear ();
+
+ static void
+ LoopThrough (TypeSummaryImpl::SummaryCallback callback, void* callback_baton);
+
+ static uint32_t
+ GetCount ();
+ };
+
+ class Categories
+ {
+ public:
+
+ static bool
+ GetCategory (const ConstString &category,
+ lldb::TypeCategoryImplSP &entry,
+ bool allow_create = true);
+
+ static void
+ Add (const ConstString &category);
+
+ static bool
+ Delete (const ConstString &category);
+
+ static void
+ Clear ();
+
+ static void
+ Clear (const ConstString &category);
+
+ static void
+ Enable (const ConstString& category,
+ TypeCategoryMap::Position = TypeCategoryMap::Default);
+
+ static void
+ Disable (const ConstString& category);
+
+ static void
+ Enable (const lldb::TypeCategoryImplSP& category,
+ TypeCategoryMap::Position = TypeCategoryMap::Default);
+
+ static void
+ Disable (const lldb::TypeCategoryImplSP& category);
+
+ static void
+ LoopThrough (FormatManager::CategoryCallback callback, void* callback_baton);
+
+ static uint32_t
+ GetCount ();
+
+ static lldb::TypeCategoryImplSP
+ GetCategoryAtIndex (size_t);
+ };
+};
+
+
+} // namespace lldb_private
+
+#endif // lldb_DataVisualization_h_
diff --git a/include/lldb/DataFormatters/FormatCache.h b/include/lldb/DataFormatters/FormatCache.h
new file mode 100644
index 000000000000..941b96c1facc
--- /dev/null
+++ b/include/lldb/DataFormatters/FormatCache.h
@@ -0,0 +1,101 @@
+//===-- FormatCache.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_FormatCache_h_
+#define lldb_FormatCache_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+
+namespace lldb_private {
+class FormatCache
+{
+private:
+ struct Entry
+ {
+ private:
+ bool m_summary_cached : 1;
+ bool m_synthetic_cached : 1;
+
+ lldb::TypeSummaryImplSP m_summary_sp;
+ lldb::SyntheticChildrenSP m_synthetic_sp;
+ public:
+ Entry ();
+ Entry (lldb::TypeSummaryImplSP);
+ Entry (lldb::SyntheticChildrenSP);
+ Entry (lldb::TypeSummaryImplSP,lldb::SyntheticChildrenSP);
+
+ bool
+ IsSummaryCached ();
+
+ bool
+ IsSyntheticCached ();
+
+ lldb::TypeSummaryImplSP
+ GetSummary ();
+
+ lldb::SyntheticChildrenSP
+ GetSynthetic ();
+
+ void
+ SetSummary (lldb::TypeSummaryImplSP);
+
+ void
+ SetSynthetic (lldb::SyntheticChildrenSP);
+ };
+ typedef std::map<ConstString,Entry> CacheMap;
+ CacheMap m_map;
+ Mutex m_mutex;
+
+ uint64_t m_cache_hits;
+ uint64_t m_cache_misses;
+
+ Entry&
+ GetEntry (const ConstString& type);
+
+public:
+ FormatCache ();
+
+ bool
+ GetSummary (const ConstString& type,lldb::TypeSummaryImplSP& summary_sp);
+
+ bool
+ GetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& synthetic_sp);
+
+ void
+ SetSummary (const ConstString& type,lldb::TypeSummaryImplSP& summary_sp);
+
+ void
+ SetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& synthetic_sp);
+
+ void
+ Clear ();
+
+ uint64_t
+ GetCacheHits ()
+ {
+ return m_cache_hits;
+ }
+
+ uint64_t
+ GetCacheMisses ()
+ {
+ return m_cache_misses;
+ }
+};
+} // namespace lldb_private
+
+#endif // lldb_FormatCache_h_
diff --git a/include/lldb/DataFormatters/FormatClasses.h b/include/lldb/DataFormatters/FormatClasses.h
new file mode 100644
index 000000000000..48a8eda4ad43
--- /dev/null
+++ b/include/lldb/DataFormatters/FormatClasses.h
@@ -0,0 +1,128 @@
+//===-- FormatClasses.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_FormatClasses_h_
+#define lldb_FormatClasses_h_
+
+// C Includes
+#include <stdint.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/DataFormatters/TypeFormat.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+
+namespace lldb_private {
+
+class TypeNameSpecifierImpl
+{
+public:
+ TypeNameSpecifierImpl() :
+ m_is_regex(false),
+ m_type()
+ {
+ }
+
+ TypeNameSpecifierImpl (const char* name, bool is_regex) :
+ m_is_regex(is_regex),
+ m_type()
+ {
+ if (name)
+ m_type.m_type_name.assign(name);
+ }
+
+ // if constructing with a given type, is_regex cannot be true since we are
+ // giving an exact type to match
+ TypeNameSpecifierImpl (lldb::TypeSP type) :
+ m_is_regex(false),
+ m_type()
+ {
+ if (type)
+ {
+ m_type.m_type_name.assign(type->GetName().GetCString());
+ m_type.m_typeimpl_sp = lldb::TypeImplSP(new TypeImpl(type));
+ }
+ }
+
+ TypeNameSpecifierImpl (ClangASTType type) :
+ m_is_regex(false),
+ m_type()
+ {
+ if (type.IsValid())
+ {
+ m_type.m_type_name.assign(type.GetConstTypeName().GetCString());
+ m_type.m_typeimpl_sp = lldb::TypeImplSP(new TypeImpl(type));
+ }
+ }
+
+ const char*
+ GetName()
+ {
+ if (m_type.m_type_name.size())
+ return m_type.m_type_name.c_str();
+ return NULL;
+ }
+
+ lldb::TypeSP
+ GetTypeSP ()
+ {
+ if (m_type.m_typeimpl_sp && m_type.m_typeimpl_sp->IsValid())
+ return m_type.m_typeimpl_sp->GetTypeSP();
+ return lldb::TypeSP();
+ }
+
+ ClangASTType
+ GetClangASTType ()
+ {
+ if (m_type.m_typeimpl_sp && m_type.m_typeimpl_sp->IsValid())
+ return m_type.m_typeimpl_sp->GetClangASTType();
+ return ClangASTType();
+ }
+
+ bool
+ IsRegex()
+ {
+ return m_is_regex;
+ }
+
+private:
+ bool m_is_regex;
+ // this works better than TypeAndOrName because the latter only wraps a TypeSP
+ // whereas TypeImplSP can also be backed by a ClangASTType which is more commonly
+ // used in LLDB. moreover, TypeImplSP is also what is currently backing SBType
+ struct TypeOrName
+ {
+ std::string m_type_name;
+ lldb::TypeImplSP m_typeimpl_sp;
+ };
+ TypeOrName m_type;
+
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(TypeNameSpecifierImpl);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_FormatClasses_h_
diff --git a/include/lldb/DataFormatters/FormatManager.h b/include/lldb/DataFormatters/FormatManager.h
new file mode 100644
index 000000000000..162e25143f27
--- /dev/null
+++ b/include/lldb/DataFormatters/FormatManager.h
@@ -0,0 +1,251 @@
+//===-- FormatManager.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_FormatManager_h_
+#define lldb_FormatManager_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/DataFormatters/FormatCache.h"
+#include "lldb/DataFormatters/FormatNavigator.h"
+#include "lldb/DataFormatters/TypeCategory.h"
+#include "lldb/DataFormatters/TypeCategoryMap.h"
+
+namespace lldb_private {
+
+// this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
+// class DataVisualization is the high-level front-end of this feature
+// clients should refer to that class as the entry-point into the data formatters
+// unless they have a good reason to bypass it and prefer to use this file's objects directly
+
+class FormatManager : public IFormatChangeListener
+{
+ typedef FormatNavigator<ConstString, TypeFormatImpl> ValueNavigator;
+ typedef ValueNavigator::MapType ValueMap;
+ typedef FormatMap<ConstString, TypeSummaryImpl> NamedSummariesMap;
+ typedef TypeCategoryMap::MapType::iterator CategoryMapIterator;
+public:
+
+ typedef TypeCategoryMap::CallbackType CategoryCallback;
+
+ FormatManager ();
+
+ ValueNavigator&
+ GetValueNavigator ()
+ {
+ return m_value_nav;
+ }
+
+ NamedSummariesMap&
+ GetNamedSummaryNavigator ()
+ {
+ return m_named_summaries_map;
+ }
+
+ void
+ EnableCategory (const ConstString& category_name,
+ TypeCategoryMap::Position pos = TypeCategoryMap::Default)
+ {
+ m_categories_map.Enable(category_name,
+ pos);
+ }
+
+ void
+ DisableCategory (const ConstString& category_name)
+ {
+ m_categories_map.Disable(category_name);
+ }
+
+ void
+ EnableCategory (const lldb::TypeCategoryImplSP& category,
+ TypeCategoryMap::Position pos = TypeCategoryMap::Default)
+ {
+ m_categories_map.Enable(category,
+ pos);
+ }
+
+ void
+ DisableCategory (const lldb::TypeCategoryImplSP& category)
+ {
+ m_categories_map.Disable(category);
+ }
+
+ bool
+ DeleteCategory (const ConstString& category_name)
+ {
+ return m_categories_map.Delete(category_name);
+ }
+
+ void
+ ClearCategories ()
+ {
+ return m_categories_map.Clear();
+ }
+
+ uint32_t
+ GetCategoriesCount ()
+ {
+ return m_categories_map.GetCount();
+ }
+
+ lldb::TypeCategoryImplSP
+ GetCategoryAtIndex (size_t index)
+ {
+ return m_categories_map.GetAtIndex(index);
+ }
+
+ void
+ LoopThroughCategories (CategoryCallback callback, void* param)
+ {
+ m_categories_map.LoopThrough(callback, param);
+ }
+
+ lldb::TypeCategoryImplSP
+ GetCategory (const char* category_name = NULL,
+ bool can_create = true)
+ {
+ if (!category_name)
+ return GetCategory(m_default_category_name);
+ return GetCategory(ConstString(category_name));
+ }
+
+ lldb::TypeCategoryImplSP
+ GetCategory (const ConstString& category_name,
+ bool can_create = true);
+
+ lldb::TypeSummaryImplSP
+ GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+ lldb::TypeFilterImplSP
+ GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::ScriptedSyntheticChildrenSP
+ GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp);
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::SyntheticChildrenSP
+ GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp);
+#endif
+
+ lldb::TypeSummaryImplSP
+ GetSummaryFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::SyntheticChildrenSP
+ GetSyntheticChildren (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+#endif
+
+ bool
+ AnyMatches (ConstString type_name,
+ TypeCategoryImpl::FormatCategoryItems items = TypeCategoryImpl::ALL_ITEM_TYPES,
+ bool only_enabled = true,
+ const char** matching_category = NULL,
+ TypeCategoryImpl::FormatCategoryItems* matching_type = NULL)
+ {
+ return m_categories_map.AnyMatches(type_name,
+ items,
+ only_enabled,
+ matching_category,
+ matching_type);
+ }
+
+ static bool
+ GetFormatFromCString (const char *format_cstr,
+ bool partial_match_ok,
+ lldb::Format &format);
+
+ static char
+ GetFormatAsFormatChar (lldb::Format format);
+
+ static const char *
+ GetFormatAsCString (lldb::Format format);
+
+ // if the user tries to add formatters for, say, "struct Foo"
+ // those will not match any type because of the way we strip qualifiers from typenames
+ // this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
+ // and strips the unnecessary qualifier
+ static ConstString
+ GetValidTypeName (const ConstString& type);
+
+ // when DataExtractor dumps a vectorOfT, it uses a predefined format for each item
+ // this method returns it, or eFormatInvalid if vector_format is not a vectorOf
+ static lldb::Format
+ GetSingleItemFormat (lldb::Format vector_format);
+
+ void
+ Changed ()
+ {
+ __sync_add_and_fetch(&m_last_revision, +1);
+ m_format_cache.Clear ();
+ }
+
+ uint32_t
+ GetCurrentRevision ()
+ {
+ return m_last_revision;
+ }
+
+ ~FormatManager ()
+ {
+ }
+
+private:
+ FormatCache m_format_cache;
+ ValueNavigator m_value_nav;
+ NamedSummariesMap m_named_summaries_map;
+ uint32_t m_last_revision;
+ TypeCategoryMap m_categories_map;
+
+ ConstString m_default_category_name;
+ ConstString m_system_category_name;
+ ConstString m_gnu_cpp_category_name;
+ ConstString m_libcxx_category_name;
+ ConstString m_objc_category_name;
+ ConstString m_corefoundation_category_name;
+ ConstString m_coregraphics_category_name;
+ ConstString m_coreservices_category_name;
+ ConstString m_vectortypes_category_name;
+ ConstString m_appkit_category_name;
+
+ TypeCategoryMap&
+ GetCategories ()
+ {
+ return m_categories_map;
+ }
+
+ // WARNING: these are temporary functions that setup formatters
+ // while a few of these actually should be globally available and setup by LLDB itself
+ // most would actually belong to the users' lldbinit file or to some other form of configurable
+ // storage
+ void
+ LoadLibStdcppFormatters ();
+
+ void
+ LoadLibcxxFormatters ();
+
+ void
+ LoadSystemFormatters ();
+
+ void
+ LoadObjCFormatters ();
+};
+
+} // namespace lldb_private
+
+#endif // lldb_FormatManager_h_
diff --git a/include/lldb/DataFormatters/FormatNavigator.h b/include/lldb/DataFormatters/FormatNavigator.h
new file mode 100644
index 000000000000..a738cfd069e7
--- /dev/null
+++ b/include/lldb/DataFormatters/FormatNavigator.h
@@ -0,0 +1,690 @@
+//===-- FormatNavigator.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_FormatNavigator_h_
+#define lldb_FormatNavigator_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/DeclObjC.h"
+
+// Project includes
+#include "lldb/lldb-public.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/DataFormatters/FormatClasses.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/TargetList.h"
+
+namespace lldb_private {
+
+// this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
+// class DataVisualization is the high-level front-end of this feature
+// clients should refer to that class as the entry-point into the data formatters
+// unless they have a good reason to bypass it and prefer to use this file's objects directly
+class IFormatChangeListener
+{
+public:
+ virtual void
+ Changed () = 0;
+
+ virtual
+ ~IFormatChangeListener () {}
+
+ virtual uint32_t
+ GetCurrentRevision () = 0;
+
+};
+
+static inline bool
+IsWhitespace (char c)
+{
+ return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
+}
+
+static inline bool
+HasPrefix (const char* str1, const char* str2)
+{
+ return ( ::strstr(str1, str2) == str1 );
+}
+
+// if the user tries to add formatters for, say, "struct Foo"
+// those will not match any type because of the way we strip qualifiers from typenames
+// this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
+// and strips the unnecessary qualifier
+static inline ConstString
+GetValidTypeName_Impl (const ConstString& type)
+{
+ int strip_len = 0;
+
+ if (type == false)
+ return type;
+
+ const char* type_cstr = type.AsCString();
+
+ if ( HasPrefix(type_cstr, "class ") )
+ strip_len = 6;
+ else if ( HasPrefix(type_cstr, "enum ") )
+ strip_len = 5;
+ else if ( HasPrefix(type_cstr, "struct ") )
+ strip_len = 7;
+ else if ( HasPrefix(type_cstr, "union ") )
+ strip_len = 6;
+
+ if (strip_len == 0)
+ return type;
+
+ type_cstr += strip_len;
+ while (IsWhitespace(*type_cstr) && ++type_cstr)
+ ;
+
+ return ConstString(type_cstr);
+}
+
+template<typename KeyType, typename ValueType>
+class FormatNavigator;
+
+template<typename KeyType, typename ValueType>
+class FormatMap
+{
+public:
+
+ typedef typename ValueType::SharedPointer ValueSP;
+ typedef std::map<KeyType, ValueSP> MapType;
+ typedef typename MapType::iterator MapIterator;
+ typedef bool(*CallbackType)(void*, KeyType, const ValueSP&);
+
+ FormatMap(IFormatChangeListener* lst) :
+ m_map(),
+ m_map_mutex(Mutex::eMutexTypeRecursive),
+ listener(lst)
+ {
+ }
+
+ void
+ Add(KeyType name,
+ const ValueSP& entry)
+ {
+ if (listener)
+ entry->GetRevision() = listener->GetCurrentRevision();
+ else
+ entry->GetRevision() = 0;
+
+ Mutex::Locker locker(m_map_mutex);
+ m_map[name] = entry;
+ if (listener)
+ listener->Changed();
+ }
+
+ bool
+ Delete (KeyType name)
+ {
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ m_map.erase(name);
+ if (listener)
+ listener->Changed();
+ return true;
+ }
+
+ void
+ Clear ()
+ {
+ Mutex::Locker locker(m_map_mutex);
+ m_map.clear();
+ if (listener)
+ listener->Changed();
+ }
+
+ bool
+ Get(KeyType name,
+ ValueSP& entry)
+ {
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ entry = iter->second;
+ return true;
+ }
+
+ void
+ LoopThrough (CallbackType callback, void* param)
+ {
+ if (callback)
+ {
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++)
+ {
+ KeyType type = pos->first;
+ if (!callback(param, type, pos->second))
+ break;
+ }
+ }
+ }
+
+ uint32_t
+ GetCount ()
+ {
+ return m_map.size();
+ }
+
+ ValueSP
+ GetValueAtIndex (size_t index)
+ {
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.begin();
+ MapIterator end = m_map.end();
+ while (index > 0)
+ {
+ iter++;
+ index--;
+ if (end == iter)
+ return ValueSP();
+ }
+ return iter->second;
+ }
+
+ KeyType
+ GetKeyAtIndex (size_t index)
+ {
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.begin();
+ MapIterator end = m_map.end();
+ while (index > 0)
+ {
+ iter++;
+ index--;
+ if (end == iter)
+ return KeyType();
+ }
+ return iter->first;
+ }
+
+protected:
+ MapType m_map;
+ Mutex m_map_mutex;
+ IFormatChangeListener* listener;
+
+ MapType&
+ map ()
+ {
+ return m_map;
+ }
+
+ Mutex&
+ mutex ()
+ {
+ return m_map_mutex;
+ }
+
+ friend class FormatNavigator<KeyType, ValueType>;
+ friend class FormatManager;
+
+};
+
+template<typename KeyType, typename ValueType>
+class FormatNavigator
+{
+protected:
+ typedef FormatMap<KeyType,ValueType> BackEndType;
+
+public:
+ typedef typename BackEndType::MapType MapType;
+ typedef typename MapType::iterator MapIterator;
+ typedef typename MapType::key_type MapKeyType;
+ typedef typename MapType::mapped_type MapValueType;
+ typedef typename BackEndType::CallbackType CallbackType;
+ typedef typename std::shared_ptr<FormatNavigator<KeyType, ValueType> > SharedPointer;
+
+ friend class TypeCategoryImpl;
+
+ FormatNavigator(std::string name,
+ IFormatChangeListener* lst) :
+ m_format_map(lst),
+ m_name(name),
+ m_id_cs(ConstString("id"))
+ {
+ }
+
+ void
+ Add (const MapKeyType &type, const MapValueType& entry)
+ {
+ Add_Impl(type, entry, (KeyType*)NULL);
+ }
+
+ bool
+ Delete (ConstString type)
+ {
+ return Delete_Impl(type, (KeyType*)NULL);
+ }
+
+ bool
+ Get(ValueObject& valobj,
+ MapValueType& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t* why = NULL)
+ {
+ uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
+ ClangASTType ast_type(valobj.GetClangType());
+ bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
+ if (ret)
+ entry = MapValueType(entry);
+ else
+ entry = MapValueType();
+ if (why)
+ *why = value;
+ return ret;
+ }
+
+ bool
+ Get (ConstString type, MapValueType& entry)
+ {
+ return Get_Impl(type, entry, (KeyType*)NULL);
+ }
+
+ bool
+ GetExact (ConstString type, MapValueType& entry)
+ {
+ return GetExact_Impl(type, entry, (KeyType*)NULL);
+ }
+
+ MapValueType
+ GetAtIndex (size_t index)
+ {
+ return m_format_map.GetValueAtIndex(index);
+ }
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierAtIndex (size_t index)
+ {
+ return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
+ }
+
+ void
+ Clear ()
+ {
+ m_format_map.Clear();
+ }
+
+ void
+ LoopThrough (CallbackType callback, void* param)
+ {
+ m_format_map.LoopThrough(callback,param);
+ }
+
+ uint32_t
+ GetCount ()
+ {
+ return m_format_map.GetCount();
+ }
+
+protected:
+
+ BackEndType m_format_map;
+
+ std::string m_name;
+
+ DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
+
+ ConstString m_id_cs;
+
+ void
+ Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
+ {
+ m_format_map.Add(type,entry);
+ }
+
+ void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy)
+ {
+ m_format_map.Add(GetValidTypeName_Impl(type), entry);
+ }
+
+ bool
+ Delete_Impl (ConstString type, ConstString *dummy)
+ {
+ return m_format_map.Delete(type);
+ }
+
+ bool
+ Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy)
+ {
+ Mutex& x_mutex = m_format_map.mutex();
+ lldb_private::Mutex::Locker locker(x_mutex);
+ MapIterator pos, end = m_format_map.map().end();
+ for (pos = m_format_map.map().begin(); pos != end; pos++)
+ {
+ lldb::RegularExpressionSP regex = pos->first;
+ if ( ::strcmp(type.AsCString(),regex->GetText()) == 0)
+ {
+ m_format_map.map().erase(pos);
+ if (m_format_map.listener)
+ m_format_map.listener->Changed();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
+ {
+ return m_format_map.Get(type, entry);
+ }
+
+ bool
+ GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
+ {
+ return Get_Impl(type,entry, (KeyType*)0);
+ }
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy)
+ {
+ ConstString key = m_format_map.GetKeyAtIndex(index);
+ if (key)
+ return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(),
+ false));
+ else
+ return lldb::TypeNameSpecifierImplSP();
+ }
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy)
+ {
+ lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
+ if (regex.get() == NULL)
+ return lldb::TypeNameSpecifierImplSP();
+ return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(),
+ true));
+ }
+
+ bool
+ Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
+ {
+ const char* key_cstr = key.AsCString();
+ if (!key_cstr)
+ return false;
+ Mutex& x_mutex = m_format_map.mutex();
+ lldb_private::Mutex::Locker locker(x_mutex);
+ MapIterator pos, end = m_format_map.map().end();
+ for (pos = m_format_map.map().begin(); pos != end; pos++)
+ {
+ lldb::RegularExpressionSP regex = pos->first;
+ if (regex->Execute(key_cstr))
+ {
+ value = pos->second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
+ {
+ Mutex& x_mutex = m_format_map.mutex();
+ lldb_private::Mutex::Locker locker(x_mutex);
+ MapIterator pos, end = m_format_map.map().end();
+ for (pos = m_format_map.map().begin(); pos != end; pos++)
+ {
+ lldb::RegularExpressionSP regex = pos->first;
+ if (strcmp(regex->GetText(),key.AsCString()) == 0)
+ {
+ value = pos->second;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ Get_BitfieldMatch (ValueObject& valobj,
+ ConstString typeName,
+ MapValueType& entry,
+ uint32_t& reason)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ // for bitfields, append size to the typename so one can custom format them
+ StreamString sstring;
+ sstring.Printf("%s:%d",typeName.AsCString(),valobj.GetBitfieldBitSize());
+ ConstString bitfieldname = ConstString(sstring.GetData());
+ if (log)
+ log->Printf("[Get_BitfieldMatch] appended bitfield info, final result is %s", bitfieldname.GetCString());
+ if (Get(bitfieldname, entry))
+ {
+ if (log)
+ log->Printf("[Get_BitfieldMatch] bitfield direct match found, returning");
+ return true;
+ }
+ else
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField;
+ if (log)
+ log->Printf("[Get_BitfieldMatch] no bitfield direct match");
+ return false;
+ }
+ }
+
+ bool Get_ObjC (ValueObject& valobj,
+ MapValueType& entry)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ lldb::ProcessSP process_sp = valobj.GetProcessSP();
+ ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime();
+ if (runtime == NULL)
+ {
+ if (log)
+ log->Printf("[Get_ObjC] no valid ObjC runtime, skipping dynamic");
+ return false;
+ }
+ ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj));
+ if (!objc_class_sp)
+ {
+ if (log)
+ log->Printf("[Get_ObjC] invalid ISA, skipping dynamic");
+ return false;
+ }
+ ConstString name (objc_class_sp->GetClassName());
+ if (log)
+ log->Printf("[Get_ObjC] dynamic type inferred is %s - looking for direct dynamic match", name.GetCString());
+ if (Get(name, entry))
+ {
+ if (log)
+ log->Printf("[Get_ObjC] direct dynamic match found, returning");
+ return true;
+ }
+ if (log)
+ log->Printf("[Get_ObjC] no dynamic match");
+ return false;
+ }
+
+ bool
+ Get_Impl (ValueObject& valobj,
+ ClangASTType clang_type,
+ MapValueType& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t& reason)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ if (!clang_type.IsValid())
+ {
+ if (log)
+ log->Printf("[Get_Impl] type is invalid, returning");
+ return false;
+ }
+
+ clang_type = clang_type.RemoveFastQualifiers();
+
+ ConstString typeName(clang_type.GetConstTypeName());
+
+ if (valobj.GetBitfieldBitSize() > 0)
+ {
+ if (Get_BitfieldMatch(valobj, typeName, entry, reason))
+ return true;
+ }
+
+ if (log)
+ log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s",
+ m_name.c_str(),
+ valobj.GetName().AsCString(),
+ typeName.AsCString());
+
+ if (Get(typeName, entry))
+ {
+ if (log)
+ log->Printf("[Get] direct match found, returning");
+ return true;
+ }
+ if (log)
+ log->Printf("[Get_Impl] no direct match");
+
+ // strip pointers and references and see if that helps
+ if (clang_type.IsReferenceType())
+ {
+ if (log)
+ log->Printf("[Get_Impl] stripping reference");
+ if (Get_Impl(valobj, clang_type.GetNonReferenceType(), entry, use_dynamic, reason) && !entry->SkipsReferences())
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
+ return true;
+ }
+ }
+ else if (clang_type.IsPointerType())
+ {
+ if (log)
+ log->Printf("[Get_Impl] stripping pointer");
+ if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
+ return true;
+ }
+ }
+
+ bool canBeObjCDynamic = valobj.GetClangType().IsPossibleDynamicType (NULL,
+ false, // no C++
+ true); // yes ObjC
+
+ if (canBeObjCDynamic)
+ {
+ if (use_dynamic != lldb::eNoDynamicValues)
+ {
+ if (log)
+ log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type");
+ if (Get_ObjC(valobj,entry))
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery;
+ return true;
+ }
+ }
+ if (log)
+ log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer");
+ if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
+ return true;
+ }
+ }
+
+ // try to strip typedef chains
+ if (clang_type.IsTypedefType())
+ {
+ if (log)
+ log->Printf("[Get_Impl] stripping typedef");
+ if ((Get_Impl(valobj, clang_type.GetTypedefedType(), entry, use_dynamic, reason)) && entry->Cascades())
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs;
+ return true;
+ }
+ }
+
+ // out of luck here
+ return false;
+ }
+
+ // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size)
+ // but the type can change (e.g. stripping pointers, ...)
+ bool Get (ValueObject& valobj,
+ ClangASTType clang_type,
+ MapValueType& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t& reason)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ if (Get_Impl (valobj, clang_type, entry, use_dynamic, reason))
+ return true;
+
+ // try going to the unqualified type
+ do {
+ if (log)
+ log->Printf("[Get] trying the unqualified type");
+ if (!clang_type.IsValid())
+ break;
+
+ ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType();
+ if (!unqual_clang_ast_type.IsValid())
+ {
+ if (log)
+ log->Printf("[Get] could not get the unqual_clang_ast_type");
+ break;
+ }
+ if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType())
+ {
+ if (log)
+ log->Printf("[Get] unqualified type is there and is not the same, let's try");
+ if (Get_Impl (valobj, unqual_clang_ast_type,entry, use_dynamic, reason))
+ return true;
+ }
+ else if (log)
+ log->Printf("[Get] unqualified type same as original type");
+ } while(false);
+
+ // if all else fails, go to static type
+ if (valobj.IsDynamic())
+ {
+ if (log)
+ log->Printf("[Get] going to static value");
+ lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
+ if (static_value_sp)
+ {
+ if (log)
+ log->Printf("[Get] has a static value - actually use it");
+ if (Get(*static_value_sp.get(), static_value_sp->GetClangType(), entry, use_dynamic, reason))
+ {
+ reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // lldb_FormatNavigator_h_
diff --git a/include/lldb/DataFormatters/TypeCategory.h b/include/lldb/DataFormatters/TypeCategory.h
new file mode 100644
index 000000000000..b76d84f4772f
--- /dev/null
+++ b/include/lldb/DataFormatters/TypeCategory.h
@@ -0,0 +1,230 @@
+//===-- TypeCategory.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_TypeCategory_h_
+#define lldb_TypeCategory_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/DataFormatters/FormatNavigator.h"
+
+namespace lldb_private {
+ class TypeCategoryImpl
+ {
+ private:
+
+ typedef FormatNavigator<ConstString, TypeSummaryImpl> SummaryNavigator;
+ typedef FormatNavigator<lldb::RegularExpressionSP, TypeSummaryImpl> RegexSummaryNavigator;
+
+ typedef FormatNavigator<ConstString, TypeFilterImpl> FilterNavigator;
+ typedef FormatNavigator<lldb::RegularExpressionSP, TypeFilterImpl> RegexFilterNavigator;
+
+#ifndef LLDB_DISABLE_PYTHON
+ typedef FormatNavigator<ConstString, ScriptedSyntheticChildren> SynthNavigator;
+ typedef FormatNavigator<lldb::RegularExpressionSP, ScriptedSyntheticChildren> RegexSynthNavigator;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+ typedef SummaryNavigator::MapType SummaryMap;
+ typedef RegexSummaryNavigator::MapType RegexSummaryMap;
+ typedef FilterNavigator::MapType FilterMap;
+ typedef RegexFilterNavigator::MapType RegexFilterMap;
+#ifndef LLDB_DISABLE_PYTHON
+ typedef SynthNavigator::MapType SynthMap;
+ typedef RegexSynthNavigator::MapType RegexSynthMap;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+ public:
+
+ typedef uint16_t FormatCategoryItems;
+ static const uint16_t ALL_ITEM_TYPES = UINT16_MAX;
+
+ typedef SummaryNavigator::SharedPointer SummaryNavigatorSP;
+ typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP;
+ typedef FilterNavigator::SharedPointer FilterNavigatorSP;
+ typedef RegexFilterNavigator::SharedPointer RegexFilterNavigatorSP;
+#ifndef LLDB_DISABLE_PYTHON
+ typedef SynthNavigator::SharedPointer SynthNavigatorSP;
+ typedef RegexSynthNavigator::SharedPointer RegexSynthNavigatorSP;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+ TypeCategoryImpl (IFormatChangeListener* clist,
+ ConstString name);
+
+ SummaryNavigatorSP
+ GetSummaryNavigator ()
+ {
+ return SummaryNavigatorSP(m_summary_nav);
+ }
+
+ RegexSummaryNavigatorSP
+ GetRegexSummaryNavigator ()
+ {
+ return RegexSummaryNavigatorSP(m_regex_summary_nav);
+ }
+
+ FilterNavigatorSP
+ GetFilterNavigator ()
+ {
+ return FilterNavigatorSP(m_filter_nav);
+ }
+
+ RegexFilterNavigatorSP
+ GetRegexFilterNavigator ()
+ {
+ return RegexFilterNavigatorSP(m_regex_filter_nav);
+ }
+
+ SummaryNavigator::MapValueType
+ GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+ FilterNavigator::MapValueType
+ GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SynthNavigator::MapValueType
+ GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp);
+#endif
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierForSummaryAtIndex (size_t index);
+
+ SummaryNavigator::MapValueType
+ GetSummaryAtIndex (size_t index);
+
+ FilterNavigator::MapValueType
+ GetFilterAtIndex (size_t index);
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierForFilterAtIndex (size_t index);
+
+#ifndef LLDB_DISABLE_PYTHON
+ SynthNavigatorSP
+ GetSyntheticNavigator ()
+ {
+ return SynthNavigatorSP(m_synth_nav);
+ }
+
+ RegexSynthNavigatorSP
+ GetRegexSyntheticNavigator ()
+ {
+ return RegexSynthNavigatorSP(m_regex_synth_nav);
+ }
+
+ SynthNavigator::MapValueType
+ GetSyntheticAtIndex (size_t index);
+
+ lldb::TypeNameSpecifierImplSP
+ GetTypeNameSpecifierForSyntheticAtIndex (size_t index);
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+ bool
+ IsEnabled () const
+ {
+ return m_enabled;
+ }
+
+ uint32_t
+ GetEnabledPosition()
+ {
+ if (m_enabled == false)
+ return UINT32_MAX;
+ else
+ return m_enabled_position;
+ }
+
+ bool
+ Get (ValueObject& valobj,
+ lldb::TypeSummaryImplSP& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t* reason = NULL);
+
+ bool
+ Get (ValueObject& valobj,
+ lldb::SyntheticChildrenSP& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t* reason = NULL);
+
+ void
+ Clear (FormatCategoryItems items = ALL_ITEM_TYPES);
+
+ bool
+ Delete (ConstString name,
+ FormatCategoryItems items = ALL_ITEM_TYPES);
+
+ uint32_t
+ GetCount (FormatCategoryItems items = ALL_ITEM_TYPES);
+
+ const char*
+ GetName ()
+ {
+ return m_name.GetCString();
+ }
+
+ bool
+ AnyMatches (ConstString type_name,
+ FormatCategoryItems items = ALL_ITEM_TYPES,
+ bool only_enabled = true,
+ const char** matching_category = NULL,
+ FormatCategoryItems* matching_type = NULL);
+
+ typedef std::shared_ptr<TypeCategoryImpl> SharedPointer;
+
+ private:
+ SummaryNavigator::SharedPointer m_summary_nav;
+ RegexSummaryNavigator::SharedPointer m_regex_summary_nav;
+ FilterNavigator::SharedPointer m_filter_nav;
+ RegexFilterNavigator::SharedPointer m_regex_filter_nav;
+#ifndef LLDB_DISABLE_PYTHON
+ SynthNavigator::SharedPointer m_synth_nav;
+ RegexSynthNavigator::SharedPointer m_regex_synth_nav;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+ bool m_enabled;
+
+ IFormatChangeListener* m_change_listener;
+
+ Mutex m_mutex;
+
+ ConstString m_name;
+
+ uint32_t m_enabled_position;
+
+ void
+ Enable (bool value, uint32_t position);
+
+ void
+ Disable ()
+ {
+ Enable(false, UINT32_MAX);
+ }
+
+ friend class TypeCategoryMap;
+
+ friend class FormatNavigator<ConstString, TypeSummaryImpl>;
+ friend class FormatNavigator<lldb::RegularExpressionSP, TypeSummaryImpl>;
+
+ friend class FormatNavigator<ConstString, TypeFilterImpl>;
+ friend class FormatNavigator<lldb::RegularExpressionSP, TypeFilterImpl>;
+
+#ifndef LLDB_DISABLE_PYTHON
+ friend class FormatNavigator<ConstString, ScriptedSyntheticChildren>;
+ friend class FormatNavigator<lldb::RegularExpressionSP, ScriptedSyntheticChildren>;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+ };
+
+} // namespace lldb_private
+
+#endif // lldb_TypeCategory_h_
diff --git a/include/lldb/DataFormatters/TypeCategoryMap.h b/include/lldb/DataFormatters/TypeCategoryMap.h
new file mode 100644
index 000000000000..c2465ad13aa7
--- /dev/null
+++ b/include/lldb/DataFormatters/TypeCategoryMap.h
@@ -0,0 +1,148 @@
+//===-- TypeCategoryMap.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_TypeCategoryMap_h_
+#define lldb_TypeCategoryMap_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/DataFormatters/FormatNavigator.h"
+#include "lldb/DataFormatters/TypeCategory.h"
+
+namespace lldb_private {
+ class TypeCategoryMap
+ {
+ private:
+ typedef ConstString KeyType;
+ typedef TypeCategoryImpl ValueType;
+ typedef ValueType::SharedPointer ValueSP;
+ typedef std::list<lldb::TypeCategoryImplSP> ActiveCategoriesList;
+ typedef ActiveCategoriesList::iterator ActiveCategoriesIterator;
+
+ public:
+ typedef std::map<KeyType, ValueSP> MapType;
+ typedef MapType::iterator MapIterator;
+ typedef bool(*CallbackType)(void*, const ValueSP&);
+ typedef uint32_t Position;
+
+ static const Position First = 0;
+ static const Position Default = 1;
+ static const Position Last = UINT32_MAX;
+
+ TypeCategoryMap (IFormatChangeListener* lst);
+
+ void
+ Add (KeyType name,
+ const ValueSP& entry);
+
+ bool
+ Delete (KeyType name);
+
+ bool
+ Enable (KeyType category_name,
+ Position pos = Default);
+
+ bool
+ Disable (KeyType category_name);
+
+ bool
+ Enable (ValueSP category,
+ Position pos = Default);
+
+ bool
+ Disable (ValueSP category);
+
+ void
+ Clear ();
+
+ bool
+ Get (KeyType name,
+ ValueSP& entry);
+
+ bool
+ Get (uint32_t pos,
+ ValueSP& entry);
+
+ void
+ LoopThrough (CallbackType callback, void* param);
+
+ lldb::TypeCategoryImplSP
+ GetAtIndex (uint32_t);
+
+ bool
+ AnyMatches (ConstString type_name,
+ TypeCategoryImpl::FormatCategoryItems items = TypeCategoryImpl::ALL_ITEM_TYPES,
+ bool only_enabled = true,
+ const char** matching_category = NULL,
+ TypeCategoryImpl::FormatCategoryItems* matching_type = NULL);
+
+ uint32_t
+ GetCount ()
+ {
+ return m_map.size();
+ }
+
+ lldb::TypeSummaryImplSP
+ GetSummaryFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+
+#ifndef LLDB_DISABLE_PYTHON
+ lldb::SyntheticChildrenSP
+ GetSyntheticChildren (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic);
+#endif
+
+ private:
+
+ class delete_matching_categories
+ {
+ lldb::TypeCategoryImplSP ptr;
+ public:
+ delete_matching_categories(lldb::TypeCategoryImplSP p) : ptr(p)
+ {}
+
+ bool operator()(const lldb::TypeCategoryImplSP& other)
+ {
+ return ptr.get() == other.get();
+ }
+ };
+
+ Mutex m_map_mutex;
+ IFormatChangeListener* listener;
+
+ MapType m_map;
+ ActiveCategoriesList m_active_categories;
+
+ MapType& map ()
+ {
+ return m_map;
+ }
+
+ ActiveCategoriesList& active_list ()
+ {
+ return m_active_categories;
+ }
+
+ Mutex& mutex ()
+ {
+ return m_map_mutex;
+ }
+
+ friend class FormatNavigator<KeyType, ValueType>;
+ friend class FormatManager;
+ };
+} // namespace lldb_private
+
+#endif // lldb_TypeCategoryMap_h_
diff --git a/include/lldb/DataFormatters/TypeFormat.h b/include/lldb/DataFormatters/TypeFormat.h
new file mode 100644
index 000000000000..77135c448ed1
--- /dev/null
+++ b/include/lldb/DataFormatters/TypeFormat.h
@@ -0,0 +1,220 @@
+//===-- TypeFormat.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_TypeFormat_h_
+#define lldb_TypeFormat_h_
+
+// C Includes
+
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+ class TypeFormatImpl
+ {
+ public:
+ class Flags
+ {
+ public:
+
+ Flags () :
+ m_flags (lldb::eTypeOptionCascade)
+ {}
+
+ Flags (const Flags& other) :
+ m_flags (other.m_flags)
+ {}
+
+ Flags (uint32_t value) :
+ m_flags (value)
+ {}
+
+ Flags&
+ operator = (const Flags& rhs)
+ {
+ if (&rhs != this)
+ m_flags = rhs.m_flags;
+
+ return *this;
+ }
+
+ Flags&
+ operator = (const uint32_t& rhs)
+ {
+ m_flags = rhs;
+ return *this;
+ }
+
+ Flags&
+ Clear()
+ {
+ m_flags = 0;
+ return *this;
+ }
+
+ bool
+ GetCascades () const
+ {
+ return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
+ }
+
+ Flags&
+ SetCascades (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionCascade;
+ else
+ m_flags &= ~lldb::eTypeOptionCascade;
+ return *this;
+ }
+
+ bool
+ GetSkipPointers () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers;
+ }
+
+ Flags&
+ SetSkipPointers (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipPointers;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipPointers;
+ return *this;
+ }
+
+ bool
+ GetSkipReferences () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences;
+ }
+
+ Flags&
+ SetSkipReferences (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipReferences;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipReferences;
+ return *this;
+ }
+
+ uint32_t
+ GetValue ()
+ {
+ return m_flags;
+ }
+
+ void
+ SetValue (uint32_t value)
+ {
+ m_flags = value;
+ }
+
+ private:
+ uint32_t m_flags;
+ };
+
+ TypeFormatImpl (lldb::Format f = lldb::eFormatInvalid,
+ const Flags& flags = Flags());
+
+ typedef std::shared_ptr<TypeFormatImpl> SharedPointer;
+ typedef bool(*ValueCallback)(void*, ConstString, const lldb::TypeFormatImplSP&);
+
+ ~TypeFormatImpl ()
+ {
+ }
+
+ bool
+ Cascades () const
+ {
+ return m_flags.GetCascades();
+ }
+ bool
+ SkipsPointers () const
+ {
+ return m_flags.GetSkipPointers();
+ }
+ bool
+ SkipsReferences () const
+ {
+ return m_flags.GetSkipReferences();
+ }
+
+ void
+ SetCascades (bool value)
+ {
+ m_flags.SetCascades(value);
+ }
+
+ void
+ SetSkipsPointers (bool value)
+ {
+ m_flags.SetSkipPointers(value);
+ }
+
+ void
+ SetSkipsReferences (bool value)
+ {
+ m_flags.SetSkipReferences(value);
+ }
+
+ lldb::Format
+ GetFormat () const
+ {
+ return m_format;
+ }
+
+ void
+ SetFormat (lldb::Format fmt)
+ {
+ m_format = fmt;
+ }
+
+ uint32_t
+ GetOptions ()
+ {
+ return m_flags.GetValue();
+ }
+
+ void
+ SetOptions (uint32_t value)
+ {
+ m_flags.SetValue(value);
+ }
+
+ uint32_t&
+ GetRevision ()
+ {
+ return m_my_revision;
+ }
+
+ std::string
+ GetDescription();
+
+ protected:
+ Flags m_flags;
+ lldb::Format m_format;
+ uint32_t m_my_revision;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeFormatImpl);
+ };
+} // namespace lldb_private
+
+#endif // lldb_TypeFormat_h_
diff --git a/include/lldb/DataFormatters/TypeSummary.h b/include/lldb/DataFormatters/TypeSummary.h
new file mode 100644
index 000000000000..2183384b9d62
--- /dev/null
+++ b/include/lldb/DataFormatters/TypeSummary.h
@@ -0,0 +1,547 @@
+//===-- TypeSummary.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_TypeSummary_h_
+#define lldb_TypeSummary_h_
+
+// C Includes
+#include <stdint.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Symbol/Type.h"
+
+namespace lldb_private {
+
+ class TypeSummaryImpl
+ {
+ public:
+ class Flags
+ {
+ public:
+
+ Flags () :
+ m_flags (lldb::eTypeOptionCascade)
+ {}
+
+ Flags (const Flags& other) :
+ m_flags (other.m_flags)
+ {}
+
+ Flags (uint32_t value) :
+ m_flags (value)
+ {}
+
+ Flags&
+ operator = (const Flags& rhs)
+ {
+ if (&rhs != this)
+ m_flags = rhs.m_flags;
+
+ return *this;
+ }
+
+ Flags&
+ operator = (const uint32_t& rhs)
+ {
+ m_flags = rhs;
+ return *this;
+ }
+
+ Flags&
+ Clear()
+ {
+ m_flags = 0;
+ return *this;
+ }
+
+ bool
+ GetCascades () const
+ {
+ return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
+ }
+
+ Flags&
+ SetCascades (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionCascade;
+ else
+ m_flags &= ~lldb::eTypeOptionCascade;
+ return *this;
+ }
+
+ bool
+ GetSkipPointers () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers;
+ }
+
+ Flags&
+ SetSkipPointers (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipPointers;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipPointers;
+ return *this;
+ }
+
+ bool
+ GetSkipReferences () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences;
+ }
+
+ Flags&
+ SetSkipReferences (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipReferences;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipReferences;
+ return *this;
+ }
+
+ bool
+ GetDontShowChildren () const
+ {
+ return (m_flags & lldb::eTypeOptionHideChildren) == lldb::eTypeOptionHideChildren;
+ }
+
+ Flags&
+ SetDontShowChildren (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionHideChildren;
+ else
+ m_flags &= ~lldb::eTypeOptionHideChildren;
+ return *this;
+ }
+
+ bool
+ GetDontShowValue () const
+ {
+ return (m_flags & lldb::eTypeOptionHideValue) == lldb::eTypeOptionHideValue;
+ }
+
+ Flags&
+ SetDontShowValue (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionHideValue;
+ else
+ m_flags &= ~lldb::eTypeOptionHideValue;
+ return *this;
+ }
+
+ bool
+ GetShowMembersOneLiner () const
+ {
+ return (m_flags & lldb::eTypeOptionShowOneLiner) == lldb::eTypeOptionShowOneLiner;
+ }
+
+ Flags&
+ SetShowMembersOneLiner (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionShowOneLiner;
+ else
+ m_flags &= ~lldb::eTypeOptionShowOneLiner;
+ return *this;
+ }
+
+ bool
+ GetHideItemNames () const
+ {
+ return (m_flags & lldb::eTypeOptionHideNames) == lldb::eTypeOptionHideNames;
+ }
+
+ Flags&
+ SetHideItemNames (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionHideNames;
+ else
+ m_flags &= ~lldb::eTypeOptionHideNames;
+ return *this;
+ }
+
+ uint32_t
+ GetValue ()
+ {
+ return m_flags;
+ }
+
+ void
+ SetValue (uint32_t value)
+ {
+ m_flags = value;
+ }
+
+ private:
+ uint32_t m_flags;
+ };
+
+ typedef enum Type
+ {
+ eTypeUnknown,
+ eTypeString,
+ eTypeScript,
+ eTypeCallback
+ } Type;
+
+ TypeSummaryImpl (const TypeSummaryImpl::Flags& flags);
+
+ bool
+ Cascades () const
+ {
+ return m_flags.GetCascades();
+ }
+ bool
+ SkipsPointers () const
+ {
+ return m_flags.GetSkipPointers();
+ }
+ bool
+ SkipsReferences () const
+ {
+ return m_flags.GetSkipReferences();
+ }
+
+ bool
+ DoesPrintChildren () const
+ {
+ return !m_flags.GetDontShowChildren();
+ }
+
+ bool
+ DoesPrintValue () const
+ {
+ return !m_flags.GetDontShowValue();
+ }
+
+ bool
+ IsOneliner () const
+ {
+ return m_flags.GetShowMembersOneLiner();
+ }
+
+ bool
+ HideNames () const
+ {
+ return m_flags.GetHideItemNames();
+ }
+
+ void
+ SetCascades (bool value)
+ {
+ m_flags.SetCascades(value);
+ }
+
+ void
+ SetSkipsPointers (bool value)
+ {
+ m_flags.SetSkipPointers(value);
+ }
+
+ void
+ SetSkipsReferences (bool value)
+ {
+ m_flags.SetSkipReferences(value);
+ }
+
+ void
+ SetDoesPrintChildren (bool value)
+ {
+ m_flags.SetDontShowChildren(!value);
+ }
+
+ void
+ SetDoesPrintValue (bool value)
+ {
+ m_flags.SetDontShowValue(!value);
+ }
+
+ void
+ SetIsOneliner (bool value)
+ {
+ m_flags.SetShowMembersOneLiner(value);
+ }
+
+ void
+ SetHideNames (bool value)
+ {
+ m_flags.SetHideItemNames(value);
+ }
+
+ uint32_t
+ GetOptions ()
+ {
+ return m_flags.GetValue();
+ }
+
+ void
+ SetOptions (uint32_t value)
+ {
+ m_flags.SetValue(value);
+ }
+
+ virtual
+ ~TypeSummaryImpl ()
+ {
+ }
+
+ // we are using a ValueObject* instead of a ValueObjectSP because we do not need to hold on to this for
+ // extended periods of time and we trust the ValueObject to stay around for as long as it is required
+ // for us to generate its summary
+ virtual bool
+ FormatObject (ValueObject *valobj,
+ std::string& dest) = 0;
+
+ virtual std::string
+ GetDescription () = 0;
+
+ virtual bool
+ IsScripted () = 0;
+
+ virtual Type
+ GetType () = 0;
+
+ uint32_t&
+ GetRevision ()
+ {
+ return m_my_revision;
+ }
+
+ typedef std::shared_ptr<TypeSummaryImpl> SharedPointer;
+ typedef bool(*SummaryCallback)(void*, ConstString, const lldb::TypeSummaryImplSP&);
+ typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const lldb::TypeSummaryImplSP&);
+
+ protected:
+ uint32_t m_my_revision;
+ Flags m_flags;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeSummaryImpl);
+ };
+
+ // simple string-based summaries, using ${var to show data
+ struct StringSummaryFormat : public TypeSummaryImpl
+ {
+ std::string m_format;
+
+ StringSummaryFormat(const TypeSummaryImpl::Flags& flags,
+ const char* f);
+
+ const char*
+ GetSummaryString () const
+ {
+ return m_format.c_str();
+ }
+
+ void
+ SetSummaryString (const char* data)
+ {
+ if (data)
+ m_format.assign(data);
+ else
+ m_format.clear();
+ }
+
+ virtual
+ ~StringSummaryFormat()
+ {
+ }
+
+ virtual bool
+ FormatObject(ValueObject *valobj,
+ std::string& dest);
+
+ virtual std::string
+ GetDescription();
+
+ virtual bool
+ IsScripted ()
+ {
+ return false;
+ }
+
+
+ virtual Type
+ GetType ()
+ {
+ return TypeSummaryImpl::eTypeString;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StringSummaryFormat);
+ };
+
+ // summaries implemented via a C++ function
+ struct CXXFunctionSummaryFormat : public TypeSummaryImpl
+ {
+
+ // we should convert these to SBValue and SBStream if we ever cross
+ // the boundary towards the external world
+ typedef bool (*Callback)(ValueObject& valobj, Stream& dest);
+
+ Callback m_impl;
+ std::string m_description;
+
+ CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags& flags,
+ Callback impl,
+ const char* description);
+
+ Callback
+ GetBackendFunction () const
+ {
+ return m_impl;
+ }
+
+ const char*
+ GetTextualInfo () const
+ {
+ return m_description.c_str();
+ }
+
+ void
+ SetBackendFunction (Callback cb_func)
+ {
+ m_impl = cb_func;
+ }
+
+ void
+ SetTextualInfo (const char* descr)
+ {
+ if (descr)
+ m_description.assign(descr);
+ else
+ m_description.clear();
+ }
+
+ virtual
+ ~CXXFunctionSummaryFormat ()
+ {
+ }
+
+ virtual bool
+ FormatObject (ValueObject *valobj,
+ std::string& dest);
+
+ virtual std::string
+ GetDescription ();
+
+ virtual bool
+ IsScripted ()
+ {
+ return false;
+ }
+
+ virtual Type
+ GetType ()
+ {
+ return TypeSummaryImpl::eTypeCallback;
+ }
+
+ typedef std::shared_ptr<CXXFunctionSummaryFormat> SharedPointer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CXXFunctionSummaryFormat);
+ };
+
+#ifndef LLDB_DISABLE_PYTHON
+
+ // Python-based summaries, running script code to show data
+ struct ScriptSummaryFormat : public TypeSummaryImpl
+ {
+ std::string m_function_name;
+ std::string m_python_script;
+ lldb::ScriptInterpreterObjectSP m_script_function_sp;
+
+ ScriptSummaryFormat(const TypeSummaryImpl::Flags& flags,
+ const char *function_name,
+ const char* python_script = NULL);
+
+ const char*
+ GetFunctionName () const
+ {
+ return m_function_name.c_str();
+ }
+
+ const char*
+ GetPythonScript () const
+ {
+ return m_python_script.c_str();
+ }
+
+ void
+ SetFunctionName (const char* function_name)
+ {
+ if (function_name)
+ m_function_name.assign(function_name);
+ else
+ m_function_name.clear();
+ m_python_script.clear();
+ }
+
+ void
+ SetPythonScript (const char* script)
+ {
+ if (script)
+ m_python_script.assign(script);
+ else
+ m_python_script.clear();
+ }
+
+ virtual
+ ~ScriptSummaryFormat ()
+ {
+ }
+
+ virtual bool
+ FormatObject (ValueObject *valobj,
+ std::string& dest);
+
+ virtual std::string
+ GetDescription ();
+
+ virtual bool
+ IsScripted ()
+ {
+ return true;
+ }
+
+ virtual Type
+ GetType ()
+ {
+ return TypeSummaryImpl::eTypeScript;
+ }
+
+ typedef std::shared_ptr<ScriptSummaryFormat> SharedPointer;
+
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScriptSummaryFormat);
+ };
+#endif
+} // namespace lldb_private
+
+#endif // lldb_TypeSummary_h_
diff --git a/include/lldb/DataFormatters/TypeSynthetic.h b/include/lldb/DataFormatters/TypeSynthetic.h
new file mode 100644
index 000000000000..a32f4b761175
--- /dev/null
+++ b/include/lldb/DataFormatters/TypeSynthetic.h
@@ -0,0 +1,594 @@
+//===-- TypeSynthetic.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_TypeSynthetic_h_
+#define lldb_TypeSynthetic_h_
+
+// C Includes
+#include <stdint.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Symbol/Type.h"
+
+namespace lldb_private {
+ class SyntheticChildrenFrontEnd
+ {
+ protected:
+ ValueObject &m_backend;
+ public:
+
+ SyntheticChildrenFrontEnd (ValueObject &backend) :
+ m_backend(backend)
+ {}
+
+ virtual
+ ~SyntheticChildrenFrontEnd ()
+ {
+ }
+
+ virtual size_t
+ CalculateNumChildren () = 0;
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx) = 0;
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name) = 0;
+
+ // this function is assumed to always succeed and it if fails, the front-end should know to deal
+ // with it in the correct way (most probably, by refusing to return any children)
+ // the return value of Update() should actually be interpreted as "ValueObjectSyntheticFilter cache is good/bad"
+ // if =true, ValueObjectSyntheticFilter is allowed to use the children it fetched previously and cached
+ // if =false, ValueObjectSyntheticFilter must throw away its cache, and query again for children
+ virtual bool
+ Update () = 0;
+
+ // if this function returns false, then CalculateNumChildren() MUST return 0 since UI frontends
+ // might validly decide not to inquire for children given a false return value from this call
+ // if it returns true, then CalculateNumChildren() can return any number >= 0 (0 being valid)
+ // it should if at all possible be more efficient than CalculateNumChildren()
+ virtual bool
+ MightHaveChildren () = 0;
+
+ typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
+ typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SyntheticChildrenFrontEnd);
+ };
+
+ class SyntheticChildren
+ {
+ public:
+
+ class Flags
+ {
+ public:
+
+ Flags () :
+ m_flags (lldb::eTypeOptionCascade)
+ {}
+
+ Flags (const Flags& other) :
+ m_flags (other.m_flags)
+ {}
+
+ Flags (uint32_t value) :
+ m_flags (value)
+ {}
+
+ Flags&
+ operator = (const Flags& rhs)
+ {
+ if (&rhs != this)
+ m_flags = rhs.m_flags;
+
+ return *this;
+ }
+
+ Flags&
+ operator = (const uint32_t& rhs)
+ {
+ m_flags = rhs;
+ return *this;
+ }
+
+ Flags&
+ Clear()
+ {
+ m_flags = 0;
+ return *this;
+ }
+
+ bool
+ GetCascades () const
+ {
+ return (m_flags & lldb::eTypeOptionCascade) == lldb::eTypeOptionCascade;
+ }
+
+ Flags&
+ SetCascades (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionCascade;
+ else
+ m_flags &= ~lldb::eTypeOptionCascade;
+ return *this;
+ }
+
+ bool
+ GetSkipPointers () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipPointers) == lldb::eTypeOptionSkipPointers;
+ }
+
+ Flags&
+ SetSkipPointers (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipPointers;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipPointers;
+ return *this;
+ }
+
+ bool
+ GetSkipReferences () const
+ {
+ return (m_flags & lldb::eTypeOptionSkipReferences) == lldb::eTypeOptionSkipReferences;
+ }
+
+ Flags&
+ SetSkipReferences (bool value = true)
+ {
+ if (value)
+ m_flags |= lldb::eTypeOptionSkipReferences;
+ else
+ m_flags &= ~lldb::eTypeOptionSkipReferences;
+ return *this;
+ }
+
+ uint32_t
+ GetValue ()
+ {
+ return m_flags;
+ }
+
+ void
+ SetValue (uint32_t value)
+ {
+ m_flags = value;
+ }
+
+ private:
+ uint32_t m_flags;
+ };
+
+ SyntheticChildren (const Flags& flags) :
+ m_flags(flags)
+ {
+ }
+
+ virtual
+ ~SyntheticChildren ()
+ {
+ }
+
+ bool
+ Cascades () const
+ {
+ return m_flags.GetCascades();
+ }
+ bool
+ SkipsPointers () const
+ {
+ return m_flags.GetSkipPointers();
+ }
+ bool
+ SkipsReferences () const
+ {
+ return m_flags.GetSkipReferences();
+ }
+
+ void
+ SetCascades (bool value)
+ {
+ m_flags.SetCascades(value);
+ }
+
+ void
+ SetSkipsPointers (bool value)
+ {
+ m_flags.SetSkipPointers(value);
+ }
+
+ void
+ SetSkipsReferences (bool value)
+ {
+ m_flags.SetSkipReferences(value);
+ }
+
+ uint32_t
+ GetOptions ()
+ {
+ return m_flags.GetValue();
+ }
+
+ void
+ SetOptions (uint32_t value)
+ {
+ m_flags.SetValue(value);
+ }
+
+ virtual bool
+ IsScripted () = 0;
+
+ virtual std::string
+ GetDescription () = 0;
+
+ virtual SyntheticChildrenFrontEnd::AutoPointer
+ GetFrontEnd (ValueObject &backend) = 0;
+
+ typedef std::shared_ptr<SyntheticChildren> SharedPointer;
+ typedef bool(*SyntheticChildrenCallback)(void*, ConstString, const SyntheticChildren::SharedPointer&);
+
+ uint32_t&
+ GetRevision ()
+ {
+ return m_my_revision;
+ }
+
+ protected:
+ uint32_t m_my_revision;
+ Flags m_flags;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SyntheticChildren);
+ };
+
+ class TypeFilterImpl : public SyntheticChildren
+ {
+ std::vector<std::string> m_expression_paths;
+ public:
+ TypeFilterImpl(const SyntheticChildren::Flags& flags) :
+ SyntheticChildren(flags),
+ m_expression_paths()
+ {
+ }
+
+ TypeFilterImpl(const SyntheticChildren::Flags& flags,
+ const std::initializer_list<const char*> items) :
+ SyntheticChildren(flags),
+ m_expression_paths()
+ {
+ for (auto path : items)
+ AddExpressionPath (path);
+ }
+
+ void
+ AddExpressionPath (const char* path)
+ {
+ AddExpressionPath(std::string(path));
+ }
+
+ void
+ Clear()
+ {
+ m_expression_paths.clear();
+ }
+
+ size_t
+ GetCount() const
+ {
+ return m_expression_paths.size();
+ }
+
+ const char*
+ GetExpressionPathAtIndex(size_t i) const
+ {
+ return m_expression_paths[i].c_str();
+ }
+
+ bool
+ SetExpressionPathAtIndex (size_t i, const char* path)
+ {
+ return SetExpressionPathAtIndex(i, std::string(path));
+ }
+
+ void
+ 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
+ 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;
+ }
+
+ bool
+ IsScripted ()
+ {
+ return false;
+ }
+
+ std::string
+ GetDescription ();
+
+ class FrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ TypeFilterImpl* filter;
+ public:
+
+ FrontEnd(TypeFilterImpl* flt,
+ ValueObject &backend) :
+ SyntheticChildrenFrontEnd(backend),
+ filter(flt)
+ {}
+
+ virtual
+ ~FrontEnd ()
+ {
+ }
+
+ virtual size_t
+ CalculateNumChildren ()
+ {
+ return filter->GetCount();
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ if (idx >= filter->GetCount())
+ return lldb::ValueObjectSP();
+ return m_backend.GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx), true);
+ }
+
+ virtual bool
+ Update() { return false; }
+
+ virtual bool
+ MightHaveChildren ()
+ {
+ return filter->GetCount() > 0;
+ }
+
+ virtual size_t
+ 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;
+ }
+
+ typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FrontEnd);
+ };
+
+ virtual SyntheticChildrenFrontEnd::AutoPointer
+ GetFrontEnd(ValueObject &backend)
+ {
+ return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(this, backend));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TypeFilterImpl);
+ };
+
+ class CXXSyntheticChildren : public SyntheticChildren
+ {
+ public:
+ typedef SyntheticChildrenFrontEnd* (*CreateFrontEndCallback) (CXXSyntheticChildren*, lldb::ValueObjectSP);
+ protected:
+ CreateFrontEndCallback m_create_callback;
+ std::string m_description;
+ public:
+ CXXSyntheticChildren (const SyntheticChildren::Flags& flags,
+ const char* description,
+ CreateFrontEndCallback callback) :
+ SyntheticChildren(flags),
+ m_create_callback(callback),
+ m_description(description ? description : "")
+ {
+ }
+
+ bool
+ IsScripted ()
+ {
+ return false;
+ }
+
+ std::string
+ GetDescription ();
+
+ virtual SyntheticChildrenFrontEnd::AutoPointer
+ GetFrontEnd (ValueObject &backend)
+ {
+ return SyntheticChildrenFrontEnd::AutoPointer(m_create_callback(this, backend.GetSP()));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CXXSyntheticChildren);
+ };
+
+#ifndef LLDB_DISABLE_PYTHON
+
+ class ScriptedSyntheticChildren : public SyntheticChildren
+ {
+ std::string m_python_class;
+ std::string m_python_code;
+ public:
+
+ ScriptedSyntheticChildren (const SyntheticChildren::Flags& flags,
+ const char* pclass,
+ const char* pcode = NULL) :
+ SyntheticChildren(flags),
+ m_python_class(),
+ m_python_code()
+ {
+ if (pclass)
+ m_python_class = pclass;
+ if (pcode)
+ m_python_code = pcode;
+ }
+
+ const char*
+ GetPythonClassName ()
+ {
+ return m_python_class.c_str();
+ }
+
+ const char*
+ GetPythonCode ()
+ {
+ return m_python_code.c_str();
+ }
+
+ void
+ SetPythonClassName (const char* fname)
+ {
+ m_python_class.assign(fname);
+ m_python_code.clear();
+ }
+
+ void
+ SetPythonCode (const char* script)
+ {
+ m_python_code.assign(script);
+ }
+
+ std::string
+ GetDescription ();
+
+ bool
+ IsScripted ()
+ {
+ return true;
+ }
+
+ class FrontEnd : public SyntheticChildrenFrontEnd
+ {
+ private:
+ std::string m_python_class;
+ lldb::ScriptInterpreterObjectSP m_wrapper_sp;
+ ScriptInterpreter *m_interpreter;
+ public:
+
+ FrontEnd (std::string pclass,
+ ValueObject &backend);
+
+ virtual
+ ~FrontEnd ();
+
+ virtual size_t
+ CalculateNumChildren ()
+ {
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return 0;
+ return m_interpreter->CalculateNumChildren(m_wrapper_sp);
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx);
+
+ virtual bool
+ Update ()
+ {
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return false;
+
+ return m_interpreter->UpdateSynthProviderInstance(m_wrapper_sp);
+ }
+
+ virtual bool
+ MightHaveChildren ()
+ {
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return false;
+
+ return m_interpreter->MightHaveChildrenSynthProviderInstance(m_wrapper_sp);
+ }
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name)
+ {
+ if (!m_wrapper_sp || m_interpreter == NULL)
+ return UINT32_MAX;
+ return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString());
+ }
+
+ typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FrontEnd);
+ };
+
+ virtual SyntheticChildrenFrontEnd::AutoPointer
+ GetFrontEnd(ValueObject &backend)
+ {
+ return SyntheticChildrenFrontEnd::AutoPointer(new FrontEnd(m_python_class, backend));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScriptedSyntheticChildren);
+ };
+#endif
+} // namespace lldb_private
+
+#endif // lldb_TypeSynthetic_h_
diff --git a/include/lldb/Expression/ASTDumper.h b/include/lldb/Expression/ASTDumper.h
new file mode 100644
index 000000000000..47f7ea460b87
--- /dev/null
+++ b/include/lldb/Expression/ASTDumper.h
@@ -0,0 +1,43 @@
+//===-- ASTDumper.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_ASTDumper_h_
+#define liblldb_ASTDumper_h_
+
+#include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeVisitor.h"
+
+#include "lldb/Core/Stream.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace lldb_private
+{
+
+class ASTDumper
+{
+public:
+ ASTDumper (clang::Decl *decl);
+ ASTDumper (clang::DeclContext *decl_ctx);
+ ASTDumper (const clang::Type *type);
+ ASTDumper (clang::QualType type);
+ ASTDumper (lldb::clang_type_t type);
+ ASTDumper (const ClangASTType &clang_type);
+
+ const char *GetCString();
+ void ToSTDERR();
+ void ToLog(Log *log, const char *prefix);
+ void ToStream(lldb::StreamSP &stream);
+private:
+ std::string m_dump;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/include/lldb/Expression/ASTResultSynthesizer.h b/include/lldb/Expression/ASTResultSynthesizer.h
new file mode 100644
index 000000000000..79709de3546a
--- /dev/null
+++ b/include/lldb/Expression/ASTResultSynthesizer.h
@@ -0,0 +1,184 @@
+//===-- ASTResultSynthesizer.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_ASTResultSynthesizer_h_
+#define liblldb_ASTResultSynthesizer_h_
+
+#include "clang/Sema/SemaConsumer.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Symbol/TaggedASTType.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ASTResultSynthesizer ASTResultSynthesizer.h "lldb/Expression/ASTResultSynthesizer.h"
+/// @brief Adds a result variable declaration to the ASTs for an expression.
+///
+/// Users expect the expression "i + 3" to return a result, even if a result
+/// variable wasn't specifically declared. To fulfil this requirement, LLDB adds
+/// a result variable to the expression, transforming it to
+/// "int $__lldb_expr_result = i + 3." The IR transformers ensure that the
+/// resulting variable is mapped to the right piece of memory.
+/// ASTResultSynthesizer's job is to add the variable and its initialization to
+/// the ASTs for the expression, and it does so by acting as a SemaConsumer for
+/// Clang.
+//----------------------------------------------------------------------
+class ASTResultSynthesizer : public clang::SemaConsumer
+{
+public:
+ //----------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] passthrough
+ /// Since the ASTs must typically go through to the Clang code generator
+ /// in order to produce LLVM IR, this SemaConsumer must allow them to
+ /// pass to the next step in the chain after processing. Passthrough is
+ /// the next ASTConsumer, or NULL if none is required.
+ ///
+ /// @param[in] target
+ /// The target, which contains the persistent variable store and the
+ /// AST importer.
+ //----------------------------------------------------------------------
+ ASTResultSynthesizer(clang::ASTConsumer *passthrough,
+ Target &target);
+
+ //----------------------------------------------------------------------
+ /// Destructor
+ //----------------------------------------------------------------------
+ ~ASTResultSynthesizer();
+
+ //----------------------------------------------------------------------
+ /// Link this consumer with a particular AST context
+ ///
+ /// @param[in] Context
+ /// This AST context will be used for types and identifiers, and also
+ /// forwarded to the passthrough consumer, if one exists.
+ //----------------------------------------------------------------------
+ void Initialize(clang::ASTContext &Context);
+
+ //----------------------------------------------------------------------
+ /// Examine a list of Decls to find the function $__lldb_expr and
+ /// transform its code
+ ///
+ /// @param[in] D
+ /// The list of Decls to search. These may contain LinkageSpecDecls,
+ /// which need to be searched recursively. That job falls to
+ /// TransformTopLevelDecl.
+ //----------------------------------------------------------------------
+ bool HandleTopLevelDecl(clang::DeclGroupRef D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleTranslationUnit(clang::ASTContext &Ctx);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleTagDeclDefinition(clang::TagDecl *D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void CompleteTentativeDefinition(clang::VarDecl *D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void PrintStats();
+
+ //----------------------------------------------------------------------
+ /// Set the Sema object to use when performing transforms, and pass it on
+ ///
+ /// @param[in] S
+ /// The Sema to use. Because Sema isn't externally visible, this class
+ /// casts it to an Action for actual use.
+ //----------------------------------------------------------------------
+ void InitializeSema(clang::Sema &S);
+
+ //----------------------------------------------------------------------
+ /// Reset the Sema to NULL now that transformations are done
+ //----------------------------------------------------------------------
+ void ForgetSema();
+private:
+ //----------------------------------------------------------------------
+ /// Hunt the given Decl for FunctionDecls named $__lldb_expr, recursing
+ /// as necessary through LinkageSpecDecls, and calling SynthesizeResult on
+ /// anything that was found
+ ///
+ /// @param[in] D
+ /// The Decl to hunt.
+ //----------------------------------------------------------------------
+ void TransformTopLevelDecl(clang::Decl *D);
+
+ //----------------------------------------------------------------------
+ /// Process an Objective-C method and produce the result variable and
+ /// initialization
+ ///
+ /// @param[in] MethodDecl
+ /// The method to process.
+ //----------------------------------------------------------------------
+ bool SynthesizeObjCMethodResult(clang::ObjCMethodDecl *MethodDecl);
+
+ //----------------------------------------------------------------------
+ /// Process a function and produce the result variable and initialization
+ ///
+ /// @param[in] FunDecl
+ /// The function to process.
+ //----------------------------------------------------------------------
+ bool SynthesizeFunctionResult(clang::FunctionDecl *FunDecl);
+
+ //----------------------------------------------------------------------
+ /// Process a function body and produce the result variable and
+ /// initialization
+ ///
+ /// @param[in] Body
+ /// The body of the function.
+ ///
+ /// @param[in] DC
+ /// The DeclContext of the function, into which the result variable
+ /// is inserted.
+ //----------------------------------------------------------------------
+ bool SynthesizeBodyResult(clang::CompoundStmt *Body,
+ clang::DeclContext *DC);
+
+ //----------------------------------------------------------------------
+ /// Given a DeclContext for a function or method, find all types
+ /// declared in the context and record any persistent types found.
+ ///
+ /// @param[in] FunDeclCtx
+ /// The context for the function to process.
+ //----------------------------------------------------------------------
+ void RecordPersistentTypes(clang::DeclContext *FunDeclCtx);
+
+ //----------------------------------------------------------------------
+ /// Given a TypeDecl, if it declares a type whose name starts with a
+ /// dollar sign, register it as a pointer type in the target's scratch
+ /// AST context.
+ ///
+ /// @param[in] Body
+ /// The body of the function.
+ //----------------------------------------------------------------------
+ void MaybeRecordPersistentType(clang::TypeDecl *D);
+
+ clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types.
+ clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer.
+ clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer.
+ Target &m_target; ///< The target, which contains the persistent variable store and the
+ clang::Sema *m_sema; ///< The Sema to use.
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/ASTStructExtractor.h b/include/lldb/Expression/ASTStructExtractor.h
new file mode 100644
index 000000000000..a1518de83d6d
--- /dev/null
+++ b/include/lldb/Expression/ASTStructExtractor.h
@@ -0,0 +1,156 @@
+//===-- ASTStructExtractor.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_ASTStructExtractor_h_
+#define liblldb_ASTStructExtractor_h_
+
+#include "clang/Sema/SemaConsumer.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangFunction.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ASTStructExtractor ASTStructExtractor.h "lldb/Expression/ASTStructExtractor.h"
+/// @brief Extracts and describes the argument structure for a wrapped function.
+///
+/// This pass integrates with ClangFunction, which calls functions with custom
+/// sets of arguments. To avoid having to implement the full calling convention
+/// for the target's architecture, ClangFunction writes a simple wrapper
+/// function that takes a pointer to an argument structure that contains room
+/// for the address of the function to be called, the values of all its
+/// arguments, and room for the function's return value.
+///
+/// The definition of this struct is itself in the body of the wrapper function,
+/// so Clang does the structure layout itself. ASTStructExtractor reads through
+/// the AST for the wrapper funtion and finds the struct.
+//----------------------------------------------------------------------
+class ASTStructExtractor : public clang::SemaConsumer
+{
+public:
+ //----------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] passthrough
+ /// Since the ASTs must typically go through to the Clang code generator
+ /// in order to produce LLVM IR, this SemaConsumer must allow them to
+ /// pass to the next step in the chain after processing. Passthrough is
+ /// the next ASTConsumer, or NULL if none is required.
+ ///
+ /// @param[in] struct_name
+ /// The name of the structure to extract from the wrapper function.
+ ///
+ /// @param[in] function
+ /// The caller object whose members should be populated with information
+ /// about the argument struct. ClangFunction friends ASTStructExtractor
+ /// for this purpose.
+ //----------------------------------------------------------------------
+ ASTStructExtractor(clang::ASTConsumer *passthrough,
+ const char *struct_name,
+ ClangFunction &function);
+
+ //----------------------------------------------------------------------
+ /// Destructor
+ //----------------------------------------------------------------------
+ virtual ~ASTStructExtractor();
+
+ //----------------------------------------------------------------------
+ /// Link this consumer with a particular AST context
+ ///
+ /// @param[in] Context
+ /// This AST context will be used for types and identifiers, and also
+ /// forwarded to the passthrough consumer, if one exists.
+ //----------------------------------------------------------------------
+ void Initialize(clang::ASTContext &Context);
+
+ //----------------------------------------------------------------------
+ /// Examine a list of Decls to find the function $__lldb_expr and
+ /// transform its code
+ ///
+ /// @param[in] D
+ /// The list of Decls to search. These may contain LinkageSpecDecls,
+ /// which need to be searched recursively. That job falls to
+ /// TransformTopLevelDecl.
+ //----------------------------------------------------------------------
+ bool HandleTopLevelDecl(clang::DeclGroupRef D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleTranslationUnit(clang::ASTContext &Ctx);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleTagDeclDefinition(clang::TagDecl *D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void CompleteTentativeDefinition(clang::VarDecl *D);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void HandleVTable(clang::CXXRecordDecl *RD, bool DefinitionRequired);
+
+ //----------------------------------------------------------------------
+ /// Passthrough stub
+ //----------------------------------------------------------------------
+ void PrintStats();
+
+ //----------------------------------------------------------------------
+ /// Set the Sema object to use when performing transforms, and pass it on
+ ///
+ /// @param[in] S
+ /// The Sema to use. Because Sema isn't externally visible, this class
+ /// casts it to an Action for actual use.
+ //----------------------------------------------------------------------
+ void InitializeSema(clang::Sema &S);
+
+ //----------------------------------------------------------------------
+ /// Reset the Sema to NULL now that transformations are done
+ //----------------------------------------------------------------------
+ void ForgetSema();
+private:
+ //----------------------------------------------------------------------
+ /// Hunt the given FunctionDecl for the argument struct and place
+ /// information about it into m_function
+ ///
+ /// @param[in] F
+ /// The FunctionDecl to hunt.
+ //----------------------------------------------------------------------
+ void
+ ExtractFromFunctionDecl(clang::FunctionDecl* F);
+
+ //----------------------------------------------------------------------
+ /// Hunt the given Decl for FunctionDecls named the same as the wrapper
+ /// function name, recursing as necessary through LinkageSpecDecls, and
+ /// calling ExtractFromFunctionDecl on anything that was found
+ ///
+ /// @param[in] D
+ /// The Decl to hunt.
+ //----------------------------------------------------------------------
+ void
+ ExtractFromTopLevelDecl(clang::Decl* D);
+
+ clang::ASTContext *m_ast_context; ///< The AST context to use for identifiers and types.
+ clang::ASTConsumer *m_passthrough; ///< The ASTConsumer down the chain, for passthrough. NULL if it's a SemaConsumer.
+ clang::SemaConsumer *m_passthrough_sema; ///< The SemaConsumer down the chain, for passthrough. NULL if it's an ASTConsumer.
+ clang::Sema *m_sema; ///< The Sema to use.
+ clang::Action *m_action; ///< The Sema to use, cast to an Action so it's usable.
+
+ ClangFunction &m_function; ///< The function to populate with information about the argument structure.
+ std::string m_struct_name; ///< The name of the structure to extract.
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/ClangASTSource.h b/include/lldb/Expression/ClangASTSource.h
new file mode 100644
index 000000000000..3e41a9e69e9b
--- /dev/null
+++ b/include/lldb/Expression/ClangASTSource.h
@@ -0,0 +1,530 @@
+//===-- ClangASTSource.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_ClangASTSource_h_
+#define liblldb_ClangASTSource_h_
+
+#include <set>
+
+#include "clang/Basic/IdentifierTable.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/ADT/SmallSet.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ClangASTSource ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+/// @brief Provider for named objects defined in the debug info for Clang
+///
+/// As Clang parses an expression, it may encounter names that are not
+/// defined inside the expression, including variables, functions, and
+/// types. Clang knows the name it is looking for, but nothing else.
+/// The ExternalSemaSource class provides Decls (VarDecl, FunDecl, TypeDecl)
+/// to Clang for these names, consulting the ClangExpressionDeclMap to do
+/// the actual lookups.
+//----------------------------------------------------------------------
+class ClangASTSource :
+ public ClangExternalASTSourceCommon,
+ public ClangASTImporter::MapCompleter
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// @param[in] declMap
+ /// A reference to the LLDB object that handles entity lookup.
+ //------------------------------------------------------------------
+ ClangASTSource (const lldb::TargetSP &target) :
+ m_import_in_progress (false),
+ m_lookups_enabled (false),
+ m_target (target),
+ m_ast_context (NULL),
+ m_active_lookups ()
+ {
+ m_ast_importer = m_target->GetClangASTImporter();
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~ClangASTSource();
+
+ //------------------------------------------------------------------
+ /// Interface stubs.
+ //------------------------------------------------------------------
+ clang::Decl *GetExternalDecl (uint32_t) { return NULL; }
+ clang::Stmt *GetExternalDeclStmt (uint64_t) { return NULL; }
+ clang::Selector GetExternalSelector (uint32_t) { return clang::Selector(); }
+ uint32_t GetNumExternalSelectors () { return 0; }
+ clang::CXXBaseSpecifier *GetExternalCXXBaseSpecifiers (uint64_t Offset)
+ { return NULL; }
+ void MaterializeVisibleDecls (const clang::DeclContext *DC)
+ { return; }
+
+ void InstallASTContext (clang::ASTContext *ast_context)
+ {
+ m_ast_context = ast_context;
+ m_ast_importer->InstallMapCompleter(ast_context, *this);
+ }
+
+ //
+ // APIs for ExternalASTSource
+ //
+
+ //------------------------------------------------------------------
+ /// Look up all Decls that match a particular name. Only handles
+ /// Identifiers and DeclContexts that are either NamespaceDecls or
+ /// TranslationUnitDecls. Calls SetExternalVisibleDeclsForName with
+ /// the result.
+ ///
+ /// The work for this function is done by
+ /// void FindExternalVisibleDecls (NameSearchContext &);
+ ///
+ /// @param[in] DC
+ /// The DeclContext to register the found Decls in.
+ ///
+ /// @param[in] Name
+ /// The name to find entries for.
+ ///
+ /// @return
+ /// Whatever SetExternalVisibleDeclsForName returns.
+ //------------------------------------------------------------------
+ bool
+ FindExternalVisibleDeclsByName (const clang::DeclContext *DC,
+ clang::DeclarationName Name);
+
+ //------------------------------------------------------------------
+ /// Enumerate all Decls in a given lexical context.
+ ///
+ /// @param[in] DC
+ /// The DeclContext being searched.
+ ///
+ /// @param[in] isKindWeWant
+ /// If non-NULL, a callback function that returns true given the
+ /// DeclKinds of desired Decls, and false otherwise.
+ ///
+ /// @param[in] Decls
+ /// A vector that is filled in with matching Decls.
+ //------------------------------------------------------------------
+ clang::ExternalLoadResult
+ FindExternalLexicalDecls (const clang::DeclContext *DC,
+ bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl*> &Decls);
+
+ //------------------------------------------------------------------
+ /// Specify the layout of the contents of a RecordDecl.
+ ///
+ /// @param[in] Record
+ /// The record (in the parser's AST context) that needs to be
+ /// laid out.
+ ///
+ /// @param[out] Size
+ /// The total size of the record in bits.
+ ///
+ /// @param[out] Alignment
+ /// The alignment of the record in bits.
+ ///
+ /// @param[in] FieldOffsets
+ /// A map that must be populated with pairs of the record's
+ /// fields (in the parser's AST context) and their offsets
+ /// (measured in bits).
+ ///
+ /// @param[in] BaseOffsets
+ /// A map that must be populated with pairs of the record's
+ /// C++ concrete base classes (in the parser's AST context,
+ /// and only if the record is a CXXRecordDecl and has base
+ /// classes) and their offsets (measured in bytes).
+ ///
+ /// @param[in] VirtualBaseOffsets
+ /// A map that must be populated with pairs of the record's
+ /// C++ virtual base classes (in the parser's AST context,
+ /// and only if the record is a CXXRecordDecl and has base
+ /// classes) and their offsets (measured in bytes).
+ ///
+ /// @return
+ /// True <=> the layout is valid.
+ //-----------------------------------------------------------------
+ bool
+ layoutRecordType(const clang::RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
+
+ //------------------------------------------------------------------
+ /// Complete a TagDecl.
+ ///
+ /// @param[in] Tag
+ /// The Decl to be completed in place.
+ //------------------------------------------------------------------
+ virtual void
+ CompleteType (clang::TagDecl *Tag);
+
+ //------------------------------------------------------------------
+ /// Complete an ObjCInterfaceDecl.
+ ///
+ /// @param[in] Class
+ /// The Decl to be completed in place.
+ //------------------------------------------------------------------
+ virtual void
+ CompleteType (clang::ObjCInterfaceDecl *Class);
+
+ //------------------------------------------------------------------
+ /// Called on entering a translation unit. Tells Clang by calling
+ /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage()
+ /// that this object has something to say about undefined names.
+ ///
+ /// @param[in] ASTConsumer
+ /// Unused.
+ //------------------------------------------------------------------
+ void StartTranslationUnit (clang::ASTConsumer *Consumer);
+
+ //
+ // APIs for NamespaceMapCompleter
+ //
+
+ //------------------------------------------------------------------
+ /// Look up the modules containing a given namespace and put the
+ /// appropriate entries in the namespace map.
+ ///
+ /// @param[in] namespace_map
+ /// The map to be completed.
+ ///
+ /// @param[in] name
+ /// The name of the namespace to be found.
+ ///
+ /// @param[in] parent_map
+ /// The map for the namespace's parent namespace, if there is
+ /// one.
+ //------------------------------------------------------------------
+ void CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map,
+ const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const;
+
+ //
+ // Helper APIs
+ //
+
+ clang::NamespaceDecl *
+ AddNamespace (NameSearchContext &context,
+ ClangASTImporter::NamespaceMapSP &namespace_decls);
+
+ //------------------------------------------------------------------
+ /// The worker function for FindExternalVisibleDeclsByName.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when filing results.
+ //------------------------------------------------------------------
+ virtual void FindExternalVisibleDecls (NameSearchContext &context);
+
+ void SetImportInProgress (bool import_in_progress) { m_import_in_progress = import_in_progress; }
+ bool GetImportInProgress () { return m_import_in_progress; }
+
+ void SetLookupsEnabled (bool lookups_enabled) { m_lookups_enabled = lookups_enabled; }
+ bool GetLookupsEnabled () { return m_lookups_enabled; }
+
+ //----------------------------------------------------------------------
+ /// @class ClangASTSourceProxy ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+ /// @brief Proxy for ClangASTSource
+ ///
+ /// Clang AST contexts like to own their AST sources, so this is a
+ /// state-free proxy object.
+ //----------------------------------------------------------------------
+ class ClangASTSourceProxy : public ClangExternalASTSourceCommon
+ {
+ public:
+ ClangASTSourceProxy (ClangASTSource &original) :
+ m_original(original)
+ {
+ }
+
+ bool
+ FindExternalVisibleDeclsByName (const clang::DeclContext *DC,
+ clang::DeclarationName Name)
+ {
+ return m_original.FindExternalVisibleDeclsByName(DC, Name);
+ }
+
+ clang::ExternalLoadResult
+ FindExternalLexicalDecls (const clang::DeclContext *DC,
+ bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl*> &Decls)
+ {
+ return m_original.FindExternalLexicalDecls(DC, isKindWeWant, Decls);
+ }
+
+ void
+ CompleteType (clang::TagDecl *Tag)
+ {
+ return m_original.CompleteType(Tag);
+ }
+
+ void
+ CompleteType (clang::ObjCInterfaceDecl *Class)
+ {
+ return m_original.CompleteType(Class);
+ }
+
+ bool
+ layoutRecordType(const clang::RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
+ {
+ return m_original.layoutRecordType(Record,
+ Size,
+ Alignment,
+ FieldOffsets,
+ BaseOffsets,
+ VirtualBaseOffsets);
+ }
+
+ void StartTranslationUnit (clang::ASTConsumer *Consumer)
+ {
+ return m_original.StartTranslationUnit(Consumer);
+ }
+
+ ClangASTMetadata *
+ GetMetadata(const void * object)
+ {
+ return m_original.GetMetadata(object);
+ }
+
+ void
+ SetMetadata(const void * object, ClangASTMetadata &metadata)
+ {
+ return m_original.SetMetadata(object, metadata);
+ }
+
+ bool
+ HasMetadata(const void * object)
+ {
+ return m_original.HasMetadata(object);
+ }
+ private:
+ ClangASTSource &m_original;
+ };
+
+ clang::ExternalASTSource *CreateProxy()
+ {
+ return new ClangASTSourceProxy(*this);
+ }
+
+protected:
+ //------------------------------------------------------------------
+ /// Look for the complete version of an Objective-C interface, and
+ /// return it if found.
+ ///
+ /// @param[in] interface_decl
+ /// An ObjCInterfaceDecl that may not be the complete one.
+ ///
+ /// @return
+ /// NULL if the complete interface couldn't be found;
+ /// the complete interface otherwise.
+ //------------------------------------------------------------------
+ clang::ObjCInterfaceDecl *
+ GetCompleteObjCInterface (clang::ObjCInterfaceDecl *interface_decl);
+
+ //------------------------------------------------------------------
+ /// Find all entities matching a given name in a given module,
+ /// using a NameSearchContext to make Decls for them.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// @param[in] module
+ /// If non-NULL, the module to query.
+ ///
+ /// @param[in] namespace_decl
+ /// If valid and module is non-NULL, the parent namespace.
+ ///
+ /// @param[in] current_id
+ /// The ID for the current FindExternalVisibleDecls invocation,
+ /// for logging purposes.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module,
+ ClangNamespaceDecl &namespace_decl,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Find all Objective-C methods matching a given selector.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ /// Its m_decl_name contains the selector and its m_decl_context
+ /// is the containing object.
+ //------------------------------------------------------------------
+ void
+ FindObjCMethodDecls (NameSearchContext &context);
+
+ //------------------------------------------------------------------
+ /// Find all Objective-C properties and ivars with a given name.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ /// Its m_decl_name contains the name and its m_decl_context
+ /// is the containing object.
+ //------------------------------------------------------------------
+ void
+ FindObjCPropertyAndIvarDecls (NameSearchContext &context);
+
+ //------------------------------------------------------------------
+ /// A wrapper for ClangASTContext::CopyType that sets a flag that
+ /// indicates that we should not respond to queries during import.
+ ///
+ /// @param[in] dest_context
+ /// The target AST context, typically the parser's AST context.
+ ///
+ /// @param[in] source_context
+ /// The source AST context, typically the AST context of whatever
+ /// symbol file the type was found in.
+ ///
+ /// @param[in] clang_type
+ /// The source type.
+ ///
+ /// @return
+ /// The imported type.
+ //------------------------------------------------------------------
+ ClangASTType
+ GuardedCopyType (const ClangASTType &src_type);
+
+ friend struct NameSearchContext;
+
+ bool m_import_in_progress;
+ bool m_lookups_enabled;
+
+ const lldb::TargetSP m_target; ///< The target to use in finding variables and types.
+ clang::ASTContext *m_ast_context; ///< The AST context requests are coming in for.
+ ClangASTImporter *m_ast_importer; ///< The target's AST importer.
+ std::set<const char *> m_active_lookups;
+};
+
+//----------------------------------------------------------------------
+/// @class NameSearchContext ClangASTSource.h "lldb/Expression/ClangASTSource.h"
+/// @brief Container for all objects relevant to a single name lookup
+///
+/// LLDB needs to create Decls for entities it finds. This class communicates
+/// what name is being searched for and provides helper functions to construct
+/// Decls given appropriate type information.
+//----------------------------------------------------------------------
+struct NameSearchContext {
+ ClangASTSource &m_ast_source; ///< The AST source making the request
+ llvm::SmallVectorImpl<clang::NamedDecl*> &m_decls; ///< The list of declarations already constructed
+ ClangASTImporter::NamespaceMapSP m_namespace_map; ///< The mapping of all namespaces found for this request back to their modules
+ const clang::DeclarationName &m_decl_name; ///< The name being looked for
+ const clang::DeclContext *m_decl_context; ///< The DeclContext to put declarations into
+ llvm::SmallSet <ClangASTType, 5> m_function_types; ///< All the types of functions that have been reported, so we don't report conflicts
+
+ struct {
+ bool variable : 1;
+ bool function_with_type_info : 1;
+ bool function : 1;
+ } m_found;
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// @param[in] astSource
+ /// A reference to the AST source making a request.
+ ///
+ /// @param[in] decls
+ /// A reference to a list into which new Decls will be placed. This
+ /// list is typically empty when the function is called.
+ ///
+ /// @param[in] name
+ /// The name being searched for (always an Identifier).
+ ///
+ /// @param[in] dc
+ /// The DeclContext to register Decls in.
+ //------------------------------------------------------------------
+ NameSearchContext (ClangASTSource &astSource,
+ llvm::SmallVectorImpl<clang::NamedDecl*> &decls,
+ clang::DeclarationName &name,
+ const clang::DeclContext *dc) :
+ m_ast_source(astSource),
+ m_decls(decls),
+ m_decl_name(name),
+ m_decl_context(dc)
+ {
+ memset(&m_found, 0, sizeof(m_found));
+ }
+
+ //------------------------------------------------------------------
+ /// Create a VarDecl with the name being searched for and the provided
+ /// type and register it in the right places.
+ ///
+ /// @param[in] type
+ /// The opaque QualType for the VarDecl being registered.
+ //------------------------------------------------------------------
+ clang::NamedDecl *AddVarDecl(const ClangASTType &type);
+
+ //------------------------------------------------------------------
+ /// Create a FunDecl with the name being searched for and the provided
+ /// type and register it in the right places.
+ ///
+ /// @param[in] type
+ /// The opaque QualType for the FunDecl being registered.
+ //------------------------------------------------------------------
+ clang::NamedDecl *AddFunDecl(const ClangASTType &type);
+
+ //------------------------------------------------------------------
+ /// Create a FunDecl with the name being searched for and generic
+ /// type (i.e. intptr_t NAME_GOES_HERE(...)) and register it in the
+ /// right places.
+ //------------------------------------------------------------------
+ clang::NamedDecl *AddGenericFunDecl();
+
+ //------------------------------------------------------------------
+ /// Create a TypeDecl with the name being searched for and the provided
+ /// type and register it in the right places.
+ ///
+ /// @param[in] type
+ /// The opaque QualType for the TypeDecl being registered.
+ //------------------------------------------------------------------
+ clang::NamedDecl *AddTypeDecl(const ClangASTType &clang_type);
+
+
+ //------------------------------------------------------------------
+ /// Add Decls from the provided DeclContextLookupResult to the list
+ /// of results.
+ ///
+ /// @param[in] result
+ /// The DeclContextLookupResult, usually returned as the result
+ /// of querying a DeclContext.
+ //------------------------------------------------------------------
+ void AddLookupResult (clang::DeclContextLookupConstResult result);
+
+ //------------------------------------------------------------------
+ /// Add a NamedDecl to the list of results.
+ ///
+ /// @param[in] decl
+ /// The NamedDecl, usually returned as the result
+ /// of querying a DeclContext.
+ //------------------------------------------------------------------
+ void AddNamedDecl (clang::NamedDecl *decl);
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/ClangExpression.h b/include/lldb/Expression/ClangExpression.h
new file mode 100644
index 000000000000..6e831e4471e8
--- /dev/null
+++ b/include/lldb/Expression/ClangExpression.h
@@ -0,0 +1,153 @@
+//===-- ClangExpression.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_ClangExpression_h_
+#define liblldb_ClangExpression_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+class RecordingMemoryManager;
+
+//----------------------------------------------------------------------
+/// @class ClangExpression ClangExpression.h "lldb/Expression/ClangExpression.h"
+/// @brief Encapsulates a single expression for use with Clang
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// and as a backend for the expr command. ClangExpression encapsulates
+/// the objects needed to parse and interpret or JIT an expression. It
+/// uses the Clang parser to produce LLVM IR from the expression.
+//----------------------------------------------------------------------
+class ClangExpression
+{
+public:
+ enum ResultType {
+ eResultTypeAny,
+ eResultTypeId
+ };
+
+ ClangExpression () :
+ m_jit_process_wp(),
+ m_jit_start_addr (LLDB_INVALID_ADDRESS),
+ m_jit_end_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual ~ClangExpression ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Return the string that the parser should parse. Must be a full
+ /// translation unit.
+ //------------------------------------------------------------------
+ virtual const char *
+ Text () = 0;
+
+ //------------------------------------------------------------------
+ /// Return the function name that should be used for executing the
+ /// expression. Text() should contain the definition of this
+ /// function.
+ //------------------------------------------------------------------
+ virtual const char *
+ FunctionName () = 0;
+
+ //------------------------------------------------------------------
+ /// Return the language that should be used when parsing. To use
+ /// the default, return eLanguageTypeUnknown.
+ //------------------------------------------------------------------
+ virtual lldb::LanguageType
+ Language ()
+ {
+ return lldb::eLanguageTypeUnknown;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ virtual ClangExpressionDeclMap *
+ DeclMap () = 0;
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ virtual clang::ASTConsumer *
+ ASTTransformer (clang::ASTConsumer *passthrough) = 0;
+
+ //------------------------------------------------------------------
+ /// Return the desired result type of the function, or
+ /// eResultTypeAny if indifferent.
+ //------------------------------------------------------------------
+ virtual ResultType
+ DesiredResultType ()
+ {
+ return eResultTypeAny;
+ }
+
+ //------------------------------------------------------------------
+ /// Flags
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Return true if validation code should be inserted into the
+ /// expression.
+ //------------------------------------------------------------------
+ virtual bool
+ NeedsValidation () = 0;
+
+ //------------------------------------------------------------------
+ /// Return true if external variables in the expression should be
+ /// resolved.
+ //------------------------------------------------------------------
+ virtual bool
+ NeedsVariableResolution () = 0;
+
+ //------------------------------------------------------------------
+ /// Return the address of the function's JIT-compiled code, or
+ /// LLDB_INVALID_ADDRESS if the function is not JIT compiled
+ //------------------------------------------------------------------
+ lldb::addr_t
+ StartAddress ()
+ {
+ return m_jit_start_addr;
+ }
+
+protected:
+
+ lldb::ProcessWP m_jit_process_wp;
+ lldb::addr_t m_jit_start_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid.
+ lldb::addr_t m_jit_end_addr; ///< The address of the JITted function within the JIT allocation. LLDB_INVALID_ADDRESS if invalid.
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpression_h_
diff --git a/include/lldb/Expression/ClangExpressionDeclMap.h b/include/lldb/Expression/ClangExpressionDeclMap.h
new file mode 100644
index 000000000000..b2a43e0ac75f
--- /dev/null
+++ b/include/lldb/Expression/ClangExpressionDeclMap.h
@@ -0,0 +1,698 @@
+//===-- ClangExpressionDeclMap.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_ClangExpressionDeclMap_h_
+#define liblldb_ClangExpressionDeclMap_h_
+
+// C Includes
+#include <signal.h>
+#include <stdint.h>
+
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "clang/AST/Decl.h"
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionDeclMap ClangExpressionDeclMap.h "lldb/Expression/ClangExpressionDeclMap.h"
+/// @brief Manages named entities that are defined in LLDB's debug information.
+///
+/// The Clang parser uses the ClangASTSource as an interface to request named
+/// entities from outside an expression. The ClangASTSource reports back, listing
+/// all possible objects corresponding to a particular name. But it in turn
+/// relies on ClangExpressionDeclMap, which performs several important functions.
+///
+/// First, it records what variables and functions were looked up and what Decls
+/// were returned for them.
+///
+/// Second, it constructs a struct on behalf of IRForTarget, recording which
+/// variables should be placed where and relaying this information back so that
+/// IRForTarget can generate context-independent code.
+///
+/// Third, it "materializes" this struct on behalf of the expression command,
+/// finding the current values of each variable and placing them into the
+/// struct so that it can be passed to the JITted version of the IR.
+///
+/// Fourth and finally, it "dematerializes" the struct after the JITted code has
+/// has executed, placing the new values back where it found the old ones.
+//----------------------------------------------------------------------
+class ClangExpressionDeclMap :
+ public ClangASTSource
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variables.
+ ///
+ /// @param[in] keep_result_in_memory
+ /// If true, inhibits the normal deallocation of the memory for
+ /// the result persistent variable, and instead marks the variable
+ /// as persisting.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when parsing.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap (bool keep_result_in_memory,
+ ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~ClangExpressionDeclMap ();
+
+ //------------------------------------------------------------------
+ /// Enable the state needed for parsing and IR transformation.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when finding types for variables.
+ /// Also used to find a "scratch" AST context to store result types.
+ ///
+ /// @param[in] materializer
+ /// If non-NULL, the materializer to populate with information about
+ /// the variables to use
+ ///
+ /// @return
+ /// True if parsing is possible; false if it is unsafe to continue.
+ //------------------------------------------------------------------
+ bool
+ WillParse (ExecutionContext &exe_ctx,
+ Materializer *materializer);
+
+ //------------------------------------------------------------------
+ /// [Used by ClangExpressionParser] For each variable that had an unknown
+ /// type at the beginning of parsing, determine its final type now.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveUnknownTypes();
+
+ //------------------------------------------------------------------
+ /// Disable the state needed for parsing and IR transformation.
+ //------------------------------------------------------------------
+ void
+ DidParse ();
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Add a variable to the list of persistent
+ /// variables for the process.
+ ///
+ /// @param[in] decl
+ /// The Clang declaration for the persistent variable, used for
+ /// lookup during parsing.
+ ///
+ /// @param[in] name
+ /// The name of the persistent variable, usually $something.
+ ///
+ /// @param[in] type
+ /// The type of the variable, in the Clang parser's context.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ AddPersistentVariable (const clang::NamedDecl *decl,
+ const ConstString &name,
+ TypeFromParser type,
+ bool is_result,
+ bool is_lvalue);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Add a variable to the struct that needs to
+ /// be materialized each time the expression runs.
+ ///
+ /// @param[in] decl
+ /// The Clang declaration for the variable.
+ ///
+ /// @param[in] name
+ /// The name of the variable.
+ ///
+ /// @param[in] value
+ /// The LLVM IR value for this variable.
+ ///
+ /// @param[in] size
+ /// The size of the variable in bytes.
+ ///
+ /// @param[in] alignment
+ /// The required alignment of the variable in bytes.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ AddValueToStruct (const clang::NamedDecl *decl,
+ const ConstString &name,
+ llvm::Value *value,
+ size_t size,
+ off_t alignment);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Finalize the struct, laying out the position
+ /// of each object in it.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ DoStructLayout ();
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Get general information about the laid-out
+ /// struct after DoStructLayout() has been called.
+ ///
+ /// @param[out] num_elements
+ /// The number of elements in the struct.
+ ///
+ /// @param[out] size
+ /// The size of the struct, in bytes.
+ ///
+ /// @param[out] alignment
+ /// The alignment of the struct, in bytes.
+ ///
+ /// @return
+ /// True if the information could be retrieved; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetStructInfo (uint32_t &num_elements,
+ size_t &size,
+ off_t &alignment);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Get specific information about one field
+ /// of the laid-out struct after DoStructLayout() has been called.
+ ///
+ /// @param[out] decl
+ /// The parsed Decl for the field, as generated by ClangASTSource
+ /// on ClangExpressionDeclMap's behalf. In the case of the result
+ /// value, this will have the name $__lldb_result even if the
+ /// result value ends up having the name $1. This is an
+ /// implementation detail of IRForTarget.
+ ///
+ /// @param[out] value
+ /// The IR value for the field (usually a GlobalVariable). In
+ /// the case of the result value, this will have the correct
+ /// name ($1, for instance). This is an implementation detail
+ /// of IRForTarget.
+ ///
+ /// @param[out] offset
+ /// The offset of the field from the beginning of the struct.
+ /// As long as the struct is aligned according to its required
+ /// alignment, this offset will align the field correctly.
+ ///
+ /// @param[out] name
+ /// The name of the field as used in materialization.
+ ///
+ /// @param[in] index
+ /// The index of the field about which information is requested.
+ ///
+ /// @return
+ /// True if the information could be retrieved; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetStructElement (const clang::NamedDecl *&decl,
+ llvm::Value *&value,
+ off_t &offset,
+ ConstString &name,
+ uint32_t index);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Get information about a function given its
+ /// Decl.
+ ///
+ /// @param[in] decl
+ /// The parsed Decl for the Function, as generated by ClangASTSource
+ /// on ClangExpressionDeclMap's behalf.
+ ///
+ /// @param[out] ptr
+ /// The absolute address of the function in the target.
+ ///
+ /// @return
+ /// True if the information could be retrieved; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetFunctionInfo (const clang::NamedDecl *decl,
+ uint64_t &ptr);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Get the address of a function given nothing
+ /// but its name. Some functions are needed but didn't get Decls made
+ /// during parsing -- specifically, sel_registerName is never called
+ /// in the generated IR but we need to call it nonetheless.
+ ///
+ /// @param[in] name
+ /// The name of the function.
+ ///
+ /// @param[out] ptr
+ /// The absolute address of the function in the target.
+ ///
+ /// @return
+ /// True if the address could be retrieved; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetFunctionAddress (const ConstString &name,
+ uint64_t &ptr);
+
+ //------------------------------------------------------------------
+ /// [Used by IRForTarget] Get the address of a symbol given nothing
+ /// but its name.
+ ///
+ /// @param[in] target
+ /// The target to find the symbol in. If not provided,
+ /// then the current parsing context's Target.
+ ///
+ /// @param[in] process
+ /// The process to use. For Objective-C symbols, the process's
+ /// Objective-C language runtime may be queried if the process
+ /// is non-NULL.
+ ///
+ /// @param[in] name
+ /// The name of the symbol.
+ ///
+ /// @return
+ /// Valid load address for the symbol
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetSymbolAddress (Target &target,
+ Process *process,
+ const ConstString &name,
+ lldb::SymbolType symbol_type);
+
+ lldb::addr_t
+ GetSymbolAddress (const ConstString &name,
+ lldb::SymbolType symbol_type);
+
+ //------------------------------------------------------------------
+ /// [Used by IRInterpreter] Get basic target information.
+ ///
+ /// @param[out] byte_order
+ /// The byte order of the target.
+ ///
+ /// @param[out] address_byte_size
+ /// The size of a pointer in bytes.
+ ///
+ /// @return
+ /// True if the information could be determined; false
+ /// otherwise.
+ //------------------------------------------------------------------
+ struct TargetInfo
+ {
+ lldb::ByteOrder byte_order;
+ size_t address_byte_size;
+
+ TargetInfo() :
+ byte_order(lldb::eByteOrderInvalid),
+ address_byte_size(0)
+ {
+ }
+
+ bool IsValid()
+ {
+ return (byte_order != lldb::eByteOrderInvalid &&
+ address_byte_size != 0);
+ }
+ };
+ TargetInfo GetTargetInfo();
+
+ //------------------------------------------------------------------
+ /// [Used by ClangASTSource] Find all entities matching a given name,
+ /// using a NameSearchContext to make Decls for them.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls (NameSearchContext &context);
+
+ //------------------------------------------------------------------
+ /// Find all entities matching a given name in a given module/namespace,
+ /// using a NameSearchContext to make Decls for them.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext that can construct Decls for this name.
+ ///
+ /// @param[in] module
+ /// If non-NULL, the module to query.
+ ///
+ /// @param[in] namespace_decl
+ /// If valid and module is non-NULL, the parent namespace.
+ ///
+ /// @param[in] name
+ /// The name as a plain C string. The NameSearchContext contains
+ /// a DeclarationName for the name so at first the name may seem
+ /// redundant, but ClangExpressionDeclMap operates in RTTI land so
+ /// it can't access DeclarationName.
+ ///
+ /// @param[in] current_id
+ /// The ID for the current FindExternalVisibleDecls invocation,
+ /// for logging purposes.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ void
+ FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module,
+ ClangNamespaceDecl &namespace_decl,
+ unsigned int current_id);
+private:
+ ClangExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser.
+ ClangExpressionVariableList m_struct_members; ///< All entities that need to be placed in the struct.
+ bool m_keep_result_in_memory; ///< True if result persistent variables generated by this expression should stay in memory.
+
+ //----------------------------------------------------------------------
+ /// The following values should not live beyond parsing
+ //----------------------------------------------------------------------
+ class ParserVars
+ {
+ public:
+ ParserVars(ClangExpressionDeclMap &decl_map) :
+ m_exe_ctx(),
+ m_sym_ctx(),
+ m_persistent_vars(NULL),
+ m_enable_lookups(false),
+ m_materializer(NULL),
+ m_decl_map(decl_map)
+ {
+ }
+
+ Target *
+ GetTarget()
+ {
+ if (m_exe_ctx.GetTargetPtr())
+ return m_exe_ctx.GetTargetPtr();
+ else if (m_sym_ctx.target_sp)
+ m_sym_ctx.target_sp.get();
+ return NULL;
+ }
+
+ ExecutionContext m_exe_ctx; ///< The execution context to use when parsing.
+ SymbolContext m_sym_ctx; ///< The symbol context to use in finding variables and types.
+ ClangPersistentVariables *m_persistent_vars; ///< The persistent variables for the process.
+ bool m_enable_lookups; ///< Set to true during parsing if we have found the first "$__lldb" name.
+ TargetInfo m_target_info; ///< Basic information about the target.
+ Materializer *m_materializer; ///< If non-NULL, the materializer to use when reporting used variables.
+ private:
+ ClangExpressionDeclMap &m_decl_map;
+ DISALLOW_COPY_AND_ASSIGN (ParserVars);
+ };
+
+ std::unique_ptr<ParserVars> m_parser_vars;
+
+ //----------------------------------------------------------------------
+ /// Activate parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ EnableParserVars()
+ {
+ if (!m_parser_vars.get())
+ m_parser_vars.reset(new ParserVars(*this));
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ DisableParserVars()
+ {
+ m_parser_vars.reset();
+ }
+
+ //----------------------------------------------------------------------
+ /// The following values contain layout information for the materialized
+ /// struct, but are not specific to a single materialization
+ //----------------------------------------------------------------------
+ struct StructVars {
+ StructVars() :
+ m_struct_alignment(0),
+ m_struct_size(0),
+ m_struct_laid_out(false),
+ m_result_name(),
+ m_object_pointer_type(NULL, NULL)
+ {
+ }
+
+ off_t m_struct_alignment; ///< The alignment of the struct in bytes.
+ size_t m_struct_size; ///< The size of the struct in bytes.
+ bool m_struct_laid_out; ///< True if the struct has been laid out and the layout is valid (that is, no new fields have been added since).
+ ConstString m_result_name; ///< The name of the result variable ($1, for example)
+ TypeFromUser m_object_pointer_type; ///< The type of the "this" variable, if one exists
+ };
+
+ std::unique_ptr<StructVars> m_struct_vars;
+
+ //----------------------------------------------------------------------
+ /// Activate struct variables
+ //----------------------------------------------------------------------
+ void
+ EnableStructVars()
+ {
+ if (!m_struct_vars.get())
+ m_struct_vars.reset(new struct StructVars);
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate struct variables
+ //----------------------------------------------------------------------
+ void
+ DisableStructVars()
+ {
+ m_struct_vars.reset();
+ }
+
+ //----------------------------------------------------------------------
+ /// Get this parser's ID for use in extracting parser- and JIT-specific
+ /// data from persistent variables.
+ //----------------------------------------------------------------------
+ uint64_t
+ GetParserID()
+ {
+ return (uint64_t)this;
+ }
+
+ //------------------------------------------------------------------
+ /// Given a target, find a data symbol that has the given name.
+ ///
+ /// @param[in] target
+ /// The target to use as the basis for the search.
+ ///
+ /// @param[in] name
+ /// The name as a plain C string.
+ ///
+ /// @return
+ /// The LLDB Symbol found, or NULL if none was found.
+ //---------------------------------------------------------
+ const Symbol *
+ FindGlobalDataSymbol (Target &target,
+ const ConstString &name);
+
+ //------------------------------------------------------------------
+ /// Given a target, find a variable that matches the given name and
+ /// type.
+ ///
+ /// @param[in] target
+ /// The target to use as a basis for finding the variable.
+ ///
+ /// @param[in] module
+ /// If non-NULL, the module to search.
+ ///
+ /// @param[in] name
+ /// The name as a plain C string.
+ ///
+ /// @param[in] namespace_decl
+ /// If non-NULL and module is non-NULL, the parent namespace.
+ ///
+ /// @param[in] type
+ /// The required type for the variable. This function may be called
+ /// during parsing, in which case we don't know its type; hence the
+ /// default.
+ ///
+ /// @return
+ /// The LLDB Variable found, or NULL if none was found.
+ //------------------------------------------------------------------
+ lldb::VariableSP
+ FindGlobalVariable (Target &target,
+ lldb::ModuleSP &module,
+ const ConstString &name,
+ ClangNamespaceDecl *namespace_decl,
+ TypeFromUser *type = NULL);
+
+ //------------------------------------------------------------------
+ /// Get the value of a variable in a given execution context and return
+ /// the associated Types if needed.
+ ///
+ /// @param[in] var
+ /// The variable to evaluate.
+ ///
+ /// @param[out] var_location
+ /// The variable location value to fill in
+ ///
+ /// @param[out] found_type
+ /// The type of the found value, as it was found in the user process.
+ /// This is only useful when the variable is being inspected on behalf
+ /// of the parser, hence the default.
+ ///
+ /// @param[out] parser_type
+ /// The type of the found value, as it was copied into the parser's
+ /// AST context. This is only useful when the variable is being
+ /// inspected on behalf of the parser, hence the default.
+ ///
+ /// @param[in] decl
+ /// The Decl to be looked up.
+ ///
+ /// @return
+ /// Return true if the value was successfully filled in.
+ //------------------------------------------------------------------
+ bool
+ GetVariableValue (lldb::VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *found_type = NULL,
+ TypeFromParser *parser_type = NULL);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// Variable, and put it in the Tuple list.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] var
+ /// The LLDB Variable that needs a Decl.
+ ///
+ /// @param[in] valobj
+ /// The LLDB ValueObject for that variable.
+ //------------------------------------------------------------------
+ void
+ AddOneVariable (NameSearchContext &context,
+ lldb::VariableSP var,
+ lldb::ValueObjectSP valobj,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// persistent variable, and put it in the list of found entities.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] pvar
+ /// The persistent variable that needs a Decl.
+ ///
+ /// @param[in] current_id
+ /// The ID of the current invocation of FindExternalVisibleDecls
+ /// for logging purposes.
+ //------------------------------------------------------------------
+ void
+ AddOneVariable (NameSearchContext &context,
+ lldb::ClangExpressionVariableSP &pvar_sp,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given LLDB
+ /// symbol (treated as a variable), and put it in the list of found
+ /// entities.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] var
+ /// The LLDB Variable that needs a Decl.
+ //------------------------------------------------------------------
+ void
+ AddOneGenericVariable (NameSearchContext &context,
+ const Symbol &symbol,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// function. (Functions are not placed in the Tuple list.) Can
+ /// handle both fully typed functions and generic functions.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] fun
+ /// The Function that needs to be created. If non-NULL, this is
+ /// a fully-typed function.
+ ///
+ /// @param[in] sym
+ /// The Symbol that corresponds to a function that needs to be
+ /// created with generic type (unitptr_t foo(...)).
+ //------------------------------------------------------------------
+ void
+ AddOneFunction (NameSearchContext &context,
+ Function *fun,
+ Symbol *sym,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// register.
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] reg_info
+ /// The information corresponding to that register.
+ //------------------------------------------------------------------
+ void
+ AddOneRegister (NameSearchContext &context,
+ const RegisterInfo *reg_info,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Use the NameSearchContext to generate a Decl for the given
+ /// type. (Types are not placed in the Tuple list.)
+ ///
+ /// @param[in] context
+ /// The NameSearchContext to use when constructing the Decl.
+ ///
+ /// @param[in] type
+ /// The type that needs to be created.
+ //------------------------------------------------------------------
+ void
+ AddOneType (NameSearchContext &context,
+ TypeFromUser &type,
+ unsigned int current_id);
+
+ //------------------------------------------------------------------
+ /// Copy a C++ class type into the parser's AST context and add a
+ /// member function declaration to it for the expression.
+ ///
+ /// @param[in] type
+ /// The type that needs to be created.
+ //------------------------------------------------------------------
+
+ TypeFromParser
+ CopyClassType(TypeFromUser &type,
+ unsigned int current_id);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionDeclMap_h_
diff --git a/include/lldb/Expression/ClangExpressionParser.h b/include/lldb/Expression/ClangExpressionParser.h
new file mode 100644
index 000000000000..3247f2094ba6
--- /dev/null
+++ b/include/lldb/Expression/ClangExpressionParser.h
@@ -0,0 +1,151 @@
+//===-- ClangExpressionParser.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_ClangExpressionParser_h_
+#define liblldb_ClangExpressionParser_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/IRForTarget.h"
+
+#include <string>
+#include <vector>
+
+namespace lldb_private
+{
+
+class IRExecutionUnit;
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionParser ClangExpressionParser.h "lldb/Expression/ClangExpressionParser.h"
+/// @brief Encapsulates an instance of Clang that can parse expressions.
+///
+/// ClangExpressionParser is responsible for preparing an instance of
+/// ClangExpression for execution. ClangExpressionParser uses ClangExpression
+/// as a glorified parameter list, performing the required parsing and
+/// conversion to formats (DWARF bytecode, or JIT compiled machine code)
+/// that can be executed.
+//----------------------------------------------------------------------
+class ClangExpressionParser
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variabes.
+ ///
+ /// @param[in] exe_scope,
+ /// If non-NULL, an execution context scope that can help to
+ /// correctly create an expression with a valid process for
+ /// optional tuning Objective-C runtime support. Can be NULL.
+ ///
+ /// @param[in] expr
+ /// The expression to be parsed.
+ //------------------------------------------------------------------
+ ClangExpressionParser (ExecutionContextScope *exe_scope,
+ ClangExpression &expr);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~ClangExpressionParser ();
+
+ //------------------------------------------------------------------
+ /// Parse a single expression and convert it to IR using Clang. Don't
+ /// wrap the expression in anything at all.
+ ///
+ /// @param[in] stream
+ /// The stream to print errors to.
+ ///
+ /// @return
+ /// The number of errors encountered during parsing. 0 means
+ /// success.
+ //------------------------------------------------------------------
+ unsigned
+ Parse (Stream &stream);
+
+ //------------------------------------------------------------------
+ /// Ready an already-parsed expression for execution, possibly
+ /// evaluating it statically.
+ ///
+ /// @param[out] func_addr
+ /// The address to which the function has been written.
+ ///
+ /// @param[out] func_end
+ /// The end of the function's allocated memory region. (func_addr
+ /// and func_end do not delimit an allocated region; the allocated
+ /// region may begin before func_addr.)
+ ///
+ /// @param[in] execution_unit_ap
+ /// After parsing, ownership of the execution unit for
+ /// for the expression is handed to this unique pointer.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to write the function into.
+ ///
+ /// @param[out] evaluated_statically
+ /// Set to true if the expression could be interpreted statically;
+ /// untouched otherwise.
+ ///
+ /// @param[out] const_result
+ /// If the result of the expression is constant, and the
+ /// expression has no side effects, this is set to the result of the
+ /// expression.
+ ///
+ /// @param[in] execution_policy
+ /// Determines whether the expression must be JIT-compiled, must be
+ /// evaluated statically, or whether this decision may be made
+ /// opportunistically.
+ ///
+ /// @return
+ /// An error code indicating the success or failure of the operation.
+ /// Test with Success().
+ //------------------------------------------------------------------
+ Error
+ PrepareForExecution (lldb::addr_t &func_addr,
+ lldb::addr_t &func_end,
+ std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
+ ExecutionContext &exe_ctx,
+ bool &can_interpret,
+ lldb_private::ExecutionPolicy execution_policy);
+
+ //------------------------------------------------------------------
+ /// Disassemble the machine code for a JITted function from the target
+ /// process's memory and print the result to a stream.
+ ///
+ /// @param[in] stream
+ /// The stream to print disassembly to.
+ ///
+ /// @param[in] exc_context
+ /// The execution context to get the machine code from.
+ ///
+ /// @return
+ /// The error generated. If .Success() is true, disassembly succeeded.
+ //------------------------------------------------------------------
+ Error
+ DisassembleFunction (Stream &stream,
+ ExecutionContext &exe_ctx);
+
+private:
+ ClangExpression & m_expr; ///< The expression to be parsed
+ std::unique_ptr<llvm::LLVMContext> m_llvm_context; ///< The LLVM context to generate IR into
+ std::unique_ptr<clang::FileManager> m_file_manager; ///< The Clang file manager object used by the compiler
+ std::unique_ptr<clang::CompilerInstance> m_compiler; ///< The Clang compiler used to parse expressions into IR
+ std::unique_ptr<clang::Builtin::Context> m_builtin_context; ///< Context for Clang built-ins
+ std::unique_ptr<clang::SelectorTable> m_selector_table; ///< Selector table for Objective-C methods
+ std::unique_ptr<clang::ASTContext> m_ast_context; ///< The AST context used to hold types and names for the parser
+ std::unique_ptr<clang::CodeGenerator> m_code_generator; ///< The Clang object that generates IR
+ std::unique_ptr<IRExecutionUnit> m_execution_unit; ///< The container for the finished Module
+};
+
+}
+
+#endif // liblldb_ClangExpressionParser_h_
diff --git a/include/lldb/Expression/ClangExpressionVariable.h b/include/lldb/Expression/ClangExpressionVariable.h
new file mode 100644
index 000000000000..620e604fb18c
--- /dev/null
+++ b/include/lldb/Expression/ClangExpressionVariable.h
@@ -0,0 +1,451 @@
+//===-- ClangExpressionVariable.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_ClangExpressionVariable_h_
+#define liblldb_ClangExpressionVariable_h_
+
+// C Includes
+#include <signal.h>
+#include <stdint.h>
+#include <string.h>
+
+// C++ Includes
+#include <map>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/TaggedASTType.h"
+
+namespace llvm {
+ class Value;
+}
+
+namespace lldb_private {
+
+class ClangExpressionVariableList;
+class ValueObjectConstResult;
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionVariable ClangExpressionVariable.h "lldb/Expression/ClangExpressionVariable.h"
+/// @brief Encapsulates one variable for the expression parser.
+///
+/// The expression parser uses variables in three different contexts:
+///
+/// First, it stores persistent variables along with the process for use
+/// in expressions. These persistent variables contain their own data
+/// and are typed.
+///
+/// Second, in an interpreted expression, it stores the local variables
+/// for the expression along with the expression. These variables
+/// contain their own data and are typed.
+///
+/// Third, in a JIT-compiled expression, it stores the variables that
+/// the expression needs to have materialized and dematerialized at each
+/// execution. These do not contain their own data but are named and
+/// typed.
+///
+/// This class supports all of these use cases using simple type
+/// polymorphism, and provides necessary support methods. Its interface
+/// is RTTI-neutral.
+//----------------------------------------------------------------------
+class ClangExpressionVariable
+{
+public:
+ ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size);
+
+ ClangExpressionVariable(const lldb::ValueObjectSP &valobj_sp);
+
+ //----------------------------------------------------------------------
+ /// If the variable contains its own data, make a Value point at it.
+ /// If \a exe_ctx in not NULL, the value will be resolved in with
+ /// that execution context.
+ ///
+ /// @param[in] value
+ /// The value to point at the data.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use to resolve \a value.
+ ///
+ /// @return
+ /// True on success; false otherwise (in particular, if this variable
+ /// does not contain its own data).
+ //----------------------------------------------------------------------
+ bool
+ PointValueAtData(Value &value, ExecutionContext *exe_ctx);
+
+ lldb::ValueObjectSP
+ GetValueObject();
+
+ //----------------------------------------------------------------------
+ /// The following values should not live beyond parsing
+ //----------------------------------------------------------------------
+ class ParserVars
+ {
+ public:
+
+ ParserVars() :
+ m_parser_type(),
+ m_named_decl (NULL),
+ m_llvm_value (NULL),
+ m_lldb_value (),
+ m_lldb_var (),
+ m_lldb_sym (NULL)
+ {
+ }
+
+ TypeFromParser m_parser_type; ///< The type of the variable according to the parser
+ const clang::NamedDecl *m_named_decl; ///< The Decl corresponding to this variable
+ llvm::Value *m_llvm_value; ///< The IR value corresponding to this variable; usually a GlobalValue
+ lldb_private::Value m_lldb_value; ///< The value found in LLDB for this variable
+ lldb::VariableSP m_lldb_var; ///< The original variable for this variable
+ const lldb_private::Symbol *m_lldb_sym; ///< The original symbol for this variable, if it was a symbol
+ };
+
+private:
+ typedef std::map <uint64_t, ParserVars> ParserVarMap;
+ ParserVarMap m_parser_vars;
+
+public:
+ //----------------------------------------------------------------------
+ /// Make this variable usable by the parser by allocating space for
+ /// parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ EnableParserVars(uint64_t parser_id)
+ {
+ m_parser_vars.insert(std::make_pair(parser_id, ParserVars()));
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate parser-specific variables
+ //----------------------------------------------------------------------
+ void
+ DisableParserVars(uint64_t parser_id)
+ {
+ m_parser_vars.erase(parser_id);
+ }
+
+ //----------------------------------------------------------------------
+ /// Access parser-specific variables
+ //----------------------------------------------------------------------
+ ParserVars *
+ GetParserVars(uint64_t parser_id)
+ {
+ ParserVarMap::iterator i = m_parser_vars.find(parser_id);
+
+ if (i == m_parser_vars.end())
+ return NULL;
+ else
+ return &i->second;
+ }
+
+ //----------------------------------------------------------------------
+ /// The following values are valid if the variable is used by JIT code
+ //----------------------------------------------------------------------
+ struct JITVars {
+ JITVars () :
+ m_alignment (0),
+ m_size (0),
+ m_offset (0)
+ {
+ }
+
+ off_t m_alignment; ///< The required alignment of the variable, in bytes
+ size_t m_size; ///< The space required for the variable, in bytes
+ off_t m_offset; ///< The offset of the variable in the struct, in bytes
+ };
+
+private:
+ typedef std::map <uint64_t, JITVars> JITVarMap;
+ JITVarMap m_jit_vars;
+
+public:
+ //----------------------------------------------------------------------
+ /// Make this variable usable for materializing for the JIT by allocating
+ /// space for JIT-specific variables
+ //----------------------------------------------------------------------
+ void
+ EnableJITVars(uint64_t parser_id)
+ {
+ m_jit_vars.insert(std::make_pair(parser_id, JITVars()));
+ }
+
+ //----------------------------------------------------------------------
+ /// Deallocate JIT-specific variables
+ //----------------------------------------------------------------------
+ void
+ DisableJITVars(uint64_t parser_id)
+ {
+ m_jit_vars.erase(parser_id);
+ }
+
+ JITVars *GetJITVars(uint64_t parser_id)
+ {
+ JITVarMap::iterator i = m_jit_vars.find(parser_id);
+
+ if (i == m_jit_vars.end())
+ return NULL;
+ else
+ return &i->second;
+ }
+
+ //----------------------------------------------------------------------
+ /// Return the variable's size in bytes
+ //----------------------------------------------------------------------
+ size_t
+ GetByteSize ();
+
+ const ConstString &
+ GetName();
+
+ RegisterInfo *
+ GetRegisterInfo();
+
+ void
+ SetRegisterInfo (const RegisterInfo *reg_info);
+
+ ClangASTType
+ GetClangType ();
+
+ void
+ SetClangType (const ClangASTType &clang_type);
+
+ TypeFromUser
+ GetTypeFromUser ();
+
+ uint8_t *
+ GetValueBytes ();
+
+ void
+ SetName (const ConstString &name);
+
+ void
+ ValueUpdated ();
+
+ // this function is used to copy the address-of m_live_sp into m_frozen_sp
+ // this is necessary because the results of certain cast and pointer-arithmetic
+ // operations (such as those described in bugzilla issues 11588 and 11618) generate
+ // frozen objcts that do not have a valid address-of, which can be troublesome when
+ // using synthetic children providers. transferring the address-of the live object
+ // solves these issues and provides the expected user-level behavior
+ void
+ TransferAddress (bool force = false);
+
+ typedef std::shared_ptr<ValueObjectConstResult> ValueObjectConstResultSP;
+
+ //----------------------------------------------------------------------
+ /// Members
+ //----------------------------------------------------------------------
+ enum Flags
+ {
+ EVNone = 0,
+ EVIsLLDBAllocated = 1 << 0, ///< This variable is resident in a location specifically allocated for it by LLDB in the target process
+ EVIsProgramReference = 1 << 1, ///< This variable is a reference to a (possibly invalid) area managed by the target program
+ EVNeedsAllocation = 1 << 2, ///< Space for this variable has yet to be allocated in the target process
+ EVIsFreezeDried = 1 << 3, ///< This variable's authoritative version is in m_frozen_sp (for example, for statically-computed results)
+ EVNeedsFreezeDry = 1 << 4, ///< Copy from m_live_sp to m_frozen_sp during dematerialization
+ EVKeepInTarget = 1 << 5, ///< Keep the allocation after the expression is complete rather than freeze drying its contents and freeing it
+ EVTypeIsReference = 1 << 6, ///< The original type of this variable is a reference, so materialize the value rather than the location
+ EVUnknownType = 1 << 7, ///< This is a symbol of unknown type, and the type must be resolved after parsing is complete
+ EVBareRegister = 1 << 8 ///< This variable is a direct reference to $pc or some other entity.
+ };
+
+ typedef uint16_t FlagType;
+
+ FlagType m_flags; // takes elements of Flags
+
+ lldb::ValueObjectSP m_frozen_sp;
+ lldb::ValueObjectSP m_live_sp;
+
+ DISALLOW_COPY_AND_ASSIGN (ClangExpressionVariable);
+};
+
+//----------------------------------------------------------------------
+/// @class ClangExpressionVariableListBase ClangExpressionVariable.h "lldb/Expression/ClangExpressionVariable.h"
+/// @brief A list of variable references.
+///
+/// This class stores variables internally, acting as the permanent store.
+//----------------------------------------------------------------------
+class ClangExpressionVariableList
+{
+public:
+ //----------------------------------------------------------------------
+ /// Implementation of methods in ClangExpressionVariableListBase
+ //----------------------------------------------------------------------
+ size_t
+ GetSize()
+ {
+ return m_variables.size();
+ }
+
+ lldb::ClangExpressionVariableSP
+ GetVariableAtIndex(size_t index)
+ {
+ lldb::ClangExpressionVariableSP var_sp;
+ if (index < m_variables.size())
+ var_sp = m_variables[index];
+ return var_sp;
+ }
+
+ size_t
+ AddVariable (const lldb::ClangExpressionVariableSP &var_sp)
+ {
+ m_variables.push_back(var_sp);
+ return m_variables.size() - 1;
+ }
+
+ bool
+ ContainsVariable (const lldb::ClangExpressionVariableSP &var_sp)
+ {
+ const size_t size = m_variables.size();
+ for (size_t index = 0; index < size; ++index)
+ {
+ if (m_variables[index].get() == var_sp.get())
+ return true;
+ }
+ return false;
+ }
+
+ //----------------------------------------------------------------------
+ /// Finds a variable by name in the list.
+ ///
+ /// @param[in] name
+ /// The name of the requested variable.
+ ///
+ /// @return
+ /// The variable requested, or NULL if that variable is not in the list.
+ //----------------------------------------------------------------------
+ lldb::ClangExpressionVariableSP
+ GetVariable (const ConstString &name)
+ {
+ lldb::ClangExpressionVariableSP var_sp;
+ for (size_t index = 0, size = GetSize(); index < size; ++index)
+ {
+ var_sp = GetVariableAtIndex(index);
+ if (var_sp->GetName() == name)
+ return var_sp;
+ }
+ var_sp.reset();
+ return var_sp;
+ }
+
+ lldb::ClangExpressionVariableSP
+ GetVariable (const char *name)
+ {
+ lldb::ClangExpressionVariableSP var_sp;
+ if (name && name[0])
+ {
+ for (size_t index = 0, size = GetSize(); index < size; ++index)
+ {
+ var_sp = GetVariableAtIndex(index);
+ const char *var_name_cstr = var_sp->GetName().GetCString();
+ if (!var_name_cstr || !name)
+ continue;
+ if (::strcmp (var_name_cstr, name) == 0)
+ return var_sp;
+ }
+ var_sp.reset();
+ }
+ return var_sp;
+ }
+
+ //----------------------------------------------------------------------
+ /// Finds a variable by NamedDecl in the list.
+ ///
+ /// @param[in] name
+ /// The name of the requested variable.
+ ///
+ /// @return
+ /// The variable requested, or NULL if that variable is not in the list.
+ //----------------------------------------------------------------------
+ lldb::ClangExpressionVariableSP
+ GetVariable (const clang::NamedDecl *decl, uint64_t parser_id)
+ {
+ lldb::ClangExpressionVariableSP var_sp;
+ for (size_t index = 0, size = GetSize(); index < size; ++index)
+ {
+ var_sp = GetVariableAtIndex(index);
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(parser_id);
+
+ if (parser_vars && parser_vars->m_named_decl == decl)
+ return var_sp;
+ }
+ var_sp.reset();
+ return var_sp;
+ }
+
+ //----------------------------------------------------------------------
+ /// Create a new variable in the list and return its index
+ //----------------------------------------------------------------------
+ lldb::ClangExpressionVariableSP
+ CreateVariable (ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size)
+ {
+ lldb::ClangExpressionVariableSP var_sp(new ClangExpressionVariable(exe_scope, byte_order, addr_byte_size));
+ m_variables.push_back(var_sp);
+ return var_sp;
+ }
+
+ lldb::ClangExpressionVariableSP
+ CreateVariable(const lldb::ValueObjectSP &valobj_sp)
+ {
+ lldb::ClangExpressionVariableSP var_sp(new ClangExpressionVariable(valobj_sp));
+ m_variables.push_back(var_sp);
+ return var_sp;
+ }
+
+ lldb::ClangExpressionVariableSP
+ CreateVariable (ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size)
+ {
+ lldb::ClangExpressionVariableSP var_sp(new ClangExpressionVariable(exe_scope, byte_order, addr_byte_size));
+ var_sp->SetName (name);
+ var_sp->SetClangType (user_type);
+ m_variables.push_back(var_sp);
+ return var_sp;
+ }
+
+ void
+ RemoveVariable (lldb::ClangExpressionVariableSP var_sp)
+ {
+ for (std::vector<lldb::ClangExpressionVariableSP>::iterator vi = m_variables.begin(), ve = m_variables.end();
+ vi != ve;
+ ++vi)
+ {
+ if (vi->get() == var_sp.get())
+ {
+ m_variables.erase(vi);
+ return;
+ }
+ }
+ }
+
+ void
+ Clear()
+ {
+ m_variables.clear();
+ }
+
+private:
+ std::vector <lldb::ClangExpressionVariableSP> m_variables;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExpressionVariable_h_
diff --git a/include/lldb/Expression/ClangFunction.h b/include/lldb/Expression/ClangFunction.h
new file mode 100644
index 000000000000..3f96f7bd3117
--- /dev/null
+++ b/include/lldb/Expression/ClangFunction.h
@@ -0,0 +1,652 @@
+//===-- ClangFunction.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ClangFunction_h_
+#define lldb_ClangFunction_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+#include <list>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private
+{
+
+class ASTStructExtractor;
+class ClangExpressionParser;
+
+//----------------------------------------------------------------------
+/// @class ClangFunction ClangFunction.h "lldb/Expression/ClangFunction.h"
+/// @brief Encapsulates a function that can be called.
+///
+/// A given ClangFunction object can handle a single function signature.
+/// Once constructed, it can set up any number of concurrent calls to
+/// functions with that signature.
+///
+/// It performs the call by synthesizing a structure that contains the pointer
+/// to the function and the arguments that should be passed to that function,
+/// and producing a special-purpose JIT-compiled function that accepts a void*
+/// pointing to this struct as its only argument and calls the function in the
+/// struct with the written arguments. This method lets Clang handle the
+/// vagaries of function calling conventions.
+///
+/// The simplest use of the ClangFunction is to construct it with a
+/// function representative of the signature you want to use, then call
+/// ExecuteFunction(ExecutionContext &, Stream &, Value &).
+///
+/// If you need to reuse the arguments for several calls, you can call
+/// InsertFunction() followed by WriteFunctionArguments(), which will return
+/// the location of the args struct for the wrapper function in args_addr_ref.
+///
+/// If you need to call the function on the thread plan stack, you can also
+/// call InsertFunction() followed by GetThreadPlanToCallFunction().
+///
+/// Any of the methods that take arg_addr_ptr or arg_addr_ref can be passed
+/// a pointer set to LLDB_INVALID_ADDRESS and new structure will be allocated
+/// and its address returned in that variable.
+///
+/// Any of the methods that take arg_addr_ptr can be passed NULL, and the
+/// argument space will be managed for you.
+//----------------------------------------------------------------------
+class ClangFunction : public ClangExpression
+{
+ friend class ASTStructExtractor;
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] exe_scope
+ /// An execution context scope that gets us at least a target and
+ /// process.
+ ///
+ /// @param[in] function_ptr
+ /// The default function to be called. Can be overridden using
+ /// WriteFunctionArguments().
+ ///
+ /// @param[in] ast_context
+ /// The AST context to evaluate argument types in.
+ ///
+ /// @param[in] arg_value_list
+ /// The default values to use when calling this function. Can
+ /// be overridden using WriteFunctionArguments().
+ //------------------------------------------------------------------
+ ClangFunction (ExecutionContextScope &exe_scope,
+ Function &function_ptr,
+ ClangASTContext *ast_context,
+ const ValueList &arg_value_list);
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] exe_scope
+ /// An execution context scope that gets us at least a target and
+ /// process.
+ ///
+ /// @param[in] ast_context
+ /// The AST context to evaluate argument types in.
+ ///
+ /// @param[in] return_qualtype
+ /// An opaque Clang QualType for the function result. Should be
+ /// defined in ast_context.
+ ///
+ /// @param[in] function_address
+ /// The address of the function to call.
+ ///
+ /// @param[in] arg_value_list
+ /// The default values to use when calling this function. Can
+ /// be overridden using WriteFunctionArguments().
+ //------------------------------------------------------------------
+ ClangFunction (ExecutionContextScope &exe_scope,
+ const ClangASTType &return_type,
+ const Address& function_address,
+ const ValueList &arg_value_list);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual
+ ~ClangFunction();
+
+ //------------------------------------------------------------------
+ /// Compile the wrapper function
+ ///
+ /// @param[in] errors
+ /// The stream to print parser errors to.
+ ///
+ /// @return
+ /// The number of errors.
+ //------------------------------------------------------------------
+ unsigned
+ CompileFunction (Stream &errors);
+
+ //------------------------------------------------------------------
+ /// Insert the default function wrapper and its default argument struct
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in,out] args_addr_ref
+ /// The address of the structure to write the arguments into. May
+ /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated
+ /// and args_addr_ref is pointed to it.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ InsertFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Stream &errors);
+
+ //------------------------------------------------------------------
+ /// Insert the default function wrapper (using the JIT)
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool WriteFunctionWrapper (ExecutionContext &exe_ctx,
+ Stream &errors);
+
+ //------------------------------------------------------------------
+ /// Insert the default function argument struct
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in,out] args_addr_ref
+ /// The address of the structure to write the arguments into. May
+ /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated
+ /// and args_addr_ref is pointed to it.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool WriteFunctionArguments (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Stream &errors);
+
+ //------------------------------------------------------------------
+ /// Insert an argument struct with a non-default function address and
+ /// non-default argument values
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in,out] args_addr_ref
+ /// The address of the structure to write the arguments into. May
+ /// be LLDB_INVALID_ADDRESS; if it is, a new structure is allocated
+ /// and args_addr_ref is pointed to it.
+ ///
+ /// @param[in] function_address
+ /// The address of the function to call.
+ ///
+ /// @param[in] arg_values
+ /// The values of the function's arguments.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool WriteFunctionArguments (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Address function_address,
+ ValueList &arg_values,
+ Stream &errors);
+
+ //------------------------------------------------------------------
+ /// [Static] Execute a function, passing it a single void* parameter.
+ /// ClangFunction uses this to call the wrapper function.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in] function_address
+ /// The address of the function in the target process.
+ ///
+ /// @param[in] void_arg
+ /// The value of the void* parameter.
+ ///
+ /// @param[in] stop_others
+ /// True if other threads should pause during execution.
+ ///
+ /// @param[in] try_all_threads
+ /// If the timeout expires, true if other threads should run. If
+ /// the function may try to take locks, this is useful.
+ ///
+ /// @param[in] unwind_on_error
+ /// If true, and the execution stops before completion, we unwind the
+ /// function call, and return the program state to what it was before the
+ /// execution. If false, we leave the program in the stopped state.
+ ///
+ /// @param[in] timeout_usec
+ /// Timeout value (0 for no timeout). If try_all_threads is true, then we
+ /// will try on one thread for the lesser of .25 sec and half the total timeout.
+ /// then switch to running all threads, otherwise this will be the total timeout.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @param[in] this_arg
+ /// If non-NULL, the function is invoked like a C++ method, with the
+ /// value pointed to by the pointer as its 'this' argument.
+ ///
+ /// @return
+ /// Returns one of the ExecutionResults enum indicating function call status.
+ //------------------------------------------------------------------
+ static ExecutionResults
+ ExecuteFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t function_address,
+ lldb::addr_t &void_arg,
+ bool stop_others,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ uint32_t timeout_usec,
+ Stream &errors,
+ lldb::addr_t* this_arg = 0);
+
+ //------------------------------------------------------------------
+ /// Run the function this ClangFunction was created with.
+ ///
+ /// This simple version will run the function stopping other threads
+ /// for a fixed timeout period (1000 usec) and if it does not complete,
+ /// we halt the process and try with all threads running.
+ ///
+ /// @param[in] exe_ctx
+ /// The thread & process in which this function will run.
+ ///
+ /// @param[in] errors
+ /// Errors will be written here if there are any.
+ ///
+ /// @param[out] results
+ /// The result value will be put here after running the function.
+ ///
+ /// @return
+ /// Returns one of the ExecutionResults enum indicating function call status.
+ //------------------------------------------------------------------
+ ExecutionResults
+ ExecuteFunction(ExecutionContext &exe_ctx,
+ Stream &errors,
+ Value &results);
+
+ //------------------------------------------------------------------
+ /// Run the function this ClangFunction was created with.
+ ///
+ /// This simple version will run the function obeying the stop_others
+ /// argument. There is no timeout.
+ ///
+ /// @param[in] exe_ctx
+ /// The thread & process in which this function will run.
+ ///
+ /// @param[in] errors
+ /// Errors will be written here if there are any.
+ ///
+ /// @param[in] stop_others
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @param[out] results
+ /// The result value will be put here after running the function.
+ ///
+ /// @return
+ /// Returns one of the ExecutionResults enum indicating function call status.
+ //------------------------------------------------------------------
+ ExecutionResults
+ ExecuteFunction(ExecutionContext &exe_ctx,
+ Stream &errors, bool stop_others,
+ Value &results);
+
+ //------------------------------------------------------------------
+ /// Run the function this ClangFunction was created with.
+ ///
+ /// This simple version will run the function on one thread. If \a timeout_usec
+ /// is not zero, we time out after that timeout. If \a try_all_threads is true, then we will
+ /// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned.
+ ///
+ /// @param[in] exe_ctx
+ /// The thread & process in which this function will run.
+ ///
+ /// @param[in] errors
+ /// Errors will be written here if there are any.
+ ///
+ /// @param[in] timeout_usec
+ /// Timeout value (0 for no timeout). If try_all_threads is true, then we
+ /// will try on one thread for the lesser of .25 sec and half the total timeout.
+ /// then switch to running all threads, otherwise this will be the total timeout.
+ ///
+ /// @param[in] try_all_threads
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @param[out] results
+ /// The result value will be put here after running the function.
+ ///
+ /// @return
+ /// Returns one of the ExecutionResults enum indicating function call status.
+ //------------------------------------------------------------------
+ ExecutionResults
+ ExecuteFunction(ExecutionContext &exe_ctx,
+ Stream &errors,
+ uint32_t single_thread_timeout_usec,
+ bool try_all_threads,
+ Value &results);
+
+ //------------------------------------------------------------------
+ /// Run the function this ClangFunction was created with.
+ ///
+ /// This is the full version.
+ ///
+ /// @param[in] exe_ctx
+ /// The thread & process in which this function will run.
+ ///
+ /// @param[in] args_addr_ptr
+ /// If NULL, the function will take care of allocating & deallocating the wrapper
+ /// args structure. Otherwise, if set to LLDB_INVALID_ADDRESS, a new structure
+ /// will be allocated, filled and the address returned to you. You are responsible
+ /// for deallocating it. And if passed in with a value other than LLDB_INVALID_ADDRESS,
+ /// this should point to an already allocated structure with the values already written.
+ ///
+ /// @param[in] errors
+ /// Errors will be written here if there are any.
+ ///
+ /// @param[in] stop_others
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @param[in] timeout_usec
+ /// Timeout value (0 for no timeout). If try_all_threads is true, then we
+ /// will try on one thread for the lesser of .25 sec and half the total timeout.
+ /// then switch to running all threads, otherwise this will be the total timeout.
+ ///
+ ///
+ /// @param[in] try_all_threads
+ /// If \b true, run only this thread, if \b false let all threads run.
+ ///
+ /// @param[out] results
+ /// The result value will be put here after running the function.
+ ///
+ /// @return
+ /// Returns one of the ExecutionResults enum indicating function call status.
+ //------------------------------------------------------------------
+ ExecutionResults
+ ExecuteFunction(ExecutionContext &exe_ctx,
+ lldb::addr_t *args_addr_ptr,
+ Stream &errors,
+ bool stop_others,
+ uint32_t timeout_usec,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ Value &results);
+
+ //------------------------------------------------------------------
+ /// [static] Get a thread plan to run a function.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in] func_addr
+ /// The address of the function in the target process.
+ ///
+ /// @param[in] args_addr_ref
+ /// The value of the void* parameter.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @param[in] stop_others
+ /// True if other threads should pause during execution.
+ ///
+ /// @param[in] unwind_on_error
+ /// True if the thread plan may simply be discarded if an error occurs.
+ ///
+ /// @param[in] ignore_breakpoints
+ /// True if the expression execution will ignore breakpoint hits and continue executing.
+ ///
+ /// @param[in] this_arg
+ /// If non-NULL (and cmd_arg is NULL), the function is invoked like a C++
+ /// method, with the value pointed to by the pointer as its 'this'
+ /// argument.
+ ///
+ /// @param[in] cmd_arg
+ /// If non-NULL, the function is invoked like an Objective-C method, with
+ /// this_arg in the 'self' slot and cmd_arg in the '_cmd' slot
+ ///
+ /// @return
+ /// A ThreadPlan for executing the function.
+ //------------------------------------------------------------------
+ static ThreadPlan *
+ GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t func_addr,
+ lldb::addr_t &args_addr_ref,
+ Stream &errors,
+ bool stop_others,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *this_arg = 0,
+ lldb::addr_t *cmd_arg = 0);
+
+ //------------------------------------------------------------------
+ /// Get a thread plan to run the function this ClangFunction was created with.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in] func_addr
+ /// The address of the function in the target process.
+ ///
+ /// @param[in] args_addr_ref
+ /// The value of the void* parameter.
+ ///
+ /// @param[in] errors
+ /// The stream to write errors to.
+ ///
+ /// @param[in] stop_others
+ /// True if other threads should pause during execution.
+ ///
+ /// @param[in] unwind_on_error
+ /// True if the thread plan may simply be discarded if an error occurs.
+ ///
+ /// @return
+ /// A ThreadPlan for executing the function.
+ //------------------------------------------------------------------
+ ThreadPlan *
+ GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Stream &errors,
+ bool stop_others,
+ bool unwind_on_error = true,
+ bool ignore_breakpoints = true)
+ {
+ return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
+ m_jit_start_addr,
+ args_addr_ref,
+ errors,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints);
+ }
+
+ //------------------------------------------------------------------
+ /// Get the result of the function from its struct
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to retrieve the result from.
+ ///
+ /// @param[in] args_addr
+ /// The address of the argument struct.
+ ///
+ /// @param[in] ret_value
+ /// The value returned by the function.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool FetchFunctionResults (ExecutionContext &exe_ctx,
+ lldb::addr_t args_addr,
+ Value &ret_value);
+
+ //------------------------------------------------------------------
+ /// Deallocate the arguments structure
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to insert the function and its arguments
+ /// into.
+ ///
+ /// @param[in] args_addr
+ /// The address of the argument struct.
+ //------------------------------------------------------------------
+ void DeallocateFunctionResults (ExecutionContext &exe_ctx,
+ lldb::addr_t args_addr);
+
+ //------------------------------------------------------------------
+ /// Interface for ClangExpression
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Return the string that the parser should parse. Must be a full
+ /// translation unit.
+ //------------------------------------------------------------------
+ const char *
+ Text ()
+ {
+ return m_wrapper_function_text.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the function name that should be used for executing the
+ /// expression. Text() should contain the definition of this
+ /// function.
+ //------------------------------------------------------------------
+ const char *
+ FunctionName ()
+ {
+ return m_wrapper_function_name.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap ()
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when registering
+ /// local variables. May be NULL if the Expression doesn't care.
+ //------------------------------------------------------------------
+ ClangExpressionVariableList *
+ LocalVariables ()
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ clang::ASTConsumer *
+ ASTTransformer (clang::ASTConsumer *passthrough);
+
+ //------------------------------------------------------------------
+ /// Return true if validation code should be inserted into the
+ /// expression.
+ //------------------------------------------------------------------
+ bool
+ NeedsValidation ()
+ {
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Return true if external variables in the expression should be
+ /// resolved.
+ //------------------------------------------------------------------
+ bool
+ NeedsVariableResolution ()
+ {
+ return false;
+ }
+
+ ValueList
+ GetArgumentValues () const
+ {
+ return m_arg_values;
+ }
+private:
+ //------------------------------------------------------------------
+ // For ClangFunction only
+ //------------------------------------------------------------------
+
+ std::unique_ptr<ClangExpressionParser> m_parser; ///< The parser responsible for compiling the function.
+ std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
+
+ Function *m_function_ptr; ///< The function we're going to call. May be NULL if we don't have debug info for the function.
+ Address m_function_addr; ///< If we don't have the FunctionSP, we at least need the address & return type.
+ ClangASTType m_function_return_type; ///< The opaque clang qual type for the function return type.
+ ClangASTContext *m_clang_ast_context; ///< This is the clang_ast_context that we're getting types from the and value, and the function return the function pointer is NULL.
+
+ std::string m_wrapper_function_name; ///< The name of the wrapper function.
+ std::string m_wrapper_function_text; ///< The contents of the wrapper function.
+ std::string m_wrapper_struct_name; ///< The name of the struct that contains the target function address, arguments, and result.
+ std::list<lldb::addr_t> m_wrapper_args_addrs; ///< The addresses of the arguments to the wrapper function.
+
+ bool m_struct_valid; ///< True if the ASTStructExtractor has populated the variables below.
+
+ //------------------------------------------------------------------
+ /// These values are populated by the ASTStructExtractor
+ size_t m_struct_size; ///< The size of the argument struct, in bytes.
+ std::vector<uint64_t> m_member_offsets; ///< The offset of each member in the struct, in bytes.
+ uint64_t m_return_size; ///< The size of the result variable, in bytes.
+ uint64_t m_return_offset; ///< The offset of the result variable in the struct, in bytes.
+ //------------------------------------------------------------------
+
+ ValueList m_arg_values; ///< The default values of the arguments.
+
+ bool m_compiled; ///< True if the wrapper function has already been parsed.
+ bool m_JITted; ///< True if the wrapper function has already been JIT-compiled.
+};
+
+} // Namespace lldb_private
+
+#endif // lldb_ClangFunction_h_
diff --git a/include/lldb/Expression/ClangPersistentVariables.h b/include/lldb/Expression/ClangPersistentVariables.h
new file mode 100644
index 000000000000..6d9dae954734
--- /dev/null
+++ b/include/lldb/Expression/ClangPersistentVariables.h
@@ -0,0 +1,75 @@
+//===-- ClangPersistentVariables.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_ClangPersistentVariables_h_
+#define liblldb_ClangPersistentVariables_h_
+
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "llvm/ADT/DenseMap.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangPersistentVariables ClangPersistentVariables.h "lldb/Expression/ClangPersistentVariables.h"
+/// @brief Manages persistent values that need to be preserved between expression invocations.
+///
+/// A list of variables that can be accessed and updated by any expression. See
+/// ClangPersistentVariable for more discussion. Also provides an increasing,
+/// 0-based counter for naming result variables.
+//----------------------------------------------------------------------
+class ClangPersistentVariables : public ClangExpressionVariableList
+{
+public:
+
+ //----------------------------------------------------------------------
+ /// Constructor
+ //----------------------------------------------------------------------
+ ClangPersistentVariables ();
+
+ lldb::ClangExpressionVariableSP
+ CreatePersistentVariable (const lldb::ValueObjectSP &valobj_sp);
+
+ lldb::ClangExpressionVariableSP
+ CreatePersistentVariable (ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size);
+
+ //----------------------------------------------------------------------
+ /// Return the next entry in the sequence of strings "$0", "$1", ... for
+ /// use naming persistent expression convenience variables.
+ ///
+ /// @return
+ /// A string that contains the next persistent variable name.
+ //----------------------------------------------------------------------
+ ConstString
+ GetNextPersistentVariableName ();
+
+ void
+ RemovePersistentVariable (lldb::ClangExpressionVariableSP variable);
+
+ void
+ RegisterPersistentType (const ConstString &name,
+ clang::TypeDecl *tag_decl);
+
+ clang::TypeDecl *
+ GetPersistentType (const ConstString &name);
+
+private:
+ uint32_t m_next_persistent_variable_id; ///< The counter used by GetNextResultName().
+
+ typedef llvm::DenseMap<const char *, clang::TypeDecl *> PersistentTypeMap;
+ PersistentTypeMap m_persistent_types; ///< The persistent types declared by the user.
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/ClangUserExpression.h b/include/lldb/Expression/ClangUserExpression.h
new file mode 100644
index 000000000000..47bfebb46648
--- /dev/null
+++ b/include/lldb/Expression/ClangUserExpression.h
@@ -0,0 +1,432 @@
+//===-- ClangUserExpression.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_ClangUserExpression_h_
+#define liblldb_ClangUserExpression_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/IRForTarget.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Target/ExecutionContext.h"
+
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangUserExpression ClangUserExpression.h "lldb/Expression/ClangUserExpression.h"
+/// @brief Encapsulates a single expression for use with Clang
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// and as a backend for the expr command. ClangUserExpression encapsulates
+/// the objects needed to parse and interpret or JIT an expression. It
+/// uses the Clang parser to produce LLVM IR from the expression.
+//----------------------------------------------------------------------
+class ClangUserExpression : public ClangExpression
+{
+public:
+ typedef std::shared_ptr<ClangUserExpression> ClangUserExpressionSP;
+
+ enum { kDefaultTimeout = 500000u };
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] expr
+ /// The expression to parse.
+ ///
+ /// @param[in] expr_prefix
+ /// If non-NULL, a C string containing translation-unit level
+ /// definitions to be included when the expression is parsed.
+ ///
+ /// @param[in] language
+ /// If not eLanguageTypeUnknown, a language to use when parsing
+ /// the expression. Currently restricted to those languages
+ /// supported by Clang.
+ ///
+ /// @param[in] desired_type
+ /// If not eResultTypeAny, the type to use for the expression
+ /// result.
+ //------------------------------------------------------------------
+ ClangUserExpression (const char *expr,
+ const char *expr_prefix,
+ lldb::LanguageType language,
+ ResultType desired_type);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual
+ ~ClangUserExpression ();
+
+ //------------------------------------------------------------------
+ /// Parse the expression
+ ///
+ /// @param[in] error_stream
+ /// A stream to print parse errors and warnings to.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when looking up entities that
+ /// are needed for parsing (locations of functions, types of
+ /// variables, persistent variables, etc.)
+ ///
+ /// @param[in] execution_policy
+ /// Determines whether interpretation is possible or mandatory.
+ ///
+ /// @param[in] keep_result_in_memory
+ /// True if the resulting persistent variable should reside in
+ /// target memory, if applicable.
+ ///
+ /// @return
+ /// True on success (no errors); false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Parse (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory);
+
+ bool
+ CanInterpret ()
+ {
+ return m_can_interpret;
+ }
+
+ bool
+ MatchesContext (ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Execute the parsed expression
+ ///
+ /// @param[in] error_stream
+ /// A stream to print errors to.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when looking up entities that
+ /// are needed for parsing (locations of variables, etc.)
+ ///
+ /// @param[in] unwind_on_error
+ /// If true, and the execution stops before completion, we unwind the
+ /// function call, and return the program state to what it was before the
+ /// execution. If false, we leave the program in the stopped state.
+ ///
+ /// @param[in] ignore_breakpoints
+ /// If true, ignore breakpoints while executing the expression.
+ ///
+ /// @param[in] shared_ptr_to_me
+ /// This is a shared pointer to this ClangUserExpression. This is
+ /// needed because Execute can push a thread plan that will hold onto
+ /// the ClangUserExpression for an unbounded period of time. So you
+ /// need to give the thread plan a reference to this object that can
+ /// keep it alive.
+ ///
+ /// @param[in] result
+ /// A pointer to direct at the persistent variable in which the
+ /// expression's result is stored.
+ ///
+ /// @param[in] try_all_threads
+ /// If true, then we will try to run all threads if the function doesn't complete on
+ /// one thread. See timeout_usec for the interaction of this variable and
+ /// the timeout.
+ ///
+ /// @param[in] timeout_usec
+ /// Timeout value (0 for no timeout). If try_all_threads is true, then we
+ /// will try on one thread for the lesser of .25 sec and half the total timeout.
+ /// then switch to running all threads, otherwise this will be the total timeout.
+ ///
+ ///
+ /// @return
+ /// A Process::Execution results value.
+ //------------------------------------------------------------------
+ ExecutionResults
+ Execute (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ ClangUserExpressionSP &shared_ptr_to_me,
+ lldb::ClangExpressionVariableSP &result,
+ bool try_all_threads,
+ uint32_t timeout_usec);
+
+ ThreadPlan *
+ GetThreadPlanToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Apply the side effects of the function to program state.
+ ///
+ /// @param[in] error_stream
+ /// A stream to print errors to.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when looking up entities that
+ /// are needed for parsing (locations of variables, etc.)
+ ///
+ /// @param[in] result
+ /// A pointer to direct at the persistent variable in which the
+ /// expression's result is stored.
+ ///
+ /// @param[in] function_stack_pointer
+ /// A pointer to the base of the function's stack frame. This
+ /// is used to determine whether the expession result resides in
+ /// memory that will still be valid, or whether it needs to be
+ /// treated as homeless for the purpose of future expressions.
+ ///
+ /// @return
+ /// A Process::Execution results value.
+ //------------------------------------------------------------------
+ bool
+ FinalizeJITExecution (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::ClangExpressionVariableSP &result,
+ lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS,
+ lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS);
+
+ //------------------------------------------------------------------
+ /// Return the string that the parser should parse. Must be a full
+ /// translation unit.
+ //------------------------------------------------------------------
+ const char *
+ Text ()
+ {
+ return m_transformed_text.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the string that the user typed.
+ //------------------------------------------------------------------
+ const char *
+ GetUserText ()
+ {
+ return m_expr_text.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the function name that should be used for executing the
+ /// expression. Text() should contain the definition of this
+ /// function.
+ //------------------------------------------------------------------
+ const char *
+ FunctionName ()
+ {
+ return "$__lldb_expr";
+ }
+
+ //------------------------------------------------------------------
+ /// Return the language that should be used when parsing. To use
+ /// the default, return eLanguageTypeUnknown.
+ //------------------------------------------------------------------
+ virtual lldb::LanguageType
+ Language ()
+ {
+ return m_language;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap ()
+ {
+ return m_expr_decl_map.get();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ clang::ASTConsumer *
+ ASTTransformer (clang::ASTConsumer *passthrough);
+
+ //------------------------------------------------------------------
+ /// Return the desired result type of the function, or
+ /// eResultTypeAny if indifferent.
+ //------------------------------------------------------------------
+ virtual ResultType
+ DesiredResultType ()
+ {
+ return m_desired_type;
+ }
+
+ //------------------------------------------------------------------
+ /// Return true if validation code should be inserted into the
+ /// expression.
+ //------------------------------------------------------------------
+ bool
+ NeedsValidation ()
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Return true if external variables in the expression should be
+ /// resolved.
+ //------------------------------------------------------------------
+ bool
+ NeedsVariableResolution ()
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Evaluate one expression and return its result.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to use when evaluating the expression.
+ ///
+ /// @param[in] execution_policy
+ /// Determines whether or not to try using the IR interpreter to
+ /// avoid running the expression on the parser.
+ ///
+ /// @param[in] language
+ /// If not eLanguageTypeUnknown, a language to use when parsing
+ /// the expression. Currently restricted to those languages
+ /// supported by Clang.
+ ///
+ /// @param[in] unwind_on_error
+ /// True if the thread's state should be restored in the case
+ /// of an error.
+ ///
+ /// @param[in] ignore_breakpoints
+ /// If true, ignore breakpoints while executing the expression.
+ ///
+ /// @param[in] result_type
+ /// If not eResultTypeAny, the type of the desired result. Will
+ /// result in parse errors if impossible.
+ ///
+ /// @param[in] expr_cstr
+ /// A C string containing the expression to be evaluated.
+ ///
+ /// @param[in] expr_prefix
+ /// If non-NULL, a C string containing translation-unit level
+ /// definitions to be included when the expression is parsed.
+ ///
+ /// @param[in/out] result_valobj_sp
+ /// If execution is successful, the result valobj is placed here.
+ ///
+ /// @param[in] try_all_threads
+ /// If true, then we will try to run all threads if the function doesn't complete on
+ /// one thread. See timeout_usec for the interaction of this variable and
+ /// the timeout.
+ ///
+ /// @param[in] timeout_usec
+ /// Timeout value (0 for no timeout). If try_all_threads is true, then we
+ /// will try on one thread for the lesser of .25 sec and half the total timeout.
+ /// then switch to running all threads, otherwise this will be the total timeout.
+ ///
+ /// @result
+ /// A Process::ExecutionResults value. eExecutionCompleted for success.
+ //------------------------------------------------------------------
+ static ExecutionResults
+ Evaluate (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ bool try_all_threads,
+ uint32_t timeout_usec);
+
+ static ExecutionResults
+ EvaluateWithError (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ Error &error,
+ bool try_all_threads,
+ uint32_t timeout_usec);
+
+ static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression.
+private:
+ //------------------------------------------------------------------
+ /// Populate m_cplusplus and m_objetivec based on the environment.
+ //------------------------------------------------------------------
+
+ void
+ ScanContext (ExecutionContext &exe_ctx,
+ lldb_private::Error &err);
+
+ bool
+ PrepareToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::addr_t &struct_address,
+ lldb::addr_t &object_ptr,
+ lldb::addr_t &cmd_ptr);
+
+ void
+ InstallContext (ExecutionContext &exe_ctx);
+
+ bool
+ LockAndCheckContext (ExecutionContext &exe_ctx,
+ lldb::TargetSP &target_sp,
+ lldb::ProcessSP &process_sp,
+ lldb::StackFrameSP &frame_sp);
+
+ lldb::ProcessWP m_process_wp; ///< The process used as the context for the expression.
+ Address m_address; ///< The address the process is stopped in.
+ lldb::addr_t m_stack_frame_bottom; ///< The bottom of the allocated stack frame.
+ lldb::addr_t m_stack_frame_top; ///< The top of the allocated stack frame.
+
+ std::string m_expr_text; ///< The text of the expression, as typed by the user
+ std::string m_expr_prefix; ///< The text of the translation-level definitions, as provided by the user
+ lldb::LanguageType m_language; ///< The language to use when parsing (eLanguageTypeUnknown means use defaults)
+ bool m_allow_cxx; ///< True if the language allows C++.
+ bool m_allow_objc; ///< True if the language allows Objective-C.
+ std::string m_transformed_text; ///< The text of the expression, as send to the parser
+ ResultType m_desired_type; ///< The type to coerce the expression's result to. If eResultTypeAny, inferred from the expression.
+
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing the expression.
+ std::unique_ptr<IRExecutionUnit> m_execution_unit_ap; ///< The execution unit the expression is stored in.
+ std::unique_ptr<Materializer> m_materializer_ap; ///< The materializer to use when running the expression.
+ std::unique_ptr<ASTResultSynthesizer> m_result_synthesizer; ///< The result synthesizer, if one is needed.
+
+ bool m_enforce_valid_object; ///< True if the expression parser should enforce the presence of a valid class pointer in order to generate the expression as a method.
+ bool m_cplusplus; ///< True if the expression is compiled as a C++ member function (true if it was parsed when exe_ctx was in a C++ method).
+ bool m_objectivec; ///< True if the expression is compiled as an Objective-C method (true if it was parsed when exe_ctx was in an Objective-C method).
+ bool m_static_method; ///< True if the expression is compiled as a static (or class) method (currently true if it was parsed when exe_ctx was in an Objective-C class method).
+ bool m_needs_object_ptr; ///< True if "this" or "self" must be looked up and passed in. False if the expression doesn't really use them and they can be NULL.
+ bool m_const_object; ///< True if "this" is const.
+ Target *m_target; ///< The target for storing persistent data like types and variables.
+
+ bool m_can_interpret; ///< True if the expression could be evaluated statically; false otherwise.
+ lldb::addr_t m_materialized_address; ///< The address at which the arguments to the expression have been materialized.
+ Materializer::DematerializerSP m_dematerializer_sp; ///< The dematerializer.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangUserExpression_h_
diff --git a/include/lldb/Expression/ClangUtilityFunction.h b/include/lldb/Expression/ClangUtilityFunction.h
new file mode 100644
index 000000000000..6da8e5ec3a8b
--- /dev/null
+++ b/include/lldb/Expression/ClangUtilityFunction.h
@@ -0,0 +1,179 @@
+//===-- ClangUtilityFunction.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_ClangUtilityFunction_h_
+#define liblldb_ClangUtilityFunction_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Expression/ClangExpression.h"
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class ClangUtilityFunction ClangUtilityFunction.h "lldb/Expression/ClangUtilityFunction.h"
+/// @brief Encapsulates a single expression for use with Clang
+///
+/// LLDB uses expressions for various purposes, notably to call functions
+/// and as a backend for the expr command. ClangUtilityFunction encapsulates
+/// a self-contained function meant to be used from other code. Utility
+/// functions can perform error-checking for ClangUserExpressions,
+//----------------------------------------------------------------------
+class ClangUtilityFunction : public ClangExpression
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] text
+ /// The text of the function. Must be a full translation unit.
+ ///
+ /// @param[in] name
+ /// The name of the function, as used in the text.
+ //------------------------------------------------------------------
+ ClangUtilityFunction (const char *text,
+ const char *name);
+
+ virtual
+ ~ClangUtilityFunction ();
+
+ //------------------------------------------------------------------
+ /// Install the utility function into a process
+ ///
+ /// @param[in] error_stream
+ /// A stream to print parse errors and warnings to.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to install the utility function to.
+ ///
+ /// @return
+ /// True on success (no errors); false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Install (Stream &error_stream, ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Check whether the given PC is inside the function
+ ///
+ /// Especially useful if the function dereferences NULL to indicate a failed
+ /// assert.
+ ///
+ /// @param[in] pc
+ /// The program counter to check.
+ ///
+ /// @return
+ /// True if the program counter falls within the function's bounds;
+ /// false if not (or the function is not JIT compiled)
+ //------------------------------------------------------------------
+ bool
+ ContainsAddress (lldb::addr_t address)
+ {
+ // nothing is both >= LLDB_INVALID_ADDRESS and < LLDB_INVALID_ADDRESS,
+ // so this always returns false if the function is not JIT compiled yet
+ return (address >= m_jit_start_addr && address < m_jit_end_addr);
+ }
+
+
+ //------------------------------------------------------------------
+ /// Return the string that the parser should parse. Must be a full
+ /// translation unit.
+ //------------------------------------------------------------------
+ const char *
+ Text ()
+ {
+ return m_function_text.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the function name that should be used for executing the
+ /// expression. Text() should contain the definition of this
+ /// function.
+ //------------------------------------------------------------------
+ const char *
+ FunctionName ()
+ {
+ return m_function_name.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when resolving external
+ /// values. May be NULL if everything should be self-contained.
+ //------------------------------------------------------------------
+ ClangExpressionDeclMap *
+ DeclMap ()
+ {
+ return m_expr_decl_map.get();
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should use when registering
+ /// local variables. May be NULL if the Expression doesn't care.
+ //------------------------------------------------------------------
+ ClangExpressionVariableList *
+ LocalVariables ()
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Return the object that the parser should allow to access ASTs.
+ /// May be NULL if the ASTs do not need to be transformed.
+ ///
+ /// @param[in] passthrough
+ /// The ASTConsumer that the returned transformer should send
+ /// the ASTs to after transformation.
+ //------------------------------------------------------------------
+ clang::ASTConsumer *
+ ASTTransformer (clang::ASTConsumer *passthrough)
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Return true if validation code should be inserted into the
+ /// expression.
+ //------------------------------------------------------------------
+ bool
+ NeedsValidation ()
+ {
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Return true if external variables in the expression should be
+ /// resolved.
+ //------------------------------------------------------------------
+ bool
+ NeedsVariableResolution ()
+ {
+ return false;
+ }
+
+private:
+ std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map; ///< The map to use when parsing and materializing the expression.
+ std::unique_ptr<IRExecutionUnit> m_execution_unit_ap;
+
+ std::string m_function_text; ///< The text of the function. Must be a well-formed translation unit.
+ std::string m_function_name; ///< The name of the function.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangUtilityFunction_h_
diff --git a/include/lldb/Expression/DWARFExpression.h b/include/lldb/Expression/DWARFExpression.h
new file mode 100644
index 000000000000..2692831ecc84
--- /dev/null
+++ b/include/lldb/Expression/DWARFExpression.h
@@ -0,0 +1,424 @@
+//===-- DWARFExpression.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_DWARFExpression_h_
+#define liblldb_DWARFExpression_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+
+namespace lldb_private {
+
+class ClangExpressionVariable;
+class ClangExpressionVariableList;
+
+class ClangExpressionDeclMap;
+
+//----------------------------------------------------------------------
+/// @class DWARFExpression DWARFExpression.h "lldb/Expression/DWARFExpression.h"
+/// @brief Encapsulates a DWARF location expression and interprets it.
+///
+/// DWARF location expressions are used in two ways by LLDB. The first
+/// use is to find entities specified in the debug information, since
+/// their locations are specified in precisely this language. The second
+/// is to interpret expressions without having to run the target in cases
+/// where the overhead from copying JIT-compiled code into the target is
+/// too high or where the target cannot be run. This class encapsulates
+/// a single DWARF location expression or a location list and interprets
+/// it.
+//----------------------------------------------------------------------
+class DWARFExpression
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ //------------------------------------------------------------------
+ DWARFExpression();
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] data
+ /// A data extractor configured to read the DWARF location expression's
+ /// bytecode.
+ ///
+ /// @param[in] data_offset
+ /// The offset of the location expression in the extractor.
+ ///
+ /// @param[in] data_length
+ /// The byte length of the location expression.
+ //------------------------------------------------------------------
+ DWARFExpression(const DataExtractor& data,
+ lldb::offset_t data_offset,
+ lldb::offset_t data_length);
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ //------------------------------------------------------------------
+ DWARFExpression(const DWARFExpression& rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual
+ ~DWARFExpression();
+
+ //------------------------------------------------------------------
+ /// Print the description of the expression to a stream
+ ///
+ /// @param[in] s
+ /// The stream to print to.
+ ///
+ /// @param[in] level
+ /// The level of verbosity to use.
+ ///
+ /// @param[in] location_list_base_addr
+ /// If this is a location list based expression, this is the
+ /// address of the object that owns it. NOTE: this value is
+ /// different from the DWARF version of the location list base
+ /// address which is compile unit relative. This base address
+ /// is the address of the object that owns the location list.
+ ///
+ /// @param[in] abi
+ /// An optional ABI plug-in that can be used to resolve register
+ /// names.
+ //------------------------------------------------------------------
+ void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level,
+ lldb::addr_t location_list_base_addr,
+ ABI *abi) const;
+
+ //------------------------------------------------------------------
+ /// Return true if the location expression contains data
+ //------------------------------------------------------------------
+ bool
+ IsValid() const;
+
+ //------------------------------------------------------------------
+ /// Return true if a location list was provided
+ //------------------------------------------------------------------
+ bool
+ IsLocationList() const;
+
+ //------------------------------------------------------------------
+ /// Search for a load address in the location list
+ ///
+ /// @param[in] process
+ /// The process to use when resolving the load address
+ ///
+ /// @param[in] addr
+ /// The address to resolve
+ ///
+ /// @return
+ /// True if IsLocationList() is true and the address was found;
+ /// false otherwise.
+ //------------------------------------------------------------------
+// bool
+// LocationListContainsLoadAddress (Process* process, const Address &addr) const;
+//
+ bool
+ LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const;
+
+ //------------------------------------------------------------------
+ /// If a location is not a location list, return true if the location
+ /// contains a DW_OP_addr () opcode in the stream that matches \a
+ /// file_addr. If file_addr is LLDB_INVALID_ADDRESS, the this
+ /// function will return true if the variable there is any DW_OP_addr
+ /// in a location that (yet still is NOT a location list). This helps
+ /// us detect if a variable is a global or static variable since
+ /// there is no other indication from DWARF debug info.
+ ///
+ /// @param[in] op_addr_idx
+ /// The DW_OP_addr index to retrieve in case there is more than
+ /// one DW_OP_addr opcode in the location byte stream.
+ ///
+ /// @param[out] error
+ /// If the location stream contains unknown DW_OP opcodes or the
+ /// data is missing, \a error will be set to \b true.
+ ///
+ /// @return
+ /// LLDB_INVALID_ADDRESS if the location doesn't contain a
+ /// DW_OP_addr for \a op_addr_idx, otherwise a valid file address
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetLocation_DW_OP_addr (uint32_t op_addr_idx, bool &error) const;
+
+ bool
+ Update_DW_OP_addr (lldb::addr_t file_addr);
+
+ //------------------------------------------------------------------
+ /// Make the expression parser read its location information from a
+ /// given data source. Does not change the offset and length
+ ///
+ /// @param[in] data
+ /// A data extractor configured to read the DWARF location expression's
+ /// bytecode.
+ //------------------------------------------------------------------
+ void
+ SetOpcodeData(const DataExtractor& data);
+
+ //------------------------------------------------------------------
+ /// Make the expression parser read its location information from a
+ /// given data source
+ ///
+ /// @param[in] data
+ /// A data extractor configured to read the DWARF location expression's
+ /// bytecode.
+ ///
+ /// @param[in] data_offset
+ /// The offset of the location expression in the extractor.
+ ///
+ /// @param[in] data_length
+ /// The byte length of the location expression.
+ //------------------------------------------------------------------
+ void
+ SetOpcodeData(const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length);
+
+ //------------------------------------------------------------------
+ /// Copy the DWARF location expression into a local buffer.
+ ///
+ /// It is a good idea to copy the data so we don't keep the entire
+ /// object file worth of data around just for a few bytes of location
+ /// expression. LLDB typically will mmap the entire contents of debug
+ /// information files, and if we use SetOpcodeData, it will get a
+ /// shared reference to all of this data for the and cause the object
+ /// file to have to stay around. Even worse, a very very large ".a"
+ /// that contains one or more .o files could end up being referenced.
+ /// Location lists are typically small so even though we are copying
+ /// the data, it shouldn't amount to that much for the variables we
+ /// end up parsing.
+ ///
+ /// @param[in] data
+ /// A data extractor configured to read and copy the DWARF
+ /// location expression's bytecode.
+ ///
+ /// @param[in] data_offset
+ /// The offset of the location expression in the extractor.
+ ///
+ /// @param[in] data_length
+ /// The byte length of the location expression.
+ //------------------------------------------------------------------
+ void
+ CopyOpcodeData (const DataExtractor& data,
+ lldb::offset_t data_offset,
+ lldb::offset_t data_length);
+
+
+ //------------------------------------------------------------------
+ /// Tells the expression that it refers to a location list.
+ ///
+ /// @param[in] slide
+ /// This value should be a slide that is applied to any values
+ /// in the location list data so the values become zero based
+ /// offsets into the object that owns the location list. We need
+ /// to make location lists relative to the objects that own them
+ /// so we can relink addresses on the fly.
+ //------------------------------------------------------------------
+ void
+ SetLocationListSlide (lldb::addr_t slide);
+
+ //------------------------------------------------------------------
+ /// Return the call-frame-info style register kind
+ //------------------------------------------------------------------
+ int
+ GetRegisterKind ();
+
+ //------------------------------------------------------------------
+ /// Set the call-frame-info style register kind
+ ///
+ /// @param[in] reg_kind
+ /// The register kind.
+ //------------------------------------------------------------------
+ void
+ SetRegisterKind (lldb::RegisterKind reg_kind);
+
+ //------------------------------------------------------------------
+ /// Wrapper for the static evaluate function that accepts an
+ /// ExecutionContextScope instead of an ExecutionContext and uses
+ /// member variables to populate many operands
+ //------------------------------------------------------------------
+ bool
+ Evaluate (ExecutionContextScope *exe_scope,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Wrapper for the static evaluate function that uses member
+ /// variables to populate many operands
+ //------------------------------------------------------------------
+ bool
+ Evaluate (ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr) const;
+
+ //------------------------------------------------------------------
+ /// Evaluate a DWARF location expression in a particular context
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context in which to evaluate the location
+ /// expression. The location expression may access the target's
+ /// memory, especially if it comes from the expression parser.
+ ///
+ /// @param[in] opcodes
+ /// This is a static method so the opcodes need to be provided
+ /// explicitly.
+ ///
+ /// @param[in] expr_locals
+ /// If the location expression was produced by the expression parser,
+ /// the list of local variables referenced by the DWARF expression.
+ /// This list should already have been populated during parsing;
+ /// the DWARF expression refers to variables by index. Can be NULL if
+ /// the location expression uses no locals.
+ ///
+ /// @param[in] decl_map
+ /// If the location expression was produced by the expression parser,
+ /// the list of external variables referenced by the location
+ /// expression. Can be NULL if the location expression uses no
+ /// external variables.
+ ///
+ /// @param[in] reg_ctx
+ /// An optional parameter which provides a RegisterContext for use
+ /// when evaluating the expression (i.e. for fetching register values).
+ /// Normally this will come from the ExecutionContext's StackFrame but
+ /// in the case where an expression needs to be evaluated while building
+ /// the stack frame list, this short-cut is available.
+ ///
+ /// @param[in] offset
+ /// The offset of the location expression in the data extractor.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the location expression.
+ ///
+ /// @param[in] reg_set
+ /// The call-frame-info style register kind.
+ ///
+ /// @param[in] initial_value_ptr
+ /// A value to put on top of the interpreter stack before evaluating
+ /// the expression, if the expression is parametrized. Can be NULL.
+ ///
+ /// @param[in] result
+ /// A value into which the result of evaluating the expression is
+ /// to be placed.
+ ///
+ /// @param[in] error_ptr
+ /// If non-NULL, used to report errors in expression evaluation.
+ ///
+ /// @return
+ /// True on success; false otherwise. If error_ptr is non-NULL,
+ /// details of the failure are provided through it.
+ //------------------------------------------------------------------
+ static bool
+ Evaluate (ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ const DataExtractor& opcodes,
+ const lldb::offset_t offset,
+ const lldb::offset_t length,
+ const uint32_t reg_set,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr);
+
+ //------------------------------------------------------------------
+ /// Loads a ClangExpressionVariableList into the object
+ ///
+ /// @param[in] locals
+ /// If non-NULL, the list of locals used by this expression.
+ /// See Evaluate().
+ //------------------------------------------------------------------
+ void
+ SetExpressionLocalVariableList (ClangExpressionVariableList *locals);
+
+ //------------------------------------------------------------------
+ /// Loads a ClangExpressionDeclMap into the object
+ ///
+ /// @param[in] locals
+ /// If non-NULL, the list of external variables used by this
+ /// expression. See Evaluate().
+ //------------------------------------------------------------------
+ void
+ SetExpressionDeclMap (ClangExpressionDeclMap *decl_map);
+
+ bool
+ GetExpressionData (DataExtractor &data) const
+ {
+ data = m_data;
+ return data.GetByteSize() > 0;
+ }
+
+ bool
+ DumpLocationForAddress (Stream *s,
+ lldb::DescriptionLevel level,
+ lldb::addr_t loclist_base_load_addr,
+ lldb::addr_t address,
+ ABI *abi);
+
+protected:
+ //------------------------------------------------------------------
+ /// Pretty-prints the location expression to a stream
+ ///
+ /// @param[in] stream
+ /// The stream to use for pretty-printing.
+ ///
+ /// @param[in] offset
+ /// The offset into the data buffer of the opcodes to be printed.
+ ///
+ /// @param[in] length
+ /// The length in bytes of the opcodes to be printed.
+ ///
+ /// @param[in] level
+ /// The level of detail to use in pretty-printing.
+ ///
+ /// @param[in] abi
+ /// An optional ABI plug-in that can be used to resolve register
+ /// names.
+ //------------------------------------------------------------------
+ void
+ DumpLocation(Stream *s,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ lldb::DescriptionLevel level,
+ ABI *abi) const;
+
+ bool
+ GetLocation (lldb::addr_t base_addr,
+ lldb::addr_t pc,
+ lldb::offset_t &offset,
+ lldb::offset_t &len);
+
+ //------------------------------------------------------------------
+ /// Classes that inherit from DWARFExpression can see and modify these
+ //------------------------------------------------------------------
+
+ DataExtractor m_data; ///< A data extractor capable of reading opcode bytes
+ lldb::RegisterKind m_reg_kind; ///< One of the defines that starts with LLDB_REGKIND_
+ lldb::addr_t m_loclist_slide; ///< A value used to slide the location list offsets so that
+ ///< they are relative to the object that owns the location list
+ ///< (the function for frame base and variable location lists)
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DWARFExpression_h_
diff --git a/include/lldb/Expression/ExpressionSourceCode.h b/include/lldb/Expression/ExpressionSourceCode.h
new file mode 100644
index 000000000000..be1014ae3047
--- /dev/null
+++ b/include/lldb/Expression/ExpressionSourceCode.h
@@ -0,0 +1,78 @@
+//===-- ExpressionSourceCode.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_ExpressionSourceCode_h
+#define liblldb_ExpressionSourceCode_h
+
+#include "lldb/lldb-enumerations.h"
+
+#include <string>
+
+namespace lldb_private
+{
+
+class ExpressionSourceCode
+{
+public:
+ static const char * g_expression_prefix;
+
+ static ExpressionSourceCode *CreateWrapped (const char *prefix,
+ const char *body)
+ {
+ return new ExpressionSourceCode ("$__lldb_expr",
+ prefix,
+ body,
+ true);
+ }
+
+ static ExpressionSourceCode *CreateUnwrapped (const char *name,
+ const char *body)
+ {
+ return new ExpressionSourceCode (name,
+ "",
+ body,
+ false);
+ }
+
+ bool NeedsWrapping () const
+ {
+ return m_wrap;
+ }
+
+ const char *GetName () const
+ {
+ return m_name.c_str();
+ }
+
+ bool GetText (std::string &text,
+ lldb::LanguageType wrapping_language,
+ bool const_object,
+ bool static_method) const;
+
+private:
+ ExpressionSourceCode (const char *name,
+ const char *prefix,
+ const char *body,
+ bool wrap) :
+ m_name(name),
+ m_prefix(prefix),
+ m_body(body),
+ m_wrap(wrap)
+ {
+ }
+
+ std::string m_name;
+ std::string m_prefix;
+ std::string m_body;
+ bool m_wrap;
+};
+
+} // namespace lldb_private
+
+#endif
diff --git a/include/lldb/Expression/IRDynamicChecks.h b/include/lldb/Expression/IRDynamicChecks.h
new file mode 100644
index 000000000000..226f5c94e98c
--- /dev/null
+++ b/include/lldb/Expression/IRDynamicChecks.h
@@ -0,0 +1,169 @@
+//===-- IRDynamicChecks.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_IRDynamicChecks_h_
+#define liblldb_IRDynamicChecks_h_
+
+#include "lldb/lldb-types.h"
+#include "llvm/Pass.h"
+
+namespace llvm {
+ class BasicBlock;
+ class CallInst;
+ class Constant;
+ class Function;
+ class Instruction;
+ class Module;
+ class DataLayout;
+ class Value;
+}
+
+namespace lldb_private
+{
+
+class ClangExpressionDeclMap;
+class ClangUtilityFunction;
+class ExecutionContext;
+class Stream;
+
+//----------------------------------------------------------------------
+/// @class DynamicCheckerFunctions IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
+/// @brief Encapsulates dynamic check functions used by expressions.
+///
+/// Each of the utility functions encapsulated in this class is responsible
+/// for validating some data that an expression is about to use. Examples are:
+///
+/// a = *b; // check that b is a valid pointer
+/// [b init]; // check that b is a valid object to send "init" to
+///
+/// The class installs each checker function into the target process and
+/// makes it available to IRDynamicChecks to use.
+//----------------------------------------------------------------------
+class DynamicCheckerFunctions
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ //------------------------------------------------------------------
+ DynamicCheckerFunctions ();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~DynamicCheckerFunctions ();
+
+ //------------------------------------------------------------------
+ /// Install the utility functions into a process. This binds the
+ /// instance of DynamicCheckerFunctions to that process.
+ ///
+ /// @param[in] error_stream
+ /// A stream to print errors on.
+ ///
+ /// @param[in] exe_ctx
+ /// The execution context to install the functions into.
+ ///
+ /// @return
+ /// True on success; false on failure, or if the functions have
+ /// already been installed.
+ //------------------------------------------------------------------
+ bool Install (Stream &error_stream,
+ ExecutionContext &exe_ctx);
+
+ bool DoCheckersExplainStop (lldb::addr_t addr, Stream &message);
+
+ std::unique_ptr<ClangUtilityFunction> m_valid_pointer_check;
+ std::unique_ptr<ClangUtilityFunction> m_objc_object_check;
+};
+
+//----------------------------------------------------------------------
+/// @class IRDynamicChecks IRDynamicChecks.h "lldb/Expression/IRDynamicChecks.h"
+/// @brief Adds dynamic checks to a user-entered expression to reduce its likelihood of crashing
+///
+/// When an IR function is executed in the target process, it may cause
+/// crashes or hangs by dereferencing NULL pointers, trying to call Objective-C
+/// methods on objects that do not respond to them, and so forth.
+///
+/// IRDynamicChecks adds calls to the functions in DynamicCheckerFunctions
+/// to appropriate locations in an expression's IR.
+//----------------------------------------------------------------------
+class IRDynamicChecks : public llvm::ModulePass
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] checker_functions
+ /// The checker functions for the target process.
+ ///
+ /// @param[in] func_name
+ /// The name of the function to prepare for execution in the target.
+ ///
+ /// @param[in] decl_map
+ /// The mapping used to look up entities in the target process. In
+ /// this case, used to find objc_msgSend
+ //------------------------------------------------------------------
+ IRDynamicChecks (DynamicCheckerFunctions &checker_functions,
+ const char* func_name = "$__lldb_expr");
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual ~IRDynamicChecks();
+
+ //------------------------------------------------------------------
+ /// Run this IR transformer on a single module
+ ///
+ /// @param[in] M
+ /// The module to run on. This module is searched for the function
+ /// $__lldb_expr, and that function is passed to the passes one by
+ /// one.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool runOnModule(llvm::Module &M);
+
+ //------------------------------------------------------------------
+ /// Interface stub
+ //------------------------------------------------------------------
+ void assignPassManager(llvm::PMStack &PMS,
+ llvm::PassManagerType T = llvm::PMT_ModulePassManager);
+
+ //------------------------------------------------------------------
+ /// Returns PMT_ModulePassManager
+ //------------------------------------------------------------------
+ llvm::PassManagerType getPotentialPassManagerType() const;
+private:
+ //------------------------------------------------------------------
+ /// A basic block-level pass to find all pointer dereferences and
+ /// validate them before use.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] M
+ /// The module currently being processed.
+ ///
+ /// @param[in] BB
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool FindDataLoads(llvm::Module &M,
+ llvm::BasicBlock &BB);
+
+ std::string m_func_name; ///< The name of the function to add checks to
+ DynamicCheckerFunctions &m_checker_functions; ///< The checker functions for the process
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/IRExecutionUnit.h b/include/lldb/Expression/IRExecutionUnit.h
new file mode 100644
index 000000000000..885b6516b0c6
--- /dev/null
+++ b/include/lldb/Expression/IRExecutionUnit.h
@@ -0,0 +1,495 @@
+//===-- IRExecutionUnit.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_IRExecutionUnit_h_
+#define lldb_IRExecutionUnit_h_
+
+// C Includes
+// C++ Includes
+#include <atomic>
+#include <string>
+#include <vector>
+#include <map>
+
+// Other libraries and framework includes
+#include "llvm/IR/Module.h"
+
+// Project includes
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Host/Mutex.h"
+
+namespace llvm {
+
+class Module;
+class ExecutionEngine;
+
+}
+
+namespace lldb_private {
+
+class Error;
+
+//----------------------------------------------------------------------
+/// @class IRExecutionUnit IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
+/// @brief Contains the IR and, optionally, JIT-compiled code for a module.
+///
+/// This class encapsulates the compiled version of an expression, in IR
+/// form (for interpretation purposes) and in raw machine code form (for
+/// execution in the target).
+///
+/// This object wraps an IR module that comes from the expression parser,
+/// and knows how to use the JIT to make it into executable code. It can
+/// then be used as input to the IR interpreter, or the address of the
+/// executable code can be passed to a thread plan to run in the target.
+///
+/// This class creates a subclass of LLVM's JITMemoryManager, because that is
+/// how the JIT emits code. Because LLDB needs to move JIT-compiled code
+/// into the target process, the IRExecutionUnit knows how to copy the
+/// emitted code into the target process.
+//----------------------------------------------------------------------
+class IRExecutionUnit : public IRMemoryMap
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ //------------------------------------------------------------------
+ IRExecutionUnit (std::unique_ptr<llvm::LLVMContext> &context_ap,
+ std::unique_ptr<llvm::Module> &module_ap,
+ ConstString &name,
+ const lldb::TargetSP &target_sp,
+ std::vector<std::string> &cpu_features);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~IRExecutionUnit();
+
+ llvm::Module *GetModule()
+ {
+ return m_module;
+ }
+
+ llvm::Function *GetFunction()
+ {
+ if (m_module)
+ return m_module->getFunction (m_name.AsCString());
+ else
+ return NULL;
+ }
+
+ void GetRunnableInfo(Error &error,
+ lldb::addr_t &func_addr,
+ lldb::addr_t &func_end);
+
+ //------------------------------------------------------------------
+ /// Accessors for IRForTarget and other clients that may want binary
+ /// data placed on their behalf. The binary data is owned by the
+ /// IRExecutionUnit unless the client explicitly chooses to free it.
+ //------------------------------------------------------------------
+
+ lldb::addr_t WriteNow(const uint8_t *bytes,
+ size_t size,
+ Error &error);
+
+ void FreeNow(lldb::addr_t allocation);
+
+private:
+ //------------------------------------------------------------------
+ /// Look up the object in m_address_map that contains a given address,
+ /// find where it was copied to, and return the remote address at the
+ /// same offset into the copied entity
+ ///
+ /// @param[in] local_address
+ /// The address in the debugger.
+ ///
+ /// @return
+ /// The address in the target process.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetRemoteAddressForLocal (lldb::addr_t local_address);
+
+ //------------------------------------------------------------------
+ /// Look up the object in m_address_map that contains a given address,
+ /// find where it was copied to, and return its address range in the
+ /// target process
+ ///
+ /// @param[in] local_address
+ /// The address in the debugger.
+ ///
+ /// @return
+ /// The range of the containing object in the target process.
+ //------------------------------------------------------------------
+ typedef std::pair <lldb::addr_t, uintptr_t> AddrRange;
+ AddrRange
+ GetRemoteRangeForLocal (lldb::addr_t local_address);
+
+ //------------------------------------------------------------------
+ /// Commit all allocations to the process and record where they were stored.
+ ///
+ /// @param[in] process
+ /// The process to allocate memory in.
+ ///
+ /// @return
+ /// True <=> all allocations were performed successfully.
+ /// This method will attempt to free allocated memory if the
+ /// operation fails.
+ //------------------------------------------------------------------
+ bool
+ CommitAllocations (lldb::ProcessSP &process_sp);
+
+ //------------------------------------------------------------------
+ /// Report all committed allocations to the execution engine.
+ ///
+ /// @param[in] engine
+ /// The execution engine to notify.
+ //------------------------------------------------------------------
+ void
+ ReportAllocations (llvm::ExecutionEngine &engine);
+
+ //------------------------------------------------------------------
+ /// Write the contents of all allocations to the process.
+ ///
+ /// @param[in] local_address
+ /// The process containing the allocations.
+ ///
+ /// @return
+ /// True <=> all allocations were performed successfully.
+ //------------------------------------------------------------------
+ bool
+ WriteData (lldb::ProcessSP &process_sp);
+
+ Error
+ DisassembleFunction (Stream &stream,
+ lldb::ProcessSP &process_sp);
+
+ class MemoryManager : public llvm::JITMemoryManager
+ {
+ public:
+ MemoryManager (IRExecutionUnit &parent);
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void setMemoryWritable ();
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void setMemoryExecutable ();
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void setPoisonMemory (bool poison)
+ {
+ m_default_mm_ap->setPoisonMemory (poison);
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void AllocateGOT()
+ {
+ m_default_mm_ap->AllocateGOT();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual uint8_t *getGOTBase() const
+ {
+ return m_default_mm_ap->getGOTBase();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual uint8_t *startFunctionBody(const llvm::Function *F,
+ uintptr_t &ActualSize);
+
+ //------------------------------------------------------------------
+ /// Allocate room for a dyld stub for a lazy-referenced function,
+ /// and add it to the m_stubs map
+ ///
+ /// @param[in] F
+ /// The function being referenced.
+ ///
+ /// @param[in] StubSize
+ /// The size of the stub.
+ ///
+ /// @param[in] Alignment
+ /// The required alignment of the stub.
+ ///
+ /// @return
+ /// Allocated space for the stub.
+ //------------------------------------------------------------------
+ virtual uint8_t *allocateStub(const llvm::GlobalValue* F,
+ unsigned StubSize,
+ unsigned Alignment);
+
+ //------------------------------------------------------------------
+ /// Complete the body of a function, and add it to the m_functions map
+ ///
+ /// @param[in] F
+ /// The function being completed.
+ ///
+ /// @param[in] FunctionStart
+ /// The first instruction of the function.
+ ///
+ /// @param[in] FunctionEnd
+ /// The last byte of the last instruction of the function.
+ //------------------------------------------------------------------
+ virtual void endFunctionBody(const llvm::Function *F,
+ uint8_t *FunctionStart,
+ uint8_t *FunctionEnd);
+ //------------------------------------------------------------------
+ /// Allocate space for an unspecified purpose, and add it to the
+ /// m_spaceBlocks map
+ ///
+ /// @param[in] Size
+ /// The size of the area.
+ ///
+ /// @param[in] Alignment
+ /// The required alignment of the area.
+ ///
+ /// @return
+ /// Allocated space.
+ //------------------------------------------------------------------
+ virtual uint8_t *allocateSpace(intptr_t Size, unsigned Alignment);
+
+ //------------------------------------------------------------------
+ /// Allocate space for executable code, and add it to the
+ /// m_spaceBlocks map
+ ///
+ /// @param[in] Size
+ /// The size of the area.
+ ///
+ /// @param[in] Alignment
+ /// The required alignment of the area.
+ ///
+ /// @param[in] SectionID
+ /// A unique identifier for the section.
+ ///
+ /// @return
+ /// Allocated space.
+ //------------------------------------------------------------------
+ virtual uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID);
+
+ //------------------------------------------------------------------
+ /// Allocate space for data, and add it to the m_spaceBlocks map
+ ///
+ /// @param[in] Size
+ /// The size of the area.
+ ///
+ /// @param[in] Alignment
+ /// The required alignment of the area.
+ ///
+ /// @param[in] SectionID
+ /// A unique identifier for the section.
+ ///
+ /// @param[in] IsReadOnly
+ /// Flag indicating the section is read-only.
+ ///
+ /// @return
+ /// Allocated space.
+ //------------------------------------------------------------------
+ virtual uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
+ unsigned SectionID, bool IsReadOnly);
+
+ //------------------------------------------------------------------
+ /// Allocate space for a global variable, and add it to the
+ /// m_spaceBlocks map
+ ///
+ /// @param[in] Size
+ /// The size of the variable.
+ ///
+ /// @param[in] Alignment
+ /// The required alignment of the variable.
+ ///
+ /// @return
+ /// Allocated space for the global.
+ //------------------------------------------------------------------
+ virtual uint8_t *allocateGlobal(uintptr_t Size,
+ unsigned Alignment);
+
+ //------------------------------------------------------------------
+ /// Called when object loading is complete and section page
+ /// permissions can be applied. Currently unimplemented for LLDB.
+ ///
+ /// @param[out] ErrMsg
+ /// The error that prevented the page protection from succeeding.
+ ///
+ /// @return
+ /// True in case of failure, false in case of success.
+ //------------------------------------------------------------------
+ virtual bool finalizeMemory(std::string *ErrMsg) {
+ // TODO: Ensure that the instruction cache is flushed because
+ // relocations are updated by dy-load. See:
+ // sys::Memory::InvalidateInstructionCache
+ // llvm::SectionMemoryManager
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void deallocateFunctionBody(void *Body);
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual size_t GetDefaultCodeSlabSize() {
+ return m_default_mm_ap->GetDefaultCodeSlabSize();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual size_t GetDefaultDataSlabSize() {
+ return m_default_mm_ap->GetDefaultDataSlabSize();
+ }
+
+ virtual size_t GetDefaultStubSlabSize() {
+ return m_default_mm_ap->GetDefaultStubSlabSize();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual unsigned GetNumCodeSlabs() {
+ return m_default_mm_ap->GetNumCodeSlabs();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual unsigned GetNumDataSlabs() {
+ return m_default_mm_ap->GetNumDataSlabs();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual unsigned GetNumStubSlabs() {
+ return m_default_mm_ap->GetNumStubSlabs();
+ }
+
+ //------------------------------------------------------------------
+ /// Passthrough interface stub
+ //------------------------------------------------------------------
+ virtual void *getPointerToNamedFunction(const std::string &Name,
+ bool AbortOnFailure = true) {
+ return m_default_mm_ap->getPointerToNamedFunction(Name, AbortOnFailure);
+ }
+ private:
+ std::unique_ptr<JITMemoryManager> m_default_mm_ap; ///< The memory allocator to use in actually creating space. All calls are passed through to it.
+ IRExecutionUnit &m_parent; ///< The execution unit this is a proxy for.
+ };
+
+ //----------------------------------------------------------------------
+ /// @class JittedFunction IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
+ /// @brief Encapsulates a single function that has been generated by the JIT.
+ ///
+ /// Functions that have been generated by the JIT are first resident in the
+ /// local process, and then placed in the target process. JittedFunction
+ /// represents a function possibly resident in both.
+ //----------------------------------------------------------------------
+ struct JittedFunction {
+ std::string m_name; ///< The function's name
+ lldb::addr_t m_local_addr; ///< The address of the function in LLDB's memory
+ lldb::addr_t m_remote_addr; ///< The address of the function in the target's memory
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// Initializes class variabes.
+ ///
+ /// @param[in] name
+ /// The name of the function.
+ ///
+ /// @param[in] local_addr
+ /// The address of the function in LLDB, or LLDB_INVALID_ADDRESS if
+ /// it is not present in LLDB's memory.
+ ///
+ /// @param[in] remote_addr
+ /// The address of the function in the target, or LLDB_INVALID_ADDRESS
+ /// if it is not present in the target's memory.
+ //------------------------------------------------------------------
+ JittedFunction (const char *name,
+ lldb::addr_t local_addr = LLDB_INVALID_ADDRESS,
+ lldb::addr_t remote_addr = LLDB_INVALID_ADDRESS) :
+ m_name (name),
+ m_local_addr (local_addr),
+ m_remote_addr (remote_addr)
+ {
+ }
+ };
+
+ static const unsigned eSectionIDInvalid = (unsigned)-1;
+
+ //----------------------------------------------------------------------
+ /// @class AllocationRecord IRExecutionUnit.h "lldb/Expression/IRExecutionUnit.h"
+ /// @brief Enacpsulates a single allocation request made by the JIT.
+ ///
+ /// Allocations made by the JIT are first queued up and then applied in
+ /// bulk to the underlying process.
+ //----------------------------------------------------------------------
+ struct AllocationRecord {
+ lldb::addr_t m_process_address;
+ uintptr_t m_host_address;
+ uint32_t m_permissions;
+ size_t m_size;
+ unsigned m_alignment;
+ unsigned m_section_id;
+
+ AllocationRecord (uintptr_t host_address,
+ uint32_t permissions,
+ size_t size,
+ unsigned alignment,
+ unsigned section_id = eSectionIDInvalid) :
+ m_process_address(LLDB_INVALID_ADDRESS),
+ m_host_address(host_address),
+ m_permissions(permissions),
+ m_size(size),
+ m_alignment(alignment),
+ m_section_id(section_id)
+ {
+ }
+
+ void dump (Log *log);
+ };
+
+ typedef std::vector<AllocationRecord> RecordVector;
+ RecordVector m_records;
+
+ std::unique_ptr<llvm::LLVMContext> m_context_ap;
+ std::unique_ptr<llvm::ExecutionEngine> m_execution_engine_ap;
+ std::unique_ptr<llvm::Module> m_module_ap; ///< Holder for the module until it's been handed off
+ llvm::Module *m_module; ///< Owned by the execution engine
+ std::vector<std::string> m_cpu_features;
+ llvm::SmallVector<JittedFunction, 1> m_jitted_functions; ///< A vector of all functions that have been JITted into machine code
+ const ConstString m_name;
+
+ std::atomic<bool> m_did_jit;
+
+ lldb::addr_t m_function_load_addr;
+ lldb::addr_t m_function_end_load_addr;
+};
+
+} // namespace lldb_private
+
+#endif // lldb_IRExecutionUnit_h_
diff --git a/include/lldb/Expression/IRForTarget.h b/include/lldb/Expression/IRForTarget.h
new file mode 100644
index 000000000000..151bf2ab4774
--- /dev/null
+++ b/include/lldb/Expression/IRForTarget.h
@@ -0,0 +1,733 @@
+//===-- IRForTarget.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_IRForTarget_h_
+#define liblldb_IRForTarget_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "llvm/Pass.h"
+
+#include <map>
+
+namespace llvm {
+ class BasicBlock;
+ class CallInst;
+ class Constant;
+ class ConstantInt;
+ class Function;
+ class GlobalValue;
+ class GlobalVariable;
+ class Instruction;
+ class Module;
+ class StoreInst;
+ class DataLayout;
+ class Type;
+ class Value;
+}
+
+namespace lldb_private {
+ class ClangExpressionDeclMap;
+ class IRExecutionUnit;
+ class IRMemoryMap;
+}
+
+//----------------------------------------------------------------------
+/// @class IRForTarget IRForTarget.h "lldb/Expression/IRForTarget.h"
+/// @brief Transforms the IR for a function to run in the target
+///
+/// Once an expression has been parsed and converted to IR, it can run
+/// in two contexts: interpreted by LLDB as a DWARF location expression,
+/// or compiled by the JIT and inserted into the target process for
+/// execution.
+///
+/// IRForTarget makes the second possible, by applying a series of
+/// transformations to the IR which make it relocatable. These
+/// transformations are discussed in more detail next to their relevant
+/// functions.
+//----------------------------------------------------------------------
+class IRForTarget : public llvm::ModulePass
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] decl_map
+ /// The list of externally-referenced variables for the expression,
+ /// for use in looking up globals and allocating the argument
+ /// struct. See the documentation for ClangExpressionDeclMap.
+ ///
+ /// @param[in] resolve_vars
+ /// True if the external variable references (including persistent
+ /// variables) should be resolved. If not, only external functions
+ /// are resolved.
+ ///
+ /// @param[in] execution_policy
+ /// Determines whether an IR interpreter can be used to statically
+ /// evaluate the expression.
+ ///
+ /// @param[in] const_result
+ /// This variable is populated with the statically-computed result
+ /// of the function, if it has no side-effects and the result can
+ /// be computed statically.
+ ///
+ /// @param[in] execution_unit
+ /// The holder for raw data associated with the expression.
+ ///
+ /// @param[in] error_stream
+ /// If non-NULL, a stream on which errors can be printed.
+ ///
+ /// @param[in] func_name
+ /// The name of the function to prepare for execution in the target.
+ //------------------------------------------------------------------
+ IRForTarget(lldb_private::ClangExpressionDeclMap *decl_map,
+ bool resolve_vars,
+ lldb_private::IRExecutionUnit &execution_unit,
+ lldb_private::Stream *error_stream,
+ const char* func_name = "$__lldb_expr");
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual ~IRForTarget();
+
+ //------------------------------------------------------------------
+ /// Run this IR transformer on a single module
+ ///
+ /// Implementation of the llvm::ModulePass::runOnModule() function.
+ ///
+ /// @param[in] llvm_module
+ /// The module to run on. This module is searched for the function
+ /// $__lldb_expr, and that function is passed to the passes one by
+ /// one.
+ ///
+ /// @param[in] interpreter_error
+ /// An error. If the expression fails to be interpreted, this error
+ /// is set to a reason why.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ virtual bool
+ runOnModule (llvm::Module &llvm_module);
+
+ //------------------------------------------------------------------
+ /// Interface stub
+ ///
+ /// Implementation of the llvm::ModulePass::assignPassManager()
+ /// function.
+ //------------------------------------------------------------------
+ virtual void
+ assignPassManager (llvm::PMStack &pass_mgr_stack,
+ llvm::PassManagerType pass_mgr_type = llvm::PMT_ModulePassManager);
+
+ //------------------------------------------------------------------
+ /// Returns PMT_ModulePassManager
+ ///
+ /// Implementation of the llvm::ModulePass::getPotentialPassManagerType()
+ /// function.
+ //------------------------------------------------------------------
+ virtual llvm::PassManagerType
+ getPotentialPassManagerType() const;
+
+private:
+ //------------------------------------------------------------------
+ /// Ensures that the current function's linkage is set to external.
+ /// Otherwise the JIT may not return an address for it.
+ ///
+ /// @param[in] llvm_function
+ /// The function whose linkage is to be fixed.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ FixFunctionLinkage (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to replace all function pointers with their
+ /// integer equivalents.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_module
+ /// The module currently being processed.
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ bool
+ HasSideEffects (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to check whether the function has side
+ /// effects.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Get the address of a fuction, and a location to put the complete
+ /// Value of the function if one is available.
+ ///
+ /// @param[in] function
+ /// The function to find the location of.
+ ///
+ /// @param[out] ptr
+ /// The location of the function in the target.
+ ///
+ /// @param[out] name
+ /// The resolved name of the function (matters for intrinsics).
+ ///
+ /// @param[out] value_ptr
+ /// A variable to put the function's completed Value* in, or NULL
+ /// if the Value* shouldn't be stored anywhere.
+ ///
+ /// @return
+ /// The pointer.
+ //------------------------------------------------------------------
+ bool
+ GetFunctionAddress (llvm::Function *function,
+ uint64_t &ptr,
+ lldb_private::ConstString &name,
+ llvm::Constant **&value_ptr);
+
+ //------------------------------------------------------------------
+ /// Build a function pointer given a type and a raw pointer.
+ ///
+ /// @param[in] type
+ /// The type of the function pointer to be built.
+ ///
+ /// @param[in] ptr
+ /// The value of the pointer.
+ ///
+ /// @return
+ /// The pointer.
+ //------------------------------------------------------------------
+ llvm::Constant *
+ BuildFunctionPointer (llvm::Type *type,
+ uint64_t ptr);
+
+ void
+ RegisterFunctionMetadata (llvm::LLVMContext &context,
+ llvm::Value *function_ptr,
+ const char *name);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True if the function has side effects (or if this cannot
+ /// be determined); false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveFunctionPointers (llvm::Module &llvm_module);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to take the generated global value
+ /// $__lldb_expr_result and make it into a persistent variable.
+ /// Also see ASTResultSynthesizer.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Find the NamedDecl corresponding to a Value. This interface is
+ /// exposed for the IR interpreter.
+ ///
+ /// @param[in] module
+ /// The module containing metadata to search
+ ///
+ /// @param[in] global
+ /// The global entity to search for
+ ///
+ /// @return
+ /// The corresponding variable declaration
+ //------------------------------------------------------------------
+public:
+ static clang::NamedDecl *
+ DeclForGlobal (const llvm::GlobalValue *global_val, llvm::Module *module);
+private:
+ clang::NamedDecl *
+ DeclForGlobal (llvm::GlobalValue *global);
+
+ //------------------------------------------------------------------
+ /// Set the constant result variable m_const_result to the provided
+ /// constant, assuming it can be evaluated. The result variable
+ /// will be reset to NULL later if the expression has side effects.
+ ///
+ /// @param[in] initializer
+ /// The constant initializer for the variable.
+ ///
+ /// @param[in] name
+ /// The name of the result variable.
+ ///
+ /// @param[in] type
+ /// The Clang type of the result variable.
+ //------------------------------------------------------------------
+ void
+ MaybeSetConstantResult (llvm::Constant *initializer,
+ const lldb_private::ConstString &name,
+ lldb_private::TypeFromParser type);
+
+ //------------------------------------------------------------------
+ /// If the IR represents a cast of a variable, set m_const_result
+ /// to the result of the cast. The result variable will be reset to
+ /// NULL latger if the expression has side effects.
+ ///
+ /// @param[in] type
+ /// The Clang type of the result variable.
+ //------------------------------------------------------------------
+ void
+ MaybeSetCastResult (lldb_private::TypeFromParser type);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ CreateResultVariable (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to find Objective-C constant strings and
+ /// transform them to calls to CFStringCreateWithBytes.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Rewrite a single Objective-C constant string.
+ ///
+ /// @param[in] NSStr
+ /// The constant NSString to be transformed
+ ///
+ /// @param[in] CStr
+ /// The constant C string inside the NSString. This will be
+ /// passed as the bytes argument to CFStringCreateWithBytes.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RewriteObjCConstString (llvm::GlobalVariable *NSStr,
+ llvm::GlobalVariable *CStr);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RewriteObjCConstStrings ();
+
+ //------------------------------------------------------------------
+ /// A basic block-level pass to find all Objective-C method calls and
+ /// rewrite them to use sel_registerName instead of statically allocated
+ /// selectors. The reason is that the selectors are created on the
+ /// assumption that the Objective-C runtime will scan the appropriate
+ /// section and prepare them. This doesn't happen when code is copied
+ /// into the target, though, and there's no easy way to induce the
+ /// runtime to scan them. So instead we get our selectors from
+ /// sel_registerName.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Replace a single selector reference
+ ///
+ /// @param[in] selector_load
+ /// The load of the statically-allocated selector.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RewriteObjCSelector (llvm::Instruction* selector_load);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RewriteObjCSelectors (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// A basic block-level pass to find all newly-declared persistent
+ /// variables and register them with the ClangExprDeclMap. This
+ /// allows them to be materialized and dematerialized like normal
+ /// external variables. Before transformation, these persistent
+ /// variables look like normal locals, so they have an allocation.
+ /// This pass excises these allocations and makes references look
+ /// like external references where they will be resolved -- like all
+ /// other external references -- by ResolveExternals().
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Handle a single allocation of a persistent variable
+ ///
+ /// @param[in] persistent_alloc
+ /// The allocation of the persistent variable.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RewritePersistentAlloc (llvm::Instruction *persistent_alloc);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ //------------------------------------------------------------------
+ bool
+ RewritePersistentAllocs (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to find all external variables and functions
+ /// used in the IR. Each found external variable is added to the
+ /// struct, and each external function is resolved in place, its call
+ /// replaced with a call to a function pointer whose value is the
+ /// address of the function in the target process.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Write an initializer to a memory array of assumed sufficient
+ /// size.
+ ///
+ /// @param[in] data
+ /// A pointer to the data to write to.
+ ///
+ /// @param[in] initializer
+ /// The initializer itself.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaterializeInitializer (uint8_t *data, llvm::Constant *initializer);
+
+ //------------------------------------------------------------------
+ /// Move an internal variable into the static allocation section.
+ ///
+ /// @param[in] global_variable
+ /// The variable.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaterializeInternalVariable (llvm::GlobalVariable *global_variable);
+
+ //------------------------------------------------------------------
+ /// Handle a single externally-defined variable
+ ///
+ /// @param[in] value
+ /// The variable.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaybeHandleVariable (llvm::Value *value);
+
+ //------------------------------------------------------------------
+ /// Handle a single externally-defined symbol
+ ///
+ /// @param[in] symbol
+ /// The symbol.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ HandleSymbol (llvm::Value *symbol);
+
+ //------------------------------------------------------------------
+ /// Handle a single externally-defined Objective-C class
+ ///
+ /// @param[in] classlist_reference
+ /// The reference, usually "01L_OBJC_CLASSLIST_REFERENCES_$_n"
+ /// where n (if present) is an index.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ HandleObjCClass(llvm::Value *classlist_reference);
+
+ //------------------------------------------------------------------
+ /// Handle all the arguments to a function call
+ ///
+ /// @param[in] C
+ /// The call instruction.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ MaybeHandleCallArguments (llvm::CallInst *call_inst);
+
+ //------------------------------------------------------------------
+ /// Resolve variable references in calls to external functions
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ResolveCalls (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// Remove calls to __cxa_atexit, which should never be generated by
+ /// expressions.
+ ///
+ /// @param[in] call_inst
+ /// The call instruction.
+ ///
+ /// @return
+ /// True if the scan was successful; false if some operation
+ /// failed
+ //------------------------------------------------------------------
+ bool
+ RemoveCXAAtExit (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ResolveExternals (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A basic block-level pass to excise guard variables from the code.
+ /// The result for the function is passed through Clang as a static
+ /// variable. Static variables normally have guard variables to
+ /// ensure that they are only initialized once.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Rewrite a load to a guard variable to return constant 0.
+ ///
+ /// @param[in] guard_load
+ /// The load instruction to zero out.
+ //------------------------------------------------------------------
+ void
+ TurnGuardLoadIntoZero(llvm::Instruction* guard_load);
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ RemoveGuards (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to allocate all string literals in a separate
+ /// allocation and redirect references to them.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ReplaceStrings ();
+
+ //------------------------------------------------------------------
+ /// A basick block-level pass to find all literals that will be
+ /// allocated as statics by the JIT (in contrast to the Strings,
+ /// which already are statics) and synthesize loads for them.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] basic_block
+ /// The basic block currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ReplaceStaticLiterals (llvm::BasicBlock &basic_block);
+
+ //------------------------------------------------------------------
+ /// A function-level pass to make all external variable references
+ /// point at the correct offsets from the void* passed into the
+ /// function. ClangExpressionDeclMap::DoStructLayout() must be called
+ /// beforehand, so that the offsets are valid.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ ReplaceVariables (llvm::Function &llvm_function);
+
+ //------------------------------------------------------------------
+ /// A module-level pass to remove all global variables from the
+ /// module since it no longer should export or import any symbols.
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// The top-level pass implementation
+ ///
+ /// @param[in] llvm_module
+ /// The module currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ StripAllGVs (llvm::Module &llvm_module);
+
+ class StaticDataAllocator {
+ public:
+ StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit);
+ lldb_private::StreamString &GetStream()
+ {
+ return m_stream_string;
+ }
+ lldb::addr_t Allocate();
+ private:
+ lldb_private::IRExecutionUnit &m_execution_unit;
+ lldb_private::StreamString m_stream_string;
+ lldb::addr_t m_allocation;
+ };
+
+ /// Flags
+ bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved
+ std::string m_func_name; ///< The name of the function to translate
+ lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...)
+ lldb_private::TypeFromParser m_result_type; ///< The type of the result variable.
+ llvm::Module *m_module; ///< The module being processed, or NULL if that has not been determined yet.
+ std::unique_ptr<llvm::DataLayout> m_target_data; ///< The target data for the module being processed, or NULL if there is no module.
+ lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls
+ StaticDataAllocator m_data_allocator; ///< The allocator to use for constant strings
+ llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type
+ llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type
+ lldb_private::Stream *m_error_stream; ///< If non-NULL, the stream on which errors should be printed
+
+ llvm::StoreInst *m_result_store; ///< If non-NULL, the store instruction that writes to the result variable. If m_has_side_effects is true, this is NULL.
+ bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult)
+
+ llvm::GlobalVariable *m_reloc_placeholder; ///< A placeholder that will be replaced by a pointer to the final location of the static allocation.
+
+ //------------------------------------------------------------------
+ /// UnfoldConstant operates on a constant [Old] which has just been
+ /// replaced with a value [New]. We assume that new_value has
+ /// been properly placed early in the function, in front of the
+ /// first instruction in the entry basic block
+ /// [FirstEntryInstruction].
+ ///
+ /// UnfoldConstant reads through the uses of Old and replaces Old
+ /// in those uses with New. Where those uses are constants, the
+ /// function generates new instructions to compute the result of the
+ /// new, non-constant expression and places them before
+ /// FirstEntryInstruction. These instructions replace the constant
+ /// uses, so UnfoldConstant calls itself recursively for those.
+ ///
+ /// @param[in] llvm_function
+ /// The function currently being processed.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+
+ class FunctionValueCache {
+ public:
+ typedef std::function <llvm::Value *(llvm::Function *)> Maker;
+
+ FunctionValueCache (Maker const &maker);
+ ~FunctionValueCache ();
+ llvm::Value *GetValue (llvm::Function *function);
+ private:
+ Maker const m_maker;
+ typedef std::map<llvm::Function *, llvm::Value *> FunctionValueMap;
+ FunctionValueMap m_values;
+ };
+
+ FunctionValueCache m_entry_instruction_finder;
+
+ static bool
+ UnfoldConstant (llvm::Constant *old_constant,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder);
+
+ //------------------------------------------------------------------
+ /// Construct a reference to m_reloc_placeholder with a given type
+ /// and offset. This typically happens after inserting data into
+ /// m_data_allocator.
+ ///
+ /// @param[in] type
+ /// The type of the value being loaded.
+ ///
+ /// @param[in] offset
+ /// The offset of the value from the base of m_data_allocator.
+ ///
+ /// @return
+ /// The Constant for the reference, usually a ConstantExpr.
+ //------------------------------------------------------------------
+ llvm::Constant *
+ BuildRelocation(llvm::Type *type,
+ uint64_t offset);
+
+ //------------------------------------------------------------------
+ /// Commit the allocation in m_data_allocator and use its final
+ /// location to replace m_reloc_placeholder.
+ ///
+ /// @param[in] module
+ /// The module that m_data_allocator resides in
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool
+ CompleteDataAllocation ();
+
+};
+
+#endif
diff --git a/include/lldb/Expression/IRInterpreter.h b/include/lldb/Expression/IRInterpreter.h
new file mode 100644
index 000000000000..5defa8dd2026
--- /dev/null
+++ b/include/lldb/Expression/IRInterpreter.h
@@ -0,0 +1,64 @@
+//===-- IRInterpreter.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_IRInterpreter_h_
+#define liblldb_IRInterpreter_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Pass.h"
+
+namespace llvm {
+ class Function;
+ class Module;
+}
+
+namespace lldb_private {
+
+class ClangExpressionDeclMap;
+class IRMemoryMap;
+
+}
+
+//----------------------------------------------------------------------
+/// @class IRInterpreter IRInterpreter.h "lldb/Expression/IRInterpreter.h"
+/// @brief Attempt to interpret the function's code if it does not require
+/// running the target.
+///
+/// In some cases, the IR for an expression can be evaluated entirely
+/// in the debugger, manipulating variables but not executing any code
+/// in the target. The IRInterpreter attempts to do this.
+//----------------------------------------------------------------------
+class IRInterpreter
+{
+public:
+ static bool
+ CanInterpret (llvm::Module &module,
+ llvm::Function &function,
+ lldb_private::Error &error);
+
+ static bool
+ Interpret (llvm::Module &module,
+ llvm::Function &function,
+ llvm::ArrayRef<lldb::addr_t> args,
+ lldb_private::IRMemoryMap &memory_map,
+ lldb_private::Error &error,
+ lldb::addr_t stack_frame_bottom,
+ lldb::addr_t stack_frame_top);
+
+private:
+ static bool
+ supportsFunction (llvm::Function &llvm_function,
+ lldb_private::Error &err);
+};
+
+#endif
diff --git a/include/lldb/Expression/IRMemoryMap.h b/include/lldb/Expression/IRMemoryMap.h
new file mode 100644
index 000000000000..affe19350e3f
--- /dev/null
+++ b/include/lldb/Expression/IRMemoryMap.h
@@ -0,0 +1,126 @@
+//===-- IRExecutionUnit.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_IRMemoryMap_h_
+#define lldb_IRMemoryMap_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/UserID.h"
+
+#include <map>
+
+namespace lldb_private
+{
+
+//----------------------------------------------------------------------
+/// @class IRMemoryMap IRMemoryMap.h "lldb/Expression/IRMemoryMap.h"
+/// @brief Encapsulates memory that may exist in the process but must
+/// also be available in the host process.
+///
+/// This class encapsulates a group of memory objects that must be readable
+/// or writable from the host process regardless of whether the process
+/// exists. This allows the IR interpreter as well as JITted code to access
+/// the same memory.
+///
+/// Point queries against this group of memory objects can be made by the
+/// address in the tar at which they reside. If the inferior does not
+/// exist, allocations still get made-up addresses. If an inferior appears
+/// at some point, then those addresses need to be re-mapped.
+//----------------------------------------------------------------------
+class IRMemoryMap
+{
+public:
+ IRMemoryMap (lldb::TargetSP target_sp);
+ ~IRMemoryMap ();
+
+ enum AllocationPolicy {
+ eAllocationPolicyInvalid = 0, ///< It is an error for an allocation to have this policy.
+ eAllocationPolicyHostOnly, ///< This allocation was created in the host and will never make it into the process.
+ ///< It is an error to create other types of allocations while such allocations exist.
+ eAllocationPolicyMirror, ///< The intent is that this allocation exist both in the host and the process and have
+ ///< the same content in both.
+ eAllocationPolicyProcessOnly ///< The intent is that this allocation exist only in the process.
+ };
+
+ lldb::addr_t Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error);
+ void Leak (lldb::addr_t process_address, Error &error);
+ void Free (lldb::addr_t process_address, Error &error);
+
+ void WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error);
+ void WriteScalarToMemory (lldb::addr_t process_address, Scalar &scalar, size_t size, Error &error);
+ void WritePointerToMemory (lldb::addr_t process_address, lldb::addr_t address, Error &error);
+ void ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error);
+ void ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error);
+ void ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error);
+
+ void GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error);
+
+ lldb::ByteOrder GetByteOrder();
+ uint32_t GetAddressByteSize();
+
+ // This function can return NULL.
+ ExecutionContextScope *GetBestExecutionContextScope();
+
+protected:
+ // This function should only be used if you know you are using the JIT.
+ // Any other cases should use GetBestExecutionContextScope().
+ lldb::ProcessWP GetProcessWP ()
+ {
+ return m_process_wp;
+ }
+
+private:
+ struct Allocation
+ {
+ lldb::addr_t m_process_alloc; ///< The (unaligned) base for the remote allocation
+ lldb::addr_t m_process_start; ///< The base address of the allocation in the process
+ size_t m_size; ///< The size of the requested allocation
+ uint32_t m_permissions; ///< The access permissions on the memory in the process. In the host, the memory is always read/write.
+ uint8_t m_alignment; ///< The alignment of the requested allocation
+ DataBufferHeap m_data;
+
+ ///< Flags
+ AllocationPolicy m_policy;
+ bool m_leak;
+ public:
+ Allocation (lldb::addr_t process_alloc,
+ lldb::addr_t process_start,
+ size_t size,
+ uint32_t permissions,
+ uint8_t alignment,
+ AllocationPolicy m_policy);
+
+ Allocation () :
+ m_process_alloc (LLDB_INVALID_ADDRESS),
+ m_process_start (LLDB_INVALID_ADDRESS),
+ m_size (0),
+ m_permissions (0),
+ m_alignment (0),
+ m_data (),
+ m_policy (eAllocationPolicyInvalid),
+ m_leak (false)
+ {
+ }
+ };
+
+ lldb::ProcessWP m_process_wp;
+ lldb::TargetWP m_target_wp;
+ typedef std::map<lldb::addr_t, Allocation> AllocationMap;
+ AllocationMap m_allocations;
+
+ lldb::addr_t FindSpace (size_t size);
+ bool ContainsHostOnlyAllocations ();
+ AllocationMap::iterator FindAllocation (lldb::addr_t addr, size_t size);
+ bool IntersectsAllocation (lldb::addr_t addr, size_t size);
+};
+
+}
+
+#endif
diff --git a/include/lldb/Expression/IRToDWARF.h b/include/lldb/Expression/IRToDWARF.h
new file mode 100644
index 000000000000..43dc99d6d476
--- /dev/null
+++ b/include/lldb/Expression/IRToDWARF.h
@@ -0,0 +1,111 @@
+//===-- IRToDWARF.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_IRToDWARF_h_
+#define liblldb_IRToDWARF_h_
+
+#include "llvm/Pass.h"
+#include "llvm/PassManager.h"
+
+#include "lldb/lldb-public.h"
+
+class Relocator;
+//----------------------------------------------------------------------
+/// @class IRToDWARF IRToDWARF.h "lldb/Expression/IRToDWARF.h"
+/// @brief Transforms the IR for a function into a DWARF location expression
+///
+/// Once an expression has been parsed and converted to IR, it can run
+/// in two contexts: interpreted by LLDB as a DWARF location expression,
+/// or compiled by the JIT and inserted into the target process for
+/// execution.
+///
+/// IRToDWARF makes the first possible, by traversing the control flow
+/// graph and writing the code for each basic block out as location
+/// expression bytecode. To ensure that the links between the basic blocks
+/// remain intact, it uses a relocator that records the location of every
+/// location expression instruction that has a relocatable operand, the
+/// target of that operand (as a basic block), and the mapping of each basic
+/// block to an actual location. After all code has been written out, the
+/// relocator post-processes it and performs all necessary relocations.
+//----------------------------------------------------------------------
+class IRToDWARF : public llvm::ModulePass
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] local_vars
+ /// A list of variables to populate with the local variables this
+ /// expression uses.
+ ///
+ /// @param[in] decl_map
+ /// The list of externally-referenced variables for the expression,
+ /// for use in looking up globals.
+ ///
+ /// @param[in] stream
+ /// The stream to dump DWARF bytecode onto.
+ ///
+ /// @param[in] func_name
+ /// The name of the function to translate to DWARF.
+ //------------------------------------------------------------------
+ IRToDWARF(lldb_private::ClangExpressionVariableList &local_vars,
+ lldb_private::ClangExpressionDeclMap *decl_map,
+ lldb_private::StreamString &strm,
+ const char* func_name = "$__lldb_expr");
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual ~IRToDWARF();
+
+ //------------------------------------------------------------------
+ /// Run this IR transformer on a single module
+ ///
+ /// @param[in] M
+ /// The module to run on. This module is searched for the function
+ /// $__lldb_expr, and that function is converted to a location
+ /// expression.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool runOnModule(llvm::Module &M);
+
+ //------------------------------------------------------------------
+ /// Interface stub
+ //------------------------------------------------------------------
+ void assignPassManager(llvm::PMStack &PMS,
+ llvm::PassManagerType T = llvm::PMT_ModulePassManager);
+
+ //------------------------------------------------------------------
+ /// Returns PMT_ModulePassManager
+ //------------------------------------------------------------------
+ llvm::PassManagerType getPotentialPassManagerType() const;
+private:
+ //------------------------------------------------------------------
+ /// Run this IR transformer on a single basic block
+ ///
+ /// @param[in] BB
+ /// The basic block to transform.
+ ///
+ /// @param[in] Relocator
+ /// The relocator to use when registering branches.
+ ///
+ /// @return
+ /// True on success; false otherwise
+ //------------------------------------------------------------------
+ bool runOnBasicBlock(llvm::BasicBlock &BB, Relocator &Relocator);
+
+ std::string m_func_name; ///< The name of the function to translate
+ lldb_private::ClangExpressionVariableList &m_local_vars; ///< The list of local variables to populate while transforming
+ lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The list of external variables
+ lldb_private::StreamString &m_strm; ///< The stream to write bytecode to
+};
+
+#endif
diff --git a/include/lldb/Expression/Materializer.h b/include/lldb/Expression/Materializer.h
new file mode 100644
index 000000000000..208a08133923
--- /dev/null
+++ b/include/lldb/Expression/Materializer.h
@@ -0,0 +1,173 @@
+//===-- Materializer.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Materializer_h
+#define lldb_Materializer_h
+
+#include "lldb/lldb-private-types.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/StackFrame.h"
+
+#include <vector>
+
+namespace lldb_private
+{
+
+class Materializer
+{
+public:
+ Materializer ();
+ ~Materializer ();
+
+ class Dematerializer
+ {
+ public:
+ Dematerializer () :
+ m_materializer(NULL),
+ m_map(NULL),
+ m_process_address(LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ ~Dematerializer ()
+ {
+ Wipe ();
+ }
+
+ void Dematerialize (Error &err,
+ lldb::ClangExpressionVariableSP &result_sp,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom);
+
+ void Wipe ();
+
+ bool IsValid ()
+ {
+ return m_materializer && m_map && (m_process_address != LLDB_INVALID_ADDRESS);
+ }
+ private:
+ friend class Materializer;
+
+ Dematerializer (Materializer &materializer,
+ lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address) :
+ m_materializer(&materializer),
+ m_map(&map),
+ m_process_address(process_address)
+ {
+ if (frame_sp)
+ {
+ m_thread_wp = frame_sp->GetThread();
+ m_stack_id = frame_sp->GetStackID();
+ }
+ }
+
+ Materializer *m_materializer;
+ lldb::ThreadWP m_thread_wp;
+ StackID m_stack_id;
+ IRMemoryMap *m_map;
+ lldb::addr_t m_process_address;
+ };
+
+ typedef std::shared_ptr<Dematerializer> DematerializerSP;
+ typedef std::weak_ptr<Dematerializer> DematerializerWP;
+
+ DematerializerSP Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err);
+
+ uint32_t AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err);
+ uint32_t AddVariable (lldb::VariableSP &variable_sp, Error &err);
+ uint32_t AddResultVariable (const TypeFromUser &type, bool is_lvalue, bool keep_in_memory, Error &err);
+ uint32_t AddSymbol (const Symbol &symbol_sp, Error &err);
+ uint32_t AddRegister (const RegisterInfo &register_info, Error &err);
+
+ uint32_t GetStructAlignment ()
+ {
+ return m_struct_alignment;
+ }
+
+ uint32_t GetStructByteSize ()
+ {
+ return m_current_offset;
+ }
+
+ uint32_t GetResultOffset ()
+ {
+ if (m_result_entity)
+ return m_result_entity->GetOffset();
+ else
+ return UINT32_MAX;
+ }
+
+ class Entity
+ {
+ public:
+ Entity () :
+ m_alignment(1),
+ m_size(0),
+ m_offset(0)
+ {
+ }
+
+ virtual ~Entity ()
+ {
+ }
+
+ virtual void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err) = 0;
+ virtual void Dematerialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address,
+ lldb::addr_t frame_top, lldb::addr_t frame_bottom, Error &err) = 0;
+ virtual void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log) = 0;
+ virtual void Wipe (IRMemoryMap &map, lldb::addr_t process_address) = 0;
+
+ uint32_t GetAlignment ()
+ {
+ return m_alignment;
+ }
+
+ uint32_t GetSize ()
+ {
+ return m_size;
+ }
+
+ uint32_t GetOffset ()
+ {
+ return m_offset;
+ }
+
+ void SetOffset (uint32_t offset)
+ {
+ m_offset = offset;
+ }
+ protected:
+ void SetSizeAndAlignmentFromType (ClangASTType &type);
+
+ uint32_t m_alignment;
+ uint32_t m_size;
+ uint32_t m_offset;
+ };
+
+private:
+ uint32_t AddStructMember (Entity &entity);
+
+ typedef std::unique_ptr<Entity> EntityUP;
+ typedef std::vector<EntityUP> EntityVector;
+
+ DematerializerWP m_dematerializer_wp;
+ EntityVector m_entities;
+ Entity *m_result_entity;
+ uint32_t m_current_offset;
+ uint32_t m_struct_alignment;
+};
+
+}
+
+#endif
diff --git a/include/lldb/Host/Condition.h b/include/lldb/Host/Condition.h
new file mode 100644
index 000000000000..98439ee2ebdf
--- /dev/null
+++ b/include/lldb/Host/Condition.h
@@ -0,0 +1,124 @@
+//===-- Condition.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_DBCondition_h_
+#define liblldb_DBCondition_h_
+#if defined(__cplusplus)
+
+
+#include <pthread.h>
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class TimeValue;
+
+//----------------------------------------------------------------------
+/// @class Condition Condition.h "lldb/Host/Condition.h"
+/// @brief A C++ wrapper class for pthread condition variables.
+///
+/// A class that wraps up a pthread condition (pthread_cond_t). The
+/// class will create a pthread condition when an instance is
+/// constructed, and detroy it when it is destructed. It also provides
+/// access to the standard pthread condition calls.
+//----------------------------------------------------------------------
+class Condition
+{
+public:
+
+ //------------------------------------------------------------------
+ /// Default constructor
+ ///
+ /// The default constructor will initialize a new pthread condition
+ /// and maintain the condition in the object state.
+ //------------------------------------------------------------------
+ Condition ();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// Destroys the pthread condition that the object owns.
+ //------------------------------------------------------------------
+ ~Condition ();
+
+ //------------------------------------------------------------------
+ /// Unblock all threads waiting for a condition variable
+ ///
+ /// @return
+ /// The return value from \c pthread_cond_broadcast()
+ //------------------------------------------------------------------
+ int
+ Broadcast ();
+
+ //------------------------------------------------------------------
+ /// Unblocks one thread waiting for the condition variable
+ ///
+ /// @return
+ /// The return value from \c pthread_cond_signal()
+ //------------------------------------------------------------------
+ int
+ Signal ();
+
+ //------------------------------------------------------------------
+ /// Wait for the condition variable to be signaled.
+ ///
+ /// The Wait() function atomically blocks the current thread
+ /// waiting on this object's condition variable, and unblocks
+ /// \a mutex. The waiting thread unblocks only after another thread
+ /// signals or broadcasts this object's condition variable.
+ ///
+ /// If \a abstime is non-NULL, this function will return when the
+ /// system time reaches the time specified in \a abstime if the
+ /// condition variable doesn't get unblocked. If \a abstime is NULL
+ /// this function will wait for an infinite amount of time for the
+ /// condition variable to be unblocked.
+ ///
+ /// The current thread re-acquires the lock on \a mutex following
+ /// the wait.
+ ///
+ /// @param[in] mutex
+ /// The mutex to use in the \c pthread_cond_timedwait() or
+ /// \c pthread_cond_wait() calls.
+ ///
+ /// @param[in] abstime
+ /// An absolute time at which to stop waiting if non-NULL, else
+ /// wait an infinite amount of time for the condition variable
+ /// toget signaled.
+ ///
+ /// @param[out] timed_out
+ /// If not NULL, will be set to true if the wait timed out, and
+ // false otherwise.
+ ///
+ /// @see Condition::Broadcast()
+ /// @see Condition::Signal()
+ //------------------------------------------------------------------
+ int
+ Wait (Mutex &mutex, const TimeValue *abstime = NULL, bool *timed_out = NULL);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ pthread_cond_t m_condition; ///< The condition variable.
+
+ //------------------------------------------------------------------
+ /// Get accessor to the pthread condition object.
+ ///
+ /// @return
+ /// A pointer to the condition variable owned by this object.
+ //------------------------------------------------------------------
+ pthread_cond_t *
+ GetCondition ();
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif
+
diff --git a/include/lldb/Host/Config.h b/include/lldb/Host/Config.h
new file mode 100644
index 000000000000..2d5d39baac3d
--- /dev/null
+++ b/include/lldb/Host/Config.h
@@ -0,0 +1,35 @@
+//===-- Config.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_Config_h_
+#define liblldb_Config_h_
+
+#if defined(__APPLE__)
+
+#include "lldb/Host/macosx/Config.h"
+
+#elif defined(__linux__)
+
+#include "lldb/Host/linux/Config.h"
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__)
+
+#include "lldb/Host/freebsd/Config.h"
+
+#elif defined(__MINGW__) || defined (__MINGW32__)
+
+#include "lldb/Host/mingw/Config.h"
+
+#else
+
+#error undefined platform
+
+#endif
+
+#endif // #ifndef liblldb_Config_h_
diff --git a/include/lldb/Host/DynamicLibrary.h b/include/lldb/Host/DynamicLibrary.h
new file mode 100644
index 000000000000..1fcc7d1883cf
--- /dev/null
+++ b/include/lldb/Host/DynamicLibrary.h
@@ -0,0 +1,51 @@
+//===-- DynamicLibrary.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLibrary_h_
+#define liblldb_DynamicLibrary_h_
+
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+
+namespace lldb_private {
+
+class DynamicLibrary
+{
+public:
+ DynamicLibrary (const FileSpec& spec, uint32_t options = Host::eDynamicLibraryOpenOptionLazy |
+ Host::eDynamicLibraryOpenOptionLocal |
+ Host::eDynamicLibraryOpenOptionLimitGetSymbol);
+
+ ~DynamicLibrary ();
+
+ template <typename T = void*>
+ T GetSymbol (const char* name)
+ {
+ Error err;
+ if (!m_handle)
+ return (T)NULL;
+ void* symbol = Host::DynamicLibraryGetSymbol (m_handle, name, err);
+ if (!symbol)
+ return (T)NULL;
+ return (T)symbol;
+ }
+
+ bool
+ IsValid ();
+
+private:
+ lldb_private::FileSpec m_filespec;
+ void* m_handle;
+
+ DISALLOW_COPY_AND_ASSIGN (DynamicLibrary);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DynamicLibrary_h_
diff --git a/include/lldb/Host/Endian.h b/include/lldb/Host/Endian.h
new file mode 100644
index 000000000000..610f3ce95c41
--- /dev/null
+++ b/include/lldb/Host/Endian.h
@@ -0,0 +1,33 @@
+//===-- Endian.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_host_endian_h_
+#define liblldb_host_endian_h_
+
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb {
+
+namespace endian {
+
+ static union EndianTest
+ {
+ uint32_t num;
+ uint8_t bytes[sizeof(uint32_t)];
+ } const endianTest = { (uint16_t)0x01020304 };
+
+ inline ByteOrder InlHostByteOrder() { return (ByteOrder)endianTest.bytes[0]; }
+
+// ByteOrder const InlHostByteOrder = (ByteOrder)endianTest.bytes[0];
+}
+
+}
+
+#endif // liblldb_host_endian_h_
+
diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h
new file mode 100644
index 000000000000..df7fe92cccba
--- /dev/null
+++ b/include/lldb/Host/File.h
@@ -0,0 +1,500 @@
+//===-- File.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_File_h_
+#define liblldb_File_h_
+#if defined(__cplusplus)
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class File File.h "lldb/Host/File.h"
+/// @brief A file class.
+///
+/// A file class that divides abstracts the LLDB core from host file
+/// functionality.
+//----------------------------------------------------------------------
+class File
+{
+public:
+ static int kInvalidDescriptor;
+ static FILE * kInvalidStream;
+
+ enum OpenOptions
+ {
+ eOpenOptionRead = (1u << 0), // Open file for reading
+ eOpenOptionWrite = (1u << 1), // Open file for writing
+ eOpenOptionAppend = (1u << 2), // Don't truncate file when opening, append to end of file
+ eOpenOptionTruncate = (1u << 3), // Truncate file when opening
+ eOpenOptionNonBlocking = (1u << 4), // File reads
+ eOpenOptionCanCreate = (1u << 5), // Create file if doesn't already exist
+ eOpenOptionCanCreateNewOnly = (1u << 6) // Can create file only if it doesn't already exist
+ };
+
+ enum Permissions
+ {
+ ePermissionsUserRead = (1u << 0),
+ ePermissionsUserWrite = (1u << 1),
+ ePermissionsUserExecute = (1u << 2),
+ ePermissionsGroupRead = (1u << 3),
+ ePermissionsGroupWrite = (1u << 4),
+ ePermissionsGroupExecute = (1u << 5),
+ ePermissionsWorldRead = (1u << 6),
+ ePermissionsWorldWrite = (1u << 7),
+ ePermissionsWorldExecute = (1u << 8),
+
+ ePermissionsUserRW = (ePermissionsUserRead | ePermissionsUserWrite | 0 ),
+ ePermissionsUserRX = (ePermissionsUserRead | 0 | ePermissionsUserExecute ),
+ ePermissionsUserRWX = (ePermissionsUserRead | ePermissionsUserWrite | ePermissionsUserExecute ),
+
+ ePermissionsGroupRW = (ePermissionsGroupRead | ePermissionsGroupWrite | 0 ),
+ ePermissionsGroupRX = (ePermissionsGroupRead | 0 | ePermissionsGroupExecute ),
+ ePermissionsGroupRWX = (ePermissionsGroupRead | ePermissionsGroupWrite | ePermissionsGroupExecute ),
+
+ ePermissionsWorldRW = (ePermissionsWorldRead | ePermissionsWorldWrite | 0 ),
+ ePermissionsWorldRX = (ePermissionsWorldRead | 0 | ePermissionsWorldExecute ),
+ ePermissionsWorldRWX = (ePermissionsWorldRead | ePermissionsWorldWrite | ePermissionsWorldExecute ),
+
+ ePermissionsEveryoneR = (ePermissionsUserRead | ePermissionsGroupRead | ePermissionsWorldRead ),
+ ePermissionsEveryoneW = (ePermissionsUserWrite | ePermissionsGroupWrite | ePermissionsWorldWrite ),
+ ePermissionsEveryoneX = (ePermissionsUserExecute | ePermissionsGroupExecute | ePermissionsWorldExecute ),
+
+ ePermissionsEveryoneRW = (ePermissionsEveryoneR | ePermissionsEveryoneW | 0 ),
+ ePermissionsEveryoneRX = (ePermissionsEveryoneR | 0 | ePermissionsEveryoneX ),
+ ePermissionsEveryoneRWX = (ePermissionsEveryoneR | ePermissionsEveryoneW | ePermissionsEveryoneX ),
+ ePermissionsDefault = (ePermissionsUserRW | ePermissionsGroupRead)
+ };
+
+ File() :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+ {
+ }
+
+ File (FILE *fh, bool transfer_ownership) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (fh),
+ m_options (0),
+ m_owned (transfer_ownership)
+ {
+ }
+
+ File (const File &rhs);
+
+ File &
+ operator= (const File &rhs);
+ //------------------------------------------------------------------
+ /// Constructor with path.
+ ///
+ /// Takes a path to a file which can be just a filename, or a full
+ /// path. If \a path is not NULL or empty, this function will call
+ /// File::Open (const char *path, uint32_t options, uint32_t permissions).
+ ///
+ /// @param[in] path
+ /// The full or partial path to a file.
+ ///
+ /// @param[in] options
+ /// Options to use when opening (see File::OpenOptions)
+ ///
+ /// @param[in] permissions
+ /// Options to use when opening (see File::Permissions)
+ ///
+ /// @see File::Open (const char *path, uint32_t options, uint32_t permissions)
+ //------------------------------------------------------------------
+ File (const char *path,
+ uint32_t options,
+ uint32_t permissions = ePermissionsDefault);
+
+
+ File (int fd, bool tranfer_ownership) :
+ m_descriptor (fd),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (tranfer_ownership)
+ {
+ }
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual in case this class is subclassed.
+ //------------------------------------------------------------------
+ virtual
+ ~File ();
+
+ bool
+ IsValid () const
+ {
+ return DescriptorIsValid() || StreamIsValid();
+ }
+
+ //------------------------------------------------------------------
+ /// Convert to pointer operator.
+ ///
+ /// This allows code to check a File object to see if it
+ /// contains anything valid using code such as:
+ ///
+ /// @code
+ /// File file(...);
+ /// if (file)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// A pointer to this object if either the directory or filename
+ /// is valid, NULL otherwise.
+ //------------------------------------------------------------------
+ operator
+ bool () const
+ {
+ return DescriptorIsValid() || StreamIsValid();
+ }
+
+ //------------------------------------------------------------------
+ /// Logical NOT operator.
+ ///
+ /// This allows code to check a File object to see if it is
+ /// invalid using code such as:
+ ///
+ /// @code
+ /// File file(...);
+ /// if (!file)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// Returns \b true if the object has an empty directory and
+ /// filename, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ operator! () const
+ {
+ return !DescriptorIsValid() && !StreamIsValid();
+ }
+
+ //------------------------------------------------------------------
+ /// Get the file spec for this file.
+ ///
+ /// @return
+ /// A reference to the file specification object.
+ //------------------------------------------------------------------
+ Error
+ GetFileSpec (FileSpec &file_spec) const;
+
+ //------------------------------------------------------------------
+ /// Open a file for read/writing with the specified options.
+ ///
+ /// Takes a path to a file which can be just a filename, or a full
+ /// path.
+ ///
+ /// @param[in] path
+ /// The full or partial path to a file.
+ ///
+ /// @param[in] options
+ /// Options to use when opening (see File::OpenOptions)
+ ///
+ /// @param[in] permissions
+ /// Options to use when opening (see File::Permissions)
+ //------------------------------------------------------------------
+ Error
+ Open (const char *path,
+ uint32_t options,
+ uint32_t permissions = ePermissionsDefault);
+
+ Error
+ Close ();
+
+ Error
+ Duplicate (const File &rhs);
+
+ int
+ GetDescriptor() const;
+
+ void
+ SetDescriptor(int fd, bool transfer_ownership);
+
+ FILE *
+ GetStream ();
+
+ void
+ SetStream (FILE *fh, bool transfer_ownership);
+
+ //------------------------------------------------------------------
+ /// Read bytes from a file from the current file position.
+ ///
+ /// NOTE: This function is NOT thread safe. Use the read function
+ /// that takes an "off_t &offset" to ensure correct operation in
+ /// multi-threaded environments.
+ ///
+ /// @param[in] buf
+ /// A buffer where to put the bytes that are read.
+ ///
+ /// @param[in/out] num_bytes
+ /// The number of bytes to read form the current file position
+ /// which gets modified with the number of bytes that were read.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Read (void *buf, size_t &num_bytes);
+
+ //------------------------------------------------------------------
+ /// Write bytes to a file at the current file position.
+ ///
+ /// NOTE: This function is NOT thread safe. Use the write function
+ /// that takes an "off_t &offset" to ensure correct operation in
+ /// multi-threaded environments.
+ ///
+ /// @param[in] buf
+ /// A buffer where to put the bytes that are read.
+ ///
+ /// @param[in/out] num_bytes
+ /// The number of bytes to write to the current file position
+ /// which gets modified with the number of bytes that were
+ /// written.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Write (const void *buf, size_t &num_bytes);
+
+ //------------------------------------------------------------------
+ /// Seek to an offset relative to the beginning of the file.
+ ///
+ /// NOTE: This function is NOT thread safe, other threads that
+ /// access this object might also change the current file position.
+ /// For thread safe reads and writes see the following functions:
+ /// @see File::Read (void *, size_t, off_t &)
+ /// @see File::Write (const void *, size_t, off_t &)
+ ///
+ /// @param[in] offset
+ /// The offset to seek to within the file relative to the
+ /// beginning of the file.
+ ///
+ /// @param[in] error_ptr
+ /// A pointer to a lldb_private::Error object that will be
+ /// filled in if non-NULL.
+ ///
+ /// @return
+ /// The resulting seek offset, or -1 on error.
+ //------------------------------------------------------------------
+ off_t
+ SeekFromStart (off_t offset, Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Seek to an offset relative to the current file position.
+ ///
+ /// NOTE: This function is NOT thread safe, other threads that
+ /// access this object might also change the current file position.
+ /// For thread safe reads and writes see the following functions:
+ /// @see File::Read (void *, size_t, off_t &)
+ /// @see File::Write (const void *, size_t, off_t &)
+ ///
+ /// @param[in] offset
+ /// The offset to seek to within the file relative to the
+ /// current file position.
+ ///
+ /// @param[in] error_ptr
+ /// A pointer to a lldb_private::Error object that will be
+ /// filled in if non-NULL.
+ ///
+ /// @return
+ /// The resulting seek offset, or -1 on error.
+ //------------------------------------------------------------------
+ off_t
+ SeekFromCurrent (off_t offset, Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Seek to an offset relative to the end of the file.
+ ///
+ /// NOTE: This function is NOT thread safe, other threads that
+ /// access this object might also change the current file position.
+ /// For thread safe reads and writes see the following functions:
+ /// @see File::Read (void *, size_t, off_t &)
+ /// @see File::Write (const void *, size_t, off_t &)
+ ///
+ /// @param[in/out] offset
+ /// The offset to seek to within the file relative to the
+ /// end of the file which gets filled in the the resulting
+ /// absolute file offset.
+ ///
+ /// @param[in] error_ptr
+ /// A pointer to a lldb_private::Error object that will be
+ /// filled in if non-NULL.
+ ///
+ /// @return
+ /// The resulting seek offset, or -1 on error.
+ //------------------------------------------------------------------
+ off_t
+ SeekFromEnd (off_t offset, Error *error_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Read bytes from a file from the specified file offset.
+ ///
+ /// NOTE: This function is thread safe in that clients manager their
+ /// own file position markers and reads on other threads won't mess
+ /// up the current read.
+ ///
+ /// @param[in] buf
+ /// A buffer where to put the bytes that are read.
+ ///
+ /// @param[in/out] num_bytes
+ /// The number of bytes to read form the current file position
+ /// which gets modified with the number of bytes that were read.
+ ///
+ /// @param[in/out] offset
+ /// The offset within the file from which to read \a num_bytes
+ /// bytes. This offset gets incremented by the number of bytes
+ /// that were read.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Read (void *dst, size_t &num_bytes, off_t &offset);
+
+ //------------------------------------------------------------------
+ /// Read bytes from a file from the specified file offset.
+ ///
+ /// NOTE: This function is thread safe in that clients manager their
+ /// own file position markers and reads on other threads won't mess
+ /// up the current read.
+ ///
+ /// @param[in/out] num_bytes
+ /// The number of bytes to read form the current file position
+ /// which gets modified with the number of bytes that were read.
+ ///
+ /// @param[in/out] offset
+ /// The offset within the file from which to read \a num_bytes
+ /// bytes. This offset gets incremented by the number of bytes
+ /// that were read.
+ ///
+ /// @param[in] null_terminate
+ /// Ensure that the data that is read is terminated with a NULL
+ /// character so that the data can be used as a C string.
+ ///
+ /// @param[out] data_buffer_sp
+ /// A data buffer to create and fill in that will contain any
+ /// data that is read from the file. This buffer will be reset
+ /// if an error occurs.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Read (size_t &num_bytes,
+ off_t &offset,
+ bool null_terminate,
+ lldb::DataBufferSP &data_buffer_sp);
+
+ //------------------------------------------------------------------
+ /// Write bytes to a file at the specified file offset.
+ ///
+ /// NOTE: This function is thread safe in that clients manager their
+ /// own file position markers, though clients will need to implement
+ /// their own locking externally to avoid multiple people writing
+ /// to the file at the same time.
+ ///
+ /// @param[in] buf
+ /// A buffer containing the bytes to write.
+ ///
+ /// @param[in/out] num_bytes
+ /// The number of bytes to write to the file at offset \a offset.
+ /// \a num_bytes gets modified with the number of bytes that
+ /// were read.
+ ///
+ /// @param[in/out] offset
+ /// The offset within the file at which to write \a num_bytes
+ /// bytes. This offset gets incremented by the number of bytes
+ /// that were written.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Write (const void *src, size_t &num_bytes, off_t &offset);
+
+ //------------------------------------------------------------------
+ /// Flush the current stream
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Flush ();
+
+ //------------------------------------------------------------------
+ /// Sync to disk.
+ ///
+ /// @return
+ /// An error object that indicates success or the reason for
+ /// failure.
+ //------------------------------------------------------------------
+ Error
+ Sync ();
+
+ //------------------------------------------------------------------
+ /// Output printf formatted output to the stream.
+ ///
+ /// Print some formatted output to the stream.
+ ///
+ /// @param[in] format
+ /// A printf style format string.
+ ///
+ /// @param[in] ...
+ /// Variable arguments that are needed for the printf style
+ /// format string \a format.
+ //------------------------------------------------------------------
+ size_t
+ Printf (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ size_t
+ PrintfVarArg(const char *format, va_list args);
+
+protected:
+
+
+ bool
+ DescriptorIsValid () const
+ {
+ return m_descriptor >= 0;
+ }
+
+ bool
+ StreamIsValid () const
+ {
+ return m_stream != kInvalidStream;
+ }
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ int m_descriptor;
+ FILE *m_stream;
+ uint32_t m_options;
+ bool m_owned;
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_File_h_
diff --git a/include/lldb/Host/FileSpec.h b/include/lldb/Host/FileSpec.h
new file mode 100644
index 000000000000..c58be9ec09d5
--- /dev/null
+++ b/include/lldb/Host/FileSpec.h
@@ -0,0 +1,692 @@
+//===-- FileSpec.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_FileSpec_h_
+#define liblldb_FileSpec_h_
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/STLUtils.h"
+#include "lldb/Host/TimeValue.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class FileSpec FileSpec.h "lldb/Host/FileSpec.h"
+/// @brief A file utility class.
+///
+/// A file specification class that divides paths up into a directory
+/// and basename. These string values of the paths are put into uniqued
+/// string pools for fast comparisons and efficient memory usage.
+///
+/// Another reason the paths are split into the directory and basename
+/// is to allow efficient debugger searching. Often in a debugger the
+/// user types in the basename of the file, for example setting a
+/// breakpoint by file and line, or specifying a module (shared library)
+/// to limit the scope in which to execute a command. The user rarely
+/// types in a full path. When the paths are already split up, it makes
+/// it easy for us to compare only the basenames of a lot of file
+/// specifications without having to split up the file path each time
+/// to get to the basename.
+//----------------------------------------------------------------------
+class FileSpec
+{
+public:
+ typedef enum FileType
+ {
+ eFileTypeInvalid = -1,
+ eFileTypeUnknown = 0,
+ eFileTypeDirectory,
+ eFileTypePipe,
+ eFileTypeRegular,
+ eFileTypeSocket,
+ eFileTypeSymbolicLink,
+ eFileTypeOther
+ } FileType;
+
+ FileSpec();
+
+ //------------------------------------------------------------------
+ /// Constructor with path.
+ ///
+ /// Takes a path to a file which can be just a filename, or a full
+ /// path. If \a path is not NULL or empty, this function will call
+ /// FileSpec::SetFile (const char *path, bool resolve).
+ ///
+ /// @param[in] path
+ /// The full or partial path to a file.
+ ///
+ /// @param[in] resolve_path
+ /// If \b true, then we resolve the path with realpath,
+ /// if \b false we trust the path is in canonical form already.
+ ///
+ /// @see FileSpec::SetFile (const char *path, bool resolve)
+ //------------------------------------------------------------------
+ explicit FileSpec (const char *path, bool resolve_path);
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Makes a copy of the uniqued directory and filename strings from
+ /// \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object reference to copy.
+ //------------------------------------------------------------------
+ FileSpec (const FileSpec& rhs);
+
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Makes a copy of the uniqued directory and filename strings from
+ /// \a rhs if it is not NULL.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object pointer to copy if non-NULL.
+ //------------------------------------------------------------------
+ FileSpec (const FileSpec* rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~FileSpec ();
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Makes a copy of the uniqued directory and filename strings from
+ /// \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object reference to assign to this object.
+ ///
+ /// @return
+ /// A const reference to this object.
+ //------------------------------------------------------------------
+ const FileSpec&
+ operator= (const FileSpec& rhs);
+
+ //------------------------------------------------------------------
+ /// Equal to operator
+ ///
+ /// Tests if this object is equal to \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object reference to compare this object
+ /// to.
+ ///
+ /// @return
+ /// \b true if this object is equal to \a rhs, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ operator== (const FileSpec& rhs) const;
+
+ //------------------------------------------------------------------
+ /// Not equal to operator
+ ///
+ /// Tests if this object is not equal to \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object reference to compare this object
+ /// to.
+ ///
+ /// @return
+ /// \b true if this object is equal to \a rhs, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ operator!= (const FileSpec& rhs) const;
+
+ //------------------------------------------------------------------
+ /// Less than to operator
+ ///
+ /// Tests if this object is less than \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const FileSpec object reference to compare this object
+ /// to.
+ ///
+ /// @return
+ /// \b true if this object is less than \a rhs, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ operator< (const FileSpec& rhs) const;
+
+ //------------------------------------------------------------------
+ /// Convert to pointer operator.
+ ///
+ /// This allows code to check a FileSpec object to see if it
+ /// contains anything valid using code such as:
+ ///
+ /// @code
+ /// FileSpec file_spec(...);
+ /// if (file_spec)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// A pointer to this object if either the directory or filename
+ /// is valid, NULL otherwise.
+ //------------------------------------------------------------------
+ operator bool() const;
+
+ //------------------------------------------------------------------
+ /// Logical NOT operator.
+ ///
+ /// This allows code to check a FileSpec object to see if it is
+ /// invalid using code such as:
+ ///
+ /// @code
+ /// FileSpec file_spec(...);
+ /// if (!file_spec)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// Returns \b true if the object has an empty directory and
+ /// filename, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ operator! () const;
+
+ //------------------------------------------------------------------
+ /// Clears the object state.
+ ///
+ /// Clear this object by releasing both the directory and filename
+ /// string values and reverting them to empty strings.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Compare two FileSpec objects.
+ ///
+ /// If \a full is true, then both the directory and the filename
+ /// must match. If \a full is false, then the directory names for
+ /// \a lhs and \a rhs are only compared if they are both not empty.
+ /// This allows a FileSpec object to only contain a filename
+ /// and it can match FileSpec objects that have matching
+ /// filenames with different paths.
+ ///
+ /// @param[in] lhs
+ /// A const reference to the Left Hand Side object to compare.
+ ///
+ /// @param[in] rhs
+ /// A const reference to the Right Hand Side object to compare.
+ ///
+ /// @param[in] full
+ /// If true, then both the directory and filenames will have to
+ /// match for a compare to return zero (equal to). If false
+ /// and either directory from \a lhs or \a rhs is empty, then
+ /// only the filename will be compared, else a full comparison
+ /// is done.
+ ///
+ /// @return
+ /// @li -1 if \a lhs is less than \a rhs
+ /// @li 0 if \a lhs is equal to \a rhs
+ /// @li 1 if \a lhs is greater than \a rhs
+ //------------------------------------------------------------------
+ static int
+ Compare (const FileSpec& lhs, const FileSpec& rhs, bool full);
+
+ static bool
+ Equal (const FileSpec& a, const FileSpec& b, bool full);
+
+ //------------------------------------------------------------------
+ /// Dump this object to a Stream.
+ ///
+ /// Dump the object to the supplied stream \a s. If the object
+ /// contains a valid directory name, it will be displayed followed
+ /// by a directory delimiter, and the filename.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s) const;
+
+ //------------------------------------------------------------------
+ /// Existence test.
+ ///
+ /// @return
+ /// \b true if the file exists on disk, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Exists () const;
+
+
+ //------------------------------------------------------------------
+ /// Expanded existence test.
+ ///
+ /// Call into the Host to see if it can help find the file (e.g. by
+ /// searching paths set in the environment, etc.).
+ ///
+ /// If found, sets the value of m_directory to the directory where
+ /// the file was found.
+ ///
+ /// @return
+ /// \b true if was able to find the file using expanded search
+ /// methods, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ResolveExecutableLocation ();
+
+ //------------------------------------------------------------------
+ /// Canonicalize this file path (basically running the static
+ /// FileSpec::Resolve method on it). Useful if you asked us not to
+ /// resolve the file path when you set the file.
+ //------------------------------------------------------------------
+ bool
+ ResolvePath ();
+
+ uint64_t
+ GetByteSize() const;
+
+ //------------------------------------------------------------------
+ /// Directory string get accessor.
+ ///
+ /// @return
+ /// A reference to the directory string object.
+ //------------------------------------------------------------------
+ ConstString &
+ GetDirectory ();
+
+ //------------------------------------------------------------------
+ /// Directory string const get accessor.
+ ///
+ /// @return
+ /// A const reference to the directory string object.
+ //------------------------------------------------------------------
+ const ConstString &
+ GetDirectory () const;
+
+ //------------------------------------------------------------------
+ /// Filename string get accessor.
+ ///
+ /// @return
+ /// A reference to the filename string object.
+ //------------------------------------------------------------------
+ ConstString &
+ GetFilename ();
+
+ //------------------------------------------------------------------
+ /// Filename string const get accessor.
+ ///
+ /// @return
+ /// A const reference to the filename string object.
+ //------------------------------------------------------------------
+ const ConstString &
+ GetFilename () const;
+
+ //------------------------------------------------------------------
+ /// Returns true if the filespec represents an implementation source
+ /// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
+ /// extension).
+ ///
+ /// @return
+ /// \b true if the filespec represents an implementation source
+ /// file, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsSourceImplementationFile () const;
+
+ //------------------------------------------------------------------
+ /// Returns true if the filespec represents path that is relative
+ /// path to the current working directory.
+ ///
+ /// @return
+ /// \b true if the filespec represents a current working
+ /// directory relative path, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsRelativeToCurrentWorkingDirectory () const;
+
+ TimeValue
+ GetModificationTime () const;
+
+ //------------------------------------------------------------------
+ /// Extract the full path to the file.
+ ///
+ /// Extract the directory and path into a fixed buffer. This is
+ /// needed as the directory and path are stored in separate string
+ /// values.
+ ///
+ /// @param[out] path
+ /// The buffer in which to place the extracted full path.
+ ///
+ /// @param[in] max_path_length
+ /// The maximum length of \a path.
+ ///
+ /// @return
+ /// Returns the number of characters that would be needed to
+ /// properly copy the full path into \a path. If the returned
+ /// number is less than \a max_path_length, then the path is
+ /// properly copied and terminated. If the return value is
+ /// >= \a max_path_length, then the path was truncated (but is
+ /// still NULL terminated).
+ //------------------------------------------------------------------
+ size_t
+ GetPath (char *path, size_t max_path_length) const;
+
+ //------------------------------------------------------------------
+ /// Extract the full path to the file.
+ ///
+ /// Extract the directory and path into a std::string, which is returned.
+ ///
+ /// @return
+ /// Returns a std::string with the directory and filename
+ /// concatenated.
+ //------------------------------------------------------------------
+ std::string
+ GetPath () const;
+
+ //------------------------------------------------------------------
+ /// Extract the extension of the file.
+ ///
+ /// Returns a ConstString that represents the extension of the filename
+ /// for this FileSpec object. If this object does not represent a file,
+ /// or the filename has no extension, ConstString(NULL) is returned.
+ /// The dot ('.') character is not returned as part of the extension
+ ///
+ /// @return
+ /// Returns the extension of the file as a ConstString object.
+ //------------------------------------------------------------------
+ ConstString
+ GetFileNameExtension () const;
+
+ //------------------------------------------------------------------
+ /// Return the filename without the extension part
+ ///
+ /// Returns a ConstString that represents the filename of this object
+ /// without the extension part (e.g. for a file named "foo.bar", "foo"
+ /// is returned)
+ ///
+ /// @return
+ /// Returns the filename without extension
+ /// as a ConstString object.
+ //------------------------------------------------------------------
+ ConstString
+ GetFileNameStrippingExtension () const;
+
+ FileType
+ GetFileType () const;
+
+ bool
+ IsDirectory () const
+ {
+ return GetFileType() == FileSpec::eFileTypeDirectory;
+ }
+
+ bool
+ IsPipe () const
+ {
+ return GetFileType() == FileSpec::eFileTypePipe;
+ }
+
+ bool
+ IsRegularFile () const
+ {
+ return GetFileType() == FileSpec::eFileTypeRegular;
+ }
+
+ bool
+ IsSocket () const
+ {
+ return GetFileType() == FileSpec::eFileTypeSocket;
+ }
+
+ bool
+ IsSymbolicLink () const
+ {
+ return GetFileType() == FileSpec::eFileTypeSymbolicLink;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Return the size in bytes that this object takes in memory. This
+ /// returns the size in bytes of this object, not any shared string
+ /// values it may refer to.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //------------------------------------------------------------------
+ /// Memory map part of, or the entire contents of, a file.
+ ///
+ /// Returns a shared pointer to a data buffer that contains all or
+ /// part of the contents of a file. The data is memory mapped and
+ /// will lazily page in data from the file as memory is accessed.
+ /// The data that is mappped will start \a offset bytes into the
+ /// file, and \a length bytes will be mapped. If \a length is
+ /// greater than the number of bytes available in the file starting
+ /// at \a offset, the number of bytes will be appropriately
+ /// truncated. The final number of bytes that get mapped can be
+ /// verified using the DataBuffer::GetByteSize() function on the return
+ /// shared data pointer object contents.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes from the beginning of the file where
+ /// memory mapping should begin.
+ ///
+ /// @param[in] length
+ /// The size in bytes that should be mapped starting \a offset
+ /// bytes into the file. If \a length is \c SIZE_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// A shared pointer to the memeory mapped data. This shared
+ /// pointer can contain a NULL DataBuffer pointer, so the contained
+ /// pointer must be checked prior to using it.
+ //------------------------------------------------------------------
+ lldb::DataBufferSP
+ MemoryMapFileContents (off_t offset = 0, size_t length = SIZE_MAX) const;
+
+ //------------------------------------------------------------------
+ /// Read part of, or the entire contents of, a file into a heap based data buffer.
+ ///
+ /// Returns a shared pointer to a data buffer that contains all or
+ /// part of the contents of a file. The data copies into a heap based
+ /// buffer that lives in the DataBuffer shared pointer object returned.
+ /// The data that is cached will start \a offset bytes into the
+ /// file, and \a length bytes will be mapped. If \a length is
+ /// greater than the number of bytes available in the file starting
+ /// at \a offset, the number of bytes will be appropriately
+ /// truncated. The final number of bytes that get mapped can be
+ /// verified using the DataBuffer::GetByteSize() function.
+ ///
+ /// @param[in] offset
+ /// The offset in bytes from the beginning of the file where
+ /// memory mapping should begin.
+ ///
+ /// @param[in] length
+ /// The size in bytes that should be mapped starting \a offset
+ /// bytes into the file. If \a length is \c SIZE_MAX, map
+ /// as many bytes as possible.
+ ///
+ /// @return
+ /// A shared pointer to the memeory mapped data. This shared
+ /// pointer can contain a NULL DataBuffer pointer, so the contained
+ /// pointer must be checked prior to using it.
+ //------------------------------------------------------------------
+ lldb::DataBufferSP
+ ReadFileContents (off_t offset = 0, size_t length = SIZE_MAX, Error *error_ptr = NULL) const;
+
+ size_t
+ ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const;
+
+
+ //------------------------------------------------------------------
+ /// Read the entire contents of a file as data that can be used
+ /// as a C string.
+ ///
+ /// Read the entire contents of a file and ensure that the data
+ /// is NULL terminated so it can be used as a C string.
+ ///
+ /// @return
+ /// A shared pointer to the data. This shared pointer can
+ /// contain a NULL DataBuffer pointer, so the contained pointer
+ /// must be checked prior to using it.
+ //------------------------------------------------------------------
+ lldb::DataBufferSP
+ ReadFileContentsAsCString(Error *error_ptr = NULL);
+ //------------------------------------------------------------------
+ /// Change the file specificed with a new path.
+ ///
+ /// Update the contents of this object with a new path. The path will
+ /// be split up into a directory and filename and stored as uniqued
+ /// string values for quick comparison and efficient memory usage.
+ ///
+ /// @param[in] path
+ /// A full, partial, or relative path to a file.
+ ///
+ /// @param[in] resolve_path
+ /// If \b true, then we will try to resolve links the path using
+ /// the static FileSpec::Resolve.
+ //------------------------------------------------------------------
+ void
+ SetFile (const char *path, bool resolve_path);
+
+ bool
+ IsResolved () const
+ {
+ return m_is_resolved;
+ }
+
+ //------------------------------------------------------------------
+ /// Set if the file path has been resolved or not.
+ ///
+ /// If you know a file path is already resolved and avoided passing
+ /// a \b true parameter for any functions that take a "bool
+ /// resolve_path" parameter, you can set the value manually using
+ /// this call to make sure we don't try and resolve it later, or try
+ /// and resolve a path that has already been resolved.
+ ///
+ /// @param[in] is_resolved
+ /// A boolean value that will replace the current value that
+ /// indicates if the paths in this object have been resolved.
+ //------------------------------------------------------------------
+ void
+ SetIsResolved (bool is_resolved)
+ {
+ m_is_resolved = is_resolved;
+ }
+ //------------------------------------------------------------------
+ /// Read the file into an array of strings, one per line.
+ ///
+ /// Opens and reads the file in this object into an array of strings,
+ /// one string per line of the file. Returns a boolean indicating
+ /// success or failure.
+ ///
+ /// @param[out] lines
+ /// The string array into which to read the file.
+ ///
+ /// @result
+ /// Returns the number of lines that were read from the file.
+ //------------------------------------------------------------------
+ size_t
+ ReadFileLines (STLStringArray &lines);
+
+ //------------------------------------------------------------------
+ /// Resolves user name and links in \a src_path, and writes the output
+ /// to \a dst_path. Note if the path pointed to by \a src_path does not
+ /// exist, the contents of \a src_path will be copied to \a dst_path
+ /// unchanged.
+ ///
+ /// @param[in] src_path
+ /// Input path to be resolved.
+ ///
+ /// @param[in] dst_path
+ /// Buffer to store the resolved path.
+ ///
+ /// @param[in] dst_len
+ /// Size of the buffer pointed to by dst_path.
+ ///
+ /// @result
+ /// The number of characters required to write the resolved path. If the
+ /// resolved path doesn't fit in dst_len, dst_len-1 characters will
+ /// be written to \a dst_path, but the actual required length will still be returned.
+ //------------------------------------------------------------------
+ static size_t
+ Resolve (const char *src_path, char *dst_path, size_t dst_len);
+
+ //------------------------------------------------------------------
+ /// Resolves the user name at the beginning of \a src_path, and writes the output
+ /// to \a dst_path. Note, \a src_path can contain other path components after the
+ /// user name, they will be copied over, and if the path doesn't start with "~" it
+ /// will also be copied over to \a dst_path.
+ ///
+ /// @param[in] src_path
+ /// Input path to be resolved.
+ ///
+ /// @param[in] dst_path
+ /// Buffer to store the resolved path.
+ ///
+ /// @param[in] dst_len
+ /// Size of the buffer pointed to by dst_path.
+ ///
+ /// @result
+ /// The number of characters required to write the resolved path, or 0 if
+ /// the user name could not be found. If the
+ /// resolved path doesn't fit in dst_len, dst_len-1 characters will
+ /// be written to \a dst_path, but the actual required length will still be returned.
+ //------------------------------------------------------------------
+ static size_t
+ ResolveUsername (const char *src_path, char *dst_path, size_t dst_len);
+
+ static size_t
+ ResolvePartialUsername (const char *partial_name, StringList &matches);
+
+ enum EnumerateDirectoryResult
+ {
+ eEnumerateDirectoryResultNext, // Enumerate next entry in the current directory
+ eEnumerateDirectoryResultEnter, // Recurse into the current entry if it is a directory or symlink, or next if not
+ eEnumerateDirectoryResultExit, // Exit from the current directory at the current level.
+ eEnumerateDirectoryResultQuit // Stop directory enumerations at any level
+ };
+
+ typedef EnumerateDirectoryResult (*EnumerateDirectoryCallbackType) (void *baton,
+ FileType file_type,
+ const FileSpec &spec
+);
+
+ static EnumerateDirectoryResult
+ EnumerateDirectory (const char *dir_path,
+ bool find_directories,
+ bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ ConstString m_directory; ///< The uniqued directory path
+ ConstString m_filename; ///< The uniqued filename path
+ mutable bool m_is_resolved; ///< True if this path has been resolved.
+};
+
+//----------------------------------------------------------------------
+/// Dump a FileSpec object to a stream
+//----------------------------------------------------------------------
+Stream& operator << (Stream& s, const FileSpec& f);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_FileSpec_h_
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
new file mode 100644
index 000000000000..547bdd5d637b
--- /dev/null
+++ b/include/lldb/Host/Host.h
@@ -0,0 +1,502 @@
+//===-- Host.h --------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Host_h_
+#define liblldb_Host_h_
+#if defined(__cplusplus)
+
+#include <stdarg.h>
+
+#include <map>
+#include <string>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Host Host.h "lldb/Host/Host.h"
+/// @brief A class that provides host computer information.
+///
+/// Host is a class that answers information about the host operating
+/// system.
+//----------------------------------------------------------------------
+class Host
+{
+public:
+ typedef bool (*MonitorChildProcessCallback) (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal, // Zero for no signal
+ int status); // Exit value of process if signal is zero
+
+ //------------------------------------------------------------------
+ /// Start monitoring a child process.
+ ///
+ /// Allows easy monitoring of child processes. \a callback will be
+ /// called when the child process exits or if it gets a signal. The
+ /// callback will only be called with signals if \a monitor_signals
+ /// is \b true. \a callback will usually be called from another
+ /// thread so the callback function must be thread safe.
+ ///
+ /// When the callback gets called, the return value indicates if
+ /// minotoring should stop. If \b true is returned from \a callback
+ /// the information will be removed. If \b false is returned then
+ /// monitoring will continue. If the child process exits, the
+ /// monitoring will automatically stop after the callback returned
+ /// ragardless of the callback return value.
+ ///
+ /// @param[in] callback
+ /// A function callback to call when a child receives a signal
+ /// (if \a monitor_signals is true) or a child exits.
+ ///
+ /// @param[in] callback_baton
+ /// A void * of user data that will be pass back when
+ /// \a callback is called.
+ ///
+ /// @param[in] pid
+ /// The process ID of a child process to monitor, -1 for all
+ /// processes.
+ ///
+ /// @param[in] monitor_signals
+ /// If \b true the callback will get called when the child
+ /// process gets a signal. If \b false, the callback will only
+ /// get called if the child process exits.
+ ///
+ /// @return
+ /// A thread handle that can be used to cancel the thread that
+ /// was spawned to monitor \a pid.
+ ///
+ /// @see static void Host::StopMonitoringChildProcess (uint32_t)
+ //------------------------------------------------------------------
+ static lldb::thread_t
+ StartMonitoringChildProcess (MonitorChildProcessCallback callback,
+ void *callback_baton,
+ lldb::pid_t pid,
+ bool monitor_signals);
+
+ //------------------------------------------------------------------
+ /// Get the host page size.
+ ///
+ /// @return
+ /// The size in bytes of a VM page on the host system.
+ //------------------------------------------------------------------
+ static size_t
+ GetPageSize();
+
+ //------------------------------------------------------------------
+ /// Returns the endianness of the host system.
+ ///
+ /// @return
+ /// Returns the endianness of the host system as a lldb::ByteOrder
+ /// enumeration.
+ //------------------------------------------------------------------
+ static lldb::ByteOrder
+ GetByteOrder ();
+
+ //------------------------------------------------------------------
+ /// Returns the number of CPUs on this current host.
+ ///
+ /// @return
+ /// Number of CPUs on this current host, or zero if the number
+ /// of CPUs can't be determined on this host.
+ //------------------------------------------------------------------
+ static uint32_t
+ GetNumberCPUS ();
+
+ static bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update);
+
+ static bool
+ GetOSBuildString (std::string &s);
+
+ static bool
+ GetOSKernelDescription (std::string &s);
+
+ static bool
+ GetHostname (std::string &s);
+
+ static const char *
+ GetUserName (uint32_t uid, std::string &user_name);
+
+ static const char *
+ GetGroupName (uint32_t gid, std::string &group_name);
+
+ static uint32_t
+ GetUserID ();
+
+ static uint32_t
+ GetGroupID ();
+
+ static uint32_t
+ GetEffectiveUserID ();
+
+ static uint32_t
+ GetEffectiveGroupID ();
+
+
+ enum SystemLogType
+ {
+ eSystemLogWarning,
+ eSystemLogError
+ };
+
+ static void
+ SystemLog (SystemLogType type, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ static void
+ SystemLog (SystemLogType type, const char *format, va_list args);
+
+ //------------------------------------------------------------------
+ /// Gets the host architecture.
+ ///
+ /// @return
+ /// A const architecture object that represents the host
+ /// architecture.
+ //------------------------------------------------------------------
+ enum SystemDefaultArchitecture
+ {
+ eSystemDefaultArchitecture, // The overall default architecture that applications will run on this host
+ eSystemDefaultArchitecture32, // If this host supports 32 bit programs, return the default 32 bit arch
+ eSystemDefaultArchitecture64 // If this host supports 64 bit programs, return the default 64 bit arch
+ };
+
+ static const ArchSpec &
+ GetArchitecture (SystemDefaultArchitecture arch_kind = eSystemDefaultArchitecture);
+
+ //------------------------------------------------------------------
+ /// Gets the host vendor string.
+ ///
+ /// @return
+ /// A const string object containing the host vendor name.
+ //------------------------------------------------------------------
+ static const ConstString &
+ GetVendorString ();
+
+ //------------------------------------------------------------------
+ /// Gets the host Operating System (OS) string.
+ ///
+ /// @return
+ /// A const string object containing the host OS name.
+ //------------------------------------------------------------------
+ static const ConstString &
+ GetOSString ();
+
+ //------------------------------------------------------------------
+ /// Gets the host target triple as a const string.
+ ///
+ /// @return
+ /// A const string object containing the host target triple.
+ //------------------------------------------------------------------
+ static const ConstString &
+ GetTargetTriple ();
+
+ //------------------------------------------------------------------
+ /// Get the process ID for the calling process.
+ ///
+ /// @return
+ /// The process ID for the current process.
+ //------------------------------------------------------------------
+ static lldb::pid_t
+ GetCurrentProcessID ();
+
+ //------------------------------------------------------------------
+ /// Get the thread ID for the calling thread in the current process.
+ ///
+ /// @return
+ /// The thread ID for the calling thread in the current process.
+ //------------------------------------------------------------------
+ static lldb::tid_t
+ GetCurrentThreadID ();
+
+ //------------------------------------------------------------------
+ /// Get the thread token (the one returned by ThreadCreate when the thread was created) for the
+ /// calling thread in the current process.
+ ///
+ /// @return
+ /// The thread token for the calling thread in the current process.
+ //------------------------------------------------------------------
+ static lldb::thread_t
+ GetCurrentThread ();
+
+ static const char *
+ GetSignalAsCString (int signo);
+
+ static void
+ WillTerminate ();
+ //------------------------------------------------------------------
+ /// Host specific thread created function call.
+ ///
+ /// This function call lets the current host OS do any thread
+ /// specific initialization that it needs, including naming the
+ /// thread. No cleanup routine is exptected to be called
+ ///
+ /// @param[in] name
+ /// The current thread's name in the current process.
+ //------------------------------------------------------------------
+ static void
+ ThreadCreated (const char *name);
+
+ static lldb::thread_t
+ ThreadCreate (const char *name,
+ lldb::thread_func_t function,
+ lldb::thread_arg_t thread_arg,
+ Error *err);
+
+ static bool
+ ThreadCancel (lldb::thread_t thread,
+ Error *error);
+
+ static bool
+ ThreadDetach (lldb::thread_t thread,
+ Error *error);
+ static bool
+ ThreadJoin (lldb::thread_t thread,
+ lldb::thread_result_t *thread_result_ptr,
+ Error *error);
+
+ //------------------------------------------------------------------
+ /// Gets the name of a thread in a process.
+ ///
+ /// This function will name a thread in a process using it's own
+ /// thread name pool, and also will attempt to set a thread name
+ /// using any supported host OS APIs.
+ ///
+ /// @param[in] pid
+ /// The process ID in which we are trying to get the name of
+ /// a thread.
+ ///
+ /// @param[in] tid
+ /// The thread ID for which we are trying retrieve the name of.
+ ///
+ /// @return
+ /// A std::string containing the thread name.
+ //------------------------------------------------------------------
+ static std::string
+ GetThreadName (lldb::pid_t pid, lldb::tid_t tid);
+
+ //------------------------------------------------------------------
+ /// Sets the name of a thread in the current process.
+ ///
+ /// @param[in] pid
+ /// The process ID in which we are trying to name a thread.
+ ///
+ /// @param[in] tid
+ /// The thread ID which we are trying to name.
+ ///
+ /// @param[in] name
+ /// The current thread's name in the current process to \a name.
+ ///
+ /// @return
+ /// \b true if the thread name was able to be set, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ static bool
+ SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name);
+
+ //------------------------------------------------------------------
+ /// Sets a shortened name of a thread in the current process.
+ ///
+ /// @param[in] pid
+ /// The process ID in which we are trying to name a thread.
+ ///
+ /// @param[in] tid
+ /// The thread ID which we are trying to name.
+ ///
+ /// @param[in] name
+ /// The current thread's name in the current process to \a name.
+ ///
+ /// @param[in] len
+ /// The maximum length for the thread's shortened name.
+ ///
+ /// @return
+ /// \b true if the thread name was able to be set, \b false
+ /// otherwise.
+ static bool
+ SetShortThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name, size_t len);
+
+ //------------------------------------------------------------------
+ /// Gets the FileSpec of the current process (the process that
+ /// that is running the LLDB code).
+ ///
+ /// @return
+ /// \b A file spec with the program name.
+ //------------------------------------------------------------------
+ static FileSpec
+ GetProgramFileSpec ();
+
+ //------------------------------------------------------------------
+ /// Given an address in the current process (the process that
+ /// is running the LLDB code), return the name of the module that
+ /// it comes from. This can be useful when you need to know the
+ /// path to the shared library that your code is running in for
+ /// loading resources that are relative to your binary.
+ ///
+ /// @param[in] host_addr
+ /// The pointer to some code in the current process.
+ ///
+ /// @return
+ /// \b A file spec with the module that contains \a host_addr,
+ /// which may be invalid if \a host_addr doesn't fall into
+ /// any valid module address range.
+ //------------------------------------------------------------------
+ static FileSpec
+ GetModuleFileSpecForHostAddress (const void *host_addr);
+
+
+
+ //------------------------------------------------------------------
+ /// If you have an executable that is in a bundle and want to get
+ /// back to the bundle directory from the path itself, this
+ /// function will change a path to a file within a bundle to the
+ /// bundle directory itself.
+ ///
+ /// @param[in] file
+ /// A file spec that might point to a file in a bundle.
+ ///
+ /// @param[out] bundle_directory
+ /// An object will be filled in with the bundle directory for
+ /// the bundle when \b true is returned. Otherwise \a file is
+ /// left untouched and \b false is returned.
+ ///
+ /// @return
+ /// \b true if \a file was resolved in \a bundle_directory,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ static bool
+ GetBundleDirectory (const FileSpec &file, FileSpec &bundle_directory);
+
+ //------------------------------------------------------------------
+ /// When executable files may live within a directory, where the
+ /// directory represents an executable bundle (like the MacOSX
+ /// app bundles), the locate the executable within the containing
+ /// bundle.
+ ///
+ /// @param[in,out] file
+ /// A file spec that currently points to the bundle that will
+ /// be filled in with the executable path within the bundle
+ /// if \b true is returned. Otherwise \a file is left untouched.
+ ///
+ /// @return
+ /// \b true if \a file was resolved, \b false if this function
+ /// was not able to resolve the path.
+ //------------------------------------------------------------------
+ static bool
+ ResolveExecutableInBundle (FileSpec &file);
+
+ //------------------------------------------------------------------
+ /// Find a resource files that are related to LLDB.
+ ///
+ /// Operating systems have different ways of storing shared
+ /// libraries and related resources. This function abstracts the
+ /// access to these paths.
+ ///
+ /// @param[in] path_type
+ /// The type of LLDB resource path you are looking for. If the
+ /// enumeration ends with "Dir", then only the \a file_spec's
+ /// directory member gets filled in.
+ ///
+ /// @param[in] file_spec
+ /// A file spec that gets filled in with the appriopriate path.
+ ///
+ /// @return
+ /// \b true if \a resource_path was resolved, \a false otherwise.
+ //------------------------------------------------------------------
+ static bool
+ GetLLDBPath (PathType path_type,
+ FileSpec &file_spec);
+
+ //------------------------------------------------------------------
+ /// Set a string that can be displayed if host application crashes.
+ ///
+ /// Some operating systems have the ability to print a description
+ /// for shared libraries when a program crashes. If the host OS
+ /// supports such a mechanism, it should be implemented to help
+ /// with crash triage.
+ ///
+ /// @param[in] format
+ /// A printf format that will be used to form a new crash
+ /// description string.
+ //------------------------------------------------------------------
+ static void
+ SetCrashDescriptionWithFormat (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+ static void
+ SetCrashDescription (const char *description);
+
+ static uint32_t
+ FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &proc_infos);
+
+ typedef std::map<lldb::pid_t, bool> TidMap;
+ typedef std::pair<lldb::pid_t, bool> TidPair;
+ static bool
+ FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach);
+
+ static bool
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
+
+ static lldb::pid_t
+ LaunchApplication (const FileSpec &app_file_spec);
+
+ static Error
+ LaunchProcess (ProcessLaunchInfo &launch_info);
+
+ static Error
+ RunShellCommand (const char *command, // Shouldn't be NULL
+ const char *working_dir, // Pass NULL to use the current working directory
+ int *status_ptr, // Pass NULL if you don't want the process exit status
+ int *signo_ptr, // Pass NULL if you don't want the signal that caused the process to exit
+ std::string *command_output, // Pass NULL if you don't want the command output
+ uint32_t timeout_sec,
+ const char *shell = "/bin/bash");
+
+ static lldb::DataBufferSP
+ GetAuxvData (lldb_private::Process *process);
+
+ static lldb::TargetSP
+ GetDummyTarget (Debugger &debugger);
+
+ static bool
+ OpenFileInExternalEditor (const FileSpec &file_spec,
+ uint32_t line_no);
+
+ static void
+ Backtrace (Stream &strm, uint32_t max_frames);
+
+ static size_t
+ GetEnvironment (StringList &env);
+
+ enum DynamicLibraryOpenOptions
+ {
+ eDynamicLibraryOpenOptionLazy = (1u << 0), // Lazily resolve symbols in this dynamic library
+ eDynamicLibraryOpenOptionLocal = (1u << 1), // Only open a shared library with local access (hide it from the global symbol namespace)
+ eDynamicLibraryOpenOptionLimitGetSymbol = (1u << 2) // DynamicLibraryGetSymbol calls on this handle will only return matches from this shared library
+ };
+ static void *
+ DynamicLibraryOpen (const FileSpec &file_spec,
+ uint32_t options,
+ Error &error);
+
+ static Error
+ DynamicLibraryClose (void *dynamic_library_handle);
+
+ static void *
+ DynamicLibraryGetSymbol (void *dynamic_library_handle,
+ const char *symbol_name,
+ Error &error);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // liblldb_Host_h_
diff --git a/include/lldb/Host/Mutex.h b/include/lldb/Host/Mutex.h
new file mode 100644
index 000000000000..63f759efe366
--- /dev/null
+++ b/include/lldb/Host/Mutex.h
@@ -0,0 +1,312 @@
+//===-- Mutex.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_Mutex_h_
+#define liblldb_Mutex_h_
+#if defined(__cplusplus)
+
+#include <pthread.h>
+#include <assert.h>
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+#include <string>
+#endif
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Mutex Mutex.h "lldb/Host/Mutex.h"
+/// @brief A C++ wrapper class for pthread mutexes.
+//----------------------------------------------------------------------
+class Mutex
+{
+public:
+ friend class Locker;
+ friend class Condition;
+
+ enum Type
+ {
+ eMutexTypeNormal, ///< Mutex that can't recursively entered by the same thread
+ eMutexTypeRecursive ///< Mutex can be recursively entered by the same thread
+ };
+
+ //------------------------------------------------------------------
+ /// @class Mutex::Locker
+ ///
+ /// A scoped locking class that allows a variety of pthread mutex
+ /// objects to have a mutex locked when an Mutex::Locker
+ /// object is created, and unlocked when it goes out of scope or
+ /// when the Mutex::Locker::Reset(pthread_mutex_t *)
+ /// is called. This provides an exception safe way to lock a mutex
+ /// in a scope.
+ //------------------------------------------------------------------
+ class Locker
+ {
+ public:
+ //--------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// This will create a scoped mutex locking object that doesn't
+ /// have a mutex to lock. One will need to be provided using the
+ /// Mutex::Locker::Reset(pthread_mutex_t *) method.
+ ///
+ /// @see Mutex::Locker::Reset(pthread_mutex_t *)
+ //--------------------------------------------------------------
+ Locker();
+
+ //--------------------------------------------------------------
+ /// Constructor with a Mutex object.
+ ///
+ /// This will create a scoped mutex locking object that extracts
+ /// the mutex owned by \a m and locks it.
+ ///
+ /// @param[in] m
+ /// An instance of a Mutex object that contains a
+ /// valid mutex object.
+ //--------------------------------------------------------------
+ Locker(Mutex& m);
+
+ //--------------------------------------------------------------
+ /// Constructor with a Mutex object pointer.
+ ///
+ /// This will create a scoped mutex locking object that extracts
+ /// the mutex owned by a m and locks it.
+ ///
+ /// @param[in] m
+ /// A pointer to instance of a Mutex object that
+ /// contains a valid mutex object.
+ //--------------------------------------------------------------
+ Locker(Mutex* m);
+
+ //--------------------------------------------------------------
+ /// Desstructor
+ ///
+ /// Unlocks any valid pthread_mutex_t that this object may
+ /// contain.
+ //--------------------------------------------------------------
+ ~Locker();
+
+ //--------------------------------------------------------------
+ /// Change the contained mutex.
+ ///
+ /// Unlock the current mutex in this object (if it contains a
+ /// valid mutex) and lock the new \a mutex object if it is
+ /// non-NULL.
+ //--------------------------------------------------------------
+ void
+ Lock (Mutex &mutex);
+
+ void
+ Lock (Mutex *mutex)
+ {
+ if (mutex)
+ Lock(*mutex);
+ }
+
+ //--------------------------------------------------------------
+ /// Change the contained mutex only if the mutex can be locked.
+ ///
+ /// Unlock the current mutex in this object (if it contains a
+ /// valid mutex) and try to lock \a mutex. If \a mutex can be
+ /// locked this object will take ownership of the lock and will
+ /// unlock it when it goes out of scope or Reset or TryLock are
+ /// called again. If the mutex is already locked, this object
+ /// will not take ownership of the mutex.
+ ///
+ /// @return
+ /// Returns \b true if the lock was aquired and the this
+ /// object will unlock the mutex when it goes out of scope,
+ /// returns \b false otherwise.
+ //--------------------------------------------------------------
+ bool
+ TryLock (Mutex &mutex, const char *failure_message = NULL);
+
+ bool
+ TryLock (Mutex *mutex, const char *failure_message = NULL)
+ {
+ if (mutex)
+ return TryLock(*mutex, failure_message);
+ else
+ return false;
+ }
+
+ void
+ Unlock ();
+
+ protected:
+ //--------------------------------------------------------------
+ /// Member variables
+ //--------------------------------------------------------------
+ Mutex *m_mutex_ptr;
+
+ private:
+ Locker(const Locker&);
+ const Locker& operator=(const Locker&);
+ };
+
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Creates a pthread mutex with no attributes.
+ //------------------------------------------------------------------
+ Mutex();
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Creates a pthread mutex with \a type as the mutex type.
+ /// Valid values for \a type include:
+ /// @li Mutex::Type::eMutexTypeNormal
+ /// @li Mutex::Type::eMutexTypeRecursive
+ ///
+ /// @param[in] type
+ /// The type of the mutex.
+ ///
+ /// @see ::pthread_mutexattr_settype()
+ //------------------------------------------------------------------
+ Mutex(Mutex::Type type);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Destroys the mutex owned by this object.
+ //------------------------------------------------------------------
+#ifdef LLDB_CONFIGURATION_DEBUG
+ virtual
+#endif
+ ~Mutex();
+
+ //------------------------------------------------------------------
+ /// Lock the mutex.
+ ///
+ /// Locks the mutex owned by this object. If the mutex is already
+ /// locked, the calling thread will block until the mutex becomes
+ /// available.
+ ///
+ /// @return
+ /// The error code from \c pthread_mutex_lock().
+ //------------------------------------------------------------------
+#ifdef LLDB_CONFIGURATION_DEBUG
+ virtual
+#endif
+ int
+ Lock();
+
+ //------------------------------------------------------------------
+ /// Try to lock the mutex.
+ ///
+ /// Attempts to lock the mutex owned by this object without blocking.
+ /// If the mutex is already locked, TryLock() will not block waiting
+ /// for the mutex, but will return an error condition.
+ ///
+ /// @return
+ /// The error code from \c pthread_mutex_trylock().
+ //------------------------------------------------------------------
+#ifdef LLDB_CONFIGURATION_DEBUG
+ virtual
+#endif
+ int
+ TryLock(const char *failure_message = NULL);
+
+ //------------------------------------------------------------------
+ /// Unlock the mutex.
+ ///
+ /// If the current thread holds the lock on the owned mutex, then
+ /// Unlock() will unlock the mutex. Calling Unlock() on this object
+ /// when the calling thread does not hold the lock will result in
+ /// undefined behavior.
+ ///
+ /// @return
+ /// The error code from \c pthread_mutex_unlock().
+ //------------------------------------------------------------------
+#ifdef LLDB_CONFIGURATION_DEBUG
+ virtual
+#endif
+ int
+ Unlock();
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ // TODO: Hide the mutex in the implementation file in case we ever need to port to an
+ // architecture that doesn't have pthread mutexes.
+ pthread_mutex_t m_mutex; ///< The pthread mutex object.
+
+private:
+ //------------------------------------------------------------------
+ /// Mutex get accessor.
+ ///
+ /// @return
+ /// A pointer to the pthread mutex object owned by this object.
+ //------------------------------------------------------------------
+ pthread_mutex_t *
+ GetMutex();
+
+ Mutex(const Mutex&);
+ const Mutex& operator=(const Mutex&);
+};
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+class TrackingMutex : public Mutex
+{
+public:
+ TrackingMutex() : Mutex() {}
+ TrackingMutex(Mutex::Type type) : Mutex (type) {}
+
+ virtual
+ ~TrackingMutex() {}
+
+ virtual int
+ Unlock ();
+
+ virtual int
+ TryLock (const char *failure_message = NULL)
+ {
+ int return_value = Mutex::TryLock();
+ if (return_value != 0 && failure_message != NULL)
+ {
+ m_failure_message.assign(failure_message);
+ m_thread_that_tried = pthread_self();
+ }
+ return return_value;
+ }
+
+protected:
+ pthread_t m_thread_that_tried;
+ std::string m_failure_message;
+};
+
+class LoggingMutex : public Mutex
+{
+public:
+ LoggingMutex() : Mutex(),m_locked(false) {}
+ LoggingMutex(Mutex::Type type) : Mutex (type),m_locked(false) {}
+
+ virtual
+ ~LoggingMutex() {}
+
+ virtual int
+ Lock ();
+
+ virtual int
+ Unlock ();
+
+ virtual int
+ TryLock (const char *failure_message = NULL);
+protected:
+ bool m_locked;
+};
+#endif
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif
diff --git a/include/lldb/Host/Predicate.h b/include/lldb/Host/Predicate.h
new file mode 100644
index 000000000000..6ddf20b67c69
--- /dev/null
+++ b/include/lldb/Host/Predicate.h
@@ -0,0 +1,509 @@
+//===-- Predicate.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_Predicate_h_
+#define liblldb_Predicate_h_
+#if defined(__cplusplus)
+
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Condition.h"
+#include <stdint.h>
+#include <time.h>
+
+//#define DB_PTHREAD_LOG_EVENTS
+
+//----------------------------------------------------------------------
+/// Enumerations for broadcasting.
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+typedef enum
+{
+ eBroadcastNever, ///< No broadcast will be sent when the value is modified.
+ eBroadcastAlways, ///< Always send a broadcast when the value is modified.
+ eBroadcastOnChange ///< Only broadcast if the value changes when the value is modified.
+
+} PredicateBroadcastType;
+
+//----------------------------------------------------------------------
+/// @class Predicate Predicate.h "lldb/Host/Predicate.h"
+/// @brief A C++ wrapper class for providing threaded access to a value
+/// of type T.
+///
+/// A templatized class that provides multi-threaded access to a value
+/// of type T. Threads can efficiently wait for bits within T to be set
+/// or reset, or wait for T to be set to be equal/not equal to a
+/// specified values.
+//----------------------------------------------------------------------
+template <class T>
+class Predicate
+{
+public:
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initializes the mutex, condition and value with their default
+ /// constructors.
+ //------------------------------------------------------------------
+ Predicate () :
+ m_value(),
+ m_mutex(),
+ m_condition()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Construct with initial T value \a initial_value.
+ ///
+ /// Initializes the mutex and condition with their default
+ /// constructors, and initializes the value with \a initial_value.
+ ///
+ /// @param[in] initial_value
+ /// The initial value for our T object.
+ //------------------------------------------------------------------
+ Predicate (T initial_value) :
+ m_value(initial_value),
+ m_mutex(),
+ m_condition()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// Destrory the condition, mutex, and T objects.
+ //------------------------------------------------------------------
+ ~Predicate ()
+ {
+ }
+
+
+ //------------------------------------------------------------------
+ /// Value get accessor.
+ ///
+ /// Copies the current \a m_value in a thread safe manor and returns
+ /// the copied value.
+ ///
+ /// @return
+ /// A copy of the current value.
+ //------------------------------------------------------------------
+ T
+ GetValue () const
+ {
+ Mutex::Locker locker(m_mutex);
+ T value = m_value;
+ return value;
+ }
+
+ //------------------------------------------------------------------
+ /// Value set accessor.
+ ///
+ /// Set the contained \a m_value to \a new_value in a thread safe
+ /// way and broadcast if needed.
+ ///
+ /// @param[in] value
+ /// The new value to set.
+ ///
+ /// @param[in] broadcast_type
+ /// A value indicating when and if to broadast. See the
+ /// PredicateBroadcastType enumeration for details.
+ ///
+ /// @see Predicate::Broadcast()
+ //------------------------------------------------------------------
+ void
+ SetValue (T value, PredicateBroadcastType broadcast_type)
+ {
+ Mutex::Locker locker(m_mutex);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, broadcast_type);
+#endif
+ const T old_value = m_value;
+ m_value = value;
+
+ Broadcast(old_value, broadcast_type);
+ }
+
+ //------------------------------------------------------------------
+ /// Set some bits in \a m_value.
+ ///
+ /// Logically set the bits \a bits in the contained \a m_value in a
+ /// thread safe way and broadcast if needed.
+ ///
+ /// @param[in] bits
+ /// The bits to set in \a m_value.
+ ///
+ /// @param[in] broadcast_type
+ /// A value indicating when and if to broadast. See the
+ /// PredicateBroadcastType enumeration for details.
+ ///
+ /// @see Predicate::Broadcast()
+ //------------------------------------------------------------------
+ void
+ SetValueBits (T bits, PredicateBroadcastType broadcast_type)
+ {
+ Mutex::Locker locker(m_mutex);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type);
+#endif
+ const T old_value = m_value;
+ m_value |= bits;
+
+ Broadcast(old_value, broadcast_type);
+ }
+
+ //------------------------------------------------------------------
+ /// Reset some bits in \a m_value.
+ ///
+ /// Logically reset (clear) the bits \a bits in the contained
+ /// \a m_value in a thread safe way and broadcast if needed.
+ ///
+ /// @param[in] bits
+ /// The bits to clear in \a m_value.
+ ///
+ /// @param[in] broadcast_type
+ /// A value indicating when and if to broadast. See the
+ /// PredicateBroadcastType enumeration for details.
+ ///
+ /// @see Predicate::Broadcast()
+ //------------------------------------------------------------------
+ void
+ ResetValueBits (T bits, PredicateBroadcastType broadcast_type)
+ {
+ Mutex::Locker locker(m_mutex);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type);
+#endif
+ const T old_value = m_value;
+ m_value &= ~bits;
+
+ Broadcast(old_value, broadcast_type);
+ }
+
+ //------------------------------------------------------------------
+ /// Wait for bits to be set in \a m_value.
+ ///
+ /// Waits in a thread safe way for any bits in \a bits to get
+ /// logically set in \a m_value. If any bits are already set in
+ /// \a m_value, this function will return without waiting.
+ ///
+ /// It is possible for the value to be changed between the time
+ /// the bits are set and the time the waiting thread wakes up.
+ /// If the bits are no longer set when the waiting thread wakes
+ /// up, it will go back into a wait state. It may be necessary
+ /// for the calling code to use additional thread synchronization
+ /// methods to detect transitory states.
+ ///
+ /// @param[in] bits
+ /// The bits we are waiting to be set in \a m_value.
+ ///
+ /// @param[in] abstime
+ /// If non-NULL, the absolute time at which we should stop
+ /// waiting, else wait an infinite amount of time.
+ ///
+ /// @return
+ /// Any bits of the requested bits that actually were set within
+ /// the time specified. Zero if a timeout or unrecoverable error
+ /// occurred.
+ //------------------------------------------------------------------
+ T
+ WaitForSetValueBits (T bits, const TimeValue *abstime = NULL)
+ {
+ int err = 0;
+ // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+ // unlock the mutex and wait for the condition to be set. When either
+ // function returns, they will re-lock the mutex. We use an auto lock/unlock
+ // class (Mutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ Mutex::Locker locker(m_mutex);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value);
+#endif
+ while (err == 0 && ((m_value & bits) == 0))
+ {
+ err = m_condition.Wait (m_mutex, abstime);
+ }
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits);
+#endif
+
+ return m_value & bits;
+ }
+
+ //------------------------------------------------------------------
+ /// Wait for bits to be reset in \a m_value.
+ ///
+ /// Waits in a thread safe way for any bits in \a bits to get
+ /// logically reset in \a m_value. If all bits are already reset in
+ /// \a m_value, this function will return without waiting.
+ ///
+ /// It is possible for the value to be changed between the time
+ /// the bits are reset and the time the waiting thread wakes up.
+ /// If the bits are no set when the waiting thread wakes up, it will
+ /// go back into a wait state. It may be necessary for the calling
+ /// code to use additional thread synchronization methods to detect
+ /// transitory states.
+ ///
+ /// @param[in] bits
+ /// The bits we are waiting to be reset in \a m_value.
+ ///
+ /// @param[in] abstime
+ /// If non-NULL, the absolute time at which we should stop
+ /// waiting, else wait an infinite amount of time.
+ ///
+ /// @return
+ /// Zero on successful waits, or non-zero if a timeout or
+ /// unrecoverable error occurs.
+ //------------------------------------------------------------------
+ T
+ WaitForResetValueBits (T bits, const TimeValue *abstime = NULL)
+ {
+ int err = 0;
+
+ // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+ // unlock the mutex and wait for the condition to be set. When either
+ // function returns, they will re-lock the mutex. We use an auto lock/unlock
+ // class (Mutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ Mutex::Locker locker(m_mutex);
+
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value);
+#endif
+ while (err == 0 && ((m_value & bits) != 0))
+ {
+ err = m_condition.Wait (m_mutex, abstime);
+ }
+
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits);
+#endif
+ return m_value & bits;
+ }
+
+ //------------------------------------------------------------------
+ /// Wait for \a m_value to be equal to \a value.
+ ///
+ /// Waits in a thread safe way for \a m_value to be equal to \a
+ /// value. If \a m_value is already equal to \a value, this
+ /// function will return without waiting.
+ ///
+ /// It is possible for the value to be changed between the time
+ /// the value is set and the time the waiting thread wakes up.
+ /// If the value no longer matches the requested value when the
+ /// waiting thread wakes up, it will go back into a wait state. It
+ /// may be necessary for the calling code to use additional thread
+ /// synchronization methods to detect transitory states.
+ ///
+ /// @param[in] value
+ /// The value we want \a m_value to be equal to.
+ ///
+ /// @param[in] abstime
+ /// If non-NULL, the absolute time at which we should stop
+ /// waiting, else wait an infinite amount of time.
+ ///
+ /// @param[out] timed_out
+ /// If not null, set to true if we return because of a time out,
+ /// and false if the value was set.
+ ///
+ /// @return
+ /// @li \b true if the \a m_value is equal to \a value
+ /// @li \b false otherwise
+ //------------------------------------------------------------------
+ bool
+ WaitForValueEqualTo (T value, const TimeValue *abstime = NULL, bool *timed_out = NULL)
+ {
+ int err = 0;
+ // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+ // unlock the mutex and wait for the condition to be set. When either
+ // function returns, they will re-lock the mutex. We use an auto lock/unlock
+ // class (Mutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ Mutex::Locker locker(m_mutex);
+
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value);
+#endif
+ if (timed_out)
+ *timed_out = false;
+
+ while (err == 0 && m_value != value)
+ {
+ err = m_condition.Wait (m_mutex, abstime, timed_out);
+ }
+
+ return m_value == value;
+ }
+
+ //------------------------------------------------------------------
+ /// Wait for \a m_value to be equal to \a value and then set it to
+ /// a new value.
+ ///
+ /// Waits in a thread safe way for \a m_value to be equal to \a
+ /// value and then sets \a m_value to \a new_value. If \a m_value
+ /// is already equal to \a value, this function will immediately
+ /// set \a m_value to \a new_value and return without waiting.
+ ///
+ /// It is possible for the value to be changed between the time
+ /// the value is set and the time the waiting thread wakes up.
+ /// If the value no longer matches the requested value when the
+ /// waiting thread wakes up, it will go back into a wait state. It
+ /// may be necessary for the calling code to use additional thread
+ /// synchronization methods to detect transitory states.
+ ///
+ /// @param[in] value
+ /// The value we want \a m_value to be equal to.
+ ///
+ /// @param[in] new_value
+ /// The value to which \a m_value will be set if \b true is
+ /// returned.
+ ///
+ /// @param[in] abstime
+ /// If non-NULL, the absolute time at which we should stop
+ /// waiting, else wait an infinite amount of time.
+ ///
+ /// @param[out] timed_out
+ /// If not null, set to true if we return because of a time out,
+ /// and false if the value was set.
+ ///
+ /// @return
+ /// @li \b true if the \a m_value became equal to \a value
+ /// @li \b false otherwise
+ //------------------------------------------------------------------
+ bool
+ WaitForValueEqualToAndSetValueTo (T wait_value, T new_value, const TimeValue *abstime = NULL, bool *timed_out = NULL)
+ {
+ int err = 0;
+ // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+ // unlock the mutex and wait for the condition to be set. When either
+ // function returns, they will re-lock the mutex. We use an auto lock/unlock
+ // class (Mutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ Mutex::Locker locker(m_mutex);
+
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (wait_value = 0x%8.8x, new_value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, wait_value, new_value, abstime, m_value);
+#endif
+ if (timed_out)
+ *timed_out = false;
+
+ while (err == 0 && m_value != wait_value)
+ {
+ err = m_condition.Wait (m_mutex, abstime, timed_out);
+ }
+
+ if (m_value == wait_value)
+ {
+ m_value = new_value;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Wait for \a m_value to not be equal to \a value.
+ ///
+ /// Waits in a thread safe way for \a m_value to not be equal to \a
+ /// value. If \a m_value is already not equal to \a value, this
+ /// function will return without waiting.
+ ///
+ /// It is possible for the value to be changed between the time
+ /// the value is set and the time the waiting thread wakes up.
+ /// If the value is equal to the test value when the waiting thread
+ /// wakes up, it will go back into a wait state. It may be
+ /// necessary for the calling code to use additional thread
+ /// synchronization methods to detect transitory states.
+ ///
+ /// @param[in] value
+ /// The value we want \a m_value to not be equal to.
+ ///
+ /// @param[out] new_value
+ /// The new value if \b true is returned.
+ ///
+ /// @param[in] abstime
+ /// If non-NULL, the absolute time at which we should stop
+ /// waiting, else wait an infinite amount of time.
+ ///
+ /// @return
+ /// @li \b true if the \a m_value is equal to \a value
+ /// @li \b false otherwise
+ //------------------------------------------------------------------
+ bool
+ WaitForValueNotEqualTo (T value, T &new_value, const TimeValue *abstime = NULL)
+ {
+ int err = 0;
+ // pthread_cond_timedwait() or pthread_cond_wait() will atomically
+ // unlock the mutex and wait for the condition to be set. When either
+ // function returns, they will re-lock the mutex. We use an auto lock/unlock
+ // class (Mutex::Locker) to allow us to return at any point in this
+ // function and not have to worry about unlocking the mutex.
+ Mutex::Locker locker(m_mutex);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value);
+#endif
+ while (err == 0 && m_value == value)
+ {
+ err = m_condition.Wait (m_mutex, abstime);
+ }
+
+ if (m_value != value)
+ {
+ new_value = m_value;
+ return true;
+ }
+ return false;
+ }
+
+protected:
+ //----------------------------------------------------------------------
+ // pthread condition and mutex variable to controll access and allow
+ // blocking between the main thread and the spotlight index thread.
+ //----------------------------------------------------------------------
+ T m_value; ///< The templatized value T that we are protecting access to
+ mutable Mutex m_mutex; ///< The mutex to use when accessing the data
+ Condition m_condition; ///< The pthread condition variable to use for signaling that data available or changed.
+
+private:
+
+ //------------------------------------------------------------------
+ /// Broadcast if needed.
+ ///
+ /// Check to see if we need to broadcast to our condition variable
+ /// depedning on the \a old_value and on the \a broadcast_type.
+ ///
+ /// If \a broadcast_type is eBroadcastNever, no broadcast will be
+ /// sent.
+ ///
+ /// If \a broadcast_type is eBroadcastAlways, the condition variable
+ /// will always be broadcast.
+ ///
+ /// If \a broadcast_type is eBroadcastOnChange, the condition
+ /// variable be broadcast if the owned value changes.
+ //------------------------------------------------------------------
+ void
+ Broadcast (T old_value, PredicateBroadcastType broadcast_type)
+ {
+ bool broadcast = (broadcast_type == eBroadcastAlways) || ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
+#ifdef DB_PTHREAD_LOG_EVENTS
+ printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, broadcast = %u\n", __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
+#endif
+ if (broadcast)
+ m_condition.Broadcast();
+ }
+
+
+ DISALLOW_COPY_AND_ASSIGN(Predicate);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_Predicate_h_
diff --git a/include/lldb/Host/ProcessRunLock.h b/include/lldb/Host/ProcessRunLock.h
new file mode 100644
index 000000000000..f563be73fce0
--- /dev/null
+++ b/include/lldb/Host/ProcessRunLock.h
@@ -0,0 +1,165 @@
+//===-- ProcessRunLock.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_ProcessRunLock_h_
+#define liblldb_ProcessRunLock_h_
+#if defined(__cplusplus)
+
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Condition.h"
+#include <pthread.h>
+#include <stdint.h>
+#include <time.h>
+
+//----------------------------------------------------------------------
+/// Enumerations for broadcasting.
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ProcessRunLock ProcessRunLock.h "lldb/Host/ProcessRunLock.h"
+/// @brief A class used to prevent the process from starting while other
+/// threads are accessing its data, and prevent access to its data while
+/// it is running.
+//----------------------------------------------------------------------
+
+class ProcessRunLock
+{
+public:
+ ProcessRunLock () :
+ m_rwlock(),
+ m_running(false)
+ {
+ int err = ::pthread_rwlock_init(&m_rwlock, NULL); (void)err;
+//#if LLDB_CONFIGURATION_DEBUG
+// assert(err == 0);
+//#endif
+ }
+
+ ~ProcessRunLock ()
+ {
+ int err = ::pthread_rwlock_destroy (&m_rwlock); (void)err;
+//#if LLDB_CONFIGURATION_DEBUG
+// assert(err == 0);
+//#endif
+ }
+
+ bool
+ ReadTryLock ()
+ {
+ ::pthread_rwlock_rdlock (&m_rwlock);
+ if (m_running == false)
+ {
+ return true;
+ }
+ ::pthread_rwlock_unlock (&m_rwlock);
+ return false;
+ }
+
+ bool
+ ReadUnlock ()
+ {
+ return ::pthread_rwlock_unlock (&m_rwlock) == 0;
+ }
+
+ bool
+ SetRunning()
+ {
+ ::pthread_rwlock_wrlock (&m_rwlock);
+ m_running = true;
+ ::pthread_rwlock_unlock (&m_rwlock);
+ return true;
+ }
+
+ bool
+ TrySetRunning()
+ {
+ bool r;
+
+ if (::pthread_rwlock_trywrlock (&m_rwlock) == 0)
+ {
+ r = !m_running;
+ m_running = true;
+ ::pthread_rwlock_unlock (&m_rwlock);
+ return r;
+ }
+ return false;
+ }
+
+ bool
+ SetStopped ()
+ {
+ ::pthread_rwlock_wrlock (&m_rwlock);
+ m_running = false;
+ ::pthread_rwlock_unlock (&m_rwlock);
+ return true;
+ }
+
+ class ProcessRunLocker
+ {
+ public:
+ ProcessRunLocker () :
+ m_lock (NULL)
+ {
+ }
+
+ ~ProcessRunLocker()
+ {
+ Unlock();
+ }
+
+ // Try to lock the read lock, but only do so if there are no writers.
+ bool
+ TryLock (ProcessRunLock *lock)
+ {
+ if (m_lock)
+ {
+ if (m_lock == lock)
+ return true; // We already have this lock locked
+ else
+ Unlock();
+ }
+ if (lock)
+ {
+ if (lock->ReadTryLock())
+ {
+ m_lock = lock;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ void
+ Unlock ()
+ {
+ if (m_lock)
+ {
+ m_lock->ReadUnlock();
+ m_lock = NULL;
+ }
+ }
+
+ ProcessRunLock *m_lock;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProcessRunLocker);
+ };
+
+protected:
+ pthread_rwlock_t m_rwlock;
+ bool m_running;
+private:
+ DISALLOW_COPY_AND_ASSIGN(ProcessRunLock);
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_ProcessRunLock_h_
diff --git a/include/lldb/Host/SocketAddress.h b/include/lldb/Host/SocketAddress.h
new file mode 100644
index 000000000000..e63b238c7994
--- /dev/null
+++ b/include/lldb/Host/SocketAddress.h
@@ -0,0 +1,256 @@
+//===-- SocketAddress.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_SocketAddress_h_
+#define liblldb_SocketAddress_h_
+
+// C Includes
+#include <stdint.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+
+#if defined(__FreeBSD__)
+#include <sys/types.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+namespace lldb_private {
+
+class SocketAddress
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SocketAddress ();
+ SocketAddress (const struct sockaddr &s);
+ SocketAddress (const struct sockaddr_in &s);
+ SocketAddress (const struct sockaddr_in6 &s);
+ SocketAddress (const struct sockaddr_storage &s);
+ SocketAddress (const SocketAddress& rhs);
+ ~SocketAddress ();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const SocketAddress&
+ operator=(const SocketAddress& rhs);
+
+ const SocketAddress&
+ operator=(const struct addrinfo *addr_info);
+
+ const SocketAddress&
+ operator=(const struct sockaddr &s);
+
+ const SocketAddress&
+ operator=(const struct sockaddr_in &s);
+
+ const SocketAddress&
+ operator=(const struct sockaddr_in6 &s);
+
+ const SocketAddress&
+ operator=(const struct sockaddr_storage &s);
+
+ //------------------------------------------------------------------
+ // Clear the contents of this socket address
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ // Get the length for the current socket address family
+ //------------------------------------------------------------------
+ socklen_t
+ GetLength () const;
+
+ //------------------------------------------------------------------
+ // Get the mex length for the the largest socket address supported.
+ //------------------------------------------------------------------
+ static socklen_t
+ GetMaxLength ();
+
+ //------------------------------------------------------------------
+ // Get the socket address family
+ //------------------------------------------------------------------
+ sa_family_t
+ GetFamily () const;
+
+ //------------------------------------------------------------------
+ // Set the socket address family
+ //------------------------------------------------------------------
+ void
+ SetFamily (sa_family_t family);
+
+ //------------------------------------------------------------------
+ // Get the port if the socket address for the family has a port
+ //------------------------------------------------------------------
+ in_port_t
+ GetPort () const;
+
+ //------------------------------------------------------------------
+ // Set the port if the socket address for the family has a port.
+ // The family must be set correctly prior to calling this function.
+ //------------------------------------------------------------------
+ bool
+ SetPort (in_port_t port);
+
+ //------------------------------------------------------------------
+ // Set the socket address according to the first match from a call
+ // to getaddrinfo() (or equivalent functions for systems that don't
+ // have getaddrinfo(). If "addr_info_ptr" is not NULL, it will get
+ // filled in with the match that was used to populate this socket
+ // address.
+ //------------------------------------------------------------------
+ bool
+ SetAddress (const struct addrinfo *hints_ptr, // Optional hints where the family, protocol and other things can be specified.
+ const char *host, // Hostname ("foo.bar.com" or "foo" or IP address string ("123.234.12.1" or "2001:0db8:85a3:0000:0000:8a2e:0370:7334")
+ const char *service, // Protocol name ("tcp", "http", etc) or a raw port number string ("81")
+ struct addrinfo *addr_info_ptr); // If non-NULL, this will get filled in with the match
+
+ //------------------------------------------------------------------
+ // Quick way to set the SocketAddress to localhost given the family.
+ // Returns true if successful, false if "family" doesn't support
+ // localhost or if "family" is not supported by this class.
+ //------------------------------------------------------------------
+ bool
+ SetToLocalhost (sa_family_t family,
+ in_port_t port);
+
+ //------------------------------------------------------------------
+ // Returns true if there is a valid socket address in this object.
+ //------------------------------------------------------------------
+ bool
+ IsValid () const;
+
+ //------------------------------------------------------------------
+ // Direct access to all of the sockaddr structures
+ //------------------------------------------------------------------
+ struct sockaddr &
+ sockaddr ()
+ {
+ return m_socket_addr.sa;
+ }
+
+ const struct sockaddr &
+ sockaddr () const
+ {
+ return m_socket_addr.sa;
+ }
+
+ struct sockaddr_in &
+ sockaddr_in ()
+ {
+ return m_socket_addr.sa_ipv4;
+ }
+
+ const struct sockaddr_in &
+ sockaddr_in () const
+ {
+ return m_socket_addr.sa_ipv4;
+ }
+
+ struct sockaddr_in6 &
+ sockaddr_in6 ()
+ {
+ return m_socket_addr.sa_ipv6;
+ }
+
+ const struct sockaddr_in6 &
+ sockaddr_in6 () const
+ {
+ return m_socket_addr.sa_ipv6;
+ }
+
+ struct sockaddr_storage &
+ sockaddr_storage ()
+ {
+ return m_socket_addr.sa_storage;
+ }
+
+
+ const struct sockaddr_storage &
+ sockaddr_storage () const
+ {
+ return m_socket_addr.sa_storage;
+ }
+
+
+ //------------------------------------------------------------------
+ // Conversion operators to allow getting the contents of this class
+ // as a pointer to the appropriate structure. This allows an instance
+ // of this class to be used in calls that take one of the sockaddr
+ // structure variants without having to manally use the correct
+ // accessor function.
+ //------------------------------------------------------------------
+
+ operator struct sockaddr * ()
+ {
+ return &m_socket_addr.sa;
+ }
+
+ operator const struct sockaddr * () const
+ {
+ return &m_socket_addr.sa;
+ }
+
+ operator struct sockaddr_in * ()
+ {
+ return &m_socket_addr.sa_ipv4;
+ }
+
+ operator const struct sockaddr_in * () const
+ {
+ return &m_socket_addr.sa_ipv4;
+ }
+
+ operator struct sockaddr_in6 * ()
+ {
+ return &m_socket_addr.sa_ipv6;
+ }
+
+ operator const struct sockaddr_in6 * () const
+ {
+ return &m_socket_addr.sa_ipv6;
+ }
+
+ operator const struct sockaddr_storage * () const
+ {
+ return &m_socket_addr.sa_storage;
+ }
+
+ operator struct sockaddr_storage * ()
+ {
+ return &m_socket_addr.sa_storage;
+ }
+
+
+protected:
+ typedef union sockaddr_tag
+ {
+ struct sockaddr sa;
+ struct sockaddr_in sa_ipv4;
+ struct sockaddr_in6 sa_ipv6;
+ struct sockaddr_storage sa_storage;
+ } sockaddr_t;
+
+ //------------------------------------------------------------------
+ // Classes that inherit from SocketAddress can see and modify these
+ //------------------------------------------------------------------
+ sockaddr_t m_socket_addr;
+};
+
+
+} // namespace lldb_private
+
+
+#endif // liblldb_SocketAddress_h_
diff --git a/include/lldb/Host/Symbols.h b/include/lldb/Host/Symbols.h
new file mode 100644
index 000000000000..9db68e1ecf15
--- /dev/null
+++ b/include/lldb/Host/Symbols.h
@@ -0,0 +1,69 @@
+//===-- Symbols.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_Symbols_h_
+#define liblldb_Symbols_h_
+
+// C Includes
+#include <stdint.h>
+#include <sys/time.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private {
+
+class Symbols
+{
+public:
+ //----------------------------------------------------------------------
+ // Locate the executable file given a module specification.
+ //
+ // Locating the file should happen only on the local computer or using
+ // the current computers global settings.
+ //----------------------------------------------------------------------
+ static FileSpec
+ LocateExecutableObjectFile (const ModuleSpec &module_spec);
+
+ //----------------------------------------------------------------------
+ // Locate the symbol file given a module specification.
+ //
+ // Locating the file should happen only on the local computer or using
+ // the current computers global settings.
+ //----------------------------------------------------------------------
+ static FileSpec
+ LocateExecutableSymbolFile (const ModuleSpec &module_spec);
+
+ static FileSpec
+ FindSymbolFileInBundle (const FileSpec& dsym_bundle_fspec,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch);
+
+ //----------------------------------------------------------------------
+ // Locate the object and symbol file given a module specification.
+ //
+ // Locating the file can try to download the file from a corporate build
+ // respository, or using any other means necessary to locate both the
+ // unstripped object file and the debug symbols.
+ // The force_lookup argument controls whether the external program is called
+ // unconditionally to find the symbol file, or if the user's settings are
+ // checked to see if they've enabled the external program before calling.
+ //
+ //----------------------------------------------------------------------
+ static bool
+ DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup = true);
+
+};
+
+} // namespace lldb_private
+
+
+#endif // liblldb_Symbols_h_
diff --git a/include/lldb/Host/Terminal.h b/include/lldb/Host/Terminal.h
new file mode 100644
index 000000000000..b334717c796b
--- /dev/null
+++ b/include/lldb/Host/Terminal.h
@@ -0,0 +1,254 @@
+//===-- Terminal.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_Terminal_h_
+#define liblldb_Terminal_h_
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+
+struct termios;
+
+namespace lldb_private {
+
+class Terminal
+{
+public:
+
+ Terminal (int fd = -1) :
+ m_fd (fd)
+ {
+ }
+
+ ~Terminal ()
+ {
+ }
+
+ bool
+ IsATerminal () const;
+
+ int
+ GetFileDescriptor () const
+ {
+ return m_fd;
+ }
+
+ void
+ SetFileDescriptor (int fd)
+ {
+ m_fd = fd;
+ }
+
+ bool
+ FileDescriptorIsValid () const
+ {
+ return m_fd != -1;
+ }
+
+ void
+ Clear ()
+ {
+ m_fd = -1;
+ }
+
+ bool
+ SetEcho (bool enabled);
+
+ bool
+ SetCanonical (bool enabled);
+
+protected:
+ int m_fd; // This may or may not be a terminal file descriptor
+};
+
+
+//----------------------------------------------------------------------
+/// @class State Terminal.h "lldb/Host/Terminal.h"
+/// @brief A terminal state saving/restoring class.
+///
+/// This class can be used to remember the terminal state for a file
+/// descriptor and later restore that state as it originally was.
+//----------------------------------------------------------------------
+class TerminalState
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor
+ //------------------------------------------------------------------
+ TerminalState();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~TerminalState();
+
+ //------------------------------------------------------------------
+ /// Save the TTY state for \a fd.
+ ///
+ /// Save the current state of the TTY for the file descriptor "fd"
+ /// and if "save_process_group" is true, attempt to save the process
+ /// group info for the TTY.
+ ///
+ /// @param[in] fd
+ /// The file descriptor to save the state of.
+ ///
+ /// @param[in] save_process_group
+ /// If \b true, save the process group settings, else do not
+ /// save the process group setttings for a TTY.
+ ///
+ /// @return
+ /// Returns \b true if \a fd describes a TTY and if the state
+ /// was able to be saved, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Save (int fd, bool save_process_group);
+
+ //------------------------------------------------------------------
+ /// Restore the TTY state to the cached state.
+ ///
+ /// Restore the state of the TTY using the cached values from a
+ /// previous call to TerminalState::Save(int,bool).
+ ///
+ /// @return
+ /// Returns \b true if the TTY state was successfully restored,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Restore () const;
+
+ //------------------------------------------------------------------
+ /// Test for valid cached TTY state information.
+ ///
+ /// @return
+ /// Returns \b true if this object has valid saved TTY state
+ /// settings that can be used to restore a previous state,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid() const;
+
+ void
+ Clear ();
+
+protected:
+
+ //------------------------------------------------------------------
+ /// Test if tflags is valid.
+ ///
+ /// @return
+ /// Returns \b true if \a m_tflags is valid and can be restored,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ TFlagsIsValid() const;
+
+ //------------------------------------------------------------------
+ /// Test if ttystate is valid.
+ ///
+ /// @return
+ /// Returns \b true if \a m_ttystate is valid and can be
+ /// restored, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ TTYStateIsValid() const;
+
+ //------------------------------------------------------------------
+ /// Test if the process group information is valid.
+ ///
+ /// @return
+ /// Returns \b true if \a m_process_group is valid and can be
+ /// restored, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ProcessGroupIsValid() const;
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Terminal m_tty; ///< A terminal
+ int m_tflags; ///< Cached tflags information.
+ std::unique_ptr<struct termios> m_termios_ap; ///< Cached terminal state information.
+ lldb::pid_t m_process_group;///< Cached process group information.
+
+};
+
+//----------------------------------------------------------------------
+/// @class TerminalStateSwitcher Terminal.h "lldb/Host/Terminal.h"
+/// @brief A TTY state switching class.
+///
+/// This class can be used to remember 2 TTY states for a given file
+/// descriptor and switch between the two states.
+//----------------------------------------------------------------------
+class TerminalStateSwitcher
+{
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ //------------------------------------------------------------------
+ TerminalStateSwitcher();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ ~TerminalStateSwitcher();
+
+ //------------------------------------------------------------------
+ /// Get the number of possible states to save.
+ ///
+ /// @return
+ /// The number of states that this TTY switcher object contains.
+ //------------------------------------------------------------------
+ uint32_t
+ GetNumberOfStates() const;
+
+ //------------------------------------------------------------------
+ /// Restore the TTY state for state at index \a idx.
+ ///
+ /// @return
+ /// Returns \b true if the TTY state was successfully restored,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Restore (uint32_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Save the TTY state information for the state at index \a idx.
+ /// The TTY state is saved for the file descriptor \a fd and
+ /// the process group information will also be saved if requested
+ /// by \a save_process_group.
+ ///
+ /// @param[in] idx
+ /// The index into the state array where the state should be
+ /// saved.
+ ///
+ /// @param[in] fd
+ /// The file descriptor for which to save the settings.
+ ///
+ /// @param[in] save_process_group
+ /// If \b true, save the process group information for the TTY.
+ ///
+ /// @return
+ /// Returns \b true if the save was successful, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ Save (uint32_t idx, int fd, bool save_process_group);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ mutable uint32_t m_currentState; ///< The currently active TTY state index.
+ TerminalState m_ttystates[2]; ///< The array of TTY states that holds saved TTY info.
+};
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_Terminal_h_
diff --git a/include/lldb/Host/TimeValue.h b/include/lldb/Host/TimeValue.h
new file mode 100644
index 000000000000..8c43d6d0e5ff
--- /dev/null
+++ b/include/lldb/Host/TimeValue.h
@@ -0,0 +1,107 @@
+//===-- TimeValue.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_TimeValue_h_
+#define liblldb_TimeValue_h_
+
+// C Includes
+#include <stdint.h>
+#include <sys/time.h>
+
+// BEGIN: MinGW work around
+#if !defined(_STRUCT_TIMESPEC) && !defined(HAVE_STRUCT_TIMESPEC)
+#include <pthread.h>
+#endif
+// END: MinGW work around
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class TimeValue
+{
+public:
+ static const uint64_t MicroSecPerSec = 1000000UL;
+ static const uint64_t NanoSecPerSec = 1000000000UL;
+ static const uint64_t NanoSecPerMicroSec = 1000U;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ TimeValue();
+ TimeValue(const TimeValue& rhs);
+ TimeValue(const struct timespec& ts);
+ TimeValue(const struct timeval& tv);
+ ~TimeValue();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const TimeValue&
+ operator=(const TimeValue& rhs);
+
+ void
+ Clear ();
+
+ uint64_t
+ GetAsNanoSecondsSinceJan1_1970() const;
+
+ uint64_t
+ GetAsMicroSecondsSinceJan1_1970() const;
+
+ uint64_t
+ GetAsSecondsSinceJan1_1970() const;
+
+ struct timespec
+ GetAsTimeSpec () const;
+
+ struct timeval
+ GetAsTimeVal () const;
+
+ bool
+ IsValid () const;
+
+ void
+ OffsetWithSeconds (uint64_t sec);
+
+ void
+ OffsetWithMicroSeconds (uint64_t usec);
+
+ void
+ OffsetWithNanoSeconds (uint64_t nsec);
+
+ static TimeValue
+ Now();
+
+ void
+ Dump (Stream *s, uint32_t width = 0) const;
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from TimeValue can see and modify these
+ //------------------------------------------------------------------
+ uint64_t m_nano_seconds;
+};
+
+bool operator == (const TimeValue &lhs, const TimeValue &rhs);
+bool operator != (const TimeValue &lhs, const TimeValue &rhs);
+bool operator < (const TimeValue &lhs, const TimeValue &rhs);
+bool operator <= (const TimeValue &lhs, const TimeValue &rhs);
+bool operator > (const TimeValue &lhs, const TimeValue &rhs);
+bool operator >= (const TimeValue &lhs, const TimeValue &rhs);
+
+uint64_t operator -(const TimeValue &lhs, const TimeValue &rhs);
+
+} // namespace lldb_private
+
+
+#endif // liblldb_TimeValue_h_
diff --git a/include/lldb/Host/freebsd/Config.h b/include/lldb/Host/freebsd/Config.h
new file mode 100644
index 000000000000..49d97dd5793c
--- /dev/null
+++ b/include/lldb/Host/freebsd/Config.h
@@ -0,0 +1,28 @@
+//===-- Config.h -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//----------------------------------------------------------------------
+// LLDB currently doesn't have a dynamic configuration mechanism, so we
+// are going to hardcode things for now. Eventually these files will
+// be auto generated by some configuration script that can detect
+// platform functionality availability.
+//----------------------------------------------------------------------
+
+#ifndef liblldb_Platform_Config_h_
+#define liblldb_Platform_Config_h_
+
+#define LLDB_CONFIG_TERMIOS_SUPPORTED 1
+
+#define LLDB_CONFIG_TILDE_RESOLVES_TO_USER 1
+
+//#define LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED 1
+
+//#define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1
+
+#endif // #ifndef liblldb_Platform_Config_h_
diff --git a/include/lldb/Interpreter/Args.h b/include/lldb/Interpreter/Args.h
new file mode 100644
index 000000000000..d06c3e56aecd
--- /dev/null
+++ b/include/lldb/Interpreter/Args.h
@@ -0,0 +1,467 @@
+//===-- Args.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_Command_h_
+#define liblldb_Command_h_
+
+// C Includes
+#include <getopt.h>
+
+// C++ Includes
+#include <list>
+#include <string>
+#include <vector>
+#include <utility>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-types.h"
+#include "lldb/lldb-types.h"
+#include "lldb/Core/Error.h"
+
+namespace lldb_private {
+
+typedef std::pair<int, std::string> OptionArgValue;
+typedef std::pair<std::string, OptionArgValue> OptionArgPair;
+typedef std::vector<OptionArgPair> OptionArgVector;
+typedef std::shared_ptr<OptionArgVector> OptionArgVectorSP;
+
+struct OptionArgElement
+{
+ enum {
+ eUnrecognizedArg = -1,
+ eBareDash = -2,
+ eBareDoubleDash = -3
+ };
+
+ OptionArgElement (int defs_index, int pos, int arg_pos) :
+ opt_defs_index(defs_index),
+ opt_pos (pos),
+ opt_arg_pos (arg_pos)
+ {
+ }
+
+ int opt_defs_index;
+ int opt_pos;
+ int opt_arg_pos;
+};
+
+typedef std::vector<OptionArgElement> OptionElementVector;
+
+//----------------------------------------------------------------------
+/// @class Args Args.h "lldb/Interpreter/Args.h"
+/// @brief A command line argument class.
+///
+/// The Args class is designed to be fed a command line. The
+/// command line is copied into an internal buffer and then split up
+/// into arguments. Arguments are space delimited if there are no quotes
+/// (single, double, or backtick quotes) surrounding the argument. Spaces
+/// can be escaped using a \ character to avoid having to surround an
+/// argument that contains a space with quotes.
+//----------------------------------------------------------------------
+class Args
+{
+public:
+
+ //------------------------------------------------------------------
+ /// Construct with an option command string.
+ ///
+ /// @param[in] command
+ /// A NULL terminated command that will be copied and split up
+ /// into arguments.
+ ///
+ /// @see Args::SetCommandString(const char *)
+ //------------------------------------------------------------------
+ Args (const char *command = NULL);
+
+ Args (const char *command, size_t len);
+
+ Args (const Args &rhs);
+
+ const Args &
+ operator= (const Args &rhs);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~Args();
+
+ //------------------------------------------------------------------
+ /// Dump all arguments to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump all arguments in the argument
+ /// vector.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s);
+
+ //------------------------------------------------------------------
+ /// Sets the command string contained by this object.
+ ///
+ /// The command string will be copied and split up into arguments
+ /// that can be accessed via the accessor functions.
+ ///
+ /// @param[in] command
+ /// A NULL terminated command that will be copied and split up
+ /// into arguments.
+ ///
+ /// @see Args::GetArgumentCount() const
+ /// @see Args::GetArgumentAtIndex (size_t) const
+ /// @see Args::GetArgumentVector ()
+ /// @see Args::Shift ()
+ /// @see Args::Unshift (const char *)
+ //------------------------------------------------------------------
+ void
+ SetCommandString (const char *command);
+
+ void
+ SetCommandString (const char *command, size_t len);
+
+ bool
+ GetCommandString (std::string &command) const;
+
+ bool
+ GetQuotedCommandString (std::string &command) const;
+
+ //------------------------------------------------------------------
+ /// Gets the number of arguments left in this command object.
+ ///
+ /// @return
+ /// The number or arguments in this object.
+ //------------------------------------------------------------------
+ size_t
+ GetArgumentCount () const;
+
+ //------------------------------------------------------------------
+ /// Gets the NULL terminated C string argument pointer for the
+ /// argument at index \a idx.
+ ///
+ /// @return
+ /// The NULL terminated C string argument pointer if \a idx is a
+ /// valid argument index, NULL otherwise.
+ //------------------------------------------------------------------
+ const char *
+ GetArgumentAtIndex (size_t idx) const;
+
+ char
+ GetArgumentQuoteCharAtIndex (size_t idx) const;
+
+ //------------------------------------------------------------------
+ /// Gets the argument vector.
+ ///
+ /// The value returned by this function can be used by any function
+ /// that takes and vector. The return value is just like \a argv
+ /// in the standard C entry point function:
+ /// \code
+ /// int main (int argc, const char **argv);
+ /// \endcode
+ ///
+ /// @return
+ /// An array of NULL terminated C string argument pointers that
+ /// also has a terminating NULL C string pointer
+ //------------------------------------------------------------------
+ char **
+ GetArgumentVector ();
+
+ //------------------------------------------------------------------
+ /// Gets the argument vector.
+ ///
+ /// The value returned by this function can be used by any function
+ /// that takes and vector. The return value is just like \a argv
+ /// in the standard C entry point function:
+ /// \code
+ /// int main (int argc, const char **argv);
+ /// \endcode
+ ///
+ /// @return
+ /// An array of NULL terminate C string argument pointers that
+ /// also has a terminating NULL C string pointer
+ //------------------------------------------------------------------
+ const char **
+ GetConstArgumentVector () const;
+
+
+ //------------------------------------------------------------------
+ /// Appends a new argument to the end of the list argument list.
+ ///
+ /// @param[in] arg_cstr
+ /// The new argument as a NULL terminated C string.
+ ///
+ /// @param[in] quote_char
+ /// If the argument was originally quoted, put in the quote char here.
+ ///
+ /// @return
+ /// The NULL terminated C string of the copy of \a arg_cstr.
+ //------------------------------------------------------------------
+ const char *
+ AppendArgument (const char *arg_cstr, char quote_char = '\0');
+
+ void
+ AppendArguments (const Args &rhs);
+
+ void
+ AppendArguments (const char **argv);
+
+ //------------------------------------------------------------------
+ /// Insert the argument value at index \a idx to \a arg_cstr.
+ ///
+ /// @param[in] idx
+ /// The index of where to insert the argument.
+ ///
+ /// @param[in] arg_cstr
+ /// The new argument as a NULL terminated C string.
+ ///
+ /// @param[in] quote_char
+ /// If the argument was originally quoted, put in the quote char here.
+ ///
+ /// @return
+ /// The NULL terminated C string of the copy of \a arg_cstr.
+ //------------------------------------------------------------------
+ const char *
+ InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char = '\0');
+
+ //------------------------------------------------------------------
+ /// Replaces the argument value at index \a idx to \a arg_cstr
+ /// if \a idx is a valid argument index.
+ ///
+ /// @param[in] idx
+ /// The index of the argument that will have its value replaced.
+ ///
+ /// @param[in] arg_cstr
+ /// The new argument as a NULL terminated C string.
+ ///
+ /// @param[in] quote_char
+ /// If the argument was originally quoted, put in the quote char here.
+ ///
+ /// @return
+ /// The NULL terminated C string of the copy of \a arg_cstr if
+ /// \a idx was a valid index, NULL otherwise.
+ //------------------------------------------------------------------
+ const char *
+ ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char = '\0');
+
+ //------------------------------------------------------------------
+ /// Deletes the argument value at index
+ /// if \a idx is a valid argument index.
+ ///
+ /// @param[in] idx
+ /// The index of the argument that will have its value replaced.
+ ///
+ //------------------------------------------------------------------
+ void
+ DeleteArgumentAtIndex (size_t idx);
+
+ //------------------------------------------------------------------
+ /// Sets the argument vector value, optionally copying all
+ /// arguments into an internal buffer.
+ ///
+ /// Sets the arguments to match those found in \a argv. All argument
+ /// strings will be copied into an internal buffers.
+ //
+ // FIXME: Handle the quote character somehow.
+ //------------------------------------------------------------------
+ void
+ SetArguments (size_t argc, const char **argv);
+
+ void
+ SetArguments (const char **argv);
+
+ //------------------------------------------------------------------
+ /// Shifts the first argument C string value of the array off the
+ /// argument array.
+ ///
+ /// The string value will be freed, so a copy of the string should
+ /// be made by calling Args::GetArgumentAtIndex (size_t) const
+ /// first and copying the returned value before calling
+ /// Args::Shift().
+ ///
+ /// @see Args::GetArgumentAtIndex (size_t) const
+ //------------------------------------------------------------------
+ void
+ Shift ();
+
+ //------------------------------------------------------------------
+ /// Inserts a class owned copy of \a arg_cstr at the beginning of
+ /// the argument vector.
+ ///
+ /// A copy \a arg_cstr will be made.
+ ///
+ /// @param[in] arg_cstr
+ /// The argument to push on the front the the argument stack.
+ ///
+ /// @param[in] quote_char
+ /// If the argument was originally quoted, put in the quote char here.
+ ///
+ /// @return
+ /// A pointer to the copy of \a arg_cstr that was made.
+ //------------------------------------------------------------------
+ const char *
+ Unshift (const char *arg_cstr, char quote_char = '\0');
+
+ //------------------------------------------------------------------
+ /// Parse the arguments in the contained arguments.
+ ///
+ /// The arguments that are consumed by the argument parsing process
+ /// will be removed from the argument vector. The arguements that
+ /// get processed start at the second argument. The first argument
+ /// is assumed to be the command and will not be touched.
+ ///
+ /// @see class Options
+ //------------------------------------------------------------------
+ Error
+ ParseOptions (Options &options);
+
+ size_t
+ FindArgumentIndexForOption (struct option *long_options, int long_options_index);
+
+ bool
+ IsPositionalArgument (const char *arg);
+
+ // The following works almost identically to ParseOptions, except that no option is required to have arguments,
+ // and it builds up the option_arg_vector as it parses the options.
+
+ void
+ ParseAliasOptions (Options &options, CommandReturnObject &result, OptionArgVector *option_arg_vector,
+ std::string &raw_input_line);
+
+ void
+ ParseArgsForCompletion (Options &options, OptionElementVector &option_element_vector, uint32_t cursor_index);
+
+ //------------------------------------------------------------------
+ // Clear the arguments.
+ //
+ // For re-setting or blanking out the list of arguments.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ static const char *
+ StripSpaces (std::string &s,
+ bool leading = true,
+ bool trailing = true,
+ bool return_null_if_empty = true);
+
+ static int32_t
+ StringToSInt32 (const char *s, int32_t fail_value = 0, int base = 0, bool *success_ptr = NULL);
+
+ static uint32_t
+ StringToUInt32 (const char *s, uint32_t fail_value = 0, int base = 0, bool *success_ptr = NULL);
+
+ static int64_t
+ StringToSInt64 (const char *s, int64_t fail_value = 0, int base = 0, bool *success_ptr = NULL);
+
+ static uint64_t
+ StringToUInt64 (const char *s, uint64_t fail_value = 0, int base = 0, bool *success_ptr = NULL);
+
+ static bool
+ UInt64ValueIsValidForByteSize (uint64_t uval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
+ return uval64 <= max;
+ }
+
+ static bool
+ SInt64ValueIsValidForByteSize (int64_t sval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
+ const int64_t min = ~(max);
+ return min <= sval64 && sval64 <= max;
+ }
+
+ static lldb::addr_t
+ StringToAddress (const ExecutionContext *exe_ctx,
+ const char *s,
+ lldb::addr_t fail_value,
+ Error *error);
+
+ static bool
+ StringToBoolean (const char *s, bool fail_value, bool *success_ptr);
+
+ static int64_t
+ StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error);
+
+ static lldb::ScriptLanguage
+ StringToScriptLanguage (const char *s, lldb::ScriptLanguage fail_value, bool *success_ptr);
+
+ static Error
+ StringToFormat (const char *s,
+ lldb::Format &format,
+ size_t *byte_size_ptr); // If non-NULL, then a byte size can precede the format character
+
+ static lldb::Encoding
+ StringToEncoding (const char *s,
+ lldb::Encoding fail_value = lldb::eEncodingInvalid);
+
+ static uint32_t
+ StringToGenericRegister (const char *s);
+
+ static const char *
+ StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update);
+
+ static const char *
+ GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg);
+
+ // EncodeEscapeSequences will change the textual representation of common
+ // escape sequences like "\n" (two characters) into a single '\n'. It does
+ // this for all of the supported escaped sequences and for the \0ooo (octal)
+ // and \xXX (hex). The resulting "dst" string will contain the character
+ // versions of all supported escape sequences. The common supported escape
+ // sequences are: "\a", "\b", "\f", "\n", "\r", "\t", "\v", "\'", "\"", "\\".
+
+ static void
+ EncodeEscapeSequences (const char *src, std::string &dst);
+
+ // ExpandEscapeSequences will change a string of possibly non-printable
+ // characters and expand them into text. So '\n' will turn into two chracters
+ // like "\n" which is suitable for human reading. When a character is not
+ // printable and isn't one of the common in escape sequences listed in the
+ // help for EncodeEscapeSequences, then it will be encoded as octal. Printable
+ // characters are left alone.
+ static void
+ ExpandEscapedCharacters (const char *src, std::string &dst);
+
+ // This one isn't really relevant to Arguments per se, but we're using the Args as a
+ // general strings container, so...
+ void
+ LongestCommonPrefix (std::string &common_prefix);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Args can see and modify these
+ //------------------------------------------------------------------
+ typedef std::list<std::string> arg_sstr_collection;
+ typedef std::vector<const char *> arg_cstr_collection;
+ typedef std::vector<char> arg_quote_char_collection;
+ arg_sstr_collection m_args;
+ arg_cstr_collection m_argv; ///< The current argument vector.
+ arg_quote_char_collection m_args_quote_char;
+
+ void
+ UpdateArgsAfterOptionParsing ();
+
+ void
+ UpdateArgvFromArgs ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Command_h_
diff --git a/include/lldb/Interpreter/CommandCompletions.h b/include/lldb/Interpreter/CommandCompletions.h
new file mode 100644
index 000000000000..c4ab1b61adeb
--- /dev/null
+++ b/include/lldb/Interpreter/CommandCompletions.h
@@ -0,0 +1,307 @@
+//===-- CommandCompletions.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_CommandCompletions_h_
+#define lldb_CommandCompletions_h_
+
+// C Includes
+// C++ Includes
+#include <set>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/RegularExpression.h"
+
+namespace lldb_private
+{
+class CommandCompletions
+{
+public:
+
+ //----------------------------------------------------------------------
+ // This is the command completion callback that is used to complete the argument of the option
+ // it is bound to (in the OptionDefinition table below). Return the total number of matches.
+ //----------------------------------------------------------------------
+ typedef int (*CompletionCallback) (CommandInterpreter &interpreter,
+ const char *completion_str, // This is the argument we are completing
+ int match_start_point, // This is the point in the list of matches that you should start returning elements
+ int max_return_elements, // This is the number of matches requested.
+ lldb_private::SearchFilter *searcher,// A search filter to limit the search...
+ bool &word_complete,
+ lldb_private::StringList &matches); // The array of matches we return.
+ typedef enum
+ {
+ eNoCompletion = 0u,
+ eSourceFileCompletion = (1u << 0),
+ eDiskFileCompletion = (1u << 1),
+ eDiskDirectoryCompletion = (1u << 2),
+ eSymbolCompletion = (1u << 3),
+ eModuleCompletion = (1u << 4),
+ eSettingsNameCompletion = (1u << 5),
+ ePlatformPluginCompletion = (1u << 6),
+ eArchitectureCompletion = (1u << 7),
+ eVariablePathCompletion = (1u << 8),
+ // This item serves two purposes. It is the last element in the enum,
+ // so you can add custom enums starting from here in your Option class.
+ // Also if you & in this bit the base code will not process the option.
+ eCustomCompletion = (1u << 9)
+
+ } CommonCompletionTypes;
+
+ struct CommonCompletionElement
+ {
+ uint32_t type;
+ CompletionCallback callback;
+ };
+
+ static bool InvokeCommonCompletionCallbacks (CommandInterpreter &interpreter,
+ uint32_t completion_mask,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches);
+
+ //----------------------------------------------------------------------
+ // These are the generic completer functions:
+ //----------------------------------------------------------------------
+ static int
+ DiskFiles (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches);
+ static int
+ DiskDirectories (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches);
+
+ static int
+ SourceFiles (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches);
+
+ static int
+ Modules (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ static int
+ Symbols (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ static int
+ SettingsNames (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ static int
+ PlatformPluginNames (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+
+ static int
+ ArchitectureNames (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ static int
+ VariablePath (CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ //----------------------------------------------------------------------
+ // The Completer class is a convenient base class for building searchers
+ // that go along with the SearchFilter passed to the standard Completer
+ // functions.
+ //----------------------------------------------------------------------
+ class Completer : public Searcher
+ {
+ public:
+ Completer (CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+ virtual ~Completer ();
+
+ virtual CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete) = 0;
+
+ virtual Depth
+ GetDepth () = 0;
+
+ virtual size_t
+ DoCompletion (SearchFilter *filter) = 0;
+
+ protected:
+ CommandInterpreter &m_interpreter;
+ std::string m_completion_str;
+ int m_match_start_point;
+ int m_max_return_elements;
+ StringList &m_matches;
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Completer);
+ };
+
+ //----------------------------------------------------------------------
+ // SouceFileCompleter implements the source file completer
+ //----------------------------------------------------------------------
+ class SourceFileCompleter : public Completer
+ {
+ public:
+
+ SourceFileCompleter (CommandInterpreter &interpreter,
+ bool include_support_files,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+ virtual Searcher::Depth GetDepth ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete);
+
+ size_t
+ DoCompletion (SearchFilter *filter);
+
+ private:
+ bool m_include_support_files;
+ FileSpecList m_matching_files;
+ const char *m_file_name;
+ const char *m_dir_name;
+ DISALLOW_COPY_AND_ASSIGN (SourceFileCompleter);
+
+ };
+
+ //----------------------------------------------------------------------
+ // ModuleCompleter implements the module completer
+ //----------------------------------------------------------------------
+ class ModuleCompleter : public Completer
+ {
+ public:
+
+ ModuleCompleter (CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+ virtual Searcher::Depth GetDepth ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete);
+
+ size_t
+ DoCompletion (SearchFilter *filter);
+
+ private:
+ const char *m_file_name;
+ const char *m_dir_name;
+ DISALLOW_COPY_AND_ASSIGN (ModuleCompleter);
+
+ };
+
+ //----------------------------------------------------------------------
+ // SymbolCompleter implements the symbol completer
+ //----------------------------------------------------------------------
+ class SymbolCompleter : public Completer
+ {
+ public:
+
+ SymbolCompleter (CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+ virtual Searcher::Depth GetDepth ();
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete);
+
+ size_t
+ DoCompletion (SearchFilter *filter);
+
+ private:
+// struct NameCmp {
+// bool operator() (const ConstString& lhs, const ConstString& rhs) const
+// {
+// return lhs < rhs;
+// }
+// };
+
+ RegularExpression m_regex;
+ typedef std::set<ConstString> collection;
+ collection m_match_set;
+ DISALLOW_COPY_AND_ASSIGN (SymbolCompleter);
+
+ };
+
+private:
+ static CommonCompletionElement g_common_completions[];
+
+};
+
+} // namespace lldb_private
+#endif // lldb_CommandCompletions_h_
diff --git a/include/lldb/Interpreter/CommandHistory.h b/include/lldb/Interpreter/CommandHistory.h
new file mode 100644
index 000000000000..dbe6e99bb5b1
--- /dev/null
+++ b/include/lldb/Interpreter/CommandHistory.h
@@ -0,0 +1,76 @@
+//===-- CommandHistory.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_CommandHistory_h_
+#define liblldb_CommandHistory_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class CommandHistory
+{
+public:
+ CommandHistory ();
+
+ ~CommandHistory ();
+
+ size_t
+ GetSize () const;
+
+ bool
+ IsEmpty () const;
+
+ const char*
+ FindString (const char* input_str) const;
+
+ const char*
+ GetStringAtIndex (size_t idx) const;
+
+ const char*
+ operator [] (size_t idx) const;
+
+ const char*
+ GetRecentmostString () const;
+
+ void
+ AppendString (const std::string& str,
+ bool reject_if_dupe = true);
+
+ void
+ Clear ();
+
+ void
+ Dump (Stream& stream,
+ size_t start_idx = 0,
+ size_t stop_idx = SIZE_MAX) const;
+
+ static const char g_repeat_char = '!';
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(CommandHistory);
+
+ typedef std::vector<std::string> History;
+ mutable Mutex m_mutex;
+ History m_history;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandHistory_h_
diff --git a/include/lldb/Interpreter/CommandInterpreter.h b/include/lldb/Interpreter/CommandInterpreter.h
new file mode 100644
index 000000000000..31fcc38eed9a
--- /dev/null
+++ b/include/lldb/Interpreter/CommandInterpreter.h
@@ -0,0 +1,486 @@
+//===-- CommandInterpreter.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_CommandInterpreter_h_
+#define liblldb_CommandInterpreter_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Interpreter/CommandHistory.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StringList.h"
+
+namespace lldb_private {
+
+class CommandInterpreter :
+ public Broadcaster,
+ public Properties
+{
+public:
+ typedef std::map<std::string, OptionArgVectorSP> OptionArgMap;
+
+ enum
+ {
+ eBroadcastBitThreadShouldExit = (1 << 0),
+ eBroadcastBitResetPrompt = (1 << 1),
+ eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
+ eBroadcastBitAsynchronousOutputData = (1 << 3),
+ eBroadcastBitAsynchronousErrorData = (1 << 4)
+ };
+
+ enum ChildrenTruncatedWarningStatus // tristate boolean to manage children truncation warning
+ {
+ eNoTruncation = 0, // never truncated
+ eUnwarnedTruncation = 1, // truncated but did not notify
+ eWarnedTruncation = 2 // truncated and notified
+ };
+
+ enum CommandTypes
+ {
+ eCommandTypesBuiltin = 0x0001, // native commands such as "frame"
+ eCommandTypesUserDef = 0x0002, // scripted commands
+ eCommandTypesAliases = 0x0004, // aliases such as "po"
+ eCommandTypesAllThem = 0xFFFF // all commands
+ };
+
+ // These two functions fill out the Broadcaster interface:
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+ void
+ SourceInitFile (bool in_cwd,
+ CommandReturnObject &result);
+
+ CommandInterpreter (Debugger &debugger,
+ lldb::ScriptLanguage script_language,
+ bool synchronous_execution);
+
+ virtual
+ ~CommandInterpreter ();
+
+ bool
+ AddCommand (const char *name,
+ const lldb::CommandObjectSP &cmd_sp,
+ bool can_replace);
+
+ bool
+ AddUserCommand (std::string name,
+ const lldb::CommandObjectSP &cmd_sp,
+ bool can_replace);
+
+ lldb::CommandObjectSP
+ GetCommandSPExact (const char *cmd,
+ bool include_aliases);
+
+ CommandObject *
+ GetCommandObjectExact (const char *cmd_cstr,
+ bool include_aliases);
+
+ CommandObject *
+ GetCommandObject (const char *cmd,
+ StringList *matches = NULL);
+
+ bool
+ CommandExists (const char *cmd);
+
+ bool
+ AliasExists (const char *cmd);
+
+ bool
+ UserCommandExists (const char *cmd);
+
+ void
+ AddAlias (const char *alias_name,
+ lldb::CommandObjectSP& command_obj_sp);
+
+ bool
+ RemoveAlias (const char *alias_name);
+
+ bool
+ GetAliasFullName (const char *cmd, std::string &full_name);
+
+ bool
+ RemoveUser (const char *alias_name);
+
+ void
+ RemoveAllUser ()
+ {
+ m_user_dict.clear();
+ }
+
+ OptionArgVectorSP
+ GetAliasOptions (const char *alias_name);
+
+
+ bool
+ ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp,
+ const char *options_args,
+ OptionArgVectorSP &option_arg_vector_sp);
+
+ void
+ RemoveAliasOptions (const char *alias_name);
+
+ void
+ AddOrReplaceAliasOptions (const char *alias_name,
+ OptionArgVectorSP &option_arg_vector_sp);
+
+ CommandObject *
+ BuildAliasResult (const char *alias_name,
+ std::string &raw_input_string,
+ std::string &alias_result,
+ CommandReturnObject &result);
+
+ bool
+ HandleCommand (const char *command_line,
+ LazyBool add_to_history,
+ CommandReturnObject &result,
+ ExecutionContext *override_context = NULL,
+ bool repeat_on_empty_command = true,
+ bool no_context_switching = false);
+
+ //------------------------------------------------------------------
+ /// Execute a list of commands in sequence.
+ ///
+ /// @param[in] commands
+ /// The list of commands to execute.
+ /// @param[in/out] context
+ /// The execution context in which to run the commands. Can be NULL in which case the default
+ /// context will be used.
+ /// @param[in] stop_on_continue
+ /// If \b true execution will end on the first command that causes the process in the
+ /// execution context to continue. If \false, we won't check the execution status.
+ /// @param[in] stop_on_error
+ /// If \b true execution will end on the first command that causes an error.
+ /// @param[in] echo_commands
+ /// If \b true echo the command before executing it. If \false, execute silently.
+ /// @param[in] print_results
+ /// If \b true print the results of the command after executing it. If \false, execute silently.
+ /// @param[out] result
+ /// This is marked as succeeding with no output if all commands execute safely,
+ /// and failed with some explanation if we aborted executing the commands at some point.
+ //------------------------------------------------------------------
+ void
+ HandleCommands (const StringList &commands,
+ ExecutionContext *context,
+ bool stop_on_continue,
+ bool stop_on_error,
+ bool echo_commands,
+ bool print_results,
+ LazyBool add_to_history,
+ CommandReturnObject &result);
+
+ //------------------------------------------------------------------
+ /// Execute a list of commands from a file.
+ ///
+ /// @param[in] file
+ /// The file from which to read in commands.
+ /// @param[in/out] context
+ /// The execution context in which to run the commands. Can be NULL in which case the default
+ /// context will be used.
+ /// @param[in] stop_on_continue
+ /// If \b true execution will end on the first command that causes the process in the
+ /// execution context to continue. If \false, we won't check the execution status.
+ /// @param[in] stop_on_error
+ /// If \b true execution will end on the first command that causes an error.
+ /// @param[in] echo_commands
+ /// If \b true echo the command before executing it. If \false, execute silently.
+ /// @param[in] print_results
+ /// If \b true print the results of the command after executing it. If \false, execute silently.
+ /// @param[out] result
+ /// This is marked as succeeding with no output if all commands execute safely,
+ /// and failed with some explanation if we aborted executing the commands at some point.
+ //------------------------------------------------------------------
+ void
+ HandleCommandsFromFile (FileSpec &file,
+ ExecutionContext *context,
+ bool stop_on_continue,
+ bool stop_on_error,
+ bool echo_commands,
+ bool print_results,
+ LazyBool add_to_history,
+ CommandReturnObject &result);
+
+ CommandObject *
+ GetCommandObjectForCommand (std::string &command_line);
+
+ // This handles command line completion. You are given a pointer to the command string buffer, to the current cursor,
+ // and to the end of the string (in case it is not NULL terminated).
+ // You also passed in an StringList object to fill with the returns.
+ // The first element of the array will be filled with the string that you would need to insert at
+ // the cursor point to complete the cursor point to the longest common matching prefix.
+ // If you want to limit the number of elements returned, set max_return_elements to the number of elements
+ // you want returned. Otherwise set max_return_elements to -1.
+ // If you want to start some way into the match list, then set match_start_point to the desired start
+ // point.
+ // Returns:
+ // -1 if the completion character should be inserted
+ // -2 if the entire command line should be deleted and replaced with matches.GetStringAtIndex(0)
+ // INT_MAX if the number of matches is > max_return_elements, but it is expensive to compute.
+ // Otherwise, returns the number of matches.
+ //
+ // FIXME: Only max_return_elements == -1 is supported at present.
+
+ int
+ HandleCompletion (const char *current_line,
+ const char *cursor,
+ const char *last_char,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches);
+
+ // This version just returns matches, and doesn't compute the substring. It is here so the
+ // Help command can call it for the first argument.
+ // word_complete tells whether a the completions are considered a "complete" response (so the
+ // completer should complete the quote & put a space after the word.
+
+ int
+ HandleCompletionMatches (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+
+ int
+ GetCommandNamesMatchingPartialString (const char *cmd_cstr,
+ bool include_aliases,
+ StringList &matches);
+
+ void
+ GetHelp (CommandReturnObject &result,
+ uint32_t types = eCommandTypesAllThem);
+
+ void
+ GetAliasHelp (const char *alias_name,
+ const char *command_name,
+ StreamString &help_string);
+
+ void
+ OutputFormattedHelpText (Stream &stream,
+ const char *command_word,
+ const char *separator,
+ const char *help_text,
+ size_t max_word_len);
+
+ // this mimics OutputFormattedHelpText but it does perform a much simpler
+ // formatting, basically ensuring line alignment. This is only good if you have
+ // some complicated layout for your help text and want as little help as reasonable
+ // in properly displaying it. Most of the times, you simply want to type some text
+ // and have it printed in a reasonable way on screen. If so, use OutputFormattedHelpText
+ void
+ OutputHelpText (Stream &stream,
+ const char *command_word,
+ const char *separator,
+ const char *help_text,
+ uint32_t max_word_len);
+
+ Debugger &
+ GetDebugger ()
+ {
+ return m_debugger;
+ }
+
+ ExecutionContext
+ GetExecutionContext()
+ {
+ return m_exe_ctx_ref.Lock();
+ }
+
+ void
+ UpdateExecutionContext (ExecutionContext *override_context);
+
+ lldb::PlatformSP
+ GetPlatform (bool prefer_target_platform);
+
+ const char *
+ ProcessEmbeddedScriptCommands (const char *arg);
+
+ const char *
+ GetPrompt ();
+
+ void
+ SetPrompt (const char *);
+
+ bool Confirm (const char *message, bool default_answer);
+
+ static size_t
+ GetConfirmationInputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction action,
+ const char *bytes,
+ size_t bytes_len);
+
+ void
+ LoadCommandDictionary ();
+
+ void
+ Initialize ();
+
+ void
+ SetScriptLanguage (lldb::ScriptLanguage lang);
+
+
+ bool
+ HasCommands ();
+
+ bool
+ HasAliases ();
+
+ bool
+ HasUserCommands ();
+
+ bool
+ HasAliasOptions ();
+
+ void
+ BuildAliasCommandArgs (CommandObject *alias_cmd_obj,
+ const char *alias_name,
+ Args &cmd_args,
+ std::string &raw_input_string,
+ CommandReturnObject &result);
+
+ int
+ GetOptionArgumentPosition (const char *in_string);
+
+ ScriptInterpreter *
+ GetScriptInterpreter (bool can_create = true);
+
+ void
+ SkipLLDBInitFiles (bool skip_lldbinit_files)
+ {
+ m_skip_lldbinit_files = skip_lldbinit_files;
+ }
+
+ void
+ SkipAppInitFiles (bool skip_app_init_files)
+ {
+ m_skip_app_init_files = m_skip_lldbinit_files;
+ }
+
+ bool
+ GetSynchronous ();
+
+ size_t
+ FindLongestCommandWord (CommandObject::CommandMap &dict);
+
+ void
+ FindCommandsForApropos (const char *word,
+ StringList &commands_found,
+ StringList &commands_help,
+ bool search_builtin_commands,
+ bool search_user_commands);
+
+ bool
+ GetBatchCommandMode () { return m_batch_command_mode; }
+
+ void
+ SetBatchCommandMode (bool value) { m_batch_command_mode = value; }
+
+ void
+ ChildrenTruncated ()
+ {
+ if (m_truncation_warning == eNoTruncation)
+ m_truncation_warning = eUnwarnedTruncation;
+ }
+
+ bool
+ TruncationWarningNecessary ()
+ {
+ return (m_truncation_warning == eUnwarnedTruncation);
+ }
+
+ void
+ TruncationWarningGiven ()
+ {
+ m_truncation_warning = eWarnedTruncation;
+ }
+
+ const char *
+ TruncationWarningText ()
+ {
+ return "*** Some of your variables have more members than the debugger will show by default. To show all of them, you can either use the --show-all-children option to %s or raise the limit by changing the target.max-children-count setting.\n";
+ }
+
+ const CommandHistory&
+ GetCommandHistory () const
+ {
+ return m_command_history;
+ }
+
+ CommandHistory&
+ GetCommandHistory ()
+ {
+ return m_command_history;
+ }
+
+ //------------------------------------------------------------------
+ // Properties
+ //------------------------------------------------------------------
+ bool
+ GetExpandRegexAliases () const;
+
+ bool
+ GetPromptOnQuit () const;
+
+ bool
+ GetStopCmdSourceOnError () const;
+
+protected:
+ friend class Debugger;
+
+ void
+ SetSynchronous (bool value);
+
+ lldb::CommandObjectSP
+ GetCommandSP (const char *cmd, bool include_aliases = true, bool exact = true, StringList *matches = NULL);
+
+private:
+
+ Error
+ PreprocessCommand (std::string &command);
+
+ Debugger &m_debugger; // The debugger session that this interpreter is associated with
+ ExecutionContextRef m_exe_ctx_ref; // The current execution context to use when handling commands
+ bool m_synchronous_execution;
+ bool m_skip_lldbinit_files;
+ bool m_skip_app_init_files;
+ CommandObject::CommandMap m_command_dict; // Stores basic built-in commands (they cannot be deleted, removed or overwritten).
+ CommandObject::CommandMap m_alias_dict; // Stores user aliases/abbreviations for commands
+ CommandObject::CommandMap m_user_dict; // Stores user-defined commands
+ OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias.
+ CommandHistory m_command_history;
+ std::string m_repeat_command; // Stores the command that will be executed for an empty command string.
+ std::unique_ptr<ScriptInterpreter> m_script_interpreter_ap;
+ char m_comment_char;
+ bool m_batch_command_mode;
+ ChildrenTruncatedWarningStatus m_truncation_warning; // Whether we truncated children and whether the user has been told
+ uint32_t m_command_source_depth;
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandInterpreter_h_
diff --git a/include/lldb/Interpreter/CommandObject.h b/include/lldb/Interpreter/CommandObject.h
new file mode 100644
index 000000000000..2bfab0a8ecc4
--- /dev/null
+++ b/include/lldb/Interpreter/CommandObject.h
@@ -0,0 +1,608 @@
+//===-- CommandObject.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_CommandObject_h_
+#define liblldb_CommandObject_h_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+class CommandObject
+{
+public:
+
+ typedef const char *(ArgumentHelpCallbackFunction) ();
+
+ struct ArgumentHelpCallback
+ {
+ ArgumentHelpCallbackFunction *help_callback;
+ bool self_formatting;
+
+ const char*
+ operator () () const
+ {
+ return (*help_callback)();
+ }
+
+ operator bool() const
+ {
+ return (help_callback != NULL);
+ }
+
+ };
+
+ struct ArgumentTableEntry // Entries in the main argument information table
+ {
+ lldb::CommandArgumentType arg_type;
+ const char *arg_name;
+ CommandCompletions::CommonCompletionTypes completion_type;
+ ArgumentHelpCallback help_function;
+ const char *help_text;
+ };
+
+ struct CommandArgumentData // Used to build individual command argument lists
+ {
+ lldb::CommandArgumentType arg_type;
+ ArgumentRepetitionType arg_repetition;
+ uint32_t arg_opt_set_association; // This arg might be associated only with some particular option set(s).
+ CommandArgumentData():
+ arg_type(lldb::eArgTypeNone),
+ arg_repetition(eArgRepeatPlain),
+ arg_opt_set_association(LLDB_OPT_SET_ALL) // By default, the arg associates to all option sets.
+ {}
+ };
+
+ typedef std::vector<CommandArgumentData> CommandArgumentEntry; // Used to build individual command argument lists
+
+ static ArgumentTableEntry g_arguments_data[lldb::eArgTypeLastArg]; // Main argument information table
+
+ typedef std::map<std::string, lldb::CommandObjectSP> CommandMap;
+
+ CommandObject (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0);
+
+ virtual
+ ~CommandObject ();
+
+
+ static const char *
+ GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type);
+
+ static const char *
+ GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
+
+ CommandInterpreter &
+ GetCommandInterpreter ()
+ {
+ return m_interpreter;
+ }
+
+ const char *
+ GetHelp ();
+
+ virtual const char *
+ GetHelpLong ();
+
+ const char *
+ GetSyntax ();
+
+ const char *
+ GetCommandName ();
+
+ void
+ SetHelp (const char * str);
+
+ void
+ SetHelpLong (const char * str);
+
+ void
+ SetHelpLong (std::string str);
+
+ void
+ SetSyntax (const char *str);
+
+ // override this to return true if you want to enable the user to delete
+ // the Command object from the Command dictionary (aliases have their own
+ // deletion scheme, so they do not need to care about this)
+ virtual bool
+ IsRemovable () const { return false; }
+
+ bool
+ IsAlias () { return m_is_alias; }
+
+ void
+ SetIsAlias (bool value) { m_is_alias = value; }
+
+ virtual bool
+ IsMultiwordObject () { return false; }
+
+ virtual lldb::CommandObjectSP
+ GetSubcommandSP (const char *sub_cmd, StringList *matches = NULL)
+ {
+ return lldb::CommandObjectSP();
+ }
+
+ virtual CommandObject *
+ GetSubcommandObject (const char *sub_cmd, StringList *matches = NULL)
+ {
+ return NULL;
+ }
+
+ virtual void
+ AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help)
+ {
+ }
+
+ void
+ GenerateHelpText (CommandReturnObject &result);
+
+ virtual void
+ GenerateHelpText (Stream &result);
+
+ // this is needed in order to allow the SBCommand class to
+ // transparently try and load subcommands - it will fail on
+ // anything but a multiword command, but it avoids us doing
+ // type checkings and casts
+ virtual bool
+ LoadSubCommand (const char *cmd_name,
+ const lldb::CommandObjectSP& command_obj)
+ {
+ return false;
+ }
+
+ virtual bool
+ WantsRawCommandString() = 0;
+
+ // By default, WantsCompletion = !WantsRawCommandString.
+ // Subclasses who want raw command string but desire, for example,
+ // argument completion should override this method to return true.
+ virtual bool
+ WantsCompletion() { return !WantsRawCommandString(); }
+
+ virtual Options *
+ GetOptions ();
+
+ static const ArgumentTableEntry*
+ GetArgumentTable ();
+
+ static lldb::CommandArgumentType
+ LookupArgumentName (const char *arg_name);
+
+ static ArgumentTableEntry *
+ FindArgumentDataByType (lldb::CommandArgumentType arg_type);
+
+ int
+ GetNumArgumentEntries ();
+
+ CommandArgumentEntry *
+ GetArgumentEntryAtIndex (int idx);
+
+ static void
+ GetArgumentHelp (Stream &str, lldb::CommandArgumentType arg_type, CommandInterpreter &interpreter);
+
+ static const char *
+ GetArgumentName (lldb::CommandArgumentType arg_type);
+
+ // Generates a nicely formatted command args string for help command output.
+ // By default, all possible args are taken into account, for example,
+ // '<expr | variable-name>'. This can be refined by passing a second arg
+ // specifying which option set(s) we are interested, which could then, for
+ // example, produce either '<expr>' or '<variable-name>'.
+ void
+ GetFormattedCommandArguments (Stream &str, uint32_t opt_set_mask = LLDB_OPT_SET_ALL);
+
+ bool
+ IsPairType (ArgumentRepetitionType arg_repeat_type);
+
+ enum
+ {
+ //----------------------------------------------------------------------
+ // eFlagRequiresTarget
+ //
+ // Ensures a valid target is contained in m_exe_ctx prior to executing
+ // the command. If a target doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidTargetDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidTargetDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eFlagRequiresTarget = (1u << 0),
+ //----------------------------------------------------------------------
+ // eFlagRequiresProcess
+ //
+ // Ensures a valid process is contained in m_exe_ctx prior to executing
+ // the command. If a process doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidProcessDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidProcessDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eFlagRequiresProcess = (1u << 1),
+ //----------------------------------------------------------------------
+ // eFlagRequiresThread
+ //
+ // Ensures a valid thread is contained in m_exe_ctx prior to executing
+ // the command. If a thread doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidThreadDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidThreadDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eFlagRequiresThread = (1u << 2),
+ //----------------------------------------------------------------------
+ // eFlagRequiresFrame
+ //
+ // Ensures a valid frame is contained in m_exe_ctx prior to executing
+ // the command. If a frame doesn't exist or is invalid, the command
+ // will fail and CommandObject::GetInvalidFrameDescription() will be
+ // returned as the error. CommandObject subclasses can override the
+ // virtual function for GetInvalidFrameDescription() to provide custom
+ // strings when needed.
+ //----------------------------------------------------------------------
+ eFlagRequiresFrame = (1u << 3),
+ //----------------------------------------------------------------------
+ // eFlagRequiresRegContext
+ //
+ // Ensures a valid register context (from the selected frame if there
+ // is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
+ // is availble from m_exe_ctx prior to executing the command. If a
+ // target doesn't exist or is invalid, the command will fail and
+ // CommandObject::GetInvalidRegContextDescription() will be returned as
+ // the error. CommandObject subclasses can override the virtual function
+ // for GetInvalidRegContextDescription() to provide custom strings when
+ // needed.
+ //----------------------------------------------------------------------
+ eFlagRequiresRegContext = (1u << 4),
+ //----------------------------------------------------------------------
+ // eFlagTryTargetAPILock
+ //
+ // Attempts to acquire the target lock if a target is selected in the
+ // command interpreter. If the command object fails to acquire the API
+ // lock, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eFlagTryTargetAPILock = (1u << 5),
+ //----------------------------------------------------------------------
+ // eFlagProcessMustBeLaunched
+ //
+ // Verifies that there is a launched process in m_exe_ctx, if there
+ // isn't, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eFlagProcessMustBeLaunched = (1u << 6),
+ //----------------------------------------------------------------------
+ // eFlagProcessMustBePaused
+ //
+ // Verifies that there is a paused process in m_exe_ctx, if there
+ // isn't, the command will fail with an appropriate error message.
+ //----------------------------------------------------------------------
+ eFlagProcessMustBePaused = (1u << 7)
+ };
+
+ bool
+ ParseOptions (Args& args, CommandReturnObject &result);
+
+ void
+ SetCommandName (const char *name);
+
+ // This function really deals with CommandObjectLists, but we didn't make a
+ // CommandObjectList class, so I'm sticking it here. But we really should have
+ // such a class. Anyway, it looks up the commands in the map that match the partial
+ // string cmd_str, inserts the matches into matches, and returns the number added.
+
+ static int
+ AddNamesMatchingPartialString (CommandMap &in_map, const char *cmd_str, StringList &matches);
+
+ //------------------------------------------------------------------
+ /// The input array contains a parsed version of the line. The insertion
+ /// point is given by cursor_index (the index in input of the word containing
+ /// the cursor) and cursor_char_position (the position of the cursor in that word.)
+ /// This default version handles calling option argument completions and then calls
+ /// HandleArgumentCompletion if the cursor is on an argument, not an option.
+ /// Don't override this method, override HandleArgumentCompletion instead unless
+ /// you have special reasons.
+ ///
+ /// @param[in] interpreter
+ /// The command interpreter doing the completion.
+ ///
+ /// @param[in] input
+ /// The command line parsed into words
+ ///
+ /// @param[in] cursor_index
+ /// The index in \ainput of the word in which the cursor lies.
+ ///
+ /// @param[in] cursor_char_pos
+ /// The character position of the cursor in its argument word.
+ ///
+ /// @param[in] match_start_point
+ /// @param[in] match_return_elements
+ /// FIXME: Not yet implemented... If there is a match that is expensive to compute, these are
+ /// here to allow you to compute the completions in batches. Start the completion from \amatch_start_point,
+ /// and return \amatch_return_elements elements.
+ ///
+ /// @param[out] word_complete
+ /// \btrue if this is a complete option value (a space will be inserted after the
+ /// completion.) \bfalse otherwise.
+ ///
+ /// @param[out] matches
+ /// The array of matches returned.
+ ///
+ /// FIXME: This is the wrong return value, since we also need to make a distinction between
+ /// total number of matches, and the window the user wants returned.
+ ///
+ /// @return
+ /// \btrue if we were in an option, \bfalse otherwise.
+ //------------------------------------------------------------------
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //------------------------------------------------------------------
+ /// The input array contains a parsed version of the line. The insertion
+ /// point is given by cursor_index (the index in input of the word containing
+ /// the cursor) and cursor_char_position (the position of the cursor in that word.)
+ /// We've constructed the map of options and their arguments as well if that is
+ /// helpful for the completion.
+ ///
+ /// @param[in] interpreter
+ /// The command interpreter doing the completion.
+ ///
+ /// @param[in] input
+ /// The command line parsed into words
+ ///
+ /// @param[in] cursor_index
+ /// The index in \ainput of the word in which the cursor lies.
+ ///
+ /// @param[in] cursor_char_pos
+ /// The character position of the cursor in its argument word.
+ ///
+ /// @param[in] opt_element_vector
+ /// The results of the options parse of \a input.
+ ///
+ /// @param[in] match_start_point
+ /// @param[in] match_return_elements
+ /// See CommandObject::HandleCompletions for a description of how these work.
+ ///
+ /// @param[out] word_complete
+ /// \btrue if this is a complete option value (a space will be inserted after the
+ /// completion.) \bfalse otherwise.
+ ///
+ /// @param[out] matches
+ /// The array of matches returned.
+ ///
+ /// FIXME: This is the wrong return value, since we also need to make a distinction between
+ /// total number of matches, and the window the user wants returned.
+ ///
+ /// @return
+ /// The number of completions.
+ //------------------------------------------------------------------
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ return 0;
+ }
+
+ bool
+ HelpTextContainsWord (const char *search_word);
+
+ //------------------------------------------------------------------
+ /// The flags accessor.
+ ///
+ /// @return
+ /// A reference to the Flags member variable.
+ //------------------------------------------------------------------
+ Flags&
+ GetFlags()
+ {
+ return m_flags;
+ }
+
+ //------------------------------------------------------------------
+ /// The flags const accessor.
+ ///
+ /// @return
+ /// A const reference to the Flags member variable.
+ //------------------------------------------------------------------
+ const Flags&
+ GetFlags() const
+ {
+ return m_flags;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the command that appropriate for a "repeat" of the current command.
+ ///
+ /// @param[in] current_command_line
+ /// The complete current command line.
+ ///
+ /// @return
+ /// NULL if there is no special repeat command - it will use the current command line.
+ /// Otherwise a pointer to the command to be repeated.
+ /// If the returned string is the empty string, the command won't be repeated.
+ //------------------------------------------------------------------
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ return NULL;
+ }
+
+ CommandOverrideCallback
+ GetOverrideCallback () const
+ {
+ return m_command_override_callback;
+ }
+
+ void *
+ GetOverrideCallbackBaton () const
+ {
+ return m_command_override_baton;
+ }
+
+ void
+ SetOverrideCallback (CommandOverrideCallback callback, void *baton)
+ {
+ m_command_override_callback = callback;
+ m_command_override_baton = baton;
+ }
+
+ virtual bool
+ Execute (const char *args_string, CommandReturnObject &result) = 0;
+
+protected:
+ virtual const char *
+ GetInvalidTargetDescription()
+ {
+ return "invalid target, create a target using the 'target create' command";
+ }
+
+ virtual const char *
+ GetInvalidProcessDescription()
+ {
+ return "invalid process";
+ }
+
+ virtual const char *
+ GetInvalidThreadDescription()
+ {
+ return "invalid thread";
+ }
+
+ virtual const char *
+ GetInvalidFrameDescription()
+ {
+ return "invalid frame";
+ }
+
+ virtual const char *
+ GetInvalidRegContextDescription ()
+ {
+ return "invalid frame, no registers";
+ }
+
+ //------------------------------------------------------------------
+ /// Check the command to make sure anything required by this
+ /// command is available.
+ ///
+ /// @param[out] result
+ /// A command result object, if it is not okay to run the command
+ /// this will be filled in with a suitable error.
+ ///
+ /// @return
+ /// \b true if it is okay to run this command, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ CheckRequirements (CommandReturnObject &result);
+
+ void
+ Cleanup ();
+
+ CommandInterpreter &m_interpreter;
+ ExecutionContext m_exe_ctx;
+ Mutex::Locker m_api_locker;
+ std::string m_cmd_name;
+ std::string m_cmd_help_short;
+ std::string m_cmd_help_long;
+ std::string m_cmd_syntax;
+ bool m_is_alias;
+ Flags m_flags;
+ std::vector<CommandArgumentEntry> m_arguments;
+ CommandOverrideCallback m_command_override_callback;
+ void * m_command_override_baton;
+
+ // Helper function to populate IDs or ID ranges as the command argument data
+ // to the specified command argument entry.
+ static void
+ AddIDsArgumentData(CommandArgumentEntry &arg, lldb::CommandArgumentType ID, lldb::CommandArgumentType IDRange);
+
+};
+
+class CommandObjectParsed : public CommandObject
+{
+public:
+
+ CommandObjectParsed (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0) :
+ CommandObject (interpreter, name, help, syntax, flags) {}
+
+ virtual
+ ~CommandObjectParsed () {};
+
+ virtual bool
+ Execute (const char *args_string, CommandReturnObject &result);
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result) = 0;
+
+ virtual bool
+ WantsRawCommandString() { return false; };
+};
+
+class CommandObjectRaw : public CommandObject
+{
+public:
+
+ CommandObjectRaw (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0) :
+ CommandObject (interpreter, name, help, syntax, flags) {}
+
+ virtual
+ ~CommandObjectRaw () {};
+
+ virtual bool
+ Execute (const char *args_string, CommandReturnObject &result);
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result) = 0;
+
+ virtual bool
+ WantsRawCommandString() { return true; };
+};
+
+
+} // namespace lldb_private
+
+
+#endif // liblldb_CommandObject_h_
diff --git a/include/lldb/Interpreter/CommandObjectMultiword.h b/include/lldb/Interpreter/CommandObjectMultiword.h
new file mode 100644
index 000000000000..491d43c4bd9d
--- /dev/null
+++ b/include/lldb/Interpreter/CommandObjectMultiword.h
@@ -0,0 +1,187 @@
+//===-- CommandObjectMultiword.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_CommandObjectMultiword_h_
+#define liblldb_CommandObjectMultiword_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiword
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiword : public CommandObject
+{
+// These two want to iterate over the subcommand dictionary.
+friend class CommandInterpreter;
+friend class CommandObjectSyntax;
+public:
+ CommandObjectMultiword (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0);
+
+ virtual
+ ~CommandObjectMultiword ();
+
+ virtual bool
+ IsMultiwordObject () { return true; }
+
+ virtual bool
+ LoadSubCommand (const char *cmd_name,
+ const lldb::CommandObjectSP& command_obj);
+
+ virtual void
+ GenerateHelpText (Stream &output_stream);
+
+ virtual lldb::CommandObjectSP
+ GetSubcommandSP (const char *sub_cmd, StringList *matches = NULL);
+
+ virtual CommandObject *
+ GetSubcommandObject (const char *sub_cmd, StringList *matches = NULL);
+
+ virtual void
+ AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help);
+
+ virtual bool
+ WantsRawCommandString() { return false; };
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index);
+
+ virtual bool
+ Execute (const char *args_string,
+ CommandReturnObject &result);
+
+ virtual bool
+ IsRemovable() const { return m_can_be_removed; }
+
+ void
+ SetRemovable (bool removable)
+ {
+ m_can_be_removed = removable;
+ }
+
+protected:
+
+ CommandObject::CommandMap m_subcommand_dict;
+ bool m_can_be_removed;
+};
+
+
+class CommandObjectProxy : public CommandObject
+{
+public:
+ CommandObjectProxy (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0);
+
+ virtual
+ ~CommandObjectProxy ();
+
+ // Subclasses must provide a command object that will be transparently
+ // used for this object.
+ virtual CommandObject *
+ GetProxyCommandObject() = 0;
+
+ virtual const char *
+ GetHelpLong ();
+
+ virtual bool
+ IsRemovable() const;
+
+ virtual bool
+ IsMultiwordObject ();
+
+ virtual lldb::CommandObjectSP
+ GetSubcommandSP (const char *sub_cmd, StringList *matches = NULL);
+
+ virtual CommandObject *
+ GetSubcommandObject (const char *sub_cmd, StringList *matches = NULL);
+
+ virtual void
+ AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help);
+
+ virtual bool
+ LoadSubCommand (const char *cmd_name,
+ const lldb::CommandObjectSP& command_obj);
+
+ virtual bool
+ WantsRawCommandString();
+
+ virtual bool
+ WantsCompletion();
+
+ virtual Options *
+ GetOptions ();
+
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ virtual const char *
+ GetRepeatCommand (Args &current_command_args,
+ uint32_t index);
+
+ virtual bool
+ Execute (const char *args_string,
+ CommandReturnObject &result);
+
+protected:
+
+ // These two want to iterate over the subcommand dictionary.
+ friend class CommandInterpreter;
+ friend class CommandObjectSyntax;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectMultiword_h_
diff --git a/include/lldb/Interpreter/CommandObjectRegexCommand.h b/include/lldb/Interpreter/CommandObjectRegexCommand.h
new file mode 100644
index 000000000000..8855680d5f8b
--- /dev/null
+++ b/include/lldb/Interpreter/CommandObjectRegexCommand.h
@@ -0,0 +1,81 @@
+//===-- CommandObjectRegexCommand.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_CommandObjectRegexCommand_h_
+#define liblldb_CommandObjectRegexCommand_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectRegexCommand
+//-------------------------------------------------------------------------
+
+class CommandObjectRegexCommand : public CommandObjectRaw
+{
+public:
+
+ CommandObjectRegexCommand (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t max_matches,
+ uint32_t completion_type_mask = 0);
+
+ virtual
+ ~CommandObjectRegexCommand ();
+
+ bool
+ AddRegexCommand (const char *re_cstr, const char *command_cstr);
+
+ bool
+ HasRegexEntries () const
+ {
+ return !m_entries.empty();
+ }
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result);
+
+ struct Entry
+ {
+ RegularExpression regex;
+ std::string command;
+ };
+
+ typedef std::list<Entry> EntryCollection;
+ const uint32_t m_max_matches;
+ const uint32_t m_completion_type_mask;
+ EntryCollection m_entries;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectRegexCommand);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectRegexCommand_h_
diff --git a/include/lldb/Interpreter/CommandReturnObject.h b/include/lldb/Interpreter/CommandReturnObject.h
new file mode 100644
index 000000000000..acd03992e5e6
--- /dev/null
+++ b/include/lldb/Interpreter/CommandReturnObject.h
@@ -0,0 +1,183 @@
+//===-- CommandReturnObject.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_CommandReturnObject_h_
+#define liblldb_CommandReturnObject_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/STLUtils.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StreamTee.h"
+
+namespace lldb_private {
+
+
+class CommandReturnObject
+{
+public:
+
+ CommandReturnObject ();
+
+ ~CommandReturnObject ();
+
+ const char *
+ GetOutputData ()
+ {
+ lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex));
+ if (stream_sp)
+ return static_cast<StreamString *>(stream_sp.get())->GetData();
+ return "";
+ }
+
+ const char *
+ GetErrorData ()
+ {
+ lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex));
+ if (stream_sp)
+ return static_cast<StreamString *>(stream_sp.get())->GetData();
+ else
+ return "";
+ }
+
+ Stream &
+ GetOutputStream ()
+ {
+ // Make sure we at least have our normal string stream output stream
+ lldb::StreamSP stream_sp (m_out_stream.GetStreamAtIndex (eStreamStringIndex));
+ if (!stream_sp)
+ {
+ stream_sp.reset (new StreamString());
+ m_out_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp);
+ }
+ return m_out_stream;
+ }
+
+ Stream &
+ GetErrorStream ()
+ {
+ // Make sure we at least have our normal string stream output stream
+ lldb::StreamSP stream_sp (m_err_stream.GetStreamAtIndex (eStreamStringIndex));
+ if (!stream_sp)
+ {
+ stream_sp.reset (new StreamString());
+ m_err_stream.SetStreamAtIndex (eStreamStringIndex, stream_sp);
+ }
+ return m_err_stream;
+ }
+
+ void
+ SetImmediateOutputFile (FILE *fh, bool transfer_fh_ownership = false)
+ {
+ lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership));
+ m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
+ }
+
+ void
+ SetImmediateErrorFile (FILE *fh, bool transfer_fh_ownership = false)
+ {
+ lldb::StreamSP stream_sp (new StreamFile (fh, transfer_fh_ownership));
+ m_err_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
+ }
+
+ void
+ SetImmediateOutputStream (const lldb::StreamSP &stream_sp)
+ {
+ m_out_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
+ }
+
+ void
+ SetImmediateErrorStream (const lldb::StreamSP &stream_sp)
+ {
+ m_err_stream.SetStreamAtIndex (eImmediateStreamIndex, stream_sp);
+ }
+
+ lldb::StreamSP
+ GetImmediateOutputStream ()
+ {
+ return m_out_stream.GetStreamAtIndex (eImmediateStreamIndex);
+ }
+
+ lldb::StreamSP
+ GetImmediateErrorStream ()
+ {
+ return m_err_stream.GetStreamAtIndex (eImmediateStreamIndex);
+ }
+
+ void
+ Clear();
+
+ void
+ AppendMessage (const char *in_string);
+
+ void
+ AppendMessageWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ AppendRawWarning (const char *in_string);
+
+ void
+ AppendWarning (const char *in_string);
+
+ void
+ AppendWarningWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ AppendError (const char *in_string);
+
+ void
+ AppendRawError (const char *in_string);
+
+ void
+ AppendErrorWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ SetError (const Error &error,
+ const char *fallback_error_cstr = NULL);
+
+ void
+ SetError (const char *error_cstr);
+
+ lldb::ReturnStatus
+ GetStatus();
+
+ void
+ SetStatus (lldb::ReturnStatus status);
+
+ bool
+ Succeeded ();
+
+ bool
+ HasResult ();
+
+ bool GetDidChangeProcessState ();
+
+ void SetDidChangeProcessState (bool b);
+
+private:
+ enum
+ {
+ eStreamStringIndex = 0,
+ eImmediateStreamIndex = 1
+ };
+
+ StreamTee m_out_stream;
+ StreamTee m_err_stream;
+
+ lldb::ReturnStatus m_status;
+ bool m_did_change_process_state;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandReturnObject_h_
diff --git a/include/lldb/Interpreter/OptionGroupArchitecture.h b/include/lldb/Interpreter/OptionGroupArchitecture.h
new file mode 100644
index 000000000000..7cd1ca3d710d
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupArchitecture.h
@@ -0,0 +1,73 @@
+//===-- OptionGroupArchitecture.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_OptionGroupArchitecture_h_
+#define liblldb_OptionGroupArchitecture_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/ArchSpec.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupArchitecture
+//-------------------------------------------------------------------------
+
+class OptionGroupArchitecture : public OptionGroup
+{
+public:
+
+ OptionGroupArchitecture ();
+
+ virtual
+ ~OptionGroupArchitecture ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ bool
+ GetArchitecture (Platform *platform, ArchSpec &arch);
+
+ bool
+ ArchitectureWasSpecified () const
+ {
+ return !m_arch_str.empty();
+ }
+ const char *
+ GetArchitectureName ()
+ {
+ if (m_arch_str.empty())
+ return NULL;
+ return m_arch_str.c_str();
+ }
+
+protected:
+
+ std::string m_arch_str; // Save the arch triple in case a platform is specified after the architecture
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupArchitecture_h_
diff --git a/include/lldb/Interpreter/OptionGroupBoolean.h b/include/lldb/Interpreter/OptionGroupBoolean.h
new file mode 100644
index 000000000000..0d861b241694
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupBoolean.h
@@ -0,0 +1,83 @@
+//===-- OptionGroupBoolean.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_OptionGroupBoolean_h_
+#define liblldb_OptionGroupBoolean_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+
+namespace lldb_private {
+ //-------------------------------------------------------------------------
+ // OptionGroupBoolean
+ //-------------------------------------------------------------------------
+
+ class OptionGroupBoolean : public OptionGroup
+ {
+ public:
+ // When 'no_argument_toggle_default' is true, then setting the option
+ // value does NOT require an argument, it sets the boolean value to the
+ // inverse of the default value
+ OptionGroupBoolean (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ const char *usage_text,
+ bool default_value,
+ bool no_argument_toggle_default);
+
+ virtual
+ ~OptionGroupBoolean ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return &m_option_definition;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ OptionValueBoolean &
+ GetOptionValue ()
+ {
+ return m_value;
+ }
+
+ const OptionValueBoolean &
+ GetOptionValue () const
+ {
+ return m_value;
+ }
+
+ protected:
+ OptionValueBoolean m_value;
+ OptionDefinition m_option_definition;
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupBoolean_h_
diff --git a/include/lldb/Interpreter/OptionGroupFile.h b/include/lldb/Interpreter/OptionGroupFile.h
new file mode 100644
index 000000000000..632a2dbdf220
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupFile.h
@@ -0,0 +1,142 @@
+//===-- OptionGroupFile.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_OptionGroupFile_h_
+#define liblldb_OptionGroupFile_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueFileSpec.h"
+#include "lldb/Interpreter/OptionValueFileSpecList.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupFile
+//-------------------------------------------------------------------------
+
+class OptionGroupFile : public OptionGroup
+{
+public:
+
+ OptionGroupFile (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text);
+
+ virtual
+ ~OptionGroupFile ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return &m_option_definition;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ OptionValueFileSpec &
+ GetOptionValue ()
+ {
+ return m_file;
+ }
+
+ const OptionValueFileSpec &
+ GetOptionValue () const
+ {
+ return m_file;
+ }
+
+protected:
+ OptionValueFileSpec m_file;
+ OptionDefinition m_option_definition;
+
+};
+
+//-------------------------------------------------------------------------
+// OptionGroupFileList
+//-------------------------------------------------------------------------
+
+class OptionGroupFileList : public OptionGroup
+{
+public:
+
+ OptionGroupFileList (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text);
+
+ virtual
+ ~OptionGroupFileList ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return &m_option_definition;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+
+ OptionValueFileSpecList &
+ GetOptionValue ()
+ {
+ return m_file_list;
+ }
+
+ const OptionValueFileSpecList &
+ GetOptionValue () const
+ {
+ return m_file_list;
+ }
+
+protected:
+ OptionValueFileSpecList m_file_list;
+ OptionDefinition m_option_definition;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupFile_h_
diff --git a/include/lldb/Interpreter/OptionGroupFormat.h b/include/lldb/Interpreter/OptionGroupFormat.h
new file mode 100644
index 000000000000..7419b0496668
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupFormat.h
@@ -0,0 +1,133 @@
+//===-- OptionGroupFormat.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_OptionGroupFormat_h_
+#define liblldb_OptionGroupFormat_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueFormat.h"
+#include "lldb/Interpreter/OptionValueSInt64.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupFormat
+//-------------------------------------------------------------------------
+
+class OptionGroupFormat : public OptionGroup
+{
+public:
+ static const uint32_t OPTION_GROUP_FORMAT = LLDB_OPT_SET_1;
+ static const uint32_t OPTION_GROUP_GDB_FMT = LLDB_OPT_SET_2;
+ static const uint32_t OPTION_GROUP_SIZE = LLDB_OPT_SET_3;
+ static const uint32_t OPTION_GROUP_COUNT = LLDB_OPT_SET_4;
+
+ OptionGroupFormat (lldb::Format default_format,
+ uint64_t default_byte_size = UINT64_MAX, // Pass UINT64_MAX to disable the "--size" option
+ uint64_t default_count = UINT64_MAX); // Pass UINT64_MAX to disable the "--count" option
+
+ virtual
+ ~OptionGroupFormat ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ lldb::Format
+ GetFormat () const
+ {
+ return m_format.GetCurrentValue();
+ }
+
+ OptionValueFormat &
+ GetFormatValue()
+ {
+ return m_format;
+ }
+
+ const OptionValueFormat &
+ GetFormatValue() const
+ {
+ return m_format;
+ }
+
+ OptionValueUInt64 &
+ GetByteSizeValue()
+ {
+ return m_byte_size;
+ }
+
+ const OptionValueUInt64 &
+ GetByteSizeValue() const
+ {
+ return m_byte_size;
+ }
+
+ OptionValueUInt64 &
+ GetCountValue()
+ {
+ return m_count;
+ }
+
+ const OptionValueUInt64 &
+ GetCountValue() const
+ {
+ return m_count;
+ }
+
+ bool
+ HasGDBFormat () const
+ {
+ return m_has_gdb_format;
+ }
+
+ bool
+ AnyOptionWasSet () const
+ {
+ return m_format.OptionWasSet() ||
+ m_byte_size.OptionWasSet() ||
+ m_count.OptionWasSet();
+ }
+
+protected:
+
+ bool
+ ParserGDBFormatLetter (CommandInterpreter &interpreter,
+ char format_letter,
+ lldb::Format &format,
+ uint32_t &byte_size);
+
+ OptionValueFormat m_format;
+ OptionValueUInt64 m_byte_size;
+ OptionValueUInt64 m_count;
+ char m_prev_gdb_format;
+ char m_prev_gdb_size;
+
+ bool m_has_gdb_format;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupFormat_h_
diff --git a/include/lldb/Interpreter/OptionGroupOutputFile.h b/include/lldb/Interpreter/OptionGroupOutputFile.h
new file mode 100644
index 000000000000..533cd6ee8eb3
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupOutputFile.h
@@ -0,0 +1,76 @@
+//===-- OptionGroupOutputFile.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_OptionGroupOutputFile_h_
+#define liblldb_OptionGroupOutputFile_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueFileSpec.h"
+
+namespace lldb_private {
+//-------------------------------------------------------------------------
+// OptionGroupOutputFile
+//-------------------------------------------------------------------------
+
+class OptionGroupOutputFile : public OptionGroup
+{
+public:
+
+ OptionGroupOutputFile ();
+
+ virtual
+ ~OptionGroupOutputFile ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ const OptionValueFileSpec &
+ GetFile ()
+ {
+ return m_file;
+ }
+
+ const OptionValueBoolean &
+ GetAppend ()
+ {
+ return m_append;
+ }
+
+ bool
+ AnyOptionWasSet () const
+ {
+ return m_file.OptionWasSet() || m_append.OptionWasSet();
+ }
+
+protected:
+ OptionValueFileSpec m_file;
+ OptionValueBoolean m_append;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupOutputFile_h_
diff --git a/include/lldb/Interpreter/OptionGroupPlatform.h b/include/lldb/Interpreter/OptionGroupPlatform.h
new file mode 100644
index 000000000000..970ad328ccb7
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupPlatform.h
@@ -0,0 +1,120 @@
+//===-- OptionGroupPlatform.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_OptionGroupPlatform_h_
+#define liblldb_OptionGroupPlatform_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// PlatformOptionGroup
+//
+// Make platform options available to any commands that need the settings.
+//-------------------------------------------------------------------------
+class OptionGroupPlatform : public OptionGroup
+{
+public:
+
+ OptionGroupPlatform (bool include_platform_option) :
+ OptionGroup(),
+ m_platform_name (),
+ m_sdk_sysroot (),
+ m_os_version_major (UINT32_MAX),
+ m_os_version_minor (UINT32_MAX),
+ m_os_version_update (UINT32_MAX),
+ m_include_platform_option (include_platform_option)
+ {
+ }
+
+ virtual
+ ~OptionGroupPlatform ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ lldb::PlatformSP
+ CreatePlatformWithOptions (CommandInterpreter &interpreter,
+ const ArchSpec &arch,
+ bool make_selected,
+ Error& error,
+ ArchSpec &platform_arch) const;
+
+ bool
+ PlatformWasSpecified () const
+ {
+ return !m_platform_name.empty();
+ }
+
+ void
+ SetPlatformName (const char *platform_name)
+ {
+ if (platform_name && platform_name[0])
+ m_platform_name.assign (platform_name);
+ else
+ m_platform_name.clear();
+ }
+
+ const ConstString &
+ GetSDKRootDirectory () const
+ {
+ return m_sdk_sysroot;
+ }
+
+ void
+ SetSDKRootDirectory (const ConstString &sdk_root_directory)
+ {
+ m_sdk_sysroot = sdk_root_directory;
+ }
+
+ const ConstString &
+ GetSDKBuild () const
+ {
+ return m_sdk_build;
+ }
+
+ void
+ SetSDKBuild (const ConstString &sdk_build)
+ {
+ m_sdk_build = sdk_build;
+ }
+
+
+protected:
+ std::string m_platform_name;
+ ConstString m_sdk_sysroot;
+ ConstString m_sdk_build;
+ uint32_t m_os_version_major;
+ uint32_t m_os_version_minor;
+ uint32_t m_os_version_update;
+ bool m_include_platform_option;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupPlatform_h_
diff --git a/include/lldb/Interpreter/OptionGroupString.h b/include/lldb/Interpreter/OptionGroupString.h
new file mode 100644
index 000000000000..e62a81bc4118
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupString.h
@@ -0,0 +1,82 @@
+//===-- OptionGroupString.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_OptionGroupString_h_
+#define liblldb_OptionGroupString_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueString.h"
+
+namespace lldb_private {
+ //-------------------------------------------------------------------------
+ // OptionGroupString
+ //-------------------------------------------------------------------------
+
+ class OptionGroupString : public OptionGroup
+ {
+ public:
+
+ OptionGroupString (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ const char *default_value);
+
+ virtual
+ ~OptionGroupString ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return &m_option_definition;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ OptionValueString &
+ GetOptionValue ()
+ {
+ return m_value;
+ }
+
+ const OptionValueString &
+ GetOptionValue () const
+ {
+ return m_value;
+ }
+
+ protected:
+ OptionValueString m_value;
+ OptionDefinition m_option_definition;
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupString_h_
diff --git a/include/lldb/Interpreter/OptionGroupUInt64.h b/include/lldb/Interpreter/OptionGroupUInt64.h
new file mode 100644
index 000000000000..c5f9e85d2f8f
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupUInt64.h
@@ -0,0 +1,82 @@
+//===-- OptionGroupUInt64.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_OptionGroupUInt64_h_
+#define liblldb_OptionGroupUInt64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+
+namespace lldb_private {
+ //-------------------------------------------------------------------------
+ // OptionGroupUInt64
+ //-------------------------------------------------------------------------
+
+ class OptionGroupUInt64 : public OptionGroup
+ {
+ public:
+
+ OptionGroupUInt64 (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ uint64_t default_value);
+
+ virtual
+ ~OptionGroupUInt64 ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return 1;
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return &m_option_definition;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ OptionValueUInt64 &
+ GetOptionValue ()
+ {
+ return m_value;
+ }
+
+ const OptionValueUInt64 &
+ GetOptionValue () const
+ {
+ return m_value;
+ }
+
+ protected:
+ OptionValueUInt64 m_value;
+ OptionDefinition m_option_definition;
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupUInt64_h_
diff --git a/include/lldb/Interpreter/OptionGroupUUID.h b/include/lldb/Interpreter/OptionGroupUUID.h
new file mode 100644
index 000000000000..ea968d737969
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupUUID.h
@@ -0,0 +1,61 @@
+//===-- OptionGroupUUID.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_OptionGroupUUID_h_
+#define liblldb_OptionGroupUUID_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionValueUUID.h"
+
+namespace lldb_private {
+//-------------------------------------------------------------------------
+// OptionGroupUUID
+//-------------------------------------------------------------------------
+
+class OptionGroupUUID : public OptionGroup
+{
+public:
+
+ OptionGroupUUID ();
+
+ virtual
+ ~OptionGroupUUID ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ const OptionValueUUID &
+ GetOptionValue () const
+ {
+ return m_uuid;
+ }
+
+protected:
+ OptionValueUUID m_uuid;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupUUID_h_
diff --git a/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h b/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
new file mode 100644
index 000000000000..da05e127d5d1
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupValueObjectDisplay.h
@@ -0,0 +1,85 @@
+//===-- OptionGroupValueObjectDisplay.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_OptionGroupValueObjectDisplay_h_
+#define liblldb_OptionGroupValueObjectDisplay_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupValueObjectDisplay
+//-------------------------------------------------------------------------
+
+class OptionGroupValueObjectDisplay : public OptionGroup
+{
+public:
+
+ OptionGroupValueObjectDisplay ();
+
+ virtual
+ ~OptionGroupValueObjectDisplay ();
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ bool
+ AnyOptionWasSet () const
+ {
+ return show_types == true ||
+ no_summary_depth != 0 ||
+ show_location == true ||
+ flat_output == true ||
+ use_objc == true ||
+ max_depth != UINT32_MAX ||
+ ptr_depth != 0 ||
+ use_synth == false ||
+ be_raw == true ||
+ ignore_cap == true;
+ }
+
+ ValueObject::DumpValueObjectOptions
+ GetAsDumpOptions (bool objc_is_compact = false,
+ lldb::Format format = lldb::eFormatDefault,
+ lldb::TypeSummaryImplSP summary_sp = lldb::TypeSummaryImplSP());
+
+ bool show_types;
+ uint32_t no_summary_depth;
+ bool show_location;
+ bool flat_output;
+ bool use_objc;
+ uint32_t max_depth;
+ uint32_t ptr_depth;
+ lldb::DynamicValueType use_dynamic;
+ bool use_synth;
+ bool be_raw;
+ bool ignore_cap;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupValueObjectDisplay_h_
diff --git a/include/lldb/Interpreter/OptionGroupVariable.h b/include/lldb/Interpreter/OptionGroupVariable.h
new file mode 100644
index 000000000000..40f4d436bc69
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupVariable.h
@@ -0,0 +1,65 @@
+//===-- OptionGroupVariable.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_OptionGroupVariable_h_
+#define liblldb_OptionGroupVariable_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupVariable
+//-------------------------------------------------------------------------
+
+ class OptionGroupVariable : public OptionGroup
+ {
+ public:
+
+ OptionGroupVariable (bool show_frame_options);
+
+ virtual
+ ~OptionGroupVariable ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ bool include_frame_options:1,
+ show_args:1, // Frame option only (include_frame_options == true)
+ show_locals:1, // Frame option only (include_frame_options == true)
+ show_globals:1, // Frame option only (include_frame_options == true)
+ use_regex:1,
+ show_scope:1,
+ show_decl:1;
+ OptionValueString summary; // the name of a named summary
+ OptionValueString summary_string; // a summary string
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionGroupVariable);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupVariable_h_
diff --git a/include/lldb/Interpreter/OptionGroupWatchpoint.h b/include/lldb/Interpreter/OptionGroupWatchpoint.h
new file mode 100644
index 000000000000..1298da80750e
--- /dev/null
+++ b/include/lldb/Interpreter/OptionGroupWatchpoint.h
@@ -0,0 +1,71 @@
+//===-- OptionGroupWatchpoint.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_OptionGroupWatchpoint_h_
+#define liblldb_OptionGroupWatchpoint_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// OptionGroupWatchpoint
+//-------------------------------------------------------------------------
+
+ class OptionGroupWatchpoint : public OptionGroup
+ {
+ public:
+
+ static bool
+ IsWatchSizeSupported(uint32_t watch_size);
+
+ OptionGroupWatchpoint ();
+
+ virtual
+ ~OptionGroupWatchpoint ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ // Note:
+ // eWatchRead == LLDB_WATCH_TYPE_READ; and
+ // eWatchWrite == LLDB_WATCH_TYPE_WRITE
+ typedef enum WatchType {
+ eWatchInvalid = 0,
+ eWatchRead,
+ eWatchWrite,
+ eWatchReadWrite
+ } WatchType;
+
+ WatchType watch_type;
+ uint32_t watch_size;
+ bool watch_type_specified;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OptionGroupWatchpoint);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionGroupWatchpoint_h_
diff --git a/include/lldb/Interpreter/OptionValue.h b/include/lldb/Interpreter/OptionValue.h
new file mode 100644
index 000000000000..33e7fc5f818b
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValue.h
@@ -0,0 +1,384 @@
+//===-- OptionValue.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_OptionValue_h_
+#define liblldb_OptionValue_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+
+namespace lldb_private {
+
+ //---------------------------------------------------------------------
+ // OptionValue
+ //---------------------------------------------------------------------
+ class OptionValue
+ {
+ public:
+ typedef enum {
+ eTypeInvalid = 0,
+ eTypeArch,
+ eTypeArgs,
+ eTypeArray,
+ eTypeBoolean,
+ eTypeDictionary,
+ eTypeEnum,
+ eTypeFileSpec,
+ eTypeFileSpecList,
+ eTypeFormat,
+ eTypePathMap,
+ eTypeProperties,
+ eTypeRegex,
+ eTypeSInt64,
+ eTypeString,
+ eTypeUInt64,
+ eTypeUUID
+ } Type;
+
+ enum {
+ eDumpOptionName = (1u << 0),
+ eDumpOptionType = (1u << 1),
+ eDumpOptionValue = (1u << 2),
+ eDumpOptionDescription = (1u << 3),
+ eDumpOptionRaw = (1u << 4),
+ eDumpGroupValue = (eDumpOptionName | eDumpOptionType | eDumpOptionValue),
+ eDumpGroupHelp = (eDumpOptionName | eDumpOptionType | eDumpOptionDescription)
+ };
+
+
+ OptionValue () :
+ m_value_was_set (false)
+ {
+ }
+
+ OptionValue (const OptionValue &rhs) :
+ m_value_was_set (rhs.m_value_was_set)
+ {
+ }
+
+ virtual ~OptionValue ()
+ {
+ }
+ //-----------------------------------------------------------------
+ // Subclasses should override these functions
+ //-----------------------------------------------------------------
+ virtual Type
+ GetType () const = 0;
+
+ // If this value is always hidden, the avoid showing any info on this
+ // value, just show the info for the child values.
+ virtual bool
+ ValueIsTransparent () const
+ {
+ return GetType() == eTypeProperties;
+ }
+
+ virtual const char *
+ GetTypeAsCString () const
+ {
+ return GetBuiltinTypeAsCString(GetType());
+ }
+
+
+ static const char *
+ GetBuiltinTypeAsCString (Type t);
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) = 0;
+
+ virtual Error
+ SetValueFromCString (const char *value, VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear () = 0;
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const = 0;
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //-----------------------------------------------------------------
+ // Subclasses can override these functions
+ //-----------------------------------------------------------------
+ virtual lldb::OptionValueSP
+ GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool will_modify,
+ Error &error) const
+ {
+ error.SetErrorStringWithFormat("'%s' is not a value subvalue", name);
+ return lldb::OptionValueSP();
+ }
+
+ virtual Error
+ SetSubValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *name,
+ const char *value);
+
+ virtual bool
+ IsAggregateValue () const
+ {
+ return false;
+ }
+
+ virtual ConstString
+ GetName() const
+ {
+ return ConstString();
+ }
+
+ virtual bool
+ DumpQualifiedName (Stream &strm) const;
+ //-----------------------------------------------------------------
+ // Subclasses should NOT override these functions as they use the
+ // above functions to implement functionality
+ //-----------------------------------------------------------------
+ uint32_t
+ GetTypeAsMask ()
+ {
+ return 1u << GetType();
+ }
+
+ static uint32_t
+ ConvertTypeToMask (OptionValue::Type type)
+ {
+ return 1u << type;
+ }
+
+ static OptionValue::Type
+ ConvertTypeMaskToType (uint32_t type_mask)
+ {
+ // If only one bit is set, then return an appropriate enumeration
+ switch (type_mask)
+ {
+ case 1u << eTypeArch: return eTypeArch;
+ case 1u << eTypeArgs: return eTypeArgs;
+ case 1u << eTypeArray: return eTypeArray;
+ case 1u << eTypeBoolean: return eTypeBoolean;
+ case 1u << eTypeDictionary: return eTypeDictionary;
+ case 1u << eTypeEnum: return eTypeEnum;
+ case 1u << eTypeFileSpec: return eTypeFileSpec;
+ case 1u << eTypeFileSpecList: return eTypeFileSpecList;
+ case 1u << eTypeFormat: return eTypeFormat;
+ case 1u << eTypePathMap: return eTypePathMap;
+ case 1u << eTypeProperties: return eTypeProperties;
+ case 1u << eTypeRegex: return eTypeRegex;
+ case 1u << eTypeSInt64: return eTypeSInt64;
+ case 1u << eTypeString: return eTypeString;
+ case 1u << eTypeUInt64: return eTypeUInt64;
+ case 1u << eTypeUUID: return eTypeUUID;
+ }
+ // Else return invalid
+ return eTypeInvalid;
+ }
+
+ static lldb::OptionValueSP
+ CreateValueFromCStringForTypeMask (const char *value_cstr,
+ uint32_t type_mask,
+ Error &error);
+
+ // Get this value as a uint64_t value if it is encoded as a boolean,
+ // uint64_t or int64_t. Other types will cause "fail_value" to be
+ // returned
+ uint64_t
+ GetUInt64Value (uint64_t fail_value, bool *success_ptr);
+
+ OptionValueArch *
+ GetAsArch ();
+
+ const OptionValueArch *
+ GetAsArch () const;
+
+ OptionValueArray *
+ GetAsArray ();
+
+ const OptionValueArray *
+ GetAsArray () const;
+
+ OptionValueArgs *
+ GetAsArgs ();
+
+ const OptionValueArgs *
+ GetAsArgs () const;
+
+ OptionValueBoolean *
+ GetAsBoolean ();
+
+ const OptionValueBoolean *
+ GetAsBoolean () const;
+
+ OptionValueDictionary *
+ GetAsDictionary ();
+
+ const OptionValueDictionary *
+ GetAsDictionary () const;
+
+ OptionValueEnumeration *
+ GetAsEnumeration ();
+
+ const OptionValueEnumeration *
+ GetAsEnumeration () const;
+
+ OptionValueFileSpec *
+ GetAsFileSpec ();
+
+ const OptionValueFileSpec *
+ GetAsFileSpec () const;
+
+ OptionValueFileSpecList *
+ GetAsFileSpecList ();
+
+ const OptionValueFileSpecList *
+ GetAsFileSpecList () const;
+
+ OptionValueFormat *
+ GetAsFormat ();
+
+ const OptionValueFormat *
+ GetAsFormat () const;
+
+ OptionValuePathMappings *
+ GetAsPathMappings ();
+
+ const OptionValuePathMappings *
+ GetAsPathMappings () const;
+
+ OptionValueProperties *
+ GetAsProperties ();
+
+ const OptionValueProperties *
+ GetAsProperties () const;
+
+ OptionValueRegex *
+ GetAsRegex ();
+
+ const OptionValueRegex *
+ GetAsRegex () const;
+
+ OptionValueSInt64 *
+ GetAsSInt64 ();
+
+ const OptionValueSInt64 *
+ GetAsSInt64 () const;
+
+ OptionValueString *
+ GetAsString ();
+
+ const OptionValueString *
+ GetAsString () const;
+
+ OptionValueUInt64 *
+ GetAsUInt64 ();
+
+ const OptionValueUInt64 *
+ GetAsUInt64 () const;
+
+ OptionValueUUID *
+ GetAsUUID ();
+
+ const OptionValueUUID *
+ GetAsUUID () const;
+
+ bool
+ GetBooleanValue (bool fail_value = false) const;
+
+ bool
+ SetBooleanValue (bool new_value);
+
+ int64_t
+ GetEnumerationValue (int64_t fail_value = -1) const;
+
+ bool
+ SetEnumerationValue (int64_t value);
+
+ FileSpec
+ GetFileSpecValue () const;
+
+ bool
+ SetFileSpecValue (const FileSpec &file_spec);
+
+ FileSpecList
+ GetFileSpecListValue () const;
+
+ lldb::Format
+ GetFormatValue (lldb::Format fail_value = lldb::eFormatDefault) const;
+
+ bool
+ SetFormatValue (lldb::Format new_value);
+
+ const RegularExpression *
+ GetRegexValue () const;
+
+ int64_t
+ GetSInt64Value (int64_t fail_value = 0) const;
+
+ bool
+ SetSInt64Value (int64_t new_value);
+
+ const char *
+ GetStringValue (const char *fail_value = NULL) const;
+
+ bool
+ SetStringValue (const char *new_value);
+
+ uint64_t
+ GetUInt64Value (uint64_t fail_value = 0) const;
+
+ bool
+ SetUInt64Value (uint64_t new_value);
+
+ UUID
+ GetUUIDValue () const;
+
+ bool
+ SetUUIDValue (const UUID &uuid);
+
+ bool
+ OptionWasSet () const
+ {
+ return m_value_was_set;
+ }
+
+ void
+ SetOptionWasSet ()
+ {
+ m_value_was_set = true;
+ }
+
+ void
+ SetParent (const lldb::OptionValueSP &parent_sp)
+ {
+ m_parent_wp = parent_sp;
+ }
+ protected:
+ lldb::OptionValueWP m_parent_wp;
+ bool m_value_was_set; // This can be used to see if a value has been set
+ // by a call to SetValueFromCString(). It is often
+ // handy to know if an option value was set from
+ // the command line or as a setting, versus if we
+ // just have the default value that was already
+ // populated in the option value.
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValue_h_
diff --git a/include/lldb/Interpreter/OptionValueArch.h b/include/lldb/Interpreter/OptionValueArch.h
new file mode 100644
index 000000000000..662e1ec9f627
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueArch.h
@@ -0,0 +1,139 @@
+//===-- OptionValueArch.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_OptionValueArch_h_
+#define liblldb_OptionValueArch_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueArch : public OptionValue
+{
+public:
+ OptionValueArch () :
+ OptionValue(),
+ m_current_value (),
+ m_default_value ()
+ {
+ }
+
+ OptionValueArch (const char *triple) :
+ OptionValue(),
+ m_current_value (triple),
+ m_default_value ()
+ {
+ m_default_value = m_current_value;
+ }
+
+ OptionValueArch (const ArchSpec &value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value)
+ {
+ }
+
+ OptionValueArch (const ArchSpec &current_value,
+ const ArchSpec &default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value)
+ {
+ }
+
+ virtual
+ ~OptionValueArch()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeArch;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ ArchSpec &
+ GetCurrentValue()
+ {
+ return m_current_value;
+ }
+
+ const ArchSpec &
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ const ArchSpec &
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (const ArchSpec &value, bool set_value_was_set)
+ {
+ m_current_value = value;
+ if (set_value_was_set)
+ m_value_was_set = true;
+ }
+
+ void
+ SetDefaultValue (const ArchSpec &value)
+ {
+ m_default_value = value;
+ }
+
+protected:
+ ArchSpec m_current_value;
+ ArchSpec m_default_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueArch_h_
diff --git a/include/lldb/Interpreter/OptionValueArgs.h b/include/lldb/Interpreter/OptionValueArgs.h
new file mode 100644
index 000000000000..365a52a8b39f
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueArgs.h
@@ -0,0 +1,46 @@
+//===-- OptionValueArgs.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_OptionValueArgs_h_
+#define liblldb_OptionValueArgs_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValueArray.h"
+
+namespace lldb_private {
+
+class OptionValueArgs : public OptionValueArray
+{
+public:
+ OptionValueArgs () :
+ OptionValueArray (OptionValue::ConvertTypeToMask (OptionValue::eTypeString))
+ {
+ }
+
+ virtual
+ ~OptionValueArgs()
+ {
+ }
+
+ size_t
+ GetArgs (Args &args);
+
+ virtual Type
+ GetType() const
+ {
+ return eTypeArgs;
+ }
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueArgs_h_
diff --git a/include/lldb/Interpreter/OptionValueArray.h b/include/lldb/Interpreter/OptionValueArray.h
new file mode 100644
index 000000000000..39ae2f6f43d6
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueArray.h
@@ -0,0 +1,178 @@
+//===-- OptionValueArray.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_OptionValueArray_h_
+#define liblldb_OptionValueArray_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueArray : public OptionValue
+{
+public:
+ OptionValueArray (uint32_t type_mask = UINT32_MAX, bool raw_value_dump = false) :
+ m_type_mask (type_mask),
+ m_values (),
+ m_raw_value_dump(raw_value_dump)
+ {
+ }
+
+ virtual
+ ~OptionValueArray()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeArray;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_values.clear();
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual bool
+ IsAggregateValue () const
+ {
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool will_modify,
+ Error &error) const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ size_t
+ GetSize () const
+ {
+ return m_values.size();
+ }
+
+ lldb::OptionValueSP
+ operator[](size_t idx) const
+ {
+ lldb::OptionValueSP value_sp;
+ if (idx < m_values.size())
+ value_sp = m_values[idx];
+ return value_sp;
+ }
+
+ lldb::OptionValueSP
+ GetValueAtIndex (size_t idx) const
+ {
+ lldb::OptionValueSP value_sp;
+ if (idx < m_values.size())
+ value_sp = m_values[idx];
+ return value_sp;
+ }
+
+ bool
+ AppendValue (const lldb::OptionValueSP &value_sp)
+ {
+ // Make sure the value_sp object is allowed to contain
+ // values of the type passed in...
+ if (value_sp && (m_type_mask & value_sp->GetTypeAsMask()))
+ {
+ m_values.push_back(value_sp);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ InsertValue (size_t idx, const lldb::OptionValueSP &value_sp)
+ {
+ // Make sure the value_sp object is allowed to contain
+ // values of the type passed in...
+ if (value_sp && (m_type_mask & value_sp->GetTypeAsMask()))
+ {
+ if (idx < m_values.size())
+ m_values.insert(m_values.begin() + idx, value_sp);
+ else
+ m_values.push_back(value_sp);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ ReplaceValue (size_t idx, const lldb::OptionValueSP &value_sp)
+ {
+ // Make sure the value_sp object is allowed to contain
+ // values of the type passed in...
+ if (value_sp && (m_type_mask & value_sp->GetTypeAsMask()))
+ {
+ if (idx < m_values.size())
+ {
+ m_values[idx] = value_sp;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ DeleteValue (size_t idx)
+ {
+ if (idx < m_values.size())
+ {
+ m_values.erase (m_values.begin() + idx);
+ return true;
+ }
+ return false;
+ }
+
+ size_t
+ GetArgs (Args &args) const;
+
+ Error
+ SetArgs (const Args &args, VarSetOperationType op);
+
+protected:
+ typedef std::vector<lldb::OptionValueSP> collection;
+
+ uint32_t m_type_mask;
+ collection m_values;
+ bool m_raw_value_dump;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueArray_h_
diff --git a/include/lldb/Interpreter/OptionValueBoolean.h b/include/lldb/Interpreter/OptionValueBoolean.h
new file mode 100644
index 000000000000..2b935e9e03e6
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueBoolean.h
@@ -0,0 +1,141 @@
+//===-- OptionValueBoolean.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_OptionValueBoolean_h_
+#define liblldb_OptionValueBoolean_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueBoolean : public OptionValue
+{
+public:
+ OptionValueBoolean (bool value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value)
+ {
+ }
+ OptionValueBoolean (bool current_value,
+ bool default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value)
+ {
+ }
+
+ virtual
+ ~OptionValueBoolean()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeBoolean;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Convert to bool operator.
+ ///
+ /// This allows code to check a OptionValueBoolean in conditions.
+ ///
+ /// @code
+ /// OptionValueBoolean bool_value(...);
+ /// if (bool_value)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// /b True this object contains a valid namespace decl, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ operator bool() const
+ {
+ return m_current_value;
+ }
+
+ const bool &
+ operator = (bool b)
+ {
+ m_current_value = b;
+ return m_current_value;
+ }
+
+ bool
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ bool
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (bool value)
+ {
+ m_current_value = value;
+ }
+
+ void
+ SetDefaultValue (bool value)
+ {
+ m_default_value = value;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+protected:
+ bool m_current_value;
+ bool m_default_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueBoolean_h_
diff --git a/include/lldb/Interpreter/OptionValueDictionary.h b/include/lldb/Interpreter/OptionValueDictionary.h
new file mode 100644
index 000000000000..5fb698b9f221
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueDictionary.h
@@ -0,0 +1,139 @@
+//===-- OptionValueDictionary.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_OptionValueDictionary_h_
+#define liblldb_OptionValueDictionary_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueDictionary : public OptionValue
+{
+public:
+ OptionValueDictionary (uint32_t type_mask = UINT32_MAX, bool raw_value_dump = true) :
+ OptionValue(),
+ m_type_mask (type_mask),
+ m_values (),
+ m_raw_value_dump (raw_value_dump)
+ {
+ }
+
+ virtual
+ ~OptionValueDictionary()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeDictionary;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_values.clear();
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual bool
+ IsAggregateValue () const
+ {
+ return true;
+ }
+
+ bool
+ IsHomogenous() const
+ {
+ return ConvertTypeMaskToType (m_type_mask) != eTypeInvalid;
+ }
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ size_t
+ GetNumValues() const
+ {
+ return m_values.size();
+ }
+
+ lldb::OptionValueSP
+ GetValueForKey (const ConstString &key) const;
+
+ virtual lldb::OptionValueSP
+ GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool will_modify,
+ Error &error) const;
+
+ virtual Error
+ SetSubValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *name,
+ const char *value);
+
+ //---------------------------------------------------------------------
+ // String value getters and setters
+ //---------------------------------------------------------------------
+ const char *
+ GetStringValueForKey (const ConstString &key);
+
+ bool
+ SetStringValueForKey (const ConstString &key,
+ const char *value,
+ bool can_replace = true);
+
+
+ bool
+ SetValueForKey (const ConstString &key,
+ const lldb::OptionValueSP &value_sp,
+ bool can_replace = true);
+
+ bool
+ DeleteValueForKey (const ConstString &key);
+
+ size_t
+ GetArgs (Args &args) const;
+
+ Error
+ SetArgs (const Args &args, VarSetOperationType op);
+
+protected:
+ typedef std::map<ConstString, lldb::OptionValueSP> collection;
+ uint32_t m_type_mask;
+ collection m_values;
+ bool m_raw_value_dump;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueDictionary_h_
diff --git a/include/lldb/Interpreter/OptionValueEnumeration.h b/include/lldb/Interpreter/OptionValueEnumeration.h
new file mode 100644
index 000000000000..012eeb68ac0e
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueEnumeration.h
@@ -0,0 +1,126 @@
+//===-- OptionValueEnumeration.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_OptionValueEnumeration_h_
+#define liblldb_OptionValueEnumeration_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+
+class OptionValueEnumeration : public OptionValue
+{
+public:
+ typedef int64_t enum_type;
+ struct EnumeratorInfo
+ {
+ enum_type value;
+ const char *description;
+ };
+ typedef UniqueCStringMap<EnumeratorInfo> EnumerationMap;
+ typedef typename EnumerationMap::Entry EnumerationMapEntry;
+
+ OptionValueEnumeration (const OptionEnumValueElement *enumerators, enum_type value);
+
+ virtual
+ ~OptionValueEnumeration();
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeEnum;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ enum_type
+ operator = (enum_type value)
+ {
+ m_current_value = value;
+ return m_current_value;
+ }
+
+ enum_type
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ enum_type
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (enum_type value)
+ {
+ m_current_value = value;
+ }
+
+ void
+ SetDefaultValue (enum_type value)
+ {
+ m_default_value = value;
+ }
+
+protected:
+ void
+ SetEnumerations (const OptionEnumValueElement *enumerators);
+
+ enum_type m_current_value;
+ enum_type m_default_value;
+ EnumerationMap m_enumerations;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueEnumeration_h_
diff --git a/include/lldb/Interpreter/OptionValueFileSpec.h b/include/lldb/Interpreter/OptionValueFileSpec.h
new file mode 100644
index 000000000000..7e74b605660c
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueFileSpec.h
@@ -0,0 +1,129 @@
+//===-- OptionValueFileSpec.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_OptionValueFileSpec_h_
+#define liblldb_OptionValueFileSpec_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueFileSpec : public OptionValue
+{
+public:
+ OptionValueFileSpec ();
+
+ OptionValueFileSpec (const FileSpec &value);
+
+ OptionValueFileSpec (const FileSpec &current_value,
+ const FileSpec &default_value);
+
+ virtual
+ ~OptionValueFileSpec()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeFileSpec;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ m_data_sp.reset();
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ FileSpec &
+ GetCurrentValue()
+ {
+ return m_current_value;
+ }
+
+ const FileSpec &
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ const FileSpec &
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (const FileSpec &value, bool set_value_was_set)
+ {
+ m_current_value = value;
+ if (set_value_was_set)
+ m_value_was_set = true;
+ m_data_sp.reset();
+ }
+
+ void
+ SetDefaultValue (const FileSpec &value)
+ {
+ m_default_value = value;
+ }
+
+ const lldb::DataBufferSP &
+ GetFileContents(bool null_terminate);
+
+ void
+ SetCompletionMask (uint32_t mask)
+ {
+ m_completion_mask = mask;
+ }
+
+protected:
+ FileSpec m_current_value;
+ FileSpec m_default_value;
+ lldb::DataBufferSP m_data_sp;
+ uint32_t m_completion_mask;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueFileSpec_h_
diff --git a/include/lldb/Interpreter/OptionValueFileSpecList.h b/include/lldb/Interpreter/OptionValueFileSpecList.h
new file mode 100644
index 000000000000..792de4e23af6
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueFileSpecList.h
@@ -0,0 +1,105 @@
+//===-- OptionValueFileSpecList.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_OptionValueFileSpecList_h_
+#define liblldb_OptionValueFileSpecList_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueFileSpecList : public OptionValue
+{
+public:
+ OptionValueFileSpecList () :
+ OptionValue(),
+ m_current_value ()
+ {
+ }
+
+ OptionValueFileSpecList (const FileSpecList &current_value) :
+ OptionValue(),
+ m_current_value (current_value)
+ {
+ }
+
+
+ virtual
+ ~OptionValueFileSpecList()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeFileSpecList;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value.Clear();
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual bool
+ IsAggregateValue () const
+ {
+ return true;
+ }
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ FileSpecList &
+ GetCurrentValue()
+ {
+ return m_current_value;
+ }
+
+ const FileSpecList &
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ void
+ SetCurrentValue (const FileSpecList &value)
+ {
+ m_current_value = value;
+ }
+
+protected:
+ FileSpecList m_current_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueFileSpecList_h_
diff --git a/include/lldb/Interpreter/OptionValueFormat.h b/include/lldb/Interpreter/OptionValueFormat.h
new file mode 100644
index 000000000000..245b2eeb5af1
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueFormat.h
@@ -0,0 +1,107 @@
+//===-- OptionValueFormat.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_OptionValueFormat_h_
+#define liblldb_OptionValueFormat_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueFormat : public OptionValue
+{
+public:
+ OptionValueFormat (lldb::Format value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value)
+ {
+ }
+
+ OptionValueFormat (lldb::Format current_value,
+ lldb::Format default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value)
+ {
+ }
+
+ virtual
+ ~OptionValueFormat()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeFormat;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ lldb::Format
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ lldb::Format
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (lldb::Format value)
+ {
+ m_current_value = value;
+ }
+
+ void
+ SetDefaultValue (lldb::Format value)
+ {
+ m_default_value = value;
+ }
+
+protected:
+ lldb::Format m_current_value;
+ lldb::Format m_default_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueFormat_h_
diff --git a/include/lldb/Interpreter/OptionValuePathMappings.h b/include/lldb/Interpreter/OptionValuePathMappings.h
new file mode 100644
index 000000000000..7ebf4947c6af
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValuePathMappings.h
@@ -0,0 +1,94 @@
+//===-- OptionValuePathMappings.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_OptionValuePathMappings_h_
+#define liblldb_OptionValuePathMappings_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/PathMappingList.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValuePathMappings : public OptionValue
+{
+public:
+ OptionValuePathMappings (bool notify_changes) :
+ OptionValue(),
+ m_path_mappings (),
+ m_notify_changes (notify_changes)
+ {
+ }
+
+ virtual
+ ~OptionValuePathMappings()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypePathMap;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_path_mappings.Clear(m_notify_changes);
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual bool
+ IsAggregateValue () const
+ {
+ return true;
+ }
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ PathMappingList &
+ GetCurrentValue()
+ {
+ return m_path_mappings;
+ }
+
+ const PathMappingList &
+ GetCurrentValue() const
+ {
+ return m_path_mappings;
+ }
+
+protected:
+ PathMappingList m_path_mappings;
+ bool m_notify_changes;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValuePathMappings_h_
diff --git a/include/lldb/Interpreter/OptionValueProperties.h b/include/lldb/Interpreter/OptionValueProperties.h
new file mode 100644
index 000000000000..0024f20e2ff6
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueProperties.h
@@ -0,0 +1,265 @@
+//===-- OptionValueProperties.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_OptionValueProperties_h_
+#define liblldb_OptionValueProperties_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Interpreter/Property.h"
+
+namespace lldb_private {
+
+class OptionValueProperties :
+ public OptionValue,
+ public std::enable_shared_from_this<OptionValueProperties>
+{
+public:
+
+ //---------------------------------------------------------------------
+ // OptionValueProperties
+ //---------------------------------------------------------------------
+ OptionValueProperties () :
+ OptionValue(),
+ m_name (),
+ m_properties (),
+ m_name_to_index ()
+ {
+ }
+
+ OptionValueProperties (const ConstString &name);
+
+ OptionValueProperties (const OptionValueProperties &global_properties);
+
+ virtual
+ ~OptionValueProperties()
+ {
+ }
+
+ virtual Type
+ GetType () const
+ {
+ return eTypeProperties;
+ }
+
+ virtual bool
+ Clear ();
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ virtual Error
+ SetValueFromCString (const char *value, VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ uint32_t dump_mask);
+
+ virtual ConstString
+ GetName () const
+ {
+ return m_name;
+ }
+
+ virtual Error
+ DumpPropertyValue (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ const char *property_path,
+ uint32_t dump_mask);
+
+ virtual void
+ DumpAllDescriptions (CommandInterpreter &interpreter,
+ Stream &strm) const;
+
+ void
+ Apropos (const char *keyword,
+ std::vector<const Property *> &matching_properties) const;
+
+ void
+ Initialize (const PropertyDefinition *setting_definitions);
+
+// bool
+// GetQualifiedName (Stream &strm);
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ virtual size_t
+ GetNumProperties() const;
+
+ virtual ConstString
+ GetPropertyNameAtIndex (uint32_t idx) const;
+
+ virtual const char *
+ GetPropertyDescriptionAtIndex (uint32_t idx) const;
+
+ //---------------------------------------------------------------------
+ // Get the index of a property given its exact name in this property
+ // collection, "name" can't be a path to a property path that refers
+ // to a property within a property
+ //---------------------------------------------------------------------
+ virtual uint32_t
+ GetPropertyIndex (const ConstString &name) const;
+
+ //---------------------------------------------------------------------
+ // Get a property by exact name exists in this property collection, name
+ // can not be a path to a property path that refers to a property within
+ // a property
+ //---------------------------------------------------------------------
+ virtual const Property *
+ GetProperty (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ const ConstString &name) const;
+
+ virtual const Property *
+ GetPropertyAtIndex (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ uint32_t idx) const;
+
+ //---------------------------------------------------------------------
+ // Property can be be a property path like "target.process.extra-startup-command"
+ //---------------------------------------------------------------------
+ virtual const Property *
+ GetPropertyAtPath (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ const char *property_path) const;
+
+ virtual lldb::OptionValueSP
+ GetPropertyValueAtIndex (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ uint32_t idx) const;
+
+ virtual lldb::OptionValueSP
+ GetValueForKey (const ExecutionContext *exe_ctx,
+ const ConstString &key,
+ bool value_will_be_modified) const;
+
+ lldb::OptionValueSP
+ GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool value_will_be_modified,
+ Error &error) const;
+
+ virtual Error
+ SetSubValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *path,
+ const char *value);
+
+ virtual bool
+ PredicateMatches (const ExecutionContext *exe_ctx,
+ const char *predicate) const
+ {
+ return false;
+ }
+
+
+ OptionValueArch *
+ GetPropertyAtIndexAsOptionValueArch (const ExecutionContext *exe_ctx, uint32_t idx) const;
+
+ bool
+ GetPropertyAtIndexAsArgs (const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const;
+
+ bool
+ SetPropertyAtIndexFromArgs (const ExecutionContext *exe_ctx, uint32_t idx, const Args &args);
+
+ bool
+ GetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const;
+
+ bool
+ SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value);
+
+ OptionValueDictionary *
+ GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const;
+
+ int64_t
+ GetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const;
+
+ bool
+ SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value);
+
+ const RegularExpression *
+ GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const;
+
+ OptionValueSInt64 *
+ GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionContext *exe_ctx, uint32_t idx) const;
+
+ int64_t
+ GetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const;
+
+ bool
+ SetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value);
+
+ uint64_t
+ GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const;
+
+ bool
+ SetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value);
+
+ const char *
+ GetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *fail_value) const;
+
+ bool
+ SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value);
+
+ OptionValueString *
+ GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;
+
+ OptionValueFileSpec *
+ GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;
+
+ FileSpec
+ GetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx) const;
+
+ bool
+ SetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx, const FileSpec &file_spec);
+
+ OptionValuePathMappings *
+ GetPropertyAtIndexAsOptionValuePathMappings (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;
+
+ OptionValueFileSpecList *
+ GetPropertyAtIndexAsOptionValueFileSpecList (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const;
+
+ void
+ AppendProperty(const ConstString &name,
+ const ConstString &desc,
+ bool is_global,
+ const lldb::OptionValueSP &value_sp);
+
+ lldb::OptionValuePropertiesSP
+ GetSubProperty (const ExecutionContext *exe_ctx,
+ const ConstString &name);
+
+protected:
+
+ const Property *
+ ProtectedGetPropertyAtIndex (uint32_t idx) const
+ {
+ if (idx < m_properties.size())
+ return &m_properties[idx];
+ return NULL;
+ }
+
+ typedef UniqueCStringMap<size_t> NameToIndex;
+
+ ConstString m_name;
+ std::vector<Property> m_properties;
+ NameToIndex m_name_to_index;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueProperties_h_
diff --git a/include/lldb/Interpreter/OptionValueRegex.h b/include/lldb/Interpreter/OptionValueRegex.h
new file mode 100644
index 000000000000..bb8c4588e22a
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueRegex.h
@@ -0,0 +1,98 @@
+//===-- OptionValueRegex.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_OptionValueRegex_h_
+#define liblldb_OptionValueRegex_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueRegex : public OptionValue
+{
+public:
+ OptionValueRegex (const char *value = NULL, uint32_t regex_flags = 0) :
+ OptionValue(),
+ m_regex (value, regex_flags)
+ {
+ }
+
+ virtual
+ ~OptionValueRegex()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeRegex;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_regex.Clear();
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+ const RegularExpression *
+ GetCurrentValue() const
+ {
+ if (m_regex.IsValid())
+ return &m_regex;
+ return NULL;
+ }
+
+ void
+ SetCurrentValue (const char *value, uint32_t regex_flags)
+ {
+ if (value && value[0])
+ m_regex.Compile (value, regex_flags);
+ else
+ m_regex.Clear();
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_regex.IsValid();
+ }
+
+protected:
+ RegularExpression m_regex;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueRegex_h_
diff --git a/include/lldb/Interpreter/OptionValueSInt64.h b/include/lldb/Interpreter/OptionValueSInt64.h
new file mode 100644
index 000000000000..8bc8fb2da2d5
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueSInt64.h
@@ -0,0 +1,172 @@
+//===-- OptionValueSInt64.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_OptionValueSInt64_h_
+#define liblldb_OptionValueSInt64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueSInt64 : public OptionValue
+{
+public:
+ OptionValueSInt64 () :
+ OptionValue(),
+ m_current_value (0),
+ m_default_value (0),
+ m_min_value (INT64_MIN),
+ m_max_value (INT64_MAX)
+ {
+ }
+
+ OptionValueSInt64 (int64_t value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value),
+ m_min_value (INT64_MIN),
+ m_max_value (INT64_MAX)
+ {
+ }
+
+ OptionValueSInt64 (int64_t current_value,
+ int64_t default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value),
+ m_min_value (INT64_MIN),
+ m_max_value (INT64_MAX)
+ {
+ }
+
+ OptionValueSInt64 (const OptionValueSInt64 &rhs) :
+ OptionValue(rhs),
+ m_current_value (rhs.m_current_value),
+ m_default_value (rhs.m_default_value),
+ m_min_value (rhs.m_min_value),
+ m_max_value (rhs.m_max_value)
+ {
+ }
+
+ virtual
+ ~OptionValueSInt64()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeSInt64;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ const int64_t &
+ operator = (int64_t value)
+ {
+ m_current_value = value;
+ return m_current_value;
+ }
+
+ int64_t
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ int64_t
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ bool
+ SetCurrentValue (int64_t value)
+ {
+ if (value >= m_min_value && value <= m_max_value)
+ {
+ m_current_value = value;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ SetDefaultValue (int64_t value)
+ {
+ if (value >= m_min_value && value <= m_max_value)
+ {
+ m_default_value = value;
+ return true;
+ }
+ return false;
+ }
+
+ void
+ SetMinimumValue (int64_t v)
+ {
+ m_min_value = v;
+ }
+
+ int64_t
+ GetMinimumValue () const
+ {
+ return m_min_value;
+ }
+
+ void
+ SetMaximumValue (int64_t v)
+ {
+ m_max_value = v;
+ }
+
+ int64_t
+ GetMaximumValue () const
+ {
+ return m_max_value;
+ }
+
+protected:
+ int64_t m_current_value;
+ int64_t m_default_value;
+ int64_t m_min_value;
+ int64_t m_max_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueSInt64_h_
diff --git a/include/lldb/Interpreter/OptionValueString.h b/include/lldb/Interpreter/OptionValueString.h
new file mode 100644
index 000000000000..a82e1403b74b
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueString.h
@@ -0,0 +1,227 @@
+//===-- OptionValueString.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_OptionValueString_h_
+#define liblldb_OptionValueString_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Flags.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueString : public OptionValue
+{
+public:
+
+ typedef Error (*ValidatorCallback) (const char* string,
+ void* baton);
+
+ enum Options
+ {
+ eOptionEncodeCharacterEscapeSequences = (1u << 0)
+ };
+
+ OptionValueString () :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(),
+ m_validator_baton()
+ {
+ }
+
+ OptionValueString (ValidatorCallback validator,
+ void* baton = NULL) :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(validator),
+ m_validator_baton(baton)
+ {
+ }
+
+ OptionValueString (const char *value) :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(),
+ m_validator_baton()
+ {
+ if (value && value[0])
+ {
+ m_current_value.assign (value);
+ m_default_value.assign (value);
+ }
+ }
+
+ OptionValueString (const char *current_value,
+ const char *default_value) :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(),
+ m_validator_baton()
+ {
+ if (current_value && current_value[0])
+ m_current_value.assign (current_value);
+ if (default_value && default_value[0])
+ m_default_value.assign (default_value);
+ }
+
+ OptionValueString (const char *value,
+ ValidatorCallback validator,
+ void* baton = NULL) :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(validator),
+ m_validator_baton(baton)
+ {
+ if (value && value[0])
+ {
+ m_current_value.assign (value);
+ m_default_value.assign (value);
+ }
+ }
+
+ OptionValueString (const char *current_value,
+ const char *default_value,
+ ValidatorCallback validator,
+ void* baton = NULL) :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_options(),
+ m_validator(validator),
+ m_validator_baton(baton)
+ {
+ if (current_value && current_value[0])
+ m_current_value.assign (current_value);
+ if (default_value && default_value[0])
+ m_default_value.assign (default_value);
+ }
+
+ virtual
+ ~OptionValueString()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeString;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ Flags &
+ GetOptions ()
+ {
+ return m_options;
+ }
+
+ const Flags &
+ GetOptions () const
+ {
+ return m_options;
+ }
+
+ const char *
+ operator = (const char *value)
+ {
+ SetCurrentValue(value);
+ return m_current_value.c_str();
+ }
+
+ const char *
+ GetCurrentValue() const
+ {
+ return m_current_value.c_str();
+ }
+
+ const char *
+ GetDefaultValue() const
+ {
+ return m_default_value.c_str();
+ }
+
+ Error
+ SetCurrentValue (const char *value);
+
+ Error
+ AppendToCurrentValue (const char *value);
+
+ void
+ SetDefaultValue (const char *value)
+ {
+ if (value && value[0])
+ m_default_value.assign (value);
+ else
+ m_default_value.clear();
+ }
+
+ bool
+ IsCurrentValueEmpty () const
+ {
+ return m_current_value.empty();
+ }
+
+ bool
+ IsDefaultValueEmpty () const
+ {
+ return m_default_value.empty();
+ }
+
+
+protected:
+ std::string m_current_value;
+ std::string m_default_value;
+ Flags m_options;
+ ValidatorCallback m_validator;
+ void* m_validator_baton;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueString_h_
diff --git a/include/lldb/Interpreter/OptionValueUInt64.h b/include/lldb/Interpreter/OptionValueUInt64.h
new file mode 100644
index 000000000000..9b5496f9835c
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueUInt64.h
@@ -0,0 +1,134 @@
+//===-- OptionValueUInt64.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_OptionValueUInt64_h_
+#define liblldb_OptionValueUInt64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueUInt64 : public OptionValue
+{
+public:
+ OptionValueUInt64 () :
+ OptionValue(),
+ m_current_value (0),
+ m_default_value (0)
+ {
+ }
+
+ OptionValueUInt64 (uint64_t value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value)
+ {
+ }
+
+ OptionValueUInt64 (uint64_t current_value,
+ uint64_t default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value)
+ {
+ }
+
+ virtual
+ ~OptionValueUInt64()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Decode a uint64_t from "value_cstr" return a OptionValueUInt64 object
+ // inside of a lldb::OptionValueSP object if all goes well. If the
+ // string isn't a uint64_t value or any other error occurs, return an
+ // empty lldb::OptionValueSP and fill error in with the correct stuff.
+ //---------------------------------------------------------------------
+ static lldb::OptionValueSP
+ Create (const char *value_cstr, Error &error);
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeUInt64;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_current_value = m_default_value;
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ const uint64_t &
+ operator = (uint64_t value)
+ {
+ m_current_value = value;
+ return m_current_value;
+ }
+
+ operator uint64_t () const
+ {
+ return m_current_value;
+ }
+
+ uint64_t
+ GetCurrentValue() const
+ {
+ return m_current_value;
+ }
+
+ uint64_t
+ GetDefaultValue() const
+ {
+ return m_default_value;
+ }
+
+ void
+ SetCurrentValue (uint64_t value)
+ {
+ m_current_value = value;
+ }
+
+ void
+ SetDefaultValue (uint64_t value)
+ {
+ m_default_value = value;
+ }
+
+protected:
+ uint64_t m_current_value;
+ uint64_t m_default_value;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueUInt64_h_
diff --git a/include/lldb/Interpreter/OptionValueUUID.h b/include/lldb/Interpreter/OptionValueUUID.h
new file mode 100644
index 000000000000..caf436e576f5
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValueUUID.h
@@ -0,0 +1,106 @@
+//===-- OptionValueUUID.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_OptionValueUUID_h_
+#define liblldb_OptionValueUUID_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/UUID.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+class OptionValueUUID : public OptionValue
+{
+public:
+ OptionValueUUID () :
+ OptionValue(),
+ m_uuid ()
+ {
+ }
+
+ OptionValueUUID (const UUID &uuid) :
+ OptionValue(),
+ m_uuid (uuid)
+ {
+ }
+
+ virtual
+ ~OptionValueUUID()
+ {
+ }
+
+ //---------------------------------------------------------------------
+ // Virtual subclass pure virtual overrides
+ //---------------------------------------------------------------------
+
+ virtual OptionValue::Type
+ GetType () const
+ {
+ return eTypeUUID;
+ }
+
+ virtual void
+ DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask);
+
+ virtual Error
+ SetValueFromCString (const char *value,
+ VarSetOperationType op = eVarSetOperationAssign);
+
+ virtual bool
+ Clear ()
+ {
+ m_uuid.Clear();
+ m_value_was_set = false;
+ return true;
+ }
+
+ virtual lldb::OptionValueSP
+ DeepCopy () const;
+
+ //---------------------------------------------------------------------
+ // Subclass specific functions
+ //---------------------------------------------------------------------
+
+ UUID &
+ GetCurrentValue()
+ {
+ return m_uuid;
+ }
+
+ const UUID &
+ GetCurrentValue() const
+ {
+ return m_uuid;
+ }
+
+ void
+ SetCurrentValue (const UUID &value)
+ {
+ m_uuid = value;
+ }
+
+ virtual size_t
+ AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+protected:
+ UUID m_uuid;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_OptionValueUUID_h_
diff --git a/include/lldb/Interpreter/OptionValues.h b/include/lldb/Interpreter/OptionValues.h
new file mode 100644
index 000000000000..41b9d2e351f4
--- /dev/null
+++ b/include/lldb/Interpreter/OptionValues.h
@@ -0,0 +1,31 @@
+//===-- OptionValues.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_OptionValues_h_
+#define liblldb_OptionValues_h_
+
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Interpreter/OptionValueArch.h"
+#include "lldb/Interpreter/OptionValueArgs.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Interpreter/OptionValueEnumeration.h"
+#include "lldb/Interpreter/OptionValueFileSpec.h"
+#include "lldb/Interpreter/OptionValueFileSpecList.h"
+#include "lldb/Interpreter/OptionValueFormat.h"
+#include "lldb/Interpreter/OptionValuePathMappings.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Interpreter/OptionValueRegex.h"
+#include "lldb/Interpreter/OptionValueSInt64.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Interpreter/OptionValueUUID.h"
+
+#endif // liblldb_OptionValues_h_
diff --git a/include/lldb/Interpreter/Options.h b/include/lldb/Interpreter/Options.h
new file mode 100644
index 000000000000..ac4daa8f579a
--- /dev/null
+++ b/include/lldb/Interpreter/Options.h
@@ -0,0 +1,487 @@
+//===-- Options.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_Options_h_
+#define liblldb_Options_h_
+
+// C Includes
+#include <getopt.h>
+
+// C++ Includes
+#include <set>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/Interpreter/Args.h"
+
+namespace lldb_private {
+
+ static inline bool
+ isprint8 (int ch)
+ {
+ if (ch & 0xffffff00u)
+ return false;
+ return isprint(ch);
+ }
+
+
+//----------------------------------------------------------------------
+/// @class Options Options.h "lldb/Interpreter/Options.h"
+/// @brief A command line option parsing protocol class.
+///
+/// Options is designed to be subclassed to contain all needed
+/// options for a given command. The options can be parsed by calling:
+/// \code
+/// Error Args::ParseOptions (Options &);
+/// \endcode
+///
+/// The options are specified using the format defined for the libc
+/// options parsing function getopt_long_only:
+/// \code
+/// #include <getopt.h>
+/// int getopt_long_only(int argc, char * const *argv, const char *optstring, const struct option *longopts, int *longindex);
+/// \endcode
+///
+/// Example code:
+/// \code
+/// #include <getopt.h>
+/// #include <string>
+///
+/// class CommandOptions : public Options
+/// {
+/// public:
+/// virtual struct option *
+/// GetLongOptions() {
+/// return g_options;
+/// }
+///
+/// virtual Error
+/// SetOptionValue (uint32_t option_idx, int option_val, const char *option_arg)
+/// {
+/// Error error;
+/// switch (option_val)
+/// {
+/// case 'g': debug = true; break;
+/// case 'v': verbose = true; break;
+/// case 'l': log_file = option_arg; break;
+/// case 'f': log_flags = strtoull(option_arg, NULL, 0); break;
+/// default:
+/// error.SetErrorStringWithFormat("unrecognized short option %c", option_val);
+/// break;
+/// }
+///
+/// return error;
+/// }
+///
+/// CommandOptions (CommandInterpreter &interpreter) : debug (true), verbose (false), log_file (), log_flags (0)
+/// {}
+///
+/// bool debug;
+/// bool verbose;
+/// std::string log_file;
+/// uint32_t log_flags;
+///
+/// static struct option g_options[];
+///
+/// };
+///
+/// struct option CommandOptions::g_options[] =
+/// {
+/// { "debug", no_argument, NULL, 'g' },
+/// { "log-file", required_argument, NULL, 'l' },
+/// { "log-flags", required_argument, NULL, 'f' },
+/// { "verbose", no_argument, NULL, 'v' },
+/// { NULL, 0, NULL, 0 }
+/// };
+///
+/// int main (int argc, const char **argv, const char **envp)
+/// {
+/// CommandOptions options;
+/// Args main_command;
+/// main_command.SetArguments(argc, argv, false);
+/// main_command.ParseOptions(options);
+///
+/// if (options.verbose)
+/// {
+/// std::cout << "verbose is on" << std::endl;
+/// }
+/// }
+/// \endcode
+//----------------------------------------------------------------------
+class Options
+{
+public:
+
+ Options (CommandInterpreter &interpreter);
+
+ virtual
+ ~Options ();
+
+ void
+ BuildGetoptTable ();
+
+ void
+ BuildValidOptionSets ();
+
+ uint32_t
+ NumCommandOptions ();
+
+ //------------------------------------------------------------------
+ /// Get the option definitions to use when parsing Args options.
+ ///
+ /// @see Args::ParseOptions (Options&)
+ /// @see man getopt_long_only
+ //------------------------------------------------------------------
+ struct option *
+ GetLongOptions ();
+
+ // This gets passed the short option as an integer...
+ void
+ OptionSeen (int short_option);
+
+ bool
+ VerifyOptions (CommandReturnObject &result);
+
+ // Verify that the options given are in the options table and can
+ // be used together, but there may be some required options that are
+ // missing (used to verify options that get folded into command aliases).
+
+ bool
+ VerifyPartialOptions (CommandReturnObject &result);
+
+ void
+ OutputFormattedUsageText (Stream &strm,
+ const char *text,
+ uint32_t output_max_columns);
+
+ void
+ GenerateOptionUsage (Stream &strm,
+ CommandObject *cmd);
+
+ bool
+ SupportsLongOption (const char *long_option);
+
+ // The following two pure virtual functions must be defined by every
+ // class that inherits from this class.
+
+ virtual const OptionDefinition*
+ GetDefinitions () { return NULL; }
+
+ // Call this prior to parsing any options. This call will call the
+ // subclass OptionParsingStarting() and will avoid the need for all
+ // OptionParsingStarting() function instances from having to call the
+ // Option::OptionParsingStarting() like they did before. This was error
+ // prone and subclasses shouldn't have to do it.
+ void
+ NotifyOptionParsingStarting ();
+
+ Error
+ NotifyOptionParsingFinished ();
+
+ //------------------------------------------------------------------
+ /// Set the value of an option.
+ ///
+ /// @param[in] option_idx
+ /// The index into the "struct option" array that was returned
+ /// by Options::GetLongOptions().
+ ///
+ /// @param[in] option_arg
+ /// The argument value for the option that the user entered, or
+ /// NULL if there is no argument for the current option.
+ ///
+ ///
+ /// @see Args::ParseOptions (Options&)
+ /// @see man getopt_long_only
+ //------------------------------------------------------------------
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg) = 0;
+
+ //------------------------------------------------------------------
+ /// Handles the generic bits of figuring out whether we are in an
+ /// option, and if so completing it.
+ ///
+ /// @param[in] input
+ /// The command line parsed into words
+ ///
+ /// @param[in] cursor_index
+ /// The index in \ainput of the word in which the cursor lies.
+ ///
+ /// @param[in] char_pos
+ /// The character position of the cursor in its argument word.
+ ///
+ /// @param[in] match_start_point
+ /// @param[in] match_return_elements
+ /// See CommandObject::HandleCompletions for a description of
+ /// how these work.
+ ///
+ /// @param[in] interpreter
+ /// The interpreter that's doing the completing.
+ ///
+ /// @param[out] word_complete
+ /// \btrue if this is a complete option value (a space will be
+ /// inserted after the completion.) \b false otherwise.
+ ///
+ /// @param[out] matches
+ /// The array of matches returned.
+ ///
+ /// FIXME: This is the wrong return value, since we also need to
+ /// make a distinction between total number of matches, and the
+ /// window the user wants returned.
+ ///
+ /// @return
+ /// \btrue if we were in an option, \bfalse otherwise.
+ //------------------------------------------------------------------
+ bool
+ HandleOptionCompletion (Args &input,
+ OptionElementVector &option_map,
+ int cursor_index,
+ int char_pos,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ lldb_private::StringList &matches);
+
+ //------------------------------------------------------------------
+ /// Handles the generic bits of figuring out whether we are in an
+ /// option, and if so completing it.
+ ///
+ /// @param[in] interpreter
+ /// The command interpreter doing the completion.
+ ///
+ /// @param[in] input
+ /// The command line parsed into words
+ ///
+ /// @param[in] cursor_index
+ /// The index in \ainput of the word in which the cursor lies.
+ ///
+ /// @param[in] char_pos
+ /// The character position of the cursor in its argument word.
+ ///
+ /// @param[in] opt_element_vector
+ /// The results of the options parse of \a input.
+ ///
+ /// @param[in] opt_element_index
+ /// The position in \a opt_element_vector of the word in \a
+ /// input containing the cursor.
+ ///
+ /// @param[in] match_start_point
+ /// @param[in] match_return_elements
+ /// See CommandObject::HandleCompletions for a description of
+ /// how these work.
+ ///
+ /// @param[out] word_complete
+ /// \btrue if this is a complete option value (a space will
+ /// be inserted after the completion.) \bfalse otherwise.
+ ///
+ /// @param[out] matches
+ /// The array of matches returned.
+ ///
+ /// FIXME: This is the wrong return value, since we also need to
+ /// make a distinction between total number of matches, and the
+ /// window the user wants returned.
+ ///
+ /// @return
+ /// \btrue if we were in an option, \bfalse otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ HandleOptionArgumentCompletion (Args &input,
+ int cursor_index,
+ int char_pos,
+ OptionElementVector &opt_element_vector,
+ int opt_element_index,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+protected:
+ // This is a set of options expressed as indexes into the options table for this Option.
+ typedef std::set<int> OptionSet;
+ typedef std::vector<OptionSet> OptionSetVector;
+
+ CommandInterpreter &m_interpreter;
+ std::vector<struct option> m_getopt_table;
+ OptionSet m_seen_options;
+ OptionSetVector m_required_options;
+ OptionSetVector m_optional_options;
+
+ OptionSetVector &GetRequiredOptions ()
+ {
+ BuildValidOptionSets();
+ return m_required_options;
+ }
+
+ OptionSetVector &GetOptionalOptions ()
+ {
+ BuildValidOptionSets();
+ return m_optional_options;
+ }
+
+ bool
+ IsASubset (const OptionSet& set_a, const OptionSet& set_b);
+
+ size_t
+ OptionsSetDiff (const OptionSet &set_a, const OptionSet &set_b, OptionSet &diffs);
+
+ void
+ OptionsSetUnion (const OptionSet &set_a, const OptionSet &set_b, OptionSet &union_set);
+
+ // Subclasses must reset their option values prior to starting a new
+ // option parse. Each subclass must override this function and revert
+ // all option settings to default values.
+ virtual void
+ OptionParsingStarting () = 0;
+
+ virtual Error
+ OptionParsingFinished ()
+ {
+ // If subclasses need to know when the options are done being parsed
+ // they can implement this function to do extra checking
+ Error error;
+ return error;
+ }
+};
+
+ class OptionGroup
+ {
+ public:
+ OptionGroup ()
+ {
+ }
+
+ virtual
+ ~OptionGroup ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions () = 0;
+
+ virtual const OptionDefinition*
+ GetDefinitions () = 0;
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value) = 0;
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter) = 0;
+
+ virtual Error
+ OptionParsingFinished (CommandInterpreter &interpreter)
+ {
+ // If subclasses need to know when the options are done being parsed
+ // they can implement this function to do extra checking
+ Error error;
+ return error;
+ }
+ };
+
+ class OptionGroupOptions : public Options
+ {
+ public:
+
+ OptionGroupOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_option_defs (),
+ m_option_infos (),
+ m_did_finalize (false)
+ {
+ }
+
+ virtual
+ ~OptionGroupOptions ()
+ {
+ }
+
+
+ //----------------------------------------------------------------------
+ /// Append options from a OptionGroup class.
+ ///
+ /// Append all options from \a group using the exact same option groups
+ /// that each option is defined with.
+ ///
+ /// @param[in] group
+ /// A group of options to take option values from and copy their
+ /// definitions into this class.
+ //----------------------------------------------------------------------
+ void
+ Append (OptionGroup* group);
+
+ //----------------------------------------------------------------------
+ /// Append options from a OptionGroup class.
+ ///
+ /// Append options from \a group that have a usage mask that has any bits
+ /// in "src_mask" set. After the option definition is copied into the
+ /// options definitions in this class, set the usage_mask to "dst_mask".
+ ///
+ /// @param[in] group
+ /// A group of options to take option values from and copy their
+ /// definitions into this class.
+ ///
+ /// @param[in] src_mask
+ /// When copying options from \a group, you might only want some of
+ /// the options to be appended to this group. This mask allows you
+ /// to control which options from \a group get added. It also allows
+ /// you to specify the same options from \a group multiple times
+ /// for different option sets.
+ ///
+ /// @param[in] dst_mask
+ /// Set the usage mask for any copied options to \a dst_mask after
+ /// copying the option definition.
+ //----------------------------------------------------------------------
+ void
+ Append (OptionGroup* group,
+ uint32_t src_mask,
+ uint32_t dst_mask);
+
+ void
+ Finalize ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx,
+ const char *option_arg);
+
+ virtual void
+ OptionParsingStarting ();
+
+ virtual Error
+ OptionParsingFinished ();
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ assert (m_did_finalize);
+ return &m_option_defs[0];
+ }
+ struct OptionInfo
+ {
+ OptionInfo (OptionGroup* g, uint32_t i) :
+ option_group (g),
+ option_index (i)
+ {
+ }
+ OptionGroup* option_group; // The group that this option came from
+ uint32_t option_index; // The original option index from the OptionGroup
+ };
+ typedef std::vector<OptionInfo> OptionInfos;
+
+ std::vector<OptionDefinition> m_option_defs;
+ OptionInfos m_option_infos;
+ bool m_did_finalize;
+ };
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Options_h_
diff --git a/include/lldb/Interpreter/Property.h b/include/lldb/Interpreter/Property.h
new file mode 100644
index 000000000000..b192758cbc41
--- /dev/null
+++ b/include/lldb/Interpreter/Property.h
@@ -0,0 +1,109 @@
+//===-- Property.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_Property_h_
+#define liblldb_Property_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Interpreter/OptionValue.h"
+
+namespace lldb_private {
+
+ // A structure that can be used to create a global table for all properties.
+ // Property class instances can be constructed using one of these.
+ struct PropertyDefinition
+ {
+ const char *name;
+ OptionValue::Type type;
+ bool global;
+ uintptr_t default_uint_value;
+ const char *default_cstr_value;
+ OptionEnumValueElement *enum_values;
+ const char *description;
+ };
+
+ class Property
+ {
+ public:
+ Property (const PropertyDefinition &definition);
+
+ Property (const ConstString &name,
+ const ConstString &desc,
+ bool is_global,
+ const lldb::OptionValueSP &value_sp);
+
+ const ConstString &
+ GetName() const
+ {
+ return m_name;
+ }
+
+ const char *
+ GetDescription () const
+ {
+ return m_description.GetCString();
+ }
+
+ const lldb::OptionValueSP &
+ GetValue() const
+ {
+ return m_value_sp;
+ }
+
+ void
+ SetOptionValue (const lldb::OptionValueSP &value_sp)
+ {
+ m_value_sp = value_sp;
+ }
+
+
+ bool
+ IsValid() const
+ {
+ return (bool)m_value_sp;
+ }
+
+ bool
+ IsGlobal () const
+ {
+ return m_is_global;
+ }
+
+ void
+ Dump (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ uint32_t dump_mask) const;
+
+ bool
+ DumpQualifiedName(Stream &strm) const;
+
+ void
+ DumpDescription (CommandInterpreter &interpreter,
+ Stream &strm,
+ uint32_t output_width,
+ bool display_qualified_name) const;
+
+ protected:
+ ConstString m_name;
+ ConstString m_description;
+ lldb::OptionValueSP m_value_sp;
+ bool m_is_global;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_Property_h_
diff --git a/include/lldb/Interpreter/PythonDataObjects.h b/include/lldb/Interpreter/PythonDataObjects.h
new file mode 100644
index 000000000000..b2c9240db09f
--- /dev/null
+++ b/include/lldb/Interpreter/PythonDataObjects.h
@@ -0,0 +1,233 @@
+//===-- PythonDataObjects.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_PythonDataObjects_h_
+#define liblldb_PythonDataObjects_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Interpreter/OptionValue.h"
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+namespace lldb_private {
+
+ class PythonObject
+ {
+ public:
+ PythonObject () :
+ m_py_obj(NULL)
+ {
+ }
+
+ PythonObject (PyObject* py_obj) :
+ m_py_obj(NULL)
+ {
+ Reset (py_obj);
+ }
+
+ PythonObject (const PythonObject &rhs) :
+ m_py_obj(NULL)
+ {
+ Reset (rhs.m_py_obj);
+ }
+
+ PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp);
+
+ virtual
+ ~PythonObject ()
+ {
+ Reset (NULL);
+ }
+
+ const PythonObject &
+ operator = (const PythonObject &rhs)
+ {
+ if (this != &rhs)
+ Reset (rhs.m_py_obj);
+ return *this;
+ }
+
+ bool
+ Reset (const PythonObject &object)
+ {
+ return Reset(object.GetPythonObject());
+ }
+
+ virtual bool
+ Reset (PyObject* py_obj = NULL)
+ {
+ if (py_obj != m_py_obj)
+ {
+ Py_XDECREF(m_py_obj);
+ m_py_obj = py_obj;
+ Py_XINCREF(m_py_obj);
+ }
+ return true;
+ }
+
+ void
+ Dump () const
+ {
+ if (m_py_obj)
+ _PyObject_Dump (m_py_obj);
+ else
+ puts ("NULL");
+ }
+
+ void
+ Dump (Stream &strm) const;
+
+ PyObject*
+ GetPythonObject () const
+ {
+ return m_py_obj;
+ }
+
+ PythonString
+ Repr ();
+
+ PythonString
+ Str ();
+
+ operator bool () const
+ {
+ return m_py_obj != NULL;
+ }
+
+ protected:
+ PyObject* m_py_obj;
+ };
+
+ class PythonString: public PythonObject
+ {
+ public:
+
+ PythonString ();
+ PythonString (PyObject *o);
+ PythonString (const PythonObject &object);
+ PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp);
+ PythonString (const char* string);
+ virtual ~PythonString ();
+
+ virtual bool
+ Reset (PyObject* py_obj = NULL);
+
+ const char*
+ GetString() const;
+
+ size_t
+ GetSize() const;
+
+ void
+ SetString (const char* string);
+ };
+
+ class PythonInteger: public PythonObject
+ {
+ public:
+
+ PythonInteger ();
+ PythonInteger (PyObject* py_obj);
+ PythonInteger (const PythonObject &object);
+ PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp);
+ PythonInteger (int64_t value);
+ virtual ~PythonInteger ();
+
+ virtual bool
+ Reset (PyObject* py_obj = NULL);
+
+ int64_t
+ GetInteger();
+
+ void
+ SetInteger (int64_t value);
+ };
+
+ class PythonList: public PythonObject
+ {
+ public:
+
+ PythonList ();
+ PythonList (PyObject* py_obj);
+ PythonList (const PythonObject &object);
+ PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp);
+ PythonList (uint32_t count);
+ virtual ~PythonList ();
+
+ virtual bool
+ Reset (PyObject* py_obj = NULL);
+
+ uint32_t
+ GetSize();
+
+ PythonObject
+ GetItemAtIndex (uint32_t index);
+
+ void
+ SetItemAtIndex (uint32_t index, const PythonObject &object);
+
+ void
+ AppendItem (const PythonObject &object);
+ };
+
+ class PythonDictionary: public PythonObject
+ {
+ public:
+
+ PythonDictionary ();
+ PythonDictionary (PyObject* object);
+ PythonDictionary (const PythonObject &object);
+ PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp);
+ virtual ~PythonDictionary ();
+
+ virtual bool
+ Reset (PyObject* object = NULL);
+
+ uint32_t GetSize();
+
+ PythonObject
+ GetItemForKey (const PythonString &key) const;
+
+ const char *
+ GetItemForKeyAsString (const PythonString &key, const char *fail_value = NULL) const;
+
+ int64_t
+ GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value = 0) const;
+
+ PythonObject
+ GetItemForKey (const char *key) const;
+
+ typedef bool (*DictionaryIteratorCallback)(PythonString* key, PythonDictionary* dict);
+
+ PythonList
+ GetKeys () const;
+
+ PythonString
+ GetKeyAtPosition (uint32_t pos) const;
+
+ PythonObject
+ GetValueAtPosition (uint32_t pos) const;
+
+ void
+ SetItemForKey (const PythonString &key, const PythonObject& value);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_PythonDataObjects_h_
diff --git a/include/lldb/Interpreter/ScriptInterpreter.h b/include/lldb/Interpreter/ScriptInterpreter.h
new file mode 100644
index 000000000000..9a66c775d47a
--- /dev/null
+++ b/include/lldb/Interpreter/ScriptInterpreter.h
@@ -0,0 +1,519 @@
+//===-- ScriptInterpreter.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_ScriptInterpreter_h_
+#define liblldb_ScriptInterpreter_h_
+
+#include "lldb/lldb-private.h"
+
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Error.h"
+
+#include "lldb/Utility/PseudoTerminal.h"
+
+
+namespace lldb_private {
+
+class ScriptInterpreterObject
+{
+public:
+ ScriptInterpreterObject() :
+ m_object(NULL)
+ {}
+
+ ScriptInterpreterObject(void* obj) :
+ m_object(obj)
+ {}
+
+ ScriptInterpreterObject(const ScriptInterpreterObject& rhs)
+ : m_object(rhs.m_object)
+ {}
+
+ virtual void*
+ GetObject()
+ {
+ return m_object;
+ }
+
+ operator bool ()
+ {
+ return m_object != NULL;
+ }
+
+ ScriptInterpreterObject&
+ operator = (const ScriptInterpreterObject& rhs)
+ {
+ if (this != &rhs)
+ m_object = rhs.m_object;
+ return *this;
+ }
+
+ virtual
+ ~ScriptInterpreterObject()
+ {}
+
+protected:
+ void* m_object;
+};
+
+class ScriptInterpreterLocker
+{
+public:
+
+ ScriptInterpreterLocker ()
+ {
+ }
+
+ virtual ~ScriptInterpreterLocker ()
+ {
+ }
+private:
+ DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterLocker);
+};
+
+
+class ScriptInterpreter
+{
+public:
+
+ typedef void (*SWIGInitCallback) (void);
+
+ typedef bool (*SWIGBreakpointCallbackFunction) (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& frame_sp,
+ const lldb::BreakpointLocationSP &bp_loc_sp);
+
+ typedef bool (*SWIGWatchpointCallbackFunction) (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& frame_sp,
+ const lldb::WatchpointSP &wp_sp);
+
+ typedef bool (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
+ void *session_dictionary,
+ const lldb::ValueObjectSP& valobj_sp,
+ void** pyfunct_wrapper,
+ std::string& retval);
+
+ typedef void* (*SWIGPythonCreateSyntheticProvider) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
+ typedef void* (*SWIGPythonCreateOSPlugin) (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ProcessSP& process_sp);
+
+ typedef uint32_t (*SWIGPythonCalculateNumChildren) (void *implementor);
+ typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx);
+ typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
+ typedef void* (*SWIGPythonCastPyObjectToSBValue) (void* data);
+ typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data);
+ typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data);
+
+
+ typedef bool (*SWIGPythonCallCommand) (const char *python_function_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger,
+ const char* args,
+ lldb_private::CommandReturnObject& cmd_retobj);
+
+ typedef bool (*SWIGPythonCallModuleInit) (const char *python_module_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger);
+
+ typedef bool (*SWIGPythonScriptKeyword_Process) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ProcessSP& process,
+ std::string& output);
+ typedef bool (*SWIGPythonScriptKeyword_Thread) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ThreadSP& thread,
+ std::string& output);
+
+ typedef bool (*SWIGPythonScriptKeyword_Target) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::TargetSP& target,
+ std::string& output);
+
+ typedef bool (*SWIGPythonScriptKeyword_Frame) (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::StackFrameSP& frame,
+ std::string& output);
+
+
+
+ typedef enum
+ {
+ eScriptReturnTypeCharPtr,
+ eScriptReturnTypeBool,
+ eScriptReturnTypeShortInt,
+ eScriptReturnTypeShortIntUnsigned,
+ eScriptReturnTypeInt,
+ eScriptReturnTypeIntUnsigned,
+ eScriptReturnTypeLongInt,
+ eScriptReturnTypeLongIntUnsigned,
+ eScriptReturnTypeLongLong,
+ eScriptReturnTypeLongLongUnsigned,
+ eScriptReturnTypeFloat,
+ eScriptReturnTypeDouble,
+ eScriptReturnTypeChar,
+ eScriptReturnTypeCharStrOrNone
+ } ScriptReturnType;
+
+ ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang);
+
+ virtual ~ScriptInterpreter ();
+
+ struct ExecuteScriptOptions
+ {
+ public:
+ ExecuteScriptOptions () :
+ m_enable_io(true),
+ m_set_lldb_globals(true),
+ m_maskout_errors(true)
+ {
+ }
+
+ bool
+ GetEnableIO () const
+ {
+ return m_enable_io;
+ }
+
+ bool
+ GetSetLLDBGlobals () const
+ {
+ return m_set_lldb_globals;
+ }
+
+ bool
+ GetMaskoutErrors () const
+ {
+ return m_maskout_errors;
+ }
+
+ ExecuteScriptOptions&
+ SetEnableIO (bool enable)
+ {
+ m_enable_io = enable;
+ return *this;
+ }
+
+ ExecuteScriptOptions&
+ SetSetLLDBGlobals (bool set)
+ {
+ m_set_lldb_globals = set;
+ return *this;
+ }
+
+ ExecuteScriptOptions&
+ SetMaskoutErrors (bool maskout)
+ {
+ m_maskout_errors = maskout;
+ return *this;
+ }
+
+ private:
+ bool m_enable_io;
+ bool m_set_lldb_globals;
+ bool m_maskout_errors;
+ };
+
+ virtual bool
+ ExecuteOneLine (const char *command,
+ CommandReturnObject *result,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions()) = 0;
+
+ virtual void
+ ExecuteInterpreterLoop () = 0;
+
+ virtual bool
+ ExecuteOneLineWithReturn (const char *in_string,
+ ScriptReturnType return_type,
+ void *ret_value,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions())
+ {
+ return true;
+ }
+
+ virtual bool
+ ExecuteMultipleLines (const char *in_string,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions())
+ {
+ return true;
+ }
+
+ virtual bool
+ ExportFunctionDefinitionToInterpreter (StringList &function_def)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateBreakpointCommandCallbackData (StringList &input, std::string& output)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateWatchpointCommandCallbackData (StringList &input, std::string& output)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token = NULL)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateTypeScriptFunction (StringList &input, std::string& output, void* name_token = NULL)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateScriptAliasFunction (StringList &input, std::string& output)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateTypeSynthClass (StringList &input, std::string& output, void* name_token = NULL)
+ {
+ return false;
+ }
+
+ virtual bool
+ GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token = NULL)
+ {
+ return false;
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ CreateSyntheticScriptedProvider (const char *class_name,
+ lldb::ValueObjectSP valobj)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_CreatePluginObject (const char *class_name,
+ lldb::ProcessSP process_sp)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t thread_id)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t tid,
+ lldb::addr_t context)
+ {
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ virtual bool
+ GenerateFunction(const char *signature, const StringList &input)
+ {
+ return false;
+ }
+
+ virtual void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result);
+
+ virtual void
+ CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+ CommandReturnObject &result);
+
+ /// Set a one-liner as the callback for the breakpoint.
+ virtual void
+ SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ const char *oneliner)
+ {
+ return;
+ }
+
+ /// Set a one-liner as the callback for the watchpoint.
+ virtual void
+ SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+ const char *oneliner)
+ {
+ return;
+ }
+
+ virtual bool
+ GetScriptedSummary (const char *function_name,
+ lldb::ValueObjectSP valobj,
+ lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
+ std::string& retval)
+ {
+ return false;
+ }
+
+ virtual size_t
+ CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor)
+ {
+ return 0;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx)
+ {
+ return lldb::ValueObjectSP();
+ }
+
+ virtual int
+ GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name)
+ {
+ return UINT32_MAX;
+ }
+
+ virtual bool
+ UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor)
+ {
+ return false;
+ }
+
+ virtual bool
+ MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor)
+ {
+ return true;
+ }
+
+ virtual bool
+ RunScriptBasedCommand (const char* impl_function,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error)
+ {
+ return false;
+ }
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Process* process,
+ std::string& output,
+ Error& error)
+ {
+ error.SetErrorString("unimplemented");
+ return false;
+ }
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Thread* thread,
+ std::string& output,
+ Error& error)
+ {
+ error.SetErrorString("unimplemented");
+ return false;
+ }
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Target* target,
+ std::string& output,
+ Error& error)
+ {
+ error.SetErrorString("unimplemented");
+ return false;
+ }
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ StackFrame* frame,
+ std::string& output,
+ Error& error)
+ {
+ error.SetErrorString("unimplemented");
+ return false;
+ }
+
+ virtual bool
+ GetDocumentationForItem (const char* item, std::string& dest)
+ {
+ dest.clear();
+ return false;
+ }
+
+ virtual bool
+ CheckObjectExists (const char* name)
+ {
+ return false;
+ }
+
+ virtual bool
+ LoadScriptingModule (const char* filename,
+ bool can_reload,
+ bool init_session,
+ lldb_private::Error& error)
+ {
+ error.SetErrorString("loading unimplemented");
+ return false;
+ }
+
+ virtual lldb::ScriptInterpreterObjectSP
+ MakeScriptObject (void* object)
+ {
+ return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterObject(object));
+ }
+
+ virtual std::unique_ptr<ScriptInterpreterLocker>
+ AcquireInterpreterLock ();
+
+ const char *
+ GetScriptInterpreterPtyName ();
+
+ int
+ GetMasterFileDescriptor ();
+
+ CommandInterpreter &
+ GetCommandInterpreter ();
+
+ static std::string
+ LanguageToString (lldb::ScriptLanguage language);
+
+ static void
+ InitializeInterpreter (SWIGInitCallback python_swig_init_callback);
+
+ static void
+ TerminateInterpreter ();
+
+ virtual void
+ ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing.
+
+protected:
+ CommandInterpreter &m_interpreter;
+ lldb::ScriptLanguage m_script_lang;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ScriptInterpreter_h_
diff --git a/include/lldb/Interpreter/ScriptInterpreterNone.h b/include/lldb/Interpreter/ScriptInterpreterNone.h
new file mode 100644
index 000000000000..6c82b60b0bcd
--- /dev/null
+++ b/include/lldb/Interpreter/ScriptInterpreterNone.h
@@ -0,0 +1,35 @@
+//===-- ScriptInterpreterNone.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_ScriptInterpreterNone_h_
+#define liblldb_ScriptInterpreterNone_h_
+
+#include "lldb/Interpreter/ScriptInterpreter.h"
+
+namespace lldb_private {
+
+class ScriptInterpreterNone : public ScriptInterpreter
+{
+public:
+
+ ScriptInterpreterNone (CommandInterpreter &interpreter);
+
+ ~ScriptInterpreterNone ();
+
+ bool
+ ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options = ExecuteScriptOptions());
+
+ void
+ ExecuteInterpreterLoop ();
+
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ScriptInterpreterNone_h_
diff --git a/include/lldb/Interpreter/ScriptInterpreterPython.h b/include/lldb/Interpreter/ScriptInterpreterPython.h
new file mode 100644
index 000000000000..2616f575d20e
--- /dev/null
+++ b/include/lldb/Interpreter/ScriptInterpreterPython.h
@@ -0,0 +1,407 @@
+//===-- ScriptInterpreterPython.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_ScriptInterpreterPython_h_
+#define liblldb_ScriptInterpreterPython_h_
+
+#ifdef LLDB_DISABLE_PYTHON
+
+// Python is disabled in this build
+
+#else
+
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+#include "lldb/lldb-private.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Host/Terminal.h"
+
+namespace lldb_private {
+
+class ScriptInterpreterPython : public ScriptInterpreter
+{
+public:
+
+ ScriptInterpreterPython (CommandInterpreter &interpreter);
+
+ ~ScriptInterpreterPython ();
+
+ bool
+ ExecuteOneLine (const char *command,
+ CommandReturnObject *result,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions());
+
+ void
+ ExecuteInterpreterLoop ();
+
+ bool
+ ExecuteOneLineWithReturn (const char *in_string,
+ ScriptInterpreter::ScriptReturnType return_type,
+ void *ret_value,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions());
+
+ bool
+ ExecuteMultipleLines (const char *in_string,
+ const ExecuteScriptOptions &options = ExecuteScriptOptions());
+
+ bool
+ ExportFunctionDefinitionToInterpreter (StringList &function_def);
+
+ bool
+ GenerateTypeScriptFunction (StringList &input, std::string& output, void* name_token = NULL);
+
+ bool
+ GenerateTypeSynthClass (StringList &input, std::string& output, void* name_token = NULL);
+
+ bool
+ GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token = NULL);
+
+ // use this if the function code is just a one-liner script
+ bool
+ GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token = NULL);
+
+ virtual bool
+ GenerateScriptAliasFunction (StringList &input, std::string& output);
+
+ lldb::ScriptInterpreterObjectSP
+ CreateSyntheticScriptedProvider (const char *class_name,
+ lldb::ValueObjectSP valobj);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_CreatePluginObject (const char *class_name,
+ lldb::ProcessSP process_sp);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t thread_id);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t tid,
+ lldb::addr_t context);
+
+ virtual size_t
+ CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor);
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor, uint32_t idx);
+
+ virtual int
+ GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor, const char* child_name);
+
+ virtual bool
+ UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor);
+
+ virtual bool
+ MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor);
+
+ virtual bool
+ RunScriptBasedCommand(const char* impl_function,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error);
+
+ bool
+ GenerateFunction(const char *signature, const StringList &input);
+
+ bool
+ GenerateBreakpointCommandCallbackData (StringList &input, std::string& output);
+
+ bool
+ GenerateWatchpointCommandCallbackData (StringList &input, std::string& output);
+
+ static size_t
+ GenerateBreakpointOptionsCommandCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ static size_t
+ GenerateWatchpointOptionsCommandCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ static bool
+ BreakpointCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ static bool
+ WatchpointCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id);
+
+ virtual bool
+ GetScriptedSummary (const char *function_name,
+ lldb::ValueObjectSP valobj,
+ lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
+ std::string& retval);
+
+ virtual bool
+ GetDocumentationForItem (const char* item, std::string& dest);
+
+ virtual bool
+ CheckObjectExists (const char* name)
+ {
+ if (!name || !name[0])
+ return false;
+ std::string temp;
+ return GetDocumentationForItem (name,temp);
+ }
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Process* process,
+ std::string& output,
+ Error& error);
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Thread* thread,
+ std::string& output,
+ Error& error);
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ Target* target,
+ std::string& output,
+ Error& error);
+
+ virtual bool
+ RunScriptFormatKeyword (const char* impl_function,
+ StackFrame* frame,
+ std::string& output,
+ Error& error);
+
+ virtual bool
+ LoadScriptingModule (const char* filename,
+ bool can_reload,
+ bool init_session,
+ lldb_private::Error& error);
+
+ virtual lldb::ScriptInterpreterObjectSP
+ MakeScriptObject (void* object);
+
+ virtual std::unique_ptr<ScriptInterpreterLocker>
+ AcquireInterpreterLock ();
+
+ void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result);
+
+ void
+ CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+ CommandReturnObject &result);
+
+ /// Set a Python one-liner as the callback for the breakpoint.
+ void
+ SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ const char *oneliner);
+
+ /// Set a one-liner as the callback for the watchpoint.
+ void
+ SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+ const char *oneliner);
+
+ StringList
+ ReadCommandInputFromUser (FILE *in_file);
+
+ virtual void
+ ResetOutputFileHandle (FILE *new_fh);
+
+ static lldb::thread_result_t
+ RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton);
+
+ static void
+ InitializePrivate ();
+
+ static void
+ InitializeInterpreter (SWIGInitCallback python_swig_init_callback);
+
+protected:
+
+ bool
+ EnterSession (bool init_lldb_globals);
+
+ void
+ LeaveSession ();
+
+ void
+ SaveTerminalState (int fd);
+
+ void
+ RestoreTerminalState ();
+
+private:
+
+ class SynchronicityHandler
+ {
+ private:
+ lldb::DebuggerSP m_debugger_sp;
+ ScriptedCommandSynchronicity m_synch_wanted;
+ bool m_old_asynch;
+ public:
+ SynchronicityHandler(lldb::DebuggerSP,
+ ScriptedCommandSynchronicity);
+ ~SynchronicityHandler();
+ };
+
+ class ScriptInterpreterPythonObject : public ScriptInterpreterObject
+ {
+ public:
+ ScriptInterpreterPythonObject() :
+ ScriptInterpreterObject()
+ {}
+
+ ScriptInterpreterPythonObject(void* obj) :
+ ScriptInterpreterObject(obj)
+ {
+ Py_XINCREF(m_object);
+ }
+
+ operator bool ()
+ {
+ return m_object && m_object != Py_None;
+ }
+
+
+ virtual
+ ~ScriptInterpreterPythonObject()
+ {
+ Py_XDECREF(m_object);
+ m_object = NULL;
+ }
+ private:
+ DISALLOW_COPY_AND_ASSIGN (ScriptInterpreterPythonObject);
+ };
+
+ class Locker : public ScriptInterpreterLocker
+ {
+ public:
+
+ enum OnEntry
+ {
+ AcquireLock = 0x0001,
+ InitSession = 0x0002,
+ InitGlobals = 0x0004
+ };
+
+ enum OnLeave
+ {
+ FreeLock = 0x0001,
+ FreeAcquiredLock = 0x0002, // do not free the lock if we already held it when calling constructor
+ TearDownSession = 0x0004
+ };
+
+ Locker (ScriptInterpreterPython *py_interpreter = NULL,
+ uint16_t on_entry = AcquireLock | InitSession,
+ uint16_t on_leave = FreeLock | TearDownSession,
+ FILE* wait_msg_handle = NULL);
+
+ ~Locker ();
+
+ private:
+
+ bool
+ DoAcquireLock ();
+
+ bool
+ DoInitSession (bool init_lldb_globals);
+
+ bool
+ DoFreeLock ();
+
+ bool
+ DoTearDownSession ();
+
+ static void
+ ReleasePythonLock ();
+
+ bool m_teardown_session;
+ ScriptInterpreterPython *m_python_interpreter;
+ FILE* m_tmp_fh;
+ PyGILState_STATE m_GILState;
+ };
+
+ class PythonInputReaderManager
+ {
+ public:
+ PythonInputReaderManager (ScriptInterpreterPython *interpreter);
+
+ operator bool()
+ {
+ return m_error;
+ }
+
+ ~PythonInputReaderManager();
+
+ private:
+
+ static size_t
+ InputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ static lldb::thread_result_t
+ RunPythonInputReader (lldb::thread_arg_t baton);
+
+ ScriptInterpreterPython *m_interpreter;
+ lldb::DebuggerSP m_debugger_sp;
+ lldb::InputReaderSP m_reader_sp;
+ bool m_error;
+ };
+
+ static size_t
+ InputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+
+ lldb_utility::PseudoTerminal m_embedded_thread_pty;
+ lldb_utility::PseudoTerminal m_embedded_python_pty;
+ lldb::InputReaderSP m_embedded_thread_input_reader_sp;
+ lldb::InputReaderSP m_embedded_python_input_reader_sp;
+ FILE *m_dbg_stdout;
+ PyObject *m_new_sysout;
+ PyObject *m_old_sysout;
+ PyObject *m_old_syserr;
+ PyObject *m_run_one_line;
+ std::string m_dictionary_name;
+ TerminalState m_terminal_state;
+ bool m_session_is_active;
+ bool m_pty_slave_is_open;
+ bool m_valid_session;
+ PyThreadState *m_command_thread_state;
+};
+} // namespace lldb_private
+
+#endif // #ifdef LLDB_DISABLE_PYTHON
+
+#endif // #ifndef liblldb_ScriptInterpreterPython_h_
diff --git a/include/lldb/Symbol/Block.h b/include/lldb/Symbol/Block.h
new file mode 100644
index 000000000000..a2d703b9069c
--- /dev/null
+++ b/include/lldb/Symbol/Block.h
@@ -0,0 +1,496 @@
+//===-- Block.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_Block_h_
+#define liblldb_Block_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Block Block.h "lldb/Symbol/Block.h"
+/// @brief A class that describes a single lexical block.
+///
+/// A Function object owns a BlockList object which owns one or more
+/// Block objects. The BlockList object contains a section offset
+/// address range, and Block objects contain one or more ranges
+/// which are offsets into that range. Blocks are can have discontiguous
+/// ranges within the BlockList adress range, and each block can
+/// contain child blocks each with their own sets of ranges.
+///
+/// Each block has a variable list that represents local, argument, and
+/// static variables that are scoped to the block.
+///
+/// Inlined functions are representated by attaching a
+/// InlineFunctionInfo shared pointer object to a block. Inlined
+/// functions are represented as named blocks.
+//----------------------------------------------------------------------
+class Block :
+ public UserID,
+ public SymbolContextScope
+{
+public:
+ typedef RangeArray<uint32_t, uint32_t, 1> RangeList;
+ typedef RangeList::Entry Range;
+
+ //------------------------------------------------------------------
+ /// Construct with a User ID \a uid, \a depth.
+ ///
+ /// Initialize this block with the specified UID \a uid. The
+ /// \a depth in the \a block_list is used to represent the parent,
+ /// sibling, and child block information and also allows for partial
+ /// parsing at the block level.
+ ///
+ /// @param[in] uid
+ /// The UID for a given block. This value is given by the
+ /// SymbolFile plug-in and can be any value that helps the
+ /// SymbolFile plug-in to match this block back to the debug
+ /// information data that it parses for further or more in
+ /// depth parsing. Common values would be the index into a
+ /// table, or an offset into the debug information.
+ ///
+ /// @param[in] depth
+ /// The integer depth of this block in the block list hierarchy.
+ ///
+ /// @param[in] block_list
+ /// The block list that this object belongs to.
+ ///
+ /// @see BlockList
+ //------------------------------------------------------------------
+ Block (lldb::user_id_t uid);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ virtual ~Block ();
+
+ //------------------------------------------------------------------
+ /// Add a child to this object.
+ ///
+ /// @param[in] child_block_sp
+ /// A shared pointer to a child block that will get added to
+ /// this block.
+ //------------------------------------------------------------------
+ void
+ AddChild (const lldb::BlockSP &child_block_sp);
+
+ //------------------------------------------------------------------
+ /// Add a new offset range to this block.
+ ///
+ /// @param[in] start_offset
+ /// An offset into this Function's address range that
+ /// describes the start address of a range for this block.
+ ///
+ /// @param[in] end_offset
+ /// An offset into this Function's address range that
+ /// describes the end address of a range for this block.
+ //------------------------------------------------------------------
+ void
+ AddRange (const Range& range);
+
+ void
+ FinalizeRanges ();
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext(SymbolContext* sc);
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ();
+
+ virtual CompileUnit *
+ CalculateSymbolContextCompileUnit ();
+
+ virtual Function *
+ CalculateSymbolContextFunction ();
+
+ virtual Block *
+ CalculateSymbolContextBlock ();
+
+ //------------------------------------------------------------------
+ /// Check if an offset is in one of the block offset ranges.
+ ///
+ /// @param[in] range_offset
+ /// An offset into the Function's address range.
+ ///
+ /// @return
+ /// Returns \b true if \a range_offset falls in one of this
+ /// block's ranges, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Contains (lldb::addr_t range_offset) const;
+
+ //------------------------------------------------------------------
+ /// Check if a offset range is in one of the block offset ranges.
+ ///
+ /// @param[in] range
+ /// An offset range into the Function's address range.
+ ///
+ /// @return
+ /// Returns \b true if \a range falls in one of this
+ /// block's ranges, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Contains (const Range& range) const;
+
+ //------------------------------------------------------------------
+ /// Check if this object contains "block" as a child block at any
+ /// depth.
+ ///
+ /// @param[in] block
+ /// A potential child block.
+ ///
+ /// @return
+ /// Returns \b true if \a block is a child of this block, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool
+ Contains (const Block *block) const;
+
+ //------------------------------------------------------------------
+ /// Dump the block contents.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] base_addr
+ /// The resolved start address of the Function's address
+ /// range. This should be resolved as the file or load address
+ /// prior to passing the value into this function for dumping.
+ ///
+ /// @param[in] depth
+ /// Limit the number of levels deep that this function should
+ /// print as this block can contain child blocks. Specify
+ /// INT_MAX to dump all child blocks.
+ ///
+ /// @param[in] show_context
+ /// If \b true, variables will dump their context information.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, lldb::addr_t base_addr, int32_t depth, bool show_context) const;
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext(Stream *s);
+
+ void
+ DumpAddressRanges (Stream *s,
+ lldb::addr_t base_addr);
+
+ void
+ GetDescription (Stream *s,
+ Function *function,
+ lldb::DescriptionLevel level,
+ Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Get the parent block.
+ ///
+ /// @return
+ /// The parent block pointer, or NULL if this block has no
+ /// parent.
+ //------------------------------------------------------------------
+ Block *
+ GetParent () const;
+
+
+ //------------------------------------------------------------------
+ /// Get the inlined block that contains this block.
+ ///
+ /// @return
+ /// If this block contains inlined function info, it will return
+ /// this block, else parent blocks will be searched to see if
+ /// any contain this block. NULL will be returned if this block
+ /// nor any parent blocks are inlined function blocks.
+ //------------------------------------------------------------------
+ Block *
+ GetContainingInlinedBlock ();
+
+ //------------------------------------------------------------------
+ /// Get the inlined parent block for this block.
+ ///
+ /// @return
+ /// The parent block pointer, or NULL if this block has no
+ /// parent.
+ //------------------------------------------------------------------
+ Block *
+ GetInlinedParent ();
+
+ //------------------------------------------------------------------
+ /// Get the sibling block for this block.
+ ///
+ /// @return
+ /// The sibling block pointer, or NULL if this block has no
+ /// sibling.
+ //------------------------------------------------------------------
+ Block *
+ GetSibling () const;
+
+ //------------------------------------------------------------------
+ /// Get the first child block.
+ ///
+ /// @return
+ /// The first child block pointer, or NULL if this block has no
+ /// children.
+ //------------------------------------------------------------------
+ Block *
+ GetFirstChild () const
+ {
+ if (m_children.empty())
+ return NULL;
+ return m_children.front().get();
+ }
+
+ //------------------------------------------------------------------
+ /// Get the variable list for this block only.
+ ///
+ /// @param[in] can_create
+ /// If \b true, the variables can be parsed if they already
+ /// haven't been, else the current state of the block will be
+ /// returned.
+ ///
+ /// @return
+ /// A variable list shared pointer that contains all variables
+ /// for this block.
+ //------------------------------------------------------------------
+ lldb::VariableListSP
+ GetBlockVariableList (bool can_create);
+
+
+ //------------------------------------------------------------------
+ /// Get the variable list for this block and optionally all child
+ /// blocks if \a get_child_variables is \b true.
+ ///
+ /// @param[in] get_child_variables
+ /// If \b true, all variables from all child blocks will be
+ /// added to the variable list.
+ ///
+ /// @param[in] can_create
+ /// If \b true, the variables can be parsed if they already
+ /// haven't been, else the current state of the block will be
+ /// returned. Passing \b true for this parameter can be used
+ /// to see the current state of what has been parsed up to this
+ /// point.
+ ///
+ /// @param[in] add_inline_child_block_variables
+ /// If this is \b false, no child variables of child blocks
+ /// that are inlined functions will be gotten. If \b true then
+ /// all child variables will be added regardless of whether they
+ /// come from inlined functions or not.
+ ///
+ /// @return
+ /// A variable list shared pointer that contains all variables
+ /// for this block.
+ //------------------------------------------------------------------
+ uint32_t
+ AppendBlockVariables (bool can_create,
+ bool get_child_block_variables,
+ bool stop_if_child_block_is_inlined_function,
+ VariableList *variable_list);
+
+ //------------------------------------------------------------------
+ /// Appends the variables from this block, and optionally from all
+ /// parent blocks, to \a variable_list.
+ ///
+ /// @param[in] can_create
+ /// If \b true, the variables can be parsed if they already
+ /// haven't been, else the current state of the block will be
+ /// returned. Passing \b true for this parameter can be used
+ /// to see the current state of what has been parsed up to this
+ /// point.
+ ///
+ /// @param[in] get_parent_variables
+ /// If \b true, all variables from all parent blocks will be
+ /// added to the variable list.
+ ///
+ /// @param[in] stop_if_block_is_inlined_function
+ /// If \b true, all variables from all parent blocks will be
+ /// added to the variable list until there are no parent blocks
+ /// or the parent block has inlined function info.
+ ///
+ /// @param[in/out] variable_list
+ /// All variables in this block, and optionally all parent
+ /// blocks will be added to this list.
+ ///
+ /// @return
+ /// The number of variable that were appended to \a
+ /// variable_list.
+ //------------------------------------------------------------------
+ uint32_t
+ AppendVariables (bool can_create,
+ bool get_parent_variables,
+ bool stop_if_block_is_inlined_function,
+ VariableList *variable_list);
+
+ //------------------------------------------------------------------
+ /// Get const accessor for any inlined function information.
+ ///
+ /// @return
+ /// A comst pointer to any inlined function information, or NULL
+ /// if this is a regular block.
+ //------------------------------------------------------------------
+ const InlineFunctionInfo*
+ GetInlinedFunctionInfo () const
+ {
+ return m_inlineInfoSP.get();
+ }
+
+ clang::DeclContext *
+ GetClangDeclContext();
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// Returns the cost of this object plus any owned objects from the
+ /// ranges, variables, and inline function information.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize() const;
+
+ //------------------------------------------------------------------
+ /// Set accessor for any inlined function information.
+ ///
+ /// @param[in] name
+ /// The method name for the inlined function. This value should
+ /// not be NULL.
+ ///
+ /// @param[in] mangled
+ /// The mangled method name for the inlined function. This can
+ /// be NULL if there is no mangled name for an inlined function
+ /// or if the name is the same as \a name.
+ ///
+ /// @param[in] decl_ptr
+ /// A optional pointer to declaration information for the
+ /// inlined function information. This value can be NULL to
+ /// indicate that no declaration information is available.
+ ///
+ /// @param[in] call_decl_ptr
+ /// Optional calling location declaration information that
+ /// describes from where this inlined function was called.
+ //------------------------------------------------------------------
+ void
+ SetInlinedFunctionInfo (const char *name,
+ const char *mangled,
+ const Declaration *decl_ptr,
+ const Declaration *call_decl_ptr);
+
+
+ void
+ SetParentScope (SymbolContextScope *parent_scope)
+ {
+ m_parent_scope = parent_scope;
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the variable list.
+ ///
+ /// Called by the SymbolFile plug-ins after they have parsed the
+ /// variable lists and are ready to hand ownership of the list over
+ /// to this object.
+ ///
+ /// @param[in] variable_list_sp
+ /// A shared pointer to a VariableList.
+ //------------------------------------------------------------------
+ void
+ SetVariableList (lldb::VariableListSP& variable_list_sp)
+ {
+ m_variable_list_sp = variable_list_sp;
+ }
+
+
+
+ bool
+ BlockInfoHasBeenParsed() const
+ {
+ return m_parsed_block_info;
+ }
+
+ void
+ SetBlockInfoHasBeenParsed (bool b, bool set_children);
+
+ Block *
+ FindBlockByID (lldb::user_id_t block_id);
+
+ size_t
+ GetNumRanges () const
+ {
+ return m_ranges.GetSize();
+ }
+
+ bool
+ GetRangeContainingOffset (const lldb::addr_t offset, Range &range);
+
+ bool
+ GetRangeContainingAddress (const Address& addr, AddressRange &range);
+
+ bool
+ GetRangeContainingLoadAddress (lldb::addr_t load_addr, Target &target, AddressRange &range);
+
+ uint32_t
+ GetRangeIndexContainingAddress (const Address& addr);
+
+ //------------------------------------------------------------------
+ // Since blocks might have multiple discontiguous addresss ranges,
+ // we need to be able to get at any of the address ranges in a block.
+ //------------------------------------------------------------------
+ bool
+ GetRangeAtIndex (uint32_t range_idx,
+ AddressRange &range);
+
+ bool
+ GetStartAddress (Address &addr);
+
+ void
+ SetDidParseVariables (bool b, bool set_children);
+
+protected:
+ typedef std::vector<lldb::BlockSP> collection;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ SymbolContextScope *m_parent_scope;
+ collection m_children;
+ RangeList m_ranges;
+ lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
+ lldb::VariableListSP m_variable_list_sp; ///< The variable list for all local, static and paramter variables scoped to this block.
+ bool m_parsed_block_info:1, ///< Set to true if this block and it's children have all been parsed
+ m_parsed_block_variables:1,
+ m_parsed_child_blocks:1;
+
+ // A parent of child blocks can be asked to find a sibling block given
+ // one of its child blocks
+ Block *
+ GetSiblingForChild (const Block *child_block) const;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (Block);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Block_h_
diff --git a/include/lldb/Symbol/ClangASTContext.h b/include/lldb/Symbol/ClangASTContext.h
new file mode 100644
index 000000000000..75fc07b480e1
--- /dev/null
+++ b/include/lldb/Symbol/ClangASTContext.h
@@ -0,0 +1,441 @@
+//===-- ClangASTContext.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_ClangASTContext_h_
+#define liblldb_ClangASTContext_h_
+
+// C Includes
+#include <stdint.h>
+
+// C++ Includes
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/SmallVector.h"
+#include "clang/AST/TemplateBase.h"
+
+
+// Project includes
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+namespace lldb_private {
+
+class Declaration;
+
+class ClangASTContext
+{
+public:
+ typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
+ typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ClangASTContext (const char *triple = NULL);
+
+ ~ClangASTContext();
+
+ clang::ASTContext *
+ getASTContext();
+
+ clang::Builtin::Context *
+ getBuiltinContext();
+
+ clang::IdentifierTable *
+ getIdentifierTable();
+
+ clang::LangOptions *
+ getLanguageOptions();
+
+ clang::SelectorTable *
+ getSelectorTable();
+
+ clang::FileManager *
+ getFileManager();
+
+ clang::SourceManager *
+ getSourceManager();
+
+ clang::DiagnosticsEngine *
+ getDiagnosticsEngine();
+
+ clang::DiagnosticConsumer *
+ getDiagnosticConsumer();
+
+ clang::TargetOptions *
+ getTargetOptions();
+
+ clang::TargetInfo *
+ getTargetInfo();
+
+ void
+ Clear();
+
+ const char *
+ GetTargetTriple ();
+
+ void
+ SetTargetTriple (const char *target_triple);
+
+ void
+ SetArchitecture (const ArchSpec &arch);
+
+ bool
+ HasExternalSource ();
+
+ void
+ SetExternalSource (llvm::OwningPtr<clang::ExternalASTSource> &ast_source_ap);
+
+ void
+ RemoveExternalSource ();
+
+ bool
+ GetCompleteDecl (clang::Decl *decl)
+ {
+ return ClangASTContext::GetCompleteDecl(getASTContext(), decl);
+ }
+
+ static bool
+ GetCompleteDecl (clang::ASTContext *ast,
+ clang::Decl *decl);
+
+ void SetMetadataAsUserID (const void *object,
+ lldb::user_id_t user_id);
+
+ void SetMetadata (const void *object,
+ ClangASTMetadata &meta_data)
+ {
+ SetMetadata(getASTContext(), object, meta_data);
+ }
+
+ static void
+ SetMetadata (clang::ASTContext *ast,
+ const void *object,
+ ClangASTMetadata &meta_data);
+
+ ClangASTMetadata *
+ GetMetadata (const void *object)
+ {
+ return GetMetadata(getASTContext(), object);
+ }
+
+ static ClangASTMetadata *
+ GetMetadata (clang::ASTContext *ast,
+ const void *object);
+
+ //------------------------------------------------------------------
+ // Basic Types
+ //------------------------------------------------------------------
+ ClangASTType
+ GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding,
+ uint32_t bit_size);
+
+ static ClangASTType
+ GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast,
+ lldb::Encoding encoding,
+ uint32_t bit_size);
+
+ ClangASTType
+ GetBasicType (lldb::BasicType type);
+
+ static ClangASTType
+ GetBasicType (clang::ASTContext *ast, lldb::BasicType type);
+
+ static ClangASTType
+ GetBasicType (clang::ASTContext *ast, const ConstString &name);
+
+ static lldb::BasicType
+ GetBasicTypeEnumeration (const ConstString &name);
+
+ ClangASTType
+ GetBuiltinTypeForDWARFEncodingAndBitSize (
+ const char *type_name,
+ uint32_t dw_ate,
+ uint32_t bit_size);
+
+ ClangASTType
+ GetCStringType(bool is_const);
+
+ static ClangASTType
+ GetUnknownAnyType(clang::ASTContext *ast);
+
+ ClangASTType
+ GetUnknownAnyType()
+ {
+ return ClangASTContext::GetUnknownAnyType(getASTContext());
+ }
+
+ uint32_t
+ GetPointerByteSize ();
+
+ static clang::DeclContext *
+ GetTranslationUnitDecl (clang::ASTContext *ast);
+
+ clang::DeclContext *
+ GetTranslationUnitDecl ()
+ {
+ return GetTranslationUnitDecl (getASTContext());
+ }
+
+ static bool
+ GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx,
+ lldb::LanguageType &language,
+ bool &is_instance_method,
+ ConstString &language_object_name);
+
+ static ClangASTType
+ CopyType(clang::ASTContext *dest_context,
+ ClangASTType source_type);
+
+ static clang::Decl *
+ CopyDecl (clang::ASTContext *dest_context,
+ clang::ASTContext *source_context,
+ clang::Decl *source_decl);
+
+ static bool
+ AreTypesSame(ClangASTType type1,
+ ClangASTType type2,
+ bool ignore_qualifiers = false);
+
+ ClangASTType
+ GetTypeForDecl (clang::TagDecl *decl);
+
+ ClangASTType
+ GetTypeForDecl (clang::ObjCInterfaceDecl *objc_decl);
+
+ //------------------------------------------------------------------
+ // Structure, Unions, Classes
+ //------------------------------------------------------------------
+
+ static clang::AccessSpecifier
+ ConvertAccessTypeToAccessSpecifier (lldb::AccessType access);
+
+ static clang::AccessSpecifier
+ UnifyAccessSpecifiers (clang::AccessSpecifier lhs, clang::AccessSpecifier rhs);
+
+ static uint32_t
+ GetNumBaseClasses (const clang::CXXRecordDecl *cxx_record_decl,
+ bool omit_empty_base_classes);
+
+ static uint32_t
+ GetIndexForRecordBase (const clang::RecordDecl *record_decl,
+ const clang::CXXBaseSpecifier *base_spec,
+ bool omit_empty_base_classes);
+
+ ClangASTType
+ CreateRecordType (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *name,
+ int kind,
+ lldb::LanguageType language,
+ ClangASTMetadata *metadata = NULL);
+
+ class TemplateParameterInfos
+ {
+ public:
+ bool
+ IsValid() const
+ {
+ if (args.empty())
+ return false;
+ return args.size() == names.size();
+ }
+
+ size_t
+ GetSize () const
+ {
+ if (IsValid())
+ return args.size();
+ return 0;
+ }
+
+ llvm::SmallVector<const char *, 8> names;
+ llvm::SmallVector<clang::TemplateArgument, 8> args;
+ };
+
+ clang::FunctionTemplateDecl *
+ CreateFunctionTemplateDecl (clang::DeclContext *decl_ctx,
+ clang::FunctionDecl *func_decl,
+ const char *name,
+ const TemplateParameterInfos &infos);
+
+ void
+ CreateFunctionTemplateSpecializationInfo (clang::FunctionDecl *func_decl,
+ clang::FunctionTemplateDecl *Template,
+ const TemplateParameterInfos &infos);
+
+ clang::ClassTemplateDecl *
+ CreateClassTemplateDecl (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *class_name,
+ int kind,
+ const TemplateParameterInfos &infos);
+
+ clang::ClassTemplateSpecializationDecl *
+ CreateClassTemplateSpecializationDecl (clang::DeclContext *decl_ctx,
+ clang::ClassTemplateDecl *class_template_decl,
+ int kind,
+ const TemplateParameterInfos &infos);
+
+ ClangASTType
+ CreateClassTemplateSpecializationType (clang::ClassTemplateSpecializationDecl *class_template_specialization_decl);
+
+ static clang::DeclContext *
+ GetAsDeclContext (clang::CXXMethodDecl *cxx_method_decl);
+
+ static clang::DeclContext *
+ GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl);
+
+
+ static bool
+ CheckOverloadedOperatorKindParameterCount (uint32_t op_kind,
+ uint32_t num_params);
+
+ bool
+ FieldIsBitfield (clang::FieldDecl* field,
+ uint32_t& bitfield_bit_size);
+
+ static bool
+ FieldIsBitfield (clang::ASTContext *ast,
+ clang::FieldDecl* field,
+ uint32_t& bitfield_bit_size);
+
+ static bool
+ RecordHasFields (const clang::RecordDecl *record_decl);
+
+
+ ClangASTType
+ CreateObjCClass (const char *name,
+ clang::DeclContext *decl_ctx,
+ bool isForwardDecl,
+ bool isInternal,
+ ClangASTMetadata *metadata = NULL);
+
+ // Returns a mask containing bits from the ClangASTContext::eTypeXXX enumerations
+
+
+ //------------------------------------------------------------------
+ // Namespace Declarations
+ //------------------------------------------------------------------
+
+ clang::NamespaceDecl *
+ GetUniqueNamespaceDeclaration (const char *name,
+ clang::DeclContext *decl_ctx);
+
+ //------------------------------------------------------------------
+ // Function Types
+ //------------------------------------------------------------------
+
+ clang::FunctionDecl *
+ CreateFunctionDeclaration (clang::DeclContext *decl_ctx,
+ const char *name,
+ const ClangASTType &function_Type,
+ int storage,
+ bool is_inline);
+
+ static ClangASTType
+ CreateFunctionType (clang::ASTContext *ast,
+ const ClangASTType &result_type,
+ const ClangASTType *args,
+ unsigned num_args,
+ bool is_variadic,
+ unsigned type_quals);
+
+ ClangASTType
+ CreateFunctionType (const ClangASTType &result_type,
+ const ClangASTType *args,
+ unsigned num_args,
+ bool is_variadic,
+ unsigned type_quals)
+ {
+ return ClangASTContext::CreateFunctionType(getASTContext(),
+ result_type,
+ args,
+ num_args,
+ is_variadic,
+ type_quals);
+ }
+
+ clang::ParmVarDecl *
+ CreateParameterDeclaration (const char *name,
+ const ClangASTType &param_type,
+ int storage);
+
+ void
+ SetFunctionParameters (clang::FunctionDecl *function_decl,
+ clang::ParmVarDecl **params,
+ unsigned num_params);
+
+ //------------------------------------------------------------------
+ // Array Types
+ //------------------------------------------------------------------
+
+ ClangASTType
+ CreateArrayType (const ClangASTType &element_type,
+ size_t element_count,
+ bool is_vector);
+
+ //------------------------------------------------------------------
+ // Enumeration Types
+ //------------------------------------------------------------------
+ ClangASTType
+ CreateEnumerationType (const char *name,
+ clang::DeclContext *decl_ctx,
+ const Declaration &decl,
+ const ClangASTType &integer_qual_type);
+
+ //------------------------------------------------------------------
+ // Floating point functions
+ //------------------------------------------------------------------
+
+ ClangASTType
+ GetFloatTypeFromBitSize (size_t bit_size)
+ {
+ return GetFloatTypeFromBitSize (getASTContext(), bit_size);
+ }
+
+ static ClangASTType
+ GetFloatTypeFromBitSize (clang::ASTContext *ast,
+ size_t bit_size);
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangASTContext can see and modify these
+ //------------------------------------------------------------------
+ std::string m_target_triple;
+ std::unique_ptr<clang::ASTContext> m_ast_ap;
+ std::unique_ptr<clang::LangOptions> m_language_options_ap;
+ std::unique_ptr<clang::FileManager> m_file_manager_ap;
+ std::unique_ptr<clang::FileSystemOptions> m_file_system_options_ap;
+ std::unique_ptr<clang::SourceManager> m_source_manager_ap;
+ std::unique_ptr<clang::DiagnosticsEngine> m_diagnostics_engine_ap;
+ std::unique_ptr<clang::DiagnosticConsumer> m_diagnostic_consumer_ap;
+ llvm::IntrusiveRefCntPtr<clang::TargetOptions> m_target_options_rp;
+ std::unique_ptr<clang::TargetInfo> m_target_info_ap;
+ std::unique_ptr<clang::IdentifierTable> m_identifier_table_ap;
+ std::unique_ptr<clang::SelectorTable> m_selector_table_ap;
+ std::unique_ptr<clang::Builtin::Context> m_builtins_ap;
+ CompleteTagDeclCallback m_callback_tag_decl;
+ CompleteObjCInterfaceDeclCallback m_callback_objc_decl;
+ void * m_callback_baton;
+ uint32_t m_pointer_byte_size;
+private:
+ //------------------------------------------------------------------
+ // For ClangASTContext only
+ //------------------------------------------------------------------
+ ClangASTContext(const ClangASTContext&);
+ const ClangASTContext& operator=(const ClangASTContext&);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangASTContext_h_
diff --git a/include/lldb/Symbol/ClangASTImporter.h b/include/lldb/Symbol/ClangASTImporter.h
new file mode 100644
index 000000000000..10df7da893a8
--- /dev/null
+++ b/include/lldb/Symbol/ClangASTImporter.h
@@ -0,0 +1,371 @@
+//===-- ClangASTImporter.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_ClangASTImporter_h_
+#define liblldb_ClangASTImporter_h_
+
+#include <map>
+#include <set>
+
+#include "lldb/lldb-types.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+
+namespace lldb_private {
+
+class ClangASTMetrics
+{
+public:
+ static void DumpCounters (Log *log);
+ static void ClearLocalCounters ()
+ {
+ local_counters = { 0, 0, 0, 0, 0, 0 };
+ }
+
+ static void RegisterVisibleQuery ()
+ {
+ ++global_counters.m_visible_query_count;
+ ++local_counters.m_visible_query_count;
+ }
+
+ static void RegisterLexicalQuery ()
+ {
+ ++global_counters.m_lexical_query_count;
+ ++local_counters.m_lexical_query_count;
+ }
+
+ static void RegisterLLDBImport ()
+ {
+ ++global_counters.m_lldb_import_count;
+ ++local_counters.m_lldb_import_count;
+ }
+
+ static void RegisterClangImport ()
+ {
+ ++global_counters.m_clang_import_count;
+ ++local_counters.m_clang_import_count;
+ }
+
+ static void RegisterDeclCompletion ()
+ {
+ ++global_counters.m_decls_completed_count;
+ ++local_counters.m_decls_completed_count;
+ }
+
+ static void RegisterRecordLayout ()
+ {
+ ++global_counters.m_record_layout_count;
+ ++local_counters.m_record_layout_count;
+ }
+
+private:
+ struct Counters
+ {
+ uint64_t m_visible_query_count;
+ uint64_t m_lexical_query_count;
+ uint64_t m_lldb_import_count;
+ uint64_t m_clang_import_count;
+ uint64_t m_decls_completed_count;
+ uint64_t m_record_layout_count;
+ };
+
+ static Counters global_counters;
+ static Counters local_counters;
+
+ static void DumpCounters (Log *log, Counters &counters);
+};
+
+class ClangASTImporter
+{
+public:
+ ClangASTImporter () :
+ m_file_manager(clang::FileSystemOptions())
+ {
+ }
+
+ clang::QualType
+ CopyType (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ clang::QualType type);
+
+ lldb::clang_type_t
+ CopyType (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ lldb::clang_type_t type);
+
+ clang::Decl *
+ CopyDecl (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ clang::Decl *decl);
+
+ lldb::clang_type_t
+ DeportType (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ lldb::clang_type_t type);
+
+ clang::Decl *
+ DeportDecl (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ clang::Decl *decl);
+
+ void
+ CompleteDecl (clang::Decl *decl);
+
+ bool
+ CompleteTagDecl (clang::TagDecl *decl);
+
+ bool
+ CompleteTagDeclWithOrigin (clang::TagDecl *decl, clang::TagDecl *origin);
+
+ bool
+ CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_decl);
+
+ bool
+ RequireCompleteType (clang::QualType type);
+
+ bool
+ ResolveDeclOrigin (const clang::Decl *decl, clang::Decl **original_decl, clang::ASTContext **original_ctx)
+ {
+ DeclOrigin origin = GetDeclOrigin(decl);
+
+ if (original_decl)
+ *original_decl = origin.decl;
+
+ if (original_ctx)
+ *original_ctx = origin.ctx;
+
+ return origin.Valid();
+ }
+
+ void
+ SetDeclOrigin (const clang::Decl *decl, clang::Decl *original_decl);
+
+ ClangASTMetadata *
+ GetDeclMetadata (const clang::Decl *decl);
+
+ //
+ // Namespace maps
+ //
+
+ typedef std::vector < std::pair<lldb::ModuleSP, ClangNamespaceDecl> > NamespaceMap;
+ typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
+
+ void RegisterNamespaceMap (const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map);
+
+ NamespaceMapSP GetNamespaceMap (const clang::NamespaceDecl *decl);
+
+ void BuildNamespaceMap (const clang::NamespaceDecl *decl);
+
+ //
+ // Comleters for maps
+ //
+
+ class MapCompleter
+ {
+ public:
+ virtual ~MapCompleter ();
+
+ virtual void CompleteNamespaceMap (NamespaceMapSP &namespace_map,
+ const ConstString &name,
+ NamespaceMapSP &parent_map) const = 0;
+ };
+
+ void InstallMapCompleter (clang::ASTContext *dst_ctx, MapCompleter &completer)
+ {
+ ASTContextMetadataSP context_md;
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end())
+ {
+ context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ }
+ else
+ {
+ context_md = context_md_iter->second;
+ }
+
+ context_md->m_map_completer = &completer;
+ }
+
+ void ForgetDestination (clang::ASTContext *dst_ctx);
+ void ForgetSource (clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
+private:
+ struct DeclOrigin
+ {
+ DeclOrigin () :
+ ctx(NULL),
+ decl(NULL)
+ {
+ }
+
+ DeclOrigin (clang::ASTContext *_ctx,
+ clang::Decl *_decl) :
+ ctx(_ctx),
+ decl(_decl)
+ {
+ }
+
+ DeclOrigin (const DeclOrigin &rhs)
+ {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ void operator= (const DeclOrigin &rhs)
+ {
+ ctx = rhs.ctx;
+ decl = rhs.decl;
+ }
+
+ bool
+ Valid ()
+ {
+ return (ctx != NULL || decl != NULL);
+ }
+
+ clang::ASTContext *ctx;
+ clang::Decl *decl;
+ };
+
+ typedef std::map<const clang::Decl *, DeclOrigin> OriginMap;
+
+ class Minion : public clang::ASTImporter
+ {
+ public:
+ Minion (ClangASTImporter &master,
+ clang::ASTContext *target_ctx,
+ clang::ASTContext *source_ctx) :
+ clang::ASTImporter(*target_ctx,
+ master.m_file_manager,
+ *source_ctx,
+ master.m_file_manager,
+ true /*minimal*/),
+ m_decls_to_deport(NULL),
+ m_decls_already_deported(NULL),
+ m_master(master),
+ m_source_ctx(source_ctx)
+ {
+ }
+
+ // A call to "InitDeportWorkQueues" puts the minion into deport mode.
+ // In deport mode, every copied Decl that could require completion is
+ // recorded and placed into the decls_to_deport set.
+ //
+ // A call to "ExecuteDeportWorkQueues" completes all the Decls that
+ // are in decls_to_deport, adding any Decls it sees along the way that
+ // it hasn't already deported. It proceeds until decls_to_deport is
+ // empty.
+ //
+ // These calls must be paired. Leaving a minion in deport mode or
+ // trying to start deport minion with a new pair of queues will result
+ // in an assertion failure.
+
+ void InitDeportWorkQueues (std::set<clang::NamedDecl *> *decls_to_deport,
+ std::set<clang::NamedDecl *> *decls_already_deported);
+ void ExecuteDeportWorkQueues ();
+
+ void ImportDefinitionTo (clang::Decl *to, clang::Decl *from);
+
+ clang::Decl *Imported (clang::Decl *from, clang::Decl *to);
+
+ std::set<clang::NamedDecl *> *m_decls_to_deport;
+ std::set<clang::NamedDecl *> *m_decls_already_deported;
+ ClangASTImporter &m_master;
+ clang::ASTContext *m_source_ctx;
+ };
+
+ typedef std::shared_ptr<Minion> MinionSP;
+ typedef std::map<clang::ASTContext *, MinionSP> MinionMap;
+ typedef std::map<const clang::NamespaceDecl *, NamespaceMapSP> NamespaceMetaMap;
+
+ struct ASTContextMetadata
+ {
+ ASTContextMetadata(clang::ASTContext *dst_ctx) :
+ m_dst_ctx (dst_ctx),
+ m_minions (),
+ m_origins (),
+ m_namespace_maps (),
+ m_map_completer (NULL)
+ {
+ }
+
+ clang::ASTContext *m_dst_ctx;
+ MinionMap m_minions;
+ OriginMap m_origins;
+
+ NamespaceMetaMap m_namespace_maps;
+ MapCompleter *m_map_completer;
+ };
+
+ typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
+ typedef std::map<const clang::ASTContext *, ASTContextMetadataSP> ContextMetadataMap;
+
+ ContextMetadataMap m_metadata_map;
+
+ ASTContextMetadataSP
+ GetContextMetadata (clang::ASTContext *dst_ctx)
+ {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter == m_metadata_map.end())
+ {
+ ASTContextMetadataSP context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
+ m_metadata_map[dst_ctx] = context_md;
+ return context_md;
+ }
+ else
+ {
+ return context_md_iter->second;
+ }
+ }
+
+ ASTContextMetadataSP
+ MaybeGetContextMetadata (clang::ASTContext *dst_ctx)
+ {
+ ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
+
+ if (context_md_iter != m_metadata_map.end())
+ return context_md_iter->second;
+ else
+ return ASTContextMetadataSP();
+ }
+
+ MinionSP
+ GetMinion (clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx)
+ {
+ ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
+
+ MinionMap &minions = context_md->m_minions;
+ MinionMap::iterator minion_iter = minions.find(src_ctx);
+
+ if (minion_iter == minions.end())
+ {
+ MinionSP minion = MinionSP(new Minion(*this, dst_ctx, src_ctx));
+ minions[src_ctx] = minion;
+ return minion;
+ }
+ else
+ {
+ return minion_iter->second;
+ }
+ }
+
+ DeclOrigin
+ GetDeclOrigin (const clang::Decl *decl);
+
+ clang::FileManager m_file_manager;
+};
+
+}
+
+#endif
diff --git a/include/lldb/Symbol/ClangASTType.h b/include/lldb/Symbol/ClangASTType.h
new file mode 100644
index 000000000000..d9e754e8ceb9
--- /dev/null
+++ b/include/lldb/Symbol/ClangASTType.h
@@ -0,0 +1,679 @@
+//===-- ClangASTType.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_ClangASTType_h_
+#define liblldb_ClangASTType_h_
+
+#include <string>
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "clang/AST/Type.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A class that can carry around a clang ASTContext and a opaque clang
+// QualType. A clang::QualType can be easily reconstructed from an
+// opaque clang type and often the ASTContext is needed when doing
+// various type related tasks, so this class allows both items to travel
+// in a single very lightweight class that can be used. There are many
+// static equivalents of the member functions that allow the ASTContext
+// and the opaque clang QualType to be specified for ease of use and
+// to avoid code duplication.
+//----------------------------------------------------------------------
+class ClangASTType
+{
+public:
+ enum {
+ eTypeHasChildren = (1u << 0),
+ eTypeHasValue = (1u << 1),
+ eTypeIsArray = (1u << 2),
+ eTypeIsBlock = (1u << 3),
+ eTypeIsBuiltIn = (1u << 4),
+ eTypeIsClass = (1u << 5),
+ eTypeIsCPlusPlus = (1u << 6),
+ eTypeIsEnumeration = (1u << 7),
+ eTypeIsFuncPrototype = (1u << 8),
+ eTypeIsMember = (1u << 9),
+ eTypeIsObjC = (1u << 10),
+ eTypeIsPointer = (1u << 11),
+ eTypeIsReference = (1u << 12),
+ eTypeIsStructUnion = (1u << 13),
+ eTypeIsTemplate = (1u << 14),
+ eTypeIsTypedef = (1u << 15),
+ eTypeIsVector = (1u << 16),
+ eTypeIsScalar = (1u << 17),
+ eTypeIsInteger = (1u << 18),
+ eTypeIsFloat = (1u << 19),
+ eTypeIsComplex = (1u << 20),
+ eTypeIsSigned = (1u << 21)
+ };
+
+
+ //----------------------------------------------------------------------
+ // Constructors and Destructors
+ //----------------------------------------------------------------------
+ ClangASTType (clang::ASTContext *ast_context, lldb::clang_type_t type) :
+ m_type (type),
+ m_ast (ast_context)
+ {
+ }
+
+ ClangASTType (clang::ASTContext *ast_context, clang::QualType qual_type);
+
+ ClangASTType (const ClangASTType &rhs) :
+ m_type (rhs.m_type),
+ m_ast (rhs.m_ast)
+ {
+ }
+
+ ClangASTType () :
+ m_type (0),
+ m_ast (0)
+ {
+ }
+
+ ~ClangASTType();
+
+ //----------------------------------------------------------------------
+ // Operators
+ //----------------------------------------------------------------------
+
+ const ClangASTType &
+ operator= (const ClangASTType &rhs)
+ {
+ m_type = rhs.m_type;
+ m_ast = rhs.m_ast;
+ return *this;
+ }
+
+
+ //----------------------------------------------------------------------
+ // Tests
+ //----------------------------------------------------------------------
+
+ operator bool () const
+ {
+ return m_type != NULL && m_ast != NULL;
+ }
+
+ bool
+ operator < (const ClangASTType &rhs) const
+ {
+ if (m_ast == rhs.m_ast)
+ return m_type < rhs.m_type;
+ return m_ast < rhs.m_ast;
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_type != NULL && m_ast != NULL;
+ }
+
+ bool
+ IsArrayType (ClangASTType *element_type,
+ uint64_t *size,
+ bool *is_incomplete) const;
+
+ bool
+ IsArrayOfScalarType () const;
+
+ bool
+ IsAggregateType () const;
+
+ bool
+ IsBeingDefined () const;
+
+ bool
+ IsCharType () const;
+
+ bool
+ IsCompleteType () const;
+
+ bool
+ IsConst() const;
+
+ bool
+ IsCStringType (uint32_t &length) const;
+
+ bool
+ IsCXXClassType () const;
+
+ bool
+ IsDefined() const;
+
+ bool
+ IsFloatingPointType (uint32_t &count, bool &is_complex) const;
+
+ bool
+ IsFunctionType (bool *is_variadic_ptr = NULL) const;
+
+ bool
+ IsVariadicFunctionType () const;
+
+ bool
+ IsFunctionPointerType () const;
+
+ bool
+ IsIntegerType (bool &is_signed) const;
+
+ bool
+ IsObjCClassType () const;
+
+ bool
+ IsObjCClassTypeAndHasIVars (bool check_superclass) const;
+
+ bool
+ IsObjCObjectOrInterfaceType () const;
+
+ bool
+ IsObjCObjectPointerType (ClangASTType *target_type = NULL);
+
+ bool
+ IsPolymorphicClass () const;
+
+ bool
+ IsPossibleCPlusPlusDynamicType (ClangASTType *target_type = NULL) const
+ {
+ return IsPossibleDynamicType (target_type, true, false);
+ }
+
+ bool
+ IsPossibleDynamicType (ClangASTType *target_type, // Can pass NULL
+ bool check_cplusplus,
+ bool check_objc) const;
+
+
+ bool
+ IsPointerToScalarType () const;
+
+ bool
+ IsPointerType (ClangASTType *pointee_type = NULL) const;
+
+ bool
+ IsPointerOrReferenceType (ClangASTType *pointee_type = NULL) const;
+
+ bool
+ IsReferenceType (ClangASTType *pointee_type = NULL) const;
+
+ bool
+ IsScalarType () const;
+
+ bool
+ IsTypedefType () const;
+
+ bool
+ IsVoidType () const;
+
+ bool
+ GetCXXClassName (std::string &class_name) const;
+
+ bool
+ GetObjCClassName (std::string &class_name);
+
+
+ //----------------------------------------------------------------------
+ // Type Completion
+ //----------------------------------------------------------------------
+
+ bool
+ GetCompleteType () const;
+
+ //----------------------------------------------------------------------
+ // AST related queries
+ //----------------------------------------------------------------------
+
+ size_t
+ GetPointerByteSize () const;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+
+ clang::ASTContext *
+ GetASTContext() const
+ {
+ return m_ast;
+ }
+
+ ConstString
+ GetConstQualifiedTypeName () const;
+
+ ConstString
+ GetConstTypeName () const;
+
+ std::string
+ GetTypeName () const;
+
+ uint32_t
+ GetTypeInfo (ClangASTType *pointee_or_element_clang_type = NULL) const;
+
+ lldb::LanguageType
+ GetMinimumLanguage ();
+
+ lldb::clang_type_t
+ GetOpaqueQualType() const
+ {
+ return m_type;
+ }
+
+ lldb::TypeClass
+ GetTypeClass () const;
+
+ void
+ SetClangType (clang::ASTContext *ast, lldb::clang_type_t type)
+ {
+ m_ast = ast;
+ m_type = type;
+ }
+
+ void
+ SetClangType (clang::ASTContext *ast, clang::QualType qual_type);
+
+ unsigned
+ GetTypeQualifiers() const;
+
+ //----------------------------------------------------------------------
+ // Creating related types
+ //----------------------------------------------------------------------
+
+ ClangASTType
+ AddConstModifier () const;
+
+ ClangASTType
+ AddRestrictModifier () const;
+
+ ClangASTType
+ AddVolatileModifier () const;
+
+ // Using the current type, create a new typedef to that type using "typedef_name"
+ // as the name and "decl_ctx" as the decl context.
+ ClangASTType
+ CreateTypedefType (const char *typedef_name,
+ clang::DeclContext *decl_ctx) const;
+
+ ClangASTType
+ GetArrayElementType (uint64_t& stride) const;
+
+ ClangASTType
+ GetCanonicalType () const;
+
+ ClangASTType
+ GetFullyUnqualifiedType () const;
+
+ // Returns -1 if this isn't a function of if the fucntion doesn't have a prototype
+ // Returns a value >= 0 if there is a prototype.
+ int
+ GetFunctionArgumentCount () const;
+
+ ClangASTType
+ GetFunctionArgumentTypeAtIndex (size_t idx);
+
+ ClangASTType
+ GetFunctionReturnType () const;
+
+ ClangASTType
+ GetLValueReferenceType () const;
+
+ ClangASTType
+ GetNonReferenceType () const;
+
+ ClangASTType
+ GetPointeeType () const;
+
+ ClangASTType
+ GetPointerType () const;
+
+ ClangASTType
+ GetRValueReferenceType () const;
+
+ // If the current object represents a typedef type, get the underlying type
+ ClangASTType
+ GetTypedefedType () const;
+
+ ClangASTType
+ RemoveFastQualifiers () const;
+
+ //----------------------------------------------------------------------
+ // Create related types using the current type's AST
+ //----------------------------------------------------------------------
+ ClangASTType
+ GetBasicTypeFromAST (lldb::BasicType basic_type) const;
+
+ //----------------------------------------------------------------------
+ // Exploring the type
+ //----------------------------------------------------------------------
+
+ uint64_t
+ GetByteSize () const;
+
+ uint64_t
+ GetBitSize () const;
+
+ lldb::Encoding
+ GetEncoding (uint64_t &count) const;
+
+ lldb::Format
+ GetFormat () const;
+
+ size_t
+ GetTypeBitAlign () const;
+
+ uint32_t
+ GetNumChildren (bool omit_empty_base_classes) const;
+
+ lldb::BasicType
+ GetBasicTypeEnumeration () const;
+
+ static lldb::BasicType
+ GetBasicTypeEnumeration (const ConstString &name);
+
+ uint32_t
+ GetNumDirectBaseClasses () const;
+
+ uint32_t
+ GetNumVirtualBaseClasses () const;
+
+ uint32_t
+ GetNumFields () const;
+
+ ClangASTType
+ GetDirectBaseClassAtIndex (size_t idx,
+ uint32_t *bit_offset_ptr) const;
+
+ ClangASTType
+ GetVirtualBaseClassAtIndex (size_t idx,
+ uint32_t *bit_offset_ptr) const;
+
+ ClangASTType
+ GetFieldAtIndex (size_t idx,
+ std::string& name,
+ uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr) const;
+
+ uint32_t
+ GetIndexOfFieldWithName (const char* name,
+ ClangASTType* field_clang_type = NULL,
+ uint64_t *bit_offset_ptr = NULL,
+ uint32_t *bitfield_bit_size_ptr = NULL,
+ bool *is_bitfield_ptr = NULL) const;
+
+ uint32_t
+ GetNumPointeeChildren () const;
+
+ ClangASTType
+ GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
+ const char *parent_name,
+ size_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ bool ignore_array_bounds,
+ std::string& child_name,
+ uint32_t &child_byte_size,
+ int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size,
+ uint32_t &child_bitfield_bit_offset,
+ bool &child_is_base_class,
+ bool &child_is_deref_of_parent) const;
+
+ // Lookup a child given a name. This function will match base class names
+ // and member member names in "clang_type" only, not descendants.
+ uint32_t
+ GetIndexOfChildWithName (const char *name,
+ bool omit_empty_base_classes) const;
+
+ // Lookup a child member given a name. This function will match member names
+ // only and will descend into "clang_type" children in search for the first
+ // member in this class, or any base class that matches "name".
+ // TODO: Return all matches for a given name by returning a vector<vector<uint32_t>>
+ // so we catch all names that match a given child name, not just the first.
+ size_t
+ GetIndexOfChildMemberWithName (const char *name,
+ bool omit_empty_base_classes,
+ std::vector<uint32_t>& child_indexes) const;
+
+ size_t
+ GetNumTemplateArguments () const;
+
+ ClangASTType
+ GetTemplateArgument (size_t idx,
+ lldb::TemplateArgumentKind &kind) const;
+
+
+ //----------------------------------------------------------------------
+ // Modifying RecordType
+ //----------------------------------------------------------------------
+ clang::FieldDecl *
+ AddFieldToRecordType (const char *name,
+ const ClangASTType &field_type,
+ lldb::AccessType access,
+ uint32_t bitfield_bit_size);
+
+ void
+ BuildIndirectFields ();
+
+ clang::VarDecl *
+ AddVariableToRecordType (const char *name,
+ const ClangASTType &var_type,
+ lldb::AccessType access);
+
+ clang::CXXMethodDecl *
+ AddMethodToCXXRecordType (const char *name,
+ const ClangASTType &method_type,
+ lldb::AccessType access,
+ bool is_virtual,
+ bool is_static,
+ bool is_inline,
+ bool is_explicit,
+ bool is_attr_used,
+ bool is_artificial);
+
+ // C++ Base Classes
+ clang::CXXBaseSpecifier *
+ CreateBaseClassSpecifier (lldb::AccessType access,
+ bool is_virtual,
+ bool base_of_class);
+
+ static void
+ DeleteBaseClassSpecifiers (clang::CXXBaseSpecifier **base_classes,
+ unsigned num_base_classes);
+
+ bool
+ SetBaseClassesForClassType (clang::CXXBaseSpecifier const * const *base_classes,
+ unsigned num_base_classes);
+
+
+ bool
+ SetObjCSuperClass (const ClangASTType &superclass_clang_type);
+
+ bool
+ AddObjCClassProperty (const char *property_name,
+ const ClangASTType &property_clang_type,
+ clang::ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name,
+ const char *property_getter_name,
+ uint32_t property_attributes,
+ ClangASTMetadata *metadata);
+
+ clang::ObjCMethodDecl *
+ AddMethodToObjCObjectType (const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]")
+ const ClangASTType &method_clang_type,
+ lldb::AccessType access,
+ bool is_artificial);
+
+ clang::DeclContext *
+ GetDeclContextForType () const;
+
+
+ bool
+ SetDefaultAccessForRecordFields (int default_accessibility,
+ int *assigned_accessibilities,
+ size_t num_assigned_accessibilities);
+
+ bool
+ SetHasExternalStorage (bool has_extern);
+
+
+ //------------------------------------------------------------------
+ // clang::TagType
+ //------------------------------------------------------------------
+
+ bool
+ SetTagTypeKind (int kind) const;
+
+ //------------------------------------------------------------------
+ // Tag Declarations
+ //------------------------------------------------------------------
+ bool
+ StartTagDeclarationDefinition ();
+
+ bool
+ CompleteTagDeclarationDefinition ();
+
+ //----------------------------------------------------------------------
+ // Modifying Enumeration types
+ //----------------------------------------------------------------------
+ bool
+ AddEnumerationValueToEnumerationType (const ClangASTType &enumerator_qual_type,
+ const Declaration &decl,
+ const char *name,
+ int64_t enum_value,
+ uint32_t enum_value_bit_size);
+
+
+
+ ClangASTType
+ GetEnumerationIntegerType () const;
+
+
+ //------------------------------------------------------------------
+ // Pointers & References
+ //------------------------------------------------------------------
+
+ // Call this function using the class type when you want to make a
+ // member pointer type to pointee_type.
+ ClangASTType
+ CreateMemberPointerType (const ClangASTType &pointee_type) const;
+
+
+ // Converts "s" to a floating point value and place resulting floating
+ // point bytes in the "dst" buffer.
+ size_t
+ ConvertStringToFloatValue (const char *s,
+ uint8_t *dst,
+ size_t dst_size) const;
+ //----------------------------------------------------------------------
+ // Dumping types
+ //----------------------------------------------------------------------
+ void
+ DumpValue (ExecutionContext *exe_ctx,
+ Stream *s,
+ lldb::Format format,
+ const DataExtractor &data,
+ lldb::offset_t data_offset,
+ size_t data_byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool show_types,
+ bool show_summary,
+ bool verbose,
+ uint32_t depth);
+
+ bool
+ DumpTypeValue (Stream *s,
+ lldb::Format format,
+ const DataExtractor &data,
+ lldb::offset_t data_offset,
+ size_t data_byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ ExecutionContextScope *exe_scope);
+
+ void
+ DumpSummary (ExecutionContext *exe_ctx,
+ Stream *s,
+ const DataExtractor &data,
+ lldb::offset_t data_offset,
+ size_t data_byte_size);
+
+ void
+ DumpTypeDescription () const; // Dump to stdout
+
+ void
+ DumpTypeDescription (Stream *s) const;
+
+ bool
+ GetValueAsScalar (const DataExtractor &data,
+ lldb::offset_t data_offset,
+ size_t data_byte_size,
+ Scalar &value) const;
+
+ bool
+ SetValueFromScalar (const Scalar &value,
+ Stream &strm);
+
+ bool
+ ReadFromMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t addr,
+ AddressType address_type,
+ DataExtractor &data);
+
+ bool
+ WriteToMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t addr,
+ AddressType address_type,
+ StreamString &new_value);
+
+
+ clang::RecordDecl *
+ GetAsRecordDecl () const;
+
+ clang::CXXRecordDecl *
+ GetAsCXXRecordDecl () const;
+
+ clang::ObjCInterfaceDecl *
+ GetAsObjCInterfaceDecl () const;
+
+ void
+ Clear()
+ {
+ m_type = NULL;
+ m_ast = NULL;
+ }
+
+ clang::QualType
+ GetQualType () const
+ {
+ if (m_type)
+ return clang::QualType::getFromOpaquePtr(m_type);
+ return clang::QualType();
+ }
+ clang::QualType
+ GetCanonicalQualType () const
+ {
+ if (m_type)
+ return clang::QualType::getFromOpaquePtr(m_type).getCanonicalType();
+ return clang::QualType();
+ }
+
+private:
+ lldb::clang_type_t m_type;
+ clang::ASTContext *m_ast;
+
+};
+
+bool operator == (const ClangASTType &lhs, const ClangASTType &rhs);
+bool operator != (const ClangASTType &lhs, const ClangASTType &rhs);
+
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ClangASTType_h_
diff --git a/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h b/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h
new file mode 100644
index 000000000000..0c8121135ef0
--- /dev/null
+++ b/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h
@@ -0,0 +1,171 @@
+//===-- ClangExternalASTSourceCallbacks.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_ClangExternalASTSourceCallbacks_h_
+#define liblldb_ClangExternalASTSourceCallbacks_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+#include <stdint.h>
+
+// Other libraries and framework includes
+#include "clang/AST/CharUnits.h"
+
+// Project includes
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+
+namespace lldb_private {
+
+class ClangExternalASTSourceCallbacks : public ClangExternalASTSourceCommon
+{
+public:
+
+ typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *);
+ typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *);
+ typedef void (*FindExternalVisibleDeclsByNameCallback)(void *baton, const clang::DeclContext *DC, clang::DeclarationName Name, llvm::SmallVectorImpl <clang::NamedDecl *> *results);
+ typedef bool (*LayoutRecordTypeCallback)(void *baton,
+ const clang::RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
+
+ ClangExternalASTSourceCallbacks (CompleteTagDeclCallback tag_decl_callback,
+ CompleteObjCInterfaceDeclCallback objc_decl_callback,
+ FindExternalVisibleDeclsByNameCallback find_by_name_callback,
+ LayoutRecordTypeCallback layout_record_type_callback,
+ void *callback_baton) :
+ m_callback_tag_decl (tag_decl_callback),
+ m_callback_objc_decl (objc_decl_callback),
+ m_callback_find_by_name (find_by_name_callback),
+ m_callback_layout_record_type (layout_record_type_callback),
+ m_callback_baton (callback_baton)
+ {
+ }
+
+ //------------------------------------------------------------------
+ // clang::ExternalASTSource
+ //------------------------------------------------------------------
+
+ virtual clang::Decl *
+ GetExternalDecl (uint32_t ID)
+ {
+ // This method only needs to be implemented if the AST source ever
+ // passes back decl sets as VisibleDeclaration objects.
+ return 0;
+ }
+
+ virtual clang::Stmt *
+ GetExternalDeclStmt (uint64_t Offset)
+ {
+ // This operation is meant to be used via a LazyOffsetPtr. It only
+ // needs to be implemented if the AST source uses methods like
+ // FunctionDecl::setLazyBody when building decls.
+ return 0;
+ }
+
+ virtual clang::Selector
+ GetExternalSelector (uint32_t ID)
+ {
+ // This operation only needs to be implemented if the AST source
+ // returns non-zero for GetNumKnownSelectors().
+ return clang::Selector();
+ }
+
+ virtual uint32_t
+ GetNumExternalSelectors()
+ {
+ return 0;
+ }
+
+ virtual clang::CXXBaseSpecifier *
+ GetExternalCXXBaseSpecifiers(uint64_t Offset)
+ {
+ return NULL;
+ }
+
+ virtual void
+ MaterializeVisibleDecls (const clang::DeclContext *decl_ctx)
+ {
+ return;
+ }
+
+ virtual clang::ExternalLoadResult
+ FindExternalLexicalDecls (const clang::DeclContext *decl_ctx,
+ bool (*isKindWeWant)(clang::Decl::Kind),
+ llvm::SmallVectorImpl<clang::Decl*> &decls)
+ {
+ // This is used to support iterating through an entire lexical context,
+ // which isn't something the debugger should ever need to do.
+ return clang::ELR_Failure;
+ }
+
+ virtual bool
+ FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx,
+ clang::DeclarationName decl_name);
+
+ virtual void
+ CompleteType (clang::TagDecl *tag_decl);
+
+ virtual void
+ CompleteType (clang::ObjCInterfaceDecl *objc_decl);
+
+ bool
+ layoutRecordType(const clang::RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets);
+ void
+ SetExternalSourceCallbacks (CompleteTagDeclCallback tag_decl_callback,
+ CompleteObjCInterfaceDeclCallback objc_decl_callback,
+ FindExternalVisibleDeclsByNameCallback find_by_name_callback,
+ LayoutRecordTypeCallback layout_record_type_callback,
+ void *callback_baton)
+ {
+ m_callback_tag_decl = tag_decl_callback;
+ m_callback_objc_decl = objc_decl_callback;
+ m_callback_find_by_name = find_by_name_callback;
+ m_callback_layout_record_type = layout_record_type_callback;
+ m_callback_baton = callback_baton;
+ }
+
+ void
+ RemoveExternalSourceCallbacks (void *callback_baton)
+ {
+ if (callback_baton == m_callback_baton)
+ {
+ m_callback_tag_decl = NULL;
+ m_callback_objc_decl = NULL;
+ m_callback_find_by_name = NULL;
+ m_callback_layout_record_type = NULL;
+ }
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ClangExternalASTSourceCallbacks can see and modify these
+ //------------------------------------------------------------------
+ CompleteTagDeclCallback m_callback_tag_decl;
+ CompleteObjCInterfaceDeclCallback m_callback_objc_decl;
+ FindExternalVisibleDeclsByNameCallback m_callback_find_by_name;
+ LayoutRecordTypeCallback m_callback_layout_record_type;
+ void * m_callback_baton;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ClangExternalASTSourceCallbacks_h_
diff --git a/include/lldb/Symbol/ClangExternalASTSourceCommon.h b/include/lldb/Symbol/ClangExternalASTSourceCommon.h
new file mode 100644
index 000000000000..72d77e74ca90
--- /dev/null
+++ b/include/lldb/Symbol/ClangExternalASTSourceCommon.h
@@ -0,0 +1,188 @@
+//===-- ClangExternalASTSourceCommon.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_ClangExternalASTSourceCommon_h
+#define liblldb_ClangExternalASTSourceCommon_h
+
+// Clang headers like to use NDEBUG inside of them to enable/disable debug
+// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// or another. This is bad because it means that if clang was built in release
+// mode, it assumes that you are building in release mode which is not always
+// the case. You can end up with functions that are defined as empty in header
+// files when NDEBUG is not defined, and this can cause link errors with the
+// clang .a files that you have since you might be missing functions in the .a
+// file. So we have to define NDEBUG when including clang headers to avoid any
+// mismatches. This is covered by rdar://problem/8691220
+
+#if !defined(NDEBUG) && !defined(LLVM_NDEBUG_OFF)
+#define LLDB_DEFINED_NDEBUG_FOR_CLANG
+#define NDEBUG
+// Need to include assert.h so it is as clang would expect it to be (disabled)
+#include <assert.h>
+#endif
+
+#include "clang/AST/ExternalASTSource.h"
+
+#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG
+#undef NDEBUG
+#undef LLDB_DEFINED_NDEBUG_FOR_CLANG
+// Need to re-include assert.h so it is as _we_ would expect it to be (enabled)
+#include <assert.h>
+#endif
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/dwarf.h"
+
+namespace lldb_private {
+
+class ClangASTMetadata
+{
+public:
+ ClangASTMetadata () :
+ m_user_id(0),
+ m_union_is_user_id(false),
+ m_union_is_isa_ptr(false),
+ m_has_object_ptr(false),
+ m_is_self (false),
+ m_is_dynamic_cxx (true)
+ {
+ }
+
+ bool
+ GetIsDynamicCXXType () const
+ {
+ return m_is_dynamic_cxx;
+ }
+
+ void
+ SetIsDynamicCXXType (bool b)
+ {
+ m_is_dynamic_cxx = b;
+ }
+
+ void
+ SetUserID (lldb::user_id_t user_id)
+ {
+ m_user_id = user_id;
+ m_union_is_user_id = true;
+ m_union_is_isa_ptr = false;
+ }
+
+ lldb::user_id_t
+ GetUserID () const
+ {
+ if (m_union_is_user_id)
+ return m_user_id;
+ else
+ return LLDB_INVALID_UID;
+ }
+
+ void
+ SetISAPtr (uint64_t isa_ptr)
+ {
+ m_isa_ptr = isa_ptr;
+ m_union_is_user_id = false;
+ m_union_is_isa_ptr = true;
+ }
+
+ uint64_t
+ GetISAPtr () const
+ {
+ if (m_union_is_isa_ptr)
+ return m_isa_ptr;
+ else
+ return 0;
+ }
+
+ void
+ SetObjectPtrName(const char *name)
+ {
+ m_has_object_ptr = true;
+ if (strcmp (name, "self") == 0)
+ m_is_self = true;
+ else if (strcmp (name, "this") == 0)
+ m_is_self = false;
+ else
+ m_has_object_ptr = false;
+ }
+
+ lldb::LanguageType
+ GetObjectPtrLanguage () const
+ {
+ if (m_has_object_ptr)
+ {
+ if (m_is_self)
+ return lldb::eLanguageTypeObjC;
+ else
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+ return lldb::eLanguageTypeUnknown;
+
+ }
+ const char *
+ GetObjectPtrName() const
+ {
+ if (m_has_object_ptr)
+ {
+ if (m_is_self)
+ return "self";
+ else
+ return "this";
+ }
+ else
+ return NULL;
+ }
+
+ bool
+ HasObjectPtr() const
+ {
+ return m_has_object_ptr;
+ }
+
+ void
+ Dump (Stream *s);
+
+private:
+ union
+ {
+ lldb::user_id_t m_user_id;
+ uint64_t m_isa_ptr;
+ };
+ bool m_union_is_user_id : 1,
+ m_union_is_isa_ptr : 1,
+ m_has_object_ptr : 1,
+ m_is_self : 1,
+ m_is_dynamic_cxx : 1;
+
+};
+
+class ClangExternalASTSourceCommon : public clang::ExternalASTSource
+{
+public:
+ ClangExternalASTSourceCommon();
+ ~ClangExternalASTSourceCommon();
+
+ virtual ClangASTMetadata *GetMetadata(const void *object);
+ virtual void SetMetadata(const void *object, ClangASTMetadata &metadata);
+ virtual bool HasMetadata(const void *object);
+private:
+ typedef llvm::DenseMap<const void *, ClangASTMetadata> MetadataMap;
+
+ MetadataMap m_metadata;
+ uint64_t m_magic; ///< Because we don't have RTTI, we must take it
+ ///< on faith that any valid ExternalASTSource that
+ ///< we try to use the *Metadata APIs on inherits
+ ///< from ClangExternalASTSourceCommon. This magic
+ ///< number exists to enforce that.
+};
+
+}
+
+#endif
diff --git a/include/lldb/Symbol/ClangNamespaceDecl.h b/include/lldb/Symbol/ClangNamespaceDecl.h
new file mode 100644
index 000000000000..d10ab2a29665
--- /dev/null
+++ b/include/lldb/Symbol/ClangNamespaceDecl.h
@@ -0,0 +1,103 @@
+//===-- ClangNamespaceDecl.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_ClangNamespaceDecl_h_
+#define liblldb_ClangNamespaceDecl_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ClangForward.h"
+
+namespace lldb_private {
+
+class ClangNamespaceDecl
+{
+public:
+ ClangNamespaceDecl () :
+ m_ast (NULL),
+ m_namespace_decl (NULL)
+ {
+ }
+
+ ClangNamespaceDecl (clang::ASTContext *ast, clang::NamespaceDecl *namespace_decl) :
+ m_ast (ast),
+ m_namespace_decl (namespace_decl)
+ {
+ }
+
+ ClangNamespaceDecl (const ClangNamespaceDecl &rhs) :
+ m_ast (rhs.m_ast),
+ m_namespace_decl (rhs.m_namespace_decl)
+ {
+ }
+
+ const ClangNamespaceDecl &
+ operator = (const ClangNamespaceDecl &rhs)
+ {
+ m_ast = rhs.m_ast;
+ m_namespace_decl = rhs.m_namespace_decl;
+ return *this;
+ }
+
+ //------------------------------------------------------------------
+ /// Convert to bool operator.
+ ///
+ /// This allows code to check a ClangNamespaceDecl object to see if
+ /// it contains a valid namespace decl using code such as:
+ ///
+ /// @code
+ /// ClangNamespaceDecl ns_decl(...);
+ /// if (ns_decl)
+ /// { ...
+ /// @endcode
+ ///
+ /// @return
+ /// /b True this object contains a valid namespace decl, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ operator bool() const
+ {
+ return m_ast != NULL && m_namespace_decl != NULL;
+ }
+
+ clang::ASTContext *
+ GetASTContext() const
+ {
+ return m_ast;
+ }
+
+ void
+ SetASTContext (clang::ASTContext *ast)
+ {
+ m_ast = ast;
+ }
+
+ clang::NamespaceDecl *
+ GetNamespaceDecl () const
+ {
+ return m_namespace_decl;
+ }
+
+ void
+ SetNamespaceDecl (clang::NamespaceDecl *namespace_decl)
+ {
+ m_namespace_decl = namespace_decl;
+ }
+
+ std::string
+ GetQualifiedName () const;
+
+protected:
+ clang::ASTContext *m_ast;
+ clang::NamespaceDecl *m_namespace_decl;
+};
+
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_ClangNamespaceDecl_h_
diff --git a/include/lldb/Symbol/CompileUnit.h b/include/lldb/Symbol/CompileUnit.h
new file mode 100644
index 000000000000..5de93670c5a7
--- /dev/null
+++ b/include/lldb/Symbol/CompileUnit.h
@@ -0,0 +1,422 @@
+//===-- CompileUnit.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_CompUnit_h_
+#define liblldb_CompUnit_h_
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/UserID.h"
+
+namespace lldb_private {
+//----------------------------------------------------------------------
+/// @class CompileUnit CompileUnit.h "lldb/Symbol/CompileUnit.h"
+/// @brief A class that describes a compilation unit.
+///
+/// A representation of a compilation unit, or compiled source file.
+/// The UserID of the compile unit is specified by the SymbolFile
+/// plug-in and can have any value as long as the value is unique
+/// within the Module that owns this compile units.
+///
+/// Each compile unit has a list of functions, global and static
+/// variables, support file list (include files and inlined source
+/// files), and a line table.
+//----------------------------------------------------------------------
+class CompileUnit :
+ public std::enable_shared_from_this<CompileUnit>,
+ public ModuleChild,
+ public FileSpec,
+ public UserID,
+ public SymbolContextScope
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with a module, path, UID and language.
+ ///
+ /// Initialize the compile unit given the owning \a module, a path
+ /// to convert into a FileSpec, the SymbolFile plug-in supplied
+ /// \a uid, and the source language type.
+ ///
+ /// @param[in] module
+ /// The parent module that owns this compile unit. This value
+ /// must be a valid pointer value.
+ ///
+ /// @param[in] user_data
+ /// User data where the SymbolFile parser can store data.
+ ///
+ /// @param[in] pathname
+ /// The path to the source file for this compile unit.
+ ///
+ /// @param[in] uid
+ /// The user ID of the compile unit. This value is supplied by
+ /// the SymbolFile plug-in and should be a value that allows
+ /// the SymbolFile plug-in to easily locate and parse additional
+ /// information for the compile unit.
+ ///
+ /// @param[in] language
+ /// A language enumeration type that describes the main language
+ /// of this compile unit.
+ ///
+ /// @see lldb::LanguageType
+ //------------------------------------------------------------------
+ CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, lldb::user_id_t uid, lldb::LanguageType language);
+
+ //------------------------------------------------------------------
+ /// Construct with a module, file spec, UID and language.
+ ///
+ /// Initialize the compile unit given the owning \a module, a path
+ /// to convert into a FileSpec, the SymbolFile plug-in supplied
+ /// \a uid, and the source language type.
+ ///
+ /// @param[in] module
+ /// The parent module that owns this compile unit. This value
+ /// must be a valid pointer value.
+ ///
+ /// @param[in] user_data
+ /// User data where the SymbolFile parser can store data.
+ ///
+ /// @param[in] file_spec
+ /// The file specification for the source file of this compile
+ /// unit.
+ ///
+ /// @param[in] uid
+ /// The user ID of the compile unit. This value is supplied by
+ /// the SymbolFile plug-in and should be a value that allows
+ /// the plug-in to easily locate and parse
+ /// additional information for the compile unit.
+ ///
+ /// @param[in] language
+ /// A language enumeration type that describes the main language
+ /// of this compile unit.
+ ///
+ /// @see lldb::LanguageType
+ //------------------------------------------------------------------
+ CompileUnit(const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &file_spec, lldb::user_id_t uid, lldb::LanguageType language);
+
+ //------------------------------------------------------------------
+ /// Destructor
+ //------------------------------------------------------------------
+ virtual
+ ~CompileUnit();
+
+ //------------------------------------------------------------------
+ /// Add a function to this compile unit.
+ ///
+ /// Typically called by the SymbolFile plug-ins as they partially
+ /// parse the debug information.
+ ///
+ /// @param[in] function_sp
+ /// A shared pointer to the a Function object.
+ //------------------------------------------------------------------
+ void
+ AddFunction(lldb::FunctionSP& function_sp);
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext(SymbolContext* sc);
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ();
+
+ virtual CompileUnit *
+ CalculateSymbolContextCompileUnit ();
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext(Stream *s);
+
+ lldb::LanguageType
+ GetLanguage();
+
+ void
+ SetLanguage(lldb::LanguageType language)
+ {
+ m_flags.Set(flagsParsedLanguage);
+ m_language = language;
+ }
+
+ void
+ GetDescription(Stream *s, lldb::DescriptionLevel level) const;
+
+ //------------------------------------------------------------------
+ /// Get a shared pointer to a function in this compile unit by
+ /// index.
+ ///
+ /// Typically called when iterating though all functions in a
+ /// compile unit after all functions have been parsed. This provides
+ /// raw access to the function shared pointer list and will not
+ /// cause the SymbolFile plug-in to parse any unparsed functions.
+ ///
+ /// @param[in] idx
+ /// An index into the function list.
+ ///
+ /// @return
+ /// A shared pointer to a function that might contain a NULL
+ /// Function class pointer.
+ //------------------------------------------------------------------
+ lldb::FunctionSP
+ GetFunctionAtIndex (size_t idx);
+
+ //------------------------------------------------------------------
+ /// Dump the compile unit contents to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] show_context
+ /// If \b true, variables will dump their symbol context
+ /// information.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, bool show_context) const;
+
+ //------------------------------------------------------------------
+ /// Find the line entry by line and optional inlined file spec.
+ ///
+ /// Finds the first line entry that has an index greater than
+ /// \a start_idx that matches \a line. If \a file_spec_ptr
+ /// is NULL, then the search matches line entries whose file matches
+ /// the file for the compile unit. If \a file_spec_ptr is
+ /// not NULL, line entries must match the specified file spec (for
+ /// inlined line table entries).
+ ///
+ /// Multiple calls to this function can find all entries that match
+ /// a given file and line by starting with \a start_idx equal to zero,
+ /// and calling this function back with the return valeu + 1.
+ ///
+ /// @param[in] start_idx
+ /// The zero based index at which to start looking for matches.
+ ///
+ /// @param[in] line
+ /// The line number to search for.
+ ///
+ /// @param[in] file_spec_ptr
+ /// If non-NULL search for entries that match this file spec,
+ /// else if NULL, search for line entries that match the compile
+ /// unit file.
+ ///
+ /// @param[in] exact
+ /// If \btrue match only if there is a line table entry for this line number.
+ /// If \bfalse, find the line table entry equal to or after this line number.
+ ///
+ /// @param[out] line_entry
+ /// If non-NULL, a copy of the line entry that was found.
+ ///
+ /// @return
+ /// The zero based index of a matching line entry, or UINT32_MAX
+ /// if no matching line entry is found.
+ //------------------------------------------------------------------
+ uint32_t
+ FindLineEntry (uint32_t start_idx,
+ uint32_t line,
+ const FileSpec* file_spec_ptr,
+ bool exact,
+ LineEntry *line_entry);
+
+ //------------------------------------------------------------------
+ /// Get the line table for the compile unit.
+ ///
+ /// Called by clients and the SymbolFile plug-in. The SymbolFile
+ /// plug-ins use this function to determine if the line table has
+ /// be parsed yet. Clients use this function to get the line table
+ /// from a compile unit.
+ ///
+ /// @return
+ /// The line table object pointer, or NULL if this line table
+ /// hasn't been parsed yet.
+ //------------------------------------------------------------------
+ LineTable*
+ GetLineTable ();
+
+ //------------------------------------------------------------------
+ /// Get the compile unit's support file list.
+ ///
+ /// The support file list is used by the line table, and any objects
+ /// that have valid Declaration objects.
+ ///
+ /// @return
+ /// A support file list object.
+ //------------------------------------------------------------------
+ FileSpecList&
+ GetSupportFiles ();
+
+ //------------------------------------------------------------------
+ /// Get the SymbolFile plug-in user data.
+ ///
+ /// SymbolFile plug-ins can store user data to internal state or
+ /// objects to quickly allow them to parse more information for a
+ /// given object.
+ ///
+ /// @return
+ /// The user data stored with the CompileUnit when it was
+ /// constructed.
+ //------------------------------------------------------------------
+ void *
+ GetUserData () const;
+
+ //------------------------------------------------------------------
+ /// Get the variable list for a compile unit.
+ ///
+ /// Called by clients to get the variable list for a compile unit.
+ /// The variable list will contain all global and static variables
+ /// that were defined at the compile unit level.
+ ///
+ /// @param[in] can_create
+ /// If \b true, the variable list will be parsed on demand. If
+ /// \b false, the current variable list will be returned even
+ /// if it contains a NULL VariableList object (typically
+ /// called by dumping routines that want to display only what
+ /// has currently been parsed).
+ ///
+ /// @return
+ /// A shared pointer to a variable list, that can contain NULL
+ /// VariableList pointer if there are no global or static
+ /// variables.
+ //------------------------------------------------------------------
+ lldb::VariableListSP
+ GetVariableList (bool can_create);
+
+ //------------------------------------------------------------------
+ /// Finds a function by user ID.
+ ///
+ /// Typically used by SymbolFile plug-ins when partially parsing
+ /// the debug information to see if the function has been parsed
+ /// yet.
+ ///
+ /// @param[in] uid
+ /// The user ID of the function to find. This value is supplied
+ /// by the SymbolFile plug-in and should be a value that
+ /// allows the plug-in to easily locate and parse additional
+ /// information in the function.
+ ///
+ /// @return
+ /// A shared pointer to the function object that might contain
+ /// a NULL Function pointer.
+ //------------------------------------------------------------------
+ lldb::FunctionSP
+ FindFunctionByUID (lldb::user_id_t uid);
+
+ //------------------------------------------------------------------
+ /// Set the line table for the compile unit.
+ ///
+ /// Called by the SymbolFile plug-in when if first parses the line
+ /// table and hands ownership of the line table to this object. The
+ /// compile unit owns the line table object and will delete the
+ /// object when it is deleted.
+ ///
+ /// @param[in] line_table
+ /// A line table object pointer that this object now owns.
+ //------------------------------------------------------------------
+ void
+ SetLineTable(LineTable* line_table);
+
+ //------------------------------------------------------------------
+ /// Set accessor for the variable list.
+ ///
+ /// Called by the SymbolFile plug-ins after they have parsed the
+ /// variable lists and are ready to hand ownership of the list over
+ /// to this object.
+ ///
+ /// @param[in] variable_list_sp
+ /// A shared pointer to a VariableList.
+ //------------------------------------------------------------------
+ void
+ SetVariableList (lldb::VariableListSP& variable_list_sp);
+
+ //------------------------------------------------------------------
+ /// Resolve symbol contexts by file and line.
+ ///
+ /// Given a file in \a file_spec, and a line number, find all
+ /// instances and append them to the supplied symbol context list
+ /// \a sc_list.
+ ///
+ /// @param[in] file_spec
+ /// A file specification. If \a file_spec contains no directory
+ /// information, only the basename will be used when matching
+ /// contexts. If the directory in \a file_spec is valid, a
+ /// complete file specification match will be performed.
+ ///
+ /// @param[in] line
+ /// The line number to match against the compile unit's line
+ /// tables.
+ ///
+ /// @param[in] check_inlines
+ /// If \b true this function will also match any inline
+ /// file and line matches. If \b false, the compile unit's
+ /// file specification must match \a file_spec for any matches
+ /// to be returned.
+ ///
+ /// @param[in] exact
+ /// If true, only resolve the context if \a line exists in the line table.
+ /// If false, resolve the context to the closest line greater than \a line
+ /// in the line table.
+ ///
+ /// @param[in] resolve_scope
+ /// For each matching line entry, this bitfield indicates what
+ /// values within each SymbolContext that gets added to \a
+ /// sc_list will be resolved. See the SymbolContext::Scope
+ /// enumeration for a list of all available bits that can be
+ /// resolved. Only SymbolContext entries that can be resolved
+ /// using a LineEntry base address will be able to be resolved.
+ ///
+ /// @param[out] sc_list
+ /// A SymbolContext list class that willl get any matching
+ /// entries appended to.
+ ///
+ /// @return
+ /// The number of new matches that were added to \a sc_list.
+ ///
+ /// @see enum SymbolContext::Scope
+ //------------------------------------------------------------------
+ uint32_t
+ ResolveSymbolContext (const FileSpec& file_spec,
+ uint32_t line,
+ bool check_inlines,
+ bool exact,
+ uint32_t resolve_scope,
+ SymbolContextList &sc_list);
+
+
+protected:
+ void *m_user_data; ///< User data for the SymbolFile parser to store information into.
+ lldb::LanguageType m_language; ///< The programming language enumeration value.
+ Flags m_flags; ///< Compile unit flags that help with partial parsing.
+ std::vector<lldb::FunctionSP> m_functions; ///< The sparsely populated list of shared pointers to functions
+ ///< that gets populated as functions get partially parsed.
+ FileSpecList m_support_files; ///< Files associated with this compile unit's line table and declarations.
+ std::unique_ptr<LineTable> m_line_table_ap; ///< Line table that will get parsed on demand.
+ lldb::VariableListSP m_variables; ///< Global and static variable list that will get parsed on demand.
+
+private:
+ enum
+ {
+ flagsParsedAllFunctions = (1u << 0), ///< Have we already parsed all our functions
+ flagsParsedVariables = (1u << 1), ///< Have we already parsed globals and statics?
+ flagsParsedSupportFiles = (1u << 2), ///< Have we already parsed the support files for this compile unit?
+ flagsParsedLineTable = (1u << 3), ///< Have we parsed the line table already?
+ flagsParsedLanguage = (1u << 4) ///< Have we parsed the line table already?
+ };
+
+ DISALLOW_COPY_AND_ASSIGN (CompileUnit);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CompUnit_h_
diff --git a/include/lldb/Symbol/DWARFCallFrameInfo.h b/include/lldb/Symbol/DWARFCallFrameInfo.h
new file mode 100644
index 000000000000..13a14f8c4041
--- /dev/null
+++ b/include/lldb/Symbol/DWARFCallFrameInfo.h
@@ -0,0 +1,150 @@
+//===-- DWARFCallFrameInfo.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_DWARFCallFrameInfo_h_
+#define liblldb_DWARFCallFrameInfo_h_
+
+#include <map>
+
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/VMRange.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+// DWARFCallFrameInfo is a class which can read eh_frame and DWARF
+// Call Frame Information FDEs. It stores little information internally.
+// Only two APIs are exported - one to find the high/low pc values
+// of a function given a text address via the information in the
+// eh_frame / debug_frame, and one to generate an UnwindPlan based
+// on the FDE in the eh_frame / debug_frame section.
+
+class DWARFCallFrameInfo
+{
+public:
+
+ DWARFCallFrameInfo (ObjectFile& objfile,
+ lldb::SectionSP& section,
+ lldb::RegisterKind reg_kind,
+ bool is_eh_frame);
+
+ ~DWARFCallFrameInfo();
+
+ // Locate an AddressRange that includes the provided Address in this
+ // object's eh_frame/debug_info
+ // Returns true if a range is found to cover that address.
+ bool
+ GetAddressRange (Address addr, AddressRange &range);
+
+ // Return an UnwindPlan based on the call frame information encoded
+ // in the FDE of this DWARFCallFrameInfo section.
+ bool
+ GetUnwindPlan (Address addr, UnwindPlan& unwind_plan);
+
+ typedef RangeVector<lldb::addr_t, uint32_t> FunctionAddressAndSizeVector;
+
+ //------------------------------------------------------------------
+ // Build a vector of file address and size for all functions in this Module
+ // based on the eh_frame FDE entries.
+ //
+ // The eh_frame information can be a useful source of file address and size of
+ // the functions in a Module. Often a binary's non-exported symbols are stripped
+ // before shipping so lldb won't know the start addr / size of many functions
+ // in the Module. But the eh_frame can help to give the addresses of these
+ // stripped symbols, at least.
+ //
+ // @param[out] function_info
+ // A vector provided by the caller is filled out. May be empty if no FDEs/no eh_frame
+ // is present in this Module.
+
+ void
+ GetFunctionAddressAndSizeVector (FunctionAddressAndSizeVector &function_info);
+
+private:
+ enum
+ {
+ CFI_AUG_MAX_SIZE = 8,
+ CFI_HEADER_SIZE = 8
+ };
+
+ struct CIE
+ {
+ dw_offset_t cie_offset;
+ uint8_t version;
+ char augmentation[CFI_AUG_MAX_SIZE]; // This is typically empty or very short.
+ uint32_t code_align;
+ int32_t data_align;
+ uint32_t return_addr_reg_num;
+ dw_offset_t inst_offset; // offset of CIE instructions in mCFIData
+ uint32_t inst_length; // length of CIE instructions in mCFIData
+ uint8_t ptr_encoding;
+ lldb_private::UnwindPlan::Row initial_row;
+
+ CIE(dw_offset_t offset) : cie_offset(offset), version (-1), code_align (0),
+ data_align (0), return_addr_reg_num (LLDB_INVALID_REGNUM), inst_offset (0),
+ inst_length (0), ptr_encoding (0), initial_row() {}
+ };
+
+ typedef std::shared_ptr<CIE> CIESP;
+
+ typedef std::map<off_t, CIESP> cie_map_t;
+
+ // Start address (file address), size, offset of FDE location
+ // used for finding an FDE for a given File address; the start address field is
+ // an offset into an individual Module.
+ typedef RangeDataVector<lldb::addr_t, uint32_t, dw_offset_t> FDEEntryMap;
+
+ bool
+ IsEHFrame() const;
+
+ bool
+ GetFDEEntryByFileAddress (lldb::addr_t file_offset, FDEEntryMap::Entry& fde_entry);
+
+ void
+ GetFDEIndex ();
+
+ bool
+ FDEToUnwindPlan (uint32_t offset, Address startaddr, UnwindPlan& unwind_plan);
+
+ const CIE*
+ GetCIE(dw_offset_t cie_offset);
+
+ void
+ GetCFIData();
+
+ ObjectFile& m_objfile;
+ lldb::SectionSP m_section_sp;
+ lldb::RegisterKind m_reg_kind;
+ Flags m_flags;
+ cie_map_t m_cie_map;
+
+ DataExtractor m_cfi_data;
+ bool m_cfi_data_initialized; // only copy the section into the DE once
+
+ FDEEntryMap m_fde_index;
+ bool m_fde_index_initialized; // only scan the section for FDEs once
+ Mutex m_fde_index_mutex; // and isolate the thread that does it
+
+ bool m_is_eh_frame;
+
+ CIESP
+ ParseCIE (const uint32_t cie_offset);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DWARFCallFrameInfo_h_
diff --git a/include/lldb/Symbol/Declaration.h b/include/lldb/Symbol/Declaration.h
new file mode 100644
index 000000000000..f014571595f0
--- /dev/null
+++ b/include/lldb/Symbol/Declaration.h
@@ -0,0 +1,278 @@
+//===-- Declaration.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_Declaration_h_
+#define liblldb_Declaration_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class Declaration Declaration.h "lldb/Symbol/Declaration.h"
+/// @brief A class that describes the declaration location of a
+/// lldb object.
+///
+/// The declarations include the file specification, line number, and
+/// the column info and can help track where functions, blocks, inlined
+/// functions, types, variables, any many other debug core objects were
+/// declared.
+//----------------------------------------------------------------------
+class Declaration
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ //------------------------------------------------------------------
+ Declaration () :
+ m_file (),
+ m_line (0)
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ ,m_column (0)
+#endif
+ {
+ }
+
+
+ //------------------------------------------------------------------
+ /// Construct with file specification, and optional line and column.
+ ///
+ /// @param[in] file_spec
+ /// The file specification that describes where this was
+ /// declared.
+ ///
+ /// @param[in] line
+ /// The line number that describes where this was declared. Set
+ /// to zero if there is no line number information.
+ ///
+ /// @param[in] column
+ /// The column number that describes where this was declared.
+ /// Set to zero if there is no column number information.
+ //------------------------------------------------------------------
+ Declaration (const FileSpec& file_spec, uint32_t line = 0, uint32_t column = 0) :
+ m_file (file_spec),
+ m_line (line)
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ ,m_column (column)
+#endif
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Construct with a reference to another Declaration object.
+ //------------------------------------------------------------------
+ Declaration (const Declaration& rhs) :
+ m_file (rhs.m_file),
+ m_line (rhs.m_line)
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ ,m_column (rhs.m_column)
+#endif
+ {
+
+ }
+
+ //------------------------------------------------------------------
+ /// Construct with a pointer to another Declaration object.
+ //------------------------------------------------------------------
+ Declaration(const Declaration* decl_ptr) :
+ m_file(),
+ m_line(0)
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ ,m_column(0)
+#endif
+ {
+ if (decl_ptr)
+ *this = *decl_ptr;
+ }
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the file specification to be empty, and the line and column
+ /// to zero.
+ //------------------------------------------------------------------
+ void
+ Clear ()
+ {
+ m_file.Clear();
+ m_line= 0;
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ m_column = 0;
+#endif
+ }
+
+ //------------------------------------------------------------------
+ /// Compare two declaration objects.
+ ///
+ /// Compares the two file specifications from \a lhs and \a rhs. If
+ /// the file specifications are equal, then continue to compare the
+ /// line number and column numbers respectively.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const Declaration object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const Declaration object reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ static int
+ Compare (const Declaration& lhs, const Declaration& rhs);
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, bool show_fullpaths) const;
+
+ bool
+ DumpStopContext (Stream *s, bool show_fullpaths) const;
+ //------------------------------------------------------------------
+ /// Get accessor for the declaration column number.
+ ///
+ /// @return
+ /// Non-zero indicates a valid column number, zero indicates no
+ /// column information is available.
+ //------------------------------------------------------------------
+ uint32_t
+ GetColumn () const
+ {
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ return m_column;
+#else
+ return 0;
+#endif
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor for file specification.
+ ///
+ /// @return
+ /// A reference to the file specification object.
+ //------------------------------------------------------------------
+ FileSpec&
+ GetFile ()
+ {
+ return m_file;
+ }
+
+ //------------------------------------------------------------------
+ /// Get const accessor for file specification.
+ ///
+ /// @return
+ /// A const reference to the file specification object.
+ //------------------------------------------------------------------
+ const FileSpec&
+ GetFile () const
+ {
+ return m_file;
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the declaration line number.
+ ///
+ /// @return
+ /// Non-zero indicates a valid line number, zero indicates no
+ /// line information is available.
+ //------------------------------------------------------------------
+ uint32_t
+ GetLine () const
+ {
+ return m_line;
+ }
+
+
+ bool
+ IsValid() const
+ {
+ return m_file && m_line != 0;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ /// The returned value does not include the bytes for any
+ /// shared string values.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+ //------------------------------------------------------------------
+ /// Set accessor for the declaration column number.
+ ///
+ /// @param[in] column
+ /// Non-zero indicates a valid column number, zero indicates no
+ /// column information is available.
+ //------------------------------------------------------------------
+ void
+ SetColumn (uint32_t column)
+ {
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ m_column = col;
+#endif
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the declaration file specification.
+ ///
+ /// @param[in] file_spec
+ /// The new declaration file specifciation.
+ //------------------------------------------------------------------
+ void
+ SetFile (const FileSpec& file_spec)
+ {
+ m_file = file_spec;
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the declaration line number.
+ ///
+ /// @param[in] line
+ /// Non-zero indicates a valid line number, zero indicates no
+ /// line information is available.
+ //------------------------------------------------------------------
+ void
+ SetLine (uint32_t line)
+ {
+ m_line = line;
+ }
+protected:
+ //------------------------------------------------------------------
+ /// Member variables.
+ //------------------------------------------------------------------
+ FileSpec m_file; ///< The file specification that points to the
+ ///< source file where the declaration occurred.
+ uint32_t m_line; ///< Non-zero values indicates a valid line number,
+ ///< zero indicates no line number information is available.
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ uint32_t m_column; ///< Non-zero values indicates a valid column number,
+ ///< zero indicates no column information is available.
+#endif
+};
+
+bool
+operator == (const Declaration &lhs, const Declaration &rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_Declaration_h_
diff --git a/include/lldb/Symbol/FuncUnwinders.h b/include/lldb/Symbol/FuncUnwinders.h
new file mode 100644
index 000000000000..fa48dc27e123
--- /dev/null
+++ b/include/lldb/Symbol/FuncUnwinders.h
@@ -0,0 +1,106 @@
+#ifndef liblldb_FuncUnwinders_h
+#define liblldb_FuncUnwinders_h
+
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class UnwindTable;
+
+class FuncUnwinders
+{
+public:
+ // FuncUnwinders objects are used to track UnwindPlans for a function
+ // (named or not - really just an address range)
+
+ // We'll record three different UnwindPlans for each address range:
+ // 1. Unwinding from a call site (a valid exception throw location)
+ // This is often sourced from the eh_frame exception handling info
+ // 2. Unwinding from a non-call site (any location in the function)
+ // This is often done by analyzing the function prologue assembly
+ // langauge instructions
+ // 3. A fast unwind method for this function which only retrieves a
+ // limited set of registers necessary to walk the stack
+ // 4. An architectural default unwind plan when none of the above are
+ // available for some reason.
+
+ // Additionally, FuncUnwinds object can be asked where the prologue
+ // instructions are finished for migrating breakpoints past the
+ // stack frame setup instructions when we don't have line table information.
+
+ FuncUnwinders (lldb_private::UnwindTable& unwind_table, lldb_private::UnwindAssembly *assembly_profiler, AddressRange range);
+
+ ~FuncUnwinders ();
+
+ // current_offset is the byte offset into the function.
+ // 0 means no instructions have executed yet. -1 means the offset is unknown.
+ // On architectures where the pc points to the next instruction that will execute, this
+ // offset value will have already been decremented by 1 to stay within the bounds of the
+ // correct function body.
+ lldb::UnwindPlanSP
+ GetUnwindPlanAtCallSite (int current_offset);
+
+ lldb::UnwindPlanSP
+ GetUnwindPlanAtNonCallSite (lldb_private::Thread& thread);
+
+ lldb::UnwindPlanSP
+ GetUnwindPlanFastUnwind (lldb_private::Thread& Thread);
+
+ lldb::UnwindPlanSP
+ GetUnwindPlanArchitectureDefault (lldb_private::Thread& thread);
+
+ lldb::UnwindPlanSP
+ GetUnwindPlanArchitectureDefaultAtFunctionEntry (lldb_private::Thread& thread);
+
+ Address&
+ GetFirstNonPrologueInsn (Target& target);
+
+ const Address&
+ GetFunctionStartAddress () const;
+
+ bool
+ ContainsAddress (const Address& addr) const
+ {
+ return m_range.ContainsFileAddress (addr);
+ }
+
+ // When we're doing an unwind using the UnwindPlanAtNonCallSite and we find an
+ // impossible unwind condition, we know that the UnwindPlan is invalid. Calling
+ // this method on the FuncUnwinder will tell it to replace that UnwindPlan with
+ // the architectural default UnwindPlan so hopefully our stack walk will get past
+ // this frame.
+ void
+ InvalidateNonCallSiteUnwindPlan (lldb_private::Thread& Thread);
+
+private:
+ UnwindTable& m_unwind_table;
+ UnwindAssembly *m_assembly_profiler;
+ AddressRange m_range;
+
+ Mutex m_mutex;
+ lldb::UnwindPlanSP m_unwind_plan_call_site_sp;
+ lldb::UnwindPlanSP m_unwind_plan_non_call_site_sp;
+ lldb::UnwindPlanSP m_unwind_plan_fast_sp;
+ lldb::UnwindPlanSP m_unwind_plan_arch_default_sp;
+ lldb::UnwindPlanSP m_unwind_plan_arch_default_at_func_entry_sp;
+
+ bool m_tried_unwind_at_call_site:1,
+ m_tried_unwind_at_non_call_site:1,
+ m_tried_unwind_fast:1,
+ m_tried_unwind_arch_default:1,
+ m_tried_unwind_arch_default_at_func_entry:1;
+
+
+ Address m_first_non_prologue_insn;
+
+ DISALLOW_COPY_AND_ASSIGN (FuncUnwinders);
+
+}; // class FuncUnwinders
+
+} // namespace lldb_private
+
+
+#endif //liblldb_FuncUnwinders_h
diff --git a/include/lldb/Symbol/Function.h b/include/lldb/Symbol/Function.h
new file mode 100644
index 000000000000..787f81c5ad27
--- /dev/null
+++ b/include/lldb/Symbol/Function.h
@@ -0,0 +1,638 @@
+//===-- Function.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_Function_h_
+#define liblldb_Function_h_
+
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Declaration.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/UserID.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class FunctionInfo Function.h "lldb/Symbol/Function.h"
+/// @brief A class that contains generic function information.
+///
+/// This provides generic function information that gets resused between
+/// inline functions and function types.
+//----------------------------------------------------------------------
+class FunctionInfo
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with the function method name and optional declaration
+ /// information.
+ ///
+ /// @param[in] name
+ /// A C string name for the method name for this function. This
+ /// value should not be the mangled named, but the simple method
+ /// name.
+ ///
+ /// @param[in] decl_ptr
+ /// Optional declaration information that describes where the
+ /// function was declared. This can be NULL.
+ //------------------------------------------------------------------
+ FunctionInfo (const char *name, const Declaration *decl_ptr);
+
+ //------------------------------------------------------------------
+ /// Construct with the function method name and optional declaration
+ /// information.
+ ///
+ /// @param[in] name
+ /// A name for the method name for this function. This value
+ /// should not be the mangled named, but the simple method name.
+ ///
+ /// @param[in] decl_ptr
+ /// Optional declaration information that describes where the
+ /// function was declared. This can be NULL.
+ //------------------------------------------------------------------
+ FunctionInfo (const ConstString& name, const Declaration *decl_ptr);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since classes inherit from this class.
+ //------------------------------------------------------------------
+ virtual
+ ~FunctionInfo ();
+
+ //------------------------------------------------------------------
+ /// Compare two function information objects.
+ ///
+ /// First compares the method names, and if equal, then compares
+ /// the declaration information.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const FunctionInfo object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const FunctionInfo object reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ static int
+ Compare (const FunctionInfo& lhs, const FunctionInfo& rhs);
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, bool show_fullpaths) const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the declaration information.
+ ///
+ /// @return
+ /// A reference to the declaration object.
+ //------------------------------------------------------------------
+ Declaration&
+ GetDeclaration ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the declaration information.
+ ///
+ /// @return
+ /// A const reference to the declaration object.
+ //------------------------------------------------------------------
+ const Declaration&
+ GetDeclaration () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the method name.
+ ///
+ /// @return
+ /// A const reference to the method name object.
+ //------------------------------------------------------------------
+ const ConstString&
+ GetName () const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ /// The returned value does not include the bytes for any
+ /// shared string values.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ virtual size_t
+ MemorySize () const;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ ConstString m_name; ///< Function method name (not a mangled name).
+ Declaration m_declaration; ///< Information describing where this function information was defined.
+};
+
+
+//----------------------------------------------------------------------
+/// @class InlineFunctionInfo Function.h "lldb/Symbol/Function.h"
+/// @brief A class that describes information for an inlined function.
+//----------------------------------------------------------------------
+class InlineFunctionInfo : public FunctionInfo
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with the function method name, mangled name, and
+ /// optional declaration information.
+ ///
+ /// @param[in] name
+ /// A C string name for the method name for this function. This
+ /// value should not be the mangled named, but the simple method
+ /// name.
+ ///
+ /// @param[in] mangled
+ /// A C string name for the mangled name for this function. This
+ /// value can be NULL if there is no mangled information.
+ ///
+ /// @param[in] decl_ptr
+ /// Optional declaration information that describes where the
+ /// function was declared. This can be NULL.
+ ///
+ /// @param[in] call_decl_ptr
+ /// Optional calling location declaration information that
+ /// describes from where this inlined function was called.
+ //------------------------------------------------------------------
+ InlineFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr);
+
+ //------------------------------------------------------------------
+ /// Construct with the function method name, mangled name, and
+ /// optional declaration information.
+ ///
+ /// @param[in] name
+ /// A name for the method name for this function. This value
+ /// should not be the mangled named, but the simple method name.
+ ///
+ /// @param[in] mangled
+ /// A name for the mangled name for this function. This value
+ /// can be empty if there is no mangled information.
+ ///
+ /// @param[in] decl_ptr
+ /// Optional declaration information that describes where the
+ /// function was declared. This can be NULL.
+ ///
+ /// @param[in] call_decl_ptr
+ /// Optional calling location declaration information that
+ /// describes from where this inlined function was called.
+ //------------------------------------------------------------------
+ InlineFunctionInfo(const ConstString& name, const Mangled &mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~InlineFunctionInfo();
+
+ //------------------------------------------------------------------
+ /// Compare two inlined function information objects.
+ ///
+ /// First compares the FunctionInfo objects, and if equal,
+ /// compares the mangled names.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const InlineFunctionInfo object
+ /// reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const InlineFunctionInfo object
+ /// reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ int
+ Compare(const InlineFunctionInfo& lhs, const InlineFunctionInfo& rhs);
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump(Stream *s, bool show_fullpaths) const;
+
+ void
+ DumpStopContext (Stream *s) const;
+
+ const ConstString &
+ GetName () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the call site declaration information.
+ ///
+ /// @return
+ /// A reference to the declaration object.
+ //------------------------------------------------------------------
+ Declaration&
+ GetCallSite ();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the call site declaration information.
+ ///
+ /// @return
+ /// A const reference to the declaration object.
+ //------------------------------------------------------------------
+ const Declaration&
+ GetCallSite () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for the mangled name object.
+ ///
+ /// @return
+ /// A reference to the mangled name object.
+ //------------------------------------------------------------------
+ Mangled&
+ GetMangled();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the mangled name object.
+ ///
+ /// @return
+ /// A const reference to the mangled name object.
+ //------------------------------------------------------------------
+ const Mangled&
+ GetMangled() const;
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ /// The returned value does not include the bytes for any
+ /// shared string values.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ virtual size_t
+ MemorySize() const;
+
+private:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Mangled m_mangled; ///< Mangled inlined function name (can be empty if there is no mangled information).
+ Declaration m_call_decl;
+};
+
+//----------------------------------------------------------------------
+/// @class Function Function.h "lldb/Symbol/Function.h"
+/// @brief A class that describes a function.
+///
+/// Functions belong to CompileUnit objects (Function::m_comp_unit),
+/// have unique user IDs (Function::UserID), know how to reconstruct
+/// their symbol context (Function::SymbolContextScope), have a
+/// specific function type (Function::m_type_uid), have a simple
+/// method name (FunctionInfo::m_name), be declared at a specific
+/// location (FunctionInfo::m_declaration), possibly have mangled
+/// names (Function::m_mangled), an optional return type
+/// (Function::m_type), and contains lexical blocks
+/// (Function::m_blocks).
+///
+/// The function inforation is split into a few pieces:
+/// @li The concrete instance information
+/// @li The abstract information
+///
+/// The abstract information is found in the function type (Type) that
+/// describes a function information, return type and parameter types.
+///
+/// The concreate information is the address range information and
+/// specific locations for an instance of this function.
+//----------------------------------------------------------------------
+class Function :
+ public UserID,
+ public SymbolContextScope
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with a compile unit, function UID, function type UID,
+ /// optional mangled name, function type, and a section offset
+ /// based address range.
+ ///
+ /// @param[in] comp_unit
+ /// The compile unit to which this function belongs.
+ ///
+ /// @param[in] func_uid
+ /// The UID for this function. This value is provided by the
+ /// SymbolFile plug-in and can be any value that allows
+ /// the plug-in to quickly find and parse more detailed
+ /// information when and if more information is needed.
+ ///
+ /// @param[in] func_type_uid
+ /// The type UID for the function Type to allow for lazy type
+ /// parsing from the debug information.
+ ///
+ /// @param[in] mangled
+ /// The optional mangled name for this function. If empty, there
+ /// is no mangled information.
+ ///
+ /// @param[in] func_type
+ /// The optional function type. If NULL, the function type will
+ /// be parsed on demand when accessed using the
+ /// Function::GetType() function by asking the SymbolFile
+ /// plug-in to get the type for \a func_type_uid.
+ ///
+ /// @param[in] range
+ /// The section offset based address for this function.
+ //------------------------------------------------------------------
+ Function (
+ CompileUnit *comp_unit,
+ lldb::user_id_t func_uid,
+ lldb::user_id_t func_type_uid,
+ const Mangled &mangled,
+ Type * func_type,
+ const AddressRange& range);
+
+ //------------------------------------------------------------------
+ /// Construct with a compile unit, function UID, function type UID,
+ /// optional mangled name, function type, and a section offset
+ /// based address range.
+ ///
+ /// @param[in] comp_unit
+ /// The compile unit to which this function belongs.
+ ///
+ /// @param[in] func_uid
+ /// The UID for this function. This value is provided by the
+ /// SymbolFile plug-in and can be any value that allows
+ /// the plug-in to quickly find and parse more detailed
+ /// information when and if more information is needed.
+ ///
+ /// @param[in] func_type_uid
+ /// The type UID for the function Type to allow for lazy type
+ /// parsing from the debug information.
+ ///
+ /// @param[in] mangled
+ /// The optional mangled name for this function. If empty, there
+ /// is no mangled information.
+ ///
+ /// @param[in] func_type
+ /// The optional function type. If NULL, the function type will
+ /// be parsed on demand when accessed using the
+ /// Function::GetType() function by asking the SymbolFile
+ /// plug-in to get the type for \a func_type_uid.
+ ///
+ /// @param[in] range
+ /// The section offset based address for this function.
+ //------------------------------------------------------------------
+ Function (
+ CompileUnit *comp_unit,
+ lldb::user_id_t func_uid,
+ lldb::user_id_t func_type_uid,
+ const char *mangled,
+ Type * func_type,
+ const AddressRange& range);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~Function ();
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext(SymbolContext* sc);
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ();
+
+ virtual CompileUnit *
+ CalculateSymbolContextCompileUnit ();
+
+ virtual Function *
+ CalculateSymbolContextFunction ();
+
+ const AddressRange &
+ GetAddressRange()
+ {
+ return m_range;
+ }
+
+ //------------------------------------------------------------------
+ /// Find the file and line number of the source location of the start
+ /// of the function. This will use the declaration if present and fall
+ /// back on the line table if that fails. So there may NOT be a line
+ /// table entry for this source file/line combo.
+ ///
+ /// @param[out] source_file
+ /// The source file.
+ ///
+ /// @param[out] line_no
+ /// The line number.
+ //------------------------------------------------------------------
+ void
+ GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no);
+
+ //------------------------------------------------------------------
+ /// Find the file and line number of the source location of the end
+ /// of the function.
+ ///
+ ///
+ /// @param[out] source_file
+ /// The source file.
+ ///
+ /// @param[out] line_no
+ /// The line number.
+ //------------------------------------------------------------------
+ void
+ GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the block list.
+ ///
+ /// @return
+ /// The block list object that describes all lexical blocks
+ /// in the function.
+ ///
+ /// @see BlockList
+ //------------------------------------------------------------------
+ Block&
+ GetBlock (bool can_create);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the compile unit that owns this function.
+ ///
+ /// @return
+ /// A compile unit object pointer.
+ //------------------------------------------------------------------
+ CompileUnit*
+ GetCompileUnit();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the compile unit that owns this function.
+ ///
+ /// @return
+ /// A const compile unit object pointer.
+ //------------------------------------------------------------------
+ const CompileUnit*
+ GetCompileUnit() const;
+
+ void
+ GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target);
+
+ //------------------------------------------------------------------
+ /// Get accessor for the frame base location.
+ ///
+ /// @return
+ /// A location expression that describes the function frame
+ /// base.
+ //------------------------------------------------------------------
+ DWARFExpression &
+ GetFrameBaseExpression()
+ {
+ return m_frame_base;
+ }
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the frame base location.
+ ///
+ /// @return
+ /// A const compile unit object pointer.
+ //------------------------------------------------------------------
+ const DWARFExpression &
+ GetFrameBaseExpression() const
+ {
+ return m_frame_base;
+ }
+
+ const ConstString &
+ GetName() const
+ {
+ return m_mangled.GetName();
+ }
+
+ const Mangled &
+ GetMangled() const
+ {
+ return m_mangled;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the DeclContext for this function, if available.
+ ///
+ /// @return
+ /// The DeclContext, or NULL if none exists.
+ //------------------------------------------------------------------
+ clang::DeclContext *
+ GetClangDeclContext();
+
+ //------------------------------------------------------------------
+ /// Get accessor for the type that describes the function
+ /// return value type, and paramter types.
+ ///
+ /// @return
+ /// A type object pointer.
+ //------------------------------------------------------------------
+ Type*
+ GetType();
+
+ //------------------------------------------------------------------
+ /// Get const accessor for the type that describes the function
+ /// return value type, and paramter types.
+ ///
+ /// @return
+ /// A const type object pointer.
+ //------------------------------------------------------------------
+ const Type*
+ GetType() const;
+
+ ClangASTType
+ GetClangType ();
+
+ uint32_t
+ GetPrologueByteSize ();
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] show_context
+ /// If \b true, variables will dump their symbol context
+ /// information.
+ //------------------------------------------------------------------
+ void
+ Dump(Stream *s, bool show_context) const;
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext(Stream *s);
+
+ //------------------------------------------------------------------
+ /// Get the memory cost of this object.
+ ///
+ /// @return
+ /// The number of bytes that this object occupies in memory.
+ /// The returned value does not include the bytes for any
+ /// shared string values.
+ ///
+ /// @see ConstString::StaticMemorySize ()
+ //------------------------------------------------------------------
+ size_t
+ MemorySize () const;
+
+protected:
+
+ enum
+ {
+ flagsCalculatedPrologueSize = (1 << 0) ///< Have we already tried to calculate the prologue size?
+ };
+
+
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ CompileUnit *m_comp_unit; ///< The compile unit that owns this function.
+ lldb::user_id_t m_type_uid; ///< The user ID of for the prototype Type for this function.
+ Type * m_type; ///< The function prototype type for this function that include the function info (FunctionInfo), return type and parameters.
+ Mangled m_mangled; ///< The mangled function name if any, if empty, there is no mangled information.
+ Block m_block; ///< All lexical blocks contained in this function.
+ AddressRange m_range; ///< The function address range that covers the widest range needed to contain all blocks
+ DWARFExpression m_frame_base; ///< The frame base expression for variables that are relative to the frame pointer.
+ Flags m_flags;
+ uint32_t m_prologue_byte_size; ///< Compute the prologue size once and cache it
+private:
+ DISALLOW_COPY_AND_ASSIGN(Function);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Function_h_
diff --git a/include/lldb/Symbol/LineEntry.h b/include/lldb/Symbol/LineEntry.h
new file mode 100644
index 000000000000..d7750cd34916
--- /dev/null
+++ b/include/lldb/Symbol/LineEntry.h
@@ -0,0 +1,174 @@
+//===-- LineEntry.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_LineEntry_h_
+#define liblldb_LineEntry_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Host/FileSpec.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class LineEntry LineEntry.h "lldb/Symbol/LineEntry.h"
+/// @brief A line table entry class.
+//----------------------------------------------------------------------
+struct LineEntry
+{
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize all member variables to invalid values.
+ //------------------------------------------------------------------
+ LineEntry ();
+
+ LineEntry
+ (
+ const lldb::SectionSP &section_sp,
+ lldb::addr_t section_offset,
+ lldb::addr_t byte_size,
+ const FileSpec &file,
+ uint32_t _line,
+ uint16_t _column,
+ bool _is_start_of_statement,
+ bool _is_start_of_basic_block,
+ bool _is_prologue_end,
+ bool _is_epilogue_begin,
+ bool _is_terminal_entry
+ );
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Clears all member variables to invalid values.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] comp_unit
+ /// The compile unit object that contains the support file
+ /// list so the line entry can dump the file name (since this
+ /// object contains a file index into the support file list).
+ ///
+ /// @param[in] show_file
+ /// If \b true, display the filename with the line entry which
+ /// requires that the compile unit object \a comp_unit be a
+ /// valid pointer.
+ ///
+ /// @param[in] style
+ /// The display style for the section offset address.
+ ///
+ /// @return
+ /// Returns \b true if the address was able to be displayed
+ /// using \a style. File and load addresses may be unresolved
+ /// and it may not be possible to display a valid address value.
+ /// Returns \b false if the address was not able to be properly
+ /// dumped.
+ ///
+ /// @see Address::DumpStyle
+ //------------------------------------------------------------------
+ bool
+ Dump (Stream *s, Target *target, bool show_file, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_range) const;
+
+ bool
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level,
+ CompileUnit* cu,
+ Target *target,
+ bool show_address_only) const;
+
+ //------------------------------------------------------------------
+ /// Dumps information specific to a process that stops at this
+ /// line entry to the supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] comp_unit
+ /// The compile unit object that contains the support file
+ /// list so the line entry can dump the file name (since this
+ /// object contains a file index into the support file list).
+ ///
+ /// @return
+ /// Returns \b true if the file and line were properly dumped,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ DumpStopContext (Stream *s, bool show_fullpaths) const;
+
+ //------------------------------------------------------------------
+ /// Check if a line entry object is valid.
+ ///
+ /// @return
+ /// Returns \b true if the line entry contains a valid section
+ /// offset address, file index, and line number, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid () const;
+
+ //------------------------------------------------------------------
+ /// Compare two LineEntry objects.
+ ///
+ /// @param[in] lhs
+ /// The Left Hand Side const LineEntry object reference.
+ ///
+ /// @param[in] rhs
+ /// The Right Hand Side const LineEntry object reference.
+ ///
+ /// @return
+ /// @li -1 if lhs < rhs
+ /// @li 0 if lhs == rhs
+ /// @li 1 if lhs > rhs
+ //------------------------------------------------------------------
+ static int
+ Compare (const LineEntry& lhs, const LineEntry& rhs);
+
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ AddressRange range; ///< The section offset address range for this line entry.
+ FileSpec file;
+ uint32_t line; ///< The source line number, or zero if there is no line number information.
+ uint16_t column; ///< The column number of the source line, or zero if there is no column information.
+ uint16_t is_start_of_statement:1, ///< Indicates this entry is the beginning of a statement.
+ is_start_of_basic_block:1, ///< Indicates this entry is the beginning of a basic block.
+ is_prologue_end:1, ///< Indicates this entry is one (of possibly many) where execution should be suspended for an entry breakpoint of a function.
+ is_epilogue_begin:1, ///< Indicates this entry is one (of possibly many) where execution should be suspended for an exit breakpoint of a function.
+ is_terminal_entry:1; ///< Indicates this entry is that of the first byte after the end of a sequence of target machine instructions.
+};
+
+//------------------------------------------------------------------
+/// Less than operator.
+///
+/// @param[in] lhs
+/// The Left Hand Side const LineEntry object reference.
+///
+/// @param[in] rhs
+/// The Right Hand Side const LineEntry object reference.
+///
+/// @return
+/// Returns \b true if lhs < rhs, false otherwise.
+//------------------------------------------------------------------
+bool operator<(const LineEntry& lhs, const LineEntry& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_LineEntry_h_
diff --git a/include/lldb/Symbol/LineTable.h b/include/lldb/Symbol/LineTable.h
new file mode 100644
index 000000000000..477c8455ded8
--- /dev/null
+++ b/include/lldb/Symbol/LineTable.h
@@ -0,0 +1,422 @@
+//===-- LineTable.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_LineTable_h_
+#define liblldb_LineTable_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/RangeMap.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class LineSequence LineTable.h "lldb/Symbol/LineTable.h"
+/// @brief An abstract base class used during symbol table creation.
+//----------------------------------------------------------------------
+class LineSequence
+{
+public:
+ LineSequence ();
+
+ virtual
+ ~LineSequence() {}
+
+ virtual void
+ Clear() = 0;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (LineSequence);
+};
+
+//----------------------------------------------------------------------
+/// @class LineTable LineTable.h "lldb/Symbol/LineTable.h"
+/// @brief A line table class.
+//----------------------------------------------------------------------
+class LineTable
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with compile unit.
+ ///
+ /// @param[in] comp_unit
+ /// The compile unit to which this line table belongs.
+ //------------------------------------------------------------------
+ LineTable (CompileUnit* comp_unit);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~LineTable ();
+
+ //------------------------------------------------------------------
+ /// Adds a new line entry to this line table.
+ ///
+ /// All line entries are maintained in file address order.
+ ///
+ /// @param[in] line_entry
+ /// A const reference to a new line_entry to add to this line
+ /// table.
+ ///
+ /// @see Address::DumpStyle
+ //------------------------------------------------------------------
+// void
+// AddLineEntry (const LineEntry& line_entry);
+
+ // Called when you can't guarantee the addresses are in increasing order
+ void
+ InsertLineEntry (lldb::addr_t file_addr,
+ uint32_t line,
+ uint16_t column,
+ uint16_t file_idx,
+ bool is_start_of_statement,
+ bool is_start_of_basic_block,
+ bool is_prologue_end,
+ bool is_epilogue_begin,
+ bool is_terminal_entry);
+
+ // Used to instantiate the LineSequence helper classw
+ LineSequence*
+ CreateLineSequenceContainer ();
+
+ // Append an entry to a caller-provided collection that will later be
+ // inserted in this line table.
+ void
+ AppendLineEntryToSequence (LineSequence* sequence,
+ lldb::addr_t file_addr,
+ uint32_t line,
+ uint16_t column,
+ uint16_t file_idx,
+ bool is_start_of_statement,
+ bool is_start_of_basic_block,
+ bool is_prologue_end,
+ bool is_epilogue_begin,
+ bool is_terminal_entry);
+
+ // Insert a sequence of entries into this line table.
+ void
+ InsertSequence (LineSequence* sequence);
+
+ //------------------------------------------------------------------
+ /// Dump all line entries in this line table to the stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] style
+ /// The display style for the address.
+ ///
+ /// @see Address::DumpStyle
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, Target *target,
+ Address::DumpStyle style,
+ Address::DumpStyle fallback_style,
+ bool show_line_ranges);
+
+ void
+ GetDescription (Stream *s,
+ Target *target,
+ lldb::DescriptionLevel level);
+
+ //------------------------------------------------------------------
+ /// Find a line entry that contains the section offset address \a
+ /// so_addr.
+ ///
+ /// @param[in] so_addr
+ /// A section offset address object containing the address we
+ /// are searching for.
+ ///
+ /// @param[out] line_entry
+ /// A copy of the line entry that was found if \b true is
+ /// returned, otherwise \a entry is left unmodified.
+ ///
+ /// @param[out] index_ptr
+ /// A pointer to a 32 bit integer that will get the actual line
+ /// entry index if it is not NULL.
+ ///
+ /// @return
+ /// Returns \b true if \a so_addr is contained in a line entry
+ /// in this line table, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr = NULL);
+
+ //------------------------------------------------------------------
+ /// Find a line entry index that has a matching file index and
+ /// source line number.
+ ///
+ /// Finds the next line entry that has a matching \a file_idx and
+ /// source line number \a line starting at the \a start_idx entries
+ /// into the line entry collection.
+ ///
+ /// @param[in] start_idx
+ /// The number of entries to skip when starting the search.
+ ///
+ /// @param[out] file_idx
+ /// The file index to search for that should be found prior
+ /// to calling this function using the following functions:
+ /// CompileUnit::GetSupportFiles()
+ /// FileSpecList::FindFileIndex (uint32_t, const FileSpec &) const
+ ///
+ /// @param[in] line
+ /// The source line to match.
+ ///
+ /// @param[in] exact
+ /// If true, match only if you find a line entry exactly matching \a line.
+ /// If false, return the closest line entry greater than \a line.
+ ///
+ /// @param[out] line_entry
+ /// A reference to a line entry object that will get a copy of
+ /// the line entry if \b true is returned, otherwise \a
+ /// line_entry is left untouched.
+ ///
+ /// @return
+ /// Returns \b true if a matching line entry is found in this
+ /// line table, \b false otherwise.
+ ///
+ /// @see CompileUnit::GetSupportFiles()
+ /// @see FileSpecList::FindFileIndex (uint32_t, const FileSpec &) const
+ //------------------------------------------------------------------
+ uint32_t
+ FindLineEntryIndexByFileIndex (uint32_t start_idx,
+ uint32_t file_idx,
+ uint32_t line,
+ bool exact,
+ LineEntry* line_entry_ptr);
+
+ uint32_t
+ FindLineEntryIndexByFileIndex (uint32_t start_idx,
+ const std::vector<uint32_t> &file_indexes,
+ uint32_t line,
+ bool exact,
+ LineEntry* line_entry_ptr);
+
+ size_t
+ FineLineEntriesForFileIndex (uint32_t file_idx,
+ bool append,
+ SymbolContextList &sc_list);
+
+ //------------------------------------------------------------------
+ /// Get the line entry from the line table at index \a idx.
+ ///
+ /// @param[in] idx
+ /// An index into the line table entry collection.
+ ///
+ /// @return
+ /// A valid line entry if \a idx is a valid index, or an invalid
+ /// line entry if \a idx is not valid.
+ ///
+ /// @see LineTable::GetSize()
+ /// @see LineEntry::IsValid() const
+ //------------------------------------------------------------------
+ bool
+ GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry);
+
+ //------------------------------------------------------------------
+ /// Gets the size of the line table in number of line table entries.
+ ///
+ /// @return
+ /// The number of line table entries in this line table.
+ //------------------------------------------------------------------
+ uint32_t
+ GetSize () const;
+
+ typedef lldb_private::RangeArray<lldb::addr_t, lldb::addr_t, 32> FileAddressRanges;
+
+ //------------------------------------------------------------------
+ /// Gets all contiguous file address ranges for the entire line table.
+ ///
+ /// @param[out] file_ranges
+ /// A collection of file address ranges that will be filled in
+ /// by this function.
+ ///
+ /// @param[out] append
+ /// If \b true, then append to \a file_ranges, otherwise clear
+ /// \a file_ranges prior to adding any ranges.
+ ///
+ /// @return
+ /// The number of address ranges added to \a file_ranges
+ //------------------------------------------------------------------
+ size_t
+ GetContiguousFileAddressRanges (FileAddressRanges &file_ranges, bool append);
+
+ //------------------------------------------------------------------
+ /// Given a file range link map, relink the current line table
+ /// and return a fixed up line table.
+ ///
+ /// @param[out] file_range_map
+ /// A collection of file ranges that maps to new file ranges
+ /// that will be used when linking the line table.
+ ///
+ /// @return
+ /// A new line table if at least one line table entry was able
+ /// to be mapped.
+ //------------------------------------------------------------------
+ typedef RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> FileRangeMap;
+
+ LineTable *
+ LinkLineTable (const FileRangeMap &file_range_map);
+
+protected:
+
+ struct Entry
+ {
+ Entry () :
+ file_addr (LLDB_INVALID_ADDRESS),
+ line (0),
+ column (0),
+ file_idx (0),
+ is_start_of_statement (false),
+ is_start_of_basic_block (false),
+ is_prologue_end (false),
+ is_epilogue_begin (false),
+ is_terminal_entry (false)
+ {
+ }
+
+ Entry ( lldb::addr_t _file_addr,
+ uint32_t _line,
+ uint16_t _column,
+ uint16_t _file_idx,
+ bool _is_start_of_statement,
+ bool _is_start_of_basic_block,
+ bool _is_prologue_end,
+ bool _is_epilogue_begin,
+ bool _is_terminal_entry) :
+ file_addr (_file_addr),
+ line (_line),
+ column (_column),
+ file_idx (_file_idx),
+ is_start_of_statement (_is_start_of_statement),
+ is_start_of_basic_block (_is_start_of_basic_block),
+ is_prologue_end (_is_prologue_end),
+ is_epilogue_begin (_is_epilogue_begin),
+ is_terminal_entry (_is_terminal_entry)
+ {
+ }
+
+ int
+ bsearch_compare (const void *key, const void *arrmem);
+
+ void
+ Clear ()
+ {
+ file_addr = LLDB_INVALID_ADDRESS;
+ line = 0;
+ column = 0;
+ file_idx = 0;
+ is_start_of_statement = false;
+ is_start_of_basic_block = false;
+ is_prologue_end = false;
+ is_epilogue_begin = false;
+ is_terminal_entry = false;
+ }
+
+ static int
+ Compare (const Entry& lhs, const Entry& rhs)
+ {
+ // Compare the sections before calling
+ #define SCALAR_COMPARE(a,b) if (a < b) return -1; if (a > b) return +1
+ SCALAR_COMPARE (lhs.file_addr, rhs.file_addr);
+ SCALAR_COMPARE (lhs.line, rhs.line);
+ SCALAR_COMPARE (lhs.column, rhs.column);
+ SCALAR_COMPARE (lhs.is_start_of_statement, rhs.is_start_of_statement);
+ SCALAR_COMPARE (lhs.is_start_of_basic_block, rhs.is_start_of_basic_block);
+ // rhs and lhs reversed on purpose below.
+ SCALAR_COMPARE (rhs.is_prologue_end, lhs.is_prologue_end);
+ SCALAR_COMPARE (lhs.is_epilogue_begin, rhs.is_epilogue_begin);
+ // rhs and lhs reversed on purpose below.
+ SCALAR_COMPARE (rhs.is_terminal_entry, lhs.is_terminal_entry);
+ SCALAR_COMPARE (lhs.file_idx, rhs.file_idx);
+ #undef SCALAR_COMPARE
+ return 0;
+ }
+
+
+ class LessThanBinaryPredicate
+ {
+ public:
+ LessThanBinaryPredicate(LineTable *line_table);
+ bool operator() (const LineTable::Entry&, const LineTable::Entry&) const;
+ protected:
+ LineTable *m_line_table;
+ };
+
+ static bool EntryAddressLessThan (const Entry& lhs, const Entry& rhs)
+ {
+ return lhs.file_addr < rhs.file_addr;
+ }
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ lldb::addr_t file_addr; ///< The file address for this line entry
+ uint32_t line; ///< The source line number, or zero if there is no line number information.
+ uint16_t column; ///< The column number of the source line, or zero if there is no column information.
+ uint16_t file_idx:11, ///< The file index into CompileUnit's file table, or zero if there is no file information.
+ is_start_of_statement:1, ///< Indicates this entry is the beginning of a statement.
+ is_start_of_basic_block:1, ///< Indicates this entry is the beginning of a basic block.
+ is_prologue_end:1, ///< Indicates this entry is one (of possibly many) where execution should be suspended for an entry breakpoint of a function.
+ is_epilogue_begin:1, ///< Indicates this entry is one (of possibly many) where execution should be suspended for an exit breakpoint of a function.
+ is_terminal_entry:1; ///< Indicates this entry is that of the first byte after the end of a sequence of target machine instructions.
+ };
+
+ struct EntrySearchInfo
+ {
+ LineTable* line_table;
+ lldb_private::Section *a_section;
+ Entry *a_entry;
+ };
+
+ //------------------------------------------------------------------
+ // Types
+ //------------------------------------------------------------------
+ typedef std::vector<lldb_private::Section*> section_collection; ///< The collection type for the sections.
+ typedef std::vector<Entry> entry_collection; ///< The collection type for the line entries.
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ CompileUnit* m_comp_unit; ///< The compile unit that this line table belongs to.
+ entry_collection m_entries; ///< The collection of line entries in this line table.
+
+ //------------------------------------------------------------------
+ // Helper class
+ //------------------------------------------------------------------
+ class LineSequenceImpl : public LineSequence
+ {
+ public:
+ LineSequenceImpl() :
+ LineSequence()
+ {}
+
+ virtual
+ ~LineSequenceImpl()
+ {}
+
+ virtual void
+ Clear();
+
+ entry_collection m_entries; ///< The collection of line entries in this sequence.
+ };
+
+ bool
+ ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (LineTable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_LineTable_h_
diff --git a/include/lldb/Symbol/ObjectContainer.h b/include/lldb/Symbol/ObjectContainer.h
new file mode 100644
index 000000000000..7fb686245057
--- /dev/null
+++ b/include/lldb/Symbol/ObjectContainer.h
@@ -0,0 +1,236 @@
+//===-- ObjectContainer.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_ObjectContainer_h_
+#define liblldb_ObjectContainer_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Host/Endian.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ObjectContainer ObjectContainer.h "lldb/Symbol/ObjectContainer.h"
+/// @brief A plug-in interface definition class for object containers.
+///
+/// Object containers contain object files from one or more
+/// architectures, and also can contain one or more named objects.
+///
+/// Typical object containers are static libraries (.a files) that
+/// contain multiple named object files, and universal files that contain
+/// multiple architectures.
+//----------------------------------------------------------------------
+class ObjectContainer :
+ public PluginInterface,
+ public ModuleChild
+{
+public:
+ //------------------------------------------------------------------
+ /// Construct with a parent module, offset, and header data.
+ ///
+ /// Object files belong to modules and a valid module must be
+ /// supplied upon construction. The at an offset within a file for
+ /// objects that contain more than one architecture or object.
+ //------------------------------------------------------------------
+ ObjectContainer (const lldb::ModuleSP &module_sp,
+ const FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset) :
+ ModuleChild (module_sp),
+ m_file (), // This file can be different than the module's file spec
+ m_offset (file_offset),
+ m_length (length),
+ m_data ()
+ {
+ if (file)
+ m_file = *file;
+ if (data_sp)
+ m_data.SetData (data_sp, data_offset, length);
+ }
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from by the plug-in instance.
+ //------------------------------------------------------------------
+ virtual
+ ~ObjectContainer()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the current contents of this object
+ /// to the supplied stream \a s. The dumping should include the
+ /// section list if it has been parsed, and the symbol table
+ /// if it has been parsed.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ virtual void
+ Dump (Stream *s) const = 0;
+
+ //------------------------------------------------------------------
+ /// Gets the architecture given an index.
+ ///
+ /// Copies the architecture specification for index \a idx.
+ ///
+ /// @param[in] idx
+ /// The architecture index to extract.
+ ///
+ /// @param[out] arch
+ /// A architecture object that will be filled in if \a idx is a
+ /// architecture valid index.
+ ///
+ /// @return
+ /// Returns \b true if \a idx is valid and \a arch has been
+ /// filled in, \b false otherwise.
+ ///
+ /// @see ObjectContainer::GetNumArchitectures() const
+ //------------------------------------------------------------------
+ virtual bool
+ GetArchitectureAtIndex (uint32_t idx, ArchSpec& arch) const
+ {
+ return false;
+ }
+
+ //------------------------------------------------------------------
+ /// Returns the offset into a file at which this object resides.
+ ///
+ /// Some files contain many object files, and this function allows
+ /// access to an object's offset within the file.
+ ///
+ /// @return
+ /// The offset in bytes into the file. Defaults to zero for
+ /// simple object files that a represented by an entire file.
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetOffset () const
+ { return m_offset; }
+
+ virtual lldb::addr_t
+ GetByteSize () const
+ { return m_length; }
+
+ //------------------------------------------------------------------
+ /// Get the number of objects within this object file (archives).
+ ///
+ /// @return
+ /// Zero for object files that are not archives, or the number
+ /// of objects contained in the archive.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetNumObjects () const
+ { return 0; }
+
+ //------------------------------------------------------------------
+ /// Get the number of architectures in this object file.
+ ///
+ /// The default implementation returns 1 as for object files that
+ /// contain a single architecture. ObjectContainer instances that
+ /// contain more than one architecture should override this function
+ /// and return an appropriate value.
+ ///
+ /// @return
+ /// The number of architectures contained in this object file.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetNumArchitectures () const
+ { return 0; }
+
+ //------------------------------------------------------------------
+ /// Attempts to parse the object header.
+ ///
+ /// This function is used as a test to see if a given plug-in
+ /// instance can parse the header data already contained in
+ /// ObjectContainer::m_data. If an object file parser does not
+ /// recognize that magic bytes in a header, false should be returned
+ /// and the next plug-in can attempt to parse an object file.
+ ///
+ /// @return
+ /// Returns \b true if the header was parsed succesfully, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ParseHeader () = 0;
+
+ //------------------------------------------------------------------
+ /// Selects an architecture in an object file.
+ ///
+ /// Object files that contain a single architecture should verify
+ /// that the specified \a arch matches the architecture in in
+ /// object file and return \b true or \b false accordingly.
+ ///
+ /// Object files that contain more than one architecture should
+ /// attempt to select that architecture, and if successful, clear
+ /// out any previous state from any previously selected architecture
+ /// and prepare to return information for the new architecture.
+ ///
+ /// @return
+ /// Returns a pointer to the object file of the requested \a
+ /// arch and optional \a name. Returns NULL of no such object
+ /// file exists in the container.
+ //------------------------------------------------------------------
+ virtual lldb::ObjectFileSP
+ GetObjectFile (const FileSpec *file) = 0;
+
+ virtual bool
+ ObjectAtIndexIsContainer (uint32_t object_idx)
+ {
+ return false;
+ }
+
+ virtual ObjectFile *
+ GetObjectFileAtIndex (uint32_t object_idx)
+ {
+ return NULL;
+ }
+
+ virtual ObjectContainer *
+ GetObjectContainerAtIndex (uint32_t object_idx)
+ {
+ return NULL;
+ }
+
+ virtual const char *
+ GetObjectNameAtIndex (uint32_t object_idx) const
+ {
+ return NULL;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ FileSpec m_file; ///< The file that represents this container objects (which can be different from the module's file).
+ lldb::addr_t m_offset; ///< The offset in bytes into the file, or the address in memory
+ lldb::addr_t m_length; ///< The size in bytes if known (can be zero).
+ DataExtractor m_data; ///< The data for this object file so things can be parsed lazily.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ObjectContainer);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ObjectContainer_h_
diff --git a/include/lldb/Symbol/ObjectFile.h b/include/lldb/Symbol/ObjectFile.h
new file mode 100644
index 000000000000..8934c31bb988
--- /dev/null
+++ b/include/lldb/Symbol/ObjectFile.h
@@ -0,0 +1,706 @@
+//===-- ObjectFile.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_ObjectFile_h_
+#define liblldb_ObjectFile_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/UnwindTable.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ObjectFile ObjectFile.h "lldb/Symbol/ObjectFile.h"
+/// @brief A plug-in interface definition class for object file parsers.
+///
+/// Object files belong to Module objects and know how to extract
+/// information from executable, shared library, and object (.o) files
+/// used by operating system runtime. The symbol table and section list
+/// for an object file.
+///
+/// Object files can be represented by the entire file, or by part of a
+/// file. Examples of object files that are part of a file include
+/// object files that contain information for multiple architectures in
+/// the same file, or archive files that contain multiple objects
+/// (ranlib archives) (possibly for multiple architectures as well).
+///
+/// Object archive files (e.g. ranlib archives) can contain
+/// multiple .o (object) files that must be selected by index or by name.
+/// The number of objects that an ObjectFile contains can be determined
+/// using the ObjectFile::GetNumObjects() const
+/// function, and followed by a call to
+/// ObjectFile::SelectObjectAtIndex (uint32_t) to change the currently
+/// selected object. Objects can also be selected by name using the
+/// ObjectFile::SelectObject(const char *) function.
+///
+/// Once an architecture is selected (and an object is selected for
+/// for archives), the object file information can be extracted from
+/// this abstract class.
+//----------------------------------------------------------------------
+class ObjectFile:
+ public std::enable_shared_from_this<ObjectFile>,
+ public PluginInterface,
+ public ModuleChild
+{
+friend class lldb_private::Module;
+
+public:
+ typedef enum
+ {
+ eTypeInvalid = 0,
+ eTypeCoreFile, /// A core file that has a checkpoint of a program's execution state
+ eTypeExecutable, /// A normal executable
+ eTypeDebugInfo, /// An object file that contains only debug information
+ eTypeDynamicLinker, /// The platform's dynamic linker executable
+ eTypeObjectFile, /// An intermediate object file
+ eTypeSharedLibrary, /// A shared library that can be used during execution
+ eTypeStubLibrary, /// A library that can be linked against but not used for execution
+ eTypeUnknown
+ } Type;
+
+ typedef enum
+ {
+ eStrataInvalid = 0,
+ eStrataUnknown,
+ eStrataUser,
+ eStrataKernel,
+ eStrataRawImage
+ } Strata;
+
+ //------------------------------------------------------------------
+ /// Construct with a parent module, offset, and header data.
+ ///
+ /// Object files belong to modules and a valid module must be
+ /// supplied upon construction. The at an offset within a file for
+ /// objects that contain more than one architecture or object.
+ //------------------------------------------------------------------
+ ObjectFile (const lldb::ModuleSP &module_sp,
+ const FileSpec *file_spec_ptr,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset);
+
+ ObjectFile (const lldb::ModuleSP &module_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr,
+ lldb::DataBufferSP& data_sp);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from by the plug-in instance.
+ //------------------------------------------------------------------
+ virtual
+ ~ObjectFile();
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the current contents of this object
+ /// to the supplied stream \a s. The dumping should include the
+ /// section list if it has been parsed, and the symbol table
+ /// if it has been parsed.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ virtual void
+ Dump (Stream *s) = 0;
+
+ //------------------------------------------------------------------
+ /// Find a ObjectFile plug-in that can parse \a file_spec.
+ ///
+ /// Scans all loaded plug-in interfaces that implement versions of
+ /// the ObjectFile plug-in interface and returns the first
+ /// instance that can parse the file.
+ ///
+ /// @param[in] module
+ /// The parent module that owns this object file.
+ ///
+ /// @param[in] file_spec
+ /// A file specification that indicates which file to use as the
+ /// object file.
+ ///
+ /// @param[in] file_offset
+ /// The offset into the file at which to start parsing the
+ /// object. This is for files that contain multiple
+ /// architectures or objects.
+ ///
+ /// @param[in] file_size
+ /// The size of the current object file if it can be determined
+ /// or if it is known. This can be zero.
+ ///
+ /// @see ObjectFile::ParseHeader()
+ //------------------------------------------------------------------
+ static lldb::ObjectFileSP
+ FindPlugin (const lldb::ModuleSP &module_sp,
+ const FileSpec* file_spec,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb::DataBufferSP &data_sp,
+ lldb::offset_t &data_offset);
+
+ //------------------------------------------------------------------
+ /// Find a ObjectFile plug-in that can parse a file in memory.
+ ///
+ /// Scans all loaded plug-in interfaces that implement versions of
+ /// the ObjectFile plug-in interface and returns the first
+ /// instance that can parse the file.
+ ///
+ /// @param[in] module
+ /// The parent module that owns this object file.
+ ///
+ /// @param[in] process_sp
+ /// A shared pointer to the process whose memory space contains
+ /// an object file. This will be stored as a std::weak_ptr.
+ ///
+ /// @param[in] header_addr
+ /// The address of the header for the object file in memory.
+ //------------------------------------------------------------------
+ static lldb::ObjectFileSP
+ FindPlugin (const lldb::ModuleSP &module_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr,
+ lldb::DataBufferSP &file_data_sp);
+
+
+ static size_t
+ GetModuleSpecifications (const FileSpec &file,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ ModuleSpecList &specs);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb_private::ModuleSpecList &specs);
+ //------------------------------------------------------------------
+ /// Split a path into a file path with object name.
+ ///
+ /// For paths like "/tmp/foo.a(bar.o)" we often need to split a path
+ /// up into the actual path name and into the object name so we can
+ /// make a valid object file from it.
+ ///
+ /// @param[in] path_with_object
+ /// A path that might contain an archive path with a .o file
+ /// specified in parens in the basename of the path.
+ ///
+ /// @param[out] archive_file
+ /// If \b true is returned, \a file_spec will be filled in with
+ /// the path to the archive.
+ ///
+ /// @param[out] archive_object
+ /// If \b true is returned, \a object will be filled in with
+ /// the name of the object inside the archive.
+ ///
+ /// @return
+ /// \b true if the path matches the pattern of archive + object
+ /// and \a archive_file and \a archive_object are modified,
+ /// \b false otherwise and \a archive_file and \a archive_object
+ /// are guaranteed to be remain unchanged.
+ //------------------------------------------------------------------
+ static bool
+ SplitArchivePathWithObject (const char *path_with_object,
+ lldb_private::FileSpec &archive_file,
+ lldb_private::ConstString &archive_object,
+ bool must_exist);
+
+ //------------------------------------------------------------------
+ /// Gets the address size in bytes for the current object file.
+ ///
+ /// @return
+ /// The size of an address in bytes for the currently selected
+ /// architecture (and object for archives). Returns zero if no
+ /// architecture or object has been selected.
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetAddressByteSize () const = 0;
+
+ //------------------------------------------------------------------
+ /// Get the address type given a file address in an object file.
+ ///
+ /// Many binary file formats know what kinds
+ /// This is primarily for ARM binaries, though it can be applied to
+ /// any executable file format that supports different opcode types
+ /// within the same binary. ARM binaries support having both ARM and
+ /// Thumb within the same executable container. We need to be able
+ /// to get
+ /// @return
+ /// The size of an address in bytes for the currently selected
+ /// architecture (and object for archives). Returns zero if no
+ /// architecture or object has been selected.
+ //------------------------------------------------------------------
+ virtual lldb::AddressClass
+ GetAddressClass (lldb::addr_t file_addr);
+
+ //------------------------------------------------------------------
+ /// Extract the dependent modules from an object file.
+ ///
+ /// If an object file has information about which other images it
+ /// depends on (such as shared libraries), this function will
+ /// provide the list. Since many executables or shared libraries
+ /// may depend on the same files,
+ /// FileSpecList::AppendIfUnique(const FileSpec &) should be
+ /// used to make sure any files that are added are not already in
+ /// the list.
+ ///
+ /// @param[out] file_list
+ /// A list of file specification objects that gets dependent
+ /// files appended to.
+ ///
+ /// @return
+ /// The number of new files that were appended to \a file_list.
+ ///
+ /// @see FileSpecList::AppendIfUnique(const FileSpec &)
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetDependentModules (FileSpecList& file_list) = 0;
+
+ //------------------------------------------------------------------
+ /// Tells whether this object file is capable of being the main executable
+ /// for a process.
+ ///
+ /// @return
+ /// \b true if it is, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ IsExecutable () const = 0;
+
+ //------------------------------------------------------------------
+ /// Returns the offset into a file at which this object resides.
+ ///
+ /// Some files contain many object files, and this function allows
+ /// access to an object's offset within the file.
+ ///
+ /// @return
+ /// The offset in bytes into the file. Defaults to zero for
+ /// simple object files that a represented by an entire file.
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetFileOffset () const
+ { return m_file_offset; }
+
+ virtual lldb::addr_t
+ GetByteSize () const
+ { return m_length; }
+
+ //------------------------------------------------------------------
+ /// Get accessor to the object file specification.
+ ///
+ /// @return
+ /// The file specification object pointer if there is one, or
+ /// NULL if this object is only from memory.
+ //------------------------------------------------------------------
+ virtual FileSpec&
+ GetFileSpec() { return m_file; }
+
+ //------------------------------------------------------------------
+ /// Get const accessor to the object file specification.
+ ///
+ /// @return
+ /// The const file specification object pointer if there is one,
+ /// or NULL if this object is only from memory.
+ //------------------------------------------------------------------
+ virtual const FileSpec&
+ GetFileSpec() const { return m_file; }
+
+ //------------------------------------------------------------------
+ /// Get the name of the cpu, vendor and OS for this object file.
+ ///
+ /// This value is a string that represents the target triple where
+ /// the cpu type, the vendor and the OS are encoded into a string.
+ ///
+ /// @param[out] target_triple
+ /// The string value of the target triple.
+ ///
+ /// @return
+ /// \b True if the target triple was able to be computed, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ GetArchitecture (ArchSpec &arch) = 0;
+
+ //------------------------------------------------------------------
+ /// Gets the section list for the currently selected architecture
+ /// (and object for archives).
+ ///
+ /// Section list parsing can be deferred by ObjectFile instances
+ /// until this accessor is called the first time.
+ ///
+ /// @return
+ /// The list of sections contained in this object file.
+ //------------------------------------------------------------------
+ virtual SectionList *
+ GetSectionList ();
+
+ virtual void
+ CreateSections (SectionList &unified_section_list) = 0;
+
+ //------------------------------------------------------------------
+ /// Gets the symbol table for the currently selected architecture
+ /// (and object for archives).
+ ///
+ /// Symbol table parsing can be deferred by ObjectFile instances
+ /// until this accessor is called the first time.
+ ///
+ /// @return
+ /// The symbol table for this object file.
+ //------------------------------------------------------------------
+ virtual Symtab *
+ GetSymtab () = 0;
+
+ //------------------------------------------------------------------
+ /// Detect if this object file has been stripped of local symbols.
+ ///
+ /// @return
+ /// Return \b true if the object file has been stripped of local
+ /// symbols.
+ //------------------------------------------------------------------
+ virtual bool
+ IsStripped () = 0;
+
+ //------------------------------------------------------------------
+ /// Frees the symbol table.
+ ///
+ /// This function should only be used when an object file is
+ ///
+ /// @param[in] flags
+ /// eSymtabFromUnifiedSectionList: Whether to clear symbol table
+ /// for unified module section list, or object file.
+ ///
+ /// @return
+ /// The symbol table for this object file.
+ //------------------------------------------------------------------
+ virtual void
+ ClearSymtab ();
+
+ //------------------------------------------------------------------
+ /// Gets the UUID for this object file.
+ ///
+ /// If the object file format contains a UUID, the value should be
+ /// returned. Else ObjectFile instances should return the MD5
+ /// checksum of all of the bytes for the object file (or memory for
+ /// memory based object files).
+ ///
+ /// @return
+ /// Returns \b true if a UUID was successfully extracted into
+ /// \a uuid, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ GetUUID (lldb_private::UUID* uuid) = 0;
+
+ //------------------------------------------------------------------
+ /// Gets the symbol file spec list for this object file.
+ ///
+ /// If the object file format contains a debug symbol file link,
+ /// the values will be return in the FileSpecList.
+ ///
+ /// @return
+ /// Returns filespeclist.
+ //------------------------------------------------------------------
+ virtual lldb_private::FileSpecList
+ GetDebugSymbolFilePaths()
+ {
+ return FileSpecList();
+ }
+
+ //------------------------------------------------------------------
+ /// Gets whether endian swapping should occur when extracting data
+ /// from this object file.
+ ///
+ /// @return
+ /// Returns \b true if endian swapping is needed, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual lldb::ByteOrder
+ GetByteOrder () const = 0;
+
+ //------------------------------------------------------------------
+ /// Attempts to parse the object header.
+ ///
+ /// This function is used as a test to see if a given plug-in
+ /// instance can parse the header data already contained in
+ /// ObjectFile::m_data. If an object file parser does not
+ /// recognize that magic bytes in a header, false should be returned
+ /// and the next plug-in can attempt to parse an object file.
+ ///
+ /// @return
+ /// Returns \b true if the header was parsed succesfully, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ParseHeader () = 0;
+
+ //------------------------------------------------------------------
+ /// Returns a reference to the UnwindTable for this ObjectFile
+ ///
+ /// The UnwindTable contains FuncUnwinders objects for any function in
+ /// this ObjectFile. If a FuncUnwinders object hasn't been created yet
+ /// (i.e. the function has yet to be unwound in a stack walk), it
+ /// will be created when requested. Specifically, we do not create
+ /// FuncUnwinders objects for functions until they are needed.
+ ///
+ /// @return
+ /// Returns the unwind table for this object file.
+ //------------------------------------------------------------------
+ virtual lldb_private::UnwindTable&
+ GetUnwindTable () { return m_unwind_table; }
+
+ //------------------------------------------------------------------
+ /// Similar to Process::GetImageInfoAddress().
+ ///
+ /// Some platforms embed auxiliary structures useful to debuggers in the
+ /// address space of the inferior process. This method returns the address
+ /// of such a structure if the information can be resolved via entries in
+ /// the object file. ELF, for example, provides a means to hook into the
+ /// runtime linker so that a debugger may monitor the loading and unloading
+ /// of shared libraries.
+ ///
+ /// @return
+ /// The address of any auxiliary tables, or an invalid address if this
+ /// object file format does not support or contain such information.
+ virtual lldb_private::Address
+ GetImageInfoAddress () { return Address(); }
+
+ //------------------------------------------------------------------
+ /// Returns the address of the Entry Point in this object file - if
+ /// the object file doesn't have an entry point (because it is not an
+ /// executable file) then an invalid address is returned.
+ ///
+ /// @return
+ /// Returns the entry address for this module.
+ //------------------------------------------------------------------
+ virtual lldb_private::Address
+ GetEntryPointAddress () { return Address();}
+
+ //------------------------------------------------------------------
+ /// Returns the address that represents the header of this object
+ /// file.
+ ///
+ /// The header address is defined as where the header for the object
+ /// file is that describes the content of the file. If the header
+ /// doesn't appear in a section that is defined in the object file,
+ /// an address with no section is returned that has the file offset
+ /// set in the m_file_offset member of the lldb_private::Address object.
+ ///
+ /// @return
+ /// Returns the entry address for this module.
+ //------------------------------------------------------------------
+ virtual lldb_private::Address
+ GetHeaderAddress () { return Address(m_memory_addr);}
+
+
+ virtual uint32_t
+ GetNumThreadContexts ()
+ {
+ return 0;
+ }
+
+ virtual lldb::RegisterContextSP
+ GetThreadContextAtIndex (uint32_t idx, lldb_private::Thread &thread)
+ {
+ return lldb::RegisterContextSP();
+ }
+
+ //------------------------------------------------------------------
+ /// The object file should be able to calculate its type by looking
+ /// at its file header and possibly the sections or other data in
+ /// the object file. The file type is used in the debugger to help
+ /// select the correct plug-ins for the job at hand, so this is
+ /// important to get right. If any eTypeXXX definitions do not match
+ /// up with the type of file you are loading, please feel free to
+ /// add a new enumeration value.
+ ///
+ /// @return
+ /// The calculated file type for the current object file.
+ //------------------------------------------------------------------
+ virtual Type
+ CalculateType() = 0;
+
+ //------------------------------------------------------------------
+ /// In cases where the type can't be calculated (elf files), this
+ /// routine allows someone to explicitly set it. As an example,
+ /// SymbolVendorELF uses this routine to set eTypeDebugInfo when
+ /// loading debug link files.
+ virtual void
+ SetType (Type type)
+ {
+ m_type = type;
+ }
+
+ //------------------------------------------------------------------
+ /// The object file should be able to calculate the strata of the
+ /// object file.
+ ///
+ /// Many object files for platforms might be for either user space
+ /// debugging or for kernel debugging. If your object file subclass
+ /// can figure this out, it will help with debugger plug-in selection
+ /// when it comes time to debug.
+ ///
+ /// @return
+ /// The calculated object file strata for the current object
+ /// file.
+ //------------------------------------------------------------------
+ virtual Strata
+ CalculateStrata() = 0;
+
+ //------------------------------------------------------------------
+ /// Get the object file version numbers.
+ ///
+ /// Many object files have a set of version numbers that describe
+ /// the version of the executable or shared library. Typically there
+ /// are major, minor and build, but there may be more. This function
+ /// will extract the versions from object files if they are available.
+ ///
+ /// If \a versions is NULL, or if \a num_versions is 0, the return
+ /// value will indicate how many version numbers are available in
+ /// this object file. Then a subsequent call can be made to this
+ /// function with a value of \a versions and \a num_versions that
+ /// has enough storage to store some or all version numbers.
+ ///
+ /// @param[out] versions
+ /// A pointer to an array of uint32_t types that is \a num_versions
+ /// long. If this value is NULL, the return value will indicate
+ /// how many version numbers are required for a subsequent call
+ /// to this function so that all versions can be retrieved. If
+ /// the value is non-NULL, then at most \a num_versions of the
+ /// existing versions numbers will be filled into \a versions.
+ /// If there is no version information available, \a versions
+ /// will be filled with \a num_versions UINT32_MAX values
+ /// and zero will be returned.
+ ///
+ /// @param[in] num_versions
+ /// The maximum number of entries to fill into \a versions. If
+ /// this value is zero, then the return value will indicate
+ /// how many version numbers there are in total so another call
+ /// to this function can be make with adequate storage in
+ /// \a versions to get all of the version numbers. If \a
+ /// num_versions is less than the actual number of version
+ /// numbers in this object file, only \a num_versions will be
+ /// filled into \a versions (if \a versions is non-NULL).
+ ///
+ /// @return
+ /// This function always returns the number of version numbers
+ /// that this object file has regardless of the number of
+ /// version numbers that were copied into \a versions.
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetVersion (uint32_t *versions, uint32_t num_versions)
+ {
+ if (versions && num_versions)
+ {
+ for (uint32_t i=0; i<num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ return 0;
+ }
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ Type
+ GetType ()
+ {
+ if (m_type == eTypeInvalid)
+ m_type = CalculateType();
+ return m_type;
+ }
+
+ Strata
+ GetStrata ()
+ {
+ if (m_strata == eStrataInvalid)
+ m_strata = CalculateStrata();
+ return m_strata;
+ }
+
+ // When an object file is in memory, subclasses should try and lock
+ // the process weak pointer. If the process weak pointer produces a
+ // valid ProcessSP, then subclasses can call this function to read
+ // memory.
+ static lldb::DataBufferSP
+ ReadMemory (const lldb::ProcessSP &process_sp,
+ lldb::addr_t addr,
+ size_t byte_size);
+
+ size_t
+ GetData (off_t offset, size_t length, DataExtractor &data) const;
+
+ size_t
+ CopyData (off_t offset, size_t length, void *dst) const;
+
+ size_t
+ ReadSectionData (const Section *section,
+ off_t section_offset,
+ void *dst,
+ size_t dst_len) const;
+ size_t
+ ReadSectionData (const Section *section,
+ DataExtractor& section_data) const;
+
+ size_t
+ MemoryMapSectionData (const Section *section,
+ DataExtractor& section_data) const;
+
+ bool
+ IsInMemory () const
+ {
+ return m_memory_addr != LLDB_INVALID_ADDRESS;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ FileSpec m_file;
+ Type m_type;
+ Strata m_strata;
+ lldb::addr_t m_file_offset; ///< The offset in bytes into the file, or the address in memory
+ lldb::addr_t m_length; ///< The length of this object file if it is known (can be zero if length is unknown or can't be determined).
+ DataExtractor m_data; ///< The data for this object file so things can be parsed lazily.
+ lldb_private::UnwindTable m_unwind_table; /// < Table of FuncUnwinders objects created for this ObjectFile's functions
+ lldb::ProcessWP m_process_wp;
+ const lldb::addr_t m_memory_addr;
+ std::unique_ptr<lldb_private::SectionList> m_sections_ap;
+ std::unique_ptr<lldb_private::Symtab> m_symtab_ap;
+
+ //------------------------------------------------------------------
+ /// Sets the architecture for a module. At present the architecture
+ /// can only be set if it is invalid. It is not allowed to switch from
+ /// one concrete architecture to another.
+ ///
+ /// @param[in] new_arch
+ /// The architecture this module will be set to.
+ ///
+ /// @return
+ /// Returns \b true if the architecture was changed, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool SetModulesArchitecture (const ArchSpec &new_arch);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (ObjectFile);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ObjectFile_h_
+
diff --git a/include/lldb/Symbol/Symbol.h b/include/lldb/Symbol/Symbol.h
new file mode 100644
index 000000000000..11c1cc7af9ab
--- /dev/null
+++ b/include/lldb/Symbol/Symbol.h
@@ -0,0 +1,317 @@
+//===-- Symbol.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_Symbol_h_
+#define liblldb_Symbol_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+
+namespace lldb_private {
+
+class Symbol :
+ public SymbolContextScope
+{
+public:
+ // ObjectFile readers can classify their symbol table entries and searches can be made
+ // on specific types where the symbol values will have drastically different meanings
+ // and sorting requirements.
+ Symbol();
+
+ Symbol (uint32_t symID,
+ const char *name,
+ bool name_is_mangled,
+ lldb::SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const lldb::SectionSP &section_sp,
+ lldb::addr_t value,
+ lldb::addr_t size,
+ bool size_is_valid,
+ uint32_t flags);
+
+ Symbol (uint32_t symID,
+ const char *name,
+ bool name_is_mangled,
+ lldb::SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const AddressRange &range,
+ bool size_is_valid,
+ uint32_t flags);
+
+ Symbol (const Symbol& rhs);
+
+ const Symbol&
+ operator= (const Symbol& rhs);
+
+ void
+ Clear();
+
+ bool
+ Compare (const ConstString& name, lldb::SymbolType type) const;
+
+ void
+ Dump (Stream *s, Target *target, uint32_t index) const;
+
+ bool
+ ValueIsAddress() const;
+
+ //------------------------------------------------------------------
+ // Access the address value. Do NOT hand out the AddressRange as an
+ // object as the byte size of the address range may not be filled in
+ // and it should be accessed via GetByteSize().
+ //------------------------------------------------------------------
+ Address &
+ GetAddress()
+ {
+ return m_addr_range.GetBaseAddress();
+ }
+
+ //------------------------------------------------------------------
+ // Access the address value. Do NOT hand out the AddressRange as an
+ // object as the byte size of the address range may not be filled in
+ // and it should be accessed via GetByteSize().
+ //------------------------------------------------------------------
+ const Address &
+ GetAddress() const
+ {
+ return m_addr_range.GetBaseAddress();
+ }
+
+ const ConstString &
+ GetName () const
+ {
+ return m_mangled.GetName();
+ }
+
+ uint32_t
+ GetID() const
+ {
+ return m_uid;
+ }
+
+ void
+ SetID(uint32_t uid)
+ {
+ m_uid = uid;
+ }
+
+ Mangled&
+ GetMangled ()
+ {
+ return m_mangled;
+ }
+
+ const Mangled&
+ GetMangled () const
+ {
+ return m_mangled;
+ }
+
+ uint32_t
+ GetSiblingIndex () const;
+
+ lldb::SymbolType
+ GetType () const
+ {
+ return (lldb::SymbolType)m_type;
+ }
+
+ void
+ SetType (lldb::SymbolType type)
+ {
+ m_type = (lldb::SymbolType)type;
+ }
+
+ const char *
+ GetTypeAsString () const;
+
+ uint32_t
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ void
+ SetFlags (uint32_t flags)
+ {
+ m_flags = flags;
+ }
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const;
+
+ bool
+ IsSynthetic () const
+ {
+ return m_is_synthetic;
+ }
+
+ void
+ SetIsSynthetic (bool b)
+ {
+ m_is_synthetic = b;
+ }
+
+
+ bool
+ GetSizeIsSynthesized() const
+ {
+ return m_size_is_synthesized;
+ }
+
+ void
+ SetSizeIsSynthesized(bool b)
+ {
+ m_size_is_synthesized = b;
+ }
+
+ bool
+ IsDebug () const
+ {
+ return m_is_debug;
+ }
+
+ void
+ SetDebug (bool b)
+ {
+ m_is_debug = b;
+ }
+
+ bool
+ IsExternal () const
+ {
+ return m_is_external;
+ }
+
+ void
+ SetExternal (bool b)
+ {
+ m_is_external = b;
+ }
+
+ bool
+ IsTrampoline () const;
+
+ bool
+ IsIndirect () const;
+
+ bool
+ GetByteSizeIsValid () const
+ {
+ return m_size_is_valid;
+ }
+
+ lldb::addr_t
+ GetByteSize () const;
+
+ void
+ SetByteSize (lldb::addr_t size)
+ {
+ m_size_is_valid = size > 0;
+ m_addr_range.SetByteSize(size);
+ }
+
+ bool
+ GetSizeIsSibling () const
+ {
+ return m_size_is_sibling;
+ }
+
+ void
+ SetSizeIsSibling (bool b)
+ {
+ m_size_is_sibling = b;
+ }
+
+// void
+// SetValue (Address &value)
+// {
+// m_addr_range.GetBaseAddress() = value;
+// }
+//
+// void
+// SetValue (const AddressRange &range)
+// {
+// m_addr_range = range;
+// }
+//
+// void
+// SetValue (lldb::addr_t value);
+// {
+// m_addr_range.GetBaseAddress().SetRawAddress(value);
+// }
+
+ // If m_type is "Code" or "Function" then this will return the prologue size
+ // in bytes, else it will return zero.
+ uint32_t
+ GetPrologueByteSize ();
+
+ bool
+ GetDemangledNameIsSynthesized() const
+ {
+ return m_demangled_is_synthesized;
+ }
+ void
+ SetDemangledNameIsSynthesized(bool b)
+ {
+ m_demangled_is_synthesized = b;
+ }
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::CalculateSymbolContext(SymbolContext*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext (SymbolContext *sc);
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ();
+
+ virtual Symbol *
+ CalculateSymbolContextSymbol ();
+
+ //------------------------------------------------------------------
+ /// @copydoc SymbolContextScope::DumpSymbolContext(Stream*)
+ ///
+ /// @see SymbolContextScope
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext (Stream *s);
+
+protected:
+
+ uint32_t m_uid; // User ID (usually the original symbol table index)
+ uint16_t m_type_data; // data specific to m_type
+ uint16_t m_type_data_resolved:1, // True if the data in m_type_data has already been calculated
+ m_is_synthetic:1, // non-zero if this symbol is not actually in the symbol table, but synthesized from other info in the object file.
+ m_is_debug:1, // non-zero if this symbol is debug information in a symbol
+ m_is_external:1, // non-zero if this symbol is globally visible
+ m_size_is_sibling:1, // m_size contains the index of this symbol's sibling
+ m_size_is_synthesized:1,// non-zero if this symbol's size was calculated using a delta between this symbol and the next
+ m_size_is_valid:1,
+ m_demangled_is_synthesized:1, // The demangled name was created should not be used for expressions or other lookups
+ m_type:8;
+ Mangled m_mangled; // uniqued symbol name/mangled name pair
+ AddressRange m_addr_range; // Contains the value, or the section offset address when the value is an address in a section, and the size (if any)
+ uint32_t m_flags; // A copy of the flags from the original symbol table, the ObjectFile plug-in can interpret these
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Symbol_h_
diff --git a/include/lldb/Symbol/SymbolContext.h b/include/lldb/Symbol/SymbolContext.h
new file mode 100644
index 000000000000..5b12adebf5f5
--- /dev/null
+++ b/include/lldb/Symbol/SymbolContext.h
@@ -0,0 +1,566 @@
+//===-- SymbolContext.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_SymbolContext_h_
+#define liblldb_SymbolContext_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/LineEntry.h"
+
+namespace lldb_private {
+
+class SymbolContextScope;
+//----------------------------------------------------------------------
+/// @class SymbolContext SymbolContext.h "lldb/Symbol/SymbolContext.h"
+/// @brief Defines a symbol context baton that can be handed other debug
+/// core functions.
+///
+/// Many debugger functions require a context when doing lookups. This
+/// class provides a common structure that can be used as the result
+/// of a query that can contain a single result. Examples of such
+/// queries include
+/// @li Looking up a load address.
+//----------------------------------------------------------------------
+class SymbolContext
+{
+public:
+
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize all pointer members to NULL and all struct members
+ /// to their default state.
+ //------------------------------------------------------------------
+ SymbolContext ();
+
+ //------------------------------------------------------------------
+ /// Construct with an object that knows how to reconstruct its
+ /// symbol context.
+ ///
+ /// @param[in] sc_scope
+ /// A symbol context scope object that knows how to reconstruct
+ /// it's context.
+ //------------------------------------------------------------------
+ explicit
+ SymbolContext (SymbolContextScope *sc_scope);
+
+ //------------------------------------------------------------------
+ /// Construct with module, and optional compile unit, function,
+ /// block, line table, line entry and symbol.
+ ///
+ /// Initialize all pointer to the specified values.
+ ///
+ /// @param[in] module
+ /// A Module pointer to the module for this context.
+ ///
+ /// @param[in] comp_unit
+ /// A CompileUnit pointer to the compile unit for this context.
+ ///
+ /// @param[in] function
+ /// A Function pointer to the function for this context.
+ ///
+ /// @param[in] block
+ /// A Block pointer to the deepest block for this context.
+ ///
+ /// @param[in] line_entry
+ /// A LineEntry pointer to the line entry for this context.
+ ///
+ /// @param[in] symbol
+ /// A Symbol pointer to the symbol for this context.
+ //------------------------------------------------------------------
+ explicit
+ SymbolContext (const lldb::TargetSP &target_sp,
+ const lldb::ModuleSP &module_sp,
+ CompileUnit *comp_unit = NULL,
+ Function *function = NULL,
+ Block *block = NULL,
+ LineEntry *line_entry = NULL,
+ Symbol *symbol = NULL);
+
+ // This version sets the target to a NULL TargetSP if you don't know it.
+ explicit
+ SymbolContext (const lldb::ModuleSP &module_sp,
+ CompileUnit *comp_unit = NULL,
+ Function *function = NULL,
+ Block *block = NULL,
+ LineEntry *line_entry = NULL,
+ Symbol *symbol = NULL);
+
+ ~SymbolContext ();
+ //------------------------------------------------------------------
+ /// Copy constructor
+ ///
+ /// Makes a copy of the another SymbolContext object \a rhs.
+ ///
+ /// @param[in] rhs
+ /// A const SymbolContext object reference to copy.
+ //------------------------------------------------------------------
+ SymbolContext (const SymbolContext& rhs);
+
+ //------------------------------------------------------------------
+ /// Assignment operator.
+ ///
+ /// Copies the address value from another SymbolContext object \a
+ /// rhs into \a this object.
+ ///
+ /// @param[in] rhs
+ /// A const SymbolContext object reference to copy.
+ ///
+ /// @return
+ /// A const SymbolContext object reference to \a this.
+ //------------------------------------------------------------------
+ const SymbolContext&
+ operator= (const SymbolContext& rhs);
+
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Resets all pointer members to NULL, and clears any class objects
+ /// to their default state.
+ //------------------------------------------------------------------
+ void
+ Clear (bool clear_target);
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Dump the stop context in this object to a Stream.
+ ///
+ /// Dump the best description of this object to the stream. The
+ /// information displayed depends on the amount and quality of the
+ /// information in this context. If a module, function, file and
+ /// line number are available, they will be dumped. If only a
+ /// module and function or symbol name with offset is available,
+ /// that will be output. Else just the address at which the target
+ /// was stopped will be displayed.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ ///
+ /// @param[in] so_addr
+ /// The resolved section offset address.
+ //------------------------------------------------------------------
+ bool
+ DumpStopContext (Stream *s,
+ ExecutionContextScope *exe_scope,
+ const Address &so_addr,
+ bool show_fullpaths,
+ bool show_module,
+ bool show_inlined_frames) const;
+
+ //------------------------------------------------------------------
+ /// Get the address range contained within a symbol context.
+ ///
+ /// Address range priority is as follows:
+ /// - line_entry address range if line_entry is valid and eSymbolContextLineEntry is set in \a scope
+ /// - block address range if block is not NULL and eSymbolContextBlock is set in \a scope
+ /// - function address range if function is not NULL and eSymbolContextFunction is set in \a scope
+ /// - symbol address range if symbol is not NULL and eSymbolContextSymbol is set in \a scope
+ ///
+ /// @param[in] scope
+ /// A mask of symbol context bits telling this function which
+ /// address ranges it can use when trying to extract one from
+ /// the valid (non-NULL) symbol context classes.
+ ///
+ /// @param[in] range_idx
+ /// The address range index to grab. Since many functions and
+ /// blocks are not always contiguous, they may have more than
+ /// one address range.
+ ///
+ /// @param[in] use_inline_block_range
+ /// If \a scope has the eSymbolContextBlock bit set, and there
+ /// is a valid block in the symbol context, return the block
+ /// address range for the containing inline function block, not
+ /// the deepest most block. This allows us to extract information
+ /// for the address range of the inlined function block, not
+ /// the deepest lexical block.
+ ///
+ /// @param[out] range
+ /// An address range object that will be filled in if \b true
+ /// is returned.
+ ///
+ /// @return
+ /// \b True if this symbol context contains items that describe
+ /// an address range, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetAddressRange (uint32_t scope,
+ uint32_t range_idx,
+ bool use_inline_block_range,
+ AddressRange &range) const;
+
+
+ void
+ GetDescription(Stream *s,
+ lldb::DescriptionLevel level,
+ Target *target) const;
+
+ uint32_t
+ GetResolvedMask () const;
+
+
+ //------------------------------------------------------------------
+ /// Find a block that defines the function represented by this
+ /// symbol context.
+ ///
+ /// If this symbol context points to a block that is an inlined
+ /// function, or is contained within an inlined function, the block
+ /// that defines the inlined function is returned.
+ ///
+ /// If this symbol context has no block in it, or the block is not
+ /// itself an inlined function block or contained within one, we
+ /// return the top level function block.
+ ///
+ /// This is a handy function to call when you want to get the block
+ /// whose variable list will include the arguments for the function
+ /// that is represented by this symbol context (whether the function
+ /// is an inline function or not).
+ ///
+ /// @return
+ /// The block object pointer that defines the function that is
+ /// represented by this symbol context object, NULL otherwise.
+ //------------------------------------------------------------------
+ Block *
+ GetFunctionBlock ();
+
+
+ //------------------------------------------------------------------
+ /// If this symbol context represents a function that is a method,
+ /// return true and provide information about the method.
+ ///
+ /// @param[out] language
+ /// If \b true is returned, the language for the method.
+ ///
+ /// @param[out] is_instance_method
+ /// If \b true is returned, \b true if this is a instance method,
+ /// \b false if this is a static/class function.
+ ///
+ /// @param[out] language_object_name
+ /// If \b true is returned, the name of the artificial variable
+ /// for the language ("this" for C++, "self" for ObjC).
+ ///
+ /// @return
+ /// \b True if this symbol context represents a function that
+ /// is a method of a class, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetFunctionMethodInfo (lldb::LanguageType &language,
+ bool &is_instance_method,
+ ConstString &language_object_name);
+
+ //------------------------------------------------------------------
+ /// Find a name of the innermost function for the symbol context.
+ ///
+ /// For instance, if the symbol context contains an inlined block,
+ /// it will return the inlined function name.
+ ///
+ /// @param[in] prefer_mangled
+ /// if \btrue, then the mangled name will be returned if there
+ /// is one. Otherwise the unmangled name will be returned if it
+ /// is available.
+ ///
+ /// @return
+ /// The name of the function represented by this symbol context.
+ //------------------------------------------------------------------
+ ConstString
+ GetFunctionName (Mangled::NamePreference preference = Mangled::ePreferDemangled) const;
+
+
+ //------------------------------------------------------------------
+ /// Get the line entry that corresponds to the function.
+ ///
+ /// If the symbol context contains an inlined block, the line entry
+ /// for the start address of the inlined function will be returned,
+ /// otherwise the line entry for the start address of the function
+ /// will be returned. This can be used after doing a
+ /// Module::FindFunctions(...) or ModuleList::FindFunctions(...)
+ /// call in order to get the correct line table information for
+ /// the symbol context.
+ /// it will return the inlined function name.
+ ///
+ /// @param[in] prefer_mangled
+ /// if \btrue, then the mangled name will be returned if there
+ /// is one. Otherwise the unmangled name will be returned if it
+ /// is available.
+ ///
+ /// @return
+ /// The name of the function represented by this symbol context.
+ //------------------------------------------------------------------
+ LineEntry
+ GetFunctionStartLineEntry () const;
+
+ //------------------------------------------------------------------
+ /// Find the block containing the inlined block that contains this block.
+ ///
+ /// For instance, if the symbol context contains an inlined block,
+ /// it will return the inlined function name.
+ ///
+ /// @param[in] curr_frame_pc
+ /// The address within the block of this object.
+ ///
+ /// @param[out] next_frame_sc
+ /// A new symbol context that does what the title says it does.
+ ///
+ /// @param[out] next_frame_addr
+ /// This is what you should report as the PC in \a next_frame_sc.
+ ///
+ /// @return
+ /// \b true if this SymbolContext specifies a block contained in an
+ /// inlined block. If this returns \b true, \a next_frame_sc and
+ /// \a next_frame_addr will be filled in correctly.
+ //------------------------------------------------------------------
+ bool
+ GetParentOfInlinedScope (const Address &curr_frame_pc,
+ SymbolContext &next_frame_sc,
+ Address &inlined_frame_addr) const;
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::TargetSP target_sp; ///< The Target for a given query
+ lldb::ModuleSP module_sp; ///< The Module for a given query
+ CompileUnit * comp_unit; ///< The CompileUnit for a given query
+ Function * function; ///< The Function for a given query
+ Block * block; ///< The Block for a given query
+ LineEntry line_entry; ///< The LineEntry for a given query
+ Symbol * symbol; ///< The Symbol for a given query
+};
+
+
+class SymbolContextSpecifier
+{
+public:
+ typedef enum SpecificationType
+ {
+ eNothingSpecified = 0,
+ eModuleSpecified = 1 << 0,
+ eFileSpecified = 1 << 1,
+ eLineStartSpecified = 1 << 2,
+ eLineEndSpecified = 1 << 3,
+ eFunctionSpecified = 1 << 4,
+ eClassOrNamespaceSpecified = 1 << 5,
+ eAddressRangeSpecified = 1 << 6
+ } SpecificationType;
+
+ // This one produces a specifier that matches everything...
+ SymbolContextSpecifier (const lldb::TargetSP& target_sp);
+
+ ~SymbolContextSpecifier();
+
+ bool
+ AddSpecification (const char *spec_string, SpecificationType type);
+
+ bool
+ AddLineSpecification (uint32_t line_no, SpecificationType type);
+
+ void
+ Clear();
+
+ bool
+ SymbolContextMatches(SymbolContext &sc);
+
+ bool
+ AddressMatches(lldb::addr_t addr);
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+private:
+ lldb::TargetSP m_target_sp;
+ std::string m_module_spec;
+ lldb::ModuleSP m_module_sp;
+ std::unique_ptr<FileSpec> m_file_spec_ap;
+ size_t m_start_line;
+ size_t m_end_line;
+ std::string m_function_spec;
+ std::string m_class_name;
+ std::unique_ptr<AddressRange> m_address_range_ap;
+ uint32_t m_type; // Or'ed bits from SpecificationType
+
+};
+
+//----------------------------------------------------------------------
+/// @class SymbolContextList SymbolContext.h "lldb/Symbol/SymbolContext.h"
+/// @brief Defines a list of symbol context objects.
+///
+/// This class provides a common structure that can be used to contain
+/// the result of a query that can contain a multiple results. Examples
+/// of such queries include:
+/// @li Looking up a function by name.
+/// @li Finding all addressses for a specified file and line number.
+//----------------------------------------------------------------------
+class SymbolContextList
+{
+public:
+ //------------------------------------------------------------------
+ /// Default constructor.
+ ///
+ /// Initialize with an empty list.
+ //------------------------------------------------------------------
+ SymbolContextList ();
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ //------------------------------------------------------------------
+ ~SymbolContextList ();
+
+ //------------------------------------------------------------------
+ /// Append a new symbol context to the list.
+ ///
+ /// @param[in] sc
+ /// A symbol context to append to the list.
+ //------------------------------------------------------------------
+ void
+ Append (const SymbolContext& sc);
+
+ void
+ Append (const SymbolContextList& sc_list);
+
+ bool
+ AppendIfUnique (const SymbolContext& sc,
+ bool merge_symbol_into_function);
+
+ bool
+ MergeSymbolContextIntoFunctionContext (const SymbolContext& symbol_sc,
+ uint32_t start_idx = 0,
+ uint32_t stop_idx = UINT32_MAX);
+
+ uint32_t
+ AppendIfUnique (const SymbolContextList& sc_list,
+ bool merge_symbol_into_function);
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Clears the symbol context list.
+ //------------------------------------------------------------------
+ void
+ Clear();
+
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of each symbol context in
+ /// the list to the supplied stream \a s.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump(Stream *s, Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Get accessor for a symbol context at index \a idx.
+ ///
+ /// Dump a description of the contents of each symbol context in
+ /// the list to the supplied stream \a s.
+ ///
+ /// @param[in] idx
+ /// The zero based index into the symbol context list.
+ ///
+ /// @param[out] sc
+ /// A reference to the symbol context to fill in.
+ ///
+ /// @return
+ /// Returns \b true if \a idx was a valid index into this
+ /// symbol context list and \a sc was filled in, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ bool
+ GetContextAtIndex(size_t idx, SymbolContext& sc) const;
+
+ //------------------------------------------------------------------
+ /// Direct reference accessor for a symbol context at index \a idx.
+ ///
+ /// The index \a idx must be a valid index, no error checking will
+ /// be done to ensure that it is valid.
+ ///
+ /// @param[in] idx
+ /// The zero based index into the symbol context list.
+ ///
+ /// @return
+ /// A const reference to the symbol context to fill in.
+ //------------------------------------------------------------------
+ SymbolContext&
+ operator [] (size_t idx)
+ {
+ return m_symbol_contexts[idx];
+ }
+
+ const SymbolContext&
+ operator [] (size_t idx) const
+ {
+ return m_symbol_contexts[idx];
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the last symbol context in the list.
+ ///
+ /// @param[out] sc
+ /// A reference to the symbol context to fill in.
+ ///
+ /// @return
+ /// Returns \b true if \a sc was filled in, \b false if the
+ /// list is empty.
+ //------------------------------------------------------------------
+ bool
+ GetLastContext(SymbolContext& sc) const;
+
+ bool
+ RemoveContextAtIndex (size_t idx);
+ //------------------------------------------------------------------
+ /// Get accessor for a symbol context list size.
+ ///
+ /// @return
+ /// Returns the number of symbol context objects in the list.
+ //------------------------------------------------------------------
+ uint32_t
+ GetSize() const;
+
+ uint32_t
+ NumLineEntriesWithLine (uint32_t line) const;
+
+ void
+ GetDescription(Stream *s,
+ lldb::DescriptionLevel level,
+ Target *target) const;
+
+protected:
+ typedef std::vector<SymbolContext> collection; ///< The collection type for the list.
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ collection m_symbol_contexts; ///< The list of symbol contexts.
+};
+
+bool operator== (const SymbolContext& lhs, const SymbolContext& rhs);
+bool operator!= (const SymbolContext& lhs, const SymbolContext& rhs);
+
+bool operator== (const SymbolContextList& lhs, const SymbolContextList& rhs);
+bool operator!= (const SymbolContextList& lhs, const SymbolContextList& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolContext_h_
diff --git a/include/lldb/Symbol/SymbolContextScope.h b/include/lldb/Symbol/SymbolContextScope.h
new file mode 100644
index 000000000000..693cc0131e27
--- /dev/null
+++ b/include/lldb/Symbol/SymbolContextScope.h
@@ -0,0 +1,137 @@
+//===-- SymbolContextScope.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_SymbolContextScope_h_
+#define liblldb_SymbolContextScope_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class SymbolContextScope SymbolContextScope.h "lldb/Symbol/SymbolContextScope.h"
+/// @brief Inherit from this if your object is part of a symbol context
+/// and can reconstruct its symbol context.
+///
+/// Many objects that are part of a symbol context that have pointers
+/// back to parent objects that own them. Any members of a symbol
+/// context that, once they are built, will not go away, can inherit
+/// from this pure virtual class and can then reconstruct their symbol
+/// context without having to keep a complete SymbolContext object in
+/// the object.
+///
+/// Examples of these objects include:
+/// @li Module
+/// @li CompileUnit
+/// @li Function
+/// @li Block
+/// @li Symbol
+///
+/// Other objects can store a "SymbolContextScope *" using any pointers
+/// to one of the above objects. This allows clients to hold onto a
+/// pointer that uniquely will identify a symbol context. Those clients
+/// can then always reconstruct the symbol context using the pointer, or
+/// use it to uniquely identify a symbol context for an object.
+///
+/// Example objects include that currently use "SymbolContextScope *"
+/// objects include:
+/// @li Variable objects that can reconstruct where they are scoped
+/// by making sure the SymbolContextScope * comes from the scope
+/// in which the variable was declared. If a variable is a global,
+/// the appropriate CompileUnit * will be used when creating the
+/// variable. A static function variables, can the Block scope
+/// in which the variable is defined. Function arguments can use
+/// the Function object as their scope. The SymbolFile parsers
+/// will set these correctly as the variables are parsed.
+/// @li Type objects that know exactly in which scope they
+/// originated much like the variables above.
+/// @li StackID objects that are able to know that if the CFA
+/// (stack pointer at the beginning of a function) and the
+/// start PC for the function/symbol and the SymbolContextScope
+/// pointer (a unique pointer that identifies a symbol context
+/// location) match within the same thread, that the stack
+/// frame is the same as the previous stack frame.
+///
+/// Objects that adhere to this protocol can reconstruct enough of a
+/// symbol context to allow functions that take a symbol context to be
+/// called. Lists can also be created using a SymbolContextScope* and
+/// and object pairs that allow large collections of objects to be
+/// passed around with minimal overhead.
+//----------------------------------------------------------------------
+class SymbolContextScope
+{
+public:
+ virtual
+ ~SymbolContextScope () {}
+
+ //------------------------------------------------------------------
+ /// Reconstruct the object's symbolc context into \a sc.
+ ///
+ /// The object should fill in as much of the SymbolContext as it
+ /// can so function calls that require a symbol context can be made
+ /// for the given object.
+ ///
+ /// @param[out] sc
+ /// A symbol context object pointer that gets filled in.
+ //------------------------------------------------------------------
+ virtual void
+ CalculateSymbolContext (SymbolContext *sc) = 0;
+
+
+ virtual lldb::ModuleSP
+ CalculateSymbolContextModule ()
+ {
+ return lldb::ModuleSP();
+ }
+
+ virtual CompileUnit *
+ CalculateSymbolContextCompileUnit ()
+ {
+ return NULL;
+ }
+
+ virtual Function *
+ CalculateSymbolContextFunction ()
+ {
+ return NULL;
+ }
+
+ virtual Block *
+ CalculateSymbolContextBlock ()
+ {
+ return NULL;
+ }
+
+ virtual Symbol *
+ CalculateSymbolContextSymbol ()
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Dump the object's symbolc context to the stream \a s.
+ ///
+ /// The object should dump its symbol context to the stream \a s.
+ /// This function is widely used in the DumpDebug and verbose output
+ /// for lldb objets.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object's symbol context.
+ //------------------------------------------------------------------
+ virtual void
+ DumpSymbolContext (Stream *s) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolContextScope_h_
diff --git a/include/lldb/Symbol/SymbolFile.h b/include/lldb/Symbol/SymbolFile.h
new file mode 100644
index 000000000000..5b774e3a7d13
--- /dev/null
+++ b/include/lldb/Symbol/SymbolFile.h
@@ -0,0 +1,167 @@
+//===-- SymbolFile.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_SymbolFile_h_
+#define liblldb_SymbolFile_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Type.h"
+
+namespace lldb_private {
+
+class SymbolFile :
+ public PluginInterface
+{
+public:
+ //------------------------------------------------------------------
+ // Symbol file ability bits.
+ //
+ // Each symbol file can claim to support one or more symbol file
+ // abilities. These get returned from SymbolFile::GetAbilities().
+ // These help us to determine which plug-in will be best to load
+ // the debug information found in files.
+ //------------------------------------------------------------------
+ enum Abilities
+ {
+ CompileUnits = (1u << 0),
+ LineTables = (1u << 1),
+ Functions = (1u << 2),
+ Blocks = (1u << 3),
+ GlobalVariables = (1u << 4),
+ LocalVariables = (1u << 5),
+ VariableTypes = (1u << 6),
+ kAllAbilities =((1u << 7) - 1u)
+ };
+
+ static SymbolFile *
+ FindPlugin (ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFile(ObjectFile* obj_file) :
+ m_obj_file(obj_file),
+ m_abilities(0),
+ m_calculated_abilities(false)
+ {
+ }
+
+ virtual
+ ~SymbolFile()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Get a mask of what this symbol file supports for the object file
+ /// that it was constructed with.
+ ///
+ /// Each symbol file gets to respond with a mask of abilities that
+ /// it supports for each object file. This happens when we are
+ /// trying to figure out which symbol file plug-in will get used
+ /// for a given object file. The plug-in that resoonds with the
+ /// best mix of "SymbolFile::Abilities" bits set, will get chosen to
+ /// be the symbol file parser. This allows each plug-in to check for
+ /// sections that contain data a symbol file plug-in would need. For
+ /// example the DWARF plug-in requires DWARF sections in a file that
+ /// contain debug information. If the DWARF plug-in doesn't find
+ /// these sections, it won't respond with many ability bits set, and
+ /// we will probably fall back to the symbol table SymbolFile plug-in
+ /// which uses any information in the symbol table. Also, plug-ins
+ /// might check for some specific symbols in a symbol table in the
+ /// case where the symbol table contains debug information (STABS
+ /// and COFF). Not a lot of work should happen in these functions
+ /// as the plug-in might not get selected due to another plug-in
+ /// having more abilities. Any initialization work should be saved
+ /// for "void SymbolFile::InitializeObject()" which will get called
+ /// on the SymbolFile object with the best set of abilities.
+ ///
+ /// @return
+ /// A uint32_t mask containing bits from the SymbolFile::Abilities
+ /// enumeration. Any bits that are set represent an ability that
+ /// this symbol plug-in can parse from the object file.
+ ///------------------------------------------------------------------
+ uint32_t GetAbilities ()
+ {
+ if (!m_calculated_abilities)
+ {
+ m_abilities = CalculateAbilities();
+ m_calculated_abilities = true;
+ }
+
+ return m_abilities;
+ }
+
+ virtual uint32_t CalculateAbilities() = 0;
+
+ //------------------------------------------------------------------
+ /// Initialize the SymbolFile object.
+ ///
+ /// The SymbolFile object with the best set of abilities (detected
+ /// in "uint32_t SymbolFile::GetAbilities()) will have this function
+ /// called if it is chosen to parse an object file. More complete
+ /// initialization can happen in this function which will get called
+ /// prior to any other functions in the SymbolFile protocol.
+ //------------------------------------------------------------------
+ virtual void InitializeObject() {}
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ // Approach 1 - iterator
+ virtual uint32_t GetNumCompileUnits() = 0;
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index) = 0;
+
+ virtual lldb::LanguageType ParseCompileUnitLanguage (const SymbolContext& sc) = 0;
+ virtual size_t ParseCompileUnitFunctions (const SymbolContext& sc) = 0;
+ virtual bool ParseCompileUnitLineTable (const SymbolContext& sc) = 0;
+ virtual bool ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files) = 0;
+ virtual size_t ParseFunctionBlocks (const SymbolContext& sc) = 0;
+ virtual size_t ParseTypes (const SymbolContext& sc) = 0;
+ virtual size_t ParseVariablesForContext (const SymbolContext& sc) = 0;
+ virtual Type* ResolveTypeUID (lldb::user_id_t type_uid) = 0;
+ virtual bool ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type) = 0;
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid) { return NULL; }
+ virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid) { return NULL; }
+ virtual uint32_t ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) = 0;
+ virtual uint32_t ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) = 0;
+ virtual uint32_t FindGlobalVariables (const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables) = 0;
+ virtual uint32_t FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables) = 0;
+ virtual uint32_t FindFunctions (const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list) = 0;
+ virtual uint32_t FindFunctions (const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list) = 0;
+ virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, TypeList& types) = 0;
+// virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types) = 0;
+ virtual TypeList * GetTypeList ();
+ virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list) = 0;
+ virtual ClangASTContext &
+ GetClangASTContext ();
+ virtual ClangNamespaceDecl
+ FindNamespace (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *parent_namespace_decl) = 0;
+
+ ObjectFile* GetObjectFile() { return m_obj_file; }
+ const ObjectFile* GetObjectFile() const { return m_obj_file; }
+
+protected:
+ ObjectFile* m_obj_file; // The object file that symbols can be extracted from.
+ uint32_t m_abilities;
+ bool m_calculated_abilities;
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFile);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolFile_h_
diff --git a/include/lldb/Symbol/SymbolVendor.h b/include/lldb/Symbol/SymbolVendor.h
new file mode 100644
index 000000000000..0eeea4eb466b
--- /dev/null
+++ b/include/lldb/Symbol/SymbolVendor.h
@@ -0,0 +1,207 @@
+//===-- SymbolVendor.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_SymbolVendor_h_
+#define liblldb_SymbolVendor_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ModuleChild.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/TypeList.h"
+
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// The symbol vendor class is designed to abstract the process of
+// searching for debug information for a given module. Platforms can
+// subclass this class and provide extra ways to find debug information.
+// Examples would be a subclass that would allow for locating a stand
+// alone debug file, parsing debug maps, or runtime data in the object
+// files. A symbol vendor can use multiple sources (SymbolFile
+// objects) to provide the information and only parse as deep as needed
+// in order to provide the information that is requested.
+//----------------------------------------------------------------------
+class SymbolVendor :
+ public ModuleChild,
+ public PluginInterface
+{
+public:
+ static SymbolVendor*
+ FindPlugin (const lldb::ModuleSP &module_sp,
+ Stream *feedback_strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendor(const lldb::ModuleSP &module_sp);
+
+ virtual
+ ~SymbolVendor();
+
+ void
+ AddSymbolFileRepresentation(const lldb::ObjectFileSP &objfile_sp);
+
+ virtual void
+ Dump(Stream *s);
+
+ virtual lldb::LanguageType
+ ParseCompileUnitLanguage (const SymbolContext& sc);
+
+ virtual size_t
+ ParseCompileUnitFunctions (const SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitLineTable (const SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitSupportFiles (const SymbolContext& sc,
+ FileSpecList& support_files);
+
+ virtual size_t
+ ParseFunctionBlocks (const SymbolContext& sc);
+
+ virtual size_t
+ ParseTypes (const SymbolContext& sc);
+
+ virtual size_t
+ ParseVariablesForContext (const SymbolContext& sc);
+
+ virtual Type*
+ ResolveTypeUID(lldb::user_id_t type_uid);
+
+ virtual uint32_t
+ ResolveSymbolContext (const Address& so_addr,
+ uint32_t resolve_scope,
+ SymbolContext& sc);
+
+ virtual uint32_t
+ ResolveSymbolContext (const FileSpec& file_spec,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list);
+
+ virtual size_t
+ FindGlobalVariables (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ VariableList& variables);
+
+ virtual size_t
+ FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variables);
+
+ virtual size_t
+ FindFunctions (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list);
+
+ virtual size_t
+ FindFunctions (const RegularExpression& regex,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list);
+
+ virtual size_t
+ FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ TypeList& types);
+
+ virtual ClangNamespaceDecl
+ FindNamespace (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *parent_namespace_decl);
+
+ virtual size_t
+ GetNumCompileUnits();
+
+ virtual bool
+ SetCompileUnitAtIndex (size_t cu_idx,
+ const lldb::CompUnitSP &cu_sp);
+
+ virtual lldb::CompUnitSP
+ GetCompileUnitAtIndex(size_t idx);
+
+ TypeList&
+ GetTypeList()
+ {
+ return m_type_list;
+ }
+
+ const TypeList&
+ GetTypeList() const
+ {
+ return m_type_list;
+ }
+
+ virtual size_t
+ GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ TypeList &type_list);
+
+ SymbolFile *
+ GetSymbolFile()
+ {
+ return m_sym_file_ap.get();
+ }
+
+ // Get module unified section list symbol table.
+ virtual Symtab *
+ GetSymtab ();
+
+ // Clear module unified section list symbol table.
+ virtual void
+ ClearSymtab ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from SymbolVendor can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector<lldb::CompUnitSP> CompileUnits;
+ typedef CompileUnits::iterator CompileUnitIter;
+ typedef CompileUnits::const_iterator CompileUnitConstIter;
+
+ TypeList m_type_list; // Uniqued types for all parsers owned by this module
+ CompileUnits m_compile_units; // The current compile units
+ lldb::ObjectFileSP m_objfile_sp; // Keep a reference to the object file in case it isn't the same as the module object file (debug symbols in a separate file)
+ std::unique_ptr<SymbolFile> m_sym_file_ap; // A single symbol file. Subclasses can add more of these if needed.
+
+private:
+ //------------------------------------------------------------------
+ // For SymbolVendor only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendor);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_SymbolVendor_h_
diff --git a/include/lldb/Symbol/Symtab.h b/include/lldb/Symbol/Symtab.h
new file mode 100644
index 000000000000..666c3b5686b9
--- /dev/null
+++ b/include/lldb/Symbol/Symtab.h
@@ -0,0 +1,160 @@
+//===-- Symtab.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_Symtab_h_
+#define liblldb_Symtab_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/Symbol.h"
+
+namespace lldb_private {
+
+class Symtab
+{
+public:
+ typedef std::vector<uint32_t> IndexCollection;
+ typedef UniqueCStringMap<uint32_t> NameToIndexMap;
+
+ typedef enum Debug {
+ eDebugNo, // Not a debug symbol
+ eDebugYes, // A debug symbol
+ eDebugAny
+ } Debug;
+
+ typedef enum Visibility {
+ eVisibilityAny,
+ eVisibilityExtern,
+ eVisibilityPrivate
+ } Visibility;
+
+ Symtab(ObjectFile *objfile);
+ ~Symtab();
+
+ void Reserve (size_t count);
+ Symbol * Resize (size_t count);
+ uint32_t AddSymbol(const Symbol& symbol);
+ size_t GetNumSymbols() const;
+ void Dump(Stream *s, Target *target, SortOrder sort_type);
+ void Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const;
+ uint32_t GetIndexForSymbol (const Symbol *symbol) const;
+ Mutex & GetMutex ()
+ {
+ return m_mutex;
+ }
+ Symbol * FindSymbolByID (lldb::user_id_t uid) const;
+ Symbol * SymbolAtIndex (size_t idx);
+ const Symbol * SymbolAtIndex (size_t idx) const;
+ Symbol * FindSymbolWithType (lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, uint32_t &start_idx);
+ uint32_t AppendSymbolIndexesWithType (lldb::SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
+ uint32_t AppendSymbolIndexesWithTypeAndFlagsValue (lldb::SymbolType symbol_type, uint32_t flags_value, std::vector<uint32_t>& indexes, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
+ uint32_t AppendSymbolIndexesWithType (lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& matches, uint32_t start_idx = 0, uint32_t end_index = UINT32_MAX) const;
+ uint32_t AppendSymbolIndexesWithName (const ConstString& symbol_name, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesWithName (const ConstString& symbol_name, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, lldb::SymbolType symbol_type, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& matches);
+ uint32_t AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regex, lldb::SymbolType symbol_type, std::vector<uint32_t>& indexes);
+ uint32_t AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regex, lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes);
+ size_t FindAllSymbolsWithNameAndType (const ConstString &name, lldb::SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes);
+ size_t FindAllSymbolsWithNameAndType (const ConstString &name, lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes);
+ size_t FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes);
+ Symbol * FindFirstSymbolWithNameAndType (const ConstString &name, lldb::SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility);
+ Symbol * FindSymbolContainingFileAddress (lldb::addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes);
+ Symbol * FindSymbolContainingFileAddress (lldb::addr_t file_addr);
+ size_t FindFunctionSymbols (const ConstString &name, uint32_t name_type_mask, SymbolContextList& sc_list);
+ void CalculateSymbolSizes ();
+
+ void SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const;
+
+ static void DumpSymbolHeader (Stream *s);
+
+
+ void Finalize ()
+ {
+ // Shrink to fit the symbols so we don't waste memory
+ if (m_symbols.capacity() > m_symbols.size())
+ {
+ collection new_symbols (m_symbols.begin(), m_symbols.end());
+ m_symbols.swap (new_symbols);
+ }
+ }
+
+ void AppendSymbolNamesToMap (const IndexCollection &indexes,
+ bool add_demangled,
+ bool add_mangled,
+ NameToIndexMap &name_to_index_map) const;
+
+protected:
+ typedef std::vector<Symbol> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ typedef RangeDataVector<lldb::addr_t, lldb::addr_t, uint32_t> FileRangeToIndexMap;
+ void InitNameIndexes ();
+ void InitAddressIndexes ();
+
+ ObjectFile * m_objfile;
+ collection m_symbols;
+ FileRangeToIndexMap m_file_addr_to_index;
+ UniqueCStringMap<uint32_t> m_name_to_index;
+ UniqueCStringMap<uint32_t> m_basename_to_index;
+ UniqueCStringMap<uint32_t> m_method_to_index;
+ UniqueCStringMap<uint32_t> m_selector_to_index;
+ mutable Mutex m_mutex; // Provide thread safety for this symbol table
+ bool m_file_addr_to_index_computed:1,
+ m_name_indexes_computed:1;
+private:
+
+ bool
+ CheckSymbolAtIndex (size_t idx, Debug symbol_debug_type, Visibility symbol_visibility) const
+ {
+ switch (symbol_debug_type)
+ {
+ case eDebugNo:
+ if (m_symbols[idx].IsDebug() == true)
+ return false;
+ break;
+
+ case eDebugYes:
+ if (m_symbols[idx].IsDebug() == false)
+ return false;
+ break;
+
+ case eDebugAny:
+ break;
+ }
+
+ switch (symbol_visibility)
+ {
+ case eVisibilityAny:
+ return true;
+
+ case eVisibilityExtern:
+ return m_symbols[idx].IsExternal();
+
+ case eVisibilityPrivate:
+ return !m_symbols[idx].IsExternal();
+ }
+ return false;
+ }
+
+ void
+ SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes,
+ SymbolContextList &sc_list);
+
+ DISALLOW_COPY_AND_ASSIGN (Symtab);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Symtab_h_
diff --git a/include/lldb/Symbol/TaggedASTType.h b/include/lldb/Symbol/TaggedASTType.h
new file mode 100644
index 000000000000..c44a5356f86d
--- /dev/null
+++ b/include/lldb/Symbol/TaggedASTType.h
@@ -0,0 +1,61 @@
+//===-- TaggedASTType.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_TaggedASTType_h_
+#define liblldb_TaggedASTType_h_
+
+#include "lldb/Symbol/ClangASTType.h"
+
+namespace lldb_private
+{
+
+// For cases in which there are multiple classes of types that are not
+// interchangeable, to allow static type checking.
+template <unsigned int C> class TaggedASTType : public ClangASTType
+{
+public:
+ TaggedASTType (const ClangASTType &clang_type) :
+ ClangASTType(clang_type)
+ {
+ }
+
+ TaggedASTType (lldb::clang_type_t type, clang::ASTContext *ast_context) :
+ ClangASTType(ast_context, type)
+ {
+ }
+
+ TaggedASTType (const TaggedASTType<C> &tw) :
+ ClangASTType(tw)
+ {
+ }
+
+ TaggedASTType () :
+ ClangASTType()
+ {
+ }
+
+ virtual
+ ~TaggedASTType()
+ {
+ }
+
+ TaggedASTType<C> &operator= (const TaggedASTType<C> &tw)
+ {
+ ClangASTType::operator= (tw);
+ return *this;
+ }
+};
+
+// Commonly-used tagged types, so code using them is interoperable
+typedef TaggedASTType<0> TypeFromParser;
+typedef TaggedASTType<1> TypeFromUser;
+
+}
+
+#endif
diff --git a/include/lldb/Symbol/Type.h b/include/lldb/Symbol/Type.h
new file mode 100644
index 000000000000..50b22fe96b9d
--- /dev/null
+++ b/include/lldb/Symbol/Type.h
@@ -0,0 +1,596 @@
+//===-- Type.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_Type_h_
+#define liblldb_Type_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/Declaration.h"
+
+#include <set>
+
+namespace lldb_private {
+
+class SymbolFileType :
+ public std::enable_shared_from_this<SymbolFileType>,
+ public UserID
+ {
+ public:
+ SymbolFileType (SymbolFile &symbol_file, lldb::user_id_t uid) :
+ UserID (uid),
+ m_symbol_file (symbol_file)
+ {
+ }
+
+ ~SymbolFileType ()
+ {
+ }
+
+ Type *
+ operator->()
+ {
+ return GetType ();
+ }
+
+ Type *
+ GetType ();
+
+ protected:
+ SymbolFile &m_symbol_file;
+ lldb::TypeSP m_type_sp;
+ };
+
+class Type :
+ public std::enable_shared_from_this<Type>,
+ public UserID
+{
+public:
+ typedef enum EncodingDataTypeTag
+ {
+ eEncodingInvalid,
+ eEncodingIsUID, ///< This type is the type whose UID is m_encoding_uid
+ eEncodingIsConstUID, ///< This type is the type whose UID is m_encoding_uid with the const qualifier added
+ eEncodingIsRestrictUID, ///< This type is the type whose UID is m_encoding_uid with the restrict qualifier added
+ eEncodingIsVolatileUID, ///< This type is the type whose UID is m_encoding_uid with the volatile qualifier added
+ eEncodingIsTypedefUID, ///< This type is pointer to a type whose UID is m_encoding_uid
+ eEncodingIsPointerUID, ///< This type is pointer to a type whose UID is m_encoding_uid
+ eEncodingIsLValueReferenceUID, ///< This type is L value reference to a type whose UID is m_encoding_uid
+ eEncodingIsRValueReferenceUID, ///< This type is R value reference to a type whose UID is m_encoding_uid
+ eEncodingIsSyntheticUID
+ } EncodingDataType;
+
+ typedef enum ResolveStateTag
+ {
+ eResolveStateUnresolved = 0,
+ eResolveStateForward = 1,
+ eResolveStateLayout = 2,
+ eResolveStateFull = 3
+ } ResolveState;
+
+ Type (lldb::user_id_t uid,
+ SymbolFile* symbol_file,
+ const ConstString &name,
+ uint64_t byte_size,
+ SymbolContextScope *context,
+ lldb::user_id_t encoding_uid,
+ EncodingDataType encoding_uid_type,
+ const Declaration& decl,
+ const ClangASTType &clang_qual_type,
+ ResolveState clang_type_resolve_state);
+
+ // This makes an invalid type. Used for functions that return a Type when they
+ // get an error.
+ Type();
+
+ Type (const Type &rhs);
+
+ const Type&
+ operator= (const Type& rhs);
+
+ void
+ Dump(Stream *s, bool show_context);
+
+ void
+ DumpTypeName(Stream *s);
+
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_name);
+
+ SymbolFile *
+ GetSymbolFile()
+ {
+ return m_symbol_file;
+ }
+ const SymbolFile *
+ GetSymbolFile() const
+ {
+ return m_symbol_file;
+ }
+
+ TypeList*
+ GetTypeList();
+
+ const ConstString&
+ GetName();
+
+ uint64_t
+ GetByteSize();
+
+ uint32_t
+ GetNumChildren (bool omit_empty_base_classes);
+
+ bool
+ IsAggregateType ();
+
+ bool
+ IsValidType ()
+ {
+ return m_encoding_uid_type != eEncodingInvalid;
+ }
+
+ bool
+ IsTypedef ()
+ {
+ return m_encoding_uid_type == eEncodingIsTypedefUID;
+ }
+
+ lldb::TypeSP
+ GetTypedefType();
+
+ const ConstString &
+ GetName () const
+ {
+ return m_name;
+ }
+
+ ConstString
+ GetQualifiedName ();
+
+ void
+ DumpValue(ExecutionContext *exe_ctx,
+ Stream *s,
+ const DataExtractor &data,
+ uint32_t data_offset,
+ bool show_type,
+ bool show_summary,
+ bool verbose,
+ lldb::Format format = lldb::eFormatDefault);
+
+ bool
+ DumpValueInMemory(ExecutionContext *exe_ctx,
+ Stream *s,
+ lldb::addr_t address,
+ AddressType address_type,
+ bool show_types,
+ bool show_summary,
+ bool verbose);
+
+ bool
+ ReadFromMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t address,
+ AddressType address_type,
+ DataExtractor &data);
+
+ bool
+ WriteToMemory (ExecutionContext *exe_ctx,
+ lldb::addr_t address,
+ AddressType address_type,
+ DataExtractor &data);
+
+ bool
+ GetIsDeclaration() const;
+
+ void
+ SetIsDeclaration(bool b);
+
+ bool
+ GetIsExternal() const;
+
+ void
+ SetIsExternal(bool b);
+
+ lldb::Format
+ GetFormat ();
+
+ lldb::Encoding
+ GetEncoding (uint64_t &count);
+
+ SymbolContextScope *
+ GetSymbolContextScope()
+ {
+ return m_context;
+ }
+ const SymbolContextScope *
+ GetSymbolContextScope() const
+ {
+ return m_context;
+ }
+ void
+ SetSymbolContextScope(SymbolContextScope *context)
+ {
+ m_context = context;
+ }
+
+ const lldb_private::Declaration &
+ GetDeclaration () const;
+
+ // Get the clang type, and resolve definitions for any
+ // class/struct/union/enum types completely.
+ ClangASTType
+ GetClangFullType ();
+
+ // Get the clang type, and resolve definitions enough so that the type could
+ // have layout performed. This allows ptrs and refs to class/struct/union/enum
+ // types remain forward declarations.
+ ClangASTType
+ GetClangLayoutType ();
+
+ // Get the clang type and leave class/struct/union/enum types as forward
+ // declarations if they haven't already been fully defined.
+ ClangASTType
+ GetClangForwardType ();
+
+ ClangASTContext &
+ GetClangASTContext ();
+
+ static int
+ Compare(const Type &a, const Type &b);
+
+ // From a fully qualified typename, split the type into the type basename
+ // and the remaining type scope (namespaces/classes).
+ static bool
+ GetTypeScopeAndBasename (const char* &name_cstr,
+ std::string &scope,
+ std::string &basename,
+ lldb::TypeClass &type_class);
+ void
+ SetEncodingType (Type *encoding_type)
+ {
+ m_encoding_type = encoding_type;
+ }
+
+ uint32_t
+ GetEncodingMask ();
+
+ ClangASTType
+ CreateClangTypedefType (Type *typedef_type, Type *base_type);
+
+ bool
+ IsRealObjCClass();
+
+ bool
+ IsCompleteObjCClass()
+ {
+ return m_flags.is_complete_objc_class;
+ }
+
+ void
+ SetIsCompleteObjCClass(bool is_complete_objc_class)
+ {
+ m_flags.is_complete_objc_class = is_complete_objc_class;
+ }
+
+protected:
+ ConstString m_name;
+ SymbolFile *m_symbol_file;
+ SymbolContextScope *m_context; // The symbol context in which this type is defined
+ Type *m_encoding_type;
+ lldb::user_id_t m_encoding_uid;
+ EncodingDataType m_encoding_uid_type;
+ uint64_t m_byte_size;
+ Declaration m_decl;
+ ClangASTType m_clang_type;
+
+ struct Flags {
+ ResolveState clang_type_resolve_state : 2;
+ bool is_complete_objc_class : 1;
+ } m_flags;
+
+ Type *
+ GetEncodingType ();
+
+ bool
+ ResolveClangType (ResolveState clang_type_resolve_state);
+};
+
+
+///
+/// Sometimes you can find the name of the type corresponding to an object, but we don't have debug
+/// information for it. If that is the case, you can return one of these objects, and then if it
+/// has a full type, you can use that, but if not at least you can print the name for informational
+/// purposes.
+///
+
+class TypeAndOrName
+{
+public:
+ TypeAndOrName ();
+ TypeAndOrName (lldb::TypeSP &type_sp);
+ TypeAndOrName (const char *type_str);
+ TypeAndOrName (const TypeAndOrName &rhs);
+ TypeAndOrName (ConstString &type_const_string);
+
+ TypeAndOrName &
+ operator= (const TypeAndOrName &rhs);
+
+ bool
+ operator==(const TypeAndOrName &other) const;
+
+ bool
+ operator!=(const TypeAndOrName &other) const;
+
+ ConstString GetName () const;
+
+ lldb::TypeSP
+ GetTypeSP () const
+ {
+ return m_type_sp;
+ }
+
+ void
+ SetName (const ConstString &type_name);
+
+ void
+ SetName (const char *type_name_cstr);
+
+ void
+ SetTypeSP (lldb::TypeSP type_sp);
+
+ bool
+ IsEmpty ();
+
+ bool
+ HasName ();
+
+ bool
+ HasTypeSP ();
+
+ void
+ Clear ();
+
+ operator
+ bool ()
+ {
+ return !IsEmpty();
+ }
+
+private:
+ lldb::TypeSP m_type_sp;
+ ConstString m_type_name;
+};
+
+// the two classes here are used by the public API as a backend to
+// the SBType and SBTypeList classes
+
+class TypeImpl
+{
+public:
+
+ TypeImpl() :
+ m_clang_ast_type(),
+ m_type_sp()
+ {
+ }
+
+ TypeImpl(const TypeImpl& rhs) :
+ m_clang_ast_type(rhs.m_clang_ast_type),
+ m_type_sp(rhs.m_type_sp)
+ {
+ }
+
+ TypeImpl(const lldb_private::ClangASTType& type);
+
+ TypeImpl(const lldb::TypeSP& type);
+
+ TypeImpl&
+ operator = (const TypeImpl& rhs);
+
+ bool
+ operator == (const TypeImpl& rhs)
+ {
+ return m_clang_ast_type == rhs.m_clang_ast_type && m_type_sp.get() == rhs.m_type_sp.get();
+ }
+
+ bool
+ operator != (const TypeImpl& rhs)
+ {
+ return m_clang_ast_type != rhs.m_clang_ast_type || m_type_sp.get() != rhs.m_type_sp.get();
+ }
+
+ bool
+ IsValid()
+ {
+ return m_type_sp.get() != NULL || m_clang_ast_type.IsValid();
+ }
+
+ const lldb_private::ClangASTType &
+ GetClangASTType() const
+ {
+ return m_clang_ast_type;
+ }
+
+ clang::ASTContext*
+ GetASTContext();
+
+ lldb::clang_type_t
+ GetOpaqueQualType();
+
+ lldb::TypeSP
+ GetTypeSP ()
+ {
+ return m_type_sp;
+ }
+
+ ConstString
+ GetName ();
+
+ bool
+ GetDescription (lldb_private::Stream &strm,
+ lldb::DescriptionLevel description_level);
+
+ void
+ SetType (const lldb::TypeSP &type_sp);
+
+private:
+ ClangASTType m_clang_ast_type;
+ lldb::TypeSP m_type_sp;
+};
+
+class TypeListImpl
+{
+public:
+ TypeListImpl() :
+ m_content()
+ {
+ }
+
+ void
+ Append (const lldb::TypeImplSP& type)
+ {
+ m_content.push_back(type);
+ }
+
+ class AppendVisitor
+ {
+ public:
+ AppendVisitor(TypeListImpl &type_list) :
+ m_type_list(type_list)
+ {
+ }
+
+ void
+ operator() (const lldb::TypeImplSP& type)
+ {
+ m_type_list.Append(type);
+ }
+
+ private:
+ TypeListImpl &m_type_list;
+ };
+
+ void
+ Append (const lldb_private::TypeList &type_list);
+
+ lldb::TypeImplSP
+ GetTypeAtIndex(size_t idx)
+ {
+ lldb::TypeImplSP type_sp;
+ if (idx < GetSize())
+ type_sp = m_content[idx];
+ return type_sp;
+ }
+
+ size_t
+ GetSize()
+ {
+ return m_content.size();
+ }
+
+private:
+ std::vector<lldb::TypeImplSP> m_content;
+};
+
+class TypeMemberImpl
+{
+public:
+ TypeMemberImpl () :
+ m_type_impl_sp (),
+ m_bit_offset (0),
+ m_name (),
+ m_bitfield_bit_size (0),
+ m_is_bitfield (false)
+
+ {
+ }
+
+ TypeMemberImpl (const lldb::TypeImplSP &type_impl_sp,
+ uint64_t bit_offset,
+ const ConstString &name,
+ uint32_t bitfield_bit_size = 0,
+ bool is_bitfield = false) :
+ m_type_impl_sp (type_impl_sp),
+ m_bit_offset (bit_offset),
+ m_name (name),
+ m_bitfield_bit_size (bitfield_bit_size),
+ m_is_bitfield (is_bitfield)
+ {
+ }
+
+ TypeMemberImpl (const lldb::TypeImplSP &type_impl_sp,
+ uint64_t bit_offset):
+ m_type_impl_sp (type_impl_sp),
+ m_bit_offset (bit_offset),
+ m_name (),
+ m_bitfield_bit_size (0),
+ m_is_bitfield (false)
+ {
+ if (m_type_impl_sp)
+ m_name = m_type_impl_sp->GetName();
+ }
+
+ const lldb::TypeImplSP &
+ GetTypeImpl ()
+ {
+ return m_type_impl_sp;
+ }
+
+ const ConstString &
+ GetName () const
+ {
+ return m_name;
+ }
+
+ uint64_t
+ GetBitOffset () const
+ {
+ return m_bit_offset;
+ }
+
+ uint32_t
+ GetBitfieldBitSize () const
+ {
+ return m_bitfield_bit_size;
+ }
+
+ void
+ SetBitfieldBitSize (uint32_t bitfield_bit_size)
+ {
+ m_bitfield_bit_size = bitfield_bit_size;
+ }
+
+ bool
+ GetIsBitfield () const
+ {
+ return m_is_bitfield;
+ }
+
+ void
+ SetIsBitfield (bool is_bitfield)
+ {
+ m_is_bitfield = is_bitfield;
+ }
+
+protected:
+ lldb::TypeImplSP m_type_impl_sp;
+ uint64_t m_bit_offset;
+ ConstString m_name;
+ uint32_t m_bitfield_bit_size; // Bit size for bitfield members only
+ bool m_is_bitfield;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_Type_h_
+
diff --git a/include/lldb/Symbol/TypeList.h b/include/lldb/Symbol/TypeList.h
new file mode 100644
index 000000000000..9c74db6bf1f4
--- /dev/null
+++ b/include/lldb/Symbol/TypeList.h
@@ -0,0 +1,88 @@
+//===-- TypeList.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_TypeList_h_
+#define liblldb_TypeList_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/Type.h"
+#include <map>
+
+namespace lldb_private {
+
+class TypeList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ TypeList();
+
+ virtual
+ ~TypeList();
+
+ void
+ Clear();
+
+ void
+ Dump(Stream *s, bool show_context);
+
+// lldb::TypeSP
+// FindType(lldb::user_id_t uid);
+
+ TypeList
+ FindTypes(const ConstString &name);
+
+ void
+ Insert (const lldb::TypeSP& type);
+
+ bool
+ InsertUnique (const lldb::TypeSP& type);
+
+ uint32_t
+ GetSize() const;
+
+ lldb::TypeSP
+ GetTypeAtIndex(uint32_t idx);
+
+ void
+ ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const;
+
+ void
+ ForEach (std::function <bool(lldb::TypeSP &type_sp)> const &callback);
+
+ bool
+ RemoveTypeWithUID (lldb::user_id_t uid);
+
+ void
+ RemoveMismatchedTypes (const char *qualified_typename,
+ bool exact_match);
+
+ void
+ RemoveMismatchedTypes (const std::string &type_scope,
+ const std::string &type_basename,
+ lldb::TypeClass type_class,
+ bool exact_match);
+
+ void
+ RemoveMismatchedTypes (lldb::TypeClass type_class);
+
+private:
+ typedef std::multimap<lldb::user_id_t, lldb::TypeSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_types;
+
+ DISALLOW_COPY_AND_ASSIGN (TypeList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_TypeList_h_
diff --git a/include/lldb/Symbol/TypeVendor.h b/include/lldb/Symbol/TypeVendor.h
new file mode 100644
index 000000000000..559b21eeb95a
--- /dev/null
+++ b/include/lldb/Symbol/TypeVendor.h
@@ -0,0 +1,61 @@
+//===-- TypeVendor.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_TypeVendor_h_
+#define liblldb_TypeVendor_h_
+
+#include "lldb/Core/ClangForward.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// The type vendor class is intended as a generic interface to search
+// for Clang types that are not necessarily backed by a specific symbol
+// file.
+//----------------------------------------------------------------------
+class TypeVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ TypeVendor()
+ {
+ }
+
+ virtual
+ ~TypeVendor()
+ {
+ }
+
+ virtual uint32_t
+ FindTypes (const ConstString &name,
+ bool append,
+ uint32_t max_matches,
+ std::vector <ClangASTType> &types) = 0;
+
+ virtual clang::ASTContext *
+ GetClangASTContext () = 0;
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from TypeVendor can see and modify these
+ //------------------------------------------------------------------
+
+private:
+ //------------------------------------------------------------------
+ // For TypeVendor only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (TypeVendor);
+};
+
+
+} // namespace lldb_private
+
+#endif
diff --git a/include/lldb/Symbol/UnwindPlan.h b/include/lldb/Symbol/UnwindPlan.h
new file mode 100644
index 000000000000..6fc5ce042357
--- /dev/null
+++ b/include/lldb/Symbol/UnwindPlan.h
@@ -0,0 +1,499 @@
+#ifndef liblldb_UnwindPlan_h
+#define liblldb_UnwindPlan_h
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ConstString.h"
+
+#include <map>
+#include <vector>
+
+namespace lldb_private {
+
+// The UnwindPlan object specifies how to unwind out of a function - where
+// this function saves the caller's register values before modifying them
+// (for non-volatile aka saved registers) and how to find this frame's
+// Canonical Frame Address (CFA).
+
+// Most commonly, registers are saved on the stack, offset some bytes from
+// the Canonical Frame Address, or CFA, which is the starting address of
+// this function's stack frame (the CFA is same as the eh_frame's CFA,
+// whatever that may be on a given architecture).
+// The CFA address for the stack frame does not change during
+// the lifetime of the function.
+
+// Internally, the UnwindPlan is structured as a vector of register locations
+// organized by code address in the function, showing which registers have been
+// saved at that point and where they are saved.
+// It can be thought of as the expanded table form of the DWARF CFI
+// encoded information.
+
+// Other unwind information sources will be converted into UnwindPlans before
+// being added to a FuncUnwinders object. The unwind source may be
+// an eh_frame FDE, a DWARF debug_frame FDE, or assembly language based
+// prologue analysis.
+// The UnwindPlan is the canonical form of this information that the unwinder
+// code will use when walking the stack.
+
+class UnwindPlan {
+public:
+
+ class Row {
+ public:
+ class RegisterLocation
+ {
+ public:
+
+ enum RestoreType
+ {
+ unspecified, // not specified, we may be able to assume this
+ // is the same register. gcc doesn't specify all
+ // initial values so we really don't know...
+ undefined, // reg is not available, e.g. volatile reg
+ same, // reg is unchanged
+ atCFAPlusOffset, // reg = deref(CFA + offset)
+ isCFAPlusOffset, // reg = CFA + offset
+ inOtherRegister, // reg = other reg
+ atDWARFExpression, // reg = deref(eval(dwarf_expr))
+ isDWARFExpression // reg = eval(dwarf_expr)
+ };
+
+ RegisterLocation() :
+ m_type(unspecified),
+ m_location()
+ {
+ }
+
+ bool
+ operator == (const RegisterLocation& rhs) const;
+
+ bool
+ operator != (const RegisterLocation &rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ void
+ SetUnspecified()
+ {
+ m_type = unspecified;
+ }
+
+ void
+ SetUndefined()
+ {
+ m_type = undefined;
+ }
+
+ void
+ SetSame()
+ {
+ m_type = same;
+ }
+
+ bool
+ IsSame () const
+ {
+ return m_type == same;
+ }
+
+ bool
+ IsUnspecified () const
+ {
+ return m_type == unspecified;
+ }
+
+ bool
+ IsCFAPlusOffset () const
+ {
+ return m_type == isCFAPlusOffset;
+ }
+
+ bool
+ IsAtCFAPlusOffset () const
+ {
+ return m_type == atCFAPlusOffset;
+ }
+
+ bool
+ IsInOtherRegister () const
+ {
+ return m_type == inOtherRegister;
+ }
+
+ bool
+ IsAtDWARFExpression () const
+ {
+ return m_type == atDWARFExpression;
+ }
+
+ bool
+ IsDWARFExpression () const
+ {
+ return m_type == isDWARFExpression;
+ }
+
+ void
+ SetAtCFAPlusOffset (int32_t offset)
+ {
+ m_type = atCFAPlusOffset;
+ m_location.offset = offset;
+ }
+
+ void
+ SetIsCFAPlusOffset (int32_t offset)
+ {
+ m_type = isCFAPlusOffset;
+ m_location.offset = offset;
+ }
+
+ void
+ SetInRegister (uint32_t reg_num)
+ {
+ m_type = inOtherRegister;
+ m_location.reg_num = reg_num;
+ }
+
+ uint32_t
+ GetRegisterNumber () const
+ {
+ if (m_type == inOtherRegister)
+ return m_location.reg_num;
+ return LLDB_INVALID_REGNUM;
+ }
+
+ RestoreType
+ GetLocationType () const
+ {
+ return m_type;
+ }
+
+ int32_t
+ GetOffset () const
+ {
+ if (m_type == atCFAPlusOffset || m_type == isCFAPlusOffset)
+ return m_location.offset;
+ return 0;
+ }
+
+ void
+ GetDWARFExpr (const uint8_t **opcodes, uint16_t& len) const
+ {
+ if (m_type == atDWARFExpression || m_type == isDWARFExpression)
+ {
+ *opcodes = m_location.expr.opcodes;
+ len = m_location.expr.length;
+ }
+ else
+ {
+ *opcodes = NULL;
+ len = 0;
+ }
+ }
+
+ void
+ SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len);
+
+ void
+ SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len);
+
+ const uint8_t *
+ GetDWARFExpressionBytes ()
+ {
+ if (m_type == atDWARFExpression || m_type == isDWARFExpression)
+ return m_location.expr.opcodes;
+ return NULL;
+ }
+
+ int
+ GetDWARFExpressionLength ()
+ {
+ if (m_type == atDWARFExpression || m_type == isDWARFExpression)
+ return m_location.expr.length;
+ return 0;
+ }
+
+ void
+ Dump (Stream &s,
+ const UnwindPlan* unwind_plan,
+ const UnwindPlan::Row* row,
+ Thread* thread,
+ bool verbose) const;
+
+ private:
+ RestoreType m_type; // How do we locate this register?
+ union
+ {
+ // For m_type == atCFAPlusOffset or m_type == isCFAPlusOffset
+ int32_t offset;
+ // For m_type == inOtherRegister
+ uint32_t reg_num; // The register number
+ // For m_type == atDWARFExpression or m_type == isDWARFExpression
+ struct {
+ const uint8_t *opcodes;
+ uint16_t length;
+ } expr;
+ } m_location;
+ };
+
+ public:
+ Row ();
+
+ Row (const UnwindPlan::Row& rhs) :
+ m_offset (rhs.m_offset),
+ m_cfa_reg_num (rhs.m_cfa_reg_num),
+ m_cfa_offset (rhs.m_cfa_offset),
+ m_register_locations (rhs.m_register_locations)
+ {
+ }
+
+ bool
+ operator == (const Row &rhs) const;
+
+ bool
+ GetRegisterInfo (uint32_t reg_num, RegisterLocation& register_location) const;
+
+ void
+ SetRegisterInfo (uint32_t reg_num, const RegisterLocation register_location);
+
+ lldb::addr_t
+ GetOffset() const
+ {
+ return m_offset;
+ }
+
+ void
+ SetOffset(lldb::addr_t offset)
+ {
+ m_offset = offset;
+ }
+
+ void
+ SlideOffset(lldb::addr_t offset)
+ {
+ m_offset += offset;
+ }
+
+ uint32_t
+ GetCFARegister () const
+ {
+ return m_cfa_reg_num;
+ }
+
+ bool
+ SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num,
+ int32_t offset,
+ bool can_replace);
+
+ bool
+ SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num,
+ int32_t offset,
+ bool can_replace);
+
+ bool
+ SetRegisterLocationToUndefined (uint32_t reg_num,
+ bool can_replace,
+ bool can_replace_only_if_unspecified);
+
+ bool
+ SetRegisterLocationToUnspecified (uint32_t reg_num,
+ bool can_replace);
+
+ bool
+ SetRegisterLocationToRegister (uint32_t reg_num,
+ uint32_t other_reg_num,
+ bool can_replace);
+
+ bool
+ SetRegisterLocationToSame (uint32_t reg_num,
+ bool must_replace);
+
+
+
+ void
+ SetCFARegister (uint32_t reg_num);
+
+ int32_t
+ GetCFAOffset () const
+ {
+ return m_cfa_offset;
+ }
+
+ void
+ SetCFAOffset (int32_t offset)
+ {
+ m_cfa_offset = offset;
+ }
+
+ void
+ Clear ();
+
+ void
+ Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, lldb::addr_t base_addr) const;
+
+ protected:
+ typedef std::map<uint32_t, RegisterLocation> collection;
+ lldb::addr_t m_offset; // Offset into the function for this row
+ uint32_t m_cfa_reg_num; // The Call Frame Address register number
+ int32_t m_cfa_offset; // The offset from the CFA for this row
+ collection m_register_locations;
+ }; // class Row
+
+public:
+
+ typedef std::shared_ptr<Row> RowSP;
+
+ UnwindPlan (lldb::RegisterKind reg_kind) :
+ m_row_list (),
+ m_plan_valid_address_range (),
+ m_register_kind (reg_kind),
+ m_return_addr_register (LLDB_INVALID_REGNUM),
+ m_source_name (),
+ m_plan_is_sourced_from_compiler (eLazyBoolCalculate),
+ m_plan_is_valid_at_all_instruction_locations (eLazyBoolCalculate)
+ {
+ }
+
+ ~UnwindPlan ()
+ {
+ }
+
+ void
+ Dump (Stream& s, Thread* thread, lldb::addr_t base_addr) const;
+
+ void
+ AppendRow (const RowSP& row_sp);
+
+ // Returns a pointer to the best row for the given offset into the function's instructions.
+ // If offset is -1 it indicates that the function start is unknown - the final row in the UnwindPlan is returned.
+ // In practice, the UnwindPlan for a function with no known start address will be the architectural default
+ // UnwindPlan which will only have one row.
+ UnwindPlan::RowSP
+ GetRowForFunctionOffset (int offset) const;
+
+ lldb::RegisterKind
+ GetRegisterKind () const
+ {
+ return m_register_kind;
+ }
+
+ void
+ SetRegisterKind (lldb::RegisterKind kind)
+ {
+ m_register_kind = kind;
+ }
+
+ void
+ SetReturnAddressRegister (uint32_t regnum)
+ {
+ m_return_addr_register = regnum;
+ }
+
+ uint32_t
+ GetReturnAddressRegister (void)
+ {
+ return m_return_addr_register;
+ }
+
+ uint32_t
+ GetInitialCFARegister () const
+ {
+ if (m_row_list.empty())
+ return LLDB_INVALID_REGNUM;
+ return m_row_list.front()->GetCFARegister();
+ }
+
+ // This UnwindPlan may not be valid at every address of the function span.
+ // For instance, a FastUnwindPlan will not be valid at the prologue setup
+ // instructions - only in the body of the function.
+ void
+ SetPlanValidAddressRange (const AddressRange& range);
+
+ const AddressRange &
+ GetAddressRange () const
+ {
+ return m_plan_valid_address_range;
+ }
+
+ bool
+ PlanValidAtAddress (Address addr);
+
+ bool
+ IsValidRowIndex (uint32_t idx) const;
+
+ const UnwindPlan::RowSP
+ GetRowAtIndex (uint32_t idx) const;
+
+ const UnwindPlan::RowSP
+ GetLastRow () const;
+
+ lldb_private::ConstString
+ GetSourceName () const;
+
+ void
+ SetSourceName (const char *);
+
+ // Was this UnwindPlan emitted by a compiler?
+ lldb_private::LazyBool
+ GetSourcedFromCompiler () const
+ {
+ return m_plan_is_sourced_from_compiler;
+ }
+
+ // Was this UnwindPlan emitted by a compiler?
+ void
+ SetSourcedFromCompiler (lldb_private::LazyBool from_compiler)
+ {
+ m_plan_is_sourced_from_compiler = from_compiler;
+ }
+
+ // Is this UnwindPlan valid at all instructions? If not, then it is assumed valid at call sites,
+ // e.g. for exception handling.
+ lldb_private::LazyBool
+ GetUnwindPlanValidAtAllInstructions () const
+ {
+ return m_plan_is_valid_at_all_instruction_locations;
+ }
+
+ // Is this UnwindPlan valid at all instructions? If not, then it is assumed valid at call sites,
+ // e.g. for exception handling.
+ void
+ SetUnwindPlanValidAtAllInstructions (lldb_private::LazyBool valid_at_all_insn)
+ {
+ m_plan_is_valid_at_all_instruction_locations = valid_at_all_insn;
+ }
+
+ int
+ GetRowCount () const;
+
+ void
+ Clear()
+ {
+ m_row_list.clear();
+ m_plan_valid_address_range.Clear();
+ m_register_kind = lldb::eRegisterKindDWARF;
+ m_source_name.Clear();
+ }
+
+ const RegisterInfo *
+ GetRegisterInfo (Thread* thread, uint32_t reg_num) const;
+
+private:
+
+
+ typedef std::vector<RowSP> collection;
+ collection m_row_list;
+ AddressRange m_plan_valid_address_range;
+ lldb::RegisterKind m_register_kind; // The RegisterKind these register numbers are in terms of - will need to be
+ // translated to lldb native reg nums at unwind time
+ uint32_t m_return_addr_register; // The register that has the return address for the caller frame
+ // e.g. the lr on arm
+ lldb_private::ConstString m_source_name; // for logging, where this UnwindPlan originated from
+ lldb_private::LazyBool m_plan_is_sourced_from_compiler;
+ lldb_private::LazyBool m_plan_is_valid_at_all_instruction_locations;
+}; // class UnwindPlan
+
+} // namespace lldb_private
+
+#endif //liblldb_UnwindPlan_h
diff --git a/include/lldb/Symbol/UnwindTable.h b/include/lldb/Symbol/UnwindTable.h
new file mode 100644
index 000000000000..cefb91eb371a
--- /dev/null
+++ b/include/lldb/Symbol/UnwindTable.h
@@ -0,0 +1,69 @@
+//===-- Symtab.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_UnwindTable_h
+#define liblldb_UnwindTable_h
+
+#include <map>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+// A class which holds all the FuncUnwinders objects for a given ObjectFile.
+// The UnwindTable is populated with FuncUnwinders objects lazily during
+// the debug session.
+
+class UnwindTable
+{
+public:
+ UnwindTable(ObjectFile& objfile);
+ ~UnwindTable();
+
+ lldb_private::DWARFCallFrameInfo *
+ GetEHFrameInfo ();
+
+ lldb::FuncUnwindersSP
+ GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc);
+
+// Normally when we create a new FuncUnwinders object we track it in this UnwindTable so it can
+// be reused later. But for the target modules show-unwind we want to create brand new
+// UnwindPlans for the function of interest - so ignore any existing FuncUnwinders for that
+// function and don't add this new one to our UnwindTable.
+// This FuncUnwinders object does have a reference to the UnwindTable but the lifetime of this
+// uncached FuncUnwinders is expected to be short so in practice this will not be a problem.
+ lldb::FuncUnwindersSP
+ GetUncachedFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc);
+
+private:
+ void
+ Dump (Stream &s);
+
+ void Initialize ();
+
+ typedef std::map<lldb::addr_t, lldb::FuncUnwindersSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ ObjectFile& m_object_file;
+ collection m_unwinds;
+
+ bool m_initialized; // delay some initialization until ObjectFile is set up
+
+ UnwindAssembly* m_assembly_profiler;
+
+ DWARFCallFrameInfo* m_eh_frame;
+
+ DISALLOW_COPY_AND_ASSIGN (UnwindTable);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_UnwindTable_h
diff --git a/include/lldb/Symbol/Variable.h b/include/lldb/Symbol/Variable.h
new file mode 100644
index 000000000000..07295d090ee6
--- /dev/null
+++ b/include/lldb/Symbol/Variable.h
@@ -0,0 +1,184 @@
+//===-- Variable.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_Variable_h_
+#define liblldb_Variable_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Declaration.h"
+
+namespace lldb_private {
+
+class Variable : public UserID
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ Variable (lldb::user_id_t uid,
+ const char *name,
+ const char *mangled, // The mangled variable name for variables in namespaces
+ const lldb::SymbolFileTypeSP &symfile_type_sp,
+ lldb::ValueType scope,
+ SymbolContextScope *owner_scope,
+ Declaration* decl,
+ const DWARFExpression& location,
+ bool external,
+ bool artificial);
+
+ virtual
+ ~Variable();
+
+ void
+ Dump(Stream *s, bool show_context) const;
+
+ bool
+ DumpDeclaration (Stream *s,
+ bool show_fullpaths,
+ bool show_module);
+
+ const Declaration&
+ GetDeclaration() const
+ {
+ return m_declaration;
+ }
+
+ const ConstString&
+ GetName() const;
+
+ SymbolContextScope *
+ GetSymbolContextScope() const
+ {
+ return m_owner_scope;
+ }
+
+ // Since a variable can have a basename "i" and also a mangled
+ // named "_ZN12_GLOBAL__N_11iE" and a demangled mangled name
+ // "(anonymous namespace)::i", this function will allow a generic match
+ // function that can be called by commands and expression parsers to make
+ // sure we match anything we come across.
+ bool
+ NameMatches (const ConstString &name) const
+ {
+ if (m_name == name)
+ return true;
+ return m_mangled.NameMatches (name);
+ }
+
+ bool
+ NameMatches (const RegularExpression& regex) const;
+
+ Type *
+ GetType();
+
+ lldb::ValueType
+ GetScope() const
+ {
+ return m_scope;
+ }
+
+ bool
+ IsExternal() const
+ {
+ return m_external;
+ }
+
+ bool
+ IsArtificial() const
+ {
+ return m_artificial;
+ }
+
+ DWARFExpression &
+ LocationExpression()
+ {
+ return m_location;
+ }
+
+ const DWARFExpression &
+ LocationExpression() const
+ {
+ return m_location;
+ }
+
+ bool
+ DumpLocationForAddress (Stream *s,
+ const Address &address);
+
+ size_t
+ MemorySize() const;
+
+ void
+ CalculateSymbolContext (SymbolContext *sc);
+
+ bool
+ IsInScope (StackFrame *frame);
+
+ bool
+ LocationIsValidForFrame (StackFrame *frame);
+
+ bool
+ LocationIsValidForAddress (const Address &address);
+
+ bool
+ GetLocationIsConstantValueData () const
+ {
+ return m_loc_is_const_data;
+ }
+
+ void
+ SetLocationIsConstantValueData (bool b)
+ {
+ m_loc_is_const_data = b;
+ }
+
+ typedef size_t (*GetVariableCallback) (void *baton,
+ const char *name,
+ VariableList &var_list);
+
+
+ static Error
+ GetValuesForVariableExpressionPath (const char *variable_expr_path,
+ ExecutionContextScope *scope,
+ GetVariableCallback callback,
+ void *baton,
+ VariableList &variable_list,
+ ValueObjectList &valobj_list);
+
+ static size_t
+ AutoComplete (const ExecutionContext &exe_ctx,
+ const char *name,
+ StringList &matches,
+ bool &word_complete);
+
+protected:
+ ConstString m_name; // The basename of the variable (no namespaces)
+ Mangled m_mangled; // The mangled name of the variable
+ lldb::SymbolFileTypeSP m_symfile_type_sp; // The type pointer of the variable (int, struct, class, etc)
+ lldb::ValueType m_scope; // global, parameter, local
+ SymbolContextScope *m_owner_scope; // The symbol file scope that this variable was defined in
+ Declaration m_declaration; // Declaration location for this item.
+ DWARFExpression m_location; // The location of this variable that can be fed to DWARFExpression::Evaluate()
+ uint8_t m_external:1, // Visible outside the containing compile unit?
+ m_artificial:1, // Non-zero if the variable is not explicitly declared in source
+ m_loc_is_const_data:1; // The m_location expression contains the constant variable value data, not a DWARF location
+private:
+ Variable(const Variable& rhs);
+ Variable& operator=(const Variable& rhs);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Variable_h_
diff --git a/include/lldb/Symbol/VariableList.h b/include/lldb/Symbol/VariableList.h
new file mode 100644
index 000000000000..2ce6146f4627
--- /dev/null
+++ b/include/lldb/Symbol/VariableList.h
@@ -0,0 +1,95 @@
+//===-- VariableList.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_VariableList_h_
+#define liblldb_VariableList_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Variable.h"
+
+namespace lldb_private {
+
+class VariableList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+// VariableList(const SymbolContext &symbol_context);
+ VariableList();
+ virtual ~VariableList();
+
+ void
+ AddVariable (const lldb::VariableSP &var_sp);
+
+ bool
+ AddVariableIfUnique (const lldb::VariableSP &var_sp);
+
+ void
+ AddVariables (VariableList *variable_list);
+
+ void
+ Clear();
+
+ void
+ Dump(Stream *s, bool show_context) const;
+
+ lldb::VariableSP
+ GetVariableAtIndex(size_t idx) const;
+
+ lldb::VariableSP
+ RemoveVariableAtIndex (size_t idx);
+
+ lldb::VariableSP
+ FindVariable (const ConstString& name);
+
+ uint32_t
+ FindVariableIndex (const lldb::VariableSP &var_sp);
+
+ // Returns the actual number of unique variables that were added to the
+ // list. "total_matches" will get updated with the actualy number of
+ // matches that were found regardless of whether they were unique or not
+ // to allow for error conditions when nothing is found, versus conditions
+ // where any varaibles that match "regex" were already in "var_list".
+ size_t
+ AppendVariablesIfUnique (const RegularExpression& regex,
+ VariableList &var_list,
+ size_t& total_matches);
+
+ size_t
+ AppendVariablesWithScope (lldb::ValueType type,
+ VariableList &var_list,
+ bool if_unique = true);
+
+ uint32_t
+ FindIndexForVariable (Variable* variable);
+
+ size_t
+ MemorySize() const;
+
+ size_t
+ GetSize() const;
+
+protected:
+ typedef std::vector<lldb::VariableSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_variables;
+private:
+ //------------------------------------------------------------------
+ // For VariableList only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (VariableList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_VariableList_h_
diff --git a/include/lldb/Symbol/VerifyDecl.h b/include/lldb/Symbol/VerifyDecl.h
new file mode 100644
index 000000000000..228e635652e6
--- /dev/null
+++ b/include/lldb/Symbol/VerifyDecl.h
@@ -0,0 +1,20 @@
+//===-- VerifyDecl.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_VariableList_h_
+#define lldb_VariableList_h_
+
+#include "lldb/Core/ClangForward.h"
+
+namespace lldb_private
+{
+ void VerifyDecl (clang::Decl *decl);
+}
+
+#endif
diff --git a/include/lldb/Target/ABI.h b/include/lldb/Target/ABI.h
new file mode 100644
index 000000000000..16f8ee7fc7d7
--- /dev/null
+++ b/include/lldb/Target/ABI.h
@@ -0,0 +1,137 @@
+//===-- ABI.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_ABI_h_
+#define liblldb_ABI_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+class ABI :
+ public PluginInterface
+{
+public:
+ virtual
+ ~ABI();
+
+ virtual size_t
+ GetRedZoneSize () const = 0;
+
+ virtual bool
+ PrepareTrivialCall (Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) const = 0;
+
+ virtual bool
+ GetArgumentValues (Thread &thread,
+ ValueList &values) const = 0;
+
+ lldb::ValueObjectSP
+ GetReturnValueObject (Thread &thread,
+ ClangASTType &type,
+ bool persistent = true) const;
+
+ // Set the Return value object in the current frame as though a function with
+ virtual Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value) = 0;
+
+protected:
+ // This is the method the ABI will call to actually calculate the return value.
+ // Don't put it in a persistant value object, that will be done by the ABI::GetReturnValueObject.
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (Thread &thread,
+ ClangASTType &type) const = 0;
+public:
+ virtual bool
+ CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan) = 0;
+
+ virtual bool
+ CreateDefaultUnwindPlan (UnwindPlan &unwind_plan) = 0;
+
+ virtual bool
+ RegisterIsVolatile (const RegisterInfo *reg_info) = 0;
+
+ // Should return true if your ABI uses frames when doing stack backtraces. This
+ // means a frame pointer is used that points to the previous stack frame in some
+ // way or another.
+ virtual bool
+ StackUsesFrames () = 0;
+
+ // Should take a look at a call frame address (CFA) which is just the stack
+ // pointer value upon entry to a function. ABIs usually impose alignment
+ // restrictions (4, 8 or 16 byte aligned), and zero is usually not allowed.
+ // This function should return true if "cfa" is valid call frame address for
+ // the ABI, and false otherwise. This is used by the generic stack frame unwinding
+ // code to help determine when a stack ends.
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa) = 0;
+
+ // Validates a possible PC value and returns true if an opcode can be at "pc".
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc) = 0;
+
+ virtual lldb::addr_t
+ FixCodeAddress (lldb::addr_t pc)
+ {
+ // Some targets might use bits in a code address to indicate
+ // a mode switch. ARM uses bit zero to signify a code address is
+ // thumb, so any ARM ABI plug-ins would strip those bits.
+ return pc;
+ }
+
+ virtual const RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count) = 0;
+
+ // Some architectures (e.g. x86) will push the return address on the stack and decrement
+ // the stack pointer when making a function call. This means that every stack frame will
+ // have a unique CFA.
+ // Other architectures (e.g. arm) pass the return address in a register so it is possible
+ // to have a frame on a backtrace that does not push anything on the stack or change the
+ // CFA.
+ virtual bool
+ FunctionCallsChangeCFA () = 0;
+
+
+ bool
+ GetRegisterInfoByName (const ConstString &name, RegisterInfo &info);
+
+ bool
+ GetRegisterInfoByKind (lldb::RegisterKind reg_kind,
+ uint32_t reg_num,
+ RegisterInfo &info);
+
+ static lldb::ABISP
+ FindPlugin (const ArchSpec &arch);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ABI can see and modify these
+ //------------------------------------------------------------------
+ ABI();
+private:
+ DISALLOW_COPY_AND_ASSIGN (ABI);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ABI_h_
diff --git a/include/lldb/Target/CPPLanguageRuntime.h b/include/lldb/Target/CPPLanguageRuntime.h
new file mode 100644
index 000000000000..98a4ab88cb25
--- /dev/null
+++ b/include/lldb/Target/CPPLanguageRuntime.h
@@ -0,0 +1,158 @@
+//===-- CPPLanguageRuntime.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_CPPLanguageRuntime_h_
+#define liblldb_CPPLanguageRuntime_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Target/LanguageRuntime.h"
+
+namespace lldb_private {
+
+class CPPLanguageRuntime :
+ public LanguageRuntime
+{
+public:
+
+ class MethodName
+ {
+ public:
+ enum Type
+ {
+ eTypeInvalid,
+ eTypeUnknownMethod,
+ eTypeClassMethod,
+ eTypeInstanceMethod
+ };
+
+ MethodName () :
+ m_full(),
+ m_basename(),
+ m_context(),
+ m_arguments(),
+ m_qualifiers(),
+ m_type (eTypeInvalid),
+ m_parsed (false),
+ m_parse_error (false)
+ {
+ }
+
+ MethodName (const ConstString &s) :
+ m_full(s),
+ m_basename(),
+ m_context(),
+ m_arguments(),
+ m_qualifiers(),
+ m_type (eTypeInvalid),
+ m_parsed (false),
+ m_parse_error (false)
+ {
+ }
+
+ void
+ Clear();
+
+ bool
+ IsValid () const
+ {
+ if (m_parse_error)
+ return false;
+ if (m_type == eTypeInvalid)
+ return false;
+ return (bool)m_full;
+ }
+
+ Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ const ConstString &
+ GetFullName () const
+ {
+ return m_full;
+ }
+
+ llvm::StringRef
+ GetBasename ();
+
+ llvm::StringRef
+ GetContext ();
+
+ llvm::StringRef
+ GetArguments ();
+
+ llvm::StringRef
+ GetQualifiers ();
+
+ protected:
+ void
+ Parse();
+
+ ConstString m_full; // Full name: "lldb::SBTarget::GetBreakpointAtIndex(unsigned int) const"
+ llvm::StringRef m_basename; // Basename: "GetBreakpointAtIndex"
+ llvm::StringRef m_context; // Decl context: "lldb::SBTarget"
+ llvm::StringRef m_arguments; // Arguments: "(unsigned int)"
+ llvm::StringRef m_qualifiers; // Qualifiers: "const"
+ Type m_type;
+ bool m_parsed;
+ bool m_parse_error;
+ };
+
+ virtual
+ ~CPPLanguageRuntime();
+
+ virtual lldb::LanguageType
+ GetLanguageType () const
+ {
+ return lldb::eLanguageTypeC_plus_plus;
+ }
+
+ virtual bool
+ IsVTableName (const char *name) = 0;
+
+ virtual bool
+ GetObjectDescription (Stream &str, ValueObject &object);
+
+ virtual bool
+ GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope);
+
+ static bool
+ IsCPPMangledName(const char *name);
+
+ static bool
+ StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end);
+
+ // in some cases, compilers will output different names for one same type. when tht happens, it might be impossible
+ // to construct SBType objects for a valid type, because the name that is available is not the same as the name that
+ // can be used as a search key in FindTypes(). the equivalents map here is meant to return possible alternative names
+ // for a type through which a search can be conducted. Currently, this is only enabled for C++ but can be extended
+ // to ObjC or other languages if necessary
+ static uint32_t
+ FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from CPPLanguageRuntime can see and modify these
+ //------------------------------------------------------------------
+ CPPLanguageRuntime(Process *process);
+private:
+ DISALLOW_COPY_AND_ASSIGN (CPPLanguageRuntime);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CPPLanguageRuntime_h_
diff --git a/include/lldb/Target/DynamicLoader.h b/include/lldb/Target/DynamicLoader.h
new file mode 100644
index 000000000000..6b76e5891ae8
--- /dev/null
+++ b/include/lldb/Target/DynamicLoader.h
@@ -0,0 +1,239 @@
+//===-- DynamicLoader.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_DynamicLoader_h_
+#define liblldb_DynamicLoader_h_
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginInterface.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class DynamicLoader DynamicLoader.h "lldb/Target/DynamicLoader.h"
+/// @brief A plug-in interface definition class for dynamic loaders.
+///
+/// Dynamic loader plug-ins track image (shared library) loading and
+/// unloading. The class is initialized given a live process that is
+/// halted at its entry point or just after attaching.
+///
+/// Dynamic loader plug-ins can track the process by registering
+/// callbacks using the:
+/// Process::RegisterNotificationCallbacks (const Notifications&)
+/// function.
+///
+/// Breakpoints can also be set in the process which can register
+/// functions that get called using:
+/// Process::BreakpointSetCallback (lldb::user_id_t, BreakpointHitCallback, void *).
+/// These breakpoint callbacks return a boolean value that indicates if
+/// the process should continue or halt and should return the global
+/// setting for this using:
+/// DynamicLoader::StopWhenImagesChange() const.
+//----------------------------------------------------------------------
+class DynamicLoader :
+ public PluginInterface
+{
+public:
+ //------------------------------------------------------------------
+ /// Find a dynamic loader plugin for a given process.
+ ///
+ /// Scans the installed DynamicLoader plug-ins and tries to find
+ /// an instance that can be used to track image changes in \a
+ /// process.
+ ///
+ /// @param[in] process
+ /// The process for which to try and locate a dynamic loader
+ /// plug-in instance.
+ ///
+ /// @param[in] plugin_name
+ /// An optional name of a specific dynamic loader plug-in that
+ /// should be used. If NULL, pick the best plug-in.
+ //------------------------------------------------------------------
+ static DynamicLoader*
+ FindPlugin (Process *process, const char *plugin_name);
+
+ //------------------------------------------------------------------
+ /// Construct with a process.
+ //------------------------------------------------------------------
+ DynamicLoader (Process *process);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from by the plug-in instance.
+ //------------------------------------------------------------------
+ virtual
+ ~DynamicLoader ();
+
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach () = 0;
+
+ //------------------------------------------------------------------
+ /// Called after launching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// the process has stopped for the first time on launch.
+ //------------------------------------------------------------------
+ virtual void
+ DidLaunch () = 0;
+
+
+ //------------------------------------------------------------------
+ /// Helper function that can be used to detect when a process has
+ /// called exec and is now a new and different process. This can
+ /// be called when necessary to try and detect the exec. The process
+ /// might be able to answer this question, but sometimes it might
+ /// not be able and the dynamic loader often knows what the program
+ /// entry point is. So the process and the dynamic loader can work
+ /// together to detect this.
+ //------------------------------------------------------------------
+ virtual bool
+ ProcessDidExec ()
+ {
+ return false;
+ }
+ //------------------------------------------------------------------
+ /// Get whether the process should stop when images change.
+ ///
+ /// When images (executables and shared libraries) get loaded or
+ /// unloaded, often debug sessions will want to try and resolve or
+ /// unresolve breakpoints that are set in these images. Any
+ /// breakpoints set by DynamicLoader plug-in instances should
+ /// return this value to ensure consistent debug session behaviour.
+ ///
+ /// @return
+ /// Returns \b true if the process should stop when images
+ /// change, \b false if the process should resume.
+ //------------------------------------------------------------------
+ bool
+ GetStopWhenImagesChange () const;
+
+ //------------------------------------------------------------------
+ /// Set whether the process should stop when images change.
+ ///
+ /// When images (executables and shared libraries) get loaded or
+ /// unloaded, often debug sessions will want to try and resolve or
+ /// unresolve breakpoints that are set in these images. The default
+ /// is set so that the process stops when images change, but this
+ /// can be overridden using this function callback.
+ ///
+ /// @param[in] stop
+ /// Boolean value that indicates whether the process should stop
+ /// when images change.
+ //------------------------------------------------------------------
+ void
+ SetStopWhenImagesChange (bool stop);
+
+ //------------------------------------------------------------------
+ /// Provides a plan to step through the dynamic loader trampoline
+ /// for the current state of \a thread.
+ ///
+ ///
+ /// @param[in] stop_others
+ /// Whether the plan should be set to stop other threads.
+ ///
+ /// @return
+ /// A pointer to the plan (caller owned) or NULL if we are not at such
+ /// a trampoline.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
+
+
+ //------------------------------------------------------------------
+ /// Some dynamic loaders provide features where there are a group of symbols "equivalent to"
+ /// a given symbol one of which will be chosen when the symbol is bound. If you want to
+ /// set a breakpoint on one of these symbols, you really need to set it on all the
+ /// equivalent symbols.
+ ///
+ ///
+ /// @param[in] original_symbol
+ /// The symbol for which we are finding equivalences.
+ ///
+ /// @param[in] module_list
+ /// The set of modules in which to search.
+ ///
+ /// @param[out] equivalent_symbols
+ /// The equivalent symbol list - any equivalent symbols found are appended to this list.
+ ///
+ /// @return
+ /// Number of equivalent symbols found.
+ //------------------------------------------------------------------
+ virtual size_t
+ FindEquivalentSymbols (Symbol *original_symbol, ModuleList &module_list, SymbolContextList &equivalent_symbols)
+ {
+ return 0;
+ }
+
+ //------------------------------------------------------------------
+ /// Ask if it is ok to try and load or unload an shared library
+ /// (image).
+ ///
+ /// The dynamic loader often knows when it would be ok to try and
+ /// load or unload a shared library. This function call allows the
+ /// dynamic loader plug-ins to check any current dyld state to make
+ /// sure it is an ok time to load a shared library.
+ ///
+ /// @return
+ /// \b true if it is currently ok to try and load a shared
+ /// library into the process, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ CanLoadImage () = 0;
+
+ //------------------------------------------------------------------
+ /// Ask if the eh_frame information for the given SymbolContext should
+ /// be relied on even when it's the first frame in a stack unwind.
+ ///
+ /// The CFI instructions from the eh_frame section are normally only
+ /// valid at call sites -- places where a program could throw an
+ /// exception and need to unwind out. But some Modules may be known
+ /// to the system as having reliable eh_frame information at all call
+ /// sites. This would be the case if the Module's contents are largely
+ /// hand-written assembly with hand-written eh_frame information.
+ /// Normally when unwinding from a function at the beginning of a stack
+ /// unwind lldb will examine the assembly instructions to understand
+ /// how the stack frame is set up and where saved registers are stored.
+ /// But with hand-written assembly this is not reliable enough -- we need
+ /// to consult those function's hand-written eh_frame information.
+ ///
+ /// @return
+ /// \b True if the symbol context should use eh_frame instructions
+ /// unconditionally when unwinding from this frame. Else \b false,
+ /// the normal lldb unwind behavior of only using eh_frame when the
+ /// function appears in the middle of the stack.
+ //------------------------------------------------------------------
+ virtual bool
+ AlwaysRelyOnEHUnwindInfo (SymbolContext &sym_ctx)
+ {
+ return false;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Process* m_process; ///< The process that this dynamic loader plug-in is tracking.
+private:
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoader);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_DynamicLoader_h_
diff --git a/include/lldb/Target/ExecutionContext.h b/include/lldb/Target/ExecutionContext.h
new file mode 100644
index 000000000000..de5fe14934a7
--- /dev/null
+++ b/include/lldb/Target/ExecutionContext.h
@@ -0,0 +1,778 @@
+//===-- ExecutionContext.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// Execution context objects refer to objects in the execution of the
+/// program that is being debugged. The consist of one or more of the
+/// following objects: target, process, thread, and frame. Many objects
+/// in the debugger need to track different executions contexts. For
+/// example, a local function variable might have an execution context
+/// that refers to a stack frame. A global or static variable might
+/// refer to a target since a stack frame isn't required in order to
+/// evaluate a global or static variable (a process isn't necessarily
+/// needed for a global variable since we might be able to read the
+/// variable value from a data section in one of the object files in
+/// a target). There are two types of objects that hold onto execution
+/// contexts: ExecutionContextRef and ExecutionContext. Both of these
+/// objects are deascribed below.
+///
+/// Not all objects in an ExectionContext objects will be valid. If you want
+/// to refer stronly (ExectionContext) or weakly (ExectionContextRef) to
+/// a process, then only the process and target references will be valid.
+/// For threads, only the thread, process and target references will be
+/// filled in. For frames, all of the objects will be filled in.
+///
+/// These classes are designed to be used as baton objects that get passed
+/// to a wide variety of functions that require execution contexts.
+//===----------------------------------------------------------------------===//
+
+
+
+#ifndef liblldb_ExecutionContext_h_
+#define liblldb_ExecutionContext_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ExecutionContextRef ExecutionContext.h "lldb/Target/ExecutionContext.h"
+/// @brief A class that holds a weak reference to an execution context.
+///
+/// ExecutionContextRef objects are designed to hold onto an execution
+/// context that might change over time. For example, if an object wants
+/// to refer to a stack frame, it should hold onto an ExecutionContextRef
+/// to a frame object. The backing object that represents the stack frame
+/// might change over time and instaces of this object can track the logical
+/// object that refers to a frame even if it does change.
+///
+/// These objects also don't keep execution objects around longer than they
+/// should since they use weak pointers. For example if an object refers
+/// to a stack frame and a stack frame is no longer in a thread, then a
+/// ExecutionContextRef object that refers to that frame will not be able
+/// to get a shared pointer to those objects since they are no longer around.
+///
+/// ExecutionContextRef objects can also be used as objects in classes
+/// that want to track a "previous execution context". Since the weak
+/// references to the execution objects (target, process, thread and frame)
+/// don't keep these objects around, they are safe to keep around.
+///
+/// The general rule of thumb is all long lived objects that want to
+/// refer to execution contexts should use ExecutionContextRef objcts.
+/// The ExecutionContext class is used to temporarily get shared
+/// pointers to any execution context objects that are still around
+/// so they are guaranteed to exist during a function that requires the
+/// objects. ExecutionContext objects should NOT be used for long term
+/// storage since they will keep objects alive with extra shared pointer
+/// references to these objects.
+//----------------------------------------------------------------------
+class ExecutionContextRef
+{
+public:
+ //------------------------------------------------------------------
+ /// Default Constructor.
+ //------------------------------------------------------------------
+ ExecutionContextRef();
+
+ //------------------------------------------------------------------
+ /// Copy Constructor.
+ //------------------------------------------------------------------
+ ExecutionContextRef (const ExecutionContextRef &rhs);
+
+ //------------------------------------------------------------------
+ /// Construct using an ExecutionContext object that might be NULL.
+ ///
+ /// If \a exe_ctx_ptr is valid, then make weak references to any
+ /// valid objects in the ExecutionContext, othewise no weak
+ /// references to any execution context objects will be made.
+ //------------------------------------------------------------------
+ ExecutionContextRef (const ExecutionContext *exe_ctx_ptr);
+
+ //------------------------------------------------------------------
+ /// Construct using an ExecutionContext object.
+ ///
+ /// Make weak references to any valid objects in the ExecutionContext.
+ //------------------------------------------------------------------
+ ExecutionContextRef (const ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Assignment operator
+ ///
+ /// Copy all weak refernces in \a rhs.
+ //------------------------------------------------------------------
+ ExecutionContextRef &
+ operator =(const ExecutionContextRef &rhs);
+
+ //------------------------------------------------------------------
+ /// Assignment operator from a ExecutionContext
+ ///
+ /// Make weak refernces to any stringly referenced objects in \a exe_ctx.
+ //------------------------------------------------------------------
+ ExecutionContextRef &
+ operator =(const ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ /// Construct using the target and all the selected items inside of it
+ /// (the process and its selected thread, and the thread's selected
+ /// frame). If there is no selected thread, default to the first thread
+ /// If there is no selected frame, default to the first frame.
+ //------------------------------------------------------------------
+ ExecutionContextRef (Target *target, bool adopt_selected);
+
+ //------------------------------------------------------------------
+ /// Construct using an execution context scope.
+ ///
+ /// If the ExecutionContextScope object is valid and refers to a frame,
+ /// make weak refernces too the frame, thread, process and target.
+ /// If the ExecutionContextScope object is valid and refers to a thread,
+ /// make weak refernces too the thread, process and target.
+ /// If the ExecutionContextScope object is valid and refers to a process,
+ /// make weak refernces too the process and target.
+ /// If the ExecutionContextScope object is valid and refers to a target,
+ /// make weak refernces too the target.
+ //------------------------------------------------------------------
+ ExecutionContextRef (ExecutionContextScope *exe_scope);
+
+ //------------------------------------------------------------------
+ /// Construct using an execution context scope.
+ ///
+ /// If the ExecutionContextScope object refers to a frame,
+ /// make weak refernces too the frame, thread, process and target.
+ /// If the ExecutionContextScope object refers to a thread,
+ /// make weak refernces too the thread, process and target.
+ /// If the ExecutionContextScope object refers to a process,
+ /// make weak refernces too the process and target.
+ /// If the ExecutionContextScope object refers to a target,
+ /// make weak refernces too the target.
+ //------------------------------------------------------------------
+ ExecutionContextRef (ExecutionContextScope &exe_scope);
+
+ ~ExecutionContextRef();
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the process and thread to NULL, and the frame index to an
+ /// invalid value.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ //------------------------------------------------------------------
+ /// Set accessor that creates a weak reference to the target
+ /// referenced in \a target_sp.
+ ///
+ /// If \a target_sp is valid this object will create a weak
+ /// reference to that object, otherwise any previous target weak
+ /// reference contained in this object will be reset.
+ ///
+ /// Only the weak reference to the target will be updated, no other
+ /// weak references will be modified. If you want this execution
+ /// context to make a weak reference to the target's process, use
+ /// the ExecutionContextRef::SetContext() functions.
+ ///
+ /// @see ExecutionContextRef::SetContext(const lldb::TargetSP &, bool)
+ //------------------------------------------------------------------
+ void
+ SetTargetSP (const lldb::TargetSP &target_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor that creates a weak reference to the process
+ /// referenced in \a process_sp.
+ ///
+ /// If \a process_sp is valid this object will create a weak
+ /// reference to that object, otherwise any previous process weak
+ /// reference contained in this object will be reset.
+ ///
+ /// Only the weak reference to the process will be updated, no other
+ /// weak references will be modified. If you want this execution
+ /// context to make a weak reference to the target, use the
+ /// ExecutionContextRef::SetContext() functions.
+ ///
+ /// @see ExecutionContextRef::SetContext(const lldb::ProcessSP &)
+ //------------------------------------------------------------------
+ void
+ SetProcessSP (const lldb::ProcessSP &process_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor that creates a weak reference to the thread
+ /// referenced in \a thread_sp.
+ ///
+ /// If \a thread_sp is valid this object will create a weak
+ /// reference to that object, otherwise any previous thread weak
+ /// reference contained in this object will be reset.
+ ///
+ /// Only the weak reference to the thread will be updated, no other
+ /// weak references will be modified. If you want this execution
+ /// context to make a weak reference to the thread's process and
+ /// target, use the ExecutionContextRef::SetContext() functions.
+ ///
+ /// @see ExecutionContextRef::SetContext(const lldb::ThreadSP &)
+ //------------------------------------------------------------------
+ void
+ SetThreadSP (const lldb::ThreadSP &thread_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor that creates a weak reference to the frame
+ /// referenced in \a frame_sp.
+ ///
+ /// If \a frame_sp is valid this object will create a weak
+ /// reference to that object, otherwise any previous frame weak
+ /// reference contained in this object will be reset.
+ ///
+ /// Only the weak reference to the frame will be updated, no other
+ /// weak references will be modified. If you want this execution
+ /// context to make a weak reference to the frame's thread, process
+ /// and target, use the ExecutionContextRef::SetContext() functions.
+ ///
+ /// @see ExecutionContextRef::SetContext(const lldb::StackFrameSP &)
+ //------------------------------------------------------------------
+ void
+ SetFrameSP (const lldb::StackFrameSP &frame_sp);
+
+ void
+ SetTargetPtr (Target* target, bool adopt_selected);
+
+ void
+ SetProcessPtr (Process *process);
+
+ void
+ SetThreadPtr (Thread *thread);
+
+ void
+ SetFramePtr (StackFrame *frame);
+
+ //------------------------------------------------------------------
+ /// Get accessor that creates a strong reference from the weak target
+ /// reference contained in this object.
+ ///
+ /// @returns
+ /// A shared pointer to a target that is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ lldb::TargetSP
+ GetTargetSP () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor that creates a strong reference from the weak process
+ /// reference contained in this object.
+ ///
+ /// @returns
+ /// A shared pointer to a process that is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ lldb::ProcessSP
+ GetProcessSP () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor that creates a strong reference from the weak thread
+ /// reference contained in this object.
+ ///
+ /// @returns
+ /// A shared pointer to a thread that is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ lldb::ThreadSP
+ GetThreadSP () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor that creates a strong reference from the weak frame
+ /// reference contained in this object.
+ ///
+ /// @returns
+ /// A shared pointer to a frame that is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ lldb::StackFrameSP
+ GetFrameSP () const;
+
+ //------------------------------------------------------------------
+ /// Create an ExecutionContext object from this object.
+ ///
+ /// Create strong references to any execution context objects that
+ /// are still valid. Any of the returned shared pointers in the
+ /// ExecutionContext objects is not guaranteed to be valid.
+ /// @returns
+ /// An execution context object that has strong references to
+ /// any valid weak references in this object.
+ //------------------------------------------------------------------
+ ExecutionContext
+ Lock () const;
+
+ //------------------------------------------------------------------
+ /// Returns true if this object has a weak reference to a thread.
+ /// The return value is only an indication of wether this object has
+ /// a weak reference and does not indicate wether the weak rerference
+ /// is valid or not.
+ //------------------------------------------------------------------
+ bool
+ HasThreadRef () const
+ {
+ return m_tid != LLDB_INVALID_THREAD_ID;
+ }
+
+ //------------------------------------------------------------------
+ /// Returns true if this object has a weak reference to a frame.
+ /// The return value is only an indication of wether this object has
+ /// a weak reference and does not indicate wether the weak rerference
+ /// is valid or not.
+ //------------------------------------------------------------------
+ bool
+ HasFrameRef () const
+ {
+ return m_stack_id.IsValid();
+ }
+
+ void
+ ClearThread ()
+ {
+ m_thread_wp.reset();
+ m_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ void
+ ClearFrame ()
+ {
+ m_stack_id.Clear();
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::TargetWP m_target_wp; ///< A weak reference to a target
+ lldb::ProcessWP m_process_wp; ///< A weak reference to a process
+ mutable lldb::ThreadWP m_thread_wp; ///< A weak reference to a thread
+ lldb::tid_t m_tid; ///< The thread ID that this object refers to in case the backing object changes
+ StackID m_stack_id; ///< The stack ID that this object refers to in case the backing object changes
+};
+
+//----------------------------------------------------------------------
+/// @class ExecutionContext ExecutionContext.h "lldb/Target/ExecutionContext.h"
+/// @brief A class that contains an execution context.
+///
+/// This baton object can be passed into any function that requires
+/// a context that specifies a target, process, thread and frame.
+/// These objects are designed to be used for short term execution
+/// context object storage while a function might be trying to evaluate
+/// something that requires a thread or frame. ExecutionContextRef
+/// objects can be used to initialize one of these objects to turn
+/// the weak execution context object references to the target, process,
+/// thread and frame into strong references (shared pointers) so that
+/// functions can guarantee that these objects won't go away in the
+/// middle of a function.
+///
+/// ExecutionContext objects should be used as short lived objects
+/// (typically on the stack) in order to lock down an execution context
+/// for local use and for passing down to other functions that also
+/// require specific contexts. They should NOT be used for long term
+/// storage, for long term storage use ExecutionContextRef objects.
+//----------------------------------------------------------------------
+class ExecutionContext
+{
+public:
+ //------------------------------------------------------------------
+ /// Default Constructor.
+ //------------------------------------------------------------------
+ ExecutionContext();
+
+ //------------------------------------------------------------------
+ // Copy constructor
+ //------------------------------------------------------------------
+ ExecutionContext (const ExecutionContext &rhs);
+
+ //------------------------------------------------------------------
+ // Adopt the target and optionally its current context.
+ //------------------------------------------------------------------
+ ExecutionContext (Target* t, bool fill_current_process_thread_frame = true);
+
+ //------------------------------------------------------------------
+ // Create execution contexts from shared pointers
+ //------------------------------------------------------------------
+ ExecutionContext (const lldb::TargetSP &target_sp, bool get_process);
+ ExecutionContext (const lldb::ProcessSP &process_sp);
+ ExecutionContext (const lldb::ThreadSP &thread_sp);
+ ExecutionContext (const lldb::StackFrameSP &frame_sp);
+ //------------------------------------------------------------------
+ // Create execution contexts from weak pointers
+ //------------------------------------------------------------------
+ ExecutionContext (const lldb::TargetWP &target_wp, bool get_process);
+ ExecutionContext (const lldb::ProcessWP &process_wp);
+ ExecutionContext (const lldb::ThreadWP &thread_wp);
+ ExecutionContext (const lldb::StackFrameWP &frame_wp);
+ ExecutionContext (const ExecutionContextRef &exe_ctx_ref);
+ ExecutionContext (const ExecutionContextRef *exe_ctx_ref);
+
+ // These two variants take in a locker, and grab the target, lock the API mutex into locker, then
+ // fill in the rest of the shared pointers.
+ ExecutionContext (const ExecutionContextRef &exe_ctx_ref, Mutex::Locker &locker);
+ ExecutionContext (const ExecutionContextRef *exe_ctx_ref, Mutex::Locker &locker);
+ //------------------------------------------------------------------
+ // Create execution contexts from execution context scopes
+ //------------------------------------------------------------------
+ ExecutionContext (ExecutionContextScope *exe_scope);
+ ExecutionContext (ExecutionContextScope &exe_scope);
+
+
+ ExecutionContext &
+ operator =(const ExecutionContext &rhs);
+
+ bool
+ operator ==(const ExecutionContext &rhs) const;
+
+ bool
+ operator !=(const ExecutionContext &rhs) const;
+
+ //------------------------------------------------------------------
+ /// Construct with process, thread, and frame index.
+ ///
+ /// Initialize with process \a p, thread \a t, and frame index \a f.
+ ///
+ /// @param[in] process
+ /// The process for this execution context.
+ ///
+ /// @param[in] thread
+ /// The thread for this execution context.
+ ///
+ /// @param[in] frame
+ /// The frame index for this execution context.
+ //------------------------------------------------------------------
+ ExecutionContext (Process* process,
+ Thread *thread = NULL,
+ StackFrame * frame = NULL);
+
+
+ ~ExecutionContext();
+ //------------------------------------------------------------------
+ /// Clear the object's state.
+ ///
+ /// Sets the process and thread to NULL, and the frame index to an
+ /// invalid value.
+ //------------------------------------------------------------------
+ void
+ Clear ();
+
+ RegisterContext *
+ GetRegisterContext () const;
+
+ ExecutionContextScope *
+ GetBestExecutionContextScope () const;
+
+ uint32_t
+ GetAddressByteSize() const;
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the target object.
+ ///
+ /// The returned pointer might be NULL. Calling HasTargetScope(),
+ /// HasProcessScope(), HasThreadScope(), or HasFrameScope()
+ /// can help to pre-validate this pointer so that this accessor can
+ /// freely be used without having to check for NULL each time.
+ ///
+ /// @see ExecutionContext::HasTargetScope() const
+ /// @see ExecutionContext::HasProcessScope() const
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Target *
+ GetTargetPtr () const;
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the process object.
+ ///
+ /// The returned pointer might be NULL. Calling HasProcessScope(),
+ /// HasThreadScope(), or HasFrameScope() can help to pre-validate
+ /// this pointer so that this accessor can freely be used without
+ /// having to check for NULL each time.
+ ///
+ /// @see ExecutionContext::HasProcessScope() const
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Process *
+ GetProcessPtr () const;
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the thread object.
+ ///
+ /// The returned pointer might be NULL. Calling HasThreadScope() or
+ /// HasFrameScope() can help to pre-validate this pointer so that
+ /// this accessor can freely be used without having to check for
+ /// NULL each time.
+ ///
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Thread *
+ GetThreadPtr () const
+ {
+ return m_thread_sp.get();
+ }
+
+ //------------------------------------------------------------------
+ /// Returns a pointer to the frame object.
+ ///
+ /// The returned pointer might be NULL. Calling HasFrameScope(),
+ /// can help to pre-validate this pointer so that this accessor can
+ /// freely be used without having to check for NULL each time.
+ ///
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ StackFrame *
+ GetFramePtr () const
+ {
+ return m_frame_sp.get();
+ }
+
+ //------------------------------------------------------------------
+ /// Returns a reference to the target object.
+ ///
+ /// Clients should call HasTargetScope(), HasProcessScope(),
+ /// HasThreadScope(), or HasFrameScope() prior to calling this
+ /// function to ensure that this ExecutionContext object contains
+ /// a valid target.
+ ///
+ /// @see ExecutionContext::HasTargetScope() const
+ /// @see ExecutionContext::HasProcessScope() const
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Target &
+ GetTargetRef () const;
+
+ //------------------------------------------------------------------
+ /// Returns a reference to the process object.
+ ///
+ /// Clients should call HasProcessScope(), HasThreadScope(), or
+ /// HasFrameScope() prior to calling this function to ensure that
+ /// this ExecutionContext object contains a valid target.
+ ///
+ /// @see ExecutionContext::HasProcessScope() const
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Process &
+ GetProcessRef () const;
+
+ //------------------------------------------------------------------
+ /// Returns a reference to the thread object.
+ ///
+ /// Clients should call HasThreadScope(), or HasFrameScope() prior
+ /// to calling this function to ensure that this ExecutionContext
+ /// object contains a valid target.
+ ///
+ /// @see ExecutionContext::HasThreadScope() const
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ Thread &
+ GetThreadRef () const;
+
+ //------------------------------------------------------------------
+ /// Returns a reference to the thread object.
+ ///
+ /// Clients should call HasFrameScope() prior to calling this
+ /// function to ensure that this ExecutionContext object contains
+ /// a valid target.
+ ///
+ /// @see ExecutionContext::HasFrameScope() const
+ //------------------------------------------------------------------
+ StackFrame &
+ GetFrameRef () const;
+
+ //------------------------------------------------------------------
+ /// Get accessor to get the target shared pointer.
+ ///
+ /// The returned shared pointer is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ const lldb::TargetSP &
+ GetTargetSP () const
+ {
+ return m_target_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor to get the process shared pointer.
+ ///
+ /// The returned shared pointer is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ const lldb::ProcessSP &
+ GetProcessSP () const
+ {
+ return m_process_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor to get the thread shared pointer.
+ ///
+ /// The returned shared pointer is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ const lldb::ThreadSP &
+ GetThreadSP () const
+ {
+ return m_thread_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor to get the frame shared pointer.
+ ///
+ /// The returned shared pointer is not guaranteed to be valid.
+ //------------------------------------------------------------------
+ const lldb::StackFrameSP &
+ GetFrameSP () const
+ {
+ return m_frame_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the target shared pointer.
+ //------------------------------------------------------------------
+ void
+ SetTargetSP (const lldb::TargetSP &target_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the process shared pointer.
+ //------------------------------------------------------------------
+ void
+ SetProcessSP (const lldb::ProcessSP &process_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the thread shared pointer.
+ //------------------------------------------------------------------
+ void
+ SetThreadSP (const lldb::ThreadSP &thread_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the frame shared pointer.
+ //------------------------------------------------------------------
+ void
+ SetFrameSP (const lldb::StackFrameSP &frame_sp);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the target shared pointer from a target
+ /// pointer.
+ //------------------------------------------------------------------
+ void
+ SetTargetPtr (Target* target);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the process shared pointer from a
+ /// process pointer.
+ //------------------------------------------------------------------
+ void
+ SetProcessPtr (Process *process);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the thread shared pointer from a thread
+ /// pointer.
+ //------------------------------------------------------------------
+ void
+ SetThreadPtr (Thread *thread);
+
+ //------------------------------------------------------------------
+ /// Set accessor to set only the frame shared pointer from a frame
+ /// pointer.
+ //------------------------------------------------------------------
+ void
+ SetFramePtr (StackFrame *frame);
+
+ //------------------------------------------------------------------
+ // Set the execution context using a target shared pointer.
+ //
+ // If "target_sp" is valid, sets the target context to match and
+ // if "get_process" is true, sets the process shared pointer if
+ // the target currently has a process.
+ //------------------------------------------------------------------
+ void
+ SetContext (const lldb::TargetSP &target_sp, bool get_process);
+
+ //------------------------------------------------------------------
+ // Set the execution context using a process shared pointer.
+ //
+ // If "process_sp" is valid, then set the process and target in this
+ // context. Thread and frame contexts will be cleared.
+ // If "process_sp" is not valid, all shared pointers are reset.
+ //------------------------------------------------------------------
+ void
+ SetContext (const lldb::ProcessSP &process_sp);
+
+ //------------------------------------------------------------------
+ // Set the execution context using a thread shared pointer.
+ //
+ // If "thread_sp" is valid, then set the thread, process and target
+ // in this context. The frame context will be cleared.
+ // If "thread_sp" is not valid, all shared pointers are reset.
+ //------------------------------------------------------------------
+ void
+ SetContext (const lldb::ThreadSP &thread_sp);
+
+ //------------------------------------------------------------------
+ // Set the execution context using a frame shared pointer.
+ //
+ // If "frame_sp" is valid, then set the frame, thread, process and
+ // target in this context
+ // If "frame_sp" is not valid, all shared pointers are reset.
+ //------------------------------------------------------------------
+ void
+ SetContext (const lldb::StackFrameSP &frame_sp);
+
+ //------------------------------------------------------------------
+ /// Returns true the ExecutionContext object contains a valid
+ /// target.
+ ///
+ /// This function can be called after initializing an ExecutionContext
+ /// object, and if it returns true, calls to GetTargetPtr() and
+ /// GetTargetRef() do not need to be checked for validity.
+ //------------------------------------------------------------------
+ bool
+ HasTargetScope () const;
+
+ //------------------------------------------------------------------
+ /// Returns true the ExecutionContext object contains a valid
+ /// target and process.
+ ///
+ /// This function can be called after initializing an ExecutionContext
+ /// object, and if it returns true, calls to GetTargetPtr() and
+ /// GetTargetRef(), GetProcessPtr(), and GetProcessRef(), do not
+ /// need to be checked for validity.
+ //------------------------------------------------------------------
+ bool
+ HasProcessScope () const;
+
+ //------------------------------------------------------------------
+ /// Returns true the ExecutionContext object contains a valid
+ /// target, process, and thread.
+ ///
+ /// This function can be called after initializing an ExecutionContext
+ /// object, and if it returns true, calls to GetTargetPtr(),
+ /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(),
+ /// and GetThreadRef() do not need to be checked for validity.
+ //------------------------------------------------------------------
+ bool
+ HasThreadScope () const;
+
+ //------------------------------------------------------------------
+ /// Returns true the ExecutionContext object contains a valid
+ /// target, process, thread and frame.
+ ///
+ /// This function can be called after initializing an ExecutionContext
+ /// object, and if it returns true, calls to GetTargetPtr(),
+ /// GetTargetRef(), GetProcessPtr(), GetProcessRef(), GetThreadPtr(),
+ /// GetThreadRef(), GetFramePtr(), and GetFrameRef() do not need
+ /// to be checked for validity.
+ //------------------------------------------------------------------
+ bool
+ HasFrameScope () const;
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ lldb::TargetSP m_target_sp; ///< The target that owns the process/thread/frame
+ lldb::ProcessSP m_process_sp; ///< The process that owns the thread/frame
+ lldb::ThreadSP m_thread_sp; ///< The thread that owns the frame
+ lldb::StackFrameSP m_frame_sp; ///< The stack frame in thread.
+};
+} // namespace lldb_private
+
+#endif // liblldb_ExecutionContext_h_
diff --git a/include/lldb/Target/ExecutionContextScope.h b/include/lldb/Target/ExecutionContextScope.h
new file mode 100644
index 000000000000..7ba40971af2c
--- /dev/null
+++ b/include/lldb/Target/ExecutionContextScope.h
@@ -0,0 +1,74 @@
+//===-- ExecutionContextScope.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_ExecutionContextScope_h_
+#define liblldb_ExecutionContextScope_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class ExecutionContextScope ExecutionContextScope.h "lldb/Symbol/ExecutionContextScope.h"
+/// @brief Inherit from this if your object can reconstruct its
+/// execution context.
+///
+/// Many objects that have pointers back to parent execution context
+/// objects can inherit from this pure virtual class can reconstruct
+/// their execution context without having to keep a complete
+/// ExecutionContext object in the object state. Examples of these
+/// objects include: Process, Thread, RegisterContext and StackFrame.
+///
+/// Bbjects can contain a valid pointer to an instance of this so they
+/// can reconstruct the execution context.
+///
+/// Objects that adhere to this protocol can reconstruct enough of a
+/// execution context to allow functions that take a execution contexts
+/// to be called.
+//----------------------------------------------------------------------
+class ExecutionContextScope
+{
+public:
+ virtual
+ ~ExecutionContextScope () {}
+
+ virtual lldb::TargetSP
+ CalculateTarget () = 0;
+
+ virtual lldb::ProcessSP
+ CalculateProcess () = 0;
+
+ virtual lldb::ThreadSP
+ CalculateThread () = 0;
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame () = 0;
+
+ //------------------------------------------------------------------
+ /// Reconstruct the object's execution context into \a sc.
+ ///
+ /// The object should fill in as much of the ExecutionContextScope as it
+ /// can so function calls that require a execution context can be made
+ /// for the given object.
+ ///
+ /// @param[out] exe_ctx
+ /// A reference to an execution context object that gets filled
+ /// in.
+ //------------------------------------------------------------------
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx) = 0;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ExecutionContextScope_h_
diff --git a/include/lldb/Target/LanguageRuntime.h b/include/lldb/Target/LanguageRuntime.h
new file mode 100644
index 000000000000..93c0437da75d
--- /dev/null
+++ b/include/lldb/Target/LanguageRuntime.h
@@ -0,0 +1,113 @@
+//===-- LanguageRuntime.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_LanguageRuntime_h_
+#define liblldb_LanguageRuntime_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Target/ExecutionContextScope.h"
+
+namespace lldb_private {
+
+class LanguageRuntime :
+ public PluginInterface
+{
+public:
+ virtual
+ ~LanguageRuntime();
+
+ static LanguageRuntime*
+ FindPlugin (Process *process, lldb::LanguageType language);
+
+ virtual lldb::LanguageType
+ GetLanguageType () const = 0;
+
+ virtual bool
+ GetObjectDescription (Stream &str, ValueObject &object) = 0;
+
+ virtual bool
+ GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) = 0;
+
+ // this call should return true if it could set the name and/or the type
+ virtual bool
+ GetDynamicTypeAndAddress (ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name,
+ Address &address) = 0;
+
+ // This should be a fast test to determine whether it is likely that this value would
+ // have a dynamic type.
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value) = 0;
+
+ virtual void
+ SetExceptionBreakpoints ()
+ {
+ }
+
+ virtual void
+ ClearExceptionBreakpoints ()
+ {
+ }
+
+ virtual bool
+ ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
+ {
+ return false;
+ }
+
+ static lldb::BreakpointSP
+ CreateExceptionBreakpoint (Target &target,
+ lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp,
+ bool is_internal = false);
+
+ static lldb::LanguageType
+ GetLanguageTypeFromString (const char *string);
+
+ static const char *
+ GetNameForLanguageType (lldb::LanguageType language);
+
+ Process *
+ GetProcess()
+ {
+ return m_process;
+ }
+
+ virtual lldb::BreakpointResolverSP
+ CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) = 0;
+
+ virtual lldb::SearchFilterSP
+ CreateExceptionSearchFilter ();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from LanguageRuntime can see and modify these
+ //------------------------------------------------------------------
+
+ LanguageRuntime(Process *process);
+ Process *m_process;
+private:
+ DISALLOW_COPY_AND_ASSIGN (LanguageRuntime);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_LanguageRuntime_h_
diff --git a/include/lldb/Target/Memory.h b/include/lldb/Target/Memory.h
new file mode 100644
index 000000000000..568bbcdf2f7c
--- /dev/null
+++ b/include/lldb/Target/Memory.h
@@ -0,0 +1,196 @@
+//===-- Memory.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_Memory_h_
+#define liblldb_Memory_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+ //----------------------------------------------------------------------
+ // A class to track memory that was read from a live process between
+ // runs.
+ //----------------------------------------------------------------------
+ class MemoryCache
+ {
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ MemoryCache (Process &process);
+
+ ~MemoryCache ();
+
+ void
+ Clear(bool clear_invalid_ranges = false);
+
+ void
+ Flush (lldb::addr_t addr, size_t size);
+
+ size_t
+ Read (lldb::addr_t addr,
+ void *dst,
+ size_t dst_len,
+ Error &error);
+
+ uint32_t
+ GetMemoryCacheLineSize() const
+ {
+ return m_cache_line_byte_size ;
+ }
+
+ void
+ AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size);
+
+ bool
+ RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size);
+
+ protected:
+ typedef std::map<lldb::addr_t, lldb::DataBufferSP> BlockMap;
+ typedef RangeArray<lldb::addr_t, lldb::addr_t, 4> InvalidRanges;
+ //------------------------------------------------------------------
+ // Classes that inherit from MemoryCache can see and modify these
+ //------------------------------------------------------------------
+ Process &m_process;
+ uint32_t m_cache_line_byte_size;
+ Mutex m_mutex;
+ BlockMap m_cache;
+ InvalidRanges m_invalid_ranges;
+ private:
+ DISALLOW_COPY_AND_ASSIGN (MemoryCache);
+ };
+
+
+ class AllocatedBlock
+ {
+ public:
+ AllocatedBlock (lldb::addr_t addr,
+ uint32_t byte_size,
+ uint32_t permissions,
+ uint32_t chunk_size);
+
+ ~AllocatedBlock ();
+
+ lldb::addr_t
+ ReserveBlock (uint32_t size);
+
+ bool
+ FreeBlock (lldb::addr_t addr);
+
+ lldb::addr_t
+ GetBaseAddress () const
+ {
+ return m_addr;
+ }
+
+ uint32_t
+ GetByteSize () const
+ {
+ return m_byte_size;
+ }
+
+ uint32_t
+ GetPermissions () const
+ {
+ return m_permissions;
+ }
+
+ uint32_t
+ GetChunkSize () const
+ {
+ return m_chunk_size;
+ }
+
+ bool
+ Contains (lldb::addr_t addr) const
+ {
+ return ((addr >= m_addr) && addr < (m_addr + m_byte_size));
+ }
+ protected:
+ uint32_t
+ TotalChunks () const
+ {
+ return m_byte_size / m_chunk_size;
+ }
+
+ uint32_t
+ CalculateChunksNeededForSize (uint32_t size) const
+ {
+ return (size + m_chunk_size - 1) / m_chunk_size;
+ }
+ const lldb::addr_t m_addr; // Base address of this block of memory
+ const uint32_t m_byte_size; // 4GB of chunk should be enough...
+ const uint32_t m_permissions; // Permissions for this memory (logical OR of lldb::Permissions bits)
+ const uint32_t m_chunk_size; // The size of chunks that the memory at m_addr is divied up into
+ typedef std::map<uint32_t, uint32_t> OffsetToChunkSize;
+ OffsetToChunkSize m_offset_to_chunk_size;
+ };
+
+
+ //----------------------------------------------------------------------
+ // A class that can track allocated memory and give out allocated memory
+ // without us having to make an allocate/deallocate call every time we
+ // need some memory in a process that is being debugged.
+ //----------------------------------------------------------------------
+ class AllocatedMemoryCache
+ {
+ public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ AllocatedMemoryCache (Process &process);
+
+ ~AllocatedMemoryCache ();
+
+ void
+ Clear();
+
+ lldb::addr_t
+ AllocateMemory (size_t byte_size,
+ uint32_t permissions,
+ Error &error);
+
+ bool
+ DeallocateMemory (lldb::addr_t ptr);
+
+ protected:
+ typedef std::shared_ptr<AllocatedBlock> AllocatedBlockSP;
+
+ AllocatedBlockSP
+ AllocatePage (uint32_t byte_size,
+ uint32_t permissions,
+ uint32_t chunk_size,
+ Error &error);
+
+
+ //------------------------------------------------------------------
+ // Classes that inherit from MemoryCache can see and modify these
+ //------------------------------------------------------------------
+ Process &m_process;
+ Mutex m_mutex;
+ typedef std::multimap<uint32_t, AllocatedBlockSP> PermissionsToBlockMap;
+ PermissionsToBlockMap m_memory_map;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (AllocatedMemoryCache);
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_Memory_h_
diff --git a/include/lldb/Target/ObjCLanguageRuntime.h b/include/lldb/Target/ObjCLanguageRuntime.h
new file mode 100644
index 000000000000..7bac57256444
--- /dev/null
+++ b/include/lldb/Target/ObjCLanguageRuntime.h
@@ -0,0 +1,604 @@
+//===-- ObjCLanguageRuntime.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_ObjCLanguageRuntime_h_
+#define liblldb_ObjCLanguageRuntime_h_
+
+// C Includes
+// C++ Includes
+#include <functional>
+#include <map>
+#include <unordered_set>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeVendor.h"
+#include "lldb/Target/LanguageRuntime.h"
+
+namespace lldb_private {
+
+class ClangUtilityFunction;
+
+class ObjCLanguageRuntime :
+ public LanguageRuntime
+{
+public:
+ class MethodName
+ {
+ public:
+ enum Type
+ {
+ eTypeUnspecified,
+ eTypeClassMethod,
+ eTypeInstanceMethod
+ };
+
+ MethodName () :
+ m_full(),
+ m_class(),
+ m_category(),
+ m_selector(),
+ m_type (eTypeUnspecified),
+ m_category_is_valid (false)
+ {
+ }
+
+ MethodName (const char *name, bool strict) :
+ m_full(),
+ m_class(),
+ m_category(),
+ m_selector(),
+ m_type (eTypeUnspecified),
+ m_category_is_valid (false)
+ {
+ SetName (name, strict);
+ }
+
+ void
+ Clear();
+
+ bool
+ IsValid (bool strict) const
+ {
+ // If "strict" is true, the name must have everything specified including
+ // the leading "+" or "-" on the method name
+ if (strict && m_type == eTypeUnspecified)
+ return false;
+ // Other than that, m_full will only be filled in if the objective C
+ // name is valid.
+ return (bool)m_full;
+ }
+
+ bool
+ HasCategory()
+ {
+ return (bool)GetCategory();
+ }
+
+ Type
+ GetType () const
+ {
+ return m_type;
+ }
+
+ const ConstString &
+ GetFullName () const
+ {
+ return m_full;
+ }
+
+ ConstString
+ GetFullNameWithoutCategory (bool empty_if_no_category);
+
+ bool
+ SetName (const char *name, bool strict);
+
+ const ConstString &
+ GetClassName ();
+
+ const ConstString &
+ GetClassNameWithCategory ();
+
+ const ConstString &
+ GetCategory ();
+
+ const ConstString &
+ GetSelector ();
+
+ // Get all possible names for a method. Examples:
+ // If name is "+[NSString(my_additions) myStringWithCString:]"
+ // names[0] => "+[NSString(my_additions) myStringWithCString:]"
+ // names[1] => "+[NSString myStringWithCString:]"
+ // If name is specified without the leading '+' or '-' like "[NSString(my_additions) myStringWithCString:]"
+ // names[0] => "+[NSString(my_additions) myStringWithCString:]"
+ // names[1] => "-[NSString(my_additions) myStringWithCString:]"
+ // names[2] => "+[NSString myStringWithCString:]"
+ // names[3] => "-[NSString myStringWithCString:]"
+ size_t
+ GetFullNames (std::vector<ConstString> &names, bool append);
+ protected:
+ ConstString m_full; // Full name: "+[NSString(my_additions) myStringWithCString:]"
+ ConstString m_class; // Class name: "NSString"
+ ConstString m_class_category; // Class with category: "NSString(my_additions)"
+ ConstString m_category; // Category: "my_additions"
+ ConstString m_selector; // Selector: "myStringWithCString:"
+ Type m_type;
+ bool m_category_is_valid;
+
+ };
+ typedef lldb::addr_t ObjCISA;
+
+ class ClassDescriptor;
+ typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
+
+ // the information that we want to support retrieving from an ObjC class
+ // this needs to be pure virtual since there are at least 2 different implementations
+ // of the runtime, and more might come
+ class ClassDescriptor
+ {
+ public:
+
+ ClassDescriptor() :
+ m_is_kvo (eLazyBoolCalculate),
+ m_is_cf (eLazyBoolCalculate),
+ m_type_wp ()
+ {
+ }
+
+ virtual
+ ~ClassDescriptor ()
+ {
+ }
+
+ virtual ConstString
+ GetClassName () = 0;
+
+ virtual ClassDescriptorSP
+ GetSuperclass () = 0;
+
+ // virtual if any implementation has some other version-specific rules
+ // but for the known v1/v2 this is all that needs to be done
+ virtual bool
+ IsKVO ()
+ {
+ if (m_is_kvo == eLazyBoolCalculate)
+ {
+ const char* class_name = GetClassName().AsCString();
+ if (class_name && *class_name)
+ m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name);
+ }
+ return (m_is_kvo == eLazyBoolYes);
+ }
+
+ // virtual if any implementation has some other version-specific rules
+ // but for the known v1/v2 this is all that needs to be done
+ virtual bool
+ IsCFType ()
+ {
+ if (m_is_cf == eLazyBoolCalculate)
+ {
+ const char* class_name = GetClassName().AsCString();
+ if (class_name && *class_name)
+ m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 ||
+ strcmp(class_name,"NSCFType") == 0);
+ }
+ return (m_is_cf == eLazyBoolYes);
+ }
+
+ virtual bool
+ IsValid () = 0;
+
+ virtual bool
+ GetTaggedPointerInfo (uint64_t* info_bits = NULL,
+ uint64_t* value_bits = NULL,
+ uint64_t* payload = NULL) = 0;
+
+ virtual uint64_t
+ GetInstanceSize () = 0;
+
+ // use to implement version-specific additional constraints on pointers
+ virtual bool
+ CheckPointer (lldb::addr_t value,
+ uint32_t ptr_size) const
+ {
+ return true;
+ }
+
+ virtual ObjCISA
+ GetISA () = 0;
+
+ // This should return true iff the interface could be completed
+ virtual bool
+ Describe (std::function <void (ObjCISA)> const &superclass_func,
+ std::function <bool (const char*, const char*)> const &instance_method_func,
+ std::function <bool (const char*, const char*)> const &class_method_func,
+ std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func)
+ {
+ return false;
+ }
+
+ lldb::TypeSP
+ GetType ()
+ {
+ return m_type_wp.lock();
+ }
+
+ void
+ SetType (const lldb::TypeSP &type_sp)
+ {
+ m_type_wp = type_sp;
+ }
+
+ protected:
+ bool
+ IsPointerValid (lldb::addr_t value,
+ uint32_t ptr_size,
+ bool allow_NULLs = false,
+ bool allow_tagged = false,
+ bool check_version_specific = false) const;
+
+ private:
+ LazyBool m_is_kvo;
+ LazyBool m_is_cf;
+ lldb::TypeWP m_type_wp;
+ };
+
+ virtual ClassDescriptorSP
+ GetClassDescriptor (ValueObject& in_value);
+
+ ClassDescriptorSP
+ GetNonKVOClassDescriptor (ValueObject& in_value);
+
+ virtual ClassDescriptorSP
+ GetClassDescriptorFromClassName (const ConstString &class_name);
+
+ virtual ClassDescriptorSP
+ GetClassDescriptorFromISA (ObjCISA isa);
+
+ ClassDescriptorSP
+ GetNonKVOClassDescriptor (ObjCISA isa);
+
+ virtual
+ ~ObjCLanguageRuntime();
+
+ virtual lldb::LanguageType
+ GetLanguageType () const
+ {
+ return lldb::eLanguageTypeObjC;
+ }
+
+ virtual bool
+ IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
+
+ virtual bool
+ ReadObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
+
+ virtual bool
+ HasReadObjCLibrary () = 0;
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
+
+ lldb::addr_t
+ LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel);
+
+ void
+ AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
+
+ TypeAndOrName
+ LookupInClassNameCache (lldb::addr_t class_addr);
+
+ void
+ AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp);
+
+ void
+ AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
+
+ lldb::TypeSP
+ LookupInCompleteClassCache (ConstString &name);
+
+ virtual ClangUtilityFunction *
+ CreateObjectChecker (const char *) = 0;
+
+ virtual ObjCRuntimeVersions
+ GetRuntimeVersion ()
+ {
+ return eObjC_VersionUnknown;
+ }
+
+ bool
+ IsValidISA(ObjCISA isa)
+ {
+ UpdateISAToDescriptorMap();
+ return m_isa_to_descriptor.count(isa) > 0;
+ }
+
+ virtual void
+ UpdateISAToDescriptorMapIfNeeded() = 0;
+
+ void
+ UpdateISAToDescriptorMap()
+ {
+ if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id)
+ {
+ UpdateISAToDescriptorMapIfNeeded ();
+ }
+ }
+
+ virtual ObjCISA
+ GetISA(const ConstString &name);
+
+ virtual ConstString
+ GetActualTypeName(ObjCISA isa);
+
+ virtual ObjCISA
+ GetParentClass(ObjCISA isa);
+
+ virtual TypeVendor *
+ GetTypeVendor()
+ {
+ return NULL;
+ }
+
+ // Finds the byte offset of the child_type ivar in parent_type. If it can't find the
+ // offset, returns LLDB_INVALID_IVAR_OFFSET.
+
+ virtual size_t
+ GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name);
+
+ // Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol),
+ // try to determine from the runtime what the value of that symbol would be.
+ // Useful when the underlying binary is stripped.
+ virtual lldb::addr_t
+ LookupRuntimeSymbol (const ConstString &name)
+ {
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ //------------------------------------------------------------------
+ /// Chop up an objective C function prototype.
+ ///
+ /// Chop up an objective C function fullname and optionally fill in
+ /// any non-NULL ConstString objects. If a ConstString * is NULL,
+ /// then this name doesn't get filled in
+ ///
+ /// @param[in] name
+ /// A fully specified objective C function name. The string might
+ /// contain a category and it includes the leading "+" or "-" and
+ /// the square brackets, no types for the arguments, just the plain
+ /// selector. A few examples:
+ /// "-[NSStringDrawingContext init]"
+ /// "-[NSStringDrawingContext addString:inRect:]"
+ /// "-[NSString(NSStringDrawing) sizeWithAttributes:]"
+ /// "+[NSString(NSStringDrawing) usesFontLeading]"
+ ///
+ /// @param[out] class_name
+ /// If non-NULL, this string will be filled in with the class
+ /// name including the category. The examples above would return:
+ /// "NSStringDrawingContext"
+ /// "NSStringDrawingContext"
+ /// "NSString(NSStringDrawing)"
+ /// "NSString(NSStringDrawing)"
+ ///
+ /// @param[out] selector_name
+ /// If non-NULL, this string will be filled in with the selector
+ /// name. The examples above would return:
+ /// "init"
+ /// "addString:inRect:"
+ /// "sizeWithAttributes:"
+ /// "usesFontLeading"
+ ///
+ /// @param[out] name_sans_category
+ /// If non-NULL, this string will be filled in with the class
+ /// name _without_ the category. If there is no category, and empty
+ /// string will be returned (as the result would be normally returned
+ /// in the "class_name" argument). The examples above would return:
+ /// <empty>
+ /// <empty>
+ /// "-[NSString sizeWithAttributes:]"
+ /// "+[NSString usesFontLeading]"
+ ///
+ /// @param[out] class_name_sans_category
+ /// If non-NULL, this string will be filled in with the prototype
+ /// name _without_ the category. If there is no category, and empty
+ /// string will be returned (as this is already the value that was
+ /// passed in). The examples above would return:
+ /// <empty>
+ /// <empty>
+ /// "NSString"
+ /// "NSString"
+ ///
+ /// @return
+ /// Returns the number of strings that were successfully filled
+ /// in.
+ //------------------------------------------------------------------
+// static uint32_t
+// ParseMethodName (const char *name,
+// ConstString *class_name, // Class name (with category if there is one)
+// ConstString *selector_name, // selector only
+// ConstString *name_sans_category, // full function name with no category (empty if no category)
+// ConstString *class_name_sans_category);// Class name without category (empty if no category)
+
+ static bool
+ IsPossibleObjCMethodName (const char *name)
+ {
+ if (!name)
+ return false;
+ bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
+ bool ends_right = (name[strlen(name) - 1] == ']');
+ return (starts_right && ends_right);
+ }
+
+ static bool
+ IsPossibleObjCSelector (const char *name)
+ {
+ if (!name)
+ return false;
+
+ if (strchr(name, ':') == NULL)
+ return true;
+ else if (name[strlen(name) - 1] == ':')
+ return true;
+ else
+ return false;
+ }
+
+ bool
+ HasNewLiteralsAndIndexing ()
+ {
+ if (m_has_new_literals_and_indexing == eLazyBoolCalculate)
+ {
+ if (CalculateHasNewLiteralsAndIndexing())
+ m_has_new_literals_and_indexing = eLazyBoolYes;
+ else
+ m_has_new_literals_and_indexing = eLazyBoolNo;
+ }
+
+ return (m_has_new_literals_and_indexing == eLazyBoolYes);
+ }
+
+ virtual void
+ SymbolsDidLoad (const ModuleList& module_list)
+ {
+ m_negative_complete_class_cache.clear();
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ObjCLanguageRuntime can see and modify these
+ //------------------------------------------------------------------
+ ObjCLanguageRuntime(Process *process);
+
+ virtual bool CalculateHasNewLiteralsAndIndexing()
+ {
+ return false;
+ }
+
+
+ bool
+ ISAIsCached (ObjCISA isa) const
+ {
+ return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
+ }
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
+ {
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name);
+
+ bool
+ AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
+ {
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
+ return true;
+ }
+ return false;
+ }
+
+private:
+ // We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
+ // function over and over.
+
+ // FIXME: We need to watch for the loading of Protocols, and flush the cache for any
+ // class that we see so changed.
+
+ struct ClassAndSel
+ {
+ ClassAndSel()
+ {
+ sel_addr = LLDB_INVALID_ADDRESS;
+ class_addr = LLDB_INVALID_ADDRESS;
+ }
+ ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) :
+ class_addr (in_class_addr),
+ sel_addr(in_sel_addr)
+ {
+ }
+ bool operator== (const ClassAndSel &rhs)
+ {
+ if (class_addr == rhs.class_addr
+ && sel_addr == rhs.sel_addr)
+ return true;
+ else
+ return false;
+ }
+
+ bool operator< (const ClassAndSel &rhs) const
+ {
+ if (class_addr < rhs.class_addr)
+ return true;
+ else if (class_addr > rhs.class_addr)
+ return false;
+ else
+ {
+ if (sel_addr < rhs.sel_addr)
+ return true;
+ else
+ return false;
+ }
+ }
+
+ lldb::addr_t class_addr;
+ lldb::addr_t sel_addr;
+ };
+
+ typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
+ typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
+ typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
+ typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
+ typedef HashToISAMap::iterator HashToISAIterator;
+
+ MsgImplMap m_impl_cache;
+ LazyBool m_has_new_literals_and_indexing;
+ ISAToDescriptorMap m_isa_to_descriptor;
+ HashToISAMap m_hash_to_isa_map;
+
+protected:
+ uint32_t m_isa_to_descriptor_stop_id;
+
+ typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
+ CompleteClassMap m_complete_class_cache;
+
+ struct ConstStringSetHelpers {
+ size_t operator () (const ConstString& arg) const // for hashing
+ {
+ return (size_t)arg.GetCString();
+ }
+ bool operator () (const ConstString& arg1, const ConstString& arg2) const // for equality
+ {
+ return arg1.operator==(arg2);
+ }
+ };
+ typedef std::unordered_set<ConstString, ConstStringSetHelpers, ConstStringSetHelpers> CompleteClassSet;
+ CompleteClassSet m_negative_complete_class_cache;
+
+ ISAToDescriptorIterator
+ GetDescriptorIterator (const ConstString &name);
+
+ DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ObjCLanguageRuntime_h_
diff --git a/include/lldb/Target/OperatingSystem.h b/include/lldb/Target/OperatingSystem.h
new file mode 100644
index 000000000000..f1c0eb06026f
--- /dev/null
+++ b/include/lldb/Target/OperatingSystem.h
@@ -0,0 +1,101 @@
+//===-- OperatingSystem.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_OperatingSystem_h_
+#define liblldb_OperatingSystem_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/PluginInterface.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+/// @class OperatingSystem OperatingSystem.h "lldb/Target/OperatingSystem.h"
+/// @brief A plug-in interface definition class for halted OS helpers.
+///
+/// Halted OS plug-ins can be used by any process to locate and create
+/// OS objects, like threads, during the lifetime of a debug session.
+/// This is commonly used when attaching to an operating system that is
+/// halted, such as when debugging over JTAG or connecting to low level
+/// kernel debug services.
+//----------------------------------------------------------------------
+
+class OperatingSystem :
+ public PluginInterface
+
+{
+public:
+ //------------------------------------------------------------------
+ /// Find a halted OS plugin for a given process.
+ ///
+ /// Scans the installed OperatingSystem plug-ins and tries to find
+ /// an instance that matches the current target triple and
+ /// executable.
+ ///
+ /// @param[in] process
+ /// The process for which to try and locate a halted OS
+ /// plug-in instance.
+ ///
+ /// @param[in] plugin_name
+ /// An optional name of a specific halted OS plug-in that
+ /// should be used. If NULL, pick the best plug-in.
+ //------------------------------------------------------------------
+ static OperatingSystem*
+ FindPlugin (Process *process, const char *plugin_name);
+
+ //------------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------------
+ OperatingSystem (Process *process);
+
+ virtual
+ ~OperatingSystem();
+
+ //------------------------------------------------------------------
+ // Plug-in Methods
+ //------------------------------------------------------------------
+ virtual bool
+ UpdateThreadList (ThreadList &old_thread_list,
+ ThreadList &real_thread_list,
+ ThreadList &new_thread_list) = 0;
+
+ virtual void
+ ThreadWasSelected (Thread *thread) = 0;
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForThread (Thread *thread, lldb::addr_t reg_data_addr) = 0;
+
+ virtual lldb::StopInfoSP
+ CreateThreadStopReason (Thread *thread) = 0;
+
+ virtual lldb::ThreadSP
+ CreateThread (lldb::tid_t tid, lldb::addr_t context)
+ {
+ return lldb::ThreadSP();
+ }
+
+ virtual bool
+ IsOperatingSystemPluginThread (const lldb::ThreadSP &thread_sp);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Process* m_process; ///< The process that this dynamic loader plug-in is tracking.
+private:
+ DISALLOW_COPY_AND_ASSIGN (OperatingSystem);
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef liblldb_OperatingSystem_h_
diff --git a/include/lldb/Target/PathMappingList.h b/include/lldb/Target/PathMappingList.h
new file mode 100644
index 000000000000..b5bcbbfd768f
--- /dev/null
+++ b/include/lldb/Target/PathMappingList.h
@@ -0,0 +1,171 @@
+//===-- PathMappingList.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_PathMappingList_h_
+#define liblldb_PathMappingList_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+// Project includes
+
+namespace lldb_private {
+
+class PathMappingList
+{
+public:
+
+ typedef void (*ChangedCallback) (const PathMappingList &path_list,
+ void *baton);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ PathMappingList ();
+
+ PathMappingList (ChangedCallback callback,
+ void *callback_baton);
+
+ PathMappingList (const PathMappingList &rhs);
+
+ ~PathMappingList ();
+
+ const PathMappingList &
+ operator =(const PathMappingList &rhs);
+
+ void
+ Append (const ConstString &path, const ConstString &replacement, bool notify);
+
+ void
+ Append (const PathMappingList &rhs, bool notify);
+
+ void
+ Clear (bool notify);
+
+ // By default, dump all pairs.
+ void
+ Dump (Stream *s, int pair_index=-1);
+
+ bool
+ IsEmpty() const
+ {
+ return m_pairs.empty();
+ }
+
+ size_t
+ GetSize () const
+ {
+ return m_pairs.size();
+ }
+
+ bool
+ GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const;
+
+ void
+ Insert (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t insert_idx,
+ bool notify);
+
+ bool
+ Remove (off_t index, bool notify);
+
+ bool
+ Remove (const ConstString &path, bool notify);
+
+ bool
+ Replace (const ConstString &path,
+ const ConstString &replacement,
+ bool notify);
+
+ bool
+ Replace (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t index,
+ bool notify);
+ bool
+ RemapPath (const ConstString &path, ConstString &new_path) const;
+
+ //------------------------------------------------------------------
+ /// Remaps a source file given \a path into \a new_path.
+ ///
+ /// Remaps \a path if any source remappings match. This function
+ /// does NOT stat the file system so it can be used in tight loops
+ /// where debug info is being parsed.
+ ///
+ /// @param[in] path
+ /// The original source file path to try and remap.
+ ///
+ /// @param[out] new_path
+ /// The newly remapped filespec that is may or may not exist.
+ ///
+ /// @return
+ /// /b true if \a path was successfully located and \a new_path
+ /// is filled in with a new source path, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ RemapPath (const char *path, std::string &new_path) const;
+
+
+ //------------------------------------------------------------------
+ /// Finds a source file given a file spec using the path remappings.
+ ///
+ /// Tries to resolve \a orig_spec by checking the path remappings.
+ /// It makes sure the file exists by checking with the file system,
+ /// so this call can be expensive if the remappings are on a network
+ /// or are even on the local file system, so use this function
+ /// sparingly (not in a tight debug info parsing loop).
+ ///
+ /// @param[in] orig_spec
+ /// The original source file path to try and remap.
+ ///
+ /// @param[out] new_spec
+ /// The newly remapped filespec that is guaranteed to exist.
+ ///
+ /// @return
+ /// /b true if \a orig_spec was successfully located and
+ /// \a new_spec is filled in with an existing file spec,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const;
+
+ uint32_t
+ FindIndexForPath (const ConstString &path) const;
+
+ uint32_t
+ GetModificationID() const
+ {
+ return m_mod_id;
+ }
+protected:
+ typedef std::pair <ConstString, ConstString> pair;
+ typedef std::vector <pair> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ iterator
+ FindIteratorForPath (const ConstString &path);
+
+ const_iterator
+ FindIteratorForPath (const ConstString &path) const;
+
+ collection m_pairs;
+ ChangedCallback m_callback;
+ void * m_callback_baton;
+ uint32_t m_mod_id; // Incremented anytime anything is added or removed.
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_PathMappingList_h_
diff --git a/include/lldb/Target/Platform.h b/include/lldb/Target/Platform.h
new file mode 100644
index 000000000000..b0a07946e74e
--- /dev/null
+++ b/include/lldb/Target/Platform.h
@@ -0,0 +1,755 @@
+//===-- Platform.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_Platform_h_
+#define liblldb_Platform_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+ //----------------------------------------------------------------------
+ /// @class Platform Platform.h "lldb/Target/Platform.h"
+ /// @brief A plug-in interface definition class for debug platform that
+ /// includes many platform abilities such as:
+ /// @li getting platform information such as supported architectures,
+ /// supported binary file formats and more
+ /// @li launching new processes
+ /// @li attaching to existing processes
+ /// @li download/upload files
+ /// @li execute shell commands
+ /// @li listing and getting info for existing processes
+ /// @li attaching and possibly debugging the platform's kernel
+ //----------------------------------------------------------------------
+ class Platform : public PluginInterface
+ {
+ public:
+
+ //------------------------------------------------------------------
+ /// Get the native host platform plug-in.
+ ///
+ /// There should only be one of these for each host that LLDB runs
+ /// upon that should be statically compiled in and registered using
+ /// preprocessor macros or other similar build mechanisms in a
+ /// PlatformSubclass::Initialize() function.
+ ///
+ /// This platform will be used as the default platform when launching
+ /// or attaching to processes unless another platform is specified.
+ //------------------------------------------------------------------
+ static lldb::PlatformSP
+ GetDefaultPlatform ();
+
+ static lldb::PlatformSP
+ GetPlatformForArchitecture (const ArchSpec &arch,
+ ArchSpec *platform_arch_ptr);
+
+ static const char *
+ GetHostPlatformName ();
+
+ static void
+ SetDefaultPlatform (const lldb::PlatformSP &platform_sp);
+
+ static lldb::PlatformSP
+ Create (const char *platform_name, Error &error);
+
+ static lldb::PlatformSP
+ Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error);
+
+ static uint32_t
+ GetNumConnectedRemotePlatforms ();
+
+ static lldb::PlatformSP
+ GetConnectedRemotePlatformAtIndex (uint32_t idx);
+
+ //------------------------------------------------------------------
+ /// Default Constructor
+ //------------------------------------------------------------------
+ Platform (bool is_host_platform);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from by the plug-in instance.
+ //------------------------------------------------------------------
+ virtual
+ ~Platform();
+
+ //------------------------------------------------------------------
+ /// Find a platform plugin for a given process.
+ ///
+ /// Scans the installed Platform plug-ins and tries to find
+ /// an instance that can be used for \a process
+ ///
+ /// @param[in] process
+ /// The process for which to try and locate a platform
+ /// plug-in instance.
+ ///
+ /// @param[in] plugin_name
+ /// An optional name of a specific platform plug-in that
+ /// should be used. If NULL, pick the best plug-in.
+ //------------------------------------------------------------------
+ static Platform*
+ FindPlugin (Process *process, const ConstString &plugin_name);
+
+ //------------------------------------------------------------------
+ /// Set the target's executable based off of the existing
+ /// architecture information in \a target given a path to an
+ /// executable \a exe_file.
+ ///
+ /// Each platform knows the architectures that it supports and can
+ /// select the correct architecture slice within \a exe_file by
+ /// inspecting the architecture in \a target. If the target had an
+ /// architecture specified, then in can try and obey that request
+ /// and optionally fail if the architecture doesn't match up.
+ /// If no architecture is specified, the platform should select the
+ /// default architecture from \a exe_file. Any application bundles
+ /// or executable wrappers can also be inspected for the actual
+ /// application binary within the bundle that should be used.
+ ///
+ /// @return
+ /// Returns \b true if this Platform plug-in was able to find
+ /// a suitable executable, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &arch,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr);
+
+
+ //------------------------------------------------------------------
+ /// Find a symbol file given a symbol file module specification.
+ ///
+ /// Each platform might have tricks to find symbol files for an
+ /// executable given information in a symbol file ModuleSpec. Some
+ /// platforms might also support symbol files that are bundles and
+ /// know how to extract the right symbol file given a bundle.
+ ///
+ /// @param[in] target
+ /// The target in which we are trying to resolve the symbol file.
+ /// The target has a list of modules that we might be able to
+ /// use in order to help find the right symbol file. If the
+ /// "m_file" or "m_platform_file" entries in the \a sym_spec
+ /// are filled in, then we might be able to locate a module in
+ /// the target, extract its UUID and locate a symbol file.
+ /// If just the "m_uuid" is specified, then we might be able
+ /// to find the module in the target that matches that UUID
+ /// and pair the symbol file along with it. If just "m_symbol_file"
+ /// is specified, we can use a variety of tricks to locate the
+ /// symbols in an SDK, PDK, or other development kit location.
+ ///
+ /// @param[in] sym_spec
+ /// A module spec that describes some information about the
+ /// symbol file we are trying to resolve. The ModuleSpec might
+ /// contain the following:
+ /// m_file - A full or partial path to an executable from the
+ /// target (might be empty).
+ /// m_platform_file - Another executable hint that contains
+ /// the path to the file as known on the
+ /// local/remote platform.
+ /// m_symbol_file - A full or partial path to a symbol file
+ /// or symbol bundle that should be used when
+ /// trying to resolve the symbol file.
+ /// m_arch - The architecture we are looking for when resolving
+ /// the symbol file.
+ /// m_uuid - The UUID of the executable and symbol file. This
+ /// can often be used to match up an exectuable with
+ /// a symbol file, or resolve an symbol file in a
+ /// symbol file bundle.
+ ///
+ /// @param[out] sym_file
+ /// The resolved symbol file spec if the returned error
+ /// indicates succes.
+ ///
+ /// @return
+ /// Returns an error that describes success or failure.
+ //------------------------------------------------------------------
+ virtual Error
+ ResolveSymbolFile (Target &target,
+ const ModuleSpec &sym_spec,
+ FileSpec &sym_file);
+
+ //------------------------------------------------------------------
+ /// Resolves the FileSpec to a (possibly) remote path. Remote
+ /// platforms must override this to resolve to a path on the remote
+ /// side.
+ //------------------------------------------------------------------
+ virtual bool
+ ResolveRemotePath (const FileSpec &platform_path,
+ FileSpec &resolved_platform_path);
+
+ bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update);
+
+ bool
+ SetOSVersion (uint32_t major,
+ uint32_t minor,
+ uint32_t update);
+
+ bool
+ GetOSBuildString (std::string &s);
+
+ bool
+ GetOSKernelDescription (std::string &s);
+
+ // Returns the the hostname if we are connected, else the short plugin
+ // name.
+ ConstString
+ GetName ();
+
+ virtual const char *
+ GetHostname ();
+
+ virtual const char *
+ GetDescription () = 0;
+
+ //------------------------------------------------------------------
+ /// Report the current status for this platform.
+ ///
+ /// The returned string usually involves returning the OS version
+ /// (if available), and any SDK directory that might be being used
+ /// for local file caching, and if connected a quick blurb about
+ /// what this platform is connected to.
+ //------------------------------------------------------------------
+ virtual void
+ GetStatus (Stream &strm);
+
+ //------------------------------------------------------------------
+ // Subclasses must be able to fetch the current OS version
+ //
+ // Remote classes must be connected for this to succeed. Local
+ // subclasses don't need to override this function as it will just
+ // call the Host::GetOSVersion().
+ //------------------------------------------------------------------
+ virtual bool
+ GetRemoteOSVersion ()
+ {
+ return false;
+ }
+
+ virtual bool
+ GetRemoteOSBuildString (std::string &s)
+ {
+ s.clear();
+ return false;
+ }
+
+ virtual bool
+ GetRemoteOSKernelDescription (std::string &s)
+ {
+ s.clear();
+ return false;
+ }
+
+ // Remote Platform subclasses need to override this function
+ virtual ArchSpec
+ GetRemoteSystemArchitecture ()
+ {
+ return ArchSpec(); // Return an invalid architecture
+ }
+
+ virtual const char *
+ GetUserName (uint32_t uid);
+
+ virtual const char *
+ GetGroupName (uint32_t gid);
+
+ //------------------------------------------------------------------
+ /// Locate a file for a platform.
+ ///
+ /// The default implementation of this function will return the same
+ /// file patch in \a local_file as was in \a platform_file.
+ ///
+ /// @param[in] platform_file
+ /// The platform file path to locate and cache locally.
+ ///
+ /// @param[in] uuid_ptr
+ /// If we know the exact UUID of the file we are looking for, it
+ /// can be specified. If it is not specified, we might now know
+ /// the exact file. The UUID is usually some sort of MD5 checksum
+ /// for the file and is sometimes known by dynamic linkers/loaders.
+ /// If the UUID is known, it is best to supply it to platform
+ /// file queries to ensure we are finding the correct file, not
+ /// just a file at the correct path.
+ ///
+ /// @param[out] local_file
+ /// A locally cached version of the platform file. For platforms
+ /// that describe the current host computer, this will just be
+ /// the same file. For remote platforms, this file might come from
+ /// and SDK directory, or might need to be sync'ed over to the
+ /// current machine for efficient debugging access.
+ ///
+ /// @return
+ /// An error object.
+ //------------------------------------------------------------------
+ virtual Error
+ GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file);
+
+ //----------------------------------------------------------------------
+ // Locate the scripting resource given a module specification.
+ //
+ // Locating the file should happen only on the local computer or using
+ // the current computers global settings.
+ //----------------------------------------------------------------------
+ virtual FileSpecList
+ LocateExecutableScriptingResources (Target *target,
+ Module &module);
+
+ virtual Error
+ GetSharedModule (const ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
+ virtual Error
+ ConnectRemote (Args& args);
+
+ virtual Error
+ DisconnectRemote ();
+
+ //------------------------------------------------------------------
+ /// Get the platform's supported architectures in the order in which
+ /// they should be searched.
+ ///
+ /// @param[in] idx
+ /// A zero based architecture index
+ ///
+ /// @param[out] arch
+ /// A copy of the archgitecture at index if the return value is
+ /// \b true.
+ ///
+ /// @return
+ /// \b true if \a arch was filled in and is valid, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) = 0;
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (Target &target,
+ BreakpointSite *bp_site) = 0;
+
+ //------------------------------------------------------------------
+ /// Launch a new process on a platform, not necessarily for
+ /// debugging, it could be just for running the process.
+ //------------------------------------------------------------------
+ virtual Error
+ LaunchProcess (ProcessLaunchInfo &launch_info);
+
+ //------------------------------------------------------------------
+ /// Lets a platform answer if it is compatible with a given
+ /// architecture and the target triple contained within.
+ //------------------------------------------------------------------
+ virtual bool
+ IsCompatibleArchitecture (const ArchSpec &arch,
+ bool exact_arch_match,
+ ArchSpec *compatible_arch_ptr);
+
+ //------------------------------------------------------------------
+ /// Not all platforms will support debugging a process by spawning
+ /// somehow halted for a debugger (specified using the
+ /// "eLaunchFlagDebug" launch flag) and then attaching. If your
+ /// platform doesn't support this, override this function and return
+ /// false.
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebugProcess ()
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Subclasses should NOT need to implement this function as it uses
+ /// the Platform::LaunchProcess() followed by Platform::Attach ()
+ //------------------------------------------------------------------
+ lldb::ProcessSP
+ 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);
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using a process ID.
+ ///
+ /// Each platform subclass needs to implement this function and
+ /// attempt to attach to the process with the process ID of \a pid.
+ /// The platform subclass should return an appropriate ProcessSP
+ /// subclass that is attached to the process, or an empty shared
+ /// pointer with an appriopriate error.
+ ///
+ /// @param[in] pid
+ /// The process ID that we should attempt to attach to.
+ ///
+ /// @return
+ /// An appropriate ProcessSP containing a valid shared pointer
+ /// to the default Process subclass for the platform that is
+ /// attached to the process, or an empty shared pointer with an
+ /// appriopriate error fill into the \a error object.
+ //------------------------------------------------------------------
+ virtual lldb::ProcessSP
+ Attach (ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Listener &listener,
+ Error &error) = 0;
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process by process name.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses. It will first call
+ /// Process::WillAttach (const char *) and if that returns \b
+ /// true, Process::DoAttach (const char *) will be called to
+ /// actually do the attach. If DoAttach returns \b true, then
+ /// Process::DidAttach() will be called.
+ ///
+ /// @param[in] process_name
+ /// A process name to match against the current process list.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ //------------------------------------------------------------------
+// virtual lldb::ProcessSP
+// Attach (const char *process_name,
+// bool wait_for_launch,
+// Error &error) = 0;
+
+ //------------------------------------------------------------------
+ // The base class Platform will take care of the host platform.
+ // Subclasses will need to fill in the remote case.
+ //------------------------------------------------------------------
+ virtual uint32_t
+ FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &proc_infos);
+
+ virtual bool
+ GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
+
+ //------------------------------------------------------------------
+ // Set a breakpoint on all functions that can end up creating a thread
+ // for this platform. This is needed when running expressions and
+ // also for process control.
+ //------------------------------------------------------------------
+ virtual lldb::BreakpointSP
+ SetThreadCreationBreakpoint (Target &target);
+
+
+ const std::string &
+ GetRemoteURL () const
+ {
+ return m_remote_url;
+ }
+
+ bool
+ IsHost () const
+ {
+ return m_is_host; // Is this the default host platform?
+ }
+
+ bool
+ IsRemote () const
+ {
+ return !m_is_host;
+ }
+
+ virtual bool
+ IsConnected () const
+ {
+ // Remote subclasses should override this function
+ return IsHost();
+ }
+
+ const ArchSpec &
+ GetSystemArchitecture();
+
+ void
+ SetSystemArchitecture (const ArchSpec &arch)
+ {
+ m_system_arch = arch;
+ if (IsHost())
+ m_os_version_set_while_connected = m_system_arch.IsValid();
+ }
+
+ // Used for column widths
+ size_t
+ GetMaxUserIDNameLength() const
+ {
+ return m_max_uid_name_len;
+ }
+ // Used for column widths
+ size_t
+ GetMaxGroupIDNameLength() const
+ {
+ return m_max_gid_name_len;
+ }
+
+ const ConstString &
+ GetSDKRootDirectory () const
+ {
+ return m_sdk_sysroot;
+ }
+
+ void
+ SetSDKRootDirectory (const ConstString &dir)
+ {
+ m_sdk_sysroot = dir;
+ }
+
+ const ConstString &
+ GetSDKBuild () const
+ {
+ return m_sdk_build;
+ }
+
+ void
+ SetSDKBuild (const ConstString &sdk_build)
+ {
+ m_sdk_build = sdk_build;
+ }
+
+ // There may be modules that we don't want to find by default for operations like "setting breakpoint by name".
+ // The platform will return "true" from this call if the passed in module happens to be one of these.
+
+ virtual bool
+ ModuleIsExcludedForNonModuleSpecificSearches (Target &target, const lldb::ModuleSP &module_sp)
+ {
+ return false;
+ }
+
+ virtual size_t
+ GetEnvironment (StringList &environment);
+
+ protected:
+ bool m_is_host;
+ // Set to true when we are able to actually set the OS version while
+ // being connected. For remote platforms, we might set the version ahead
+ // of time before we actually connect and this version might change when
+ // we actually connect to a remote platform. For the host platform this
+ // will be set to the once we call Host::GetOSVersion().
+ bool m_os_version_set_while_connected;
+ bool m_system_arch_set_while_connected;
+ ConstString m_sdk_sysroot; // the root location of where the SDK files are all located
+ ConstString m_sdk_build;
+ std::string m_remote_url;
+ std::string m_name;
+ uint32_t m_major_os_version;
+ uint32_t m_minor_os_version;
+ uint32_t m_update_os_version;
+ ArchSpec m_system_arch; // The architecture of the kernel or the remote platform
+ typedef std::map<uint32_t, ConstString> IDToNameMap;
+ Mutex m_uid_map_mutex;
+ Mutex m_gid_map_mutex;
+ IDToNameMap m_uid_map;
+ IDToNameMap m_gid_map;
+ size_t m_max_uid_name_len;
+ size_t m_max_gid_name_len;
+
+ const char *
+ GetCachedUserName (uint32_t uid)
+ {
+ Mutex::Locker locker (m_uid_map_mutex);
+ IDToNameMap::iterator pos = m_uid_map.find (uid);
+ if (pos != m_uid_map.end())
+ {
+ // return the empty string if our string is NULL
+ // so we can tell when things were in the negative
+ // cached (didn't find a valid user name, don't keep
+ // trying)
+ return pos->second.AsCString("");
+ }
+ return NULL;
+ }
+
+ const char *
+ SetCachedUserName (uint32_t uid, const char *name, size_t name_len)
+ {
+ Mutex::Locker locker (m_uid_map_mutex);
+ ConstString const_name (name);
+ m_uid_map[uid] = const_name;
+ if (m_max_uid_name_len < name_len)
+ m_max_uid_name_len = name_len;
+ // Const strings lives forever in our const string pool, so we can return the const char *
+ return const_name.GetCString();
+ }
+
+ void
+ SetUserNameNotFound (uint32_t uid)
+ {
+ Mutex::Locker locker (m_uid_map_mutex);
+ m_uid_map[uid] = ConstString();
+ }
+
+
+ void
+ ClearCachedUserNames ()
+ {
+ Mutex::Locker locker (m_uid_map_mutex);
+ m_uid_map.clear();
+ }
+
+ const char *
+ GetCachedGroupName (uint32_t gid)
+ {
+ Mutex::Locker locker (m_gid_map_mutex);
+ IDToNameMap::iterator pos = m_gid_map.find (gid);
+ if (pos != m_gid_map.end())
+ {
+ // return the empty string if our string is NULL
+ // so we can tell when things were in the negative
+ // cached (didn't find a valid group name, don't keep
+ // trying)
+ return pos->second.AsCString("");
+ }
+ return NULL;
+ }
+
+ const char *
+ SetCachedGroupName (uint32_t gid, const char *name, size_t name_len)
+ {
+ Mutex::Locker locker (m_gid_map_mutex);
+ ConstString const_name (name);
+ m_gid_map[gid] = const_name;
+ if (m_max_gid_name_len < name_len)
+ m_max_gid_name_len = name_len;
+ // Const strings lives forever in our const string pool, so we can return the const char *
+ return const_name.GetCString();
+ }
+
+ void
+ SetGroupNameNotFound (uint32_t gid)
+ {
+ Mutex::Locker locker (m_gid_map_mutex);
+ m_gid_map[gid] = ConstString();
+ }
+
+ void
+ ClearCachedGroupNames ()
+ {
+ Mutex::Locker locker (m_gid_map_mutex);
+ m_gid_map.clear();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Platform);
+ };
+
+
+ class PlatformList
+ {
+ public:
+ PlatformList() :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_platforms (),
+ m_selected_platform_sp()
+ {
+ }
+
+ ~PlatformList()
+ {
+ }
+
+ void
+ Append (const lldb::PlatformSP &platform_sp, bool set_selected)
+ {
+ Mutex::Locker locker (m_mutex);
+ m_platforms.push_back (platform_sp);
+ if (set_selected)
+ m_selected_platform_sp = m_platforms.back();
+ }
+
+ size_t
+ GetSize()
+ {
+ Mutex::Locker locker (m_mutex);
+ return m_platforms.size();
+ }
+
+ lldb::PlatformSP
+ GetAtIndex (uint32_t idx)
+ {
+ lldb::PlatformSP platform_sp;
+ {
+ Mutex::Locker locker (m_mutex);
+ if (idx < m_platforms.size())
+ platform_sp = m_platforms[idx];
+ }
+ return platform_sp;
+ }
+
+ //------------------------------------------------------------------
+ /// Select the active platform.
+ ///
+ /// In order to debug remotely, other platform's can be remotely
+ /// connected to and set as the selected platform for any subsequent
+ /// debugging. This allows connection to remote targets and allows
+ /// the ability to discover process info, launch and attach to remote
+ /// processes.
+ //------------------------------------------------------------------
+ lldb::PlatformSP
+ GetSelectedPlatform ()
+ {
+ Mutex::Locker locker (m_mutex);
+ if (!m_selected_platform_sp && !m_platforms.empty())
+ m_selected_platform_sp = m_platforms.front();
+
+ return m_selected_platform_sp;
+ }
+
+ void
+ SetSelectedPlatform (const lldb::PlatformSP &platform_sp)
+ {
+ if (platform_sp)
+ {
+ Mutex::Locker locker (m_mutex);
+ const size_t num_platforms = m_platforms.size();
+ for (size_t idx=0; idx<num_platforms; ++idx)
+ {
+ if (m_platforms[idx].get() == platform_sp.get())
+ {
+ m_selected_platform_sp = m_platforms[idx];
+ return;
+ }
+ }
+ m_platforms.push_back (platform_sp);
+ m_selected_platform_sp = m_platforms.back();
+ }
+ }
+
+ protected:
+ typedef std::vector<lldb::PlatformSP> collection;
+ mutable Mutex m_mutex;
+ collection m_platforms;
+ lldb::PlatformSP m_selected_platform_sp;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformList);
+ };
+} // namespace lldb_private
+
+#endif // liblldb_Platform_h_
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h
new file mode 100644
index 000000000000..ef89a1eb1418
--- /dev/null
+++ b/include/lldb/Target/Process.h
@@ -0,0 +1,3786 @@
+//===-- Process.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_Process_h_
+#define liblldb_Process_h_
+
+// C Includes
+#include <limits.h>
+#include <spawn.h>
+
+// C++ Includes
+#include <list>
+#include <iosfwd>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Expression/IRDynamicChecks.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/ProcessRunLock.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/Memory.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// ProcessProperties
+//----------------------------------------------------------------------
+class ProcessProperties : public Properties
+{
+public:
+ ProcessProperties(bool is_global);
+
+ virtual
+ ~ProcessProperties();
+
+ bool
+ GetDisableMemoryCache() const;
+
+ Args
+ GetExtraStartupCommands () const;
+
+ void
+ SetExtraStartupCommands (const Args &args);
+
+ FileSpec
+ GetPythonOSPluginPath () const;
+
+ void
+ SetPythonOSPluginPath (const FileSpec &file);
+
+ bool
+ GetIgnoreBreakpointsInExpressions () const;
+
+ void
+ SetIgnoreBreakpointsInExpressions (bool ignore);
+
+ bool
+ GetUnwindOnErrorInExpressions () const;
+
+ void
+ SetUnwindOnErrorInExpressions (bool ignore);
+
+ bool
+ GetStopOnSharedLibraryEvents () const;
+
+ void
+ SetStopOnSharedLibraryEvents (bool stop);
+
+ bool
+ GetDetachKeepsStopped () const;
+
+ void
+ SetDetachKeepsStopped (bool keep_stopped);
+};
+
+typedef std::shared_ptr<ProcessProperties> ProcessPropertiesSP;
+
+//----------------------------------------------------------------------
+// ProcessInfo
+//
+// A base class for information for a process. This can be used to fill
+// out information for a process prior to launching it, or it can be
+// used for an instance of a process and can be filled in with the
+// existing values for that process.
+//----------------------------------------------------------------------
+class ProcessInfo
+{
+public:
+ ProcessInfo () :
+ m_executable (),
+ m_arguments (),
+ m_environment (),
+ m_uid (UINT32_MAX),
+ m_gid (UINT32_MAX),
+ m_arch(),
+ m_pid (LLDB_INVALID_PROCESS_ID)
+ {
+ }
+
+ ProcessInfo (const char *name,
+ const ArchSpec &arch,
+ lldb::pid_t pid) :
+ m_executable (name, false),
+ m_arguments (),
+ m_environment(),
+ m_uid (UINT32_MAX),
+ m_gid (UINT32_MAX),
+ m_arch (arch),
+ m_pid (pid)
+ {
+ }
+
+ void
+ Clear ()
+ {
+ m_executable.Clear();
+ m_arguments.Clear();
+ m_environment.Clear();
+ m_uid = UINT32_MAX;
+ m_gid = UINT32_MAX;
+ m_arch.Clear();
+ m_pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ const char *
+ GetName() const
+ {
+ return m_executable.GetFilename().GetCString();
+ }
+
+ size_t
+ GetNameLength() const
+ {
+ return m_executable.GetFilename().GetLength();
+ }
+
+ FileSpec &
+ GetExecutableFile ()
+ {
+ return m_executable;
+ }
+
+ void
+ SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg)
+ {
+ if (exe_file)
+ {
+ m_executable = exe_file;
+ if (add_exe_file_as_first_arg)
+ {
+ char filename[PATH_MAX];
+ if (exe_file.GetPath(filename, sizeof(filename)))
+ m_arguments.InsertArgumentAtIndex (0, filename);
+ }
+ }
+ else
+ {
+ m_executable.Clear();
+ }
+ }
+
+ const FileSpec &
+ GetExecutableFile () const
+ {
+ return m_executable;
+ }
+
+ uint32_t
+ GetUserID() const
+ {
+ return m_uid;
+ }
+
+ uint32_t
+ GetGroupID() const
+ {
+ return m_gid;
+ }
+
+ bool
+ UserIDIsValid () const
+ {
+ return m_uid != UINT32_MAX;
+ }
+
+ bool
+ GroupIDIsValid () const
+ {
+ return m_gid != UINT32_MAX;
+ }
+
+ void
+ SetUserID (uint32_t uid)
+ {
+ m_uid = uid;
+ }
+
+ void
+ SetGroupID (uint32_t gid)
+ {
+ m_gid = gid;
+ }
+
+ ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ lldb::pid_t
+ GetProcessID () const
+ {
+ return m_pid;
+ }
+
+ void
+ SetProcessID (lldb::pid_t pid)
+ {
+ m_pid = pid;
+ }
+
+ bool
+ ProcessIDIsValid() const
+ {
+ return m_pid != LLDB_INVALID_PROCESS_ID;
+ }
+
+ void
+ Dump (Stream &s, Platform *platform) const;
+
+ Args &
+ GetArguments ()
+ {
+ return m_arguments;
+ }
+
+ const Args &
+ GetArguments () const
+ {
+ return m_arguments;
+ }
+
+ const char *
+ GetArg0 () const
+ {
+ if (m_arg0.empty())
+ return NULL;
+ return m_arg0.c_str();
+ }
+
+ void
+ SetArg0 (const char *arg)
+ {
+ if (arg && arg[0])
+ m_arg0 = arg;
+ else
+ m_arg0.clear();
+ }
+
+ void
+ SetArguments (const Args& args, bool first_arg_is_executable);
+
+ void
+ SetArguments (char const **argv, bool first_arg_is_executable);
+
+ Args &
+ GetEnvironmentEntries ()
+ {
+ return m_environment;
+ }
+
+ const Args &
+ GetEnvironmentEntries () const
+ {
+ return m_environment;
+ }
+
+protected:
+ FileSpec m_executable;
+ std::string m_arg0; // argv[0] if supported. If empty, then use m_executable.
+ // Not all process plug-ins support specifying an argv[0]
+ // that differs from the resolved platform executable
+ // (which is in m_executable)
+ Args m_arguments; // All program arguments except argv[0]
+ Args m_environment;
+ uint32_t m_uid;
+ uint32_t m_gid;
+ ArchSpec m_arch;
+ lldb::pid_t m_pid;
+};
+
+//----------------------------------------------------------------------
+// ProcessInstanceInfo
+//
+// Describes an existing process and any discoverable information that
+// pertains to that process.
+//----------------------------------------------------------------------
+class ProcessInstanceInfo : public ProcessInfo
+{
+public:
+ ProcessInstanceInfo () :
+ ProcessInfo (),
+ m_euid (UINT32_MAX),
+ m_egid (UINT32_MAX),
+ m_parent_pid (LLDB_INVALID_PROCESS_ID)
+ {
+ }
+
+ ProcessInstanceInfo (const char *name,
+ const ArchSpec &arch,
+ lldb::pid_t pid) :
+ ProcessInfo (name, arch, pid),
+ m_euid (UINT32_MAX),
+ m_egid (UINT32_MAX),
+ m_parent_pid (LLDB_INVALID_PROCESS_ID)
+ {
+ }
+
+ void
+ Clear ()
+ {
+ ProcessInfo::Clear();
+ m_euid = UINT32_MAX;
+ m_egid = UINT32_MAX;
+ m_parent_pid = LLDB_INVALID_PROCESS_ID;
+ }
+
+ uint32_t
+ GetEffectiveUserID() const
+ {
+ return m_euid;
+ }
+
+ uint32_t
+ GetEffectiveGroupID() const
+ {
+ return m_egid;
+ }
+
+ bool
+ EffectiveUserIDIsValid () const
+ {
+ return m_euid != UINT32_MAX;
+ }
+
+ bool
+ EffectiveGroupIDIsValid () const
+ {
+ return m_egid != UINT32_MAX;
+ }
+
+ void
+ SetEffectiveUserID (uint32_t uid)
+ {
+ m_euid = uid;
+ }
+
+ void
+ SetEffectiveGroupID (uint32_t gid)
+ {
+ m_egid = gid;
+ }
+
+ lldb::pid_t
+ GetParentProcessID () const
+ {
+ return m_parent_pid;
+ }
+
+ void
+ SetParentProcessID (lldb::pid_t pid)
+ {
+ m_parent_pid = pid;
+ }
+
+ bool
+ ParentProcessIDIsValid() const
+ {
+ return m_parent_pid != LLDB_INVALID_PROCESS_ID;
+ }
+
+ void
+ Dump (Stream &s, Platform *platform) const;
+
+ static void
+ DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose);
+
+ void
+ DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const;
+
+protected:
+ uint32_t m_euid;
+ uint32_t m_egid;
+ lldb::pid_t m_parent_pid;
+};
+
+
+//----------------------------------------------------------------------
+// ProcessLaunchInfo
+//
+// Describes any information that is required to launch a process.
+//----------------------------------------------------------------------
+
+class ProcessLaunchInfo : public ProcessInfo
+{
+public:
+
+ class FileAction
+ {
+ public:
+ enum Action
+ {
+ eFileActionNone,
+ eFileActionClose,
+ eFileActionDuplicate,
+ eFileActionOpen
+ };
+
+
+ FileAction () :
+ m_action (eFileActionNone),
+ m_fd (-1),
+ m_arg (-1),
+ m_path ()
+ {
+ }
+
+ void
+ Clear()
+ {
+ m_action = eFileActionNone;
+ m_fd = -1;
+ m_arg = -1;
+ m_path.clear();
+ }
+
+ bool
+ Close (int fd);
+
+ bool
+ Duplicate (int fd, int dup_fd);
+
+ bool
+ Open (int fd, const char *path, bool read, bool write);
+
+ static bool
+ AddPosixSpawnFileAction (posix_spawn_file_actions_t *file_actions,
+ const FileAction *info,
+ Log *log,
+ Error& error);
+
+ int
+ GetFD () const
+ {
+ return m_fd;
+ }
+
+ Action
+ GetAction () const
+ {
+ return m_action;
+ }
+
+ int
+ GetActionArgument () const
+ {
+ return m_arg;
+ }
+
+ const char *
+ GetPath () const
+ {
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+ }
+
+ protected:
+ Action m_action; // The action for this file
+ int m_fd; // An existing file descriptor
+ int m_arg; // oflag for eFileActionOpen*, dup_fd for eFileActionDuplicate
+ std::string m_path; // A file path to use for opening after fork or posix_spawn
+ };
+
+ ProcessLaunchInfo () :
+ ProcessInfo(),
+ m_working_dir (),
+ m_plugin_name (),
+ m_shell (),
+ m_flags (0),
+ m_file_actions (),
+ m_pty (),
+ m_resume_count (0),
+ m_monitor_callback (NULL),
+ m_monitor_callback_baton (NULL),
+ m_monitor_signals (false)
+ {
+ }
+
+ 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)
+ {
+ if (stdin_path)
+ {
+ ProcessLaunchInfo::FileAction file_action;
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stdout_path)
+ {
+ ProcessLaunchInfo::FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stderr_path)
+ {
+ ProcessLaunchInfo::FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (working_directory)
+ SetWorkingDirectory(working_directory);
+ }
+
+ void
+ AppendFileAction (const FileAction &info)
+ {
+ m_file_actions.push_back(info);
+ }
+
+ bool
+ AppendCloseFileAction (int fd)
+ {
+ FileAction file_action;
+ if (file_action.Close (fd))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ AppendDuplicateFileAction (int fd, int dup_fd)
+ {
+ FileAction file_action;
+ if (file_action.Duplicate (fd, dup_fd))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ AppendOpenFileAction (int fd, const char *path, bool read, bool write)
+ {
+ FileAction file_action;
+ if (file_action.Open (fd, path, read, write))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+ }
+
+ bool
+ AppendSuppressFileAction (int fd, bool read, bool write)
+ {
+ FileAction file_action;
+ if (file_action.Open (fd, "/dev/null", read, write))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+ }
+
+ void
+ FinalizeFileActions (Target *target,
+ bool default_to_use_pty);
+
+ size_t
+ GetNumFileActions () const
+ {
+ return m_file_actions.size();
+ }
+
+ const FileAction *
+ GetFileActionAtIndex (size_t idx) const
+ {
+ if (idx < m_file_actions.size())
+ return &m_file_actions[idx];
+ return NULL;
+ }
+
+ const FileAction *
+ GetFileActionForFD (int fd) const
+ {
+ for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
+ {
+ if (m_file_actions[idx].GetFD () == fd)
+ return &m_file_actions[idx];
+ }
+ return NULL;
+ }
+
+ Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ const char *
+ GetWorkingDirectory () const
+ {
+ if (m_working_dir.empty())
+ return NULL;
+ return m_working_dir.c_str();
+ }
+
+ void
+ SetWorkingDirectory (const char *working_dir)
+ {
+ if (working_dir && working_dir[0])
+ m_working_dir.assign (working_dir);
+ else
+ m_working_dir.clear();
+ }
+
+ void
+ SwapWorkingDirectory (std::string &working_dir)
+ {
+ m_working_dir.swap (working_dir);
+ }
+
+
+ const char *
+ GetProcessPluginName () const
+ {
+ if (m_plugin_name.empty())
+ return NULL;
+ return m_plugin_name.c_str();
+ }
+
+ void
+ SetProcessPluginName (const char *plugin)
+ {
+ if (plugin && plugin[0])
+ m_plugin_name.assign (plugin);
+ else
+ m_plugin_name.clear();
+ }
+
+ const char *
+ GetShell () const
+ {
+ if (m_shell.empty())
+ return NULL;
+ return m_shell.c_str();
+ }
+
+ void
+ SetShell (const char * path)
+ {
+ if (path && path[0])
+ {
+ m_shell.assign (path);
+ m_flags.Set (lldb::eLaunchFlagLaunchInShell);
+ }
+ else
+ {
+ m_shell.clear();
+ m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
+ }
+ }
+
+ uint32_t
+ GetResumeCount () const
+ {
+ return m_resume_count;
+ }
+
+ void
+ SetResumeCount (uint32_t c)
+ {
+ m_resume_count = c;
+ }
+
+ bool
+ GetLaunchInSeparateProcessGroup ()
+ {
+ return m_flags.Test(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+ }
+
+ void
+ SetLaunchInSeparateProcessGroup (bool separate)
+ {
+ if (separate)
+ m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+ else
+ m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+
+ }
+
+ void
+ Clear ()
+ {
+ ProcessInfo::Clear();
+ m_working_dir.clear();
+ m_plugin_name.clear();
+ m_shell.clear();
+ m_flags.Clear();
+ m_file_actions.clear();
+ m_resume_count = 0;
+ }
+
+ bool
+ ConvertArgumentsForLaunchingInShell (Error &error,
+ bool localhost,
+ bool will_debug,
+ bool first_arg_is_full_shell_command);
+
+ void
+ SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
+ void *baton,
+ bool monitor_signals)
+ {
+ m_monitor_callback = callback;
+ m_monitor_callback_baton = baton;
+ m_monitor_signals = monitor_signals;
+ }
+
+ bool
+ MonitorProcess () const
+ {
+ if (m_monitor_callback && ProcessIDIsValid())
+ {
+ Host::StartMonitoringChildProcess (m_monitor_callback,
+ m_monitor_callback_baton,
+ GetProcessID(),
+ m_monitor_signals);
+ return true;
+ }
+ return false;
+ }
+
+ lldb_utility::PseudoTerminal &
+ GetPTY ()
+ {
+ return m_pty;
+ }
+
+protected:
+ std::string m_working_dir;
+ std::string m_plugin_name;
+ std::string m_shell;
+ Flags m_flags; // Bitwise OR of bits from lldb::LaunchFlags
+ std::vector<FileAction> m_file_actions; // File actions for any other files
+ lldb_utility::PseudoTerminal m_pty;
+ uint32_t m_resume_count; // How many times do we resume after launching
+ Host::MonitorChildProcessCallback m_monitor_callback;
+ void *m_monitor_callback_baton;
+ bool m_monitor_signals;
+
+};
+
+//----------------------------------------------------------------------
+// ProcessLaunchInfo
+//
+// Describes any information that is required to launch a process.
+//----------------------------------------------------------------------
+
+class ProcessAttachInfo : public ProcessInstanceInfo
+{
+public:
+ ProcessAttachInfo() :
+ ProcessInstanceInfo(),
+ m_plugin_name (),
+ m_resume_count (0),
+ m_wait_for_launch (false),
+ m_ignore_existing (true),
+ m_continue_once_attached (false)
+ {
+ }
+
+ ProcessAttachInfo (const ProcessLaunchInfo &launch_info) :
+ ProcessInstanceInfo(),
+ m_plugin_name (),
+ m_resume_count (0),
+ m_wait_for_launch (false),
+ m_ignore_existing (true),
+ m_continue_once_attached (false)
+ {
+ ProcessInfo::operator= (launch_info);
+ SetProcessPluginName (launch_info.GetProcessPluginName());
+ SetResumeCount (launch_info.GetResumeCount());
+ }
+
+ bool
+ GetWaitForLaunch () const
+ {
+ return m_wait_for_launch;
+ }
+
+ void
+ SetWaitForLaunch (bool b)
+ {
+ m_wait_for_launch = b;
+ }
+
+ bool
+ GetIgnoreExisting () const
+ {
+ return m_ignore_existing;
+ }
+
+ void
+ SetIgnoreExisting (bool b)
+ {
+ m_ignore_existing = b;
+ }
+
+ bool
+ GetContinueOnceAttached () const
+ {
+ return m_continue_once_attached;
+ }
+
+ void
+ SetContinueOnceAttached (bool b)
+ {
+ m_continue_once_attached = b;
+ }
+
+ uint32_t
+ GetResumeCount () const
+ {
+ return m_resume_count;
+ }
+
+ void
+ SetResumeCount (uint32_t c)
+ {
+ m_resume_count = c;
+ }
+
+ const char *
+ GetProcessPluginName () const
+ {
+ if (m_plugin_name.empty())
+ return NULL;
+ return m_plugin_name.c_str();
+ }
+
+ void
+ SetProcessPluginName (const char *plugin)
+ {
+ if (plugin && plugin[0])
+ m_plugin_name.assign (plugin);
+ else
+ m_plugin_name.clear();
+ }
+
+ void
+ Clear ()
+ {
+ ProcessInstanceInfo::Clear();
+ m_plugin_name.clear();
+ m_resume_count = 0;
+ m_wait_for_launch = false;
+ m_ignore_existing = true;
+ m_continue_once_attached = false;
+ }
+
+ bool
+ ProcessInfoSpecified () const
+ {
+ if (GetExecutableFile())
+ return true;
+ if (GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ if (GetParentProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ return false;
+ }
+protected:
+ std::string m_plugin_name;
+ uint32_t m_resume_count; // How many times do we resume after launching
+ bool m_wait_for_launch;
+ bool m_ignore_existing;
+ bool m_continue_once_attached; // Supports the use-case scenario of immediately continuing the process once attached.
+};
+
+class ProcessLaunchCommandOptions : public Options
+{
+public:
+
+ ProcessLaunchCommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~ProcessLaunchCommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ()
+ {
+ launch_info.Clear();
+ }
+
+ 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.
+
+ ProcessLaunchInfo launch_info;
+};
+
+//----------------------------------------------------------------------
+// ProcessInstanceInfoMatch
+//
+// A class to help matching one ProcessInstanceInfo to another.
+//----------------------------------------------------------------------
+
+class ProcessInstanceInfoMatch
+{
+public:
+ ProcessInstanceInfoMatch () :
+ m_match_info (),
+ m_name_match_type (eNameMatchIgnore),
+ m_match_all_users (false)
+ {
+ }
+
+ ProcessInstanceInfoMatch (const char *process_name,
+ NameMatchType process_name_match_type) :
+ m_match_info (),
+ m_name_match_type (process_name_match_type),
+ m_match_all_users (false)
+ {
+ m_match_info.GetExecutableFile().SetFile(process_name, false);
+ }
+
+ ProcessInstanceInfo &
+ GetProcessInfo ()
+ {
+ return m_match_info;
+ }
+
+ const ProcessInstanceInfo &
+ GetProcessInfo () const
+ {
+ return m_match_info;
+ }
+
+ bool
+ GetMatchAllUsers () const
+ {
+ return m_match_all_users;
+ }
+
+ void
+ SetMatchAllUsers (bool b)
+ {
+ m_match_all_users = b;
+ }
+
+ NameMatchType
+ GetNameMatchType () const
+ {
+ return m_name_match_type;
+ }
+
+ void
+ SetNameMatchType (NameMatchType name_match_type)
+ {
+ m_name_match_type = name_match_type;
+ }
+
+ bool
+ NameMatches (const char *process_name) const;
+
+ bool
+ Matches (const ProcessInstanceInfo &proc_info) const;
+
+ bool
+ MatchAllProcesses () const;
+ void
+ Clear ();
+
+protected:
+ ProcessInstanceInfo m_match_info;
+ NameMatchType m_name_match_type;
+ bool m_match_all_users;
+};
+
+class ProcessInstanceInfoList
+{
+public:
+ ProcessInstanceInfoList () :
+ m_infos()
+ {
+ }
+
+ void
+ Clear()
+ {
+ m_infos.clear();
+ }
+
+ size_t
+ GetSize()
+ {
+ return m_infos.size();
+ }
+
+ void
+ Append (const ProcessInstanceInfo &info)
+ {
+ m_infos.push_back (info);
+ }
+
+ const char *
+ GetProcessNameAtIndex (size_t idx)
+ {
+ if (idx < m_infos.size())
+ return m_infos[idx].GetName();
+ return NULL;
+ }
+
+ size_t
+ GetProcessNameLengthAtIndex (size_t idx)
+ {
+ if (idx < m_infos.size())
+ return m_infos[idx].GetNameLength();
+ return 0;
+ }
+
+ lldb::pid_t
+ GetProcessIDAtIndex (size_t idx)
+ {
+ if (idx < m_infos.size())
+ return m_infos[idx].GetProcessID();
+ return 0;
+ }
+
+ bool
+ GetInfoAtIndex (size_t idx, ProcessInstanceInfo &info)
+ {
+ if (idx < m_infos.size())
+ {
+ info = m_infos[idx];
+ return true;
+ }
+ return false;
+ }
+
+ // You must ensure "idx" is valid before calling this function
+ const ProcessInstanceInfo &
+ GetProcessInfoAtIndex (size_t idx) const
+ {
+ assert (idx < m_infos.size());
+ return m_infos[idx];
+ }
+
+protected:
+ typedef std::vector<ProcessInstanceInfo> collection;
+ collection m_infos;
+};
+
+
+// This class tracks the Modification state of the process. Things that can currently modify
+// the program are running the program (which will up the StopID) and writing memory (which
+// will up the MemoryID.)
+// FIXME: Should we also include modification of register states?
+
+class ProcessModID
+{
+friend bool operator== (const ProcessModID &lhs, const ProcessModID &rhs);
+public:
+ ProcessModID () :
+ m_stop_id (0),
+ m_last_natural_stop_id(0),
+ m_resume_id (0),
+ m_memory_id (0),
+ m_last_user_expression_resume (0),
+ m_running_user_expression (false)
+ {}
+
+ ProcessModID (const ProcessModID &rhs) :
+ m_stop_id (rhs.m_stop_id),
+ m_memory_id (rhs.m_memory_id)
+ {}
+
+ const ProcessModID & operator= (const ProcessModID &rhs)
+ {
+ if (this != &rhs)
+ {
+ m_stop_id = rhs.m_stop_id;
+ m_memory_id = rhs.m_memory_id;
+ }
+ return *this;
+ }
+
+ ~ProcessModID () {}
+
+ void BumpStopID () {
+ m_stop_id++;
+ if (!IsLastResumeForUserExpression())
+ m_last_natural_stop_id++;
+ }
+
+ void BumpMemoryID () { m_memory_id++; }
+
+ void BumpResumeID () {
+ m_resume_id++;
+ if (m_running_user_expression > 0)
+ m_last_user_expression_resume = m_resume_id;
+ }
+
+ uint32_t GetStopID() const { return m_stop_id; }
+ uint32_t GetLastNaturalStopID() const { return m_last_natural_stop_id; }
+ uint32_t GetMemoryID () const { return m_memory_id; }
+ uint32_t GetResumeID () const { return m_resume_id; }
+ uint32_t GetLastUserExpressionResumeID () const { return m_last_user_expression_resume; }
+
+ bool MemoryIDEqual (const ProcessModID &compare) const
+ {
+ return m_memory_id == compare.m_memory_id;
+ }
+
+ bool StopIDEqual (const ProcessModID &compare) const
+ {
+ return m_stop_id == compare.m_stop_id;
+ }
+
+ void SetInvalid ()
+ {
+ m_stop_id = UINT32_MAX;
+ }
+
+ bool IsValid () const
+ {
+ return m_stop_id != UINT32_MAX;
+ }
+
+ bool
+ IsLastResumeForUserExpression () const
+ {
+ return m_resume_id == m_last_user_expression_resume;
+ }
+
+ void
+ SetRunningUserExpression (bool on)
+ {
+ // REMOVEME printf ("Setting running user expression %s at resume id %d - value: %d.\n", on ? "on" : "off", m_resume_id, m_running_user_expression);
+ if (on)
+ m_running_user_expression++;
+ else
+ m_running_user_expression--;
+ }
+
+private:
+ uint32_t m_stop_id;
+ uint32_t m_last_natural_stop_id;
+ uint32_t m_resume_id;
+ uint32_t m_memory_id;
+ uint32_t m_last_user_expression_resume;
+ uint32_t m_running_user_expression;
+};
+inline bool operator== (const ProcessModID &lhs, const ProcessModID &rhs)
+{
+ if (lhs.StopIDEqual (rhs)
+ && lhs.MemoryIDEqual (rhs))
+ return true;
+ else
+ return false;
+}
+
+inline bool operator!= (const ProcessModID &lhs, const ProcessModID &rhs)
+{
+ if (!lhs.StopIDEqual (rhs)
+ || !lhs.MemoryIDEqual (rhs))
+ return true;
+ else
+ return false;
+}
+
+class MemoryRegionInfo
+{
+public:
+ typedef Range<lldb::addr_t, lldb::addr_t> RangeType;
+
+ enum OptionalBool {
+ eDontKnow = -1,
+ eNo = 0,
+ eYes = 1
+ };
+
+ MemoryRegionInfo () :
+ m_range (),
+ m_read (eDontKnow),
+ m_write (eDontKnow),
+ m_execute (eDontKnow)
+ {
+ }
+
+ ~MemoryRegionInfo ()
+ {
+ }
+
+ RangeType &
+ GetRange()
+ {
+ return m_range;
+ }
+
+ void
+ Clear()
+ {
+ m_range.Clear();
+ m_read = m_write = m_execute = eDontKnow;
+ }
+
+ const RangeType &
+ GetRange() const
+ {
+ return m_range;
+ }
+
+ OptionalBool
+ GetReadable () const
+ {
+ return m_read;
+ }
+
+ OptionalBool
+ GetWritable () const
+ {
+ return m_write;
+ }
+
+ OptionalBool
+ GetExecutable () const
+ {
+ return m_execute;
+ }
+
+ void
+ SetReadable (OptionalBool val)
+ {
+ m_read = val;
+ }
+
+ void
+ SetWritable (OptionalBool val)
+ {
+ m_write = val;
+ }
+
+ void
+ SetExecutable (OptionalBool val)
+ {
+ m_execute = val;
+ }
+
+protected:
+ RangeType m_range;
+ OptionalBool m_read;
+ OptionalBool m_write;
+ OptionalBool m_execute;
+};
+
+//----------------------------------------------------------------------
+/// @class Process Process.h "lldb/Target/Process.h"
+/// @brief A plug-in interface definition class for debugging a process.
+//----------------------------------------------------------------------
+class Process :
+ public std::enable_shared_from_this<Process>,
+ public ProcessProperties,
+ public UserID,
+ public Broadcaster,
+ public ExecutionContextScope,
+ public PluginInterface
+{
+friend class ThreadList;
+friend class ClangFunction; // For WaitForStateChangeEventsPrivate
+friend class CommandObjectProcessLaunch;
+friend class ProcessEventData;
+friend class CommandObjectBreakpointCommand;
+friend class StopInfo;
+
+public:
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitStateChanged = (1 << 0),
+ eBroadcastBitInterrupt = (1 << 1),
+ eBroadcastBitSTDOUT = (1 << 2),
+ eBroadcastBitSTDERR = (1 << 3),
+ eBroadcastBitProfileData = (1 << 4)
+ };
+
+ enum
+ {
+ eBroadcastInternalStateControlStop = (1<<0),
+ eBroadcastInternalStateControlPause = (1<<1),
+ eBroadcastInternalStateControlResume = (1<<2)
+ };
+
+ typedef Range<lldb::addr_t, lldb::addr_t> LoadRange;
+ // We use a read/write lock to allow on or more clients to
+ // access the process state while the process is stopped (reader).
+ // We lock the write lock to control access to the process
+ // while it is running (readers, or clients that want the process
+ // stopped can block waiting for the process to stop, or just
+ // try to lock it to see if they can immediately access the stopped
+ // process. If the try read lock fails, then the process is running.
+ typedef ProcessRunLock::ProcessRunLocker StopLocker;
+
+ // These two functions fill out the Broadcaster interface:
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+
+ //------------------------------------------------------------------
+ /// A notification structure that can be used by clients to listen
+ /// for changes in a process's lifetime.
+ ///
+ /// @see RegisterNotificationCallbacks (const Notifications&)
+ /// @see UnregisterNotificationCallbacks (const Notifications&)
+ //------------------------------------------------------------------
+#ifndef SWIG
+ typedef struct
+ {
+ void *baton;
+ void (*initialize)(void *baton, Process *process);
+ void (*process_state_changed) (void *baton, Process *process, lldb::StateType state);
+ } Notifications;
+
+ class ProcessEventData :
+ public EventData
+ {
+ friend class Process;
+
+ public:
+ ProcessEventData ();
+ ProcessEventData (const lldb::ProcessSP &process, lldb::StateType state);
+
+ virtual ~ProcessEventData();
+
+ static const ConstString &
+ GetFlavorString ();
+
+ virtual const ConstString &
+ GetFlavor () const;
+
+ const lldb::ProcessSP &
+ GetProcessSP() const
+ {
+ return m_process_sp;
+ }
+ lldb::StateType
+ GetState() const
+ {
+ return m_state;
+ }
+ bool
+ GetRestarted () const
+ {
+ return m_restarted;
+ }
+
+ size_t
+ GetNumRestartedReasons ()
+ {
+ return m_restarted_reasons.size();
+ }
+
+ const char *
+ GetRestartedReasonAtIndex(size_t idx)
+ {
+ if (idx > m_restarted_reasons.size())
+ return NULL;
+ else
+ return m_restarted_reasons[idx].c_str();
+ }
+
+ bool
+ GetInterrupted () const
+ {
+ return m_interrupted;
+ }
+
+ virtual void
+ Dump (Stream *s) const;
+
+ virtual void
+ DoOnRemoval (Event *event_ptr);
+
+ static const Process::ProcessEventData *
+ GetEventDataFromEvent (const Event *event_ptr);
+
+ static lldb::ProcessSP
+ GetProcessFromEvent (const Event *event_ptr);
+
+ static lldb::StateType
+ GetStateFromEvent (const Event *event_ptr);
+
+ static bool
+ GetRestartedFromEvent (const Event *event_ptr);
+
+ static size_t
+ GetNumRestartedReasons(const Event *event_ptr);
+
+ static const char *
+ GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx);
+
+ static void
+ AddRestartedReason (Event *event_ptr, const char *reason);
+
+ static void
+ SetRestartedInEvent (Event *event_ptr, bool new_value);
+
+ static bool
+ GetInterruptedFromEvent (const Event *event_ptr);
+
+ static void
+ SetInterruptedInEvent (Event *event_ptr, bool new_value);
+
+ static bool
+ SetUpdateStateOnRemoval (Event *event_ptr);
+
+ private:
+
+ void
+ SetUpdateStateOnRemoval()
+ {
+ m_update_state++;
+ }
+ void
+ SetRestarted (bool new_value)
+ {
+ m_restarted = new_value;
+ }
+ void
+ SetInterrupted (bool new_value)
+ {
+ m_interrupted = new_value;
+ }
+ void
+ AddRestartedReason (const char *reason)
+ {
+ m_restarted_reasons.push_back(reason);
+ }
+
+ lldb::ProcessSP m_process_sp;
+ lldb::StateType m_state;
+ std::vector<std::string> m_restarted_reasons;
+ bool m_restarted; // For "eStateStopped" events, this is true if the target was automatically restarted.
+ int m_update_state;
+ bool m_interrupted;
+ DISALLOW_COPY_AND_ASSIGN (ProcessEventData);
+
+ };
+
+#endif
+
+ static void
+ SettingsInitialize ();
+
+ static void
+ SettingsTerminate ();
+
+ static const ProcessPropertiesSP &
+ GetGlobalProperties();
+
+ //------------------------------------------------------------------
+ /// Construct with a shared pointer to a target, and the Process listener.
+ //------------------------------------------------------------------
+ Process(Target &target, Listener &listener);
+
+ //------------------------------------------------------------------
+ /// Destructor.
+ ///
+ /// The destructor is virtual since this class is designed to be
+ /// inherited from by the plug-in instance.
+ //------------------------------------------------------------------
+ virtual
+ ~Process();
+
+ //------------------------------------------------------------------
+ /// Find a Process plug-in that can debug \a module using the
+ /// currently selected architecture.
+ ///
+ /// Scans all loaded plug-in interfaces that implement versions of
+ /// the Process plug-in interface and returns the first instance
+ /// that can debug the file.
+ ///
+ /// @param[in] module_sp
+ /// The module shared pointer that this process will debug.
+ ///
+ /// @param[in] plugin_name
+ /// If NULL, select the best plug-in for the binary. If non-NULL
+ /// then look for a plugin whose PluginInfo's name matches
+ /// this string.
+ ///
+ /// @see Process::CanDebug ()
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ FindPlugin (Target &target,
+ const char *plugin_name,
+ Listener &listener,
+ const FileSpec *crash_file_path);
+
+
+
+ //------------------------------------------------------------------
+ /// Static function that can be used with the \b host function
+ /// Host::StartMonitoringChildProcess ().
+ ///
+ /// This function can be used by lldb_private::Process subclasses
+ /// when they want to watch for a local process and have its exit
+ /// status automatically set when the host child process exits.
+ /// Subclasses should call Host::StartMonitoringChildProcess ()
+ /// with:
+ /// callback = Process::SetHostProcessExitStatus
+ /// callback_baton = NULL
+ /// pid = Process::GetID()
+ /// monitor_signals = false
+ //------------------------------------------------------------------
+ static bool
+ SetProcessExitStatus (void *callback_baton, // The callback baton which should be set to NULL
+ lldb::pid_t pid, // The process ID we want to monitor
+ bool exited,
+ int signo, // Zero for no signal
+ int status); // Exit value of process if signal is zero
+
+ lldb::ByteOrder
+ GetByteOrder () const;
+
+ uint32_t
+ GetAddressByteSize () const;
+
+ uint32_t
+ GetUniqueID() const
+ {
+ return m_process_unique_id;
+ }
+ //------------------------------------------------------------------
+ /// Check if a plug-in instance can debug the file in \a module.
+ ///
+ /// Each plug-in is given a chance to say whether it can debug
+ /// the file in \a module. If the Process plug-in instance can
+ /// debug a file on the current system, it should return \b true.
+ ///
+ /// @return
+ /// Returns \b true if this Process plug-in instance can
+ /// debug the executable, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (Target &target,
+ bool plugin_specified_by_name) = 0;
+
+
+ //------------------------------------------------------------------
+ /// This object is about to be destroyed, do any necessary cleanup.
+ ///
+ /// Subclasses that override this method should always call this
+ /// superclass method.
+ //------------------------------------------------------------------
+ virtual void
+ Finalize();
+
+
+ //------------------------------------------------------------------
+ /// Return whether this object is valid (i.e. has not been finalized.)
+ ///
+ /// @return
+ /// Returns \b true if this Process has not been finalized
+ /// and \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsValid() const
+ {
+ return !m_finalize_called;
+ }
+
+ //------------------------------------------------------------------
+ /// Return a multi-word command object that can be used to expose
+ /// plug-in specific commands.
+ ///
+ /// This object will be used to resolve plug-in commands and can be
+ /// triggered by a call to:
+ ///
+ /// (lldb) process commmand <args>
+ ///
+ /// @return
+ /// A CommandObject which can be one of the concrete subclasses
+ /// of CommandObject like CommandObjectRaw, CommandObjectParsed,
+ /// or CommandObjectMultiword.
+ //------------------------------------------------------------------
+ virtual CommandObject *
+ GetPluginCommandObject()
+ {
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ /// Launch a new process.
+ ///
+ /// Launch a new process by spawning a new process using the
+ /// target object's executable module's file as the file to launch.
+ /// Arguments are given in \a argv, and the environment variables
+ /// are in \a envp. Standard input and output files can be
+ /// optionally re-directed to \a stdin_path, \a stdout_path, and
+ /// \a stderr_path.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses. It will first call Process::WillLaunch (Module *)
+ /// and if that returns \b true, Process::DoLaunch (Module*,
+ /// char const *[],char const *[],const char *,const char *,
+ /// const char *) will be called to actually do the launching. If
+ /// DoLaunch returns \b true, then Process::DidLaunch() will be
+ /// called.
+ ///
+ /// @param[in] argv
+ /// The argument array.
+ ///
+ /// @param[in] envp
+ /// The environment array.
+ ///
+ /// @param[in] launch_flags
+ /// Flags to modify the launch (@see lldb::LaunchFlags)
+ ///
+ /// @param[in] stdin_path
+ /// The path to use when re-directing the STDIN of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stdout_path
+ /// The path to use when re-directing the STDOUT of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stderr_path
+ /// The path to use when re-directing the STDERR of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] working_directory
+ /// The working directory to have the child process run in
+ ///
+ /// @return
+ /// An error object. Call GetID() to get the process ID if
+ /// the error object is success.
+ //------------------------------------------------------------------
+ virtual Error
+ Launch (const ProcessLaunchInfo &launch_info);
+
+ virtual Error
+ LoadCore ();
+
+ virtual Error
+ DoLoadCore ()
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support loading core files.", GetPluginName().GetCString());
+ return error;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the dynamic loader plug-in for this process.
+ ///
+ /// The default action is to let the DynamicLoader plug-ins check
+ /// the main executable and the DynamicLoader will select itself
+ /// automatically. Subclasses can override this if inspecting the
+ /// executable is not desired, or if Process subclasses can only
+ /// use a specific DynamicLoader plug-in.
+ //------------------------------------------------------------------
+ virtual DynamicLoader *
+ GetDynamicLoader ();
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using the process attach info.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses. It will first call WillAttach (lldb::pid_t)
+ /// or WillAttach (const char *), and if that returns \b
+ /// true, DoAttach (lldb::pid_t) or DoAttach (const char *) will
+ /// be called to actually do the attach. If DoAttach returns \b
+ /// true, then Process::DidAttach() will be called.
+ ///
+ /// @param[in] pid
+ /// The process ID that we should attempt to attach to.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ Attach (ProcessAttachInfo &attach_info);
+
+ //------------------------------------------------------------------
+ /// Attach to a remote system via a URL
+ ///
+ /// @param[in] strm
+ /// A stream where output intended for the user
+ /// (if the driver has a way to display that) generated during
+ /// the connection. This may be NULL if no output is needed.A
+ ///
+ /// @param[in] remote_url
+ /// The URL format that we are connecting to.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ ConnectRemote (Stream *strm, const char *remote_url);
+
+ bool
+ GetShouldDetach () const
+ {
+ return m_should_detach;
+ }
+
+ void
+ SetShouldDetach (bool b)
+ {
+ m_should_detach = b;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the image information address for the current process.
+ ///
+ /// Some runtimes have system functions that can help dynamic
+ /// loaders locate the dynamic loader information needed to observe
+ /// shared libraries being loaded or unloaded. This function is
+ /// in the Process interface (as opposed to the DynamicLoader
+ /// interface) to ensure that remote debugging can take advantage of
+ /// this functionality.
+ ///
+ /// @return
+ /// The address of the dynamic loader information, or
+ /// LLDB_INVALID_ADDRESS if this is not supported by this
+ /// interface.
+ //------------------------------------------------------------------
+ virtual lldb::addr_t
+ GetImageInfoAddress ();
+
+ //------------------------------------------------------------------
+ /// Load a shared library into this process.
+ ///
+ /// Try and load a shared library into the current process. This
+ /// call might fail in the dynamic loader plug-in says it isn't safe
+ /// to try and load shared libraries at the moment.
+ ///
+ /// @param[in] image_spec
+ /// The image file spec that points to the shared library that
+ /// you want to load.
+ ///
+ /// @param[out] error
+ /// An error object that gets filled in with any errors that
+ /// might occur when trying to load the shared library.
+ ///
+ /// @return
+ /// A token that represents the shared library that can be
+ /// later used to unload the shared library. A value of
+ /// LLDB_INVALID_IMAGE_TOKEN will be returned if the shared
+ /// library can't be opened.
+ //------------------------------------------------------------------
+ virtual uint32_t
+ LoadImage (const FileSpec &image_spec, Error &error);
+
+ virtual Error
+ UnloadImage (uint32_t image_token);
+
+ //------------------------------------------------------------------
+ /// Register for process and thread notifications.
+ ///
+ /// Clients can register nofication callbacks by filling out a
+ /// Process::Notifications structure and calling this function.
+ ///
+ /// @param[in] callbacks
+ /// A structure that contains the notification baton and
+ /// callback functions.
+ ///
+ /// @see Process::Notifications
+ //------------------------------------------------------------------
+#ifndef SWIG
+ void
+ RegisterNotificationCallbacks (const Process::Notifications& callbacks);
+#endif
+ //------------------------------------------------------------------
+ /// Unregister for process and thread notifications.
+ ///
+ /// Clients can unregister nofication callbacks by passing a copy of
+ /// the original baton and callbacks in \a callbacks.
+ ///
+ /// @param[in] callbacks
+ /// A structure that contains the notification baton and
+ /// callback functions.
+ ///
+ /// @return
+ /// Returns \b true if the notification callbacks were
+ /// successfully removed from the process, \b false otherwise.
+ ///
+ /// @see Process::Notifications
+ //------------------------------------------------------------------
+#ifndef SWIG
+ bool
+ UnregisterNotificationCallbacks (const Process::Notifications& callbacks);
+#endif
+ //==================================================================
+ // Built in Process Control functions
+ //==================================================================
+ //------------------------------------------------------------------
+ /// Resumes all of a process's threads as configured using the
+ /// Thread run control functions.
+ ///
+ /// Threads for a process should be updated with one of the run
+ /// control actions (resume, step, or suspend) that they should take
+ /// when the process is resumed. If no run control action is given
+ /// to a thread it will be resumed by default.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses. This function will take care of disabling any
+ /// breakpoints that threads may be stopped at, single stepping, and
+ /// re-enabling breakpoints, and enabling the basic flow control
+ /// that the plug-in instances need not worry about.
+ ///
+ /// N.B. This function also sets the Write side of the Run Lock,
+ /// which is unset when the corresponding stop event is pulled off
+ /// the Public Event Queue. If you need to resume the process without
+ /// setting the Run Lock, use PrivateResume (though you should only do
+ /// that from inside the Process class.
+ ///
+ /// @return
+ /// Returns an error object.
+ ///
+ /// @see Thread:Resume()
+ /// @see Thread:Step()
+ /// @see Thread:Suspend()
+ //------------------------------------------------------------------
+ Error
+ Resume();
+
+ //------------------------------------------------------------------
+ /// Halts a running process.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ /// If the process is successfully halted, a eStateStopped
+ /// process event with GetInterrupted will be broadcast. If false, we will
+ /// halt the process with no events generated by the halt.
+ ///
+ /// @param[in] clear_thread_plans
+ /// If true, when the process stops, clear all thread plans.
+ ///
+ /// @return
+ /// Returns an error object. If the error is empty, the process is halted.
+ /// otherwise the halt has failed.
+ //------------------------------------------------------------------
+ Error
+ Halt (bool clear_thread_plans = false);
+
+ //------------------------------------------------------------------
+ /// Detaches from a running or stopped process.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ ///
+ /// @param[in] keep_stopped
+ /// If true, don't resume the process on detach.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ Error
+ Detach (bool keep_stopped);
+
+ //------------------------------------------------------------------
+ /// Kills the process and shuts down all threads that were spawned
+ /// to track and monitor the process.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ Error
+ Destroy();
+
+ //------------------------------------------------------------------
+ /// Sends a process a UNIX signal \a signal.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ Error
+ Signal (int signal);
+
+ virtual UnixSignals &
+ GetUnixSignals ()
+ {
+ return m_unix_signals;
+ }
+
+ //==================================================================
+ // Plug-in Process Control Overrides
+ //==================================================================
+
+ //------------------------------------------------------------------
+ /// Called before attaching to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before attaching a
+ /// process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillAttachToProcessWithID (lldb::pid_t pid)
+ {
+ return Error();
+ }
+
+ //------------------------------------------------------------------
+ /// Called before attaching to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before attaching a
+ /// process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+ {
+ return Error();
+ }
+
+ //------------------------------------------------------------------
+ /// Attach to a remote system via a URL
+ ///
+ /// @param[in] strm
+ /// A stream where output intended for the user
+ /// (if the driver has a way to display that) generated during
+ /// the connection. This may be NULL if no output is needed.A
+ ///
+ /// @param[in] remote_url
+ /// The URL format that we are connecting to.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ DoConnectRemote (Stream *strm, const char *remote_url)
+ {
+ Error error;
+ error.SetErrorString ("remote connections are not supported");
+ return error;
+ }
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using a process ID.
+ ///
+ /// @param[in] pid
+ /// The process ID that we should attempt to attach to.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ DoAttachToProcessWithID (lldb::pid_t pid)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString());
+ return error;
+ }
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using a process ID.
+ ///
+ /// @param[in] pid
+ /// The process ID that we should attempt to attach to.
+ ///
+ /// @param[in] attach_info
+ /// Information on how to do the attach. For example, GetUserID()
+ /// will return the uid to attach as.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ /// hanming : need flag
+ //------------------------------------------------------------------
+ virtual Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support attaching to a process by pid", GetPluginName().GetCString());
+ return error;
+ }
+
+ //------------------------------------------------------------------
+ /// Attach to an existing process using a partial process name.
+ ///
+ /// @param[in] process_name
+ /// The name of the process to attach to.
+ ///
+ /// @param[in] wait_for_launch
+ /// If \b true, wait for the process to be launched and attach
+ /// as soon as possible after it does launch. If \b false, then
+ /// search for a matching process the currently exists.
+ ///
+ /// @param[in] attach_info
+ /// Information on how to do the attach. For example, GetUserID()
+ /// will return the uid to attach as.
+ ///
+ /// @return
+ /// Returns \a pid if attaching was successful, or
+ /// LLDB_INVALID_PROCESS_ID if attaching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info)
+ {
+ Error error;
+ error.SetErrorString("attach by name is not supported");
+ return error;
+ }
+
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow Process plug-ins to execute some code after attaching to
+ /// a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach () {}
+
+
+ //------------------------------------------------------------------
+ /// Called after a process re-execs itself.
+ ///
+ /// Allow Process plug-ins to execute some code after a process has
+ /// exec'ed itself. Subclasses typically should override DoDidExec()
+ /// as the lldb_private::Process class needs to remove its dynamic
+ /// loader, runtime, ABI and other plug-ins, as well as unload all
+ /// shared libraries.
+ //------------------------------------------------------------------
+ virtual void
+ DidExec ();
+
+ //------------------------------------------------------------------
+ /// Subclasses of Process should implement this function if they
+ /// need to do anything after a process exec's itself.
+ //------------------------------------------------------------------
+ virtual void
+ DoDidExec ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Called before launching to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before launching a
+ /// process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillLaunch (Module* module)
+ {
+ return Error();
+ }
+
+ //------------------------------------------------------------------
+ /// Launch a new process.
+ ///
+ /// Launch a new process by spawning a new process using \a module's
+ /// file as the file to launch. Arguments are given in \a argv,
+ /// and the environment variables are in \a envp. Standard input
+ /// and output files can be optionally re-directed to \a stdin_path,
+ /// \a stdout_path, and \a stderr_path.
+ ///
+ /// @param[in] module
+ /// The module from which to extract the file specification and
+ /// launch.
+ ///
+ /// @param[in] argv
+ /// The argument array.
+ ///
+ /// @param[in] envp
+ /// The environment array.
+ ///
+ /// @param[in] launch_flags
+ /// Flags to modify the launch (@see lldb::LaunchFlags)
+ ///
+ /// @param[in] stdin_path
+ /// The path to use when re-directing the STDIN of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stdout_path
+ /// The path to use when re-directing the STDOUT of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] stderr_path
+ /// The path to use when re-directing the STDERR of the new
+ /// process. If all stdXX_path arguments are NULL, a pseudo
+ /// terminal will be used.
+ ///
+ /// @param[in] working_directory
+ /// The working directory to have the child process run in
+ ///
+ /// @return
+ /// A new valid process ID, or LLDB_INVALID_PROCESS_ID if
+ /// launching fails.
+ //------------------------------------------------------------------
+ virtual Error
+ DoLaunch (Module *exe_module,
+ const ProcessLaunchInfo &launch_info)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support launching processes", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Called after launching a process.
+ ///
+ /// Allow Process plug-ins to execute some code after launching
+ /// a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidLaunch () {}
+
+
+
+ //------------------------------------------------------------------
+ /// Called before resuming to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before resuming a
+ /// process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillResume () { return Error(); }
+
+ //------------------------------------------------------------------
+ /// Resumes all of a process's threads as configured using the
+ /// Thread run control functions.
+ ///
+ /// Threads for a process should be updated with one of the run
+ /// control actions (resume, step, or suspend) that they should take
+ /// when the process is resumed. If no run control action is given
+ /// to a thread it will be resumed by default.
+ ///
+ /// @return
+ /// Returns \b true if the process successfully resumes using
+ /// the thread run control actions, \b false otherwise.
+ ///
+ /// @see Thread:Resume()
+ /// @see Thread:Step()
+ /// @see Thread:Suspend()
+ //------------------------------------------------------------------
+ virtual Error
+ DoResume ()
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support resuming processes", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Called after resuming a process.
+ ///
+ /// Allow Process plug-ins to execute some code after resuming
+ /// a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidResume () {}
+
+
+ //------------------------------------------------------------------
+ /// Called before halting to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before halting a
+ /// process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillHalt () { return Error(); }
+
+ //------------------------------------------------------------------
+ /// Halts a running process.
+ ///
+ /// DoHalt must produce one and only one stop StateChanged event if it actually
+ /// stops the process. If the stop happens through some natural event (for
+ /// instance a SIGSTOP), then forwarding that event will do. Otherwise, you must
+ /// generate the event manually. Note also, the private event thread is stopped when
+ /// DoHalt is run to prevent the events generated while halting to trigger
+ /// other state changes before the halt is complete.
+ ///
+ /// @param[out] caused_stop
+ /// If true, then this Halt caused the stop, otherwise, the
+ /// process was already stopped.
+ ///
+ /// @return
+ /// Returns \b true if the process successfully halts, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ DoHalt (bool &caused_stop)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support halting processes", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Called after halting a process.
+ ///
+ /// Allow Process plug-ins to execute some code after halting
+ /// a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidHalt () {}
+
+ //------------------------------------------------------------------
+ /// Called before detaching from a process.
+ ///
+ /// Allow Process plug-ins to execute some code before detaching
+ /// from a process.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ WillDetach ()
+ {
+ return Error();
+ }
+
+ //------------------------------------------------------------------
+ /// Detaches from a running or stopped process.
+ ///
+ /// @return
+ /// Returns \b true if the process successfully detaches, \b
+ /// false otherwise.
+ //------------------------------------------------------------------
+ virtual Error
+ DoDetach (bool keep_stopped)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support detaching from processes", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Called after detaching from a process.
+ ///
+ /// Allow Process plug-ins to execute some code after detaching
+ /// from a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidDetach () {}
+
+ virtual bool
+ DetachRequiresHalt() { return false; }
+
+ //------------------------------------------------------------------
+ /// Called before sending a signal to a process.
+ ///
+ /// Allow Process plug-ins to execute some code before sending a
+ /// signal to a process.
+ ///
+ /// @return
+ /// Returns no error if it is safe to proceed with a call to
+ /// Process::DoSignal(int), otherwise an error describing what
+ /// prevents the signal from being sent.
+ //------------------------------------------------------------------
+ virtual Error
+ WillSignal () { return Error(); }
+
+ //------------------------------------------------------------------
+ /// Sends a process a UNIX signal \a signal.
+ ///
+ /// @return
+ /// Returns an error object.
+ //------------------------------------------------------------------
+ virtual Error
+ DoSignal (int signal)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support senging signals to processes", GetPluginName().GetCString());
+ return error;
+ }
+
+ virtual Error
+ WillDestroy () { return Error(); }
+
+ virtual Error
+ DoDestroy () = 0;
+
+ virtual void
+ DidDestroy () { }
+
+ virtual bool
+ DestroyRequiresHalt() { return true; }
+
+
+ //------------------------------------------------------------------
+ /// Called after sending a signal to a process.
+ ///
+ /// Allow Process plug-ins to execute some code after sending a
+ /// signal to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidSignal () {}
+
+ //------------------------------------------------------------------
+ /// Currently called as part of ShouldStop.
+ /// FIXME: Should really happen when the target stops before the
+ /// event is taken from the queue...
+ ///
+ /// This callback is called as the event
+ /// is about to be queued up to allow Process plug-ins to execute
+ /// some code prior to clients being notified that a process was
+ /// stopped. Common operations include updating the thread list,
+ /// invalidating any thread state (registers, stack, etc) prior to
+ /// letting the notification go out.
+ ///
+ //------------------------------------------------------------------
+ virtual void
+ RefreshStateAfterStop () = 0;
+
+ //------------------------------------------------------------------
+ /// Get the target object pointer for this module.
+ ///
+ /// @return
+ /// A Target object pointer to the target that owns this
+ /// module.
+ //------------------------------------------------------------------
+ Target &
+ GetTarget ()
+ {
+ return m_target;
+ }
+
+ //------------------------------------------------------------------
+ /// Get the const target object pointer for this module.
+ ///
+ /// @return
+ /// A const Target object pointer to the target that owns this
+ /// module.
+ //------------------------------------------------------------------
+ const Target &
+ GetTarget () const
+ {
+ return m_target;
+ }
+
+ //------------------------------------------------------------------
+ /// Flush all data in the process.
+ ///
+ /// Flush the memory caches, all threads, and any other cached data
+ /// in the process.
+ ///
+ /// This function can be called after a world changing event like
+ /// adding a new symbol file, or after the process makes a large
+ /// context switch (from boot ROM to booted into an OS).
+ //------------------------------------------------------------------
+ void
+ Flush ();
+
+ //------------------------------------------------------------------
+ /// Get accessor for the current process state.
+ ///
+ /// @return
+ /// The current state of the process.
+ ///
+ /// @see lldb::StateType
+ //------------------------------------------------------------------
+ lldb::StateType
+ GetState ();
+
+ ExecutionResults
+ RunThreadPlan (ExecutionContext &exe_ctx,
+ lldb::ThreadPlanSP &thread_plan_sp,
+ bool stop_others,
+ bool run_others,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ uint32_t timeout_usec,
+ Stream &errors);
+
+ static const char *
+ ExecutionResultAsCString (ExecutionResults result);
+
+ void
+ GetStatus (Stream &ostrm);
+
+ size_t
+ GetThreadStatus (Stream &ostrm,
+ bool only_threads_with_stop_reason,
+ uint32_t start_frame,
+ uint32_t num_frames,
+ uint32_t num_frames_with_source);
+
+ void
+ SendAsyncInterrupt ();
+
+protected:
+
+ void
+ SetState (lldb::EventSP &event_sp);
+
+ lldb::StateType
+ GetPrivateState ();
+
+ //------------------------------------------------------------------
+ /// The "private" side of resuming a process. This doesn't alter the
+ /// state of m_run_lock, but just causes the process to resume.
+ ///
+ /// @return
+ /// An Error object describing the success or failure of the resume.
+ //------------------------------------------------------------------
+ Error
+ PrivateResume ();
+
+ //------------------------------------------------------------------
+ // Called internally
+ //------------------------------------------------------------------
+ void
+ CompleteAttach ();
+
+public:
+ //------------------------------------------------------------------
+ /// Get the exit status for a process.
+ ///
+ /// @return
+ /// The process's return code, or -1 if the current process
+ /// state is not eStateExited.
+ //------------------------------------------------------------------
+ int
+ GetExitStatus ();
+
+ //------------------------------------------------------------------
+ /// Get a textual description of what the process exited.
+ ///
+ /// @return
+ /// The textual description of why the process exited, or NULL
+ /// if there is no description available.
+ //------------------------------------------------------------------
+ const char *
+ GetExitDescription ();
+
+
+ virtual void
+ DidExit ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Get the Modification ID of the process.
+ ///
+ /// @return
+ /// The modification ID of the process.
+ //------------------------------------------------------------------
+ ProcessModID
+ GetModID () const
+ {
+ return m_mod_id;
+ }
+
+ const ProcessModID &
+ GetModIDRef () const
+ {
+ return m_mod_id;
+ }
+
+ uint32_t
+ GetStopID () const
+ {
+ return m_mod_id.GetStopID();
+ }
+
+ uint32_t
+ GetResumeID () const
+ {
+ return m_mod_id.GetResumeID();
+ }
+
+ uint32_t
+ GetLastUserExpressionResumeID () const
+ {
+ return m_mod_id.GetLastUserExpressionResumeID();
+ }
+
+ uint32_t
+ GetLastNaturalStopID()
+ {
+ return m_mod_id.GetLastNaturalStopID();
+ }
+
+ //------------------------------------------------------------------
+ /// Set accessor for the process exit status (return code).
+ ///
+ /// Sometimes a child exits and the exit can be detected by global
+ /// functions (signal handler for SIGCHLD for example). This
+ /// accessor allows the exit status to be set from an external
+ /// source.
+ ///
+ /// Setting this will cause a eStateExited event to be posted to
+ /// the process event queue.
+ ///
+ /// @param[in] exit_status
+ /// The value for the process's return code.
+ ///
+ /// @see lldb::StateType
+ //------------------------------------------------------------------
+ virtual bool
+ SetExitStatus (int exit_status, const char *cstr);
+
+ //------------------------------------------------------------------
+ /// Check if a process is still alive.
+ ///
+ /// @return
+ /// Returns \b true if the process is still valid, \b false
+ /// otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive () = 0;
+
+ //------------------------------------------------------------------
+ /// Before lldb detaches from a process, it warns the user that they are about to lose their debug session.
+ /// In some cases, this warning doesn't need to be emitted -- for instance, with core file debugging where
+ /// the user can reconstruct the "state" by simply re-running the debugger on the core file.
+ ///
+ /// @return
+ // true if the user should be warned about detaching from this process.
+ //------------------------------------------------------------------
+ virtual bool
+ WarnBeforeDetach () const
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Actually do the reading of memory from a process.
+ ///
+ /// Subclasses must override this function and can return fewer
+ /// bytes than requested when memory requests are too large. This
+ /// class will break up the memory requests and keep advancing the
+ /// arguments along as needed.
+ ///
+ /// @param[in] vm_addr
+ /// A virtual load address that indicates where to start reading
+ /// memory from.
+ ///
+ /// @param[in] size
+ /// The number of bytes to read.
+ ///
+ /// @param[out] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// will receive the memory bytes.
+ ///
+ /// @return
+ /// The number of bytes that were actually read into \a buf.
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ Error &error) = 0;
+
+ //------------------------------------------------------------------
+ /// Read of memory from a process.
+ ///
+ /// This function will read memory from the current process's
+ /// address space and remove any traps that may have been inserted
+ /// into the memory.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses, the subclasses should implement
+ /// Process::DoReadMemory (lldb::addr_t, size_t, void *).
+ ///
+ /// @param[in] vm_addr
+ /// A virtual load address that indicates where to start reading
+ /// memory from.
+ ///
+ /// @param[out] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// will receive the memory bytes.
+ ///
+ /// @param[in] size
+ /// The number of bytes to read.
+ ///
+ /// @return
+ /// The number of bytes that were actually read into \a buf. If
+ /// the returned number is greater than zero, yet less than \a
+ /// size, then this function will get called again with \a
+ /// vm_addr, \a buf, and \a size updated appropriately. Zero is
+ /// returned to indicate an error.
+ //------------------------------------------------------------------
+ virtual size_t
+ ReadMemory (lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ Error &error);
+
+ //------------------------------------------------------------------
+ /// Read a NULL terminated string from memory
+ ///
+ /// This function will read a cache page at a time until a NULL
+ /// string terminator is found. It will stop reading if an aligned
+ /// sequence of NULL termination \a type_width bytes is not found
+ /// before reading \a cstr_max_len bytes. The results are always
+ /// guaranteed to be NULL terminated, and that no more than
+ /// (max_bytes - type_width) bytes will be read.
+ ///
+ /// @param[in] vm_addr
+ /// The virtual load address to start the memory read.
+ ///
+ /// @param[in] str
+ /// A character buffer containing at least max_bytes.
+ ///
+ /// @param[in] max_bytes
+ /// The maximum number of bytes to read.
+ ///
+ /// @param[in] error
+ /// The error status of the read operation.
+ ///
+ /// @param[in] type_width
+ /// The size of the null terminator (1 to 4 bytes per
+ /// character). Defaults to 1.
+ ///
+ /// @return
+ /// The error status or the number of bytes prior to the null terminator.
+ //------------------------------------------------------------------
+ size_t
+ ReadStringFromMemory (lldb::addr_t vm_addr,
+ char *str,
+ size_t max_bytes,
+ Error &error,
+ size_t type_width = 1);
+
+ //------------------------------------------------------------------
+ /// Read a NULL terminated C string from memory
+ ///
+ /// This function will read a cache page at a time until the NULL
+ /// C string terminator is found. It will stop reading if the NULL
+ /// termination byte isn't found before reading \a cstr_max_len
+ /// bytes, and the results are always guaranteed to be NULL
+ /// terminated (at most cstr_max_len - 1 bytes will be read).
+ //------------------------------------------------------------------
+ size_t
+ ReadCStringFromMemory (lldb::addr_t vm_addr,
+ char *cstr,
+ size_t cstr_max_len,
+ Error &error);
+
+ size_t
+ ReadCStringFromMemory (lldb::addr_t vm_addr,
+ std::string &out_str,
+ Error &error);
+
+ size_t
+ ReadMemoryFromInferior (lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ Error &error);
+
+ //------------------------------------------------------------------
+ /// Reads an unsigned integer of the specified byte size from
+ /// process memory.
+ ///
+ /// @param[in] load_addr
+ /// A load address of the integer to read.
+ ///
+ /// @param[in] byte_size
+ /// The size in byte of the integer to read.
+ ///
+ /// @param[in] fail_value
+ /// The value to return if we fail to read an integer.
+ ///
+ /// @param[out] error
+ /// An error that indicates the success or failure of this
+ /// operation. If error indicates success (error.Success()),
+ /// then the value returned can be trusted, otherwise zero
+ /// will be returned.
+ ///
+ /// @return
+ /// The unsigned integer that was read from the process memory
+ /// space. If the integer was smaller than a uint64_t, any
+ /// unused upper bytes will be zero filled. If the process
+ /// byte order differs from the host byte order, the integer
+ /// value will be appropriately byte swapped into host byte
+ /// order.
+ //------------------------------------------------------------------
+ uint64_t
+ ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
+ size_t byte_size,
+ uint64_t fail_value,
+ Error &error);
+
+ lldb::addr_t
+ ReadPointerFromMemory (lldb::addr_t vm_addr,
+ Error &error);
+
+ bool
+ WritePointerToMemory (lldb::addr_t vm_addr,
+ lldb::addr_t ptr_value,
+ Error &error);
+
+ //------------------------------------------------------------------
+ /// Actually do the writing of memory to a process.
+ ///
+ /// @param[in] vm_addr
+ /// A virtual load address that indicates where to start writing
+ /// memory to.
+ ///
+ /// @param[in] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// contains the data to write.
+ ///
+ /// @param[in] size
+ /// The number of bytes to write.
+ ///
+ /// @param[out] error
+ /// An error value in case the memory write fails.
+ ///
+ /// @return
+ /// The number of bytes that were actually written.
+ //------------------------------------------------------------------
+ virtual size_t
+ DoWriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error)
+ {
+ error.SetErrorStringWithFormat("error: %s does not support writing to processes", GetPluginName().GetCString());
+ return 0;
+ }
+
+
+ //------------------------------------------------------------------
+ /// Write all or part of a scalar value to memory.
+ ///
+ /// The value contained in \a scalar will be swapped to match the
+ /// byte order of the process that is being debugged. If \a size is
+ /// less than the size of scalar, the least significate \a size bytes
+ /// from scalar will be written. If \a size is larger than the byte
+ /// size of scalar, then the extra space will be padded with zeros
+ /// and the scalar value will be placed in the least significant
+ /// bytes in memory.
+ ///
+ /// @param[in] vm_addr
+ /// A virtual load address that indicates where to start writing
+ /// memory to.
+ ///
+ /// @param[in] scalar
+ /// The scalar to write to the debugged process.
+ ///
+ /// @param[in] size
+ /// This value can be smaller or larger than the scalar value
+ /// itself. If \a size is smaller than the size of \a scalar,
+ /// the least significant bytes in \a scalar will be used. If
+ /// \a size is larger than the byte size of \a scalar, then
+ /// the extra space will be padded with zeros. If \a size is
+ /// set to UINT32_MAX, then the size of \a scalar will be used.
+ ///
+ /// @param[out] error
+ /// An error value in case the memory write fails.
+ ///
+ /// @return
+ /// The number of bytes that were actually written.
+ //------------------------------------------------------------------
+ size_t
+ WriteScalarToMemory (lldb::addr_t vm_addr,
+ const Scalar &scalar,
+ size_t size,
+ Error &error);
+
+ size_t
+ ReadScalarIntegerFromMemory (lldb::addr_t addr,
+ uint32_t byte_size,
+ bool is_signed,
+ Scalar &scalar,
+ Error &error);
+
+ //------------------------------------------------------------------
+ /// Write memory to a process.
+ ///
+ /// This function will write memory to the current process's
+ /// address space and maintain any traps that might be present due
+ /// to software breakpoints.
+ ///
+ /// This function is not meant to be overridden by Process
+ /// subclasses, the subclasses should implement
+ /// Process::DoWriteMemory (lldb::addr_t, size_t, void *).
+ ///
+ /// @param[in] vm_addr
+ /// A virtual load address that indicates where to start writing
+ /// memory to.
+ ///
+ /// @param[in] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// contains the data to write.
+ ///
+ /// @param[in] size
+ /// The number of bytes to write.
+ ///
+ /// @return
+ /// The number of bytes that were actually written.
+ //------------------------------------------------------------------
+ size_t
+ WriteMemory (lldb::addr_t vm_addr, const void *buf, size_t size, Error &error);
+
+
+ //------------------------------------------------------------------
+ /// Actually allocate memory in the process.
+ ///
+ /// This function will allocate memory in the process's address
+ /// space. This can't rely on the generic function calling mechanism,
+ /// since that requires this function.
+ ///
+ /// @param[in] size
+ /// The size of the allocation requested.
+ ///
+ /// @return
+ /// The address of the allocated buffer in the process, or
+ /// LLDB_INVALID_ADDRESS if the allocation failed.
+ //------------------------------------------------------------------
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+ {
+ error.SetErrorStringWithFormat("error: %s does not support allocating in the debug process", GetPluginName().GetCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+
+ //------------------------------------------------------------------
+ /// The public interface to allocating memory in the process.
+ ///
+ /// This function will allocate memory in the process's address
+ /// space. This can't rely on the generic function calling mechanism,
+ /// since that requires this function.
+ ///
+ /// @param[in] size
+ /// The size of the allocation requested.
+ ///
+ /// @param[in] permissions
+ /// Or together any of the lldb::Permissions bits. The permissions on
+ /// a given memory allocation can't be changed after allocation. Note
+ /// that a block that isn't set writable can still be written on from lldb,
+ /// just not by the process itself.
+ ///
+ /// @param[in/out] error
+ /// An error object to fill in if things go wrong.
+ /// @return
+ /// The address of the allocated buffer in the process, or
+ /// LLDB_INVALID_ADDRESS if the allocation failed.
+ //------------------------------------------------------------------
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions, Error &error);
+
+
+ //------------------------------------------------------------------
+ /// Resolve dynamically loaded indirect functions.
+ ///
+ /// @param[in] address
+ /// The load address of the indirect function to resolve.
+ ///
+ /// @param[out] error
+ /// An error value in case the resolve fails.
+ ///
+ /// @return
+ /// The address of the resolved function.
+ /// LLDB_INVALID_ADDRESS if the resolution failed.
+ //------------------------------------------------------------------
+
+ virtual lldb::addr_t
+ ResolveIndirectFunction(const Address *address, Error &error)
+ {
+ error.SetErrorStringWithFormat("error: %s does not support indirect functions in the debug process", GetPluginName().GetCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ virtual Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info)
+ {
+ Error error;
+ error.SetErrorString ("Process::GetMemoryRegionInfo() not supported");
+ return error;
+ }
+
+ virtual Error
+ GetWatchpointSupportInfo (uint32_t &num)
+ {
+ Error error;
+ num = 0;
+ error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported");
+ return error;
+ }
+
+ virtual Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after)
+ {
+ Error error;
+ num = 0;
+ after = true;
+ error.SetErrorString ("Process::GetWatchpointSupportInfo() not supported");
+ return error;
+ }
+
+ lldb::ModuleSP
+ ReadModuleFromMemory (const FileSpec& file_spec,
+ lldb::addr_t header_addr);
+
+ //------------------------------------------------------------------
+ /// Attempt to get the attributes for a region of memory in the process.
+ ///
+ /// It may be possible for the remote debug server to inspect attributes
+ /// for a region of memory in the process, such as whether there is a
+ /// valid page of memory at a given address or whether that page is
+ /// readable/writable/executable by the process.
+ ///
+ /// @param[in] load_addr
+ /// The address of interest in the process.
+ ///
+ /// @param[out] permissions
+ /// If this call returns successfully, this bitmask will have
+ /// its Permissions bits set to indicate whether the region is
+ /// readable/writable/executable. If this call fails, the
+ /// bitmask values are undefined.
+ ///
+ /// @return
+ /// Returns true if it was able to determine the attributes of the
+ /// memory region. False if not.
+ //------------------------------------------------------------------
+
+ virtual bool
+ GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
+ {
+ MemoryRegionInfo range_info;
+ permissions = 0;
+ Error error (GetMemoryRegionInfo (load_addr, range_info));
+ if (!error.Success())
+ return false;
+ if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetWritable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
+ {
+ return false;
+ }
+
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsReadable;
+
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsWritable;
+
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsExecutable;
+
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Determines whether executing JIT-compiled code in this process
+ /// is possible.
+ ///
+ /// @return
+ /// True if execution of JIT code is possible; false otherwise.
+ //------------------------------------------------------------------
+ bool CanJIT ();
+
+ //------------------------------------------------------------------
+ /// Sets whether executing JIT-compiled code in this process
+ /// is possible.
+ ///
+ /// @param[in] can_jit
+ /// True if execution of JIT code is possible; false otherwise.
+ //------------------------------------------------------------------
+ void SetCanJIT (bool can_jit);
+
+ //------------------------------------------------------------------
+ /// Actually deallocate memory in the process.
+ ///
+ /// This function will deallocate memory in the process's address
+ /// space that was allocated with AllocateMemory.
+ ///
+ /// @param[in] ptr
+ /// A return value from AllocateMemory, pointing to the memory you
+ /// want to deallocate.
+ ///
+ /// @return
+ /// \btrue if the memory was deallocated, \bfalse otherwise.
+ //------------------------------------------------------------------
+
+ virtual Error
+ DoDeallocateMemory (lldb::addr_t ptr)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support deallocating in the debug process", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ //------------------------------------------------------------------
+ /// The public interface to deallocating memory in the process.
+ ///
+ /// This function will deallocate memory in the process's address
+ /// space that was allocated with AllocateMemory.
+ ///
+ /// @param[in] ptr
+ /// A return value from AllocateMemory, pointing to the memory you
+ /// want to deallocate.
+ ///
+ /// @return
+ /// \btrue if the memory was deallocated, \bfalse otherwise.
+ //------------------------------------------------------------------
+
+ Error
+ DeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ /// Get any available STDOUT.
+ ///
+ /// If the process was launched without supplying valid file paths
+ /// for stdin, stdout, and stderr, then the Process class might
+ /// try to cache the STDOUT for the process if it is able. Events
+ /// will be queued indicating that there is STDOUT available that
+ /// can be retrieved using this function.
+ ///
+ /// @param[out] buf
+ /// A buffer that will receive any STDOUT bytes that are
+ /// currently available.
+ ///
+ /// @param[out] buf_size
+ /// The size in bytes for the buffer \a buf.
+ ///
+ /// @return
+ /// The number of bytes written into \a buf. If this value is
+ /// equal to \a buf_size, another call to this function should
+ /// be made to retrieve more STDOUT data.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDOUT (char *buf, size_t buf_size, Error &error);
+
+ //------------------------------------------------------------------
+ /// Get any available STDERR.
+ ///
+ /// If the process was launched without supplying valid file paths
+ /// for stdin, stdout, and stderr, then the Process class might
+ /// try to cache the STDERR for the process if it is able. Events
+ /// will be queued indicating that there is STDERR available that
+ /// can be retrieved using this function.
+ ///
+ /// @param[out] buf
+ /// A buffer that will receive any STDERR bytes that are
+ /// currently available.
+ ///
+ /// @param[out] buf_size
+ /// The size in bytes for the buffer \a buf.
+ ///
+ /// @return
+ /// The number of bytes written into \a buf. If this value is
+ /// equal to \a buf_size, another call to this function should
+ /// be made to retrieve more STDERR data.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetSTDERR (char *buf, size_t buf_size, Error &error);
+
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, Error &error)
+ {
+ error.SetErrorString("stdin unsupported");
+ return 0;
+ }
+
+ //------------------------------------------------------------------
+ /// Get any available profile data.
+ ///
+ /// @param[out] buf
+ /// A buffer that will receive any profile data bytes that are
+ /// currently available.
+ ///
+ /// @param[out] buf_size
+ /// The size in bytes for the buffer \a buf.
+ ///
+ /// @return
+ /// The number of bytes written into \a buf. If this value is
+ /// equal to \a buf_size, another call to this function should
+ /// be made to retrieve more profile data.
+ //------------------------------------------------------------------
+ virtual size_t
+ GetAsyncProfileData (char *buf, size_t buf_size, Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ size_t
+ GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site);
+
+ virtual Error
+ EnableBreakpointSite (BreakpointSite *bp_site)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support enabling breakpoints", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ virtual Error
+ DisableBreakpointSite (BreakpointSite *bp_site)
+ {
+ Error error;
+ error.SetErrorStringWithFormat("error: %s does not support disabling breakpoints", GetPluginName().GetCString());
+ return error;
+ }
+
+
+ // This is implemented completely using the lldb::Process API. Subclasses
+ // don't need to implement this function unless the standard flow of
+ // read existing opcode, write breakpoint opcode, verify breakpoint opcode
+ // doesn't work for a specific process plug-in.
+ virtual Error
+ EnableSoftwareBreakpoint (BreakpointSite *bp_site);
+
+ // This is implemented completely using the lldb::Process API. Subclasses
+ // don't need to implement this function unless the standard flow of
+ // restoring original opcode in memory and verifying the restored opcode
+ // doesn't work for a specific process plug-in.
+ virtual Error
+ DisableSoftwareBreakpoint (BreakpointSite *bp_site);
+
+ BreakpointSiteList &
+ GetBreakpointSiteList();
+
+ const BreakpointSiteList &
+ GetBreakpointSiteList() const;
+
+ void
+ DisableAllBreakpointSites ();
+
+ Error
+ ClearBreakpointSiteByID (lldb::user_id_t break_id);
+
+ lldb::break_id_t
+ CreateBreakpointSite (const lldb::BreakpointLocationSP &owner,
+ bool use_hardware);
+
+ Error
+ DisableBreakpointSiteByID (lldb::user_id_t break_id);
+
+ Error
+ EnableBreakpointSiteByID (lldb::user_id_t break_id);
+
+
+ // BreakpointLocations use RemoveOwnerFromBreakpointSite to remove
+ // themselves from the owner's list of this breakpoint sites.
+ void
+ RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id,
+ lldb::user_id_t owner_loc_id,
+ lldb::BreakpointSiteSP &bp_site_sp);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints (optional)
+ //----------------------------------------------------------------------
+ virtual Error
+ EnableWatchpoint (Watchpoint *wp, bool notify = true);
+
+ virtual Error
+ DisableWatchpoint (Watchpoint *wp, bool notify = true);
+
+ //------------------------------------------------------------------
+ // Thread Queries
+ //------------------------------------------------------------------
+ virtual bool
+ UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) = 0;
+
+ void
+ UpdateThreadListIfNeeded ();
+
+ ThreadList &
+ GetThreadList ()
+ {
+ return m_thread_list;
+ }
+
+ uint32_t
+ GetNextThreadIndexID (uint64_t thread_id);
+
+ lldb::ThreadSP
+ CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context);
+
+ // Returns true if an index id has been assigned to a thread.
+ bool
+ HasAssignedIndexIDToThread(uint64_t sb_thread_id);
+
+ // Given a thread_id, it will assign a more reasonable index id for display to the user.
+ // If the thread_id has previously been assigned, the same index id will be used.
+ uint32_t
+ AssignIndexIDToThread(uint64_t thread_id);
+
+ //------------------------------------------------------------------
+ // Event Handling
+ //------------------------------------------------------------------
+ lldb::StateType
+ GetNextEvent (lldb::EventSP &event_sp);
+
+ lldb::StateType
+ WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr = NULL);
+
+ lldb::StateType
+ WaitForStateChangedEvents (const TimeValue *timeout, lldb::EventSP &event_sp);
+
+ Event *
+ PeekAtStateChangedEvents ();
+
+
+ class
+ ProcessEventHijacker
+ {
+ public:
+ ProcessEventHijacker (Process &process, Listener *listener) :
+ m_process (process)
+ {
+ m_process.HijackProcessEvents (listener);
+ }
+ ~ProcessEventHijacker ()
+ {
+ m_process.RestoreProcessEvents();
+ }
+
+ private:
+ Process &m_process;
+ };
+ friend class ProcessEventHijacker;
+ //------------------------------------------------------------------
+ /// If you need to ensure that you and only you will hear about some public
+ /// event, then make a new listener, set to listen to process events, and
+ /// then call this with that listener. Then you will have to wait on that
+ /// listener explicitly for events (rather than using the GetNextEvent & WaitFor*
+ /// calls above. Be sure to call RestoreProcessEvents when you are done.
+ ///
+ /// @param[in] listener
+ /// This is the new listener to whom all process events will be delivered.
+ ///
+ /// @return
+ /// Returns \b true if the new listener could be installed,
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ HijackProcessEvents (Listener *listener);
+
+ //------------------------------------------------------------------
+ /// Restores the process event broadcasting to its normal state.
+ ///
+ //------------------------------------------------------------------
+ void
+ RestoreProcessEvents ();
+
+private:
+ //------------------------------------------------------------------
+ /// This is the part of the event handling that for a process event.
+ /// It decides what to do with the event and returns true if the
+ /// event needs to be propagated to the user, and false otherwise.
+ /// If the event is not propagated, this call will most likely set
+ /// the target to executing again.
+ /// There is only one place where this call should be called, HandlePrivateEvent.
+ /// Don't call it from anywhere else...
+ ///
+ /// @param[in] event_ptr
+ /// This is the event we are handling.
+ ///
+ /// @return
+ /// Returns \b true if the event should be reported to the
+ /// user, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ShouldBroadcastEvent (Event *event_ptr);
+
+public:
+ const lldb::ABISP &
+ GetABI ();
+
+ OperatingSystem *
+ GetOperatingSystem ()
+ {
+ return m_os_ap.get();
+ }
+
+
+ virtual LanguageRuntime *
+ GetLanguageRuntime (lldb::LanguageType language, bool retry_if_null = true);
+
+ virtual CPPLanguageRuntime *
+ GetCPPLanguageRuntime (bool retry_if_null = true);
+
+ virtual ObjCLanguageRuntime *
+ GetObjCLanguageRuntime (bool retry_if_null = true);
+
+ bool
+ IsPossibleDynamicValue (ValueObject& in_value);
+
+ bool
+ IsRunning () const;
+
+ DynamicCheckerFunctions *GetDynamicCheckers()
+ {
+ return m_dynamic_checkers_ap.get();
+ }
+
+ void SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
+ {
+ m_dynamic_checkers_ap.reset(dynamic_checkers);
+ }
+
+ //------------------------------------------------------------------
+ /// Call this to set the lldb in the mode where it breaks on new thread
+ /// creations, and then auto-restarts. This is useful when you are trying
+ /// to run only one thread, but either that thread or the kernel is creating
+ /// new threads in the process. If you stop when the thread is created, you
+ /// can immediately suspend it, and keep executing only the one thread you intend.
+ ///
+ /// @return
+ /// Returns \b true if we were able to start up the notification
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ StartNoticingNewThreads()
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Call this to turn off the stop & notice new threads mode.
+ ///
+ /// @return
+ /// Returns \b true if we were able to start up the notification
+ /// \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ StopNoticingNewThreads()
+ {
+ return true;
+ }
+
+ void
+ SetRunningUserExpression (bool on);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual lldb::TargetSP
+ CalculateTarget ();
+
+ virtual lldb::ProcessSP
+ CalculateProcess ()
+ {
+ return shared_from_this();
+ }
+
+ virtual lldb::ThreadSP
+ CalculateThread ()
+ {
+ return lldb::ThreadSP();
+ }
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame ()
+ {
+ return lldb::StackFrameSP();
+ }
+
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx);
+
+ void
+ SetSTDIOFileDescriptor (int file_descriptor);
+
+ //------------------------------------------------------------------
+ // Add a permanent region of memory that should never be read or
+ // written to. This can be used to ensure that memory reads or writes
+ // to certain areas of memory never end up being sent to the
+ // DoReadMemory or DoWriteMemory functions which can improve
+ // performance.
+ //------------------------------------------------------------------
+ void
+ AddInvalidMemoryRegion (const LoadRange &region);
+
+ //------------------------------------------------------------------
+ // Remove a permanent region of memory that should never be read or
+ // written to that was previously added with AddInvalidMemoryRegion.
+ //------------------------------------------------------------------
+ bool
+ RemoveInvalidMemoryRange (const LoadRange &region);
+
+ //------------------------------------------------------------------
+ // If the setup code of a thread plan needs to do work that might involve
+ // calling a function in the target, it should not do that work directly
+ // in one of the thread plan functions (DidPush/WillResume) because
+ // such work needs to be handled carefully. Instead, put that work in
+ // a PreResumeAction callback, and register it with the process. It will
+ // get done before the actual "DoResume" gets called.
+ //------------------------------------------------------------------
+
+ typedef bool (PreResumeActionCallback)(void *);
+
+ void
+ AddPreResumeAction (PreResumeActionCallback callback, void *baton);
+
+ bool
+ RunPreResumeActions ();
+
+ void
+ ClearPreResumeActions ();
+
+ ProcessRunLock &
+ GetRunLock ()
+ {
+ if (Host::GetCurrentThread() == m_private_state_thread)
+ return m_private_run_lock;
+ else
+ return m_public_run_lock;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // NextEventAction provides a way to register an action on the next
+ // event that is delivered to this process. There is currently only
+ // one next event action allowed in the process at one time. If a
+ // new "NextEventAction" is added while one is already present, the
+ // old action will be discarded (with HandleBeingUnshipped called
+ // after it is discarded.)
+ //
+ // If you want to resume the process as a result of a resume action,
+ // call RequestResume, don't call Resume directly.
+ //------------------------------------------------------------------
+ class NextEventAction
+ {
+ public:
+ typedef enum EventActionResult
+ {
+ eEventActionSuccess,
+ eEventActionRetry,
+ eEventActionExit
+ } EventActionResult;
+
+ NextEventAction (Process *process) :
+ m_process(process)
+ {
+ }
+
+ virtual
+ ~NextEventAction()
+ {
+ }
+
+ virtual EventActionResult PerformAction (lldb::EventSP &event_sp) = 0;
+ virtual void HandleBeingUnshipped () {}
+ virtual EventActionResult HandleBeingInterrupted () = 0;
+ virtual const char *GetExitString() = 0;
+ void RequestResume()
+ {
+ m_process->m_resume_requested = true;
+ }
+ protected:
+ Process *m_process;
+ };
+
+ void SetNextEventAction (Process::NextEventAction *next_event_action)
+ {
+ if (m_next_event_action_ap.get())
+ m_next_event_action_ap->HandleBeingUnshipped();
+
+ m_next_event_action_ap.reset(next_event_action);
+ }
+
+ // This is the completer for Attaching:
+ class AttachCompletionHandler : public NextEventAction
+ {
+ public:
+ AttachCompletionHandler (Process *process, uint32_t exec_count) :
+ NextEventAction (process),
+ m_exec_count (exec_count)
+ {
+ }
+
+ virtual
+ ~AttachCompletionHandler()
+ {
+ }
+
+ virtual EventActionResult PerformAction (lldb::EventSP &event_sp);
+ virtual EventActionResult HandleBeingInterrupted ();
+ virtual const char *GetExitString();
+ private:
+ uint32_t m_exec_count;
+ std::string m_exit_string;
+ };
+
+ bool
+ HijackPrivateProcessEvents (Listener *listener);
+
+ void
+ RestorePrivateProcessEvents ();
+
+ bool
+ PrivateStateThreadIsValid () const
+ {
+ return IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
+ }
+
+ //------------------------------------------------------------------
+ // Type definitions
+ //------------------------------------------------------------------
+ typedef std::map<lldb::LanguageType, lldb::LanguageRuntimeSP> LanguageRuntimeCollection;
+
+ struct PreResumeCallbackAndBaton
+ {
+ bool (*callback) (void *);
+ void *baton;
+ PreResumeCallbackAndBaton (PreResumeActionCallback in_callback, void *in_baton) :
+ callback (in_callback),
+ baton (in_baton)
+ {
+ }
+ };
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ Target & m_target; ///< The target that owns this process.
+ ThreadSafeValue<lldb::StateType> m_public_state;
+ ThreadSafeValue<lldb::StateType> m_private_state; // The actual state of our process
+ Broadcaster m_private_state_broadcaster; // This broadcaster feeds state changed events into the private state thread's listener.
+ Broadcaster m_private_state_control_broadcaster; // This is the control broadcaster, used to pause, resume & stop the private state thread.
+ Listener m_private_state_listener; // This is the listener for the private state thread.
+ Predicate<bool> m_private_state_control_wait; /// This Predicate is used to signal that a control operation is complete.
+ lldb::thread_t m_private_state_thread; // Thread ID for the thread that watches interal state events
+ ProcessModID m_mod_id; ///< Tracks the state of the process over stops and other alterations.
+ uint32_t m_process_unique_id; ///< Each lldb_private::Process class that is created gets a unique integer ID that increments with each new instance
+ uint32_t m_thread_index_id; ///< Each thread is created with a 1 based index that won't get re-used.
+ std::map<uint64_t, uint32_t> m_thread_id_to_index_id_map;
+ int m_exit_status; ///< The exit status of the process, or -1 if not set.
+ std::string m_exit_string; ///< A textual description of why a process exited.
+ Mutex m_thread_mutex;
+ ThreadList m_thread_list_real; ///< The threads for this process as are known to the protocol we are debugging with
+ ThreadList m_thread_list; ///< The threads for this process as the user will see them. This is usually the same as
+ ///< m_thread_list_real, but might be different if there is an OS plug-in creating memory threads
+ std::vector<Notifications> m_notifications; ///< The list of notifications that this process can deliver.
+ std::vector<lldb::addr_t> m_image_tokens;
+ Listener &m_listener;
+ BreakpointSiteList m_breakpoint_site_list; ///< This is the list of breakpoint locations we intend to insert in the target.
+ std::unique_ptr<DynamicLoader> m_dyld_ap;
+ std::unique_ptr<DynamicCheckerFunctions> m_dynamic_checkers_ap; ///< The functions used by the expression parser to validate data that expressions use.
+ std::unique_ptr<OperatingSystem> m_os_ap;
+ UnixSignals m_unix_signals; /// This is the current signal set for this process.
+ lldb::ABISP m_abi_sp;
+ lldb::InputReaderSP m_process_input_reader;
+ Communication m_stdio_communication;
+ Mutex m_stdio_communication_mutex;
+ std::string m_stdout_data;
+ std::string m_stderr_data;
+ Mutex m_profile_data_comm_mutex;
+ std::vector<std::string> m_profile_data;
+ MemoryCache m_memory_cache;
+ AllocatedMemoryCache m_allocated_memory_cache;
+ bool m_should_detach; /// Should we detach if the process object goes away with an explicit call to Kill or Detach?
+ LanguageRuntimeCollection m_language_runtimes;
+ std::unique_ptr<NextEventAction> m_next_event_action_ap;
+ std::vector<PreResumeCallbackAndBaton> m_pre_resume_actions;
+ ProcessRunLock m_public_run_lock;
+ ProcessRunLock m_private_run_lock;
+ Predicate<bool> m_currently_handling_event; // This predicate is set in HandlePrivateEvent while all its business is being done.
+ bool m_currently_handling_do_on_removals;
+ bool m_resume_requested; // If m_currently_handling_event or m_currently_handling_do_on_removals are true, Resume will only request a resume, using this flag to check.
+ bool m_finalize_called;
+ bool m_clear_thread_plans_on_stop;
+ lldb::StateType m_last_broadcast_state; /// This helps with the Public event coalescing in ShouldBroadcastEvent.
+ bool m_destroy_in_process;
+
+ enum {
+ eCanJITDontKnow= 0,
+ eCanJITYes,
+ eCanJITNo
+ } m_can_jit;
+
+ size_t
+ RemoveBreakpointOpcodesFromBuffer (lldb::addr_t addr, size_t size, uint8_t *buf) const;
+
+ void
+ SynchronouslyNotifyStateChanged (lldb::StateType state);
+
+ void
+ SetPublicState (lldb::StateType new_state, bool restarted);
+
+ void
+ SetPrivateState (lldb::StateType state);
+
+ bool
+ StartPrivateStateThread (bool force = false);
+
+ void
+ StopPrivateStateThread ();
+
+ void
+ PausePrivateStateThread ();
+
+ void
+ ResumePrivateStateThread ();
+
+ static void *
+ PrivateStateThread (void *arg);
+
+ void *
+ RunPrivateStateThread ();
+
+ void
+ HandlePrivateEvent (lldb::EventSP &event_sp);
+
+ lldb::StateType
+ WaitForProcessStopPrivate (const TimeValue *timeout, lldb::EventSP &event_sp);
+
+ // This waits for both the state change broadcaster, and the control broadcaster.
+ // If control_only, it only waits for the control broadcaster.
+
+ bool
+ WaitForEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp, bool control_only);
+
+ lldb::StateType
+ WaitForStateChangedEventsPrivate (const TimeValue *timeout, lldb::EventSP &event_sp);
+
+ lldb::StateType
+ WaitForState (const TimeValue *timeout,
+ const lldb::StateType *match_states,
+ const uint32_t num_match_states);
+
+ size_t
+ WriteMemoryPrivate (lldb::addr_t addr, const void *buf, size_t size, Error &error);
+
+ void
+ AppendSTDOUT (const char *s, size_t len);
+
+ void
+ AppendSTDERR (const char *s, size_t len);
+
+ void
+ BroadcastAsyncProfileData(const std::string &one_profile_data);
+
+ static void
+ STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ void
+ PushProcessInputReader ();
+
+ void
+ PopProcessInputReader ();
+
+ void
+ ResetProcessInputReader ();
+
+ static size_t
+ ProcessInputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ Error
+ HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp);
+
+private:
+ //------------------------------------------------------------------
+ // For Process only
+ //------------------------------------------------------------------
+ void ControlPrivateStateThread (uint32_t signal);
+
+ DISALLOW_COPY_AND_ASSIGN (Process);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Process_h_
diff --git a/include/lldb/Target/RegisterContext.h b/include/lldb/Target/RegisterContext.h
new file mode 100644
index 000000000000..dd0e73fc7eb3
--- /dev/null
+++ b/include/lldb/Target/RegisterContext.h
@@ -0,0 +1,213 @@
+//===-- RegisterContext.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_h_
+#define liblldb_RegisterContext_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ExecutionContextScope.h"
+
+namespace lldb_private {
+
+class RegisterContext :
+ public std::enable_shared_from_this<RegisterContext>,
+ public ExecutionContextScope
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContext (Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContext ();
+
+ void
+ InvalidateIfNeeded (bool force);
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters () = 0;
+
+ virtual size_t
+ GetRegisterCount () = 0;
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg) = 0;
+
+ virtual size_t
+ GetRegisterSetCount () = 0;
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set) = 0;
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value) = 0;
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value) = 0;
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp) = 0;
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) = 0;
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) = 0;
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+ //------------------------------------------------------------------
+ // Subclasses should not override these
+ //------------------------------------------------------------------
+ virtual lldb::tid_t
+ GetThreadID() const;
+
+ virtual Thread &
+ GetThread ()
+ {
+ return m_thread;
+ }
+
+ const RegisterInfo *
+ GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0);
+
+ uint64_t
+ GetPC (uint64_t fail_value = LLDB_INVALID_ADDRESS);
+
+ bool
+ SetPC (uint64_t pc);
+
+ uint64_t
+ GetSP (uint64_t fail_value = LLDB_INVALID_ADDRESS);
+
+ bool
+ SetSP (uint64_t sp);
+
+ uint64_t
+ GetFP (uint64_t fail_value = LLDB_INVALID_ADDRESS);
+
+ bool
+ SetFP (uint64_t fp);
+
+ const char *
+ GetRegisterName (uint32_t reg);
+
+ uint64_t
+ GetReturnAddress (uint64_t fail_value = LLDB_INVALID_ADDRESS);
+
+ uint64_t
+ GetFlags (uint64_t fail_value = 0);
+
+ uint64_t
+ ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value);
+
+ uint64_t
+ ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value);
+
+ bool
+ WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval);
+
+ bool
+ WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval);
+ bool
+ ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual lldb::TargetSP
+ CalculateTarget ();
+
+ virtual lldb::ProcessSP
+ CalculateProcess ();
+
+ virtual lldb::ThreadSP
+ CalculateThread ();
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame ();
+
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx);
+
+ uint32_t
+ GetStopID () const
+ {
+ return m_stop_id;
+ }
+
+ void
+ SetStopID (uint32_t stop_id)
+ {
+ m_stop_id = stop_id;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from RegisterContext can see and modify these
+ //------------------------------------------------------------------
+ Thread &m_thread; // The thread that this register context belongs to.
+ uint32_t m_concrete_frame_idx; // The concrete frame index for this register context
+ uint32_t m_stop_id; // The stop ID that any data in this context is valid for
+private:
+ //------------------------------------------------------------------
+ // For RegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContext);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_RegisterContext_h_
diff --git a/include/lldb/Target/SectionLoadList.h b/include/lldb/Target/SectionLoadList.h
new file mode 100644
index 000000000000..ac05bf7a9cb4
--- /dev/null
+++ b/include/lldb/Target/SectionLoadList.h
@@ -0,0 +1,89 @@
+//===-- SectionLoadList.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_SectionLoadList_h_
+#define liblldb_SectionLoadList_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class SectionLoadList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SectionLoadList () :
+ m_addr_to_sect (),
+ m_sect_to_addr (),
+ m_mutex (Mutex::eMutexTypeRecursive)
+
+ {
+ }
+
+ ~SectionLoadList()
+ {
+ // Call clear since this takes a lock and clears the section load list
+ // in case another thread is currently using this section load list
+ Clear();
+ }
+
+ bool
+ IsEmpty() const;
+
+ void
+ Clear ();
+
+ lldb::addr_t
+ GetSectionLoadAddress (const lldb::SectionSP &section_sp) const;
+
+ bool
+ ResolveLoadAddress (lldb::addr_t load_addr, Address &so_addr) const;
+
+ bool
+ SetSectionLoadAddress (const lldb::SectionSP &section_sp, lldb::addr_t load_addr, bool warn_multiple = false);
+
+ // The old load address should be specified when unloading to ensure we get
+ // the correct instance of the section as a shared library could be loaded
+ // at more than one location.
+ bool
+ SetSectionUnloaded (const lldb::SectionSP &section_sp, lldb::addr_t load_addr);
+
+ // Unload all instances of a section. This function can be used on systems
+ // that don't support multiple copies of the same shared library to be
+ // loaded at the same time.
+ size_t
+ SetSectionUnloaded (const lldb::SectionSP &section_sp);
+
+ void
+ Dump (Stream &s, Target *target);
+
+protected:
+ typedef std::map<lldb::addr_t, lldb::SectionSP> addr_to_sect_collection;
+ typedef llvm::DenseMap<const Section *, lldb::addr_t> sect_to_addr_collection;
+ addr_to_sect_collection m_addr_to_sect;
+ sect_to_addr_collection m_sect_to_addr;
+ mutable Mutex m_mutex;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SectionLoadList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_SectionLoadList_h_
diff --git a/include/lldb/Target/StackFrame.h b/include/lldb/Target/StackFrame.h
new file mode 100644
index 000000000000..877bd8ce661b
--- /dev/null
+++ b/include/lldb/Target/StackFrame.h
@@ -0,0 +1,207 @@
+//===-- StackFrame.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_StackFrame_h_
+#define liblldb_StackFrame_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackID.h"
+
+namespace lldb_private {
+
+class StackFrame :
+ public std::enable_shared_from_this<StackFrame>,
+ public ExecutionContextScope
+{
+public:
+ enum ExpressionPathOption
+ {
+ eExpressionPathOptionCheckPtrVsMember = (1u << 0),
+ eExpressionPathOptionsNoFragileObjcIvar = (1u << 1),
+ eExpressionPathOptionsNoSyntheticChildren = (1u << 2),
+ eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3),
+ eExpressionPathOptionsAllowDirectIVarAccess = (1u << 4)
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StackFrame (const lldb::ThreadSP &thread_sp,
+ lldb::user_id_t frame_idx,
+ lldb::user_id_t concrete_frame_idx,
+ lldb::addr_t cfa,
+ lldb::addr_t pc,
+ const SymbolContext *sc_ptr);
+
+ StackFrame (const lldb::ThreadSP &thread_sp,
+ lldb::user_id_t frame_idx,
+ lldb::user_id_t concrete_frame_idx,
+ const lldb::RegisterContextSP &reg_context_sp,
+ lldb::addr_t cfa,
+ lldb::addr_t pc,
+ const SymbolContext *sc_ptr);
+
+ StackFrame (const lldb::ThreadSP &thread_sp,
+ lldb::user_id_t frame_idx,
+ lldb::user_id_t concrete_frame_idx,
+ const lldb::RegisterContextSP &reg_context_sp,
+ lldb::addr_t cfa,
+ const Address& pc,
+ const SymbolContext *sc_ptr);
+
+ virtual ~StackFrame ();
+
+ lldb::ThreadSP
+ GetThread () const
+ {
+ return m_thread_wp.lock();
+ }
+
+ StackID&
+ GetStackID();
+
+ const Address&
+ GetFrameCodeAddress();
+
+ void
+ ChangePC (lldb::addr_t pc);
+
+ const SymbolContext&
+ GetSymbolContext (uint32_t resolve_scope);
+
+ bool
+ GetFrameBaseValue(Scalar &value, Error *error_ptr);
+
+ Block *
+ GetFrameBlock ();
+
+ lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ const lldb::RegisterContextSP &
+ GetRegisterContextSP () const
+ {
+ return m_reg_context_sp;
+ }
+
+ VariableList *
+ GetVariableList (bool get_file_globals);
+
+ lldb::VariableListSP
+ GetInScopeVariableList (bool get_file_globals);
+
+ // See ExpressionPathOption enumeration for "options" values
+ lldb::ValueObjectSP
+ GetValueForVariableExpressionPath (const char *var_expr,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t options,
+ lldb::VariableSP &var_sp,
+ Error &error);
+
+ bool
+ HasDebugInformation ();
+
+ const char *
+ Disassemble ();
+
+ void
+ DumpUsingSettingsFormat (Stream *strm);
+
+ void
+ Dump (Stream *strm, bool show_frame_index, bool show_fullpaths);
+
+ bool
+ IsInlined ();
+
+ uint32_t
+ GetFrameIndex () const;
+
+ uint32_t
+ GetConcreteFrameIndex () const
+ {
+ return m_concrete_frame_index;
+ }
+
+ lldb::ValueObjectSP
+ GetValueObjectForFrameVariable (const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic);
+
+ lldb::ValueObjectSP
+ TrackGlobalVariable (const lldb::VariableSP &variable_sp, lldb::DynamicValueType use_dynamic);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual lldb::TargetSP
+ CalculateTarget ();
+
+ virtual lldb::ProcessSP
+ CalculateProcess ();
+
+ virtual lldb::ThreadSP
+ CalculateThread ();
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame ();
+
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx);
+
+ bool
+ GetStatus (Stream &strm,
+ bool show_frame_info,
+ bool show_source);
+
+protected:
+ friend class StackFrameList;
+
+ void
+ SetSymbolContextScope (SymbolContextScope *symbol_scope);
+
+ void
+ UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame);
+
+ void
+ UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame);
+
+ bool
+ HasCachedData () const;
+
+private:
+ //------------------------------------------------------------------
+ // For StackFrame only
+ //------------------------------------------------------------------
+ lldb::ThreadWP m_thread_wp;
+ uint32_t m_frame_index;
+ uint32_t m_concrete_frame_index;
+ lldb::RegisterContextSP m_reg_context_sp;
+ StackID m_id;
+ Address m_frame_code_addr; // The frame code address (might not be the same as the actual PC for inlined frames) as a section/offset address
+ SymbolContext m_sc;
+ Flags m_flags;
+ Scalar m_frame_base;
+ Error m_frame_base_error;
+ lldb::VariableListSP m_variable_list_sp;
+ ValueObjectList m_variable_list_value_objects; // Value objects for each variable in m_variable_list_sp
+ StreamString m_disassembly;
+ DISALLOW_COPY_AND_ASSIGN (StackFrame);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StackFrame_h_
diff --git a/include/lldb/Target/StackFrameList.h b/include/lldb/Target/StackFrameList.h
new file mode 100644
index 000000000000..b2689d0391e9
--- /dev/null
+++ b/include/lldb/Target/StackFrameList.h
@@ -0,0 +1,157 @@
+//===-- StackFrameList.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_StackFrameList_h_
+#define liblldb_StackFrameList_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/StackFrame.h"
+
+namespace lldb_private {
+
+class StackFrameList
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StackFrameList (Thread &thread,
+ const lldb::StackFrameListSP &prev_frames_sp,
+ bool show_inline_frames);
+
+ ~StackFrameList();
+
+ uint32_t
+ GetNumFrames (bool can_create = true);
+
+ lldb::StackFrameSP
+ GetFrameAtIndex (uint32_t idx);
+
+ lldb::StackFrameSP
+ GetFrameWithConcreteFrameIndex (uint32_t unwind_idx);
+
+ lldb::StackFrameSP
+ GetFrameWithStackID (const StackID &stack_id);
+
+ // Mark a stack frame as the current frame
+ uint32_t
+ SetSelectedFrame (lldb_private::StackFrame *frame);
+
+ uint32_t
+ GetSelectedFrameIndex () const;
+
+ // Mark a stack frame as the current frame using the frame index
+ bool
+ SetSelectedFrameByIndex (uint32_t idx);
+
+ uint32_t
+ GetVisibleStackFrameIndex(uint32_t idx)
+ {
+ if (m_current_inlined_depth < UINT32_MAX)
+ return idx - m_current_inlined_depth;
+ else
+ return idx;
+ }
+
+ void
+ CalculateCurrentInlinedDepth ();
+
+ void
+ SetDefaultFileAndLineToSelectedFrame();
+
+ void
+ Clear ();
+
+ void
+ InvalidateFrames (uint32_t start_idx);
+
+ void
+ Dump (Stream *s);
+
+ lldb::StackFrameSP
+ GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr);
+
+ size_t
+ GetStatus (Stream &strm,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source);
+
+protected:
+
+ friend class Thread;
+
+ bool
+ SetFrameAtIndex (uint32_t idx, lldb::StackFrameSP &frame_sp);
+
+ static void
+ Merge (std::unique_ptr<StackFrameList>& curr_ap,
+ lldb::StackFrameListSP& prev_sp);
+
+ void
+ GetFramesUpTo (uint32_t end_idx);
+
+ bool
+ GetAllFramesFetched()
+ {
+ return m_concrete_frames_fetched == UINT32_MAX;
+ }
+
+ void
+ SetAllFramesFetched ()
+ {
+ m_concrete_frames_fetched = UINT32_MAX;
+ }
+
+ bool
+ DecrementCurrentInlinedDepth ();
+
+ void
+ ResetCurrentInlinedDepth();
+
+ uint32_t
+ GetCurrentInlinedDepth ();
+
+ void
+ SetCurrentInlinedDepth (uint32_t new_depth);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from StackFrameList can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector<lldb::StackFrameSP> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ Thread &m_thread;
+ lldb::StackFrameListSP m_prev_frames_sp;
+ mutable Mutex m_mutex;
+ collection m_frames;
+ uint32_t m_selected_frame_idx;
+ uint32_t m_concrete_frames_fetched;
+ uint32_t m_current_inlined_depth;
+ lldb::addr_t m_current_inlined_pc;
+ bool m_show_inlined_frames;
+
+private:
+ //------------------------------------------------------------------
+ // For StackFrameList only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (StackFrameList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StackFrameList_h_
diff --git a/include/lldb/Target/StackID.h b/include/lldb/Target/StackID.h
new file mode 100644
index 000000000000..7e713c73d972
--- /dev/null
+++ b/include/lldb/Target/StackID.h
@@ -0,0 +1,149 @@
+//===-- StackID.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_StackID_h_
+#define liblldb_StackID_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/AddressRange.h"
+
+namespace lldb_private {
+
+class StackID
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StackID () :
+ m_pc (LLDB_INVALID_ADDRESS),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_symbol_scope (NULL)
+ {
+ }
+
+ explicit
+ StackID (lldb::addr_t pc, lldb::addr_t cfa, SymbolContextScope *symbol_scope) :
+ m_pc (pc),
+ m_cfa (cfa),
+ m_symbol_scope (symbol_scope)
+ {
+ }
+
+ StackID (const StackID& rhs) :
+ m_pc (rhs.m_pc),
+ m_cfa (rhs.m_cfa),
+ m_symbol_scope (rhs.m_symbol_scope)
+ {
+ }
+
+ ~StackID()
+ {
+ }
+
+ lldb::addr_t
+ GetPC() const
+ {
+ return m_pc;
+ }
+
+ lldb::addr_t
+ GetCallFrameAddress() const
+ {
+ return m_cfa;
+ }
+
+ SymbolContextScope *
+ GetSymbolContextScope () const
+ {
+ return m_symbol_scope;
+ }
+
+ void
+ SetSymbolContextScope (SymbolContextScope *symbol_scope)
+ {
+ m_symbol_scope = symbol_scope;
+ }
+
+ void
+ Clear ()
+ {
+ m_pc = LLDB_INVALID_ADDRESS;
+ m_cfa = LLDB_INVALID_ADDRESS;
+ m_symbol_scope = NULL;
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_pc != LLDB_INVALID_ADDRESS || m_cfa != LLDB_INVALID_ADDRESS;
+ }
+
+ void
+ Dump (Stream *s);
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const StackID&
+ operator=(const StackID& rhs)
+ {
+ if (this != &rhs)
+ {
+ m_pc = rhs.m_pc;
+ m_cfa = rhs.m_cfa;
+ m_symbol_scope = rhs.m_symbol_scope;
+ }
+ return *this;
+ }
+
+protected:
+
+ friend class StackFrame;
+
+ void
+ SetPC (lldb::addr_t pc)
+ {
+ m_pc = pc;
+ }
+
+
+ //------------------------------------------------------------------
+ // Classes that inherit from StackID can see and modify these
+ //------------------------------------------------------------------
+ lldb::addr_t m_pc; // The pc value for the function/symbol for this frame. This will
+ // only get used if the symbol scope is NULL (the code where we are
+ // stopped is not represented by any function or symbol in any
+ // shared library).
+ lldb::addr_t m_cfa; // The call frame address (stack pointer) value
+ // at the beginning of the function that uniquely
+ // identifies this frame (along with m_symbol_scope below)
+ SymbolContextScope *m_symbol_scope; // If NULL, there is no block or symbol for this frame.
+ // If not NULL, this will either be the scope for the
+ // lexical block for the frame, or the scope
+ // for the symbol. Symbol context scopes are
+ // always be unique pointers since the are part
+ // of the Block and Symbol objects and can easily
+ // be used to tell if a stack ID is the same as
+ // another.
+};
+
+bool operator== (const StackID& lhs, const StackID& rhs);
+bool operator!= (const StackID& lhs, const StackID& rhs);
+
+// frame_id_1 < frame_id_2 means "frame_id_1 is YOUNGER than frame_id_2"
+bool operator< (const StackID& lhs, const StackID& rhs);
+
+} // namespace lldb_private
+
+#endif // liblldb_StackID_h_
diff --git a/include/lldb/Target/StopInfo.h b/include/lldb/Target/StopInfo.h
new file mode 100644
index 000000000000..3435d392e2b9
--- /dev/null
+++ b/include/lldb/Target/StopInfo.h
@@ -0,0 +1,227 @@
+//===-- StopInfo.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_StopInfo_h_
+#define liblldb_StopInfo_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Target/Process.h"
+
+namespace lldb_private {
+
+class StopInfo
+{
+ friend class Process::ProcessEventData;
+ friend class ThreadPlanBase;
+
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfo (Thread &thread, uint64_t value);
+
+ virtual ~StopInfo()
+ {
+ }
+
+
+ bool
+ IsValid () const;
+
+ void
+ SetThread (const lldb::ThreadSP &thread_sp)
+ {
+ m_thread_wp = thread_sp;
+ }
+
+ lldb::ThreadSP
+ GetThread() const
+ {
+ return m_thread_wp.lock();
+ }
+
+ // The value of the StopInfo depends on the StopReason.
+ // StopReason Meaning
+ // ----------------------------------------------
+ // eStopReasonBreakpoint BreakpointSiteID
+ // eStopReasonSignal Signal number
+ // eStopReasonWatchpoint WatchpointLocationID
+ // eStopReasonPlanComplete No significance
+
+ uint64_t
+ GetValue() const
+ {
+ return m_value;
+ }
+
+ virtual lldb::StopReason
+ GetStopReason () const = 0;
+
+ // ShouldStopSynchronous will get called before any thread plans are consulted, and if it says we should
+ // resume the target, then we will just immediately resume. This should not run any code in or resume the
+ // target.
+
+ virtual bool
+ ShouldStopSynchronous (Event *event_ptr)
+ {
+ return true;
+ }
+
+ void
+ OverrideShouldNotify (bool override_value)
+ {
+ m_override_should_notify = override_value ? eLazyBoolYes : eLazyBoolNo;
+ }
+
+ // If should stop returns false, check if we should notify of this event
+ virtual bool
+ ShouldNotify (Event *event_ptr)
+ {
+ if (m_override_should_notify == eLazyBoolCalculate)
+ return DoShouldNotify (event_ptr);
+ else
+ return m_override_should_notify == eLazyBoolYes;
+ }
+
+ virtual void
+ WillResume (lldb::StateType resume_state)
+ {
+ // By default, don't do anything
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ return m_description.c_str();
+ }
+
+ virtual void
+ SetDescription (const char *desc_cstr)
+ {
+ if (desc_cstr && desc_cstr[0])
+ m_description.assign (desc_cstr);
+ else
+ m_description.clear();
+ }
+
+ // Sometimes the thread plan logic will know that it wants a given stop to stop or not,
+ // regardless of what the ordinary logic for that StopInfo would dictate. The main example
+ // of this is the ThreadPlanCallFunction, which for instance knows - based on how that particular
+ // expression was executed - whether it wants all breakpoints to auto-continue or not.
+ // Use OverrideShouldStop on the StopInfo to implement this.
+
+ void
+ OverrideShouldStop (bool override_value)
+ {
+ m_override_should_stop = override_value ? eLazyBoolYes : eLazyBoolNo;
+ }
+
+ bool
+ GetOverrideShouldStop()
+ {
+ return m_override_should_stop != eLazyBoolCalculate;
+ }
+
+ bool
+ GetOverriddenShouldStopValue ()
+ {
+ return m_override_should_stop == eLazyBoolYes;
+ }
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithBreakpointSiteID (Thread &thread, lldb::break_id_t break_id);
+
+ // This creates a StopInfo for the thread where the should_stop is already set, and won't be recalculated.
+ static lldb::StopInfoSP
+ CreateStopReasonWithBreakpointSiteID (Thread &thread, lldb::break_id_t break_id, bool should_stop);
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithWatchpointID (Thread &thread, lldb::break_id_t watch_id);
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithSignal (Thread &thread, int signo);
+
+ static lldb::StopInfoSP
+ CreateStopReasonToTrace (Thread &thread);
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithPlan (lldb::ThreadPlanSP &plan, lldb::ValueObjectSP return_valobj_sp);
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithException (Thread &thread, const char *description);
+
+ static lldb::StopInfoSP
+ CreateStopReasonWithExec (Thread &thread);
+
+ static lldb::ValueObjectSP
+ GetReturnValueObject (lldb::StopInfoSP &stop_info_sp);
+
+protected:
+ // Perform any action that is associated with this stop. This is done as the
+ // Event is removed from the event queue. ProcessEventData::DoOnRemoval does the job.
+
+ virtual void
+ PerformAction (Event *event_ptr)
+ {
+ }
+
+ virtual bool
+ DoShouldNotify (Event *event_ptr)
+ {
+ return false;
+ }
+
+ // Stop the thread by default. Subclasses can override this to allow
+ // the thread to continue if desired. The ShouldStop method should not do anything
+ // that might run code. If you need to run code when deciding whether to stop
+ // at this StopInfo, that must be done in the PerformAction.
+ // The PerformAction will always get called before the ShouldStop. This is done by the
+ // ProcessEventData::DoOnRemoval, though the ThreadPlanBase needs to consult this later on.
+ virtual bool
+ ShouldStop (Event *event_ptr)
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ // Classes that inherit from StackID can see and modify these
+ //------------------------------------------------------------------
+ lldb::ThreadWP m_thread_wp; // The thread corresponding to the stop reason.
+ uint32_t m_stop_id; // The process stop ID for which this stop info is valid
+ uint32_t m_resume_id; // This is the resume ID when we made this stop ID.
+ uint64_t m_value; // A generic value that can be used for things pertaining to this stop info
+ std::string m_description; // A textual description describing this stop.
+ LazyBool m_override_should_notify;
+ LazyBool m_override_should_stop;
+
+ // This determines whether the target has run since this stop info.
+ // N.B. running to evaluate a user expression does not count.
+ bool HasTargetRunSinceMe ();
+
+ // MakeStopInfoValid is necessary to allow saved stop infos to resurrect themselves as valid.
+ // It should only be used by Thread::RestoreThreadStateFromCheckpoint and to make sure the one-step
+ // needed for before-the-fact watchpoints does not prevent us from stopping
+ void
+ MakeStopInfoValid ();
+
+private:
+ friend class Thread;
+
+ DISALLOW_COPY_AND_ASSIGN (StopInfo);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfo_h_
diff --git a/include/lldb/Target/Target.h b/include/lldb/Target/Target.h
new file mode 100644
index 000000000000..87fa57b3a299
--- /dev/null
+++ b/include/lldb/Target/Target.h
@@ -0,0 +1,1223 @@
+//===-- Target.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Target_h_
+#define liblldb_Target_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Breakpoint/BreakpointList.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueEnumeration.h"
+#include "lldb/Interpreter/OptionValueFileSpec.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/PathMappingList.h"
+#include "lldb/Target/SectionLoadList.h"
+
+namespace lldb_private {
+
+extern OptionEnumValueElement g_dynamic_value_types[];
+
+typedef enum InlineStrategy
+{
+ eInlineBreakpointsNever = 0,
+ eInlineBreakpointsHeaders,
+ eInlineBreakpointsAlways
+} InlineStrategy;
+
+typedef enum LoadScriptFromSymFile
+{
+ eLoadScriptFromSymFileTrue,
+ eLoadScriptFromSymFileFalse,
+ eLoadScriptFromSymFileWarn
+} LoadScriptFromSymFile;
+
+//----------------------------------------------------------------------
+// TargetProperties
+//----------------------------------------------------------------------
+class TargetProperties : public Properties
+{
+public:
+ TargetProperties(Target *target);
+
+ virtual
+ ~TargetProperties();
+
+ ArchSpec
+ GetDefaultArchitecture () const;
+
+ void
+ SetDefaultArchitecture (const ArchSpec& arch);
+
+ lldb::DynamicValueType
+ GetPreferDynamicValue() const;
+
+ bool
+ GetDisableASLR () const;
+
+ void
+ SetDisableASLR (bool b);
+
+ bool
+ GetDisableSTDIO () const;
+
+ void
+ SetDisableSTDIO (bool b);
+
+ const char *
+ GetDisassemblyFlavor() const;
+
+// void
+// SetDisassemblyFlavor(const char *flavor);
+
+ InlineStrategy
+ GetInlineStrategy () const;
+
+ const char *
+ GetArg0 () const;
+
+ void
+ SetArg0 (const char *arg);
+
+ bool
+ GetRunArguments (Args &args) const;
+
+ void
+ SetRunArguments (const Args &args);
+
+ size_t
+ GetEnvironmentAsArgs (Args &env) const;
+
+ bool
+ GetSkipPrologue() const;
+
+ PathMappingList &
+ GetSourcePathMap () const;
+
+ FileSpecList &
+ GetExecutableSearchPaths ();
+
+ FileSpecList &
+ GetDebugFileSearchPaths ();
+
+ bool
+ GetEnableSyntheticValue () const;
+
+ uint32_t
+ GetMaximumNumberOfChildrenToDisplay() const;
+
+ uint32_t
+ GetMaximumSizeOfStringSummary() const;
+
+ uint32_t
+ GetMaximumMemReadSize () const;
+
+ FileSpec
+ GetStandardInputPath () const;
+
+ void
+ SetStandardInputPath (const char *path);
+
+ FileSpec
+ GetStandardOutputPath () const;
+
+ void
+ SetStandardOutputPath (const char *path);
+
+ FileSpec
+ GetStandardErrorPath () const;
+
+ void
+ SetStandardErrorPath (const char *path);
+
+ bool
+ GetBreakpointsConsultPlatformAvoidList ();
+
+ const char *
+ GetExpressionPrefixContentsAsCString ();
+
+ bool
+ GetUseHexImmediates() const;
+
+ bool
+ GetUseFastStepping() const;
+
+ LoadScriptFromSymFile
+ GetLoadScriptFromSymbolFile() const;
+
+ Disassembler::HexImmediateStyle
+ GetHexImmediateStyle() const;
+
+ MemoryModuleLoadLevel
+ GetMemoryModuleLoadLevel() const;
+
+};
+
+typedef std::shared_ptr<TargetProperties> TargetPropertiesSP;
+
+class EvaluateExpressionOptions
+{
+public:
+ static const uint32_t default_timeout = 500000;
+ EvaluateExpressionOptions() :
+ m_execution_policy(eExecutionPolicyOnlyWhenNeeded),
+ m_coerce_to_id(false),
+ m_unwind_on_error(true),
+ m_ignore_breakpoints (false),
+ m_keep_in_memory(false),
+ m_run_others(true),
+ m_use_dynamic(lldb::eNoDynamicValues),
+ m_timeout_usec(default_timeout)
+ {}
+
+ ExecutionPolicy
+ GetExecutionPolicy () const
+ {
+ return m_execution_policy;
+ }
+
+ EvaluateExpressionOptions&
+ SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways)
+ {
+ m_execution_policy = policy;
+ return *this;
+ }
+
+ bool
+ DoesCoerceToId () const
+ {
+ return m_coerce_to_id;
+ }
+
+ EvaluateExpressionOptions&
+ SetCoerceToId (bool coerce = true)
+ {
+ m_coerce_to_id = coerce;
+ return *this;
+ }
+
+ bool
+ DoesUnwindOnError () const
+ {
+ return m_unwind_on_error;
+ }
+
+ EvaluateExpressionOptions&
+ SetUnwindOnError (bool unwind = false)
+ {
+ m_unwind_on_error = unwind;
+ return *this;
+ }
+
+ bool
+ DoesIgnoreBreakpoints () const
+ {
+ return m_ignore_breakpoints;
+ }
+
+ EvaluateExpressionOptions&
+ SetIgnoreBreakpoints (bool ignore = false)
+ {
+ m_ignore_breakpoints = ignore;
+ return *this;
+ }
+
+ bool
+ DoesKeepInMemory () const
+ {
+ return m_keep_in_memory;
+ }
+
+ EvaluateExpressionOptions&
+ SetKeepInMemory (bool keep = true)
+ {
+ m_keep_in_memory = keep;
+ return *this;
+ }
+
+ lldb::DynamicValueType
+ GetUseDynamic () const
+ {
+ return m_use_dynamic;
+ }
+
+ EvaluateExpressionOptions&
+ SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget)
+ {
+ m_use_dynamic = dynamic;
+ return *this;
+ }
+
+ uint32_t
+ GetTimeoutUsec () const
+ {
+ return m_timeout_usec;
+ }
+
+ EvaluateExpressionOptions&
+ SetTimeoutUsec (uint32_t timeout = 0)
+ {
+ m_timeout_usec = timeout;
+ return *this;
+ }
+
+ bool
+ GetRunOthers () const
+ {
+ return m_run_others;
+ }
+
+ EvaluateExpressionOptions&
+ SetRunOthers (bool run_others = true)
+ {
+ m_run_others = run_others;
+ return *this;
+ }
+
+private:
+ ExecutionPolicy m_execution_policy;
+ bool m_coerce_to_id;
+ bool m_unwind_on_error;
+ bool m_ignore_breakpoints;
+ bool m_keep_in_memory;
+ bool m_run_others;
+ lldb::DynamicValueType m_use_dynamic;
+ uint32_t m_timeout_usec;
+};
+
+//----------------------------------------------------------------------
+// Target
+//----------------------------------------------------------------------
+class Target :
+ public std::enable_shared_from_this<Target>,
+ public TargetProperties,
+ public Broadcaster,
+ public ExecutionContextScope,
+ public ModuleList::Notifier
+{
+public:
+ friend class TargetList;
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitBreakpointChanged = (1 << 0),
+ eBroadcastBitModulesLoaded = (1 << 1),
+ eBroadcastBitModulesUnloaded = (1 << 2),
+ eBroadcastBitWatchpointChanged = (1 << 3),
+ eBroadcastBitSymbolsLoaded = (1 << 4)
+ };
+
+ // These two functions fill out the Broadcaster interface:
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+ // This event data class is for use by the TargetList to broadcast new target notifications.
+ class TargetEventData : public EventData
+ {
+ public:
+
+ static const ConstString &
+ GetFlavorString ();
+
+ virtual const ConstString &
+ GetFlavor () const;
+
+ TargetEventData (const lldb::TargetSP &new_target_sp);
+
+ lldb::TargetSP &
+ GetTarget()
+ {
+ return m_target_sp;
+ }
+
+ virtual
+ ~TargetEventData();
+
+ virtual void
+ Dump (Stream *s) const;
+
+ static const lldb::TargetSP
+ GetTargetFromEvent (const lldb::EventSP &event_sp);
+
+ static const TargetEventData *
+ GetEventDataFromEvent (const Event *event_sp);
+
+ private:
+ lldb::TargetSP m_target_sp;
+
+ DISALLOW_COPY_AND_ASSIGN (TargetEventData);
+ };
+
+ static void
+ SettingsInitialize ();
+
+ static void
+ SettingsTerminate ();
+
+// static lldb::UserSettingsControllerSP &
+// GetSettingsController ();
+
+ static FileSpecList
+ GetDefaultExecutableSearchPaths ();
+
+ static FileSpecList
+ GetDefaultDebugFileSearchPaths ();
+
+ static ArchSpec
+ GetDefaultArchitecture ();
+
+ static void
+ SetDefaultArchitecture (const ArchSpec &arch);
+
+// void
+// UpdateInstanceName ();
+
+ lldb::ModuleSP
+ GetSharedModule (const ModuleSpec &module_spec,
+ Error *error_ptr = NULL);
+
+ //----------------------------------------------------------------------
+ // Settings accessors
+ //----------------------------------------------------------------------
+
+ static const TargetPropertiesSP &
+ GetGlobalProperties();
+
+
+private:
+ //------------------------------------------------------------------
+ /// Construct with optional file and arch.
+ ///
+ /// This member is private. Clients must use
+ /// TargetList::CreateTarget(const FileSpec*, const ArchSpec*)
+ /// so all targets can be tracked from the central target list.
+ ///
+ /// @see TargetList::CreateTarget(const FileSpec*, const ArchSpec*)
+ //------------------------------------------------------------------
+ Target (Debugger &debugger,
+ const ArchSpec &target_arch,
+ const lldb::PlatformSP &platform_sp);
+
+ // Helper function.
+ bool
+ ProcessIsValid ();
+
+public:
+ ~Target();
+
+ Mutex &
+ GetAPIMutex ()
+ {
+ return m_mutex;
+ }
+
+ void
+ DeleteCurrentProcess ();
+
+ void
+ CleanupProcess ();
+ //------------------------------------------------------------------
+ /// Dump a description of this object to a Stream.
+ ///
+ /// Dump a description of the contents of this object to the
+ /// supplied stream \a s. The dumped content will be only what has
+ /// been loaded or parsed up to this point at which this function
+ /// is called, so this is a good way to see what has been parsed
+ /// in a target.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the object descripton.
+ //------------------------------------------------------------------
+ void
+ Dump (Stream *s, lldb::DescriptionLevel description_level);
+
+ const lldb::ProcessSP &
+ CreateProcess (Listener &listener,
+ const char *plugin_name,
+ const FileSpec *crash_file);
+
+ const lldb::ProcessSP &
+ GetProcessSP () const;
+
+ bool
+ IsValid()
+ {
+ return m_valid;
+ }
+
+ void
+ Destroy();
+
+ //------------------------------------------------------------------
+ // This part handles the breakpoints.
+ //------------------------------------------------------------------
+
+ BreakpointList &
+ GetBreakpointList(bool internal = false);
+
+ const BreakpointList &
+ GetBreakpointList(bool internal = false) const;
+
+ lldb::BreakpointSP
+ GetLastCreatedBreakpoint ()
+ {
+ return m_last_created_breakpoint;
+ }
+
+ lldb::BreakpointSP
+ GetBreakpointByID (lldb::break_id_t break_id);
+
+ // Use this to create a file and line breakpoint to a given module or all module it is NULL
+ lldb::BreakpointSP
+ CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpec &file,
+ uint32_t line_no,
+ LazyBool check_inlines = eLazyBoolCalculate,
+ LazyBool skip_prologue = eLazyBoolCalculate,
+ bool internal = false);
+
+ // Use this to create breakpoint that matches regex against the source lines in files given in source_file_list:
+ lldb::BreakpointSP
+ CreateSourceRegexBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *source_file_list,
+ RegularExpression &source_regex,
+ bool internal = false);
+
+ // Use this to create a breakpoint from a load address
+ lldb::BreakpointSP
+ CreateBreakpoint (lldb::addr_t load_addr,
+ bool internal = false);
+
+ // Use this to create Address breakpoints:
+ lldb::BreakpointSP
+ CreateBreakpoint (Address &addr,
+ bool internal = false);
+
+ // Use this to create a function breakpoint by regexp in containingModule/containingSourceFiles, or all modules if it is NULL
+ // When "skip_prologue is set to eLazyBoolCalculate, we use the current target
+ // setting, else we use the values passed in
+ lldb::BreakpointSP
+ CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ RegularExpression &func_regexp,
+ LazyBool skip_prologue = eLazyBoolCalculate,
+ bool internal = false);
+
+ // Use this to create a function breakpoint by name in containingModule, or all modules if it is NULL
+ // When "skip_prologue is set to eLazyBoolCalculate, we use the current target
+ // setting, else we use the values passed in
+ lldb::BreakpointSP
+ CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const char *func_name,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue = eLazyBoolCalculate,
+ bool internal = false);
+
+ lldb::BreakpointSP
+ CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal = false);
+
+ // This is the same as the func_name breakpoint except that you can specify a vector of names. This is cheaper
+ // than a regular expression breakpoint in the case where you just want to set a breakpoint on a set of names
+ // you already know.
+ lldb::BreakpointSP
+ CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const char *func_names[],
+ size_t num_names,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue = eLazyBoolCalculate,
+ bool internal = false);
+
+ lldb::BreakpointSP
+ CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const std::vector<std::string> &func_names,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue = eLazyBoolCalculate,
+ bool internal = false);
+
+
+ // Use this to create a general breakpoint:
+ lldb::BreakpointSP
+ CreateBreakpoint (lldb::SearchFilterSP &filter_sp,
+ lldb::BreakpointResolverSP &resolver_sp,
+ bool internal = false);
+
+ // Use this to create a watchpoint:
+ lldb::WatchpointSP
+ CreateWatchpoint (lldb::addr_t addr,
+ size_t size,
+ const ClangASTType *type,
+ uint32_t kind,
+ Error &error);
+
+ lldb::WatchpointSP
+ GetLastCreatedWatchpoint ()
+ {
+ return m_last_created_watchpoint;
+ }
+
+ WatchpointList &
+ GetWatchpointList()
+ {
+ return m_watchpoint_list;
+ }
+
+ void
+ RemoveAllBreakpoints (bool internal_also = false);
+
+ void
+ DisableAllBreakpoints (bool internal_also = false);
+
+ void
+ EnableAllBreakpoints (bool internal_also = false);
+
+ bool
+ DisableBreakpointByID (lldb::break_id_t break_id);
+
+ bool
+ EnableBreakpointByID (lldb::break_id_t break_id);
+
+ bool
+ RemoveBreakpointByID (lldb::break_id_t break_id);
+
+ // The flag 'end_to_end', default to true, signifies that the operation is
+ // performed end to end, for both the debugger and the debuggee.
+
+ bool
+ RemoveAllWatchpoints (bool end_to_end = true);
+
+ bool
+ DisableAllWatchpoints (bool end_to_end = true);
+
+ bool
+ EnableAllWatchpoints (bool end_to_end = true);
+
+ bool
+ ClearAllWatchpointHitCounts ();
+
+ bool
+ IgnoreAllWatchpoints (uint32_t ignore_count);
+
+ bool
+ DisableWatchpointByID (lldb::watch_id_t watch_id);
+
+ bool
+ EnableWatchpointByID (lldb::watch_id_t watch_id);
+
+ bool
+ RemoveWatchpointByID (lldb::watch_id_t watch_id);
+
+ bool
+ IgnoreWatchpointByID (lldb::watch_id_t watch_id, uint32_t ignore_count);
+
+ //------------------------------------------------------------------
+ /// Get \a load_addr as a callable code load address for this target
+ ///
+ /// Take \a load_addr and potentially add any address bits that are
+ /// needed to make the address callable. For ARM this can set bit
+ /// zero (if it already isn't) if \a load_addr is a thumb function.
+ /// If \a addr_class is set to eAddressClassInvalid, then the address
+ /// adjustment will always happen. If it is set to an address class
+ /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be
+ /// returned.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetCallableLoadAddress (lldb::addr_t load_addr, lldb::AddressClass addr_class = lldb::eAddressClassInvalid) const;
+
+ //------------------------------------------------------------------
+ /// Get \a load_addr as an opcode for this target.
+ ///
+ /// Take \a load_addr and potentially strip any address bits that are
+ /// needed to make the address point to an opcode. For ARM this can
+ /// clear bit zero (if it already isn't) if \a load_addr is a
+ /// thumb function and load_addr is in code.
+ /// If \a addr_class is set to eAddressClassInvalid, then the address
+ /// adjustment will always happen. If it is set to an address class
+ /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be
+ /// returned.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ GetOpcodeLoadAddress (lldb::addr_t load_addr, lldb::AddressClass addr_class = lldb::eAddressClassInvalid) const;
+
+protected:
+ //------------------------------------------------------------------
+ /// Implementing of ModuleList::Notifier.
+ //------------------------------------------------------------------
+
+ virtual void
+ ModuleAdded (const ModuleList& module_list, const lldb::ModuleSP& module_sp);
+
+ virtual void
+ ModuleRemoved (const ModuleList& module_list, const lldb::ModuleSP& module_sp);
+
+ virtual void
+ ModuleUpdated (const ModuleList& module_list,
+ const lldb::ModuleSP& old_module_sp,
+ const lldb::ModuleSP& new_module_sp);
+ virtual void
+ WillClearList (const ModuleList& module_list);
+
+public:
+
+ void
+ ModulesDidLoad (ModuleList &module_list);
+
+ void
+ ModulesDidUnload (ModuleList &module_list);
+
+ void
+ SymbolsDidLoad (ModuleList &module_list);
+
+ //------------------------------------------------------------------
+ /// Gets the module for the main executable.
+ ///
+ /// Each process has a notion of a main executable that is the file
+ /// that will be executed or attached to. Executable files can have
+ /// dependent modules that are discovered from the object files, or
+ /// discovered at runtime as things are dynamically loaded.
+ ///
+ /// @return
+ /// The shared pointer to the executable module which can
+ /// contains a NULL Module object if no executable has been
+ /// set.
+ ///
+ /// @see DynamicLoader
+ /// @see ObjectFile::GetDependentModules (FileSpecList&)
+ /// @see Process::SetExecutableModule(lldb::ModuleSP&)
+ //------------------------------------------------------------------
+ lldb::ModuleSP
+ GetExecutableModule ();
+
+ Module*
+ GetExecutableModulePointer ();
+
+ //------------------------------------------------------------------
+ /// Set the main executable module.
+ ///
+ /// Each process has a notion of a main executable that is the file
+ /// that will be executed or attached to. Executable files can have
+ /// dependent modules that are discovered from the object files, or
+ /// discovered at runtime as things are dynamically loaded.
+ ///
+ /// Setting the executable causes any of the current dependant
+ /// image information to be cleared and replaced with the static
+ /// dependent image information found by calling
+ /// ObjectFile::GetDependentModules (FileSpecList&) on the main
+ /// executable and any modules on which it depends. Calling
+ /// Process::GetImages() will return the newly found images that
+ /// were obtained from all of the object files.
+ ///
+ /// @param[in] module_sp
+ /// A shared pointer reference to the module that will become
+ /// the main executable for this process.
+ ///
+ /// @param[in] get_dependent_files
+ /// If \b true then ask the object files to track down any
+ /// known dependent files.
+ ///
+ /// @see ObjectFile::GetDependentModules (FileSpecList&)
+ /// @see Process::GetImages()
+ //------------------------------------------------------------------
+ void
+ SetExecutableModule (lldb::ModuleSP& module_sp, bool get_dependent_files);
+
+ bool
+ LoadScriptingResources (std::list<Error>& errors,
+ Stream* feedback_stream = NULL,
+ bool continue_on_error = true)
+ {
+ return m_images.LoadScriptingResourcesInTarget(this,errors,feedback_stream,continue_on_error);
+ }
+
+ //------------------------------------------------------------------
+ /// Get accessor for the images for this process.
+ ///
+ /// Each process has a notion of a main executable that is the file
+ /// that will be executed or attached to. Executable files can have
+ /// dependent modules that are discovered from the object files, or
+ /// discovered at runtime as things are dynamically loaded. After
+ /// a main executable has been set, the images will contain a list
+ /// of all the files that the executable depends upon as far as the
+ /// object files know. These images will usually contain valid file
+ /// virtual addresses only. When the process is launched or attached
+ /// to, the DynamicLoader plug-in will discover where these images
+ /// were loaded in memory and will resolve the load virtual
+ /// addresses is each image, and also in images that are loaded by
+ /// code.
+ ///
+ /// @return
+ /// A list of Module objects in a module list.
+ //------------------------------------------------------------------
+ const ModuleList&
+ GetImages () const
+ {
+ return m_images;
+ }
+
+ ModuleList&
+ GetImages ()
+ {
+ return m_images;
+ }
+
+ //------------------------------------------------------------------
+ /// Return whether this FileSpec corresponds to a module that should be considered for general searches.
+ ///
+ /// This API will be consulted by the SearchFilterForNonModuleSpecificSearches
+ /// and any module that returns \b true will not be searched. Note the
+ /// SearchFilterForNonModuleSpecificSearches is the search filter that
+ /// gets used in the CreateBreakpoint calls when no modules is provided.
+ ///
+ /// The target call at present just consults the Platform's call of the
+ /// same name.
+ ///
+ /// @param[in] module_sp
+ /// A shared pointer reference to the module that checked.
+ ///
+ /// @return \b true if the module should be excluded, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_spec);
+
+ //------------------------------------------------------------------
+ /// Return whether this module should be considered for general searches.
+ ///
+ /// This API will be consulted by the SearchFilterForNonModuleSpecificSearches
+ /// and any module that returns \b true will not be searched. Note the
+ /// SearchFilterForNonModuleSpecificSearches is the search filter that
+ /// gets used in the CreateBreakpoint calls when no modules is provided.
+ ///
+ /// The target call at present just consults the Platform's call of the
+ /// same name.
+ ///
+ /// FIXME: When we get time we should add a way for the user to set modules that they
+ /// don't want searched, in addition to or instead of the platform ones.
+ ///
+ /// @param[in] module_sp
+ /// A shared pointer reference to the module that checked.
+ ///
+ /// @return \b true if the module should be excluded, \b false otherwise.
+ //------------------------------------------------------------------
+ bool
+ ModuleIsExcludedForNonModuleSpecificSearches (const lldb::ModuleSP &module_sp);
+
+ ArchSpec &
+ GetArchitecture ()
+ {
+ return m_arch;
+ }
+
+ const ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ //------------------------------------------------------------------
+ /// Set the architecture for this target.
+ ///
+ /// If the current target has no Images read in, then this just sets the architecture, which will
+ /// be used to select the architecture of the ExecutableModule when that is set.
+ /// If the current target has an ExecutableModule, then calling SetArchitecture with a different
+ /// architecture from the currently selected one will reset the ExecutableModule to that slice
+ /// of the file backing the ExecutableModule. If the file backing the ExecutableModule does not
+ /// contain a fork of this architecture, then this code will return false, and the architecture
+ /// won't be changed.
+ /// If the input arch_spec is the same as the already set architecture, this is a no-op.
+ ///
+ /// @param[in] arch_spec
+ /// The new architecture.
+ ///
+ /// @return
+ /// \b true if the architecture was successfully set, \bfalse otherwise.
+ //------------------------------------------------------------------
+ bool
+ SetArchitecture (const ArchSpec &arch_spec);
+
+ Debugger &
+ GetDebugger ()
+ {
+ return m_debugger;
+ }
+
+ size_t
+ ReadMemoryFromFileCache (const Address& addr,
+ void *dst,
+ size_t dst_len,
+ Error &error);
+
+ // Reading memory through the target allows us to skip going to the process
+ // for reading memory if possible and it allows us to try and read from
+ // any constant sections in our object files on disk. If you always want
+ // live program memory, read straight from the process. If you possibly
+ // want to read from const sections in object files, read from the target.
+ // This version of ReadMemory will try and read memory from the process
+ // if the process is alive. The order is:
+ // 1 - if (prefer_file_cache == true) then read from object file cache
+ // 2 - if there is a valid process, try and read from its memory
+ // 3 - if (prefer_file_cache == false) then read from object file cache
+ size_t
+ ReadMemory (const Address& addr,
+ bool prefer_file_cache,
+ void *dst,
+ size_t dst_len,
+ Error &error,
+ lldb::addr_t *load_addr_ptr = NULL);
+
+ size_t
+ ReadCStringFromMemory (const Address& addr, std::string &out_str, Error &error);
+
+ size_t
+ ReadCStringFromMemory (const Address& addr, char *dst, size_t dst_max_len, Error &result_error);
+
+ size_t
+ ReadScalarIntegerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ uint32_t byte_size,
+ bool is_signed,
+ Scalar &scalar,
+ Error &error);
+
+ uint64_t
+ ReadUnsignedIntegerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ size_t integer_byte_size,
+ uint64_t fail_value,
+ Error &error);
+
+ bool
+ ReadPointerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ Error &error,
+ Address &pointer_addr);
+
+ SectionLoadList&
+ GetSectionLoadList()
+ {
+ return m_section_load_list;
+ }
+
+ const SectionLoadList&
+ GetSectionLoadList() const
+ {
+ return m_section_load_list;
+ }
+
+ static Target *
+ GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr,
+ const SymbolContext *sc_ptr);
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual lldb::TargetSP
+ CalculateTarget ();
+
+ virtual lldb::ProcessSP
+ CalculateProcess ();
+
+ virtual lldb::ThreadSP
+ CalculateThread ();
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame ();
+
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx);
+
+ PathMappingList &
+ GetImageSearchPathList ();
+
+ ClangASTContext *
+ GetScratchClangASTContext(bool create_on_demand=true);
+
+ ClangASTImporter *
+ GetClangASTImporter();
+
+
+ // Since expressions results can persist beyond the lifetime of a process,
+ // and the const expression results are available after a process is gone,
+ // we provide a way for expressions to be evaluated from the Target itself.
+ // If an expression is going to be run, then it should have a frame filled
+ // in in th execution context.
+ ExecutionResults
+ EvaluateExpression (const char *expression,
+ StackFrame *frame,
+ lldb::ValueObjectSP &result_valobj_sp,
+ const EvaluateExpressionOptions& options = EvaluateExpressionOptions());
+
+ ClangPersistentVariables &
+ GetPersistentVariables()
+ {
+ return m_persistent_variables;
+ }
+
+ //------------------------------------------------------------------
+ // Target Stop Hooks
+ //------------------------------------------------------------------
+ class StopHook : public UserID
+ {
+ public:
+ ~StopHook ();
+
+ StopHook (const StopHook &rhs);
+
+ StringList *
+ GetCommandPointer ()
+ {
+ return &m_commands;
+ }
+
+ const StringList &
+ GetCommands()
+ {
+ return m_commands;
+ }
+
+ lldb::TargetSP &
+ GetTarget()
+ {
+ return m_target_sp;
+ }
+
+ void
+ SetCommands (StringList &in_commands)
+ {
+ m_commands = in_commands;
+ }
+
+ // Set the specifier. The stop hook will own the specifier, and is responsible for deleting it when we're done.
+ void
+ SetSpecifier (SymbolContextSpecifier *specifier)
+ {
+ m_specifier_sp.reset (specifier);
+ }
+
+ SymbolContextSpecifier *
+ GetSpecifier ()
+ {
+ return m_specifier_sp.get();
+ }
+
+ // Set the Thread Specifier. The stop hook will own the thread specifier, and is responsible for deleting it when we're done.
+ void
+ SetThreadSpecifier (ThreadSpec *specifier);
+
+ ThreadSpec *
+ GetThreadSpecifier()
+ {
+ return m_thread_spec_ap.get();
+ }
+
+ bool
+ IsActive()
+ {
+ return m_active;
+ }
+
+ void
+ SetIsActive (bool is_active)
+ {
+ m_active = is_active;
+ }
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+ private:
+ lldb::TargetSP m_target_sp;
+ StringList m_commands;
+ lldb::SymbolContextSpecifierSP m_specifier_sp;
+ std::unique_ptr<ThreadSpec> m_thread_spec_ap;
+ bool m_active;
+
+ // Use AddStopHook to make a new empty stop hook. The GetCommandPointer and fill it with commands,
+ // and SetSpecifier to set the specifier shared pointer (can be null, that will match anything.)
+ StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid);
+ friend class Target;
+ };
+ typedef std::shared_ptr<StopHook> StopHookSP;
+
+ // Add an empty stop hook to the Target's stop hook list, and returns a shared pointer to it in new_hook.
+ // Returns the id of the new hook.
+ lldb::user_id_t
+ AddStopHook (StopHookSP &new_hook);
+
+ void
+ RunStopHooks ();
+
+ size_t
+ GetStopHookSize();
+
+ bool
+ SetSuppresStopHooks (bool suppress)
+ {
+ bool old_value = m_suppress_stop_hooks;
+ m_suppress_stop_hooks = suppress;
+ return old_value;
+ }
+
+ bool
+ GetSuppressStopHooks ()
+ {
+ return m_suppress_stop_hooks;
+ }
+
+ bool
+ SetSuppressSyntheticValue (bool suppress)
+ {
+ bool old_value = m_suppress_synthetic_value;
+ m_suppress_synthetic_value = suppress;
+ return old_value;
+ }
+
+ bool
+ GetSuppressSyntheticValue ()
+ {
+ return m_suppress_synthetic_value;
+ }
+
+// StopHookSP &
+// GetStopHookByIndex (size_t index);
+//
+ bool
+ RemoveStopHookByID (lldb::user_id_t uid);
+
+ void
+ RemoveAllStopHooks ();
+
+ StopHookSP
+ GetStopHookByID (lldb::user_id_t uid);
+
+ bool
+ SetStopHookActiveStateByID (lldb::user_id_t uid, bool active_state);
+
+ void
+ SetAllStopHooksActiveState (bool active_state);
+
+ size_t GetNumStopHooks () const
+ {
+ return m_stop_hooks.size();
+ }
+
+ StopHookSP
+ GetStopHookAtIndex (size_t index)
+ {
+ if (index >= GetNumStopHooks())
+ return StopHookSP();
+ StopHookCollection::iterator pos = m_stop_hooks.begin();
+
+ while (index > 0)
+ {
+ pos++;
+ index--;
+ }
+ return (*pos).second;
+ }
+
+ lldb::PlatformSP
+ GetPlatform ()
+ {
+ return m_platform_sp;
+ }
+
+ void
+ SetPlatform (const lldb::PlatformSP &platform_sp)
+ {
+ m_platform_sp = platform_sp;
+ }
+
+ SourceManager &
+ GetSourceManager ();
+
+ //------------------------------------------------------------------
+ // Methods.
+ //------------------------------------------------------------------
+ lldb::SearchFilterSP
+ GetSearchFilterForModule (const FileSpec *containingModule);
+
+ lldb::SearchFilterSP
+ GetSearchFilterForModuleList (const FileSpecList *containingModuleList);
+
+ lldb::SearchFilterSP
+ GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, const FileSpecList *containingSourceFiles);
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ Debugger & m_debugger;
+ lldb::PlatformSP m_platform_sp; ///< The platform for this target.
+ Mutex m_mutex; ///< An API mutex that is used by the lldb::SB* classes make the SB interface thread safe
+ ArchSpec m_arch;
+ ModuleList m_images; ///< The list of images for this process (shared libraries and anything dynamically loaded).
+ SectionLoadList m_section_load_list;
+ BreakpointList m_breakpoint_list;
+ BreakpointList m_internal_breakpoint_list;
+ lldb::BreakpointSP m_last_created_breakpoint;
+ WatchpointList m_watchpoint_list;
+ lldb::WatchpointSP m_last_created_watchpoint;
+ // We want to tightly control the process destruction process so
+ // we can correctly tear down everything that we need to, so the only
+ // class that knows about the process lifespan is this target class.
+ lldb::ProcessSP m_process_sp;
+ bool m_valid;
+ lldb::SearchFilterSP m_search_filter_sp;
+ PathMappingList m_image_search_paths;
+ std::unique_ptr<ClangASTContext> m_scratch_ast_context_ap;
+ std::unique_ptr<ClangASTSource> m_scratch_ast_source_ap;
+ std::unique_ptr<ClangASTImporter> m_ast_importer_ap;
+ ClangPersistentVariables m_persistent_variables; ///< These are the persistent variables associated with this process for the expression parser.
+
+ std::unique_ptr<SourceManager> m_source_manager_ap;
+
+ typedef std::map<lldb::user_id_t, StopHookSP> StopHookCollection;
+ StopHookCollection m_stop_hooks;
+ lldb::user_id_t m_stop_hook_next_id;
+ bool m_suppress_stop_hooks;
+ bool m_suppress_synthetic_value;
+
+ static void
+ ImageSearchPathsChanged (const PathMappingList &path_list,
+ void *baton);
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (Target);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Target_h_
diff --git a/include/lldb/Target/TargetList.h b/include/lldb/Target/TargetList.h
new file mode 100644
index 000000000000..41404e11c7fa
--- /dev/null
+++ b/include/lldb/Target/TargetList.h
@@ -0,0 +1,239 @@
+//===-- TargetList.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_TargetList_h_
+#define liblldb_TargetList_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Target.h"
+
+namespace lldb_private {
+
+class TargetList : public Broadcaster
+{
+private:
+ friend class Debugger;
+
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// The constructor for the target list is private. Clients can
+ /// get ahold of of the one and only target list through the
+ /// lldb_private::Debugger::GetSharedInstance().GetTargetList().
+ ///
+ /// @see static TargetList& lldb_private::Debugger::GetTargetList().
+ //------------------------------------------------------------------
+ TargetList(Debugger &debugger);
+
+public:
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitInterrupt = (1 << 0)
+ };
+
+
+ // These two functions fill out the Broadcaster interface:
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+ virtual ~TargetList();
+
+ //------------------------------------------------------------------
+ /// Create a new Target.
+ ///
+ /// Clients must use this function to create a Target. This allows
+ /// a global list of targets to be maintained in a central location
+ /// so signal handlers and other global functions can use it to
+ /// locate an appropriate target to deliver asynchronous information
+ /// to.
+ ///
+ /// @param[in] debugger
+ /// The debugger to associate this target with
+ ///
+ /// @param[in] file_spec
+ /// The main executable file for a debug target. This value
+ /// can be NULL and the file can be set later using:
+ /// Target::SetExecutableModule (ModuleSP&)
+ ///
+ /// @param[in] triple_cstr
+ /// A target triple string to be used for the target. This can
+ /// be NULL if the triple is not known or when attaching to a
+ /// process.
+ ///
+ /// @param[in] get_dependent_modules
+ /// Track down the dependent modules for an executable and
+ /// load those into the module list.
+ ///
+ /// @param[in] platform_options
+ /// A pointer to the platform options to use when creating this
+ /// target. If this value is NULL, then the currently selected
+ /// platform will be used.
+ ///
+ /// @param[out] target_sp
+ /// A shared pointer to a target that will be filled in if
+ /// this call is successful.
+ ///
+ /// @return
+ /// An error object that indicates success or failure
+ //------------------------------------------------------------------
+ Error
+ CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const char *triple_cstr,
+ bool get_dependent_modules,
+ const OptionGroupPlatform *platform_options,
+ lldb::TargetSP &target_sp);
+
+ //------------------------------------------------------------------
+ /// Create a new Target.
+ ///
+ /// Same as the function above, but used when you already know the
+ /// platform you will be using
+ //------------------------------------------------------------------
+ Error
+ CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& arch,
+ bool get_dependent_modules,
+ lldb::PlatformSP &platform_sp,
+ lldb::TargetSP &target_sp);
+
+ //------------------------------------------------------------------
+ /// Delete a Target object from the list.
+ ///
+ /// When clients are done with the Target objets, this function
+ /// should be called to release the memory associated with a target
+ /// object.
+ ///
+ /// @param[in] target_sp
+ /// The shared pointer to a target.
+ ///
+ /// @return
+ /// Returns \b true if the target was successfully removed from
+ /// from this target list, \b false otherwise. The client will
+ /// be left with the last remaining shared pointer to the target
+ /// in \a target_sp which can then be properly released.
+ //------------------------------------------------------------------
+ bool
+ DeleteTarget (lldb::TargetSP &target_sp);
+
+ int
+ GetNumTargets () const;
+
+ lldb::TargetSP
+ GetTargetAtIndex (uint32_t index) const;
+
+ uint32_t
+ GetIndexOfTarget (lldb::TargetSP target_sp) const;
+
+ //------------------------------------------------------------------
+ /// Find the target that contains has an executable whose path
+ /// matches \a exe_file_spec, and whose architecture matches
+ /// \a arch_ptr if arch_ptr is not NULL.
+ ///
+ /// @param[in] exe_file_spec
+ /// A file spec containing a basename, or a full path (directory
+ /// and basename). If \a exe_file_spec contains only a filename
+ /// (empty GetDirectory() value) then matching will be done
+ /// solely based on the filenames and directories won't be
+ /// compared. If \a exe_file_spec contains a filename and a
+ /// directory, then both must match.
+ ///
+ /// @param[in] exe_arch_ptr
+ /// If not NULL then the architecture also needs to match, else
+ /// the architectures will be compared.
+ ///
+ /// @return
+ /// A shared pointer to a target object. The returned shared
+ /// pointer will contain NULL if no target objects have a
+ /// executable whose full or partial path matches
+ /// with a matching process ID.
+ //------------------------------------------------------------------
+ lldb::TargetSP
+ FindTargetWithExecutableAndArchitecture (const FileSpec &exe_file_spec,
+ const ArchSpec *exe_arch_ptr = NULL) const;
+
+ //------------------------------------------------------------------
+ /// Find the target that contains a process with process ID \a
+ /// pid.
+ ///
+ /// @param[in] pid
+ /// The process ID to search our target list for.
+ ///
+ /// @return
+ /// A shared pointer to a target object. The returned shared
+ /// pointer will contain NULL if no target objects own a process
+ /// with a matching process ID.
+ //------------------------------------------------------------------
+ lldb::TargetSP
+ FindTargetWithProcessID (lldb::pid_t pid) const;
+
+ lldb::TargetSP
+ FindTargetWithProcess (lldb_private::Process *process) const;
+
+ lldb::TargetSP
+ GetTargetSP (Target *target) const;
+
+ //------------------------------------------------------------------
+ /// Send an async interrupt to one or all processes.
+ ///
+ /// Find the target that contains the process with process ID \a
+ /// pid and send a LLDB_EVENT_ASYNC_INTERRUPT event to the process's
+ /// event queue.
+ ///
+ /// @param[in] pid
+ /// The process ID to search our target list for, if \a pid is
+ /// LLDB_INVALID_PROCESS_ID, then the interrupt will be sent to
+ /// all processes.
+ ///
+ /// @return
+ /// The number of async interrupts sent.
+ //------------------------------------------------------------------
+ uint32_t
+ SendAsyncInterrupt (lldb::pid_t pid = LLDB_INVALID_PROCESS_ID);
+
+ uint32_t
+ SignalIfRunning (lldb::pid_t pid, int signo);
+
+ uint32_t
+ SetSelectedTarget (Target *target);
+
+ lldb::TargetSP
+ GetSelectedTarget ();
+
+
+protected:
+ typedef std::vector<lldb::TargetSP> collection;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ collection m_target_list;
+ mutable Mutex m_target_list_mutex;
+ uint32_t m_selected_target_idx;
+private:
+ DISALLOW_COPY_AND_ASSIGN (TargetList);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_TargetList_h_
diff --git a/include/lldb/Target/Thread.h b/include/lldb/Target/Thread.h
new file mode 100644
index 000000000000..e4e532e4b331
--- /dev/null
+++ b/include/lldb/Target/Thread.h
@@ -0,0 +1,1067 @@
+//===-- Thread.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_Thread_h_
+#define liblldb_Thread_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrameList.h"
+
+#define LLDB_THREAD_MAX_STOP_EXC_DATA 8
+
+namespace lldb_private {
+
+class ThreadProperties : public Properties
+{
+public:
+ ThreadProperties(bool is_global);
+
+ virtual
+ ~ThreadProperties();
+
+ //------------------------------------------------------------------
+ /// The regular expression returned determines symbols that this
+ /// thread won't stop in during "step-in" operations.
+ ///
+ /// @return
+ /// A pointer to a regular expression to compare against symbols,
+ /// or NULL if all symbols are allowed.
+ ///
+ //------------------------------------------------------------------
+ const RegularExpression *
+ GetSymbolsToAvoidRegexp();
+
+ bool
+ GetTraceEnabledState() const;
+};
+
+typedef std::shared_ptr<ThreadProperties> ThreadPropertiesSP;
+
+class Thread :
+ public std::enable_shared_from_this<Thread>,
+ public ThreadProperties,
+ public UserID,
+ public ExecutionContextScope,
+ public Broadcaster
+{
+public:
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitStackChanged = (1 << 0),
+ eBroadcastBitThreadSuspended = (1 << 1),
+ eBroadcastBitThreadResumed = (1 << 2),
+ eBroadcastBitSelectedFrameChanged = (1 << 3),
+ eBroadcastBitThreadSelected = (1 << 4)
+ };
+
+ static ConstString &GetStaticBroadcasterClass ();
+
+ virtual ConstString &GetBroadcasterClass() const
+ {
+ return GetStaticBroadcasterClass();
+ }
+
+ class ThreadEventData :
+ public EventData
+ {
+ public:
+ ThreadEventData (const lldb::ThreadSP thread_sp);
+
+ ThreadEventData (const lldb::ThreadSP thread_sp, const StackID &stack_id);
+
+ ThreadEventData();
+
+ virtual ~ThreadEventData();
+
+ static const ConstString &
+ GetFlavorString ();
+
+ virtual const ConstString &
+ GetFlavor () const
+ {
+ return ThreadEventData::GetFlavorString ();
+ }
+
+ virtual void
+ Dump (Stream *s) const;
+
+ static const ThreadEventData *
+ GetEventDataFromEvent (const Event *event_ptr);
+
+ static lldb::ThreadSP
+ GetThreadFromEvent (const Event *event_ptr);
+
+ static StackID
+ GetStackIDFromEvent (const Event *event_ptr);
+
+ static lldb::StackFrameSP
+ GetStackFrameFromEvent (const Event *event_ptr);
+
+ lldb::ThreadSP
+ GetThread () const
+ {
+ return m_thread_sp;
+ }
+
+ StackID
+ GetStackID () const
+ {
+ return m_stack_id;
+ }
+
+ private:
+ lldb::ThreadSP m_thread_sp;
+ StackID m_stack_id;
+ DISALLOW_COPY_AND_ASSIGN (ThreadEventData);
+ };
+
+ // TODO: You shouldn't just checkpoint the register state alone, so this should get
+ // moved to protected. To do that ThreadStateCheckpoint needs to be returned as a token...
+ class RegisterCheckpoint
+ {
+ public:
+
+ RegisterCheckpoint() :
+ m_stack_id (),
+ m_data_sp ()
+ {
+ }
+
+ RegisterCheckpoint (const StackID &stack_id) :
+ m_stack_id (stack_id),
+ m_data_sp ()
+ {
+ }
+
+ ~RegisterCheckpoint()
+ {
+ }
+
+ const RegisterCheckpoint&
+ operator= (const RegisterCheckpoint &rhs)
+ {
+ if (this != &rhs)
+ {
+ this->m_stack_id = rhs.m_stack_id;
+ this->m_data_sp = rhs.m_data_sp;
+ }
+ return *this;
+ }
+
+ RegisterCheckpoint (const RegisterCheckpoint &rhs) :
+ m_stack_id (rhs.m_stack_id),
+ m_data_sp (rhs.m_data_sp)
+ {
+ }
+
+ const StackID &
+ GetStackID()
+ {
+ return m_stack_id;
+ }
+
+ void
+ SetStackID (const StackID &stack_id)
+ {
+ m_stack_id = stack_id;
+ }
+
+ lldb::DataBufferSP &
+ GetData()
+ {
+ return m_data_sp;
+ }
+
+ const lldb::DataBufferSP &
+ GetData() const
+ {
+ return m_data_sp;
+ }
+
+ protected:
+ StackID m_stack_id;
+ lldb::DataBufferSP m_data_sp;
+ };
+
+ struct ThreadStateCheckpoint
+ {
+ uint32_t orig_stop_id; // Dunno if I need this yet but it is an interesting bit of data.
+ lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you might continue with the wrong signals.
+ RegisterCheckpoint register_backup; // You need to restore the registers, of course...
+ uint32_t current_inlined_depth;
+ lldb::addr_t current_inlined_pc;
+ };
+
+ static void
+ SettingsInitialize ();
+
+ static void
+ SettingsTerminate ();
+
+ static const ThreadPropertiesSP &
+ GetGlobalProperties();
+
+ Thread (Process &process, lldb::tid_t tid);
+ virtual ~Thread();
+
+ lldb::ProcessSP
+ GetProcess() const
+ {
+ return m_process_wp.lock();
+ }
+
+ int
+ GetResumeSignal () const
+ {
+ return m_resume_signal;
+ }
+
+ void
+ SetResumeSignal (int signal)
+ {
+ m_resume_signal = signal;
+ }
+
+ lldb::StateType
+ GetState() const;
+
+ void
+ SetState (lldb::StateType state);
+
+ lldb::StateType
+ GetResumeState () const
+ {
+ return m_resume_state;
+ }
+
+ void
+ SetResumeState (lldb::StateType state)
+ {
+ m_resume_state = state;
+ }
+
+ // This function is called on all the threads before "ShouldResume" and
+ // "WillResume" in case a thread needs to change its state before the
+ // ThreadList polls all the threads to figure out which ones actually
+ // will get to run and how.
+ void
+ SetupForResume ();
+
+ // Do not override this function, it is for thread plan logic only
+ bool
+ ShouldResume (lldb::StateType resume_state);
+
+ // Override this to do platform specific tasks before resume.
+ virtual void
+ WillResume (lldb::StateType resume_state)
+ {
+ }
+
+ // This clears generic thread state after a resume. If you subclass this,
+ // be sure to call it.
+ virtual void
+ DidResume ();
+
+ // This notifies the thread when a private stop occurs.
+ virtual void
+ DidStop ();
+
+ virtual void
+ RefreshStateAfterStop() = 0;
+
+ void
+ WillStop ();
+
+ bool
+ ShouldStop (Event *event_ptr);
+
+ Vote
+ ShouldReportStop (Event *event_ptr);
+
+ Vote
+ ShouldReportRun (Event *event_ptr);
+
+ void
+ Flush ();
+
+ // Return whether this thread matches the specification in ThreadSpec. This is a virtual
+ // method because at some point we may extend the thread spec with a platform specific
+ // dictionary of attributes, which then only the platform specific Thread implementation
+ // would know how to match. For now, this just calls through to the ThreadSpec's
+ // ThreadPassesBasicTests method.
+ virtual bool
+ MatchesSpec (const ThreadSpec *spec);
+
+ lldb::StopInfoSP
+ GetStopInfo ();
+
+ lldb::StopReason
+ GetStopReason();
+
+ // This sets the stop reason to a "blank" stop reason, so you can call functions on the thread
+ // without having the called function run with whatever stop reason you stopped with.
+ void
+ SetStopInfoToNothing();
+
+ bool
+ ThreadStoppedForAReason ();
+
+ static const char *
+ RunModeAsCString (lldb::RunMode mode);
+
+ static const char *
+ StopReasonAsCString (lldb::StopReason reason);
+
+ virtual const char *
+ GetInfo ()
+ {
+ return NULL;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ return NULL;
+ }
+
+ virtual uint32_t
+ GetStackFrameCount()
+ {
+ return GetStackFrameList()->GetNumFrames();
+ }
+
+ virtual lldb::StackFrameSP
+ GetStackFrameAtIndex (uint32_t idx)
+ {
+ return GetStackFrameList()->GetFrameAtIndex(idx);
+ }
+
+ virtual lldb::StackFrameSP
+ GetFrameWithConcreteFrameIndex (uint32_t unwind_idx);
+
+ bool
+ DecrementCurrentInlinedDepth()
+ {
+ return GetStackFrameList()->DecrementCurrentInlinedDepth();
+ }
+
+ uint32_t
+ GetCurrentInlinedDepth()
+ {
+ return GetStackFrameList()->GetCurrentInlinedDepth();
+ }
+
+ Error
+ ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp, bool broadcast = false);
+
+ Error
+ ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp, bool broadcast = false);
+
+ virtual lldb::StackFrameSP
+ GetFrameWithStackID (const StackID &stack_id)
+ {
+ if (stack_id.IsValid())
+ return GetStackFrameList()->GetFrameWithStackID (stack_id);
+ return lldb::StackFrameSP();
+ }
+
+ uint32_t
+ GetSelectedFrameIndex ()
+ {
+ return GetStackFrameList()->GetSelectedFrameIndex();
+ }
+
+ lldb::StackFrameSP
+ GetSelectedFrame ()
+ {
+ lldb::StackFrameListSP stack_frame_list_sp(GetStackFrameList());
+ return stack_frame_list_sp->GetFrameAtIndex (stack_frame_list_sp->GetSelectedFrameIndex());
+ }
+
+ uint32_t
+ SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast = false);
+
+
+ bool
+ SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast = false);
+
+ bool
+ SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream);
+
+ void
+ SetDefaultFileAndLineToSelectedFrame()
+ {
+ GetStackFrameList()->SetDefaultFileAndLineToSelectedFrame();
+ }
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext () = 0;
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (StackFrame *frame) = 0;
+
+ virtual void
+ ClearStackFrames ();
+
+ virtual bool
+ SetBackingThread (const lldb::ThreadSP &thread_sp)
+ {
+ return false;
+ }
+
+ virtual lldb::ThreadSP
+ GetBackingThread () const
+ {
+ return lldb::ThreadSP();
+ }
+
+ virtual void
+ ClearBackingThread ()
+ {
+ // Subclasses can use this function if a thread is actually backed by
+ // another thread. This is currently used for the OperatingSystem plug-ins
+ // where they might have a thread that is in memory, yet its registers
+ // are available through the lldb_private::Thread subclass for the current
+ // lldb_private::Process class. Since each time the process stops the backing
+ // threads for memory threads can change, we need a way to clear the backing
+ // thread for all memory threads each time we stop.
+ }
+
+ void
+ DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx);
+
+ //------------------------------------------------------------------
+ // Thread Plan Providers:
+ // This section provides the basic thread plans that the Process control
+ // machinery uses to run the target. ThreadPlan.h provides more details on
+ // how this mechanism works.
+ // The thread provides accessors to a set of plans that perform basic operations.
+ // The idea is that particular Platform plugins can override these methods to
+ // provide the implementation of these basic operations appropriate to their
+ // environment.
+ //
+ // NB: All the QueueThreadPlanXXX providers return Shared Pointers to
+ // Thread plans. This is useful so that you can modify the plans after
+ // creation in ways specific to that plan type. Also, it is often necessary for
+ // ThreadPlans that utilize other ThreadPlans to implement their task to keep a shared
+ // pointer to the sub-plan.
+ // But besides that, the shared pointers should only be held onto by entities who live no longer
+ // than the thread containing the ThreadPlan.
+ // FIXME: If this becomes a problem, we can make a version that just returns a pointer,
+ // which it is clearly unsafe to hold onto, and a shared pointer version, and only allow
+ // ThreadPlan and Co. to use the latter. That is made more annoying to do because there's
+ // no elegant way to friend a method to all sub-classes of a given class.
+ //
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Queues the base plan for a thread.
+ /// The version returned by Process does some things that are useful,
+ /// like handle breakpoints and signals, so if you return a plugin specific
+ /// one you probably want to call through to the Process one for anything
+ /// your plugin doesn't explicitly handle.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueFundamentalPlan (bool abort_other_plans);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step over a breakpoint at the current PC of \a thread.
+ /// The default version returned by Process handles trap based breakpoints, and
+ /// will disable the breakpoint, single step over it, then re-enable it.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step one instruction from the current PC of \a thread.
+ ///
+ /// @param[in] step_over
+ /// \b true if we step over calls to functions, false if we step in.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepSingleInstruction (bool step_over,
+ bool abort_other_plans,
+ bool stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step through an address range, stepping over
+ /// function calls.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] type
+ /// Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
+ ///
+ /// @param[in] range
+ /// The address range to step through.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepOverRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// Queues the plan used to step through an address range, stepping into functions.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] type
+ /// Type of step to do, only eStepTypeInto and eStepTypeOver are supported by this plan.
+ ///
+ /// @param[in] range
+ /// The address range to step through.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] step_in_target
+ /// Name if function we are trying to step into. We will step out if we don't land in that function.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @param[in] avoid_code_without_debug_info
+ /// If \b true we will step out if we step into code with no debug info.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepInRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
+ lldb::RunMode stop_other_threads,
+ bool avoid_code_without_debug_info);
+
+ //------------------------------------------------------------------
+ /// Queue the plan used to step out of the function at the current PC of
+ /// \a thread.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] addr_context
+ /// When dealing with stepping through inlined functions the current PC is not enough information to know
+ /// what "step" means. For instance a series of nested inline functions might start at the same address.
+ // The \a addr_context provides the current symbol context the step
+ /// is supposed to be out of.
+ // FIXME: Currently unused.
+ ///
+ /// @param[in] first_insn
+ /// \b true if this is the first instruction of a function.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @param[in] stop_vote
+ /// @param[in] run_vote
+ /// See standard meanings for the stop & run votes in ThreadPlan.h.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepOut (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote, // = eVoteYes,
+ Vote run_vote, // = eVoteNoOpinion);
+ uint32_t frame_idx);
+
+ //------------------------------------------------------------------
+ /// Gets the plan used to step through the code that steps from a function
+ /// call site at the current PC into the actual function call.
+ ///
+ ///
+ /// @param[in] return_stack_id
+ /// The stack id that we will return to (by setting backstop breakpoints on the return
+ /// address to that frame) if we fail to step through.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepThrough (StackID &return_stack_id,
+ bool abort_other_plans,
+ bool stop_other_threads);
+
+ //------------------------------------------------------------------
+ /// Gets the plan used to continue from the current PC.
+ /// This is a simple plan, mostly useful as a backstop when you are continuing
+ /// for some particular purpose.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @param[in] target_addr
+ /// The address to which we're running.
+ ///
+ /// @param[in] stop_other_threads
+ /// \b true if we will stop other threads while we single step this one.
+ ///
+ /// @return
+ /// A shared pointer to the newly queued thread plan, or NULL if the plan could not be queued.
+ //------------------------------------------------------------------
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForRunToAddress (bool abort_other_plans,
+ Address &target_addr,
+ bool stop_other_threads);
+
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others,
+ uint32_t frame_idx);
+
+ virtual lldb::ThreadPlanSP
+ QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error = false,
+ bool ignore_breakpoints = true);
+
+ //------------------------------------------------------------------
+ // Thread Plan accessors:
+ //------------------------------------------------------------------
+
+ //------------------------------------------------------------------
+ /// Gets the plan which will execute next on the plan stack.
+ ///
+ /// @return
+ /// A pointer to the next executed plan.
+ //------------------------------------------------------------------
+ ThreadPlan *
+ GetCurrentPlan ();
+
+ //------------------------------------------------------------------
+ /// Unwinds the thread stack for the innermost expression plan currently
+ /// on the thread plan stack.
+ ///
+ /// @return
+ /// An error if the thread plan could not be unwound.
+ //------------------------------------------------------------------
+
+ Error
+ UnwindInnermostExpression();
+
+private:
+ bool
+ PlanIsBasePlan (ThreadPlan *plan_ptr);
+
+ void
+ BroadcastSelectedFrameChange(StackID &new_frame_id);
+
+public:
+
+ //------------------------------------------------------------------
+ /// Gets the outer-most plan that was popped off the plan stack in the
+ /// most recent stop. Useful for printing the stop reason accurately.
+ ///
+ /// @return
+ /// A pointer to the last completed plan.
+ //------------------------------------------------------------------
+ lldb::ThreadPlanSP
+ GetCompletedPlan ();
+
+ //------------------------------------------------------------------
+ /// Gets the outer-most return value from the completed plans
+ ///
+ /// @return
+ /// A ValueObjectSP, either empty if there is no return value,
+ /// or containing the return value.
+ //------------------------------------------------------------------
+ lldb::ValueObjectSP
+ GetReturnValueObject ();
+
+ //------------------------------------------------------------------
+ /// Checks whether the given plan is in the completed plans for this
+ /// stop.
+ ///
+ /// @param[in] plan
+ /// Pointer to the plan you're checking.
+ ///
+ /// @return
+ /// Returns true if the input plan is in the completed plan stack,
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool
+ IsThreadPlanDone (ThreadPlan *plan);
+
+ //------------------------------------------------------------------
+ /// Checks whether the given plan is in the discarded plans for this
+ /// stop.
+ ///
+ /// @param[in] plan
+ /// Pointer to the plan you're checking.
+ ///
+ /// @return
+ /// Returns true if the input plan is in the discarded plan stack,
+ /// false otherwise.
+ //------------------------------------------------------------------
+ bool
+ WasThreadPlanDiscarded (ThreadPlan *plan);
+
+ //------------------------------------------------------------------
+ /// Queues a generic thread plan.
+ ///
+ /// @param[in] plan_sp
+ /// The plan to queue.
+ ///
+ /// @param[in] abort_other_plans
+ /// \b true if we discard the currently queued plans and replace them with this one.
+ /// Otherwise this plan will go on the end of the plan stack.
+ ///
+ /// @return
+ /// A pointer to the last completed plan.
+ //------------------------------------------------------------------
+ void
+ QueueThreadPlan (lldb::ThreadPlanSP &plan_sp, bool abort_other_plans);
+
+
+ //------------------------------------------------------------------
+ /// Discards the plans queued on the plan stack of the current thread. This is
+ /// arbitrated by the "Master" ThreadPlans, using the "OkayToDiscard" call.
+ // But if \a force is true, all thread plans are discarded.
+ //------------------------------------------------------------------
+ void
+ DiscardThreadPlans (bool force);
+
+ //------------------------------------------------------------------
+ /// Discards the plans queued on the plan stack of the current thread up to and
+ /// including up_to_plan_sp.
+ //
+ // @param[in] up_to_plan_sp
+ // Discard all plans up to and including this one.
+ //------------------------------------------------------------------
+ void
+ DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp);
+
+ void
+ DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr);
+
+ //------------------------------------------------------------------
+ /// Prints the current plan stack.
+ ///
+ /// @param[in] s
+ /// The stream to which to dump the plan stack info.
+ ///
+ //------------------------------------------------------------------
+ void
+ DumpThreadPlans (Stream *s) const;
+
+ virtual bool
+ CheckpointThreadState (ThreadStateCheckpoint &saved_state);
+
+ virtual bool
+ RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state);
+
+ virtual bool
+ RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state);
+
+ void
+ EnableTracer (bool value, bool single_step);
+
+ void
+ SetTracer (lldb::ThreadPlanTracerSP &tracer_sp);
+
+ //------------------------------------------------------------------
+ // Get the thread index ID. The index ID that is guaranteed to not
+ // be re-used by a process. They start at 1 and increase with each
+ // new thread. This allows easy command line access by a unique ID
+ // that is easier to type than the actual system thread ID.
+ //------------------------------------------------------------------
+ uint32_t
+ GetIndexID () const;
+
+
+ //------------------------------------------------------------------
+ // The API ID is often the same as the Thread::GetID(), but not in
+ // all cases. Thread::GetID() is the user visible thread ID that
+ // clients would want to see. The API thread ID is the thread ID
+ // that is used when sending data to/from the debugging protocol.
+ //------------------------------------------------------------------
+ virtual lldb::user_id_t
+ GetProtocolID () const
+ {
+ return GetID();
+ }
+
+ //------------------------------------------------------------------
+ // lldb::ExecutionContextScope pure virtual functions
+ //------------------------------------------------------------------
+ virtual lldb::TargetSP
+ CalculateTarget ();
+
+ virtual lldb::ProcessSP
+ CalculateProcess ();
+
+ virtual lldb::ThreadSP
+ CalculateThread ();
+
+ virtual lldb::StackFrameSP
+ CalculateStackFrame ();
+
+ virtual void
+ CalculateExecutionContext (ExecutionContext &exe_ctx);
+
+ lldb::StackFrameSP
+ GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr);
+
+ size_t
+ GetStatus (Stream &strm,
+ uint32_t start_frame,
+ uint32_t num_frames,
+ uint32_t num_frames_with_source);
+
+ size_t
+ GetStackFrameStatus (Stream& strm,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source);
+
+ // We need a way to verify that even though we have a thread in a shared
+ // pointer that the object itself is still valid. Currently this won't be
+ // the case if DestroyThread() was called. DestroyThread is called when
+ // a thread has been removed from the Process' thread list.
+ bool
+ IsValid () const
+ {
+ return !m_destroy_called;
+ }
+
+ // Sets and returns a valid stop info based on the process stop ID and the
+ // current thread plan. If the thread stop ID does not match the process'
+ // stop ID, the private stop reason is not set and an invalid StopInfoSP may
+ // be returned.
+ //
+ // NOTE: This function must be called before the current thread plan is
+ // moved to the completed plan stack (in Thread::ShouldStop()).
+ //
+ // NOTE: If subclasses override this function, ensure they do not overwrite
+ // the m_actual_stop_info if it is valid. The stop info may be a
+ // "checkpointed and restored" stop info, so if it is still around it is
+ // right even if you have not calculated this yourself, or if it disagrees
+ // with what you might have calculated.
+ virtual lldb::StopInfoSP
+ GetPrivateStopInfo ();
+
+ //----------------------------------------------------------------------
+ // Ask the thread subclass to set its stop info.
+ //
+ // Thread subclasses should call Thread::SetStopInfo(...) with the
+ // reason the thread stopped.
+ //
+ // @return
+ // True if Thread::SetStopInfo(...) was called, false otherwise.
+ //----------------------------------------------------------------------
+ virtual bool
+ CalculateStopInfo () = 0;
+
+ //----------------------------------------------------------------------
+ // Gets the temporary resume state for a thread.
+ //
+ // This value gets set in each thread by complex debugger logic in
+ // Thread::ShouldResume() and an appropriate thread resume state will get
+ // set in each thread every time the process is resumed prior to calling
+ // Process::DoResume(). The lldb_private::Process subclass should adhere
+ // to the thread resume state request which will be one of:
+ //
+ // eStateRunning - thread will resume when process is resumed
+ // eStateStepping - thread should step 1 instruction and stop when process
+ // is resumed
+ // eStateSuspended - thread should not execute any instructions when
+ // process is resumed
+ //----------------------------------------------------------------------
+ lldb::StateType
+ GetTemporaryResumeState() const
+ {
+ return m_temporary_resume_state;
+ }
+
+ void
+ SetStopInfo (const lldb::StopInfoSP &stop_info_sp);
+
+ void
+ SetShouldReportStop (Vote vote);
+
+protected:
+
+ friend class ThreadPlan;
+ friend class ThreadList;
+ friend class ThreadEventData;
+ friend class StackFrameList;
+ friend class StackFrame;
+ friend class OperatingSystem;
+
+ // This is necessary to make sure thread assets get destroyed while the thread is still in good shape
+ // to call virtual thread methods. This must be called by classes that derive from Thread in their destructor.
+ virtual void DestroyThread ();
+
+ void
+ PushPlan (lldb::ThreadPlanSP &plan_sp);
+
+ void
+ PopPlan ();
+
+ void
+ DiscardPlan ();
+
+ ThreadPlan *GetPreviousPlan (ThreadPlan *plan);
+
+ typedef std::vector<lldb::ThreadPlanSP> plan_stack;
+
+ virtual bool
+ SaveFrameZeroState (RegisterCheckpoint &checkpoint);
+
+ virtual bool
+ RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint);
+
+ // register_data_sp must be a DataSP passed to ReadAllRegisterValues.
+ bool
+ ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp);
+
+ virtual lldb_private::Unwind *
+ GetUnwinder ();
+
+ // Check to see whether the thread is still at the last breakpoint hit that stopped it.
+ virtual bool
+ IsStillAtLastBreakpointHit();
+
+ // Some threads are threads that are made up by OperatingSystem plugins that
+ // are threads that exist and are context switched out into memory. The
+ // OperatingSystem plug-in need a ways to know if a thread is "real" or made
+ // up.
+ virtual bool
+ IsOperatingSystemPluginThread () const
+ {
+ return false;
+ }
+
+
+ lldb::StackFrameListSP
+ GetStackFrameList ();
+
+ struct ThreadState
+ {
+ uint32_t orig_stop_id;
+ lldb::StopInfoSP stop_info_sp;
+ RegisterCheckpoint register_backup;
+ };
+
+ //------------------------------------------------------------------
+ // Classes that inherit from Process can see and modify these
+ //------------------------------------------------------------------
+ lldb::ProcessWP m_process_wp; ///< The process that owns this thread.
+ lldb::StopInfoSP m_stop_info_sp; ///< The private stop reason for this thread
+ uint32_t m_stop_info_stop_id; // This is the stop id for which the StopInfo is valid. Can use this so you know that
+ // the thread's m_stop_info_sp is current and you don't have to fetch it again
+ const uint32_t m_index_id; ///< A unique 1 based index assigned to each thread for easy UI/command line access.
+ lldb::RegisterContextSP m_reg_context_sp; ///< The register context for this thread's current register state.
+ lldb::StateType m_state; ///< The state of our process.
+ mutable Mutex m_state_mutex; ///< Multithreaded protection for m_state.
+ plan_stack m_plan_stack; ///< The stack of plans this thread is executing.
+ plan_stack m_completed_plan_stack; ///< Plans that have been completed by this stop. They get deleted when the thread resumes.
+ plan_stack m_discarded_plan_stack; ///< Plans that have been discarded by this stop. They get deleted when the thread resumes.
+ mutable Mutex m_frame_mutex; ///< Multithreaded protection for m_state.
+ lldb::StackFrameListSP m_curr_frames_sp; ///< The stack frames that get lazily populated after a thread stops.
+ lldb::StackFrameListSP m_prev_frames_sp; ///< The previous stack frames from the last time this thread stopped.
+ int m_resume_signal; ///< The signal that should be used when continuing this thread.
+ lldb::StateType m_resume_state; ///< This state is used to force a thread to be suspended from outside the ThreadPlan logic.
+ lldb::StateType m_temporary_resume_state; ///< This state records what the thread was told to do by the thread plan logic for the current resume.
+ /// It gets set in Thread::ShoudResume.
+ std::unique_ptr<lldb_private::Unwind> m_unwinder_ap;
+ bool m_destroy_called; // This is used internally to make sure derived Thread classes call DestroyThread.
+ LazyBool m_override_should_notify;
+private:
+ //------------------------------------------------------------------
+ // For Thread only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (Thread);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Thread_h_
diff --git a/include/lldb/Target/ThreadList.h b/include/lldb/Target/ThreadList.h
new file mode 100644
index 000000000000..ddf49b002ecf
--- /dev/null
+++ b/include/lldb/Target/ThreadList.h
@@ -0,0 +1,163 @@
+//===-- ThreadList.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_ThreadList_h_
+#define liblldb_ThreadList_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+
+
+// FIXME: Currently this is a thread list with lots of functionality for use only by
+// the process for which this is the thread list. If we ever want a container class
+// to hand out that is just a random subset of threads, with iterator functionality,
+// then we should make that part a base class, and make a ProcessThreadList for the
+// process.
+namespace lldb_private {
+
+class ThreadList
+{
+friend class Process;
+
+public:
+
+ ThreadList (Process *process);
+
+ ThreadList (const ThreadList &rhs);
+
+ ~ThreadList ();
+
+ const ThreadList&
+ operator = (const ThreadList& rhs);
+
+ uint32_t
+ GetSize(bool can_update = true);
+
+ void
+ AddThread (const lldb::ThreadSP &thread_sp);
+
+ // Return the selected thread if there is one. Otherwise, return the thread
+ // selected at index 0.
+ lldb::ThreadSP
+ GetSelectedThread ();
+
+ bool
+ SetSelectedThreadByID (lldb::tid_t tid, bool notify = false);
+
+ bool
+ SetSelectedThreadByIndexID (uint32_t index_id, bool notify = false);
+
+ void
+ Clear();
+
+ void
+ Flush();
+
+ void
+ Destroy();
+
+ // Note that "idx" is not the same as the "thread_index". It is a zero
+ // based index to accessing the current threads, whereas "thread_index"
+ // is a unique index assigned
+ lldb::ThreadSP
+ GetThreadAtIndex (uint32_t idx, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ RemoveThreadByID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update = true);
+
+ lldb::ThreadSP
+ FindThreadByIndexID (uint32_t index_id, bool can_update = true);
+
+ lldb::ThreadSP
+ GetThreadSPForThreadPtr (Thread *thread_ptr);
+
+ bool
+ ShouldStop (Event *event_ptr);
+
+ Vote
+ ShouldReportStop (Event *event_ptr);
+
+ Vote
+ ShouldReportRun (Event *event_ptr);
+
+ void
+ RefreshStateAfterStop ();
+
+ //------------------------------------------------------------------
+ /// The thread list asks tells all the threads it is about to resume.
+ /// If a thread can "resume" without having to resume the target, it
+ /// will return false for WillResume, and then the process will not be
+ /// restarted.
+ ///
+ /// @return
+ /// \b true instructs the process to resume normally,
+ /// \b false means start & stopped events will be generated, but
+ /// the process will not actually run. The thread must then return
+ /// the correct StopInfo when asked.
+ ///
+ //------------------------------------------------------------------
+ bool
+ WillResume ();
+
+ void
+ DidResume ();
+
+ void
+ DidStop ();
+
+ void
+ DiscardThreadPlans();
+
+ uint32_t
+ GetStopID () const;
+
+ void
+ SetStopID (uint32_t stop_id);
+
+ Mutex &
+ GetMutex ();
+
+ void
+ Update (ThreadList &rhs);
+
+protected:
+
+ void
+ SetShouldReportStop (Vote vote);
+
+ void
+ NotifySelectedThreadChanged (lldb::tid_t tid);
+
+ typedef std::vector<lldb::ThreadSP> collection;
+ //------------------------------------------------------------------
+ // Classes that inherit from Process can see and modify these
+ //------------------------------------------------------------------
+ Process *m_process; ///< The process that manages this thread list.
+ uint32_t m_stop_id; ///< The process stop ID that this thread list is valid for.
+ collection m_threads; ///< The threads for this process.
+ lldb::tid_t m_selected_tid; ///< For targets that need the notion of a current thread.
+
+private:
+ ThreadList ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadList_h_
diff --git a/include/lldb/Target/ThreadPlan.h b/include/lldb/Target/ThreadPlan.h
new file mode 100644
index 000000000000..3c83fd1b9630
--- /dev/null
+++ b/include/lldb/Target/ThreadPlan.h
@@ -0,0 +1,658 @@
+//===-- ThreadPlan.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_ThreadPlan_h_
+#define liblldb_ThreadPlan_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/UserID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanTracer.h"
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+//------------------------------------------------------------------
+// ThreadPlan:
+// This is the pure virtual base class for thread plans.
+//
+// The thread plans provide the "atoms" of behavior that
+// all the logical process control, either directly from commands or through
+// more complex composite plans will rely on.
+//
+// Plan Stack:
+//
+// The thread maintaining a thread plan stack, and you program the actions of a particular thread
+// by pushing plans onto the plan stack.
+// There is always a "Current" plan, which is the head of the plan stack, though in some cases
+// a plan may defer to plans higher in the stack for some piece of information.
+//
+// The plan stack is never empty, there is always a Base Plan which persists through the life
+// of the running process.
+//
+//
+// Creating Plans:
+//
+// The thread plan is generally created and added to the plan stack through the QueueThreadPlanFor... API
+// in lldb::Thread. Those API's will return the plan that performs the named operation in a manner
+// appropriate for the current process. The plans in lldb/source/Target are generic
+// implementations, but a Process plugin can override them.
+//
+// ValidatePlan is then called. If it returns false, the plan is unshipped. This is a little
+// convenience which keeps us from having to error out of the constructor.
+//
+// Then the plan is added to the plan stack. When the plan is added to the plan stack its DidPush
+// will get called. This is useful if a plan wants to push any additional plans as it is constructed,
+// since you need to make sure you're already on the stack before you push additional plans.
+//
+// Completed Plans:
+//
+// When the target process stops the plans are queried, among other things, for whether their job is done.
+// If it is they are moved from the plan stack to the Completed Plan stack in reverse order from their position
+// on the plan stack (since multiple plans may be done at a given stop.) This is used primarily so that
+// the lldb::Thread::StopInfo for the thread can be set properly. If one plan pushes another to achieve part of
+// its job, but it doesn't want that sub-plan to be the one that sets the StopInfo, then call SetPrivate on the
+// sub-plan when you create it, and the Thread will pass over that plan in reporting the reason for the stop.
+//
+// Discarded plans:
+//
+// Your plan may also get discarded, i.e. moved from the plan stack to the "discarded plan stack". This can
+// happen, for instance, if the plan is calling a function and the function call crashes and you want
+// to unwind the attempt to call. So don't assume that your plan will always successfully stop. Which leads to:
+//
+// Cleaning up after your plans:
+//
+// When the plan is moved from the plan stack its WillPop method is always called, no matter why. Once it is
+// moved off the plan stack it is done, and won't get a chance to run again. So you should
+// undo anything that affects target state in this method. But be sure to leave the plan able to correctly
+// fill the StopInfo, however.
+// N.B. Don't wait to do clean up target state till the destructor, since that will usually get called when
+// the target resumes, and you want to leave the target state correct for new plans in the time between when
+// your plan gets unshipped and the next resume.
+//
+// Over the lifetime of the plan, various methods of the ThreadPlan are then called in response to changes of state in
+// the process we are debugging as follows:
+//
+// Resuming:
+//
+// When the target process is about to be restarted, the plan's WillResume method is called,
+// giving the plan a chance to prepare for the run. If WillResume returns false, then the
+// process is not restarted. Be sure to set an appropriate error value in the Process if
+// you have to do this. Note, ThreadPlans actually implement DoWillResume, WillResume wraps that call.
+//
+// Next the "StopOthers" method of all the threads are polled, and if one thread's Current plan
+// returns "true" then only that thread gets to run. If more than one returns "true" the threads that want to run solo
+// get run one by one round robin fashion. Otherwise all are let to run.
+//
+// Note, the way StopOthers is implemented, the base class implementation just asks the previous plan. So if your plan
+// has no opinion about whether it should run stopping others or not, just don't implement StopOthers, and the parent
+// will be asked.
+//
+// Finally, for each thread that is running, it run state is set to the return of RunState from the
+// thread's Current plan.
+//
+// Responding to a stop:
+//
+// When the target process stops, the plan is called in the following stages:
+//
+// First the thread asks the Current Plan if it can handle this stop by calling PlanExplainsStop.
+// If the Current plan answers "true" then it is asked if the stop should percolate all the way to the
+// user by calling the ShouldStop method. If the current plan doesn't explain the stop, then we query down
+// the plan stack for a plan that does explain the stop. The plan that does explain the stop then needs to
+// figure out what to do about the plans below it in the stack. If the stop is recoverable, then the plan that
+// understands it can just do what it needs to set up to restart, and then continue.
+// Otherwise, the plan that understood the stop should call DiscardPlanStack to clean up the stack below it.
+// Note, plans actually implement DoPlanExplainsStop, the result is cached in PlanExplainsStop so the DoPlanExplainsStop
+// itself will only get called once per stop.
+//
+// Master plans:
+//
+// In the normal case, when we decide to stop, we will collapse the plan stack up to the point of the plan that understood
+// the stop reason. However, if a plan wishes to stay on the stack after an event it didn't directly handle
+// it can designate itself a "Master" plan by responding true to IsMasterPlan, and then if it wants not to be
+// discarded, it can return true to OkayToDiscard, and it and all its dependent plans will be preserved when
+// we resume execution.
+//
+// The other effect of being a master plan is that when the Master plan is done , if it has set "OkayToDiscard" to false,
+// then it will be popped & execution will stop and return to the user. Remember that if OkayToDiscard is false, the
+// plan will be popped and control will be given to the next plan above it on the stack So setting OkayToDiscard to
+// false means the user will regain control when the MasterPlan is completed.
+//
+// Between these two controls this allows things like: a MasterPlan/DontDiscard Step Over to hit a breakpoint, stop and
+// return control to the user, but then when the user continues, the step out succeeds.
+// Even more tricky, when the breakpoint is hit, the user can continue to step in/step over/etc, and finally when they
+// continue, they will finish up the Step Over.
+//
+// FIXME: MasterPlan & OkayToDiscard aren't really orthogonal. MasterPlan designation means that this plan controls
+// it's fate and the fate of plans below it. OkayToDiscard tells whether the MasterPlan wants to stay on the stack. I
+// originally thought "MasterPlan-ness" would need to be a fixed characteristic of a ThreadPlan, in which case you needed
+// the extra control. But that doesn't seem to be true. So we should be able to convert to only MasterPlan status to mean
+// the current "MasterPlan/DontDiscard". Then no plans would be MasterPlans by default, and you would set the ones you
+// wanted to be "user level" in this way.
+//
+//
+// Actually Stopping:
+//
+// If a plan says responds "true" to ShouldStop, then it is asked if it's job is complete by calling
+// MischiefManaged. If that returns true, the thread is popped from the plan stack and added to the
+// Completed Plan Stack. Then the next plan in the stack is asked if it ShouldStop, and it returns "true",
+// it is asked if it is done, and if yes popped, and so on till we reach a plan that is not done.
+//
+// Since you often know in the ShouldStop method whether your plan is complete, as a convenience you can call
+// SetPlanComplete and the ThreadPlan implementation of MischiefManaged will return "true", without your having
+// to redo the calculation when your sub-classes MischiefManaged is called. If you call SetPlanComplete, you can
+// later use IsPlanComplete to determine whether the plan is complete. This is only a convenience for sub-classes,
+// the logic in lldb::Thread will only call MischiefManaged.
+//
+// One slightly tricky point is you have to be careful using SetPlanComplete in PlanExplainsStop because you
+// are not guaranteed that PlanExplainsStop for a plan will get called before ShouldStop gets called. If your sub-plan
+// explained the stop and then popped itself, only your ShouldStop will get called.
+//
+// If ShouldStop for any thread returns "true", then the WillStop method of the Current plan of
+// all threads will be called, the stop event is placed on the Process's public broadcaster, and
+// control returns to the upper layers of the debugger.
+//
+// Reporting the stop:
+//
+// When the process stops, the thread is given a StopReason, in the form of a StopInfo object. If there is a completed
+// plan corresponding to the stop, then the "actual" stop reason will be suppressed, and instead a StopInfoThreadPlan
+// object will be cons'ed up from the highest completed plan in the stack. However, if the plan doesn't want to be
+// the stop reason, then it can call SetPlanComplete and pass in "false" for the "success" parameter. In that case,
+// the real stop reason will be used instead. One exapmle of this is the "StepRangeStepIn" thread plan. If it stops
+// because of a crash or breakpoint hit, it wants to unship itself, because it isn't so useful to have step in keep going
+// after a breakpoint hit. But it can't be the reason for the stop or no-one would see that they had hit a breakpoint.
+//
+// Cleaning up the plan stack:
+//
+// One of the complications of MasterPlans is that you may get past the limits of a plan without triggering it to clean
+// itself up. For instance, if you are doing a MasterPlan StepOver, and hit a breakpoint in a called function, then
+// step over enough times to step out of the initial StepOver range, each of the step overs will explain the stop &
+// take themselves off the stack, but control would never be returned to the original StepOver. Eventually, the user
+// will continue, and when that continue stops, the old stale StepOver plan that was left on the stack will get woken
+// up and notice it is done. But that can leave junk on the stack for a while. To avoid that, the plans implement a
+// "IsPlanStale" method, that can check whether it is relevant anymore. On stop, after the regular plan negotiation,
+// the remaining plan stack is consulted and if any plan says it is stale, it and the plans below it are discarded from
+// the stack.
+//
+// Automatically Resuming:
+//
+// If ShouldStop for all threads returns "false", then the target process will resume. This then cycles back to
+// Resuming above.
+//
+// Reporting eStateStopped events when the target is restarted:
+//
+// If a plan decides to auto-continue the target by returning "false" from ShouldStop, then it will be asked
+// whether the Stopped event should still be reported. For instance, if you hit a breakpoint that is a User set
+// breakpoint, but the breakpoint callback said to continue the target process, you might still want to inform
+// the upper layers of lldb that the stop had happened.
+// The way this works is every thread gets to vote on whether to report the stop. If all votes are eVoteNoOpinion,
+// then the thread list will decide what to do (at present it will pretty much always suppress these stopped events.)
+// If there is an eVoteYes, then the event will be reported regardless of the other votes. If there is an eVoteNo
+// and no eVoteYes's, then the event won't be reported.
+//
+// One other little detail here, sometimes a plan will push another plan onto the plan stack to do some part of
+// the first plan's job, and it would be convenient to tell that plan how it should respond to ShouldReportStop.
+// You can do that by setting the stop_vote in the child plan when you create it.
+//
+// Suppressing the initial eStateRunning event:
+//
+// The private process running thread will take care of ensuring that only one "eStateRunning" event will be
+// delivered to the public Process broadcaster per public eStateStopped event. However there are some cases
+// where the public state of this process is eStateStopped, but a thread plan needs to restart the target, but
+// doesn't want the running event to be publically broadcast. The obvious example of this is running functions
+// by hand as part of expression evaluation. To suppress the running event return eVoteNo from ShouldReportStop,
+// to force a running event to be reported return eVoteYes, in general though you should return eVoteNoOpinion
+// which will allow the ThreadList to figure out the right thing to do.
+// The run_vote argument to the constructor works like stop_vote, and is a way for a plan to instruct a sub-plan
+// on how to respond to ShouldReportStop.
+//
+//------------------------------------------------------------------
+
+class ThreadPlan :
+ public UserID
+{
+public:
+ typedef enum
+ {
+ eAllThreads,
+ eSomeThreads,
+ eThisThread
+ } ThreadScope;
+
+ // We use these enums so that we can cast a base thread plan to it's real type without having to resort
+ // to dynamic casting.
+ typedef enum
+ {
+ eKindGeneric,
+ eKindNull,
+ eKindBase,
+ eKindCallFunction,
+ eKindStepInstruction,
+ eKindStepOut,
+ eKindStepOverBreakpoint,
+ eKindStepOverRange,
+ eKindStepInRange,
+ eKindRunToAddress,
+ eKindStepThrough,
+ eKindStepUntil,
+ eKindTestCondition
+
+ } ThreadPlanKind;
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadPlan (ThreadPlanKind kind,
+ const char *name,
+ Thread &thread,
+ Vote stop_vote,
+ Vote run_vote);
+
+ virtual
+ ~ThreadPlan();
+
+ //------------------------------------------------------------------
+ /// Returns the name of this thread plan.
+ ///
+ /// @return
+ /// A const char * pointer to the thread plan's name.
+ //------------------------------------------------------------------
+ const char *
+ GetName () const
+ {
+ return m_name.c_str();
+ }
+
+ //------------------------------------------------------------------
+ /// Returns the Thread that is using this thread plan.
+ ///
+ /// @return
+ /// A pointer to the thread plan's owning thread.
+ //------------------------------------------------------------------
+ Thread &
+ GetThread()
+ {
+ return m_thread;
+ }
+
+ const Thread &
+ GetThread() const
+ {
+ return m_thread;
+ }
+
+ Target &
+ GetTarget()
+ {
+ return m_thread.GetProcess()->GetTarget();
+ }
+
+ const Target &
+ GetTarget() const
+ {
+ return m_thread.GetProcess()->GetTarget();
+ }
+
+ //------------------------------------------------------------------
+ /// Print a description of this thread to the stream \a s.
+ /// \a thread.
+ ///
+ /// @param[in] s
+ /// The stream to which to print the description.
+ ///
+ /// @param[in] level
+ /// The level of description desired. Note that eDescriptionLevelBrief
+ /// will be used in the stop message printed when the plan is complete.
+ //------------------------------------------------------------------
+ virtual void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level) = 0;
+
+ //------------------------------------------------------------------
+ /// Returns whether this plan could be successfully created.
+ ///
+ /// @param[in] error
+ /// A stream to which to print some reason why the plan could not be created.
+ /// Can be NULL.
+ ///
+ /// @return
+ /// \b true if the plan should be queued, \b false otherwise.
+ //------------------------------------------------------------------
+ virtual bool
+ ValidatePlan (Stream *error) = 0;
+
+ bool
+ TracerExplainsStop ()
+ {
+ if (!m_tracer_sp)
+ return false;
+ else
+ return m_tracer_sp->TracerExplainsStop();
+ }
+
+
+ lldb::StateType
+ RunState ();
+
+ bool
+ PlanExplainsStop (Event *event_ptr);
+
+ virtual bool
+ ShouldStop (Event *event_ptr) = 0;
+
+ virtual bool
+ ShouldAutoContinue (Event *event_ptr)
+ {
+ return false;
+ }
+
+ // Whether a "stop class" event should be reported to the "outside world". In general
+ // if a thread plan is active, events should not be reported.
+
+ virtual Vote
+ ShouldReportStop (Event *event_ptr);
+
+ virtual Vote
+ ShouldReportRun (Event *event_ptr);
+
+ virtual void
+ SetStopOthers (bool new_value);
+
+ virtual bool
+ StopOthers ();
+
+ // This is the wrapper for DoWillResume that does generic ThreadPlan logic, then
+ // calls DoWillResume.
+ bool
+ WillResume (lldb::StateType resume_state, bool current_plan);
+
+ virtual bool
+ WillStop () = 0;
+
+ bool
+ IsMasterPlan()
+ {
+ return m_is_master_plan;
+ }
+
+ bool
+ SetIsMasterPlan (bool value)
+ {
+ bool old_value = m_is_master_plan;
+ m_is_master_plan = value;
+ return old_value;
+ }
+
+ virtual bool
+ OkayToDiscard();
+
+ void
+ SetOkayToDiscard (bool value)
+ {
+ m_okay_to_discard = value;
+ }
+
+ // The base class MischiefManaged does some cleanup - so you have to call it
+ // in your MischiefManaged derived class.
+ virtual bool
+ MischiefManaged ();
+
+ virtual void
+ ThreadDestroyed ()
+ {
+ // Any cleanup that a plan might want to do in case the thread goes away
+ // in the middle of the plan being queued on a thread can be done here.
+ }
+
+ bool
+ GetPrivate ()
+ {
+ return m_plan_private;
+ }
+
+ void
+ SetPrivate (bool input)
+ {
+ m_plan_private = input;
+ }
+
+ virtual void
+ DidPush();
+
+ virtual void
+ WillPop();
+
+ // This pushes a plan onto the plan stack of the current plan's thread.
+ void
+ PushPlan (lldb::ThreadPlanSP &thread_plan_sp)
+ {
+ m_thread.PushPlan (thread_plan_sp);
+ }
+
+ ThreadPlanKind GetKind() const
+ {
+ return m_kind;
+ }
+
+ bool
+ IsPlanComplete();
+
+ void
+ SetPlanComplete (bool success = true);
+
+ virtual bool
+ IsPlanStale ()
+ {
+ return false;
+ }
+
+ bool
+ PlanSucceeded ()
+ {
+ return m_plan_succeeded;
+ }
+
+ virtual bool
+ IsBasePlan()
+ {
+ return false;
+ }
+
+ lldb::ThreadPlanTracerSP &
+ GetThreadPlanTracer()
+ {
+ return m_tracer_sp;
+ }
+
+ void
+ SetThreadPlanTracer (lldb::ThreadPlanTracerSP new_tracer_sp)
+ {
+ m_tracer_sp = new_tracer_sp;
+ }
+
+ void
+ DoTraceLog ()
+ {
+ if (m_tracer_sp && m_tracer_sp->TracingEnabled())
+ m_tracer_sp->Log();
+ }
+
+ // Some thread plans hide away the actual stop info which caused any particular stop. For
+ // instance the ThreadPlanCallFunction restores the original stop reason so that stopping and
+ // calling a few functions won't lose the history of the run.
+ // This call can be implemented to get you back to the real stop info.
+ virtual lldb::StopInfoSP
+ GetRealStopInfo ()
+ {
+ return m_thread.GetStopInfo ();
+ }
+
+ virtual lldb::ValueObjectSP
+ GetReturnValueObject ()
+ {
+ return lldb::ValueObjectSP();
+ }
+
+ // If a thread plan stores the state before it was run, then you might
+ // want to restore the state when it is done. This will do that job.
+ // This is mostly useful for artificial plans like CallFunction plans.
+
+ virtual bool
+ RestoreThreadState()
+ {
+ // Nothing to do in general.
+ return true;
+ }
+
+ virtual bool
+ IsVirtualStep()
+ {
+ return false;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from ThreadPlan can see and modify these
+ //------------------------------------------------------------------
+
+ virtual bool
+ DoWillResume (lldb::StateType resume_state, bool current_plan) { return true; };
+
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr) = 0;
+
+ // This gets the previous plan to the current plan (for forwarding requests).
+ // This is mostly a formal requirement, it allows us to make the Thread's
+ // GetPreviousPlan protected, but only friend ThreadPlan to thread.
+
+ ThreadPlan *
+ GetPreviousPlan ()
+ {
+ return m_thread.GetPreviousPlan (this);
+ }
+
+ // This forwards the private Thread::GetPrivateStopInfo which is generally what
+ // ThreadPlan's need to know.
+
+ lldb::StopInfoSP
+ GetPrivateStopInfo()
+ {
+ return m_thread.GetPrivateStopInfo ();
+ }
+
+ void
+ SetStopInfo (lldb::StopInfoSP stop_reason_sp)
+ {
+ m_thread.SetStopInfo (stop_reason_sp);
+ }
+
+ void
+ CachePlanExplainsStop (bool does_explain)
+ {
+ m_cached_plan_explains_stop = does_explain ? eLazyBoolYes : eLazyBoolNo;
+ }
+
+ LazyBool
+ GetCachedPlanExplainsStop () const
+ {
+ return m_cached_plan_explains_stop;
+ }
+
+ virtual lldb::StateType
+ GetPlanRunState () = 0;
+
+ Thread &m_thread;
+ Vote m_stop_vote;
+ Vote m_run_vote;
+
+private:
+ //------------------------------------------------------------------
+ // For ThreadPlan only
+ //------------------------------------------------------------------
+ static lldb::user_id_t GetNextID ();
+
+ ThreadPlanKind m_kind;
+ std::string m_name;
+ Mutex m_plan_complete_mutex;
+ LazyBool m_cached_plan_explains_stop;
+ bool m_plan_complete;
+ bool m_plan_private;
+ bool m_okay_to_discard;
+ bool m_is_master_plan;
+ bool m_plan_succeeded;
+
+ lldb::ThreadPlanTracerSP m_tracer_sp;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(ThreadPlan);
+};
+
+//----------------------------------------------------------------------
+// ThreadPlanNull:
+// Threads are assumed to always have at least one plan on the plan stack.
+// This is put on the plan stack when a thread is destroyed so that if you
+// accidentally access a thread after it is destroyed you won't crash.
+// But asking questions of the ThreadPlanNull is definitely an error.
+//----------------------------------------------------------------------
+
+class ThreadPlanNull : public ThreadPlan
+{
+public:
+ ThreadPlanNull (Thread &thread);
+ virtual ~ThreadPlanNull ();
+
+ virtual void
+ GetDescription (Stream *s,
+ lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual bool
+ MischiefManaged ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ IsBasePlan()
+ {
+ return true;
+ }
+
+ virtual bool
+ OkayToDiscard ()
+ {
+ return false;
+ }
+
+protected:
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr);
+
+ virtual lldb::StateType
+ GetPlanRunState ();
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlan_h_
diff --git a/include/lldb/Target/ThreadPlanBase.h b/include/lldb/Target/ThreadPlanBase.h
new file mode 100644
index 000000000000..69959e12f848
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanBase.h
@@ -0,0 +1,71 @@
+//===-- ThreadPlanBase.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_ThreadPlanFundamental_h_
+#define liblldb_ThreadPlanFundamental_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+
+//------------------------------------------------------------------
+// Base thread plans:
+// This is the generic version of the bottom most plan on the plan stack. It should
+// be able to handle generic breakpoint hitting, and signals and exceptions.
+//------------------------------------------------------------------
+
+class ThreadPlanBase : public ThreadPlan
+{
+friend class Process; // RunThreadPlan manages "stopper" base plans.
+public:
+ virtual ~ThreadPlanBase ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual Vote ShouldReportStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+ virtual bool OkayToDiscard()
+ {
+ return false;
+ }
+
+ virtual bool
+ IsBasePlan()
+ {
+ return true;
+ }
+
+protected:
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+ ThreadPlanBase (Thread &thread);
+
+private:
+ friend lldb::ThreadPlanSP
+ Thread::QueueFundamentalPlan(bool abort_other_plans);
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanBase);
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanFundamental_h_
diff --git a/include/lldb/Target/ThreadPlanCallFunction.h b/include/lldb/Target/ThreadPlanCallFunction.h
new file mode 100644
index 000000000000..d747706c6393
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanCallFunction.h
@@ -0,0 +1,193 @@
+//===-- ThreadPlanCallFunction.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_ThreadPlanCallFunction_h_
+#define liblldb_ThreadPlanCallFunction_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanCallFunction : public ThreadPlan
+{
+ // Create a thread plan to call a function at the address passed in the "function"
+ // argument. If you plan to call GetReturnValueObject, then pass in the
+ // return type, otherwise just pass in an invalid ClangASTType.
+public:
+ ThreadPlanCallFunction (Thread &thread,
+ const Address &function,
+ const ClangASTType &return_type,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error = true,
+ bool ignore_breakpoints = false,
+ lldb::addr_t *this_arg = 0,
+ lldb::addr_t *cmd_arg = 0);
+
+ ThreadPlanCallFunction (Thread &thread,
+ const Address &function,
+ const ClangASTType &return_type,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL);
+
+ virtual
+ ~ThreadPlanCallFunction ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual Vote
+ ShouldReportStop(Event *event_ptr);
+
+ virtual bool
+ StopOthers ();
+
+ virtual void
+ SetStopOthers (bool new_value);
+
+ virtual lldb::StateType
+ GetPlanRunState ();
+
+ virtual void
+ DidPush ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ MischiefManaged ();
+
+ // To get the return value from a function call you must create a
+ // lldb::ValueSP that contains a valid clang type in its context and call
+ // RequestReturnValue. The ValueSP will be stored and when the function is
+ // done executing, the object will check if there is a requested return
+ // value. If there is, the return value will be retrieved using the
+ // ABI::GetReturnValue() for the ABI in the process. Then after the thread
+ // plan is complete, you can call "GetReturnValue()" to retrieve the value
+ // that was extracted.
+
+ virtual lldb::ValueObjectSP
+ GetReturnValueObject ()
+ {
+ return m_return_valobj_sp;
+ }
+
+ // Return the stack pointer that the function received
+ // on entry. Any stack address below this should be
+ // considered invalid after the function has been
+ // cleaned up.
+ lldb::addr_t
+ GetFunctionStackPointer()
+ {
+ return m_function_sp;
+ }
+
+ // Classes that derive from ClangFunction, and implement
+ // their own WillPop methods should call this so that the
+ // thread state gets restored if the plan gets discarded.
+ virtual void
+ WillPop ();
+
+ // If the thread plan stops mid-course, this will be the stop reason that interrupted us.
+ // Once DoTakedown is called, this will be the real stop reason at the end of the function call.
+ // If it hasn't been set for one or the other of these reasons, we'll return the PrivateStopReason.
+ // This is needed because we want the CallFunction thread plans not to show up as the stop reason.
+ // But if something bad goes wrong, it is nice to be able to tell the user what really happened.
+
+ virtual lldb::StopInfoSP
+ GetRealStopInfo()
+ {
+ if (m_real_stop_info_sp)
+ return m_real_stop_info_sp;
+ else
+ return GetPrivateStopInfo ();
+ }
+
+ lldb::addr_t
+ GetStopAddress ()
+ {
+ return m_stop_address;
+ }
+
+ virtual bool
+ RestoreThreadState();
+
+protected:
+ void ReportRegisterState (const char *message);
+
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr);
+
+private:
+
+ bool
+ ConstructorSetup (Thread &thread,
+ ABI *& abi,
+ lldb::addr_t &start_load_addr,
+ lldb::addr_t &function_load_addr);
+
+ void
+ DoTakedown (bool success);
+
+ void
+ SetBreakpoints ();
+
+ void
+ ClearBreakpoints ();
+
+ bool
+ BreakpointsExplainStop ();
+
+ bool m_valid;
+ bool m_stop_other_threads;
+ Address m_function_addr;
+ Address m_start_addr;
+ lldb::addr_t m_function_sp;
+ Thread::RegisterCheckpoint m_register_backup;
+ lldb::ThreadPlanSP m_subplan_sp;
+ LanguageRuntime *m_cxx_language_runtime;
+ LanguageRuntime *m_objc_language_runtime;
+ Thread::ThreadStateCheckpoint m_stored_thread_state;
+ lldb::StopInfoSP m_real_stop_info_sp; // In general we want to hide call function
+ // thread plans, but for reporting purposes,
+ // it's nice to know the real stop reason.
+ // This gets set in DoTakedown.
+ StreamString m_constructor_errors;
+ ClangASTType m_return_type;
+ lldb::ValueObjectSP m_return_valobj_sp; // If this contains a valid pointer, use the ABI to extract values when complete
+ bool m_takedown_done; // We want to ensure we only do the takedown once. This ensures that.
+ lldb::addr_t m_stop_address; // This is the address we stopped at. Also set in DoTakedown;
+ bool m_unwind_on_error;
+ bool m_ignore_breakpoints;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallFunction);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanCallFunction_h_
diff --git a/include/lldb/Target/ThreadPlanCallUserExpression.h b/include/lldb/Target/ThreadPlanCallUserExpression.h
new file mode 100644
index 000000000000..7a7ec33049e0
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanCallUserExpression.h
@@ -0,0 +1,65 @@
+//===-- ThreadPlanCallUserExpression.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_ThreadPlanCallUserExpression_h_
+#define liblldb_ThreadPlanCallUserExpression_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+namespace lldb_private {
+
+class ThreadPlanCallUserExpression : public ThreadPlanCallFunction
+{
+public:
+ ThreadPlanCallUserExpression (Thread &thread,
+ Address &function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *this_arg,
+ lldb::addr_t *cmd_arg,
+ ClangUserExpression::ClangUserExpressionSP &user_expression_sp);
+
+ virtual
+ ~ThreadPlanCallUserExpression ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual void
+ WillPop ()
+ {
+ ThreadPlanCallFunction::WillPop();
+ if (m_user_expression_sp)
+ m_user_expression_sp.reset();
+ }
+
+ virtual lldb::StopInfoSP
+ GetRealStopInfo();
+
+protected:
+private:
+ ClangUserExpression::ClangUserExpressionSP m_user_expression_sp; // This is currently just used to ensure the
+ // User expression the initiated this ThreadPlan
+ // lives as long as the thread plan does.
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanCallUserExpression);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanCallUserExpression_h_
diff --git a/include/lldb/Target/ThreadPlanRunToAddress.h b/include/lldb/Target/ThreadPlanRunToAddress.h
new file mode 100644
index 000000000000..d94820668017
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanRunToAddress.h
@@ -0,0 +1,85 @@
+//===-- ThreadPlanRunToAddress.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_ThreadPlanRunToAddress_h_
+#define liblldb_ThreadPlanRunToAddress_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanRunToAddress : public ThreadPlan
+{
+public:
+ ThreadPlanRunToAddress (Thread &thread,
+ Address &address,
+ bool stop_others);
+
+ ThreadPlanRunToAddress (Thread &thread,
+ lldb::addr_t address,
+ bool stop_others);
+
+ ThreadPlanRunToAddress (Thread &thread,
+ const std::vector<lldb::addr_t> &addresses,
+ bool stop_others);
+
+
+ virtual
+ ~ThreadPlanRunToAddress ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ValidatePlan (Stream *error);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ virtual bool
+ StopOthers ();
+
+ virtual void
+ SetStopOthers (bool new_value);
+
+ virtual lldb::StateType
+ GetPlanRunState ();
+
+ virtual bool
+ WillStop ();
+
+ virtual bool
+ MischiefManaged ();
+
+protected:
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr);
+
+ void SetInitialBreakpoints();
+ bool AtOurAddress();
+private:
+ bool m_stop_others;
+ std::vector<lldb::addr_t> m_addresses; // This is the address we are going to run to.
+ // TODO: Would it be useful to have multiple addresses?
+ std::vector<lldb::break_id_t> m_break_ids; // This is the breakpoint we are using to stop us at m_address.
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanRunToAddress);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanRunToAddress_h_
diff --git a/include/lldb/Target/ThreadPlanShouldStopHere.h b/include/lldb/Target/ThreadPlanShouldStopHere.h
new file mode 100644
index 000000000000..62068b78ae4e
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanShouldStopHere.h
@@ -0,0 +1,94 @@
+//===-- ThreadPlanShouldStopHere.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_ThreadPlanShouldStopHere_h_
+#define liblldb_ThreadPlanShouldStopHere_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+// This is an interface that ThreadPlans can adopt to allow flexible modifications of the behavior
+// when a thread plan comes to a place where it would ordinarily stop. If such modification makes
+// sense for your plan, inherit from this class, and when you would be about to stop (in your ShouldStop
+// method), call InvokeShouldStopHereCallback, and if that returns a non-NULL plan, execute that
+// plan instead of stopping.
+//
+// The classic example of the use of this is ThreadPlanStepInRange not stopping in frames that have
+// no debug information.
+//
+// This class also defines a set of flags to control general aspects of this "ShouldStop" behavior.
+// A class implementing this protocol needs to define a default set of flags, and can provide access to
+// changing that default flag set if it wishes.
+
+class ThreadPlanShouldStopHere
+{
+public:
+ enum
+ {
+ eNone = 0,
+ eAvoidInlines = (1 << 0),
+ eAvoidNoDebug = (1 << 1)
+ };
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ThreadPlanShouldStopHere (ThreadPlan *owner,
+ ThreadPlanShouldStopHereCallback callback = NULL,
+ void *baton = NULL);
+ virtual
+ ~ThreadPlanShouldStopHere();
+
+ void
+ SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton);
+
+ lldb::ThreadPlanSP
+ InvokeShouldStopHereCallback ();
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+protected:
+ // Implement this, and call it in the plan's constructor to set the default flags.
+ virtual void SetFlagsToDefault () = 0;
+
+ //------------------------------------------------------------------
+ // Classes that inherit from ThreadPlanShouldStopHere can see and modify these
+ //------------------------------------------------------------------
+ ThreadPlanShouldStopHereCallback m_callback;
+ void * m_baton;
+ ThreadPlan *m_owner;
+ lldb_private::Flags m_flags;
+
+private:
+ //------------------------------------------------------------------
+ // For ThreadPlanShouldStopHere only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanShouldStopHere);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanShouldStopHere_h_
diff --git a/include/lldb/Target/ThreadPlanStepInRange.h b/include/lldb/Target/ThreadPlanStepInRange.h
new file mode 100644
index 000000000000..dbc8446b2e18
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepInRange.h
@@ -0,0 +1,110 @@
+//===-- ThreadPlanStepInRange.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_ThreadPlanStepInRange_h_
+#define liblldb_ThreadPlanStepInRange_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepInRange :
+ public ThreadPlanStepRange,
+ public ThreadPlanShouldStopHere
+{
+public:
+ ThreadPlanStepInRange (Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ ThreadPlanStepInRange (Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_into_function_name,
+ lldb::RunMode stop_others);
+
+ virtual
+ ~ThreadPlanStepInRange ();
+
+ virtual void
+ GetDescription (Stream *s, lldb::DescriptionLevel level);
+
+ virtual bool
+ ShouldStop (Event *event_ptr);
+
+ void SetAvoidRegexp(const char *name);
+
+ void SetStepInTarget (const char *target)
+ {
+ m_step_into_target.SetCString(target);
+ }
+
+ static lldb::ThreadPlanSP
+ DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton);
+
+ static void
+ SetDefaultFlagValue (uint32_t new_value);
+
+ bool
+ IsVirtualStep();
+
+protected:
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+
+ virtual bool
+ DoPlanExplainsStop (Event *event_ptr);
+
+ virtual void
+ SetFlagsToDefault ();
+
+ bool
+ FrameMatchesAvoidRegexp ();
+
+private:
+
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepOverRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepInRange (bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
+ lldb::RunMode stop_others,
+ bool avoid_code_without_debug_info);
+
+
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ static uint32_t s_default_flag_values;
+ lldb::ThreadPlanSP m_sub_plan_sp; // Keep track of the last plan we were running. If it fails, we should stop.
+ std::unique_ptr<RegularExpression> m_avoid_regexp_ap;
+ bool m_step_past_prologue; // FIXME: For now hard-coded to true, we could put a switch in for this if there's
+ // demand for that.
+ bool m_virtual_step; // true if we've just done a "virtual step", i.e. just moved the inline stack depth.
+ ConstString m_step_into_target;
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepInRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepInRange_h_
diff --git a/include/lldb/Target/ThreadPlanStepInstruction.h b/include/lldb/Target/ThreadPlanStepInstruction.h
new file mode 100644
index 000000000000..eb4a64bcbc84
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepInstruction.h
@@ -0,0 +1,64 @@
+//===-- ThreadPlanStepInstruction.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_ThreadPlanStepInstruction_h_
+#define liblldb_ThreadPlanStepInstruction_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepInstruction : public ThreadPlan
+{
+public:
+ virtual ~ThreadPlanStepInstruction ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+
+ ThreadPlanStepInstruction (Thread &thread,
+ bool step_over,
+ bool stop_others,
+ Vote stop_vote,
+ Vote run_vote);
+
+private:
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepSingleInstruction (bool step_over, bool abort_other_plans, bool stop_other_threads);
+
+ lldb::addr_t m_instruction_addr;
+ bool m_stop_other_threads;
+ bool m_step_over;
+ // These two are used only for the step over case.
+ bool m_start_has_symbol;
+ StackID m_stack_id;
+ StackID m_parent_frame_id;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepInstruction);
+
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepInstruction_h_
diff --git a/include/lldb/Target/ThreadPlanStepOut.h b/include/lldb/Target/ThreadPlanStepOut.h
new file mode 100644
index 000000000000..2737978a4edc
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepOut.h
@@ -0,0 +1,90 @@
+//===-- ThreadPlanStepOut.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_ThreadPlanStepOut_h_
+#define liblldb_ThreadPlanStepOut_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepOut : public ThreadPlan
+{
+public:
+ ThreadPlanStepOut (Thread &thread,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_others,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx);
+
+ virtual ~ThreadPlanStepOut ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+ virtual void DidPush();
+ virtual bool IsPlanStale();
+
+ virtual lldb::ValueObjectSP GetReturnValueObject()
+ {
+ return m_return_valobj_sp;
+ }
+
+protected:
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+ bool QueueInlinedStepPlan (bool queue_now);
+
+private:
+ SymbolContext *m_step_from_context;
+ lldb::addr_t m_step_from_insn;
+ StackID m_step_out_to_id;
+ StackID m_immediate_step_from_id;
+ lldb::break_id_t m_return_bp_id;
+ lldb::addr_t m_return_addr;
+ bool m_first_insn;
+ bool m_stop_others;
+ lldb::ThreadPlanSP m_step_through_inline_plan_sp;
+ lldb::ThreadPlanSP m_step_out_plan_sp;
+ Function *m_immediate_step_from_function;
+ lldb::ValueObjectSP m_return_valobj_sp;
+
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepOut (bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_others,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx);
+
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ void
+ CalculateReturnValue();
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOut);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOut_h_
diff --git a/include/lldb/Target/ThreadPlanStepOverBreakpoint.h b/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
new file mode 100644
index 000000000000..41cac5c9b0b4
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepOverBreakpoint.h
@@ -0,0 +1,57 @@
+//===-- ThreadPlanStepOverBreakpoint.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_ThreadPlanStepOverBreakpoint_h_
+#define liblldb_ThreadPlanStepOverBreakpoint_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepOverBreakpoint : public ThreadPlan
+{
+public:
+ virtual ~ThreadPlanStepOverBreakpoint ();
+
+ ThreadPlanStepOverBreakpoint (Thread &thread);
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+ virtual void ThreadDestroyed ();
+ void SetAutoContinue (bool do_it);
+ virtual bool ShouldAutoContinue(Event *event_ptr);
+
+protected:
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+
+ void ReenableBreakpointSite ();
+private:
+
+ lldb::addr_t m_breakpoint_addr;
+ lldb::user_id_t m_breakpoint_site_id;
+ bool m_auto_continue;
+ bool m_reenabled_breakpoint_site;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOverBreakpoint);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOverBreakpoint_h_
diff --git a/include/lldb/Target/ThreadPlanStepOverRange.h b/include/lldb/Target/ThreadPlanStepOverRange.h
new file mode 100644
index 000000000000..de9e66829dc7
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepOverRange.h
@@ -0,0 +1,52 @@
+//===-- ThreadPlanStepOverRange.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_ThreadPlanStepOverRange_h_
+#define liblldb_ThreadPlanStepOverRange_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepOverRange : public ThreadPlanStepRange
+{
+public:
+
+ ThreadPlanStepOverRange (Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ virtual ~ThreadPlanStepOverRange ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ShouldStop (Event *event_ptr);
+
+protected:
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+
+private:
+
+ bool m_first_resume;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepOverRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepOverRange_h_
diff --git a/include/lldb/Target/ThreadPlanStepRange.h b/include/lldb/Target/ThreadPlanStepRange.h
new file mode 100644
index 000000000000..486fd6528390
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepRange.h
@@ -0,0 +1,94 @@
+//===-- ThreadPlanStepRange.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_ThreadPlanStepRange_h_
+#define liblldb_ThreadPlanStepRange_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepRange : public ThreadPlan
+{
+public:
+ ThreadPlanStepRange (ThreadPlanKind kind,
+ const char *name,
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others);
+
+ virtual ~ThreadPlanStepRange ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level) = 0;
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr) = 0;
+ virtual Vote ShouldReportStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+ virtual void DidPush ();
+ virtual bool IsPlanStale ();
+
+
+ void AddRange(const AddressRange &new_range);
+
+protected:
+
+ bool InRange();
+ lldb::FrameComparison CompareCurrentFrameToStartFrame();
+ bool InSymbol();
+ void DumpRanges (Stream *s);
+
+ Disassembler *
+ GetDisassembler ();
+
+ InstructionList *
+ GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset);
+
+ // Pushes a plan to proceed through the next section of instructions in the range - usually just a RunToAddress
+ // plan to run to the next branch. Returns true if it pushed such a plan. If there was no available 'quick run'
+ // plan, then just single step.
+ bool
+ SetNextBranchBreakpoint ();
+
+ void
+ ClearNextBranchBreakpoint();
+
+ bool
+ NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp);
+
+ SymbolContext m_addr_context;
+ std::vector<AddressRange> m_address_ranges;
+ lldb::RunMode m_stop_others;
+ StackID m_stack_id; // Use the stack ID so we can tell step out from step in.
+ bool m_no_more_plans; // Need this one so we can tell if we stepped into a call,
+ // but can't continue, in which case we are done.
+ bool m_first_run_event; // We want to broadcast only one running event, our first.
+ lldb::BreakpointSP m_next_branch_bp_sp;
+ bool m_use_fast_step;
+
+private:
+ std::vector<lldb::DisassemblerSP> m_instruction_ranges;
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepRange);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepRange_h_
diff --git a/include/lldb/Target/ThreadPlanStepThrough.h b/include/lldb/Target/ThreadPlanStepThrough.h
new file mode 100644
index 000000000000..16979663eb1b
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepThrough.h
@@ -0,0 +1,71 @@
+//===-- ThreadPlanStepThrough.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_ThreadPlanStepThrough_h_
+#define liblldb_ThreadPlanStepThrough_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+class ThreadPlanStepThrough : public ThreadPlan
+{
+public:
+ virtual ~ThreadPlanStepThrough ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+ virtual void DidPush();
+
+protected:
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+
+ ThreadPlanStepThrough (Thread &thread,
+ StackID &return_stack_id,
+ bool stop_others);
+
+ void
+ LookForPlanToStepThroughFromCurrentPC ();
+
+ bool
+ HitOurBackstopBreakpoint();
+
+private:
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id,
+ bool abort_other_plans,
+ bool stop_others);
+
+ void ClearBackstopBreakpoint();
+
+ lldb::ThreadPlanSP m_sub_plan_sp;
+ lldb::addr_t m_start_address;
+ lldb::break_id_t m_backstop_bkpt_id;
+ lldb::addr_t m_backstop_addr;
+ StackID m_return_stack_id;
+ bool m_stop_others;
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepThrough);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepThrough_h_
diff --git a/include/lldb/Target/ThreadPlanStepUntil.h b/include/lldb/Target/ThreadPlanStepUntil.h
new file mode 100644
index 000000000000..5aa3876df53c
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanStepUntil.h
@@ -0,0 +1,80 @@
+//===-- ThreadPlanStepUntil.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_ThreadPlanStepUntil_h_
+#define liblldb_ThreadPlanStepUntil_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+
+namespace lldb_private {
+
+
+class ThreadPlanStepUntil : public ThreadPlan
+{
+public:
+ virtual ~ThreadPlanStepUntil ();
+
+ virtual void GetDescription (Stream *s, lldb::DescriptionLevel level);
+ virtual bool ValidatePlan (Stream *error);
+ virtual bool ShouldStop (Event *event_ptr);
+ virtual bool StopOthers ();
+ virtual lldb::StateType GetPlanRunState ();
+ virtual bool WillStop ();
+ virtual bool MischiefManaged ();
+
+protected:
+ virtual bool DoWillResume (lldb::StateType resume_state, bool current_plan);
+ virtual bool DoPlanExplainsStop (Event *event_ptr);
+
+ ThreadPlanStepUntil (Thread &thread,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others,
+ uint32_t frame_idx = 0);
+ void AnalyzeStop(void);
+
+private:
+
+ StackID m_stack_id;
+ lldb::addr_t m_step_from_insn;
+ lldb::break_id_t m_return_bp_id;
+ lldb::addr_t m_return_addr;
+ bool m_stepped_out;
+ bool m_should_stop;
+ bool m_ran_analyze;
+ bool m_explains_stop;
+
+ typedef std::map<lldb::addr_t,lldb::break_id_t> until_collection;
+ until_collection m_until_points;
+ bool m_stop_others;
+
+ void Clear();
+
+ friend lldb::ThreadPlanSP
+ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others,
+ uint32_t frame_idx);
+
+ // Need an appropriate marker for the current stack so we can tell step out
+ // from step in.
+
+ DISALLOW_COPY_AND_ASSIGN (ThreadPlanStepUntil);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanStepUntil_h_
diff --git a/include/lldb/Target/ThreadPlanTracer.h b/include/lldb/Target/ThreadPlanTracer.h
new file mode 100644
index 000000000000..4eb0c783e57d
--- /dev/null
+++ b/include/lldb/Target/ThreadPlanTracer.h
@@ -0,0 +1,131 @@
+//===-- ThreadPlanTracer.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_ThreadPlanTracer_h_
+#define liblldb_ThreadPlanTracer_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Symbol/TaggedASTType.h"
+#include "lldb/Target/Thread.h"
+
+namespace lldb_private {
+
+class ThreadPlanTracer
+{
+friend class ThreadPlan;
+
+public:
+
+ typedef enum ThreadPlanTracerStyle
+ {
+ eLocation = 0,
+ eStateChange,
+ eCheckFrames,
+ ePython
+ } ThreadPlanTracerStyle;
+ ThreadPlanTracer (Thread &thread, lldb::StreamSP &stream_sp);
+ ThreadPlanTracer (Thread &thread);
+
+ virtual ~ThreadPlanTracer()
+ {
+ }
+
+ virtual void TracingStarted ()
+ {
+
+ }
+
+ virtual void TracingEnded ()
+ {
+
+ }
+
+ bool
+ EnableTracing(bool value)
+ {
+ bool old_value = m_enabled;
+ m_enabled = value;
+ if (old_value == false && value == true)
+ TracingStarted();
+ else if (old_value == true && value == false)
+ TracingEnded();
+
+ return old_value;
+ }
+
+ bool
+ TracingEnabled()
+ {
+ return m_enabled;
+ }
+
+ bool
+ EnableSingleStep (bool value)
+ {
+ bool old_value = m_single_step;
+ m_single_step = value;
+ return old_value;
+ }
+
+ bool
+ SingleStepEnabled ()
+ {
+ return m_single_step;
+ }
+
+protected:
+ Thread &m_thread;
+
+ Stream *
+ GetLogStream ();
+
+
+
+ virtual void Log();
+
+private:
+ bool
+ TracerExplainsStop ();
+
+ bool m_single_step;
+ bool m_enabled;
+ lldb::StreamSP m_stream_sp;
+};
+
+class ThreadPlanAssemblyTracer : public ThreadPlanTracer
+{
+public:
+ ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp);
+ ThreadPlanAssemblyTracer (Thread &thread);
+ virtual ~ThreadPlanAssemblyTracer ();
+ virtual void TracingStarted ();
+ virtual void TracingEnded ();
+ virtual void Log();
+private:
+
+ Disassembler *
+ GetDisassembler ();
+
+ TypeFromUser
+ GetIntPointerType();
+
+ lldb::DisassemblerSP m_disassembler_sp;
+ TypeFromUser m_intptr_type;
+ std::vector<RegisterValue> m_register_values;
+ lldb::DataBufferSP m_buffer_sp;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadPlanTracer_h_
diff --git a/include/lldb/Target/ThreadSpec.h b/include/lldb/Target/ThreadSpec.h
new file mode 100644
index 000000000000..e0d30934f373
--- /dev/null
+++ b/include/lldb/Target/ThreadSpec.h
@@ -0,0 +1,155 @@
+//===-- ThreadSpec.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_ThreadSpec_h_
+#define liblldb_ThreadSpec_h_
+
+#include <map>
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+
+// Note: For now the thread spec has only fixed elements -
+// Thread ID
+// Thread Index
+// Thread Name
+// Thread Queue Name
+//
+// But if we need more generality, we can hang a key/value map off of this structure.
+// That's why the thread matches spec test is done as a virtual method in Thread::MatchesSpec,
+// since it is the native thread that would know how to interpret the keys.
+// I was going to do the Queue Name this way out of sheer orneriness, but that seems a
+// sufficiently general concept, so I put it in here on its own.
+
+class ThreadSpec
+{
+public:
+ ThreadSpec ();
+
+ ThreadSpec (const ThreadSpec &rhs);
+
+ const ThreadSpec &
+ operator=(const ThreadSpec &rhs);
+
+ void
+ SetIndex (uint32_t index)
+ {
+ m_index = index;
+ }
+
+ void
+ SetTID (lldb::tid_t tid)
+ {
+ m_tid = tid;
+ }
+
+ void
+ SetName (const char *name)
+ {
+ m_name = name;
+ }
+
+ void
+ SetQueueName (const char *queue_name)
+ {
+ m_queue_name = queue_name;
+ }
+
+ uint32_t
+ GetIndex () const
+ {
+ return m_index;
+ }
+
+ lldb::tid_t
+ GetTID () const
+ {
+ return m_tid;
+ }
+
+ const char *
+ GetName () const;
+
+ const char *
+ GetQueueName () const;
+
+ bool
+ TIDMatches (lldb::tid_t thread_id) const
+ {
+ if (m_tid == LLDB_INVALID_THREAD_ID || thread_id == LLDB_INVALID_THREAD_ID)
+ return true;
+ else
+ return thread_id == m_tid;
+ }
+
+ bool
+ TIDMatches (Thread &thread) const;
+
+ bool
+ IndexMatches (uint32_t index) const
+ {
+ if (m_index == UINT32_MAX || index == UINT32_MAX)
+ return true;
+ else
+ return index == m_index;
+ }
+
+ bool
+ IndexMatches (Thread &thread) const;
+
+ bool
+ NameMatches (const char *name) const
+ {
+ if (m_name.empty())
+ return true;
+ else if (name == NULL)
+ return false;
+ else
+ return m_name == name;
+ }
+
+ bool
+ NameMatches (Thread &thread) const;
+
+ bool
+ QueueNameMatches (const char *queue_name) const
+ {
+ if (m_queue_name.empty())
+ return true;
+ else if (queue_name == NULL)
+ return false;
+ else
+ return m_queue_name == queue_name;
+ }
+
+ bool
+ QueueNameMatches (Thread &thread) const;
+
+ bool
+ ThreadPassesBasicTests (Thread &thread) const;
+
+ bool
+ HasSpecification () const;
+
+ void
+ GetDescription (Stream *s, lldb::DescriptionLevel level) const;
+
+protected:
+private:
+ uint32_t m_index;
+ lldb::tid_t m_tid;
+ std::string m_name;
+ std::string m_queue_name;
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ThreadSpec_h_
diff --git a/include/lldb/Target/UnixSignals.h b/include/lldb/Target/UnixSignals.h
new file mode 100644
index 000000000000..f47a90bbf545
--- /dev/null
+++ b/include/lldb/Target/UnixSignals.h
@@ -0,0 +1,144 @@
+//===-- UnixSignals.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnixSignals_h_
+#define lldb_UnixSignals_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+
+namespace lldb_private
+{
+
+class UnixSignals
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ UnixSignals();
+
+ virtual
+ ~UnixSignals();
+
+ const char *
+ GetSignalAsCString (int32_t signo) const;
+
+ bool
+ SignalIsValid (int32_t signo) const;
+
+ int32_t
+ GetSignalNumberFromName (const char *name) const;
+
+ const char *
+ GetSignalInfo (int32_t signo,
+ bool &should_suppress,
+ bool &should_stop,
+ bool &should_notify) const;
+
+ bool
+ GetShouldSuppress (int32_t signo) const;
+
+ bool
+ SetShouldSuppress (int32_t signo,
+ bool value);
+
+ bool
+ SetShouldSuppress (const char *signal_name,
+ bool value);
+
+ bool
+ GetShouldStop (int32_t signo) const;
+
+ bool
+ SetShouldStop (int32_t signo,
+ bool value);
+ bool
+ SetShouldStop (const char *signal_name,
+ bool value);
+
+ bool
+ GetShouldNotify (int32_t signo) const;
+
+ bool
+ SetShouldNotify (int32_t signo, bool value);
+
+ bool
+ SetShouldNotify (const char *signal_name,
+ bool value);
+
+ // These provide an iterator through the signals available on this system.
+ // Call GetFirstSignalNumber to get the first entry, then iterate on GetNextSignalNumber
+ // till you get back LLDB_INVALID_SIGNAL_NUMBER.
+ int32_t
+ GetFirstSignalNumber () const;
+
+ int32_t
+ GetNextSignalNumber (int32_t current_signal) const;
+
+ // We assume that the elements of this object are constant once it is constructed,
+ // since a process should never need to add or remove symbols as it runs. So don't
+ // call these functions anywhere but the constructor of your subclass of UnixSignals or in
+ // your Process Plugin's GetUnixSignals method before you return the UnixSignal object.
+
+ void
+ AddSignal (int signo,
+ const char *name,
+ const char *short_name,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify,
+ const char *description);
+
+ void
+ RemoveSignal (int signo);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from UnixSignals can see and modify these
+ //------------------------------------------------------------------
+
+ struct Signal
+ {
+ ConstString m_name;
+ ConstString m_short_name;
+ std::string m_description;
+ bool m_suppress:1,
+ m_stop:1,
+ m_notify:1;
+
+ Signal (const char *name,
+ const char *short_name,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify,
+ const char *description);
+
+ ~Signal () {}
+ };
+
+ void
+ Reset ();
+
+ typedef std::map <int32_t, Signal> collection;
+
+ collection m_signals;
+
+ DISALLOW_COPY_AND_ASSIGN (UnixSignals);
+};
+
+} // Namespace lldb
+#endif // lldb_UnixSignals_h_
diff --git a/include/lldb/Target/Unwind.h b/include/lldb/Target/Unwind.h
new file mode 100644
index 000000000000..7cda4aeb2e18
--- /dev/null
+++ b/include/lldb/Target/Unwind.h
@@ -0,0 +1,120 @@
+//===-- Unwind.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_Unwind_h_
+#define liblldb_Unwind_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+class Unwind
+{
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Unwind can see and modify these
+ //------------------------------------------------------------------
+ Unwind(Thread &thread) :
+ m_thread (thread),
+ m_unwind_mutex()
+ {
+ }
+
+public:
+ virtual
+ ~Unwind()
+ {
+ }
+
+ void
+ Clear()
+ {
+ Mutex::Locker locker(m_unwind_mutex);
+ DoClear();
+
+ }
+
+ uint32_t
+ GetFrameCount()
+ {
+ Mutex::Locker locker(m_unwind_mutex);
+ return DoGetFrameCount();
+ }
+
+ uint32_t
+ GetFramesUpTo (uint32_t end_idx)
+ {
+ lldb::addr_t cfa;
+ lldb::addr_t pc;
+ uint32_t idx;
+
+ for (idx = 0; idx < end_idx; idx++)
+ {
+ if (!DoGetFrameInfoAtIndex (idx, cfa, pc))
+ {
+ break;
+ }
+ }
+ return idx;
+ }
+
+ bool
+ GetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc)
+ {
+ Mutex::Locker locker(m_unwind_mutex);
+ return DoGetFrameInfoAtIndex (frame_idx, cfa, pc);
+ }
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame (StackFrame *frame)
+ {
+ Mutex::Locker locker(m_unwind_mutex);
+ return DoCreateRegisterContextForFrame (frame);
+ }
+
+ Thread &
+ GetThread()
+ {
+ return m_thread;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from Unwind can see and modify these
+ //------------------------------------------------------------------
+ virtual void
+ DoClear() = 0;
+
+ virtual uint32_t
+ DoGetFrameCount() = 0;
+
+ virtual bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc) = 0;
+
+ virtual lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (StackFrame *frame) = 0;
+
+ Thread &m_thread;
+ Mutex m_unwind_mutex;
+private:
+ DISALLOW_COPY_AND_ASSIGN (Unwind);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_Unwind_h_
diff --git a/include/lldb/Target/UnwindAssembly.h b/include/lldb/Target/UnwindAssembly.h
new file mode 100644
index 000000000000..6a4ae0c30f27
--- /dev/null
+++ b/include/lldb/Target/UnwindAssembly.h
@@ -0,0 +1,58 @@
+//===-- UnwindAssembly.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_UnwindAssembly_h_
+#define utility_UnwindAssembly_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginInterface.h"
+
+namespace lldb_private {
+
+class UnwindAssembly :
+ public PluginInterface
+{
+public:
+ static UnwindAssembly*
+ FindPlugin (const ArchSpec &arch);
+
+ virtual
+ ~UnwindAssembly();
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func,
+ Thread& thread,
+ UnwindPlan& unwind_plan) = 0;
+
+ virtual bool
+ GetFastUnwindPlan (AddressRange& func,
+ Thread& thread,
+ UnwindPlan &unwind_plan) = 0;
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ Address& first_non_prologue_insn) = 0;
+
+protected:
+ UnwindAssembly (const ArchSpec &arch);
+ ArchSpec m_arch;
+
+private:
+ UnwindAssembly(); // Outlaw default constructor
+ DISALLOW_COPY_AND_ASSIGN (UnwindAssembly);
+};
+
+} // namespace lldb_private
+
+#endif //utility_UnwindAssembly_h_
+
+
diff --git a/include/lldb/Utility/AnsiTerminal.h b/include/lldb/Utility/AnsiTerminal.h
new file mode 100644
index 000000000000..036950c1bd45
--- /dev/null
+++ b/include/lldb/Utility/AnsiTerminal.h
@@ -0,0 +1,156 @@
+//===---------------------AnsiTerminal.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+
+#define ANSI_FG_COLOR_BLACK 30
+#define ANSI_FG_COLOR_RED 31
+#define ANSI_FG_COLOR_GREEN 32
+#define ANSI_FG_COLOR_YELLOW 33
+#define ANSI_FG_COLOR_BLUE 34
+#define ANSI_FG_COLOR_PURPLE 35
+#define ANSI_FG_COLOR_CYAN 36
+#define ANSI_FG_COLOR_WHITE 37
+
+#define ANSI_BG_COLOR_BLACK 40
+#define ANSI_BG_COLOR_RED 41
+#define ANSI_BG_COLOR_GREEN 42
+#define ANSI_BG_COLOR_YELLOW 43
+#define ANSI_BG_COLOR_BLUE 44
+#define ANSI_BG_COLOR_PURPLE 45
+#define ANSI_BG_COLOR_CYAN 46
+#define ANSI_BG_COLOR_WHITE 47
+
+#define ANSI_SPECIAL_FRAMED 51
+#define ANSI_SPECIAL_ENCIRCLED 52
+
+#define ANSI_CTRL_NORMAL 0
+#define ANSI_CTRL_BOLD 1
+#define ANSI_CTRL_FAINT 2
+#define ANSI_CTRL_ITALIC 3
+#define ANSI_CTRL_UNDERLINE 4
+#define ANSI_CTRL_SLOW_BLINK 5
+#define ANSI_CTRL_FAST_BLINK 6
+#define ANSI_CTRL_IMAGE_NEGATIVE 7
+#define ANSI_CTRL_CONCEAL 8
+#define ANSI_CTRL_CROSSED_OUT 9
+
+#define ANSI_ESC_START "\033["
+#define ANSI_ESC_END "m"
+
+#define ANSI_1_CTRL(ctrl1) "\033["##ctrl1 ANSI_ESC_END
+#define ANSI_2_CTRL(ctrl1,ctrl2) "\033["##ctrl1";"##ctrl2 ANSI_ESC_END
+
+namespace lldb_utility {
+
+ namespace ansi {
+ const char *k_escape_start = "\033[";
+ const char *k_escape_end = "m";
+
+ const char *k_fg_black = "30";
+ const char *k_fg_red = "31";
+ const char *k_fg_green = "32";
+ const char *k_fg_yellow = "33";
+ const char *k_fg_blue = "34";
+ const char *k_fg_purple = "35";
+ const char *k_fg_cyan = "36";
+ const char *k_fg_white = "37";
+
+ const char *k_bg_black = "40";
+ const char *k_bg_red = "41";
+ const char *k_bg_green = "42";
+ const char *k_bg_yellow = "43";
+ const char *k_bg_blue = "44";
+ const char *k_bg_purple = "45";
+ const char *k_bg_cyan = "46";
+ const char *k_bg_white = "47";
+
+ const char *k_ctrl_normal = "0";
+ const char *k_ctrl_bold = "1";
+ const char *k_ctrl_faint = "2";
+ const char *k_ctrl_italic = "3";
+ const char *k_ctrl_underline = "4";
+ const char *k_ctrl_slow_blink = "5";
+ const char *k_ctrl_fast_blink = "6";
+ const char *k_ctrl_negative = "7";
+ const char *k_ctrl_conceal = "8";
+ const char *k_ctrl_crossed_out = "9";
+
+ inline std::string
+ FormatAnsiTerminalCodes(const char *format, bool do_color = true)
+ {
+ // Convert "${ansi.XXX}" tokens to ansi values or clear them if do_color is false.
+ static const struct
+ {
+ const char *name;
+ const char *value;
+ } g_color_tokens[] =
+ {
+ #define _TO_STR2(_val) #_val
+ #define _TO_STR(_val) _TO_STR2(_val)
+ { "fg.black}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLACK) ANSI_ESC_END },
+ { "fg.red}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_RED) ANSI_ESC_END },
+ { "fg.green}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_GREEN) ANSI_ESC_END },
+ { "fg.yellow}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_YELLOW) ANSI_ESC_END },
+ { "fg.blue}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_BLUE) ANSI_ESC_END },
+ { "fg.purple}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_PURPLE) ANSI_ESC_END },
+ { "fg.cyan}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_CYAN) ANSI_ESC_END },
+ { "fg.white}", ANSI_ESC_START _TO_STR(ANSI_FG_COLOR_WHITE) ANSI_ESC_END },
+ { "bg.black}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLACK) ANSI_ESC_END },
+ { "bg.red}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_RED) ANSI_ESC_END },
+ { "bg.green}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_GREEN) ANSI_ESC_END },
+ { "bg.yellow}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_YELLOW) ANSI_ESC_END },
+ { "bg.blue}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_BLUE) ANSI_ESC_END },
+ { "bg.purple}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_PURPLE) ANSI_ESC_END },
+ { "bg.cyan}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_CYAN) ANSI_ESC_END },
+ { "bg.white}", ANSI_ESC_START _TO_STR(ANSI_BG_COLOR_WHITE) ANSI_ESC_END },
+ { "normal}", ANSI_ESC_START _TO_STR(ANSI_CTRL_NORMAL) ANSI_ESC_END },
+ { "bold}", ANSI_ESC_START _TO_STR(ANSI_CTRL_BOLD) ANSI_ESC_END },
+ { "faint}", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAINT) ANSI_ESC_END },
+ { "italic}", ANSI_ESC_START _TO_STR(ANSI_CTRL_ITALIC) ANSI_ESC_END },
+ { "underline}", ANSI_ESC_START _TO_STR(ANSI_CTRL_UNDERLINE) ANSI_ESC_END },
+ { "slow-blink}", ANSI_ESC_START _TO_STR(ANSI_CTRL_SLOW_BLINK) ANSI_ESC_END },
+ { "fast-blink}", ANSI_ESC_START _TO_STR(ANSI_CTRL_FAST_BLINK) ANSI_ESC_END },
+ { "negative}", ANSI_ESC_START _TO_STR(ANSI_CTRL_IMAGE_NEGATIVE) ANSI_ESC_END },
+ { "conceal}", ANSI_ESC_START _TO_STR(ANSI_CTRL_CONCEAL) ANSI_ESC_END },
+ { "crossed-out}", ANSI_ESC_START _TO_STR(ANSI_CTRL_CROSSED_OUT) ANSI_ESC_END },
+ #undef _TO_STR
+ #undef _TO_STR2
+ };
+ static const char tok_hdr[] = "${ansi.";
+
+ std::string fmt;
+ for (const char *p = format; *p; ++p)
+ {
+ const char *tok_start = strstr (p, tok_hdr);
+ if (!tok_start)
+ {
+ fmt.append (p, strlen(p));
+ break;
+ }
+
+ fmt.append (p, tok_start - p);
+ p = tok_start;
+
+ const char *tok_str = tok_start + sizeof(tok_hdr) - 1;
+ for (size_t i = 0; i < sizeof(g_color_tokens) / sizeof(g_color_tokens[0]); ++i)
+ {
+ if (!strncmp (tok_str, g_color_tokens[i].name, strlen(g_color_tokens[i].name)))
+ {
+ if (do_color)
+ fmt.append (g_color_tokens[i].value);
+ p = tok_str + strlen (g_color_tokens[i].name) - 1;
+ break;
+ }
+ }
+ }
+ return fmt;
+ }
+ }
+}
diff --git a/include/lldb/Utility/CleanUp.h b/include/lldb/Utility/CleanUp.h
new file mode 100644
index 000000000000..ab15d1999b7d
--- /dev/null
+++ b/include/lldb/Utility/CleanUp.h
@@ -0,0 +1,322 @@
+//===-- CleanUp.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_CleanUp_h_
+#define liblldb_CleanUp_h_
+
+#include "lldb/lldb-public.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+// Templated class that guarantees that a cleanup callback function will
+// be called. The cleanup function will be called once under the
+// following conditions:
+// - when the object goes out of scope
+// - when the user explicitly calls clean.
+// - the current value will be cleaned up when a new value is set using
+// set(T value) as long as the current value hasn't already been cleaned.
+//
+// This class is designed to be used with simple types for type T (like
+// file descriptors, opaque handles, pointers, etc). If more complex
+// type T objects are desired, we need to probably specialize this class
+// to take "const T&" for all input T parameters. Yet if a type T is
+// complex already it might be better to build the cleanup funcionality
+// into T.
+//
+// The cleanup function must take one argument that is of type T.
+// The calback function return type is R. The return value is currently
+// needed for "CallbackType". If there is an easy way to get around the
+// need for the return value we can change this class.
+//
+// The two template parameters are:
+// T - The variable type of value that will be stored and used as the
+// sole argument for the cleanup callback.
+// R - The return type for the cleanup function.
+//
+// EXAMPLES
+// // Use with file handles that get opened where you want to close
+// // them. Below we use "int open(const char *path, int oflag, ...)"
+// // which returns an integer file descriptor. -1 is the invalid file
+// // descriptor so to make an object that will call "int close(int fd)"
+// // automatically we can use:
+//
+// CleanUp <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close);
+//
+// // malloc/free example
+// CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free);
+//----------------------------------------------------------------------
+template <typename T, typename R = void>
+class CleanUp
+{
+public:
+ typedef T value_type;
+ typedef R (*CallbackType)(value_type);
+
+ //----------------------------------------------------------------------
+ // Constructor that sets the current value only. No values are
+ // considered to be invalid and the cleanup function will be called
+ // regardless of the value of m_current_value.
+ //----------------------------------------------------------------------
+ CleanUp (value_type value, CallbackType callback) :
+ m_current_value (value),
+ m_invalid_value (),
+ m_callback (callback),
+ m_callback_called (false),
+ m_invalid_value_is_valid (false)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ // Constructor that sets the current value and also the invalid value.
+ // The cleanup function will be called on "m_value" as long as it isn't
+ // equal to "m_invalid_value".
+ //----------------------------------------------------------------------
+ CleanUp (value_type value, value_type invalid, CallbackType callback) :
+ m_current_value (value),
+ m_invalid_value (invalid),
+ m_callback (callback),
+ m_callback_called (false),
+ m_invalid_value_is_valid (true)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ // Automatically cleanup when this object goes out of scope.
+ //----------------------------------------------------------------------
+ ~CleanUp ()
+ {
+ clean();
+ }
+
+ //----------------------------------------------------------------------
+ // Access the value stored in this class
+ //----------------------------------------------------------------------
+ value_type get()
+ {
+ return m_current_value;
+ }
+
+ //----------------------------------------------------------------------
+ // Access the value stored in this class
+ //----------------------------------------------------------------------
+ const value_type
+ get() const
+ {
+ return m_current_value;
+ }
+
+ //----------------------------------------------------------------------
+ // Reset the owned value to "value". If a current value is valid and
+ // the cleanup callback hasn't been called, the previous value will
+ // be cleaned up (see void CleanUp::clean()).
+ //----------------------------------------------------------------------
+ void
+ set (const value_type value)
+ {
+ // Cleanup the current value if needed
+ clean ();
+ // Now set the new value and mark our callback as not called
+ m_callback_called = false;
+ m_current_value = value;
+ }
+
+ //----------------------------------------------------------------------
+ // Checks is "m_current_value" is valid. The value is considered valid
+ // no invalid value was supplied during construction of this object or
+ // if an invalid value was supplied and "m_current_value" is not equal
+ // to "m_invalid_value".
+ //
+ // Returns true if "m_current_value" is valid, false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ is_valid() const
+ {
+ if (m_invalid_value_is_valid)
+ return m_current_value != m_invalid_value;
+ return true;
+ }
+
+ //----------------------------------------------------------------------
+ // This function will call the cleanup callback provided in the
+ // constructor one time if the value is considered valid (See is_valid()).
+ // This function sets m_callback_called to true so we don't call the
+ // cleanup callback multiple times on the same value.
+ //----------------------------------------------------------------------
+ void
+ clean()
+ {
+ if (m_callback && !m_callback_called)
+ {
+ m_callback_called = true;
+ if (is_valid())
+ m_callback(m_current_value);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Cancels the cleanup that would have been called on "m_current_value"
+ // if it was valid. This function can be used to release the value
+ // contained in this object so ownership can be transfered to the caller.
+ //----------------------------------------------------------------------
+ value_type
+ release ()
+ {
+ m_callback_called = true;
+ return m_current_value;
+ }
+
+private:
+ value_type m_current_value;
+ const value_type m_invalid_value;
+ CallbackType m_callback;
+ bool m_callback_called;
+ bool m_invalid_value_is_valid;
+
+ // Outlaw default constructor, copy constructor and the assignment operator
+ DISALLOW_COPY_AND_ASSIGN (CleanUp);
+};
+
+template <typename T, typename R, typename A0>
+class CleanUp2
+{
+public:
+ typedef T value_type;
+ typedef R (*CallbackType)(value_type, A0);
+
+ //----------------------------------------------------------------------
+ // Constructor that sets the current value only. No values are
+ // considered to be invalid and the cleanup function will be called
+ // regardless of the value of m_current_value.
+ //----------------------------------------------------------------------
+ CleanUp2 (value_type value, CallbackType callback, A0 arg) :
+ m_current_value (value),
+ m_invalid_value (),
+ m_callback (callback),
+ m_callback_called (false),
+ m_invalid_value_is_valid (false),
+ m_argument(arg)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ // Constructor that sets the current value and also the invalid value.
+ // The cleanup function will be called on "m_value" as long as it isn't
+ // equal to "m_invalid_value".
+ //----------------------------------------------------------------------
+ CleanUp2 (value_type value, value_type invalid, CallbackType callback, A0 arg) :
+ m_current_value (value),
+ m_invalid_value (invalid),
+ m_callback (callback),
+ m_callback_called (false),
+ m_invalid_value_is_valid (true),
+ m_argument(arg)
+ {
+ }
+
+ //----------------------------------------------------------------------
+ // Automatically cleanup when this object goes out of scope.
+ //----------------------------------------------------------------------
+ ~CleanUp2 ()
+ {
+ clean();
+ }
+
+ //----------------------------------------------------------------------
+ // Access the value stored in this class
+ //----------------------------------------------------------------------
+ value_type get()
+ {
+ return m_current_value;
+ }
+
+ //----------------------------------------------------------------------
+ // Access the value stored in this class
+ //----------------------------------------------------------------------
+ const value_type
+ get() const
+ {
+ return m_current_value;
+ }
+
+ //----------------------------------------------------------------------
+ // Reset the owned value to "value". If a current value is valid and
+ // the cleanup callback hasn't been called, the previous value will
+ // be cleaned up (see void CleanUp::clean()).
+ //----------------------------------------------------------------------
+ void
+ set (const value_type value)
+ {
+ // Cleanup the current value if needed
+ clean ();
+ // Now set the new value and mark our callback as not called
+ m_callback_called = false;
+ m_current_value = value;
+ }
+
+ //----------------------------------------------------------------------
+ // Checks is "m_current_value" is valid. The value is considered valid
+ // no invalid value was supplied during construction of this object or
+ // if an invalid value was supplied and "m_current_value" is not equal
+ // to "m_invalid_value".
+ //
+ // Returns true if "m_current_value" is valid, false otherwise.
+ //----------------------------------------------------------------------
+ bool
+ is_valid() const
+ {
+ if (m_invalid_value_is_valid)
+ return m_current_value != m_invalid_value;
+ return true;
+ }
+
+ //----------------------------------------------------------------------
+ // This function will call the cleanup callback provided in the
+ // constructor one time if the value is considered valid (See is_valid()).
+ // This function sets m_callback_called to true so we don't call the
+ // cleanup callback multiple times on the same value.
+ //----------------------------------------------------------------------
+ void
+ clean()
+ {
+ if (m_callback && !m_callback_called)
+ {
+ m_callback_called = true;
+ if (is_valid())
+ m_callback(m_current_value, m_argument);
+ }
+ }
+
+ //----------------------------------------------------------------------
+ // Cancels the cleanup that would have been called on "m_current_value"
+ // if it was valid. This function can be used to release the value
+ // contained in this object so ownership can be transfered to the caller.
+ //----------------------------------------------------------------------
+ value_type
+ release ()
+ {
+ m_callback_called = true;
+ return m_current_value;
+ }
+
+private:
+ value_type m_current_value;
+ const value_type m_invalid_value;
+ CallbackType m_callback;
+ bool m_callback_called;
+ bool m_invalid_value_is_valid;
+ A0 m_argument;
+
+ // Outlaw default constructor, copy constructor and the assignment operator
+ DISALLOW_COPY_AND_ASSIGN (CleanUp2);
+};
+
+} // namespace lldb_utility
+
+#endif // #ifndef liblldb_CleanUp_h_
diff --git a/include/lldb/Utility/PriorityPointerPair.h b/include/lldb/Utility/PriorityPointerPair.h
new file mode 100644
index 000000000000..49f0765d0f96
--- /dev/null
+++ b/include/lldb/Utility/PriorityPointerPair.h
@@ -0,0 +1,150 @@
+//===-- PriorityPointerPair.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_PriorityPointerPair_h_
+#define liblldb_PriorityPointerPair_h_
+
+#include "lldb/lldb-public.h"
+#include "lldb/Utility/SharingPtr.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+// A prioritized pair of SharedPtr<T>. One of the two pointers is high
+// priority, the other is low priority.
+// The Get() method always returns high, if *high != NULL,
+// otherwise, low is returned (even if *low == NULL)
+//----------------------------------------------------------------------
+
+template<typename T>
+class PriorityPointerPair
+{
+public:
+
+ typedef T& reference_type;
+ typedef T* pointer_type;
+
+ typedef typename std::shared_ptr<T> T_SP;
+
+ PriorityPointerPair() :
+ m_high(),
+ m_low()
+ {}
+
+ PriorityPointerPair(pointer_type high,
+ pointer_type low) :
+ m_high(high),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(pointer_type low) :
+ m_high(),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(T_SP& high,
+ T_SP& low) :
+ m_high(high),
+ m_low(low)
+ {}
+
+ PriorityPointerPair(T_SP& low) :
+ m_high(),
+ m_low(low)
+ {}
+
+ void
+ SwapLow(pointer_type l)
+ {
+ m_low.swap(l);
+ }
+
+ void
+ SwapHigh(pointer_type h)
+ {
+ m_high.swap(h);
+ }
+
+ void
+ SwapLow(T_SP l)
+ {
+ m_low.swap(l);
+ }
+
+ void
+ SwapHigh(T_SP h)
+ {
+ m_high.swap(h);
+ }
+
+ T_SP
+ GetLow()
+ {
+ return m_low;
+ }
+
+ T_SP
+ GetHigh()
+ {
+ return m_high;
+ }
+
+ T_SP
+ Get()
+ {
+ if (m_high.get())
+ return m_high;
+ return m_low;
+ }
+
+ void
+ ResetHigh()
+ {
+ m_high.reset();
+ }
+
+ void
+ ResetLow()
+ {
+ m_low.reset();
+ }
+
+ void
+ Reset()
+ {
+ ResetLow();
+ ResetHigh();
+ }
+
+ reference_type
+ operator*() const
+ {
+ return Get().operator*();
+ }
+
+ pointer_type
+ operator->() const
+ {
+ return Get().operator->();
+ }
+
+ ~PriorityPointerPair();
+
+private:
+
+ T_SP m_high;
+ T_SP m_low;
+
+ DISALLOW_COPY_AND_ASSIGN (PriorityPointerPair);
+
+};
+
+} // namespace lldb_utility
+
+#endif // #ifndef liblldb_PriorityPointerPair_h_
diff --git a/include/lldb/Utility/PseudoTerminal.h b/include/lldb/Utility/PseudoTerminal.h
new file mode 100644
index 000000000000..c79800fab75c
--- /dev/null
+++ b/include/lldb/Utility/PseudoTerminal.h
@@ -0,0 +1,266 @@
+//===-- PseudoTerminal.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_PseudoTerminal_h_
+#define liblldb_PseudoTerminal_h_
+#if defined(__cplusplus)
+
+
+#include <fcntl.h>
+#include <string>
+
+#include "lldb/lldb-defines.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+/// @class PseudoTerminal PseudoTerminal.h "lldb/Core/PseudoTerminal.h"
+/// @brief A pseudo terminal helper class.
+///
+/// The pseudo terminal class abtracts the use of pseudo terminals on
+/// the host system.
+//----------------------------------------------------------------------
+class PseudoTerminal
+{
+public:
+ enum
+ {
+ invalid_fd = -1 ///< Invalid file descriptor value
+ };
+
+ //------------------------------------------------------------------
+ /// Default constructor
+ ///
+ /// Constructs this object with invalid master and slave file
+ /// descriptors.
+ //------------------------------------------------------------------
+ PseudoTerminal ();
+
+ //------------------------------------------------------------------
+ /// Destructor
+ ///
+ /// The destructor will close the master and slave file descriptors
+ /// if they are valid and ownwership has not been released using
+ /// one of:
+ /// @li PseudoTerminal::ReleaseMasterFileDescriptor()
+ /// @li PseudoTerminal::ReleaseSaveFileDescriptor()
+ //------------------------------------------------------------------
+ ~PseudoTerminal ();
+
+ //------------------------------------------------------------------
+ /// Close the master file descriptor if it is valid.
+ //------------------------------------------------------------------
+ void
+ CloseMasterFileDescriptor ();
+
+ //------------------------------------------------------------------
+ /// Close the slave file descriptor if it is valid.
+ //------------------------------------------------------------------
+ void
+ CloseSlaveFileDescriptor ();
+
+ //------------------------------------------------------------------
+ /// Fork a child process that uses pseudo terminals for its stdio.
+ ///
+ /// In the parent process, a call to this function results in a pid
+ /// being returned. If the pid is valid, the master file descriptor
+ /// can be used for read/write access to stdio of the child process.
+ ///
+ /// In the child process the stdin/stdout/stderr will already be
+ /// routed to the slave pseudo terminal and the master file
+ /// descriptor will be closed as it is no longer needed by the child
+ /// process.
+ ///
+ /// This class will close the file descriptors for the master/slave
+ /// when the destructor is called. The file handles can be released
+ /// using either:
+ /// @li PseudoTerminal::ReleaseMasterFileDescriptor()
+ /// @li PseudoTerminal::ReleaseSaveFileDescriptor()
+ ///
+ /// @param[out] error
+ /// An pointer to an error that can describe any errors that
+ /// occur. This can be NULL if no error status is desired.
+ ///
+ /// @return
+ /// @li \b Parent process: a child process ID that is greater
+ /// than zero, or -1 if the fork fails.
+ /// @li \b Child process: zero.
+ //------------------------------------------------------------------
+ lldb::pid_t
+ Fork (char *error_str, size_t error_len);
+
+ //------------------------------------------------------------------
+ /// The master file descriptor accessor.
+ ///
+ /// This object retains ownership of the master file descriptor when
+ /// this accessor is used. Users can call the member function
+ /// PseudoTerminal::ReleaseMasterFileDescriptor() if this
+ /// object should release ownership of the slave file descriptor.
+ ///
+ /// @return
+ /// The master file descriptor, or PseudoTerminal::invalid_fd
+ /// if the master file descriptor is not currently valid.
+ ///
+ /// @see PseudoTerminal::ReleaseMasterFileDescriptor()
+ //------------------------------------------------------------------
+ int
+ GetMasterFileDescriptor () const;
+
+ //------------------------------------------------------------------
+ /// The slave file descriptor accessor.
+ ///
+ /// This object retains ownership of the slave file descriptor when
+ /// this accessor is used. Users can call the member function
+ /// PseudoTerminal::ReleaseSlaveFileDescriptor() if this
+ /// object should release ownership of the slave file descriptor.
+ ///
+ /// @return
+ /// The slave file descriptor, or PseudoTerminal::invalid_fd
+ /// if the slave file descriptor is not currently valid.
+ ///
+ /// @see PseudoTerminal::ReleaseSlaveFileDescriptor()
+ //------------------------------------------------------------------
+ int
+ GetSlaveFileDescriptor () const;
+
+ //------------------------------------------------------------------
+ /// Get the name of the slave pseudo terminal.
+ ///
+ /// A master pseudo terminal should already be valid prior to
+ /// calling this function.
+ ///
+ /// @param[out] error
+ /// An pointer to an error that can describe any errors that
+ /// occur. This can be NULL if no error status is desired.
+ ///
+ /// @return
+ /// The name of the slave pseudo terminal as a NULL terminated
+ /// C. This string that comes from static memory, so a copy of
+ /// the string should be made as subsequent calls can change
+ /// this value. NULL is returned if this object doesn't have
+ /// a valid master pseudo terminal opened or if the call to
+ /// \c ptsname() fails.
+ ///
+ /// @see PseudoTerminal::OpenFirstAvailableMaster()
+ //------------------------------------------------------------------
+ const char*
+ GetSlaveName (char *error_str, size_t error_len) const;
+
+ //------------------------------------------------------------------
+ /// Open the first available pseudo terminal.
+ ///
+ /// Opens the first available pseudo terminal with \a oflag as the
+ /// permissions. The opened master file descriptor is stored in this
+ /// object and can be accessed by calling the
+ /// PseudoTerminal::GetMasterFileDescriptor() accessor. Clients
+ /// can call the PseudoTerminal::ReleaseMasterFileDescriptor()
+ /// accessor function if they wish to use the master file descriptor
+ /// beyond the lifespan of this object.
+ ///
+ /// If this object still has a valid master file descriptor when its
+ /// destructor is called, it will close it.
+ ///
+ /// @param[in] oflag
+ /// Flags to use when calling \c posix_openpt(\a oflag).
+ /// A value of "O_RDWR|O_NOCTTY" is suggested.
+ ///
+ /// @param[out] error
+ /// An pointer to an error that can describe any errors that
+ /// occur. This can be NULL if no error status is desired.
+ ///
+ /// @return
+ /// @li \b true when the a master files descriptor is
+ /// successfully opened.
+ /// @li \b false if anything goes wrong.
+ ///
+ /// @see PseudoTerminal::GetMasterFileDescriptor()
+ /// @see PseudoTerminal::ReleaseMasterFileDescriptor()
+ //------------------------------------------------------------------
+ bool
+ OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len);
+
+ //------------------------------------------------------------------
+ /// Open the slave for the current master pseudo terminal.
+ ///
+ /// A master pseudo terminal should already be valid prior to
+ /// calling this function. The opened slave file descriptor is
+ /// stored in this object and can be accessed by calling the
+ /// PseudoTerminal::GetSlaveFileDescriptor() accessor. Clients
+ /// can call the PseudoTerminal::ReleaseSlaveFileDescriptor()
+ /// accessor function if they wish to use the slave file descriptor
+ /// beyond the lifespan of this object.
+ ///
+ /// If this object still has a valid slave file descriptor when its
+ /// destructor is called, it will close it.
+ ///
+ /// @param[in] oflag
+ /// Flags to use when calling \c open(\a oflag).
+ ///
+ /// @param[out] error
+ /// An pointer to an error that can describe any errors that
+ /// occur. This can be NULL if no error status is desired.
+ ///
+ /// @return
+ /// @li \b true when the a master files descriptor is
+ /// successfully opened.
+ /// @li \b false if anything goes wrong.
+ ///
+ /// @see PseudoTerminal::OpenFirstAvailableMaster()
+ /// @see PseudoTerminal::GetSlaveFileDescriptor()
+ /// @see PseudoTerminal::ReleaseSlaveFileDescriptor()
+ //------------------------------------------------------------------
+ bool
+ OpenSlave (int oflag, char *error_str, size_t error_len);
+
+ //------------------------------------------------------------------
+ /// Release the master file descriptor.
+ ///
+ /// Releases ownership of the master pseudo terminal file descriptor
+ /// without closing it. The destructor for this class will close the
+ /// master file descriptor if the ownership isn't released using this
+ /// call and the master file descriptor has been opened.
+ ///
+ /// @return
+ /// The master file descriptor, or PseudoTerminal::invalid_fd
+ /// if the mast file descriptor is not currently valid.
+ //------------------------------------------------------------------
+ int
+ ReleaseMasterFileDescriptor ();
+
+ //------------------------------------------------------------------
+ /// Release the slave file descriptor.
+ ///
+ /// Release ownership of the slave pseudo terminal file descriptor
+ /// without closing it. The destructor for this class will close the
+ /// slave file descriptor if the ownership isn't released using this
+ /// call and the slave file descriptor has been opened.
+ ///
+ /// @return
+ /// The slave file descriptor, or PseudoTerminal::invalid_fd
+ /// if the slave file descriptor is not currently valid.
+ //------------------------------------------------------------------
+ int
+ ReleaseSlaveFileDescriptor ();
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ int m_master_fd; ///< The file descriptor for the master.
+ int m_slave_fd; ///< The file descriptor for the slave.
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PseudoTerminal);
+
+};
+
+} // namespace lldb
+
+#endif // #if defined(__cplusplus)
+#endif // #ifndef liblldb_PseudoTerminal_h_
diff --git a/include/lldb/Utility/PythonPointer.h b/include/lldb/Utility/PythonPointer.h
new file mode 100644
index 000000000000..f782f7f1313c
--- /dev/null
+++ b/include/lldb/Utility/PythonPointer.h
@@ -0,0 +1,77 @@
+//===---------------------PythonPointer.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_PythonPointer_h_
+#define utility_PythonPointer_h_
+
+#include <algorithm>
+
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+namespace lldb_private {
+
+template<class T>
+class PythonPointer
+{
+public:
+ typedef PyObject* element_type;
+private:
+ element_type* ptr_;
+ bool my_ref;
+public:
+
+ PythonPointer(element_type p, bool steal_ref = false) :
+ ptr_(p),
+ my_ref(!steal_ref)
+ {
+ if (my_ref)
+ Py_INCREF(ptr_);
+ }
+
+ PythonPointer(const PythonPointer& r, bool steal_ref = false) :
+ ptr_(r.ptr_),
+ my_ref(!steal_ref)
+ {
+ if (my_ref)
+ Py_INCREF(ptr_);
+ }
+
+ ~PythonPointer()
+ {
+ if (my_ref)
+ Py_XDECREF(ptr_);
+ }
+
+ PythonPointer
+ StealReference()
+ {
+ return PythonPointer(ptr_,true);
+ }
+
+ PythonPointer
+ DuplicateReference()
+ {
+ return PythonPointer(ptr_, false);
+ }
+
+ element_type get() const {return ptr_;}
+
+ bool IsNull() { return ptr_ == NULL; }
+ bool IsNone() { return ptr_ == Py_None; }
+
+ operator PyObject* () { return ptr_; }
+};
+
+} // namespace lldb
+
+#endif // utility_PythonPointer_h_
diff --git a/include/lldb/Utility/Range.h b/include/lldb/Utility/Range.h
new file mode 100644
index 000000000000..1257adb719a1
--- /dev/null
+++ b/include/lldb/Utility/Range.h
@@ -0,0 +1,89 @@
+//===--------------------- Range.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_Range_h_
+#define utility_Range_h_
+
+#include <stdint.h>
+#include <algorithm>
+
+namespace lldb_utility {
+
+class Range
+{
+public:
+
+ typedef uint64_t ValueType;
+
+ static const ValueType OPEN_END = UINT64_MAX;
+
+ Range (const Range& rng);
+
+ Range (ValueType low = 0,
+ ValueType high = OPEN_END);
+
+ Range&
+ operator = (const Range& rhs);
+
+ ValueType
+ GetLow ()
+ {
+ return m_low;
+ }
+
+ ValueType
+ GetHigh ()
+ {
+ return m_high;
+ }
+
+ void
+ SetLow (ValueType low)
+ {
+ m_low = low;
+ }
+
+ void
+ SetHigh (ValueType high)
+ {
+ m_high = high;
+ }
+
+ void
+ Flip ();
+
+ void
+ Intersection (const Range& other);
+
+ void
+ Union (const Range& other);
+
+ typedef bool (*RangeCallback)(ValueType index);
+
+ void
+ Iterate (RangeCallback callback);
+
+ ValueType
+ GetSize ();
+
+ bool
+ IsEmpty ();
+
+private:
+
+ void
+ InitRange ();
+
+ ValueType m_low;
+ ValueType m_high;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef utility_Range_h_
diff --git a/include/lldb/Utility/RefCounter.h b/include/lldb/Utility/RefCounter.h
new file mode 100644
index 000000000000..6daed5498eb8
--- /dev/null
+++ b/include/lldb/Utility/RefCounter.h
@@ -0,0 +1,56 @@
+//===-- RefCounter.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_RefCounter_h_
+#define liblldb_RefCounter_h_
+
+#include "lldb/lldb-public.h"
+
+namespace lldb_utility {
+
+//----------------------------------------------------------------------
+// A simple reference counter object. You need an uint32_t* to use it
+// Once that is in place, everyone who needs to ref-count, can say
+// RefCounter ref(ptr);
+// (of course, the pointer is a shared resource, and must be accessible to
+// everyone who needs it). Synchronization is handled by RefCounter itself
+// The counter is decreased each time a RefCounter to it goes out of scope
+//----------------------------------------------------------------------
+class RefCounter
+{
+public:
+ typedef uint32_t value_type;
+
+ RefCounter(value_type* ctr);
+
+ ~RefCounter();
+
+private:
+ value_type* m_counter;
+ DISALLOW_COPY_AND_ASSIGN (RefCounter);
+
+ template <class T>
+ inline T
+ increment(T* t)
+ {
+ return __sync_fetch_and_add(t, 1);
+ }
+
+ template <class T>
+ inline T
+ decrement(T* t)
+ {
+ return __sync_fetch_and_add(t, -1);
+ }
+
+};
+
+} // namespace lldb_utility
+
+#endif // #ifndef liblldb_RefCounter_h_
diff --git a/include/lldb/Utility/SharedCluster.h b/include/lldb/Utility/SharedCluster.h
new file mode 100644
index 000000000000..991af4b4fa49
--- /dev/null
+++ b/include/lldb/Utility/SharedCluster.h
@@ -0,0 +1,108 @@
+//===------------------SharedCluster.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_SharedCluster_h_
+#define utility_SharedCluster_h_
+
+#include "lldb/Utility/SharingPtr.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private {
+
+namespace imp
+{
+ template <typename T>
+ class shared_ptr_refcount : public lldb_private::imp::shared_count
+ {
+ public:
+ template<class Y> shared_ptr_refcount (Y *in) : shared_count (0), manager(in) {}
+
+ shared_ptr_refcount() : shared_count (0) {}
+
+ virtual ~shared_ptr_refcount ()
+ {
+ }
+
+ virtual void on_zero_shared ()
+ {
+ manager->DecrementRefCount();
+ }
+ private:
+ T *manager;
+ };
+
+} // namespace imp
+
+template <class T>
+class ClusterManager
+{
+public:
+ ClusterManager () :
+ m_objects(),
+ m_external_ref(0),
+ m_mutex(Mutex::eMutexTypeNormal) {}
+
+ ~ClusterManager ()
+ {
+ size_t n_items = m_objects.size();
+ for (size_t i = 0; i < n_items; i++)
+ {
+ delete m_objects[i];
+ }
+ // Decrement refcount should have been called on this ClusterManager,
+ // and it should have locked the mutex, now we will unlock it before
+ // we destroy it...
+ m_mutex.Unlock();
+ }
+
+ void ManageObject (T *new_object)
+ {
+ Mutex::Locker locker (m_mutex);
+ if (!ContainsObject(new_object))
+ m_objects.push_back (new_object);
+ }
+
+ typename lldb_private::SharingPtr<T> GetSharedPointer(T *desired_object)
+ {
+ {
+ Mutex::Locker locker (m_mutex);
+ m_external_ref++;
+ assert (ContainsObject(desired_object));
+ }
+ return typename lldb_private::SharingPtr<T> (desired_object, new imp::shared_ptr_refcount<ClusterManager> (this));
+ }
+
+private:
+
+ bool ContainsObject (const T *desired_object)
+ {
+ typename std::vector<T *>::iterator pos, end = m_objects.end();
+ pos = std::find(m_objects.begin(), end, desired_object);
+ return pos != end;
+ }
+
+ void DecrementRefCount ()
+ {
+ m_mutex.Lock();
+ m_external_ref--;
+ if (m_external_ref == 0)
+ delete this;
+ else
+ m_mutex.Unlock();
+ }
+
+ friend class imp::shared_ptr_refcount<ClusterManager>;
+
+ std::vector<T *> m_objects;
+ int m_external_ref;
+ Mutex m_mutex;
+};
+
+} // namespace lldb_private
+#endif // utility_SharedCluster_h_
diff --git a/include/lldb/Utility/SharingPtr.h b/include/lldb/Utility/SharingPtr.h
new file mode 100644
index 000000000000..814b54b5cfe6
--- /dev/null
+++ b/include/lldb/Utility/SharingPtr.h
@@ -0,0 +1,816 @@
+//===---------------------SharingPtr.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_SharingPtr_h_
+#define utility_SharingPtr_h_
+
+#include <algorithm>
+#include <memory>
+
+//#define ENABLE_SP_LOGGING 1 // DON'T CHECK THIS LINE IN UNLESS COMMENTED OUT
+#if defined (ENABLE_SP_LOGGING)
+
+extern "C" void track_sp (void *sp_this, void *ptr, long count);
+
+#endif
+
+namespace lldb_private {
+
+namespace imp {
+
+template <class T>
+inline T
+increment(T& t)
+{
+ return __sync_add_and_fetch(&t, 1);
+}
+
+template <class T>
+inline T
+decrement(T& t)
+{
+ return __sync_add_and_fetch(&t, -1);
+}
+
+class shared_count
+{
+ shared_count(const shared_count&);
+ shared_count& operator=(const shared_count&);
+
+protected:
+ long shared_owners_;
+ virtual ~shared_count();
+private:
+ virtual void on_zero_shared() = 0;
+
+public:
+ explicit shared_count(long refs = 0)
+ : shared_owners_(refs) {}
+
+ void add_shared();
+ void release_shared();
+ long use_count() const {return shared_owners_ + 1;}
+};
+
+template <class T>
+class shared_ptr_pointer
+ : public shared_count
+{
+ T data_;
+public:
+ shared_ptr_pointer(T p)
+ : data_(p) {}
+
+private:
+ virtual void on_zero_shared();
+
+ // Outlaw copy constructor and assignment operator to keep effictive C++
+ // warnings down to a minumum
+ shared_ptr_pointer (const shared_ptr_pointer &);
+ shared_ptr_pointer & operator=(const shared_ptr_pointer &);
+};
+
+template <class T>
+void
+shared_ptr_pointer<T>::on_zero_shared()
+{
+ delete data_;
+}
+
+template <class T>
+class shared_ptr_emplace
+ : public shared_count
+{
+ T data_;
+public:
+
+ shared_ptr_emplace()
+ : data_() {}
+
+ template <class A0>
+ shared_ptr_emplace(A0& a0)
+ : data_(a0) {}
+
+ template <class A0, class A1>
+ shared_ptr_emplace(A0& a0, A1& a1)
+ : data_(a0, a1) {}
+
+ template <class A0, class A1, class A2>
+ shared_ptr_emplace(A0& a0, A1& a1, A2& a2)
+ : data_(a0, a1, a2) {}
+
+ template <class A0, class A1, class A2, class A3>
+ shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3)
+ : data_(a0, a1, a2, a3) {}
+
+ template <class A0, class A1, class A2, class A3, class A4>
+ shared_ptr_emplace(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
+ : data_(a0, a1, a2, a3, a4) {}
+
+private:
+ virtual void on_zero_shared();
+public:
+ T* get() {return &data_;}
+};
+
+template <class T>
+void
+shared_ptr_emplace<T>::on_zero_shared()
+{
+}
+
+} // namespace
+
+template<class T>
+class SharingPtr
+{
+public:
+ typedef T element_type;
+private:
+ element_type* ptr_;
+ imp::shared_count* cntrl_;
+
+ struct nat {int for_bool_;};
+public:
+ SharingPtr();
+ template<class Y> explicit SharingPtr(Y* p);
+ template<class Y> explicit SharingPtr(Y* p, imp::shared_count *ctrl_block);
+ template<class Y> SharingPtr(const SharingPtr<Y>& r, element_type *p);
+ SharingPtr(const SharingPtr& r);
+ template<class Y>
+ SharingPtr(const SharingPtr<Y>& r);
+
+ ~SharingPtr();
+
+ SharingPtr& operator=(const SharingPtr& r);
+ template<class Y> SharingPtr& operator=(const SharingPtr<Y>& r);
+
+ void swap(SharingPtr& r);
+ void reset();
+ template<class Y> void reset(Y* p);
+
+ element_type* get() const {return ptr_;}
+ element_type& operator*() const {return *ptr_;}
+ element_type* operator->() const {return ptr_;}
+ long use_count() const {return cntrl_ ? cntrl_->use_count() : 0;}
+ bool unique() const {return use_count() == 1;}
+ bool empty() const {return cntrl_ == 0;}
+ operator nat*() const {return (nat*)get();}
+
+ static SharingPtr<T> make_shared();
+
+ template<class A0>
+ static SharingPtr<T> make_shared(A0&);
+
+ template<class A0, class A1>
+ static SharingPtr<T> make_shared(A0&, A1&);
+
+ template<class A0, class A1, class A2>
+ static SharingPtr<T> make_shared(A0&, A1&, A2&);
+
+ template<class A0, class A1, class A2, class A3>
+ static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&);
+
+ template<class A0, class A1, class A2, class A3, class A4>
+ static SharingPtr<T> make_shared(A0&, A1&, A2&, A3&, A4&);
+
+private:
+
+ template <class U> friend class SharingPtr;
+};
+
+template<class T>
+inline
+SharingPtr<T>::SharingPtr()
+ : ptr_(0),
+ cntrl_(0)
+{
+}
+
+template<class T>
+template<class Y>
+SharingPtr<T>::SharingPtr(Y* p)
+ : ptr_(p), cntrl_(0)
+{
+ std::unique_ptr<Y> hold(p);
+ typedef imp::shared_ptr_pointer<Y*> _CntrlBlk;
+ cntrl_ = new _CntrlBlk(p);
+ hold.release();
+}
+
+template<class T>
+template<class Y>
+SharingPtr<T>::SharingPtr(Y* p, imp::shared_count *cntrl_block)
+ : ptr_(p), cntrl_(cntrl_block)
+{
+}
+
+template<class T>
+template<class Y>
+inline
+SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r, element_type *p)
+ : ptr_(p),
+ cntrl_(r.cntrl_)
+{
+ if (cntrl_)
+ cntrl_->add_shared();
+}
+
+template<class T>
+inline
+SharingPtr<T>::SharingPtr(const SharingPtr& r)
+ : ptr_(r.ptr_),
+ cntrl_(r.cntrl_)
+{
+ if (cntrl_)
+ cntrl_->add_shared();
+}
+
+template<class T>
+template<class Y>
+inline
+SharingPtr<T>::SharingPtr(const SharingPtr<Y>& r)
+ : ptr_(r.ptr_),
+ cntrl_(r.cntrl_)
+{
+ if (cntrl_)
+ cntrl_->add_shared();
+}
+
+template<class T>
+SharingPtr<T>::~SharingPtr()
+{
+ if (cntrl_)
+ cntrl_->release_shared();
+}
+
+template<class T>
+inline
+SharingPtr<T>&
+SharingPtr<T>::operator=(const SharingPtr& r)
+{
+ SharingPtr(r).swap(*this);
+ return *this;
+}
+
+template<class T>
+template<class Y>
+inline
+SharingPtr<T>&
+SharingPtr<T>::operator=(const SharingPtr<Y>& r)
+{
+ SharingPtr(r).swap(*this);
+ return *this;
+}
+
+template<class T>
+inline
+void
+SharingPtr<T>::swap(SharingPtr& r)
+{
+ std::swap(ptr_, r.ptr_);
+ std::swap(cntrl_, r.cntrl_);
+}
+
+template<class T>
+inline
+void
+SharingPtr<T>::reset()
+{
+ SharingPtr().swap(*this);
+}
+
+template<class T>
+template<class Y>
+inline
+void
+SharingPtr<T>::reset(Y* p)
+{
+ SharingPtr(p).swap(*this);
+}
+
+template<class T>
+SharingPtr<T>
+SharingPtr<T>::make_shared()
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk();
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+template<class A0>
+SharingPtr<T>
+SharingPtr<T>::make_shared(A0& a0)
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk(a0);
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+template<class A0, class A1>
+SharingPtr<T>
+SharingPtr<T>::make_shared(A0& a0, A1& a1)
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk(a0, a1);
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+template<class A0, class A1, class A2>
+SharingPtr<T>
+SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2)
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk(a0, a1, a2);
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+template<class A0, class A1, class A2, class A3>
+SharingPtr<T>
+SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3)
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk(a0, a1, a2, a3);
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+template<class A0, class A1, class A2, class A3, class A4>
+SharingPtr<T>
+SharingPtr<T>::make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
+{
+ typedef imp::shared_ptr_emplace<T> CntrlBlk;
+ SharingPtr<T> r;
+ r.cntrl_ = new CntrlBlk(a0, a1, a2, a3, a4);
+ r.ptr_ = static_cast<CntrlBlk*>(r.cntrl_)->get();
+ return r;
+}
+
+template<class T>
+inline
+SharingPtr<T>
+make_shared()
+{
+ return SharingPtr<T>::make_shared();
+}
+
+template<class T, class A0>
+inline
+SharingPtr<T>
+make_shared(A0& a0)
+{
+ return SharingPtr<T>::make_shared(a0);
+}
+
+template<class T, class A0, class A1>
+inline
+SharingPtr<T>
+make_shared(A0& a0, A1& a1)
+{
+ return SharingPtr<T>::make_shared(a0, a1);
+}
+
+template<class T, class A0, class A1, class A2>
+inline
+SharingPtr<T>
+make_shared(A0& a0, A1& a1, A2& a2)
+{
+ return SharingPtr<T>::make_shared(a0, a1, a2);
+}
+
+template<class T, class A0, class A1, class A2, class A3>
+inline
+SharingPtr<T>
+make_shared(A0& a0, A1& a1, A2& a2, A3& a3)
+{
+ return SharingPtr<T>::make_shared(a0, a1, a2, a3);
+}
+
+template<class T, class A0, class A1, class A2, class A3, class A4>
+inline
+SharingPtr<T>
+make_shared(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4)
+{
+ return SharingPtr<T>::make_shared(a0, a1, a2, a3, a4);
+}
+
+
+template<class T, class U>
+inline
+bool
+operator==(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
+{
+ return __x.get() == __y.get();
+}
+
+template<class T, class U>
+inline
+bool
+operator!=(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
+{
+ return !(__x == __y);
+}
+
+template<class T, class U>
+inline
+bool
+operator<(const SharingPtr<T>& __x, const SharingPtr<U>& __y)
+{
+ return __x.get() < __y.get();
+}
+
+template<class T>
+inline
+void
+swap(SharingPtr<T>& __x, SharingPtr<T>& __y)
+{
+ __x.swap(__y);
+}
+
+template<class T, class U>
+inline
+SharingPtr<T>
+static_pointer_cast(const SharingPtr<U>& r)
+{
+ return SharingPtr<T>(r, static_cast<T*>(r.get()));
+}
+
+template<class T, class U>
+SharingPtr<T>
+const_pointer_cast(const SharingPtr<U>& r)
+{
+ return SharingPtr<T>(r, const_cast<T*>(r.get()));
+}
+
+template <class T>
+class LoggingSharingPtr
+ : public SharingPtr<T>
+{
+ typedef SharingPtr<T> base;
+
+public:
+ typedef void (*Callback)(void*, const LoggingSharingPtr&, bool action);
+ // action: false means increment just happened
+ // true means decrement is about to happen
+
+private:
+ Callback cb_;
+ void* baton_;
+
+public:
+ LoggingSharingPtr() : cb_(0), baton_(0) {}
+ LoggingSharingPtr(Callback cb, void* baton)
+ : cb_(cb), baton_(baton)
+ {
+ if (cb_)
+ cb_(baton_, *this, false);
+ }
+
+ template <class Y>
+ LoggingSharingPtr(Y* p)
+ : base(p), cb_(0), baton_(0) {}
+
+ template <class Y>
+ LoggingSharingPtr(Y* p, Callback cb, void* baton)
+ : base(p), cb_(cb), baton_(baton)
+ {
+ if (cb_)
+ cb_(baton_, *this, false);
+ }
+
+ ~LoggingSharingPtr()
+ {
+ if (cb_)
+ cb_(baton_, *this, true);
+ }
+
+ LoggingSharingPtr(const LoggingSharingPtr& p)
+ : base(p), cb_(p.cb_), baton_(p.baton_)
+ {
+ if (cb_)
+ cb_(baton_, *this, false);
+ }
+
+ LoggingSharingPtr& operator=(const LoggingSharingPtr& p)
+ {
+ if (cb_)
+ cb_(baton_, *this, true);
+ base::operator=(p);
+ cb_ = p.cb_;
+ baton_ = p.baton_;
+ if (cb_)
+ cb_(baton_, *this, false);
+ return *this;
+ }
+
+ void reset()
+ {
+ if (cb_)
+ cb_(baton_, *this, true);
+ base::reset();
+ }
+
+ template <class Y>
+ void reset(Y* p)
+ {
+ if (cb_)
+ cb_(baton_, *this, true);
+ base::reset(p);
+ if (cb_)
+ cb_(baton_, *this, false);
+ }
+
+ void SetCallback(Callback cb, void* baton)
+ {
+ cb_ = cb;
+ baton_ = baton;
+ }
+
+ void ClearCallback()
+ {
+ cb_ = 0;
+ baton_ = 0;
+ }
+};
+
+
+template <class T>
+class IntrusiveSharingPtr;
+
+template <class T>
+class ReferenceCountedBase
+{
+public:
+ explicit ReferenceCountedBase()
+ : shared_owners_(-1)
+ {
+ }
+
+ void
+ add_shared();
+
+ void
+ release_shared();
+
+ long
+ use_count() const
+ {
+ return shared_owners_ + 1;
+ }
+
+protected:
+ long shared_owners_;
+
+ friend class IntrusiveSharingPtr<T>;
+
+private:
+ ReferenceCountedBase(const ReferenceCountedBase&);
+ ReferenceCountedBase& operator=(const ReferenceCountedBase&);
+};
+
+ template <class T>
+ void
+ lldb_private::ReferenceCountedBase<T>::add_shared()
+ {
+ imp::increment(shared_owners_);
+ }
+
+ template <class T>
+ void
+ lldb_private::ReferenceCountedBase<T>::release_shared()
+ {
+ if (imp::decrement(shared_owners_) == -1)
+ delete static_cast<T*>(this);
+ }
+
+
+template <class T>
+class ReferenceCountedBaseVirtual : public imp::shared_count
+{
+public:
+ explicit ReferenceCountedBaseVirtual () :
+ imp::shared_count(-1)
+ {
+ }
+
+ virtual
+ ~ReferenceCountedBaseVirtual ()
+ {
+ }
+
+ virtual void on_zero_shared ();
+
+};
+
+template <class T>
+void
+ReferenceCountedBaseVirtual<T>::on_zero_shared()
+{
+}
+
+template <typename T>
+class IntrusiveSharingPtr
+{
+public:
+ typedef T element_type;
+
+ explicit
+ IntrusiveSharingPtr () :
+ ptr_(0)
+ {
+ }
+
+ explicit
+ IntrusiveSharingPtr (T* ptr) :
+ ptr_(ptr)
+ {
+ add_shared();
+ }
+
+ IntrusiveSharingPtr (const IntrusiveSharingPtr& rhs) :
+ ptr_(rhs.ptr_)
+ {
+ add_shared();
+ }
+
+ template <class X>
+ IntrusiveSharingPtr (const IntrusiveSharingPtr<X>& rhs)
+ : ptr_(rhs.get())
+ {
+ add_shared();
+ }
+
+ IntrusiveSharingPtr&
+ operator= (const IntrusiveSharingPtr& rhs)
+ {
+ reset(rhs.get());
+ return *this;
+ }
+
+ template <class X> IntrusiveSharingPtr&
+ operator= (const IntrusiveSharingPtr<X>& rhs)
+ {
+ reset(rhs.get());
+ return *this;
+ }
+
+ IntrusiveSharingPtr&
+ operator= (T *ptr)
+ {
+ reset(ptr);
+ return *this;
+ }
+
+ ~IntrusiveSharingPtr()
+ {
+ release_shared();
+#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ // NULL out the pointer in objects which can help with leaks detection.
+ // We don't enable this for LLDB_CONFIGURATION_BUILD_AND_INTEGRATION or
+ // when none of the LLDB_CONFIGURATION_XXX macros are defined since
+ // those would be builds for release. But for debug and release builds
+ // that are for development, we NULL out the pointers to catch potential
+ // issues.
+ ptr_ = NULL;
+#endif // #if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ }
+
+ T&
+ operator*() const
+ {
+ return *ptr_;
+ }
+
+ T*
+ operator->() const
+ {
+ return ptr_;
+ }
+
+ T*
+ get() const
+ {
+ return ptr_;
+ }
+
+ operator bool() const
+ {
+ return ptr_ != 0;
+ }
+
+ void
+ swap (IntrusiveSharingPtr& rhs)
+ {
+ std::swap(ptr_, rhs.ptr_);
+#if defined (ENABLE_SP_LOGGING)
+ track_sp (this, ptr_, use_count());
+ track_sp (&rhs, rhs.ptr_, rhs.use_count());
+#endif
+ }
+
+ void
+ reset(T* ptr = NULL)
+ {
+ IntrusiveSharingPtr(ptr).swap(*this);
+ }
+
+ long
+ use_count () const
+ {
+ if (ptr_)
+ return ptr_->use_count();
+ return 0;
+ }
+
+ bool
+ unique () const
+ {
+ return use_count () == 1;
+ }
+
+private:
+ element_type *ptr_;
+
+ void
+ add_shared()
+ {
+ if (ptr_)
+ {
+ ptr_->add_shared();
+#if defined (ENABLE_SP_LOGGING)
+ track_sp (this, ptr_, ptr_->use_count());
+#endif
+ }
+ }
+ void
+ release_shared()
+ {
+ if (ptr_)
+ {
+#if defined (ENABLE_SP_LOGGING)
+ track_sp (this, NULL, ptr_->use_count() - 1);
+#endif
+ ptr_->release_shared();
+ }
+ }
+};
+
+template<class T, class U>
+inline bool operator== (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
+{
+ return lhs.get() == rhs.get();
+}
+
+template<class T, class U>
+inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, const IntrusiveSharingPtr<U>& rhs)
+{
+ return lhs.get() != rhs.get();
+}
+
+template<class T, class U>
+inline bool operator== (const IntrusiveSharingPtr<T>& lhs, U* rhs)
+{
+ return lhs.get() == rhs;
+}
+
+template<class T, class U>
+inline bool operator!= (const IntrusiveSharingPtr<T>& lhs, U* rhs)
+{
+ return lhs.get() != rhs;
+}
+
+template<class T, class U>
+inline bool operator== (T* lhs, const IntrusiveSharingPtr<U>& rhs)
+{
+ return lhs == rhs.get();
+}
+
+template<class T, class U>
+inline bool operator!= (T* lhs, const IntrusiveSharingPtr<U>& rhs)
+{
+ return lhs != rhs.get();
+}
+
+} // namespace lldb_private
+
+#endif // utility_SharingPtr_h_
diff --git a/include/lldb/Utility/Utils.h b/include/lldb/Utility/Utils.h
new file mode 100644
index 000000000000..46bc1847c0b7
--- /dev/null
+++ b/include/lldb/Utility/Utils.h
@@ -0,0 +1,22 @@
+//===-- Utils.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_Utils_h_
+#define utility_Utils_h_
+
+// These utilities have llvm namespace.
+#include "llvm/ADT/STLExtras.h"
+
+namespace lldb_private {
+
+// Add lldb utilities here.
+
+} // namespace lldb_private
+
+#endif // utility_Utils
diff --git a/include/lldb/lldb-defines.h b/include/lldb/lldb-defines.h
new file mode 100644
index 000000000000..3318aa15f5ac
--- /dev/null
+++ b/include/lldb/lldb-defines.h
@@ -0,0 +1,125 @@
+//===-- lldb-defines.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_defines_h_
+#define LLDB_lldb_defines_h_
+
+#include "lldb/lldb-types.h"
+
+#if !defined(UINT32_MAX)
+ #define UINT32_MAX 4294967295U
+#endif
+
+#if !defined(UINT64_MAX)
+ #define UINT64_MAX 18446744073709551615ULL
+#endif
+
+//----------------------------------------------------------------------
+// LLDB version
+//
+// A build script phase can modify this version number if needed.
+//----------------------------------------------------------------------
+//#define LLDB_VERSION
+//#define LLDB_REVISION
+//#define LLDB_VERSION_STRING
+
+//----------------------------------------------------------------------
+// LLDB defines
+//----------------------------------------------------------------------
+#define LLDB_GENERIC_ERROR UINT32_MAX
+
+//----------------------------------------------------------------------
+// Breakpoints
+//----------------------------------------------------------------------
+#define LLDB_INVALID_BREAK_ID 0
+#define LLDB_DEFAULT_BREAK_SIZE 0
+#define LLDB_BREAK_ID_IS_VALID(bid) ((bid) != (LLDB_INVALID_BREAK_ID))
+#define LLDB_BREAK_ID_IS_INTERNAL(bid) ((bid) < 0)
+
+//----------------------------------------------------------------------
+// Watchpoints
+//----------------------------------------------------------------------
+#define LLDB_INVALID_WATCH_ID 0
+#define LLDB_WATCH_ID_IS_VALID(uid) ((uid) != (LLDB_INVALID_WATCH_ID))
+#define LLDB_WATCH_TYPE_READ (1u << 0)
+#define LLDB_WATCH_TYPE_WRITE (1u << 1)
+#define LLDB_WATCH_TYPE_IS_VALID(type) ((type | LLDB_WATCH_TYPE_READ) || (type | LLDB_WATCH_TYPE_WRITE))
+
+//----------------------------------------------------------------------
+// Generic Register Numbers
+//----------------------------------------------------------------------
+#define LLDB_REGNUM_GENERIC_PC 0 // Program Counter
+#define LLDB_REGNUM_GENERIC_SP 1 // Stack Pointer
+#define LLDB_REGNUM_GENERIC_FP 2 // Frame Pointer
+#define LLDB_REGNUM_GENERIC_RA 3 // Return Address
+#define LLDB_REGNUM_GENERIC_FLAGS 4 // Processor flags register
+#define LLDB_REGNUM_GENERIC_ARG1 5 // The register that would contain pointer size or less argument 1 (if any)
+#define LLDB_REGNUM_GENERIC_ARG2 6 // The register that would contain pointer size or less argument 2 (if any)
+#define LLDB_REGNUM_GENERIC_ARG3 7 // The register that would contain pointer size or less argument 3 (if any)
+#define LLDB_REGNUM_GENERIC_ARG4 8 // The register that would contain pointer size or less argument 4 (if any)
+#define LLDB_REGNUM_GENERIC_ARG5 9 // The register that would contain pointer size or less argument 5 (if any)
+#define LLDB_REGNUM_GENERIC_ARG6 10 // The register that would contain pointer size or less argument 6 (if any)
+#define LLDB_REGNUM_GENERIC_ARG7 11 // The register that would contain pointer size or less argument 7 (if any)
+#define LLDB_REGNUM_GENERIC_ARG8 12 // The register that would contain pointer size or less argument 8 (if any)
+//---------------------------------------------------------------------
+/// Invalid value definitions
+//----------------------------------------------------------------------
+#define LLDB_INVALID_ADDRESS UINT64_MAX
+#define LLDB_INVALID_INDEX32 UINT32_MAX
+#define LLDB_INVALID_IVAR_OFFSET UINT32_MAX
+#define LLDB_INVALID_IMAGE_TOKEN UINT32_MAX
+#define LLDB_INVALID_REGNUM UINT32_MAX
+#define LLDB_INVALID_UID UINT64_MAX
+#define LLDB_INVALID_PROCESS_ID 0
+#define LLDB_INVALID_THREAD_ID 0
+#define LLDB_INVALID_FRAME_ID UINT32_MAX
+#define LLDB_INVALID_SIGNAL_NUMBER INT32_MAX
+#define LLDB_INVALID_OFFSET UINT64_MAX // Must match max of lldb::offset_t
+
+//----------------------------------------------------------------------
+/// CPU Type defintions
+//----------------------------------------------------------------------
+#define LLDB_ARCH_DEFAULT "systemArch"
+#define LLDB_ARCH_DEFAULT_32BIT "systemArch32"
+#define LLDB_ARCH_DEFAULT_64BIT "systemArch64"
+#define LLDB_INVALID_CPUTYPE (0xFFFFFFFEu)
+
+//----------------------------------------------------------------------
+/// Option Set defintions
+//----------------------------------------------------------------------
+// FIXME: I'm sure there's some #define magic that can create all 32 sets on the
+// fly. That would have the added benefit of making this unreadable.
+#define LLDB_MAX_NUM_OPTION_SETS 32
+#define LLDB_OPT_SET_ALL 0xFFFFFFFFU
+#define LLDB_OPT_SET_1 (1U << 0)
+#define LLDB_OPT_SET_2 (1U << 1)
+#define LLDB_OPT_SET_3 (1U << 2)
+#define LLDB_OPT_SET_4 (1U << 3)
+#define LLDB_OPT_SET_5 (1U << 4)
+#define LLDB_OPT_SET_6 (1U << 5)
+#define LLDB_OPT_SET_7 (1U << 6)
+#define LLDB_OPT_SET_8 (1U << 7)
+#define LLDB_OPT_SET_9 (1U << 8)
+#define LLDB_OPT_SET_10 (1U << 9)
+#define LLDB_OPT_SET_FROM_TO(A, B) (((1U << (B)) - 1) ^ (((1U << (A))-1) >> 1))
+
+#if defined(__cplusplus)
+
+//----------------------------------------------------------------------
+/// @def DISALLOW_COPY_AND_ASSIGN(TypeName)
+/// Macro definition for easily disallowing copy constructor and
+/// assignment operators in C++ classes.
+//----------------------------------------------------------------------
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ const TypeName& operator=(const TypeName&)
+
+#endif // #if defined(__cplusplus)
+
+#endif // LLDB_lldb_defines_h_
diff --git a/include/lldb/lldb-enumerations.h b/include/lldb/lldb-enumerations.h
new file mode 100644
index 000000000000..6ec5ed6a35e2
--- /dev/null
+++ b/include/lldb/lldb-enumerations.h
@@ -0,0 +1,685 @@
+//===-- lldb-enumerations.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_enumerations_h_
+#define LLDB_lldb_enumerations_h_
+
+namespace lldb {
+
+ //----------------------------------------------------------------------
+ // Process and Thread States
+ //----------------------------------------------------------------------
+ typedef enum StateType
+ {
+ eStateInvalid = 0,
+ eStateUnloaded, ///< Process is object is valid, but not currently loaded
+ eStateConnected, ///< Process is connected to remote debug services, but not launched or attached to anything yet
+ eStateAttaching, ///< Process is currently trying to attach
+ eStateLaunching, ///< Process is in the process of launching
+ eStateStopped, ///< Process or thread is stopped and can be examined.
+ eStateRunning, ///< Process or thread is running and can't be examined.
+ eStateStepping, ///< Process or thread is in the process of stepping and can not be examined.
+ eStateCrashed, ///< Process or thread has crashed and can be examined.
+ eStateDetached, ///< Process has been detached and can't be examined.
+ eStateExited, ///< Process has exited and can't be examined.
+ eStateSuspended ///< Process or thread is in a suspended state as far
+ ///< as the debugger is concerned while other processes
+ ///< or threads get the chance to run.
+ } StateType;
+
+ //----------------------------------------------------------------------
+ // Launch Flags
+ //----------------------------------------------------------------------
+ typedef enum LaunchFlags
+ {
+ eLaunchFlagNone = 0u,
+ eLaunchFlagExec = (1u << 0), ///< Exec when launching and turn the calling process into a new process
+ eLaunchFlagDebug = (1u << 1), ///< Stop as soon as the process launches to allow the process to be debugged
+ eLaunchFlagStopAtEntry = (1u << 2), ///< Stop at the program entry point instead of auto-continuing when launching or attaching at entry point
+ eLaunchFlagDisableASLR = (1u << 3), ///< Disable Address Space Layout Randomization
+ eLaunchFlagDisableSTDIO = (1u << 4), ///< Disable stdio for inferior process (e.g. for a GUI app)
+ eLaunchFlagLaunchInTTY = (1u << 5), ///< Launch the process in a new TTY if supported by the host
+ eLaunchFlagLaunchInShell= (1u << 6), ///< Launch the process inside a shell to get shell expansion
+ eLaunchFlagLaunchInSeparateProcessGroup = (1u << 7) ///< Launch the process in a separate process group
+ } LaunchFlags;
+
+ //----------------------------------------------------------------------
+ // Thread Run Modes
+ //----------------------------------------------------------------------
+ typedef enum RunMode {
+ eOnlyThisThread,
+ eAllThreads,
+ eOnlyDuringStepping
+ } RunMode;
+
+ //----------------------------------------------------------------------
+ // Byte ordering definitions
+ //----------------------------------------------------------------------
+ typedef enum ByteOrder
+ {
+ eByteOrderInvalid = 0,
+ eByteOrderBig = 1,
+ eByteOrderPDP = 2,
+ eByteOrderLittle = 4
+ } ByteOrder;
+
+ //----------------------------------------------------------------------
+ // Register encoding definitions
+ //----------------------------------------------------------------------
+ typedef enum Encoding
+ {
+ eEncodingInvalid = 0,
+ eEncodingUint, // unsigned integer
+ eEncodingSint, // signed integer
+ eEncodingIEEE754, // float
+ eEncodingVector // vector registers
+ } Encoding;
+
+ //----------------------------------------------------------------------
+ // Display format definitions
+ //----------------------------------------------------------------------
+ typedef enum Format
+ {
+ eFormatDefault = 0,
+ eFormatInvalid = 0,
+ eFormatBoolean,
+ eFormatBinary,
+ eFormatBytes,
+ eFormatBytesWithASCII,
+ eFormatChar,
+ eFormatCharPrintable, // Only printable characters, space if not printable
+ eFormatComplex, // Floating point complex type
+ eFormatComplexFloat = eFormatComplex,
+ eFormatCString, // NULL terminated C strings
+ eFormatDecimal,
+ eFormatEnum,
+ eFormatHex,
+ eFormatHexUppercase,
+ eFormatFloat,
+ eFormatOctal,
+ eFormatOSType, // OS character codes encoded into an integer 'PICT' 'text' etc...
+ eFormatUnicode16,
+ eFormatUnicode32,
+ eFormatUnsigned,
+ eFormatPointer,
+ eFormatVectorOfChar,
+ eFormatVectorOfSInt8,
+ eFormatVectorOfUInt8,
+ eFormatVectorOfSInt16,
+ eFormatVectorOfUInt16,
+ eFormatVectorOfSInt32,
+ eFormatVectorOfUInt32,
+ eFormatVectorOfSInt64,
+ eFormatVectorOfUInt64,
+ eFormatVectorOfFloat32,
+ eFormatVectorOfFloat64,
+ eFormatVectorOfUInt128,
+ eFormatComplexInteger, // Integer complex type
+ eFormatCharArray, // Print characters with no single quotes, used for character arrays that can contain non printable characters
+ eFormatAddressInfo, // Describe what an address points to (func + offset with file/line, symbol + offset, data, etc)
+ eFormatHexFloat, // ISO C99 hex float string
+ eFormatInstruction, // Disassemble an opcode
+ eFormatVoid, // Do not print this
+ kNumFormats
+ } Format;
+
+ //----------------------------------------------------------------------
+ // Description levels for "void GetDescription(Stream *, DescriptionLevel)" calls
+ //----------------------------------------------------------------------
+ typedef enum DescriptionLevel
+ {
+ eDescriptionLevelBrief = 0,
+ eDescriptionLevelFull,
+ eDescriptionLevelVerbose,
+ eDescriptionLevelInitial,
+ kNumDescriptionLevels
+ } DescriptionLevel;
+
+ //----------------------------------------------------------------------
+ // Script interpreter types
+ //----------------------------------------------------------------------
+ typedef enum ScriptLanguage
+ {
+ eScriptLanguageNone,
+ eScriptLanguagePython,
+ eScriptLanguageDefault = eScriptLanguagePython
+ } ScriptLanguage;
+
+ //----------------------------------------------------------------------
+ // Register numbering types
+ //----------------------------------------------------------------------
+ typedef enum RegisterKind
+ {
+ eRegisterKindGCC = 0, // the register numbers seen in eh_frame
+ eRegisterKindDWARF, // the register numbers seen DWARF
+ eRegisterKindGeneric, // insn ptr reg, stack ptr reg, etc not specific to any particular target
+ eRegisterKindGDB, // the register numbers gdb uses (matches stabs numbers?)
+ eRegisterKindLLDB, // lldb's internal register numbers
+ kNumRegisterKinds
+ } RegisterKind;
+
+ //----------------------------------------------------------------------
+ // Thread stop reasons
+ //----------------------------------------------------------------------
+ typedef enum StopReason
+ {
+ eStopReasonInvalid = 0,
+ eStopReasonNone,
+ eStopReasonTrace,
+ eStopReasonBreakpoint,
+ eStopReasonWatchpoint,
+ eStopReasonSignal,
+ eStopReasonException,
+ eStopReasonExec, // Program was re-exec'ed
+ eStopReasonPlanComplete,
+ eStopReasonThreadExiting
+ } StopReason;
+
+ //----------------------------------------------------------------------
+ // Command Return Status Types
+ //----------------------------------------------------------------------
+ typedef enum ReturnStatus
+ {
+ eReturnStatusInvalid,
+ eReturnStatusSuccessFinishNoResult,
+ eReturnStatusSuccessFinishResult,
+ eReturnStatusSuccessContinuingNoResult,
+ eReturnStatusSuccessContinuingResult,
+ eReturnStatusStarted,
+ eReturnStatusFailed,
+ eReturnStatusQuit
+ } ReturnStatus;
+
+
+ //----------------------------------------------------------------------
+ // Connection Status Types
+ //----------------------------------------------------------------------
+ typedef enum ConnectionStatus
+ {
+ eConnectionStatusSuccess, // Success
+ eConnectionStatusEndOfFile, // End-of-file encountered
+ eConnectionStatusError, // Check GetError() for details
+ eConnectionStatusTimedOut, // Request timed out
+ eConnectionStatusNoConnection, // No connection
+ eConnectionStatusLostConnection // Lost connection while connected to a valid connection
+ } ConnectionStatus;
+
+ typedef enum ErrorType
+ {
+ eErrorTypeInvalid,
+ eErrorTypeGeneric, ///< Generic errors that can be any value.
+ eErrorTypeMachKernel, ///< Mach kernel error codes.
+ eErrorTypePOSIX ///< POSIX error codes.
+ } ErrorType;
+
+
+ typedef enum ValueType
+ {
+ eValueTypeInvalid = 0,
+ eValueTypeVariableGlobal = 1, // globals variable
+ eValueTypeVariableStatic = 2, // static variable
+ eValueTypeVariableArgument = 3, // function argument variables
+ eValueTypeVariableLocal = 4, // function local variables
+ eValueTypeRegister = 5, // stack frame register value
+ eValueTypeRegisterSet = 6, // A collection of stack frame register values
+ eValueTypeConstResult = 7 // constant result variables
+ } ValueType;
+
+ //----------------------------------------------------------------------
+ // Token size/granularities for Input Readers
+ //----------------------------------------------------------------------
+
+ typedef enum InputReaderGranularity
+ {
+ eInputReaderGranularityInvalid = 0,
+ eInputReaderGranularityByte,
+ eInputReaderGranularityWord,
+ eInputReaderGranularityLine,
+ eInputReaderGranularityAll
+ } InputReaderGranularity;
+
+ //------------------------------------------------------------------
+ /// These mask bits allow a common interface for queries that can
+ /// limit the amount of information that gets parsed to only the
+ /// information that is requested. These bits also can indicate what
+ /// actually did get resolved during query function calls.
+ ///
+ /// Each definition corresponds to a one of the member variables
+ /// in this class, and requests that that item be resolved, or
+ /// indicates that the member did get resolved.
+ //------------------------------------------------------------------
+ typedef enum SymbolContextItem
+ {
+ eSymbolContextTarget = (1u << 0), ///< Set when \a target is requested from a query, or was located in query results
+ eSymbolContextModule = (1u << 1), ///< Set when \a module is requested from a query, or was located in query results
+ eSymbolContextCompUnit = (1u << 2), ///< Set when \a comp_unit is requested from a query, or was located in query results
+ eSymbolContextFunction = (1u << 3), ///< Set when \a function is requested from a query, or was located in query results
+ eSymbolContextBlock = (1u << 4), ///< Set when the deepest \a block is requested from a query, or was located in query results
+ eSymbolContextLineEntry = (1u << 5), ///< Set when \a line_entry is requested from a query, or was located in query results
+ eSymbolContextSymbol = (1u << 6), ///< Set when \a symbol is requested from a query, or was located in query results
+ eSymbolContextEverything = ((eSymbolContextSymbol << 1) - 1u) ///< Indicates to try and lookup everything up during a query.
+ } SymbolContextItem;
+
+ typedef enum Permissions
+ {
+ ePermissionsWritable = (1u << 0),
+ ePermissionsReadable = (1u << 1),
+ ePermissionsExecutable = (1u << 2)
+ } Permissions;
+
+ typedef enum InputReaderAction
+ {
+ eInputReaderActivate, // reader is newly pushed onto the reader stack
+ eInputReaderAsynchronousOutputWritten, // an async output event occurred; the reader may want to do something
+ eInputReaderReactivate, // reader is on top of the stack again after another reader was popped off
+ eInputReaderDeactivate, // another reader was pushed on the stack
+ eInputReaderGotToken, // reader got one of its tokens (granularity)
+ eInputReaderInterrupt, // reader received an interrupt signal (probably from a control-c)
+ eInputReaderEndOfFile, // reader received an EOF char (probably from a control-d)
+ eInputReaderDone // reader was just popped off the stack and is done
+ } InputReaderAction;
+
+ typedef enum BreakpointEventType
+ {
+ eBreakpointEventTypeInvalidType = (1u << 0),
+ eBreakpointEventTypeAdded = (1u << 1),
+ eBreakpointEventTypeRemoved = (1u << 2),
+ eBreakpointEventTypeLocationsAdded = (1u << 3), // Locations added doesn't get sent when the breakpoint is created
+ eBreakpointEventTypeLocationsRemoved = (1u << 4),
+ eBreakpointEventTypeLocationsResolved = (1u << 5),
+ eBreakpointEventTypeEnabled = (1u << 6),
+ eBreakpointEventTypeDisabled = (1u << 7),
+ eBreakpointEventTypeCommandChanged = (1u << 8),
+ eBreakpointEventTypeConditionChanged = (1u << 9),
+ eBreakpointEventTypeIgnoreChanged = (1u << 10),
+ eBreakpointEventTypeThreadChanged = (1u << 11)
+ } BreakpointEventType;
+
+ typedef enum WatchpointEventType
+ {
+ eWatchpointEventTypeInvalidType = (1u << 0),
+ eWatchpointEventTypeAdded = (1u << 1),
+ eWatchpointEventTypeRemoved = (1u << 2),
+ eWatchpointEventTypeEnabled = (1u << 6),
+ eWatchpointEventTypeDisabled = (1u << 7),
+ eWatchpointEventTypeCommandChanged = (1u << 8),
+ eWatchpointEventTypeConditionChanged = (1u << 9),
+ eWatchpointEventTypeIgnoreChanged = (1u << 10),
+ eWatchpointEventTypeThreadChanged = (1u << 11),
+ eWatchpointEventTypeTypeChanged = (1u << 12)
+ } WatchpointEventType;
+
+
+ //----------------------------------------------------------------------
+ /// Programming language type.
+ ///
+ /// These enumerations use the same language enumerations as the DWARF
+ /// specification for ease of use and consistency.
+ /// The enum -> string code is in LanguageRuntime.cpp, don't change this
+ /// table without updating that code as well.
+ //----------------------------------------------------------------------
+ typedef enum LanguageType
+ {
+ eLanguageTypeUnknown = 0x0000, ///< Unknown or invalid language value.
+ eLanguageTypeC89 = 0x0001, ///< ISO C:1989.
+ eLanguageTypeC = 0x0002, ///< Non-standardized C, such as K&R.
+ eLanguageTypeAda83 = 0x0003, ///< ISO Ada:1983.
+ eLanguageTypeC_plus_plus = 0x0004, ///< ISO C++:1998.
+ eLanguageTypeCobol74 = 0x0005, ///< ISO Cobol:1974.
+ eLanguageTypeCobol85 = 0x0006, ///< ISO Cobol:1985.
+ eLanguageTypeFortran77 = 0x0007, ///< ISO Fortran 77.
+ eLanguageTypeFortran90 = 0x0008, ///< ISO Fortran 90.
+ eLanguageTypePascal83 = 0x0009, ///< ISO Pascal:1983.
+ eLanguageTypeModula2 = 0x000a, ///< ISO Modula-2:1996.
+ eLanguageTypeJava = 0x000b, ///< Java.
+ eLanguageTypeC99 = 0x000c, ///< ISO C:1999.
+ eLanguageTypeAda95 = 0x000d, ///< ISO Ada:1995.
+ eLanguageTypeFortran95 = 0x000e, ///< ISO Fortran 95.
+ eLanguageTypePLI = 0x000f, ///< ANSI PL/I:1976.
+ eLanguageTypeObjC = 0x0010, ///< Objective-C.
+ eLanguageTypeObjC_plus_plus = 0x0011, ///< Objective-C++.
+ eLanguageTypeUPC = 0x0012, ///< Unified Parallel C.
+ eLanguageTypeD = 0x0013, ///< D.
+ eLanguageTypePython = 0x0014, ///< Python.
+ eNumLanguageTypes
+ } LanguageType;
+
+ typedef enum DynamicValueType
+ {
+ eNoDynamicValues = 0,
+ eDynamicCanRunTarget = 1,
+ eDynamicDontRunTarget = 2
+ } DynamicValueType;
+
+ typedef enum AccessType
+ {
+ eAccessNone,
+ eAccessPublic,
+ eAccessPrivate,
+ eAccessProtected,
+ eAccessPackage
+ } AccessType;
+
+ typedef enum CommandArgumentType
+ {
+ eArgTypeAddress = 0,
+ eArgTypeAddressOrExpression,
+ eArgTypeAliasName,
+ eArgTypeAliasOptions,
+ eArgTypeArchitecture,
+ eArgTypeBoolean,
+ eArgTypeBreakpointID,
+ eArgTypeBreakpointIDRange,
+ eArgTypeByteSize,
+ eArgTypeClassName,
+ eArgTypeCommandName,
+ eArgTypeCount,
+ eArgTypeDirectoryName,
+ eArgTypeDisassemblyFlavor,
+ eArgTypeEndAddress,
+ eArgTypeExpression,
+ eArgTypeExpressionPath,
+ eArgTypeExprFormat,
+ eArgTypeFilename,
+ eArgTypeFormat,
+ eArgTypeFrameIndex,
+ eArgTypeFullName,
+ eArgTypeFunctionName,
+ eArgTypeFunctionOrSymbol,
+ eArgTypeGDBFormat,
+ eArgTypeIndex,
+ eArgTypeLanguage,
+ eArgTypeLineNum,
+ eArgTypeLogCategory,
+ eArgTypeLogChannel,
+ eArgTypeMethod,
+ eArgTypeName,
+ eArgTypeNewPathPrefix,
+ eArgTypeNumLines,
+ eArgTypeNumberPerLine,
+ eArgTypeOffset,
+ eArgTypeOldPathPrefix,
+ eArgTypeOneLiner,
+ eArgTypePid,
+ eArgTypePlugin,
+ eArgTypeProcessName,
+ eArgTypePythonClass,
+ eArgTypePythonFunction,
+ eArgTypePythonScript,
+ eArgTypeQueueName,
+ eArgTypeRegisterName,
+ eArgTypeRegularExpression,
+ eArgTypeRunArgs,
+ eArgTypeRunMode,
+ eArgTypeScriptedCommandSynchronicity,
+ eArgTypeScriptLang,
+ eArgTypeSearchWord,
+ eArgTypeSelector,
+ eArgTypeSettingIndex,
+ eArgTypeSettingKey,
+ eArgTypeSettingPrefix,
+ eArgTypeSettingVariableName,
+ eArgTypeShlibName,
+ eArgTypeSourceFile,
+ eArgTypeSortOrder,
+ eArgTypeStartAddress,
+ eArgTypeSummaryString,
+ eArgTypeSymbol,
+ eArgTypeThreadID,
+ eArgTypeThreadIndex,
+ eArgTypeThreadName,
+ eArgTypeUnsignedInteger,
+ eArgTypeUnixSignal,
+ eArgTypeVarName,
+ eArgTypeValue,
+ eArgTypeWidth,
+ eArgTypeNone,
+ eArgTypePlatform,
+ eArgTypeWatchpointID,
+ eArgTypeWatchpointIDRange,
+ eArgTypeWatchType,
+ eArgTypeLastArg // Always keep this entry as the last entry in this enumeration!!
+ } CommandArgumentType;
+
+ //----------------------------------------------------------------------
+ // Symbol types
+ //----------------------------------------------------------------------
+ typedef enum SymbolType
+ {
+ eSymbolTypeAny = 0,
+ eSymbolTypeInvalid = 0,
+ eSymbolTypeAbsolute,
+ eSymbolTypeCode,
+ eSymbolTypeResolver,
+ eSymbolTypeData,
+ eSymbolTypeTrampoline,
+ eSymbolTypeRuntime,
+ eSymbolTypeException,
+ eSymbolTypeSourceFile,
+ eSymbolTypeHeaderFile,
+ eSymbolTypeObjectFile,
+ eSymbolTypeCommonBlock,
+ eSymbolTypeBlock,
+ eSymbolTypeLocal,
+ eSymbolTypeParam,
+ eSymbolTypeVariable,
+ eSymbolTypeVariableType,
+ eSymbolTypeLineEntry,
+ eSymbolTypeLineHeader,
+ eSymbolTypeScopeBegin,
+ eSymbolTypeScopeEnd,
+ eSymbolTypeAdditional, // When symbols take more than one entry, the extra entries get this type
+ eSymbolTypeCompiler,
+ eSymbolTypeInstrumentation,
+ eSymbolTypeUndefined,
+ eSymbolTypeObjCClass,
+ eSymbolTypeObjCMetaClass,
+ eSymbolTypeObjCIVar
+ } SymbolType;
+
+ typedef enum SectionType
+ {
+ eSectionTypeInvalid,
+ eSectionTypeCode,
+ eSectionTypeContainer, // The section contains child sections
+ eSectionTypeData,
+ eSectionTypeDataCString, // Inlined C string data
+ eSectionTypeDataCStringPointers, // Pointers to C string data
+ eSectionTypeDataSymbolAddress, // Address of a symbol in the symbol table
+ eSectionTypeData4,
+ eSectionTypeData8,
+ eSectionTypeData16,
+ eSectionTypeDataPointers,
+ eSectionTypeDebug,
+ eSectionTypeZeroFill,
+ eSectionTypeDataObjCMessageRefs, // Pointer to function pointer + selector
+ eSectionTypeDataObjCCFStrings, // Objective C const CFString/NSString objects
+ eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugAranges,
+ eSectionTypeDWARFDebugFrame,
+ eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugLine,
+ eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugMacInfo,
+ eSectionTypeDWARFDebugPubNames,
+ eSectionTypeDWARFDebugPubTypes,
+ eSectionTypeDWARFDebugRanges,
+ eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFAppleNames,
+ eSectionTypeDWARFAppleTypes,
+ eSectionTypeDWARFAppleNamespaces,
+ eSectionTypeDWARFAppleObjC,
+ eSectionTypeELFSymbolTable, // Elf SHT_SYMTAB section
+ eSectionTypeELFDynamicSymbols, // Elf SHT_DYNSYM section
+ eSectionTypeELFRelocationEntries, // Elf SHT_REL or SHT_REL section
+ eSectionTypeELFDynamicLinkInfo, // Elf SHT_DYNAMIC section
+ eSectionTypeEHFrame,
+ eSectionTypeOther
+
+ } SectionType;
+
+ typedef enum EmulateInstructionOptions
+ {
+ eEmulateInstructionOptionNone = (0u),
+ eEmulateInstructionOptionAutoAdvancePC = (1u << 0),
+ eEmulateInstructionOptionIgnoreConditions = (1u << 1)
+ } EmulateInstructionOptions;
+
+ typedef enum FunctionNameType
+ {
+ eFunctionNameTypeNone = 0u,
+ eFunctionNameTypeAuto = (1u << 1), // Automatically figure out which FunctionNameType
+ // bits to set based on the function name.
+ eFunctionNameTypeFull = (1u << 2), // The function name.
+ // For C this is the same as just the name of the function
+ // For C++ this is the mangled or demangled version of the mangled name.
+ // For ObjC this is the full function signature with the + or
+ // - and the square brackets and the class and selector
+ eFunctionNameTypeBase = (1u << 3), // The function name only, no namespaces or arguments and no class
+ // methods or selectors will be searched.
+ eFunctionNameTypeMethod = (1u << 4), // Find function by method name (C++) with no namespace or arguments
+ eFunctionNameTypeSelector = (1u << 5), // Find function by selector name (ObjC) names
+ eFunctionNameTypeAny = eFunctionNameTypeAuto // DEPRECATED: use eFunctionNameTypeAuto
+ } FunctionNameType;
+
+
+ //----------------------------------------------------------------------
+ // Basic types enumeration for the public API SBType::GetBasicType()
+ //----------------------------------------------------------------------
+ typedef enum BasicType
+ {
+ eBasicTypeInvalid = 0,
+ eBasicTypeVoid = 1,
+ eBasicTypeChar,
+ eBasicTypeSignedChar,
+ eBasicTypeUnsignedChar,
+ eBasicTypeWChar,
+ eBasicTypeSignedWChar,
+ eBasicTypeUnsignedWChar,
+ eBasicTypeChar16,
+ eBasicTypeChar32,
+ eBasicTypeShort,
+ eBasicTypeUnsignedShort,
+ eBasicTypeInt,
+ eBasicTypeUnsignedInt,
+ eBasicTypeLong,
+ eBasicTypeUnsignedLong,
+ eBasicTypeLongLong,
+ eBasicTypeUnsignedLongLong,
+ eBasicTypeInt128,
+ eBasicTypeUnsignedInt128,
+ eBasicTypeBool,
+ eBasicTypeHalf,
+ eBasicTypeFloat,
+ eBasicTypeDouble,
+ eBasicTypeLongDouble,
+ eBasicTypeFloatComplex,
+ eBasicTypeDoubleComplex,
+ eBasicTypeLongDoubleComplex,
+ eBasicTypeObjCID,
+ eBasicTypeObjCClass,
+ eBasicTypeObjCSel,
+ eBasicTypeNullPtr,
+ eBasicTypeOther
+ } BasicType;
+
+ typedef enum TypeClass
+ {
+ eTypeClassInvalid = (0u),
+ eTypeClassArray = (1u << 0),
+ eTypeClassBlockPointer = (1u << 1),
+ eTypeClassBuiltin = (1u << 2),
+ eTypeClassClass = (1u << 3),
+ eTypeClassComplexFloat = (1u << 4),
+ eTypeClassComplexInteger = (1u << 5),
+ eTypeClassEnumeration = (1u << 6),
+ eTypeClassFunction = (1u << 7),
+ eTypeClassMemberPointer = (1u << 8),
+ eTypeClassObjCObject = (1u << 9),
+ eTypeClassObjCInterface = (1u << 10),
+ eTypeClassObjCObjectPointer = (1u << 11),
+ eTypeClassPointer = (1u << 12),
+ eTypeClassReference = (1u << 13),
+ eTypeClassStruct = (1u << 14),
+ eTypeClassTypedef = (1u << 15),
+ eTypeClassUnion = (1u << 16),
+ eTypeClassVector = (1u << 17),
+ // Define the last type class as the MSBit of a 32 bit value
+ eTypeClassOther = (1u << 31),
+ // Define a mask that can be used for any type when finding types
+ eTypeClassAny = (0xffffffffu)
+ } TypeClass;
+
+ typedef enum TemplateArgumentKind
+ {
+ eTemplateArgumentKindNull = 0,
+ eTemplateArgumentKindType,
+ eTemplateArgumentKindDeclaration,
+ eTemplateArgumentKindIntegral,
+ eTemplateArgumentKindTemplate,
+ eTemplateArgumentKindTemplateExpansion,
+ eTemplateArgumentKindExpression,
+ eTemplateArgumentKindPack
+
+ } TemplateArgumentKind;
+
+ //----------------------------------------------------------------------
+ // Options that can be set for a formatter to alter its behavior
+ // Not all of these are applicable to all formatter types
+ //----------------------------------------------------------------------
+ typedef enum TypeOptions
+ {
+ eTypeOptionNone = (0u),
+ eTypeOptionCascade = (1u << 0),
+ eTypeOptionSkipPointers = (1u << 1),
+ eTypeOptionSkipReferences = (1u << 2),
+ eTypeOptionHideChildren = (1u << 3),
+ eTypeOptionHideValue = (1u << 4),
+ eTypeOptionShowOneLiner = (1u << 5),
+ eTypeOptionHideNames = (1u << 6)
+ } TypeOptions;
+
+ //----------------------------------------------------------------------
+ // This is the return value for frame comparisons. When frame A pushes
+ // frame B onto the stack, frame A is OLDER than frame B.
+ //----------------------------------------------------------------------
+ typedef enum FrameComparison
+ {
+ eFrameCompareInvalid,
+ eFrameCompareUnknown,
+ eFrameCompareEqual,
+ eFrameCompareYounger,
+ eFrameCompareOlder
+ } FrameComparison;
+
+ //----------------------------------------------------------------------
+ // Address Class
+ //
+ // A way of classifying an address used for disassembling and setting
+ // breakpoints. Many object files can track exactly what parts of their
+ // object files are code, data and other information. This is of course
+ // above and beyond just looking at the section types. For example, code
+ // might contain PC relative data and the object file might be able to
+ // tell us that an address in code is data.
+ //----------------------------------------------------------------------
+ typedef enum AddressClass
+ {
+ eAddressClassInvalid,
+ eAddressClassUnknown,
+ eAddressClassCode,
+ eAddressClassCodeAlternateISA,
+ eAddressClassData,
+ eAddressClassDebug,
+ eAddressClassRuntime
+ } AddressClass;
+
+} // namespace lldb
+
+
+#endif // LLDB_lldb_enumerations_h_
diff --git a/include/lldb/lldb-forward.h b/include/lldb/lldb-forward.h
new file mode 100644
index 000000000000..84af8b646901
--- /dev/null
+++ b/include/lldb/lldb-forward.h
@@ -0,0 +1,378 @@
+//===-- lldb-forward.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_forward_h_
+#define LLDB_lldb_forward_h_
+
+#if defined(__cplusplus)
+
+#include "lldb/Utility/SharingPtr.h"
+
+//----------------------------------------------------------------------
+// lldb forward declarations
+//----------------------------------------------------------------------
+namespace lldb_private {
+
+class ABI;
+class Address;
+class AddressImpl;
+class AddressRange;
+class AddressResolver;
+class ArchSpec;
+class Args;
+class ASTResultSynthesizer;
+class Baton;
+class Block;
+class Breakpoint;
+class BreakpointID;
+class BreakpointIDList;
+class BreakpointList;
+class BreakpointLocation;
+class BreakpointLocationCollection;
+class BreakpointLocationList;
+class BreakpointOptions;
+class BreakpointResolver;
+class BreakpointSite;
+class BreakpointSiteList;
+class BroadcastEventSpec;
+class Broadcaster;
+class BroadcasterManager;
+class CPPLanguageRuntime;
+class ClangASTContext;
+class ClangASTImporter;
+class ClangASTMetadata;
+class ClangASTSource;
+class ClangASTType;
+class ClangNamespaceDecl;
+class ClangExpression;
+class ClangExpressionDeclMap;
+class ClangExpressionParser;
+class ClangExpressionVariable;
+class ClangExpressionVariableList;
+class ClangExpressionVariableList;
+class ClangExpressionVariables;
+class ClangFunction;
+class ClangPersistentVariables;
+class ClangUserExpression;
+class ClangUtilityFunction;
+class CommandInterpreter;
+class CommandObject;
+class CommandReturnObject;
+class Communication;
+class CompileUnit;
+class Condition;
+class Connection;
+class ConnectionFileDescriptor;
+class ConstString;
+class CXXSyntheticChildren;
+class DWARFCallFrameInfo;
+class DWARFExpression;
+class DataBuffer;
+class DataEncoder;
+class DataExtractor;
+class Debugger;
+class Declaration;
+class Disassembler;
+class DynamicLibrary;
+class DynamicLoader;
+class EmulateInstruction;
+class Error;
+class EvaluateExpressionOptions;
+class Event;
+class EventData;
+class ExecutionContext;
+class ExecutionContextRef;
+class ExecutionContextRefLocker;
+class ExecutionContextScope;
+class FileSpec;
+class FileSpecList;
+class Flags;
+class TypeCategoryImpl;
+class FormatManager;
+class FuncUnwinders;
+class Function;
+class FunctionInfo;
+class InlineFunctionInfo;
+class InputReader;
+class Instruction;
+class InstructionList;
+class IRExecutionUnit;
+class LanguageRuntime;
+class LineTable;
+class Listener;
+class Log;
+class LogChannel;
+class Mangled;
+class Materializer;
+class Module;
+class ModuleList;
+class ModuleSpec;
+class ModuleSpecList;
+class Mutex;
+struct NameSearchContext;
+class ObjCLanguageRuntime;
+class ObjectContainer;
+class OptionGroup;
+class OptionGroupPlatform;
+class ObjectFile;
+class OperatingSystem;
+class Options;
+class OptionValue;
+class OptionValueArch;
+class OptionValueArgs;
+class OptionValueArray;
+class OptionValueBoolean;
+class OptionValueDictionary;
+class OptionValueEnumeration;
+class OptionValueFileSpec;
+class OptionValueFileSpecList;
+class OptionValueFormat;
+class OptionValuePathMappings;
+class OptionValueProperties;
+class OptionValueRegex;
+class OptionValueSInt64;
+class OptionValueString;
+class OptionValueUInt64;
+class OptionValueUUID;
+class NamedOption;
+class PathMappingList;
+class Platform;
+class Process;
+class ProcessAttachInfo;
+class ProcessModID;
+class ProcessInfo;
+class ProcessInstanceInfo;
+class ProcessInstanceInfoList;
+class ProcessInstanceInfoMatch;
+class ProcessLaunchInfo;
+class Property;
+struct PropertyDefinition;
+class PythonArray;
+class PythonDictionary;
+class PythonInteger;
+class PythonObject;
+class PythonString;
+class RegisterContext;
+class RegisterLocation;
+class RegisterLocationList;
+class RegisterValue;
+class RegularExpression;
+class Scalar;
+class ScriptInterpreter;
+class ScriptInterpreterLocker;
+class ScriptInterpreterObject;
+#ifndef LLDB_DISABLE_PYTHON
+class ScriptInterpreterPython;
+struct ScriptSummaryFormat;
+#endif
+class SearchFilter;
+class Section;
+class SectionImpl;
+class SectionList;
+class Settings;
+class SourceManager;
+class SourceManagerImpl;
+class StackFrame;
+class StackFrameImpl;
+class StackFrameList;
+class StackID;
+class StopInfo;
+class Stoppoint;
+class StoppointCallbackContext;
+class StoppointLocation;
+class Stream;
+template <unsigned N> class StreamBuffer;
+class StreamFile;
+class StreamString;
+class StringList;
+struct StringSummaryFormat;
+class TypeSummaryImpl;
+class Symbol;
+class SymbolContext;
+class SymbolContextList;
+class SymbolContextScope;
+class SymbolContextSpecifier;
+class SymbolFile;
+class SymbolFileType;
+class SymbolVendor;
+class Symtab;
+class SyntheticChildren;
+class SyntheticChildrenFrontEnd;
+class TypeFilterImpl;
+#ifndef LLDB_DISABLE_PYTHON
+class ScriptedSyntheticChildren;
+#endif
+class Target;
+class TargetList;
+class Thread;
+class ThreadList;
+class ThreadPlan;
+class ThreadPlanBase;
+class ThreadPlanRunToAddress;
+class ThreadPlanStepInstruction;
+class ThreadPlanStepOut;
+class ThreadPlanStepOverBreakpoint;
+class ThreadPlanStepRange;
+class ThreadPlanStepThrough;
+class ThreadPlanTracer;
+class ThreadSpec;
+class TimeValue;
+class Type;
+class TypeCategoryMap;
+class TypeImpl;
+class TypeAndOrName;
+class TypeList;
+class TypeListImpl;
+class TypeMemberImpl;
+class TypeNameSpecifierImpl;
+class UUID;
+class Unwind;
+class UnwindAssembly;
+class UnwindPlan;
+class UnwindTable;
+class VMRange;
+class Value;
+class TypeFormatImpl;
+class ValueList;
+class ValueObject;
+class ValueObjectChild;
+class ValueObjectConstResult;
+class ValueObjectConstResultChild;
+class ValueObjectConstResultImpl;
+class ValueObjectList;
+class Variable;
+class VariableList;
+class Watchpoint;
+class WatchpointList;
+class WatchpointOptions;
+struct LineEntry;
+
+} // namespace lldb_private
+
+//----------------------------------------------------------------------
+// lldb forward declarations
+//----------------------------------------------------------------------
+namespace lldb {
+
+ typedef std::shared_ptr<lldb_private::ABI> ABISP;
+ typedef std::shared_ptr<lldb_private::Baton> BatonSP;
+ typedef std::shared_ptr<lldb_private::Block> BlockSP;
+ typedef std::shared_ptr<lldb_private::Breakpoint> BreakpointSP;
+ typedef std::weak_ptr<lldb_private::Breakpoint> BreakpointWP;
+ typedef std::shared_ptr<lldb_private::BreakpointSite> BreakpointSiteSP;
+ typedef std::weak_ptr<lldb_private::BreakpointSite> BreakpointSiteWP;
+ typedef std::shared_ptr<lldb_private::BreakpointLocation> BreakpointLocationSP;
+ typedef std::weak_ptr<lldb_private::BreakpointLocation> BreakpointLocationWP;
+ typedef std::shared_ptr<lldb_private::BreakpointResolver> BreakpointResolverSP;
+ typedef std::shared_ptr<lldb_private::Broadcaster> BroadcasterSP;
+ typedef std::shared_ptr<lldb_private::ClangExpressionVariable> ClangExpressionVariableSP;
+ typedef std::shared_ptr<lldb_private::CommandObject> CommandObjectSP;
+ typedef std::shared_ptr<lldb_private::Communication> CommunicationSP;
+ typedef std::shared_ptr<lldb_private::Connection> ConnectionSP;
+ typedef std::shared_ptr<lldb_private::CompileUnit> CompUnitSP;
+ typedef std::shared_ptr<lldb_private::DataBuffer> DataBufferSP;
+ typedef std::shared_ptr<lldb_private::DataExtractor> DataExtractorSP;
+ typedef std::shared_ptr<lldb_private::Debugger> DebuggerSP;
+ typedef std::weak_ptr<lldb_private::Debugger> DebuggerWP;
+ typedef std::shared_ptr<lldb_private::Disassembler> DisassemblerSP;
+ typedef std::shared_ptr<lldb_private::DynamicLibrary> DynamicLibrarySP;
+ typedef std::shared_ptr<lldb_private::DynamicLoader> DynamicLoaderSP;
+ typedef std::shared_ptr<lldb_private::Event> EventSP;
+ typedef std::shared_ptr<lldb_private::ExecutionContextRef> ExecutionContextRefSP;
+ typedef std::shared_ptr<lldb_private::Function> FunctionSP;
+ typedef std::shared_ptr<lldb_private::FuncUnwinders> FuncUnwindersSP;
+ typedef std::shared_ptr<lldb_private::InlineFunctionInfo> InlineFunctionInfoSP;
+ typedef std::shared_ptr<lldb_private::InputReader> InputReaderSP;
+ typedef std::shared_ptr<lldb_private::Instruction> InstructionSP;
+ typedef std::shared_ptr<lldb_private::LanguageRuntime> LanguageRuntimeSP;
+ typedef std::shared_ptr<lldb_private::LineTable> LineTableSP;
+ typedef std::shared_ptr<lldb_private::Listener> ListenerSP;
+ typedef std::shared_ptr<lldb_private::LogChannel> LogChannelSP;
+ typedef std::shared_ptr<lldb_private::Module> ModuleSP;
+ typedef std::weak_ptr<lldb_private::Module> ModuleWP;
+ typedef std::shared_ptr<lldb_private::ObjectFile> ObjectFileSP;
+ typedef std::weak_ptr<lldb_private::ObjectFile> ObjectFileWP;
+ typedef std::shared_ptr<lldb_private::OptionValue> OptionValueSP;
+ typedef std::weak_ptr<lldb_private::OptionValue> OptionValueWP;
+ typedef std::shared_ptr<lldb_private::OptionValueArch> OptionValueArchSP;
+ typedef std::shared_ptr<lldb_private::OptionValueArgs> OptionValueArgsSP;
+ typedef std::shared_ptr<lldb_private::OptionValueArray> OptionValueArraySP;
+ typedef std::shared_ptr<lldb_private::OptionValueBoolean> OptionValueBooleanSP;
+ typedef std::shared_ptr<lldb_private::OptionValueDictionary> OptionValueDictionarySP;
+ typedef std::shared_ptr<lldb_private::OptionValueFileSpec> OptionValueFileSpecSP;
+ typedef std::shared_ptr<lldb_private::OptionValueFileSpecList> OptionValueFileSpecListSP;
+ typedef std::shared_ptr<lldb_private::OptionValueFormat> OptionValueFormatSP;
+ typedef std::shared_ptr<lldb_private::OptionValuePathMappings> OptionValuePathMappingsSP;
+ typedef std::shared_ptr<lldb_private::OptionValueProperties> OptionValuePropertiesSP;
+ typedef std::shared_ptr<lldb_private::OptionValueRegex> OptionValueRegexSP;
+ typedef std::shared_ptr<lldb_private::OptionValueSInt64> OptionValueSInt64SP;
+ typedef std::shared_ptr<lldb_private::OptionValueString> OptionValueStringSP;
+ typedef std::shared_ptr<lldb_private::OptionValueUInt64> OptionValueUInt64SP;
+ typedef std::shared_ptr<lldb_private::OptionValueUUID> OptionValueUUIDSP;
+ typedef std::shared_ptr<lldb_private::Platform> PlatformSP;
+ typedef std::shared_ptr<lldb_private::Process> ProcessSP;
+ typedef std::shared_ptr<lldb_private::ProcessAttachInfo> ProcessAttachInfoSP;
+ typedef std::shared_ptr<lldb_private::ProcessLaunchInfo> ProcessLaunchInfoSP;
+ typedef std::weak_ptr<lldb_private::Process> ProcessWP;
+ typedef std::shared_ptr<lldb_private::Property> PropertySP;
+ typedef std::shared_ptr<lldb_private::RegisterContext> RegisterContextSP;
+ typedef std::shared_ptr<lldb_private::RegularExpression> RegularExpressionSP;
+ typedef std::shared_ptr<lldb_private::ScriptInterpreterObject> ScriptInterpreterObjectSP;
+#ifndef LLDB_DISABLE_PYTHON
+ typedef std::shared_ptr<lldb_private::ScriptSummaryFormat> ScriptSummaryFormatSP;
+#endif // #ifndef LLDB_DISABLE_PYTHON
+ typedef std::shared_ptr<lldb_private::Section> SectionSP;
+ typedef std::weak_ptr<lldb_private::Section> SectionWP;
+ typedef std::shared_ptr<lldb_private::SearchFilter> SearchFilterSP;
+ typedef std::shared_ptr<lldb_private::Settings> SettingsSP;
+ typedef std::shared_ptr<lldb_private::StackFrame> StackFrameSP;
+ typedef std::weak_ptr<lldb_private::StackFrame> StackFrameWP;
+ typedef std::shared_ptr<lldb_private::StackFrameList> StackFrameListSP;
+ typedef std::shared_ptr<lldb_private::StopInfo> StopInfoSP;
+ typedef std::shared_ptr<lldb_private::StoppointLocation> StoppointLocationSP;
+ typedef std::shared_ptr<lldb_private::Stream> StreamSP;
+ typedef std::weak_ptr<lldb_private::Stream> StreamWP;
+ typedef std::shared_ptr<lldb_private::StringSummaryFormat> StringTypeSummaryImplSP;
+ typedef std::shared_ptr<lldb_private::SymbolFile> SymbolFileSP;
+ typedef std::shared_ptr<lldb_private::SymbolFileType> SymbolFileTypeSP;
+ typedef std::weak_ptr<lldb_private::SymbolFileType> SymbolFileTypeWP;
+ typedef std::shared_ptr<lldb_private::SymbolContextSpecifier> SymbolContextSpecifierSP;
+ typedef std::shared_ptr<lldb_private::SyntheticChildren> SyntheticChildrenSP;
+ typedef std::shared_ptr<lldb_private::SyntheticChildrenFrontEnd> SyntheticChildrenFrontEndSP;
+ typedef std::shared_ptr<lldb_private::Target> TargetSP;
+ typedef std::weak_ptr<lldb_private::Target> TargetWP;
+ typedef std::shared_ptr<lldb_private::Thread> ThreadSP;
+ typedef std::weak_ptr<lldb_private::Thread> ThreadWP;
+ typedef std::shared_ptr<lldb_private::ThreadPlan> ThreadPlanSP;
+ typedef std::shared_ptr<lldb_private::ThreadPlanTracer> ThreadPlanTracerSP;
+ typedef std::shared_ptr<lldb_private::Type> TypeSP;
+ typedef std::weak_ptr<lldb_private::Type> TypeWP;
+ typedef std::shared_ptr<lldb_private::TypeCategoryImpl> TypeCategoryImplSP;
+ typedef std::shared_ptr<lldb_private::TypeImpl> TypeImplSP;
+ typedef std::shared_ptr<lldb_private::TypeFilterImpl> TypeFilterImplSP;
+ typedef std::shared_ptr<lldb_private::TypeFormatImpl> TypeFormatImplSP;
+ typedef std::shared_ptr<lldb_private::TypeNameSpecifierImpl> TypeNameSpecifierImplSP;
+ typedef std::shared_ptr<lldb_private::TypeSummaryImpl> TypeSummaryImplSP;
+#ifndef LLDB_DISABLE_PYTHON
+ typedef std::shared_ptr<lldb_private::ScriptedSyntheticChildren> ScriptedSyntheticChildrenSP;
+#endif
+ typedef std::shared_ptr<lldb_private::UnwindPlan> UnwindPlanSP;
+ typedef lldb_private::SharingPtr<lldb_private::ValueObject> ValueObjectSP;
+ typedef std::shared_ptr<lldb_private::Value> ValueSP;
+ typedef std::shared_ptr<lldb_private::ValueList> ValueListSP;
+ typedef std::shared_ptr<lldb_private::Variable> VariableSP;
+ typedef std::shared_ptr<lldb_private::VariableList> VariableListSP;
+ typedef std::shared_ptr<lldb_private::ValueObjectList> ValueObjectListSP;
+ typedef std::shared_ptr<lldb_private::Watchpoint> WatchpointSP;
+
+} // namespace lldb
+
+
+#endif // #if defined(__cplusplus)
+#endif // LLDB_lldb_forward_h_
diff --git a/include/lldb/lldb-private-enumerations.h b/include/lldb/lldb-private-enumerations.h
new file mode 100644
index 000000000000..60c90907145f
--- /dev/null
+++ b/include/lldb/lldb-private-enumerations.h
@@ -0,0 +1,245 @@
+//===-- lldb-private-enumerations.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_private_enumerations_h_
+#define LLDB_lldb_private_enumerations_h_
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// Thread Step Types
+//----------------------------------------------------------------------
+typedef enum StepType
+{
+ eStepTypeNone,
+ eStepTypeTrace, ///< Single step one instruction.
+ eStepTypeTraceOver, ///< Single step one instruction, stepping over.
+ eStepTypeInto, ///< Single step into a specified context.
+ eStepTypeOver, ///< Single step over a specified context.
+ eStepTypeOut ///< Single step out a specified context.
+} StepType;
+
+//----------------------------------------------------------------------
+// Address Types
+//----------------------------------------------------------------------
+typedef enum AddressType
+{
+ eAddressTypeInvalid = 0,
+ eAddressTypeFile, ///< Address is an address as found in an object or symbol file
+ eAddressTypeLoad, ///< Address is an address as in the current target inferior process
+ eAddressTypeHost ///< Address is an address in the process that is running this code
+} AddressType;
+
+//----------------------------------------------------------------------
+// Votes - Need a tri-state, yes, no, no opinion...
+//----------------------------------------------------------------------
+typedef enum Vote
+{
+ eVoteNo = -1,
+ eVoteNoOpinion = 0,
+ eVoteYes = 1
+} Vote;
+
+typedef enum ArchitectureType
+{
+ eArchTypeInvalid,
+ eArchTypeMachO,
+ eArchTypeELF,
+ kNumArchTypes
+} ArchitectureType;
+
+//----------------------------------------------------------------------
+/// Settable state variable types.
+///
+//----------------------------------------------------------------------
+
+//typedef enum SettableVariableType
+//{
+// eSetVarTypeInt,
+// eSetVarTypeBoolean,
+// eSetVarTypeString,
+// eSetVarTypeArray,
+// eSetVarTypeDictionary,
+// eSetVarTypeEnum,
+// eSetVarTypeNone
+//} SettableVariableType;
+
+typedef enum VarSetOperationType
+{
+ eVarSetOperationReplace,
+ eVarSetOperationInsertBefore,
+ eVarSetOperationInsertAfter,
+ eVarSetOperationRemove,
+ eVarSetOperationAppend,
+ eVarSetOperationClear,
+ eVarSetOperationAssign,
+ eVarSetOperationInvalid
+} VarSetOperationType;
+
+typedef enum ArgumentRepetitionType
+{
+ eArgRepeatPlain, // Exactly one occurrence
+ eArgRepeatOptional, // At most one occurrence, but it's optional
+ eArgRepeatPlus, // One or more occurrences
+ eArgRepeatStar, // Zero or more occurrences
+ eArgRepeatRange, // Repetition of same argument, from 1 to n
+ eArgRepeatPairPlain, // A pair of arguments that must always go together ([arg-type arg-value]), occurs exactly once
+ eArgRepeatPairOptional, // A pair that occurs at most once (optional)
+ eArgRepeatPairPlus, // One or more occurrences of a pair
+ eArgRepeatPairStar, // Zero or more occurrences of a pair
+ eArgRepeatPairRange, // A pair that repeats from 1 to n
+ eArgRepeatPairRangeOptional // A pair that repeats from 1 to n, but is optional
+} ArgumentRepetitionType;
+
+typedef enum SortOrder
+{
+ eSortOrderNone,
+ eSortOrderByAddress,
+ eSortOrderByName
+} SortOrder;
+
+
+//----------------------------------------------------------------------
+// Used in conjunction with Host::GetLLDBPath () to find files that
+// are related to
+//----------------------------------------------------------------------
+typedef enum PathType
+{
+ ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
+ ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
+ ePathTypeHeaderDir, // Find LLDB header file directory
+ ePathTypePythonDir, // Find Python modules (PYTHONPATH) directory
+ ePathTypeLLDBSystemPlugins, // System plug-ins directory
+ ePathTypeLLDBUserPlugins // User plug-ins directory
+} PathType;
+
+
+//----------------------------------------------------------------------
+// We can execute ThreadPlans on one thread with various fall-back modes
+// (try other threads after timeout, etc.) This enum gives the result of
+// thread plan executions.
+//----------------------------------------------------------------------
+typedef enum ExecutionResults
+{
+ eExecutionSetupError,
+ eExecutionCompleted,
+ eExecutionDiscarded,
+ eExecutionInterrupted,
+ eExecutionHitBreakpoint,
+ eExecutionTimedOut
+} ExecutionResults;
+
+typedef enum ObjCRuntimeVersions {
+ eObjC_VersionUnknown = 0,
+ eAppleObjC_V1 = 1,
+ eAppleObjC_V2 = 2
+} ObjCRuntimeVersions;
+
+
+//----------------------------------------------------------------------
+// LazyBool is for boolean values that need to be calculated lazily.
+// Values start off set to eLazyBoolCalculate, and then they can be
+// calculated once and set to eLazyBoolNo or eLazyBoolYes.
+//----------------------------------------------------------------------
+typedef enum LazyBool {
+ eLazyBoolCalculate = -1,
+ eLazyBoolNo = 0,
+ eLazyBoolYes = 1
+} LazyBool;
+
+//------------------------------------------------------------------
+/// Name matching
+//------------------------------------------------------------------
+typedef enum NameMatchType
+{
+ eNameMatchIgnore,
+ eNameMatchEquals,
+ eNameMatchContains,
+ eNameMatchStartsWith,
+ eNameMatchEndsWith,
+ eNameMatchRegularExpression
+
+} NameMatchType;
+
+
+//------------------------------------------------------------------
+/// Instruction types
+//------------------------------------------------------------------
+typedef enum InstructionType
+{
+ eInstructionTypeAny, // Support for any instructions at all (at least one)
+ eInstructionTypePrologueEpilogue, // All prologue and epilogue instructons that push and pop register values and modify sp/fp
+ eInstructionTypePCModifying, // Any instruction that modifies the program counter/instruction pointer
+ eInstructionTypeAll // All instructions of any kind
+
+} InstructionType;
+
+
+//------------------------------------------------------------------
+/// Format category entry types
+//------------------------------------------------------------------
+typedef enum FormatCategoryItem
+{
+ eFormatCategoryItemSummary = 0x0001,
+ eFormatCategoryItemRegexSummary = 0x0002,
+ eFormatCategoryItemFilter = 0x0004,
+ eFormatCategoryItemRegexFilter = 0x0008,
+ eFormatCategoryItemSynth = 0x0010,
+ eFormatCategoryItemRegexSynth = 0x0020
+} FormatCategoryItem;
+
+//------------------------------------------------------------------
+/// Expression execution policies
+//------------------------------------------------------------------
+typedef enum {
+ eExecutionPolicyOnlyWhenNeeded,
+ eExecutionPolicyNever,
+ eExecutionPolicyAlways
+} ExecutionPolicy;
+
+//----------------------------------------------------------------------
+// Ways that the FormatManager picks a particular format for a type
+//----------------------------------------------------------------------
+typedef enum FormatterChoiceCriterion
+{
+ eFormatterChoiceCriterionDirectChoice = 0x00000000,
+ eFormatterChoiceCriterionStrippedPointerReference = 0x00000001,
+ eFormatterChoiceCriterionNavigatedTypedefs = 0x00000002,
+ eFormatterChoiceCriterionRegularExpressionSummary = 0x00000004,
+ eFormatterChoiceCriterionRegularExpressionFilter = 0x00000004,
+ eFormatterChoiceCriterionDynamicObjCDiscovery = 0x00000008,
+ eFormatterChoiceCriterionStrippedBitField = 0x00000010,
+ eFormatterChoiceCriterionWentToStaticValue = 0x00000020
+} FormatterChoiceCriterion;
+
+//----------------------------------------------------------------------
+// Synchronicity behavior of scripted commands
+//----------------------------------------------------------------------
+typedef enum ScriptedCommandSynchronicity
+{
+ eScriptedCommandSynchronicitySynchronous,
+ eScriptedCommandSynchronicityAsynchronous,
+ eScriptedCommandSynchronicityCurrentValue // use whatever the current synchronicity is
+} ScriptedCommandSynchronicity;
+
+
+//----------------------------------------------------------------------
+// Loading modules from memory
+//----------------------------------------------------------------------
+typedef enum MemoryModuleLoadLevel {
+ eMemoryModuleLoadLevelMinimal, // Load sections only
+ eMemoryModuleLoadLevelPartial, // Load function bounds but no symbols
+ eMemoryModuleLoadLevelComplete, // Load sections and all symbols
+} MemoryModuleLoadLevel;
+
+
+} // namespace lldb_private
+
+
+#endif // LLDB_lldb_private_enumerations_h_
diff --git a/include/lldb/lldb-private-interfaces.h b/include/lldb/lldb-private-interfaces.h
new file mode 100644
index 000000000000..949cafed98b3
--- /dev/null
+++ b/include/lldb/lldb-private-interfaces.h
@@ -0,0 +1,46 @@
+//===-- lldb-private-interfaces.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_lldb_private_interfaces_h_
+#define liblldb_lldb_private_interfaces_h_
+
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private
+{
+ typedef lldb::ABISP (*ABICreateInstance) (const ArchSpec &arch);
+ typedef Disassembler* (*DisassemblerCreateInstance) (const ArchSpec &arch, const char *flavor);
+ typedef DynamicLoader* (*DynamicLoaderCreateInstance) (Process* process, bool force);
+ typedef ObjectContainer* (*ObjectContainerCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length);
+ typedef size_t (*ObjectFileGetModuleSpecifications) (const FileSpec &file, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &module_specs);
+ typedef ObjectFile* (*ObjectFileCreateInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, lldb::offset_t data_offset, const FileSpec* file, lldb::offset_t file_offset, lldb::offset_t length);
+ typedef ObjectFile* (*ObjectFileCreateMemoryInstance) (const lldb::ModuleSP &module_sp, lldb::DataBufferSP& data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t offset);
+ typedef LogChannel* (*LogChannelCreateInstance) ();
+ typedef EmulateInstruction * (*EmulateInstructionCreateInstance) (const ArchSpec &arch, InstructionType inst_type);
+ typedef OperatingSystem* (*OperatingSystemCreateInstance) (Process *process, bool force);
+ typedef LanguageRuntime *(*LanguageRuntimeCreateInstance) (Process *process, lldb::LanguageType language);
+ typedef Platform* (*PlatformCreateInstance) (bool force, const ArchSpec *arch);
+ typedef lldb::ProcessSP (*ProcessCreateInstance) (Target &target, Listener &listener, const FileSpec *crash_file_path);
+ typedef SymbolFile* (*SymbolFileCreateInstance) (ObjectFile* obj_file);
+ typedef SymbolVendor* (*SymbolVendorCreateInstance) (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm); // Module can be NULL for default system symbol vendor
+ typedef bool (*BreakpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
+ typedef bool (*WatchpointHitCallback) (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id);
+ typedef lldb::ThreadPlanSP (*ThreadPlanShouldStopHereCallback) (ThreadPlan *current_plan, Flags &flags, void *baton);
+ typedef UnwindAssembly* (*UnwindAssemblyCreateInstance) (const ArchSpec &arch);
+ typedef int (*ComparisonFunction)(const void *, const void *);
+ typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
+ typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+
+#endif // liblldb_lldb_private_interfaces_h_
diff --git a/include/lldb/lldb-private-log.h b/include/lldb/lldb-private-log.h
new file mode 100644
index 000000000000..31a1c23c5e67
--- /dev/null
+++ b/include/lldb/lldb-private-log.h
@@ -0,0 +1,90 @@
+//===-- lldb-private-log.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_lldb_private_log_h_
+#define liblldb_lldb_private_log_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+
+//----------------------------------------------------------------------
+// Log Bits specific to logging in lldb
+//----------------------------------------------------------------------
+#define LIBLLDB_LOG_VERBOSE (1u << 0)
+#define LIBLLDB_LOG_PROCESS (1u << 1)
+#define LIBLLDB_LOG_THREAD (1u << 2)
+#define LIBLLDB_LOG_DYNAMIC_LOADER (1u << 3)
+#define LIBLLDB_LOG_EVENTS (1u << 4)
+#define LIBLLDB_LOG_BREAKPOINTS (1u << 5)
+#define LIBLLDB_LOG_WATCHPOINTS (1u << 6)
+#define LIBLLDB_LOG_STEP (1u << 7)
+#define LIBLLDB_LOG_EXPRESSIONS (1u << 8)
+#define LIBLLDB_LOG_TEMPORARY (1u << 9)
+#define LIBLLDB_LOG_STATE (1u << 10)
+#define LIBLLDB_LOG_OBJECT (1u << 11)
+#define LIBLLDB_LOG_COMMUNICATION (1u << 12)
+#define LIBLLDB_LOG_CONNECTION (1u << 13)
+#define LIBLLDB_LOG_HOST (1u << 14)
+#define LIBLLDB_LOG_UNWIND (1u << 15)
+#define LIBLLDB_LOG_API (1u << 16)
+#define LIBLLDB_LOG_SCRIPT (1u << 17)
+#define LIBLLDB_LOG_COMMANDS (1U << 18)
+#define LIBLLDB_LOG_TYPES (1u << 19)
+#define LIBLLDB_LOG_SYMBOLS (1u << 20)
+#define LIBLLDB_LOG_MODULES (1u << 21)
+#define LIBLLDB_LOG_TARGET (1u << 22)
+#define LIBLLDB_LOG_MMAP (1u << 23)
+#define LIBLLDB_LOG_OS (1u << 24)
+#define LIBLLDB_LOG_ALL (UINT32_MAX)
+#define LIBLLDB_LOG_DEFAULT (LIBLLDB_LOG_PROCESS |\
+ LIBLLDB_LOG_THREAD |\
+ LIBLLDB_LOG_DYNAMIC_LOADER |\
+ LIBLLDB_LOG_BREAKPOINTS |\
+ LIBLLDB_LOG_WATCHPOINTS |\
+ LIBLLDB_LOG_STEP |\
+ LIBLLDB_LOG_STATE |\
+ LIBLLDB_LOG_SYMBOLS |\
+ LIBLLDB_LOG_TARGET |\
+ LIBLLDB_LOG_COMMANDS)
+
+namespace lldb_private {
+
+void
+LogIfAllCategoriesSet (uint32_t mask, const char *format, ...);
+
+void
+LogIfAnyCategoriesSet (uint32_t mask, const char *format, ...);
+
+Log *
+GetLogIfAllCategoriesSet (uint32_t mask);
+
+Log *
+GetLogIfAnyCategoriesSet (uint32_t mask);
+
+uint32_t
+GetLogMask ();
+
+bool
+IsLogVerbose ();
+
+void
+DisableLog (const char **categories, Stream *feedback_strm);
+
+Log *
+EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm);
+
+void
+ListLogCategories (Stream *strm);
+
+} // namespace lldb_private
+
+#endif // liblldb_lldb_private_log_h_
diff --git a/include/lldb/lldb-private-types.h b/include/lldb/lldb-private-types.h
new file mode 100644
index 000000000000..4340af114be3
--- /dev/null
+++ b/include/lldb/lldb-private-types.h
@@ -0,0 +1,74 @@
+//===-- lldb-private-types.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_lldb_private_types_h_
+#define liblldb_lldb_private_types_h_
+
+#if defined(__cplusplus)
+
+#include "lldb/lldb-private.h"
+
+namespace lldb_private
+{
+ //----------------------------------------------------------------------
+ // Every register is described in detail including its name, alternate
+ // name (optional), encoding, size in bytes and the default display
+ // format.
+ //----------------------------------------------------------------------
+ typedef struct
+ {
+ const char *name; // Name of this register, can't be NULL
+ const char *alt_name; // Alternate name of this register, can be NULL
+ uint32_t byte_size; // Size in bytes of the register
+ uint32_t byte_offset; // The byte offset in the register context data where this register's value is found
+ lldb::Encoding encoding; // Encoding of the register bits
+ lldb::Format format; // Default display format
+ uint32_t kinds[lldb::kNumRegisterKinds]; // Holds all of the various register numbers for all register kinds
+ uint32_t *value_regs; // List of registers that must be terminated with LLDB_INVALID_REGNUM
+ uint32_t *invalidate_regs; // List of registers that must be invalidated when this register is modified, list must be terminated with LLDB_INVALID_REGNUM
+ } RegisterInfo;
+
+ //----------------------------------------------------------------------
+ // Registers are grouped into register sets
+ //----------------------------------------------------------------------
+ typedef struct
+ {
+ const char *name; // Name of this register set
+ const char *short_name; // A short name for this register set
+ size_t num_registers; // The number of registers in REGISTERS array below
+ const uint32_t *registers; // An array of register numbers in this set
+ } RegisterSet;
+
+ typedef struct
+ {
+ int64_t value;
+ const char *string_value;
+ const char *usage;
+ } OptionEnumValueElement;
+
+ typedef struct
+ {
+ uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0
+ // then this option belongs to option set n.
+ bool required; // This option is required (in the current usage level)
+ const char *long_option; // Full name for this option.
+ int short_option; // Single character for this option.
+ int option_has_arg; // no_argument, required_argument or optional_argument
+ OptionEnumValueElement *enum_values; // If non-NULL an array of enum values.
+ uint32_t completion_type; // Cookie the option class can use to do define the argument completion.
+ lldb::CommandArgumentType argument_type; // Type of argument this option takes
+ const char *usage_text; // Full text explaining what this options does and what (if any) argument to
+ // pass it.
+ } OptionDefinition;
+
+} // namespace lldb_private
+
+#endif // #if defined(__cplusplus)
+
+#endif // liblldb_lldb_private_types_h_
diff --git a/include/lldb/lldb-private.h b/include/lldb/lldb-private.h
new file mode 100644
index 000000000000..90590601d945
--- /dev/null
+++ b/include/lldb/lldb-private.h
@@ -0,0 +1,84 @@
+//===-- lldb-private.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_lldb_private_h_
+#define lldb_lldb_private_h_
+
+#if defined(__cplusplus)
+
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-private-enumerations.h"
+#include "lldb/lldb-private-interfaces.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/lldb-private-types.h"
+
+namespace lldb_private {
+
+//------------------------------------------------------------------
+/// Initializes lldb.
+///
+/// This function should be called prior to using any lldb
+/// classes to ensure they have a chance to do any static
+/// initialization that they need to do.
+//------------------------------------------------------------------
+void
+Initialize();
+
+
+//------------------------------------------------------------------
+/// Notifies any classes that lldb will be terminating soon.
+///
+/// This function will be called when the Debugger shared instance
+/// is being destructed and will give classes the ability to clean
+/// up any threads or other resources they have that they might not
+/// be able to clean up in their own destructors.
+///
+/// Internal classes that need this ability will need to add their
+/// void T::WillTerminate() method in the body of this function in
+/// lldb.cpp to ensure it will get called.
+///
+/// TODO: when we start having external plug-ins, we will need a way
+/// for plug-ins to register a WillTerminate callback.
+//------------------------------------------------------------------
+void
+WillTerminate();
+
+//------------------------------------------------------------------
+/// Terminates lldb
+///
+/// This function optionally can be called when clients are done
+/// using lldb functionality to free up any static resources
+/// that have been allocated during initialization or during
+/// function calls. No lldb functions should be called after
+/// calling this function without again calling DCInitialize()
+/// again.
+//------------------------------------------------------------------
+void
+Terminate();
+
+
+const char *
+GetVersion ();
+
+const char *
+GetVoteAsCString (Vote vote);
+
+const char *
+GetSectionTypeAsCString (lldb::SectionType sect_type);
+
+bool
+NameMatches (const char *name, NameMatchType match_type, const char *match);
+
+} // namespace lldb_private
+
+
+#endif // defined(__cplusplus)
+
+
+#endif // lldb_lldb_private_h_
diff --git a/include/lldb/lldb-public.h b/include/lldb/lldb-public.h
new file mode 100644
index 000000000000..b010edf5859a
--- /dev/null
+++ b/include/lldb/lldb-public.h
@@ -0,0 +1,18 @@
+//===-- lldb-include.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_h_
+#define LLDB_lldb_h_
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-types.h"
+
+#endif // LLDB_lldb_h_
diff --git a/include/lldb/lldb-python.h b/include/lldb/lldb-python.h
new file mode 100644
index 000000000000..229e3967e4a5
--- /dev/null
+++ b/include/lldb/lldb-python.h
@@ -0,0 +1,29 @@
+//===-- lldb-python.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_python_h_
+#define LLDB_lldb_python_h_
+
+// Python.h needs to be included before any system headers in order to avoid redefinition of macros
+
+#ifdef LLDB_DISABLE_PYTHON
+
+// Python is disabled in this build
+
+#else
+
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+#endif // LLDB_DISABLE_PYTHON
+
+#endif // LLDB_lldb_python_h_
diff --git a/include/lldb/lldb-types.h b/include/lldb/lldb-types.h
new file mode 100644
index 000000000000..2693c0c822bb
--- /dev/null
+++ b/include/lldb/lldb-types.h
@@ -0,0 +1,83 @@
+//===-- lldb-types.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_types_h_
+#define LLDB_lldb_types_h_
+
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+
+//----------------------------------------------------------------------
+// All host systems must define:
+// lldb::condition_t The native condition type (or a substitute class) for conditions on the host system.
+// lldb::mutex_t The native mutex type for mutex objects on the host system.
+// lldb::thread_t The native thread type for spawned threads on the system
+// lldb::thread_arg_t The type of the one any only thread creation argument for the host system
+// lldb::thread_result_t The return type that gets returned when a thread finishes.
+// lldb::thread_func_t The function prototype used to spawn a thread on the host system.
+// #define LLDB_INVALID_PROCESS_ID ...
+// #define LLDB_INVALID_THREAD_ID ...
+// #define LLDB_INVALID_HOST_THREAD ...
+// #define IS_VALID_LLDB_HOST_THREAD ...
+//----------------------------------------------------------------------
+
+// TODO: Add a bunch of ifdefs to determine the host system and what
+// things should be defined. Currently MacOSX is being assumed by default
+// since that is what lldb was first developed for.
+
+namespace lldb {
+ //----------------------------------------------------------------------
+ // MacOSX Types
+ //----------------------------------------------------------------------
+ typedef ::pthread_mutex_t mutex_t;
+ typedef pthread_cond_t condition_t;
+ typedef pthread_t thread_t; // Host thread type
+ typedef void * thread_arg_t; // Host thread argument type
+ typedef void * thread_result_t; // Host thread result type
+ typedef void * (*thread_func_t)(void *); // Host thread function type
+ typedef void (*LogOutputCallback) (const char *, void *baton);
+ typedef bool (*CommandOverrideCallback)(void *baton, const char **argv);
+} // namespace lldb
+
+#if defined(__MINGW32__)
+
+const lldb::thread_t lldb_invalid_host_thread_const = { NULL, 0 } ;
+#define LLDB_INVALID_HOST_THREAD (lldb_invalid_host_thread_const)
+#define IS_VALID_LLDB_HOST_THREAD(t) (!(NULL == (t).p && 0 == (t).x))
+
+#else
+
+#define LLDB_INVALID_HOST_THREAD ((lldb::thread_t)NULL)
+#define IS_VALID_LLDB_HOST_THREAD(t) ((t) != LLDB_INVALID_HOST_THREAD)
+
+#endif
+
+#define LLDB_INVALID_HOST_TIME { 0, 0 }
+
+namespace lldb
+{
+ typedef uint64_t addr_t;
+ typedef uint64_t user_id_t;
+ typedef uint64_t pid_t;
+ typedef uint64_t tid_t;
+ typedef uint64_t offset_t;
+ typedef int32_t break_id_t;
+ typedef int32_t watch_id_t;
+ typedef void * clang_type_t;
+}
+
+
+#endif // LLDB_lldb_types_h_
diff --git a/include/lldb/lldb-versioning.h b/include/lldb/lldb-versioning.h
new file mode 100644
index 000000000000..8ccc67d8e9c0
--- /dev/null
+++ b/include/lldb/lldb-versioning.h
@@ -0,0 +1,1607 @@
+//===-- lldb-versioning.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_lldb_versioning_h_
+#define LLDB_lldb_versioning_h_
+
+//----------------------------------------------------------------------
+// LLDB API version
+//----------------------------------------------------------------------
+#define LLDB_API_MAJOR_VERSION 1
+#define LLDB_API_MINOR_VERSION 0
+
+/*
+ API versioning
+ ---------------------------------
+
+ The LLDB API is versioned independently of the LLDB source base
+ Our API version numbers are composed of a major and a minor number
+
+ The major number means a complete and stable revision of the API. Major numbers are compatibility breakers
+ (i.e. when we change the API major number, there is no promise of compatibility with the previous major version
+ and we are free to remove and/or change any APIs)
+ Minor numbers are a work-in-progress evolution of the API. APIs will not be removed or changed across minor versions
+ (minors do not break compatibility). However, we can deprecate APIs in minor versions or add new APIs in minor versions
+ A deprecated API is supposedly going to be removed in the next major version and will generate a warning if used
+ APIs we add in minor versions will not be removed (at least until the following major) but they might theoretically be deprecated
+ in a following minor version
+ Users are discouraged from using the LLDB version number to test for API features and should instead use the API version checking
+ as discussed below
+
+ API version checking
+ ---------------------------------
+
+ You can (optionally) sign into an API version checking feature
+ To do so you need to define three macros:
+ LLDB_API_CHECK_VERSIONING - define to any value (or no value)
+ LLDB_API_MAJOR_VERSION_WANTED - which major version of the LLDB API you are targeting
+ LLDB_API_MINOR_VERSION_WANTED - which minor version of the LLDB API you are targeting
+
+ If these macros exist - LLDB will enable version checking of the public API
+
+ If LLDB_API_MAJOR_VERSION is not equal to LLDB_API_MAJOR_VERSION_WANTED we will immediately halt your compilation with an error
+ This is by design, since we do not make any promise of compatibility across major versions - if you really want to test your luck, disable the versioning altogether
+
+ If the major version test passes, you have signed up for a specific minor version of the API
+ Whenever we add or deprecate an API in a minor version, we will mark it with either
+ LLDB_API_NEW_IN_DOT_x - this API is new in LLDB .x
+ LLDB_API_DEPRECATED_IN_DOT_x - this API is deprecated as of .x
+
+ If you are using an API new in DOT_x
+ if LLDB_API_MINOR_VERSION_WANTED >= x then all is well, else you will get a compilation error
+ This is meant to prevent you from using APIs that are newer than whatever LLDB you want to target
+
+ If you are using an API deprecated in DOT_x
+ if LLDB_API_MINOR_VERSION_WANTED >= x then you will get a compilation warning, else all is well
+ This is meant to let you know that you are using an API that is deprecated and might go away
+
+ Caveats
+ ---------------------------------
+
+ Version checking only works on clang on OSX - you will get an error if you try to enable it on any other OS/compiler
+ If you want to enable version checking on other platforms, you will need to define appropriate implementations for
+ LLDB_API_IMPL_DEPRECATED and LLDB_API_IMPL_TOONEW and any other infrastructure your compiler needs for this purpose
+
+ We have no deprecation-as-error mode
+
+ There is no support for API versioning in Python
+
+ We reserve to use macros whose names begin with LLDB_API_ and you should not use them in your source code as they might conflict
+ with present or future macro names we are using to implement versioning
+*/
+
+// if you want the version checking to work on other OS/compiler, define appropriate IMPL_DEPRECATED/IMPL_TOONEW
+// and define LLDB_API_CHECK_VERSIONING_WORKS when you are ready to go live
+#if defined(__APPLE__) && defined(__clang__)
+#define LLDB_API_IMPL_DEPRECATED __attribute__((deprecated))
+#define LLDB_API_IMPL_TOONEW __attribute__((unavailable))
+#define LLDB_API_CHECK_VERSIONING_WORKS
+#endif
+
+#if defined(LLDB_API_CHECK_VERSIONING) && !defined(LLDB_API_CHECK_VERSIONING_WORKS)
+#error "API version checking will not work here - please disable or create and submit patches to lldb-versioning.h"
+#endif
+
+#if defined(LLDB_API_CHECK_VERSIONING_WORKS) && (!defined(LLDB_API_IMPL_DEPRECATED) || !defined(LLDB_API_IMPL_TOONEW))
+#error "LLDB_API_CHECK_VERSIONING_WORKS needs LLDB_API_IMPL_DEPRECATED and LLDB_API_IMPL_TOONEW to be defined"
+#endif
+
+#if defined(LLDB_API_CHECK_VERSIONING) && defined(LLDB_API_MAJOR_VERSION_WANTED) && defined(LLDB_API_MINOR_VERSION_WANTED)
+
+#if defined (LLDB_API_MAJOR_VERSION) && (LLDB_API_MAJOR_VERSION != LLDB_API_MAJOR_VERSION_WANTED)
+#error "Cannot link using this LLDB version - public API versions are incompatible"
+#endif
+
+#define LLDB_API_MINOR_VERSION_DOT_0 0
+#define LLDB_API_MINOR_VERSION_DOT_1 1
+#define LLDB_API_MINOR_VERSION_DOT_2 2
+#define LLDB_API_MINOR_VERSION_DOT_3 3
+#define LLDB_API_MINOR_VERSION_DOT_4 4
+#define LLDB_API_MINOR_VERSION_DOT_5 5
+#define LLDB_API_MINOR_VERSION_DOT_6 6
+#define LLDB_API_MINOR_VERSION_DOT_7 7
+#define LLDB_API_MINOR_VERSION_DOT_8 8
+#define LLDB_API_MINOR_VERSION_DOT_9 9
+#define LLDB_API_MINOR_VERSION_DOT_10 10
+#define LLDB_API_MINOR_VERSION_DOT_11 11
+#define LLDB_API_MINOR_VERSION_DOT_12 12
+#define LLDB_API_MINOR_VERSION_DOT_13 13
+#define LLDB_API_MINOR_VERSION_DOT_14 14
+#define LLDB_API_MINOR_VERSION_DOT_15 15
+#define LLDB_API_MINOR_VERSION_DOT_16 16
+#define LLDB_API_MINOR_VERSION_DOT_17 17
+#define LLDB_API_MINOR_VERSION_DOT_18 18
+#define LLDB_API_MINOR_VERSION_DOT_19 19
+#define LLDB_API_MINOR_VERSION_DOT_20 20
+#define LLDB_API_MINOR_VERSION_DOT_21 21
+#define LLDB_API_MINOR_VERSION_DOT_22 22
+#define LLDB_API_MINOR_VERSION_DOT_23 23
+#define LLDB_API_MINOR_VERSION_DOT_24 24
+#define LLDB_API_MINOR_VERSION_DOT_25 25
+#define LLDB_API_MINOR_VERSION_DOT_26 26
+#define LLDB_API_MINOR_VERSION_DOT_27 27
+#define LLDB_API_MINOR_VERSION_DOT_28 28
+#define LLDB_API_MINOR_VERSION_DOT_29 29
+#define LLDB_API_MINOR_VERSION_DOT_30 30
+#define LLDB_API_MINOR_VERSION_DOT_31 31
+#define LLDB_API_MINOR_VERSION_DOT_32 32
+#define LLDB_API_MINOR_VERSION_DOT_33 33
+#define LLDB_API_MINOR_VERSION_DOT_34 34
+#define LLDB_API_MINOR_VERSION_DOT_35 35
+#define LLDB_API_MINOR_VERSION_DOT_36 36
+#define LLDB_API_MINOR_VERSION_DOT_37 37
+#define LLDB_API_MINOR_VERSION_DOT_38 38
+#define LLDB_API_MINOR_VERSION_DOT_39 39
+#define LLDB_API_MINOR_VERSION_DOT_40 40
+#define LLDB_API_MINOR_VERSION_DOT_41 41
+#define LLDB_API_MINOR_VERSION_DOT_42 42
+#define LLDB_API_MINOR_VERSION_DOT_43 43
+#define LLDB_API_MINOR_VERSION_DOT_44 44
+#define LLDB_API_MINOR_VERSION_DOT_45 45
+#define LLDB_API_MINOR_VERSION_DOT_46 46
+#define LLDB_API_MINOR_VERSION_DOT_47 47
+#define LLDB_API_MINOR_VERSION_DOT_48 48
+#define LLDB_API_MINOR_VERSION_DOT_49 49
+#define LLDB_API_MINOR_VERSION_DOT_50 50
+#define LLDB_API_MINOR_VERSION_DOT_51 51
+#define LLDB_API_MINOR_VERSION_DOT_52 52
+#define LLDB_API_MINOR_VERSION_DOT_53 53
+#define LLDB_API_MINOR_VERSION_DOT_54 54
+#define LLDB_API_MINOR_VERSION_DOT_55 55
+#define LLDB_API_MINOR_VERSION_DOT_56 56
+#define LLDB_API_MINOR_VERSION_DOT_57 57
+#define LLDB_API_MINOR_VERSION_DOT_58 58
+#define LLDB_API_MINOR_VERSION_DOT_59 59
+#define LLDB_API_MINOR_VERSION_DOT_60 60
+#define LLDB_API_MINOR_VERSION_DOT_61 61
+#define LLDB_API_MINOR_VERSION_DOT_62 62
+#define LLDB_API_MINOR_VERSION_DOT_63 63
+#define LLDB_API_MINOR_VERSION_DOT_64 64
+#define LLDB_API_MINOR_VERSION_DOT_65 65
+#define LLDB_API_MINOR_VERSION_DOT_66 66
+#define LLDB_API_MINOR_VERSION_DOT_67 67
+#define LLDB_API_MINOR_VERSION_DOT_68 68
+#define LLDB_API_MINOR_VERSION_DOT_69 69
+#define LLDB_API_MINOR_VERSION_DOT_70 70
+#define LLDB_API_MINOR_VERSION_DOT_71 71
+#define LLDB_API_MINOR_VERSION_DOT_72 72
+#define LLDB_API_MINOR_VERSION_DOT_73 73
+#define LLDB_API_MINOR_VERSION_DOT_74 74
+#define LLDB_API_MINOR_VERSION_DOT_75 75
+#define LLDB_API_MINOR_VERSION_DOT_76 76
+#define LLDB_API_MINOR_VERSION_DOT_77 77
+#define LLDB_API_MINOR_VERSION_DOT_78 78
+#define LLDB_API_MINOR_VERSION_DOT_79 79
+#define LLDB_API_MINOR_VERSION_DOT_80 80
+#define LLDB_API_MINOR_VERSION_DOT_81 81
+#define LLDB_API_MINOR_VERSION_DOT_82 82
+#define LLDB_API_MINOR_VERSION_DOT_83 83
+#define LLDB_API_MINOR_VERSION_DOT_84 84
+#define LLDB_API_MINOR_VERSION_DOT_85 85
+#define LLDB_API_MINOR_VERSION_DOT_86 86
+#define LLDB_API_MINOR_VERSION_DOT_87 87
+#define LLDB_API_MINOR_VERSION_DOT_88 88
+#define LLDB_API_MINOR_VERSION_DOT_89 89
+#define LLDB_API_MINOR_VERSION_DOT_90 90
+#define LLDB_API_MINOR_VERSION_DOT_91 91
+#define LLDB_API_MINOR_VERSION_DOT_92 92
+#define LLDB_API_MINOR_VERSION_DOT_93 93
+#define LLDB_API_MINOR_VERSION_DOT_94 94
+#define LLDB_API_MINOR_VERSION_DOT_95 95
+#define LLDB_API_MINOR_VERSION_DOT_96 96
+#define LLDB_API_MINOR_VERSION_DOT_97 97
+#define LLDB_API_MINOR_VERSION_DOT_98 98
+#define LLDB_API_MINOR_VERSION_DOT_99 99
+
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_0
+#define LLDB_API_NEW_IN_DOT_0 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_0
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_0
+#define LLDB_API_DEPRECATED_IN_DOT_0 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_0
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_1
+#define LLDB_API_NEW_IN_DOT_1 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_1
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_1
+#define LLDB_API_DEPRECATED_IN_DOT_1 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_1
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_2
+#define LLDB_API_NEW_IN_DOT_2 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_2
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_2
+#define LLDB_API_DEPRECATED_IN_DOT_2 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_2
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_3
+#define LLDB_API_NEW_IN_DOT_3 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_3
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_3
+#define LLDB_API_DEPRECATED_IN_DOT_3 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_3
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_4
+#define LLDB_API_NEW_IN_DOT_4 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_4
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_4
+#define LLDB_API_DEPRECATED_IN_DOT_4 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_4
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_5
+#define LLDB_API_NEW_IN_DOT_5 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_5
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_5
+#define LLDB_API_DEPRECATED_IN_DOT_5 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_5
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_6
+#define LLDB_API_NEW_IN_DOT_6 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_6
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_6
+#define LLDB_API_DEPRECATED_IN_DOT_6 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_6
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_7
+#define LLDB_API_NEW_IN_DOT_7 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_7
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_7
+#define LLDB_API_DEPRECATED_IN_DOT_7 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_7
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_8
+#define LLDB_API_NEW_IN_DOT_8 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_8
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_8
+#define LLDB_API_DEPRECATED_IN_DOT_8 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_8
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_9
+#define LLDB_API_NEW_IN_DOT_9 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_9
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_9
+#define LLDB_API_DEPRECATED_IN_DOT_9 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_9
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_10
+#define LLDB_API_NEW_IN_DOT_10 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_10
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_10
+#define LLDB_API_DEPRECATED_IN_DOT_10 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_10
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_11
+#define LLDB_API_NEW_IN_DOT_11 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_11
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_11
+#define LLDB_API_DEPRECATED_IN_DOT_11 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_11
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_12
+#define LLDB_API_NEW_IN_DOT_12 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_12
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_12
+#define LLDB_API_DEPRECATED_IN_DOT_12 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_12
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_13
+#define LLDB_API_NEW_IN_DOT_13 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_13
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_13
+#define LLDB_API_DEPRECATED_IN_DOT_13 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_13
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_14
+#define LLDB_API_NEW_IN_DOT_14 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_14
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_14
+#define LLDB_API_DEPRECATED_IN_DOT_14 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_14
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_15
+#define LLDB_API_NEW_IN_DOT_15 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_15
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_15
+#define LLDB_API_DEPRECATED_IN_DOT_15 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_15
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_16
+#define LLDB_API_NEW_IN_DOT_16 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_16
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_16
+#define LLDB_API_DEPRECATED_IN_DOT_16 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_16
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_17
+#define LLDB_API_NEW_IN_DOT_17 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_17
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_17
+#define LLDB_API_DEPRECATED_IN_DOT_17 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_17
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_18
+#define LLDB_API_NEW_IN_DOT_18 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_18
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_18
+#define LLDB_API_DEPRECATED_IN_DOT_18 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_18
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_19
+#define LLDB_API_NEW_IN_DOT_19 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_19
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_19
+#define LLDB_API_DEPRECATED_IN_DOT_19 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_19
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_20
+#define LLDB_API_NEW_IN_DOT_20 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_20
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_20
+#define LLDB_API_DEPRECATED_IN_DOT_20 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_20
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_21
+#define LLDB_API_NEW_IN_DOT_21 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_21
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_21
+#define LLDB_API_DEPRECATED_IN_DOT_21 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_21
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_22
+#define LLDB_API_NEW_IN_DOT_22 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_22
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_22
+#define LLDB_API_DEPRECATED_IN_DOT_22 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_22
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_23
+#define LLDB_API_NEW_IN_DOT_23 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_23
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_23
+#define LLDB_API_DEPRECATED_IN_DOT_23 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_23
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_24
+#define LLDB_API_NEW_IN_DOT_24 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_24
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_24
+#define LLDB_API_DEPRECATED_IN_DOT_24 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_24
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_25
+#define LLDB_API_NEW_IN_DOT_25 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_25
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_25
+#define LLDB_API_DEPRECATED_IN_DOT_25 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_25
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_26
+#define LLDB_API_NEW_IN_DOT_26 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_26
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_26
+#define LLDB_API_DEPRECATED_IN_DOT_26 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_26
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_27
+#define LLDB_API_NEW_IN_DOT_27 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_27
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_27
+#define LLDB_API_DEPRECATED_IN_DOT_27 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_27
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_28
+#define LLDB_API_NEW_IN_DOT_28 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_28
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_28
+#define LLDB_API_DEPRECATED_IN_DOT_28 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_28
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_29
+#define LLDB_API_NEW_IN_DOT_29 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_29
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_29
+#define LLDB_API_DEPRECATED_IN_DOT_29 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_29
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_30
+#define LLDB_API_NEW_IN_DOT_30 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_30
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_30
+#define LLDB_API_DEPRECATED_IN_DOT_30 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_30
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_31
+#define LLDB_API_NEW_IN_DOT_31 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_31
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_31
+#define LLDB_API_DEPRECATED_IN_DOT_31 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_31
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_32
+#define LLDB_API_NEW_IN_DOT_32 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_32
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_32
+#define LLDB_API_DEPRECATED_IN_DOT_32 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_32
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_33
+#define LLDB_API_NEW_IN_DOT_33 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_33
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_33
+#define LLDB_API_DEPRECATED_IN_DOT_33 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_33
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_34
+#define LLDB_API_NEW_IN_DOT_34 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_34
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_34
+#define LLDB_API_DEPRECATED_IN_DOT_34 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_34
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_35
+#define LLDB_API_NEW_IN_DOT_35 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_35
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_35
+#define LLDB_API_DEPRECATED_IN_DOT_35 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_35
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_36
+#define LLDB_API_NEW_IN_DOT_36 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_36
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_36
+#define LLDB_API_DEPRECATED_IN_DOT_36 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_36
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_37
+#define LLDB_API_NEW_IN_DOT_37 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_37
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_37
+#define LLDB_API_DEPRECATED_IN_DOT_37 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_37
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_38
+#define LLDB_API_NEW_IN_DOT_38 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_38
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_38
+#define LLDB_API_DEPRECATED_IN_DOT_38 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_38
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_39
+#define LLDB_API_NEW_IN_DOT_39 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_39
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_39
+#define LLDB_API_DEPRECATED_IN_DOT_39 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_39
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_40
+#define LLDB_API_NEW_IN_DOT_40 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_40
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_40
+#define LLDB_API_DEPRECATED_IN_DOT_40 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_40
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_41
+#define LLDB_API_NEW_IN_DOT_41 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_41
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_41
+#define LLDB_API_DEPRECATED_IN_DOT_41 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_41
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_42
+#define LLDB_API_NEW_IN_DOT_42 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_42
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_42
+#define LLDB_API_DEPRECATED_IN_DOT_42 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_42
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_43
+#define LLDB_API_NEW_IN_DOT_43 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_43
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_43
+#define LLDB_API_DEPRECATED_IN_DOT_43 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_43
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_44
+#define LLDB_API_NEW_IN_DOT_44 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_44
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_44
+#define LLDB_API_DEPRECATED_IN_DOT_44 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_44
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_45
+#define LLDB_API_NEW_IN_DOT_45 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_45
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_45
+#define LLDB_API_DEPRECATED_IN_DOT_45 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_45
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_46
+#define LLDB_API_NEW_IN_DOT_46 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_46
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_46
+#define LLDB_API_DEPRECATED_IN_DOT_46 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_46
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_47
+#define LLDB_API_NEW_IN_DOT_47 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_47
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_47
+#define LLDB_API_DEPRECATED_IN_DOT_47 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_47
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_48
+#define LLDB_API_NEW_IN_DOT_48 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_48
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_48
+#define LLDB_API_DEPRECATED_IN_DOT_48 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_48
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_49
+#define LLDB_API_NEW_IN_DOT_49 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_49
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_49
+#define LLDB_API_DEPRECATED_IN_DOT_49 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_49
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_50
+#define LLDB_API_NEW_IN_DOT_50 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_50
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_50
+#define LLDB_API_DEPRECATED_IN_DOT_50 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_50
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_51
+#define LLDB_API_NEW_IN_DOT_51 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_51
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_51
+#define LLDB_API_DEPRECATED_IN_DOT_51 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_51
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_52
+#define LLDB_API_NEW_IN_DOT_52 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_52
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_52
+#define LLDB_API_DEPRECATED_IN_DOT_52 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_52
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_53
+#define LLDB_API_NEW_IN_DOT_53 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_53
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_53
+#define LLDB_API_DEPRECATED_IN_DOT_53 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_53
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_54
+#define LLDB_API_NEW_IN_DOT_54 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_54
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_54
+#define LLDB_API_DEPRECATED_IN_DOT_54 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_54
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_55
+#define LLDB_API_NEW_IN_DOT_55 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_55
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_55
+#define LLDB_API_DEPRECATED_IN_DOT_55 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_55
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_56
+#define LLDB_API_NEW_IN_DOT_56 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_56
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_56
+#define LLDB_API_DEPRECATED_IN_DOT_56 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_56
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_57
+#define LLDB_API_NEW_IN_DOT_57 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_57
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_57
+#define LLDB_API_DEPRECATED_IN_DOT_57 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_57
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_58
+#define LLDB_API_NEW_IN_DOT_58 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_58
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_58
+#define LLDB_API_DEPRECATED_IN_DOT_58 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_58
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_59
+#define LLDB_API_NEW_IN_DOT_59 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_59
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_59
+#define LLDB_API_DEPRECATED_IN_DOT_59 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_59
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_60
+#define LLDB_API_NEW_IN_DOT_60 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_60
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_60
+#define LLDB_API_DEPRECATED_IN_DOT_60 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_60
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_61
+#define LLDB_API_NEW_IN_DOT_61 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_61
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_61
+#define LLDB_API_DEPRECATED_IN_DOT_61 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_61
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_62
+#define LLDB_API_NEW_IN_DOT_62 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_62
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_62
+#define LLDB_API_DEPRECATED_IN_DOT_62 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_62
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_63
+#define LLDB_API_NEW_IN_DOT_63 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_63
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_63
+#define LLDB_API_DEPRECATED_IN_DOT_63 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_63
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_64
+#define LLDB_API_NEW_IN_DOT_64 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_64
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_64
+#define LLDB_API_DEPRECATED_IN_DOT_64 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_64
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_65
+#define LLDB_API_NEW_IN_DOT_65 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_65
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_65
+#define LLDB_API_DEPRECATED_IN_DOT_65 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_65
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_66
+#define LLDB_API_NEW_IN_DOT_66 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_66
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_66
+#define LLDB_API_DEPRECATED_IN_DOT_66 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_66
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_67
+#define LLDB_API_NEW_IN_DOT_67 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_67
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_67
+#define LLDB_API_DEPRECATED_IN_DOT_67 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_67
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_68
+#define LLDB_API_NEW_IN_DOT_68 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_68
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_68
+#define LLDB_API_DEPRECATED_IN_DOT_68 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_68
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_69
+#define LLDB_API_NEW_IN_DOT_69 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_69
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_69
+#define LLDB_API_DEPRECATED_IN_DOT_69 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_69
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_70
+#define LLDB_API_NEW_IN_DOT_70 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_70
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_70
+#define LLDB_API_DEPRECATED_IN_DOT_70 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_70
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_71
+#define LLDB_API_NEW_IN_DOT_71 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_71
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_71
+#define LLDB_API_DEPRECATED_IN_DOT_71 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_71
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_72
+#define LLDB_API_NEW_IN_DOT_72 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_72
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_72
+#define LLDB_API_DEPRECATED_IN_DOT_72 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_72
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_73
+#define LLDB_API_NEW_IN_DOT_73 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_73
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_73
+#define LLDB_API_DEPRECATED_IN_DOT_73 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_73
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_74
+#define LLDB_API_NEW_IN_DOT_74 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_74
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_74
+#define LLDB_API_DEPRECATED_IN_DOT_74 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_74
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_75
+#define LLDB_API_NEW_IN_DOT_75 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_75
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_75
+#define LLDB_API_DEPRECATED_IN_DOT_75 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_75
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_76
+#define LLDB_API_NEW_IN_DOT_76 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_76
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_76
+#define LLDB_API_DEPRECATED_IN_DOT_76 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_76
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_77
+#define LLDB_API_NEW_IN_DOT_77 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_77
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_77
+#define LLDB_API_DEPRECATED_IN_DOT_77 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_77
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_78
+#define LLDB_API_NEW_IN_DOT_78 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_78
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_78
+#define LLDB_API_DEPRECATED_IN_DOT_78 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_78
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_79
+#define LLDB_API_NEW_IN_DOT_79 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_79
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_79
+#define LLDB_API_DEPRECATED_IN_DOT_79 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_79
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_80
+#define LLDB_API_NEW_IN_DOT_80 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_80
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_80
+#define LLDB_API_DEPRECATED_IN_DOT_80 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_80
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_81
+#define LLDB_API_NEW_IN_DOT_81 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_81
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_81
+#define LLDB_API_DEPRECATED_IN_DOT_81 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_81
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_82
+#define LLDB_API_NEW_IN_DOT_82 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_82
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_82
+#define LLDB_API_DEPRECATED_IN_DOT_82 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_82
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_83
+#define LLDB_API_NEW_IN_DOT_83 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_83
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_83
+#define LLDB_API_DEPRECATED_IN_DOT_83 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_83
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_84
+#define LLDB_API_NEW_IN_DOT_84 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_84
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_84
+#define LLDB_API_DEPRECATED_IN_DOT_84 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_84
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_85
+#define LLDB_API_NEW_IN_DOT_85 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_85
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_85
+#define LLDB_API_DEPRECATED_IN_DOT_85 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_85
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_86
+#define LLDB_API_NEW_IN_DOT_86 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_86
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_86
+#define LLDB_API_DEPRECATED_IN_DOT_86 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_86
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_87
+#define LLDB_API_NEW_IN_DOT_87 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_87
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_87
+#define LLDB_API_DEPRECATED_IN_DOT_87 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_87
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_88
+#define LLDB_API_NEW_IN_DOT_88 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_88
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_88
+#define LLDB_API_DEPRECATED_IN_DOT_88 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_88
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_89
+#define LLDB_API_NEW_IN_DOT_89 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_89
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_89
+#define LLDB_API_DEPRECATED_IN_DOT_89 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_89
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_90
+#define LLDB_API_NEW_IN_DOT_90 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_90
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_90
+#define LLDB_API_DEPRECATED_IN_DOT_90 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_90
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_91
+#define LLDB_API_NEW_IN_DOT_91 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_91
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_91
+#define LLDB_API_DEPRECATED_IN_DOT_91 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_91
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_92
+#define LLDB_API_NEW_IN_DOT_92 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_92
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_92
+#define LLDB_API_DEPRECATED_IN_DOT_92 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_92
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_93
+#define LLDB_API_NEW_IN_DOT_93 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_93
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_93
+#define LLDB_API_DEPRECATED_IN_DOT_93 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_93
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_94
+#define LLDB_API_NEW_IN_DOT_94 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_94
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_94
+#define LLDB_API_DEPRECATED_IN_DOT_94 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_94
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_95
+#define LLDB_API_NEW_IN_DOT_95 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_95
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_95
+#define LLDB_API_DEPRECATED_IN_DOT_95 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_95
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_96
+#define LLDB_API_NEW_IN_DOT_96 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_96
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_96
+#define LLDB_API_DEPRECATED_IN_DOT_96 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_96
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_97
+#define LLDB_API_NEW_IN_DOT_97 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_97
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_97
+#define LLDB_API_DEPRECATED_IN_DOT_97 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_97
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_98
+#define LLDB_API_NEW_IN_DOT_98 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_98
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_98
+#define LLDB_API_DEPRECATED_IN_DOT_98 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_98
+#endif
+#if LLDB_API_MINOR_VERSION_WANTED < LLDB_API_MINOR_VERSION_DOT_99
+#define LLDB_API_NEW_IN_DOT_99 LLDB_API_IMPL_TOONEW
+#else
+#define LLDB_API_NEW_IN_DOT_99
+#endif
+
+
+#if LLDB_API_MINOR_VERSION_WANTED >= LLDB_API_MINOR_VERSION_DOT_99
+#define LLDB_API_DEPRECATED_IN_DOT_99 LLDB_API_IMPL_DEPRECATED
+#else
+#define LLDB_API_DEPRECATED_IN_DOT_99
+#endif
+
+#else // defined(LLDB_CHECK_API_VERSIONING) && defined(LLDB_API_MAJOR_VERSION_WANTED) && defined(LLDB_API_MINOR_VERSION_WANTED) && defined (LLDB_API_MAJOR_VERSION)
+
+#define LLDB_API_NEW_IN_DOT_0
+#define LLDB_API_DEPRECATED_IN_DOT_0
+#define LLDB_API_NEW_IN_DOT_1
+#define LLDB_API_DEPRECATED_IN_DOT_1
+#define LLDB_API_NEW_IN_DOT_2
+#define LLDB_API_DEPRECATED_IN_DOT_2
+#define LLDB_API_NEW_IN_DOT_3
+#define LLDB_API_DEPRECATED_IN_DOT_3
+#define LLDB_API_NEW_IN_DOT_4
+#define LLDB_API_DEPRECATED_IN_DOT_4
+#define LLDB_API_NEW_IN_DOT_5
+#define LLDB_API_DEPRECATED_IN_DOT_5
+#define LLDB_API_NEW_IN_DOT_6
+#define LLDB_API_DEPRECATED_IN_DOT_6
+#define LLDB_API_NEW_IN_DOT_7
+#define LLDB_API_DEPRECATED_IN_DOT_7
+#define LLDB_API_NEW_IN_DOT_8
+#define LLDB_API_DEPRECATED_IN_DOT_8
+#define LLDB_API_NEW_IN_DOT_9
+#define LLDB_API_DEPRECATED_IN_DOT_9
+#define LLDB_API_NEW_IN_DOT_10
+#define LLDB_API_DEPRECATED_IN_DOT_10
+#define LLDB_API_NEW_IN_DOT_11
+#define LLDB_API_DEPRECATED_IN_DOT_11
+#define LLDB_API_NEW_IN_DOT_12
+#define LLDB_API_DEPRECATED_IN_DOT_12
+#define LLDB_API_NEW_IN_DOT_13
+#define LLDB_API_DEPRECATED_IN_DOT_13
+#define LLDB_API_NEW_IN_DOT_14
+#define LLDB_API_DEPRECATED_IN_DOT_14
+#define LLDB_API_NEW_IN_DOT_15
+#define LLDB_API_DEPRECATED_IN_DOT_15
+#define LLDB_API_NEW_IN_DOT_16
+#define LLDB_API_DEPRECATED_IN_DOT_16
+#define LLDB_API_NEW_IN_DOT_17
+#define LLDB_API_DEPRECATED_IN_DOT_17
+#define LLDB_API_NEW_IN_DOT_18
+#define LLDB_API_DEPRECATED_IN_DOT_18
+#define LLDB_API_NEW_IN_DOT_19
+#define LLDB_API_DEPRECATED_IN_DOT_19
+#define LLDB_API_NEW_IN_DOT_20
+#define LLDB_API_DEPRECATED_IN_DOT_20
+#define LLDB_API_NEW_IN_DOT_21
+#define LLDB_API_DEPRECATED_IN_DOT_21
+#define LLDB_API_NEW_IN_DOT_22
+#define LLDB_API_DEPRECATED_IN_DOT_22
+#define LLDB_API_NEW_IN_DOT_23
+#define LLDB_API_DEPRECATED_IN_DOT_23
+#define LLDB_API_NEW_IN_DOT_24
+#define LLDB_API_DEPRECATED_IN_DOT_24
+#define LLDB_API_NEW_IN_DOT_25
+#define LLDB_API_DEPRECATED_IN_DOT_25
+#define LLDB_API_NEW_IN_DOT_26
+#define LLDB_API_DEPRECATED_IN_DOT_26
+#define LLDB_API_NEW_IN_DOT_27
+#define LLDB_API_DEPRECATED_IN_DOT_27
+#define LLDB_API_NEW_IN_DOT_28
+#define LLDB_API_DEPRECATED_IN_DOT_28
+#define LLDB_API_NEW_IN_DOT_29
+#define LLDB_API_DEPRECATED_IN_DOT_29
+#define LLDB_API_NEW_IN_DOT_30
+#define LLDB_API_DEPRECATED_IN_DOT_30
+#define LLDB_API_NEW_IN_DOT_31
+#define LLDB_API_DEPRECATED_IN_DOT_31
+#define LLDB_API_NEW_IN_DOT_32
+#define LLDB_API_DEPRECATED_IN_DOT_32
+#define LLDB_API_NEW_IN_DOT_33
+#define LLDB_API_DEPRECATED_IN_DOT_33
+#define LLDB_API_NEW_IN_DOT_34
+#define LLDB_API_DEPRECATED_IN_DOT_34
+#define LLDB_API_NEW_IN_DOT_35
+#define LLDB_API_DEPRECATED_IN_DOT_35
+#define LLDB_API_NEW_IN_DOT_36
+#define LLDB_API_DEPRECATED_IN_DOT_36
+#define LLDB_API_NEW_IN_DOT_37
+#define LLDB_API_DEPRECATED_IN_DOT_37
+#define LLDB_API_NEW_IN_DOT_38
+#define LLDB_API_DEPRECATED_IN_DOT_38
+#define LLDB_API_NEW_IN_DOT_39
+#define LLDB_API_DEPRECATED_IN_DOT_39
+#define LLDB_API_NEW_IN_DOT_40
+#define LLDB_API_DEPRECATED_IN_DOT_40
+#define LLDB_API_NEW_IN_DOT_41
+#define LLDB_API_DEPRECATED_IN_DOT_41
+#define LLDB_API_NEW_IN_DOT_42
+#define LLDB_API_DEPRECATED_IN_DOT_42
+#define LLDB_API_NEW_IN_DOT_43
+#define LLDB_API_DEPRECATED_IN_DOT_43
+#define LLDB_API_NEW_IN_DOT_44
+#define LLDB_API_DEPRECATED_IN_DOT_44
+#define LLDB_API_NEW_IN_DOT_45
+#define LLDB_API_DEPRECATED_IN_DOT_45
+#define LLDB_API_NEW_IN_DOT_46
+#define LLDB_API_DEPRECATED_IN_DOT_46
+#define LLDB_API_NEW_IN_DOT_47
+#define LLDB_API_DEPRECATED_IN_DOT_47
+#define LLDB_API_NEW_IN_DOT_48
+#define LLDB_API_DEPRECATED_IN_DOT_48
+#define LLDB_API_NEW_IN_DOT_49
+#define LLDB_API_DEPRECATED_IN_DOT_49
+#define LLDB_API_NEW_IN_DOT_50
+#define LLDB_API_DEPRECATED_IN_DOT_50
+#define LLDB_API_NEW_IN_DOT_51
+#define LLDB_API_DEPRECATED_IN_DOT_51
+#define LLDB_API_NEW_IN_DOT_52
+#define LLDB_API_DEPRECATED_IN_DOT_52
+#define LLDB_API_NEW_IN_DOT_53
+#define LLDB_API_DEPRECATED_IN_DOT_53
+#define LLDB_API_NEW_IN_DOT_54
+#define LLDB_API_DEPRECATED_IN_DOT_54
+#define LLDB_API_NEW_IN_DOT_55
+#define LLDB_API_DEPRECATED_IN_DOT_55
+#define LLDB_API_NEW_IN_DOT_56
+#define LLDB_API_DEPRECATED_IN_DOT_56
+#define LLDB_API_NEW_IN_DOT_57
+#define LLDB_API_DEPRECATED_IN_DOT_57
+#define LLDB_API_NEW_IN_DOT_58
+#define LLDB_API_DEPRECATED_IN_DOT_58
+#define LLDB_API_NEW_IN_DOT_59
+#define LLDB_API_DEPRECATED_IN_DOT_59
+#define LLDB_API_NEW_IN_DOT_60
+#define LLDB_API_DEPRECATED_IN_DOT_60
+#define LLDB_API_NEW_IN_DOT_61
+#define LLDB_API_DEPRECATED_IN_DOT_61
+#define LLDB_API_NEW_IN_DOT_62
+#define LLDB_API_DEPRECATED_IN_DOT_62
+#define LLDB_API_NEW_IN_DOT_63
+#define LLDB_API_DEPRECATED_IN_DOT_63
+#define LLDB_API_NEW_IN_DOT_64
+#define LLDB_API_DEPRECATED_IN_DOT_64
+#define LLDB_API_NEW_IN_DOT_65
+#define LLDB_API_DEPRECATED_IN_DOT_65
+#define LLDB_API_NEW_IN_DOT_66
+#define LLDB_API_DEPRECATED_IN_DOT_66
+#define LLDB_API_NEW_IN_DOT_67
+#define LLDB_API_DEPRECATED_IN_DOT_67
+#define LLDB_API_NEW_IN_DOT_68
+#define LLDB_API_DEPRECATED_IN_DOT_68
+#define LLDB_API_NEW_IN_DOT_69
+#define LLDB_API_DEPRECATED_IN_DOT_69
+#define LLDB_API_NEW_IN_DOT_70
+#define LLDB_API_DEPRECATED_IN_DOT_70
+#define LLDB_API_NEW_IN_DOT_71
+#define LLDB_API_DEPRECATED_IN_DOT_71
+#define LLDB_API_NEW_IN_DOT_72
+#define LLDB_API_DEPRECATED_IN_DOT_72
+#define LLDB_API_NEW_IN_DOT_73
+#define LLDB_API_DEPRECATED_IN_DOT_73
+#define LLDB_API_NEW_IN_DOT_74
+#define LLDB_API_DEPRECATED_IN_DOT_74
+#define LLDB_API_NEW_IN_DOT_75
+#define LLDB_API_DEPRECATED_IN_DOT_75
+#define LLDB_API_NEW_IN_DOT_76
+#define LLDB_API_DEPRECATED_IN_DOT_76
+#define LLDB_API_NEW_IN_DOT_77
+#define LLDB_API_DEPRECATED_IN_DOT_77
+#define LLDB_API_NEW_IN_DOT_78
+#define LLDB_API_DEPRECATED_IN_DOT_78
+#define LLDB_API_NEW_IN_DOT_79
+#define LLDB_API_DEPRECATED_IN_DOT_79
+#define LLDB_API_NEW_IN_DOT_80
+#define LLDB_API_DEPRECATED_IN_DOT_80
+#define LLDB_API_NEW_IN_DOT_81
+#define LLDB_API_DEPRECATED_IN_DOT_81
+#define LLDB_API_NEW_IN_DOT_82
+#define LLDB_API_DEPRECATED_IN_DOT_82
+#define LLDB_API_NEW_IN_DOT_83
+#define LLDB_API_DEPRECATED_IN_DOT_83
+#define LLDB_API_NEW_IN_DOT_84
+#define LLDB_API_DEPRECATED_IN_DOT_84
+#define LLDB_API_NEW_IN_DOT_85
+#define LLDB_API_DEPRECATED_IN_DOT_85
+#define LLDB_API_NEW_IN_DOT_86
+#define LLDB_API_DEPRECATED_IN_DOT_86
+#define LLDB_API_NEW_IN_DOT_87
+#define LLDB_API_DEPRECATED_IN_DOT_87
+#define LLDB_API_NEW_IN_DOT_88
+#define LLDB_API_DEPRECATED_IN_DOT_88
+#define LLDB_API_NEW_IN_DOT_89
+#define LLDB_API_DEPRECATED_IN_DOT_89
+#define LLDB_API_NEW_IN_DOT_90
+#define LLDB_API_DEPRECATED_IN_DOT_90
+#define LLDB_API_NEW_IN_DOT_91
+#define LLDB_API_DEPRECATED_IN_DOT_91
+#define LLDB_API_NEW_IN_DOT_92
+#define LLDB_API_DEPRECATED_IN_DOT_92
+#define LLDB_API_NEW_IN_DOT_93
+#define LLDB_API_DEPRECATED_IN_DOT_93
+#define LLDB_API_NEW_IN_DOT_94
+#define LLDB_API_DEPRECATED_IN_DOT_94
+#define LLDB_API_NEW_IN_DOT_95
+#define LLDB_API_DEPRECATED_IN_DOT_95
+#define LLDB_API_NEW_IN_DOT_96
+#define LLDB_API_DEPRECATED_IN_DOT_96
+#define LLDB_API_NEW_IN_DOT_97
+#define LLDB_API_DEPRECATED_IN_DOT_97
+#define LLDB_API_NEW_IN_DOT_98
+#define LLDB_API_DEPRECATED_IN_DOT_98
+#define LLDB_API_NEW_IN_DOT_99
+#define LLDB_API_DEPRECATED_IN_DOT_99
+#endif // defined(LLDB_CHECK_API_VERSIONING) && defined(LLDB_API_MAJOR_VERSION_WANTED) && defined(LLDB_API_MINOR_VERSION_WANTED) && defined (LLDB_API_MAJOR_VERSION)
+
+#endif // LLDB_lldb_versioning_h_ \ No newline at end of file
diff --git a/source/API/SBAddress.cpp b/source/API/SBAddress.cpp
new file mode 100644
index 000000000000..799c90907634
--- /dev/null
+++ b/source/API/SBAddress.cpp
@@ -0,0 +1,326 @@
+//===-- SBAddress.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/SBAddress.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBSection.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Target.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBAddress::SBAddress () :
+ m_opaque_ap ()
+{
+}
+
+SBAddress::SBAddress (const Address *lldb_object_ptr) :
+ m_opaque_ap ()
+{
+ if (lldb_object_ptr)
+ ref() = *lldb_object_ptr;
+}
+
+SBAddress::SBAddress (const SBAddress &rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+}
+
+
+SBAddress::SBAddress (lldb::SBSection section, lldb::addr_t offset) :
+ m_opaque_ap(new Address (section.GetSP(), 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()
+{
+ SetLoadAddress (load_addr, target);
+}
+
+
+
+SBAddress::~SBAddress ()
+{
+}
+
+const SBAddress &
+SBAddress::operator = (const SBAddress &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+ else
+ m_opaque_ap.reset();
+ }
+ return *this;
+}
+
+bool
+SBAddress::IsValid () const
+{
+ return m_opaque_ap.get() != NULL && m_opaque_ap->IsValid();
+}
+
+void
+SBAddress::Clear ()
+{
+ m_opaque_ap.reset();
+}
+
+void
+SBAddress::SetAddress (lldb::SBSection section, lldb::addr_t offset)
+{
+ Address &addr = ref();
+ addr.SetSection (section.GetSP());
+ addr.SetOffset (offset);
+}
+
+
+void
+SBAddress::SetAddress (const Address *lldb_object_ptr)
+{
+ if (lldb_object_ptr)
+ ref() = *lldb_object_ptr;
+ else
+ m_opaque_ap.reset();
+}
+
+lldb::addr_t
+SBAddress::GetFileAddress () const
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetFileAddress();
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+lldb::addr_t
+SBAddress::GetLoadAddress (const SBTarget &target) const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ lldb::addr_t addr = LLDB_INVALID_ADDRESS;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ if (m_opaque_ap.get())
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ addr = m_opaque_ap->GetLoadAddress (target_sp.get());
+ }
+ }
+
+ if (log)
+ {
+ if (addr == LLDB_INVALID_ADDRESS)
+ log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => LLDB_INVALID_ADDRESS", target_sp.get());
+ else
+ log->Printf ("SBAddress::GetLoadAddress (SBTarget(%p)) => 0x%" PRIx64, target_sp.get(), addr);
+ }
+
+ return addr;
+}
+
+void
+SBAddress::SetLoadAddress (lldb::addr_t load_addr, lldb::SBTarget &target)
+{
+ // Create the address object if we don't already have one
+ ref();
+ if (target.IsValid())
+ *this = target.ResolveLoadAddress(load_addr);
+ else
+ m_opaque_ap->Clear();
+
+ // Check if we weren't were able to resolve a section offset address.
+ // If we weren't it is ok, the load address might be a location on the
+ // stack or heap, so we should just have an address with no section and
+ // a valid offset
+ if (!m_opaque_ap->IsValid())
+ m_opaque_ap->SetOffset(load_addr);
+}
+
+bool
+SBAddress::OffsetAddress (addr_t offset)
+{
+ if (m_opaque_ap.get())
+ {
+ addr_t addr_offset = m_opaque_ap->GetOffset();
+ if (addr_offset != LLDB_INVALID_ADDRESS)
+ {
+ m_opaque_ap->SetOffset(addr_offset + offset);
+ return true;
+ }
+ }
+ return false;
+}
+
+lldb::SBSection
+SBAddress::GetSection ()
+{
+ lldb::SBSection sb_section;
+ if (m_opaque_ap.get())
+ sb_section.SetSP (m_opaque_ap->GetSection());
+ return sb_section;
+}
+
+lldb::addr_t
+SBAddress::GetOffset ()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetOffset();
+ return 0;
+}
+
+Address *
+SBAddress::operator->()
+{
+ return m_opaque_ap.get();
+}
+
+const Address *
+SBAddress::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+Address &
+SBAddress::ref ()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new Address());
+ return *m_opaque_ap;
+}
+
+const Address &
+SBAddress::ref () const
+{
+ // This object should already have checked with "IsValid()"
+ // prior to calling this function. In case you didn't we will assert
+ // and die to let you know.
+ assert (m_opaque_ap.get());
+ return *m_opaque_ap;
+}
+
+Address *
+SBAddress::get ()
+{
+ return m_opaque_ap.get();
+}
+
+bool
+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())
+ {
+ m_opaque_ap->Dump (&strm,
+ NULL,
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress,
+ 4);
+ StreamString sstrm;
+// m_opaque_ap->Dump (&sstrm, NULL, Address::DumpStyleResolvedDescription, Address::DumpStyleInvalid, 4);
+// if (sstrm.GetData())
+// strm.Printf (" (%s)", sstrm.GetData());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+SBModule
+SBAddress::GetModule ()
+{
+ SBModule sb_module;
+ if (m_opaque_ap.get())
+ sb_module.SetSP (m_opaque_ap->GetModule());
+ return sb_module;
+}
+
+SBSymbolContext
+SBAddress::GetSymbolContext (uint32_t resolve_scope)
+{
+ SBSymbolContext sb_sc;
+ if (m_opaque_ap.get())
+ m_opaque_ap->CalculateSymbolContext (&sb_sc.ref(), resolve_scope);
+ return sb_sc;
+}
+
+SBCompileUnit
+SBAddress::GetCompileUnit ()
+{
+ SBCompileUnit sb_comp_unit;
+ if (m_opaque_ap.get())
+ sb_comp_unit.reset(m_opaque_ap->CalculateSymbolContextCompileUnit());
+ return sb_comp_unit;
+}
+
+SBFunction
+SBAddress::GetFunction ()
+{
+ SBFunction sb_function;
+ if (m_opaque_ap.get())
+ sb_function.reset(m_opaque_ap->CalculateSymbolContextFunction());
+ return sb_function;
+}
+
+SBBlock
+SBAddress::GetBlock ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ap.get())
+ sb_block.SetPtr(m_opaque_ap->CalculateSymbolContextBlock());
+ return sb_block;
+}
+
+SBSymbol
+SBAddress::GetSymbol ()
+{
+ SBSymbol sb_symbol;
+ if (m_opaque_ap.get())
+ sb_symbol.reset(m_opaque_ap->CalculateSymbolContextSymbol());
+ return sb_symbol;
+}
+
+SBLineEntry
+SBAddress::GetLineEntry ()
+{
+ SBLineEntry sb_line_entry;
+ if (m_opaque_ap.get())
+ {
+ LineEntry line_entry;
+ if (m_opaque_ap->CalculateSymbolContextLineEntry (line_entry))
+ sb_line_entry.SetLineEntry (line_entry);
+ }
+ return sb_line_entry;
+}
+
+AddressClass
+SBAddress::GetAddressClass ()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetAddressClass();
+ return eAddressClassInvalid;
+}
+
diff --git a/source/API/SBBlock.cpp b/source/API/SBBlock.cpp
new file mode 100644
index 000000000000..c8a665f7d6fb
--- /dev/null
+++ b/source/API/SBBlock.cpp
@@ -0,0 +1,373 @@
+//===-- SBBlock.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/SBBlock.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBBlock::SBBlock () :
+ m_opaque_ptr (NULL)
+{
+}
+
+SBBlock::SBBlock (lldb_private::Block *lldb_object_ptr) :
+ m_opaque_ptr (lldb_object_ptr)
+{
+}
+
+SBBlock::SBBlock(const SBBlock &rhs) :
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBBlock &
+SBBlock::operator = (const SBBlock &rhs)
+{
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ return *this;
+}
+
+SBBlock::~SBBlock ()
+{
+ m_opaque_ptr = NULL;
+}
+
+bool
+SBBlock::IsValid () const
+{
+ return m_opaque_ptr != NULL;
+}
+
+bool
+SBBlock::IsInlined () const
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetInlinedFunctionInfo () != NULL;
+ return false;
+}
+
+const char *
+SBBlock::GetInlinedName () const
+{
+ if (m_opaque_ptr)
+ {
+ const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo ();
+ if (inlined_info)
+ return inlined_info->GetName().AsCString (NULL);
+ }
+ return NULL;
+}
+
+SBFileSpec
+SBBlock::GetInlinedCallSiteFile () const
+{
+ SBFileSpec sb_file;
+ if (m_opaque_ptr)
+ {
+ const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo ();
+ if (inlined_info)
+ sb_file.SetFileSpec (inlined_info->GetCallSite().GetFile());
+ }
+ return sb_file;
+}
+
+uint32_t
+SBBlock::GetInlinedCallSiteLine () const
+{
+ if (m_opaque_ptr)
+ {
+ const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo ();
+ if (inlined_info)
+ return inlined_info->GetCallSite().GetLine();
+ }
+ return 0;
+}
+
+uint32_t
+SBBlock::GetInlinedCallSiteColumn () const
+{
+ if (m_opaque_ptr)
+ {
+ const InlineFunctionInfo* inlined_info = m_opaque_ptr->GetInlinedFunctionInfo ();
+ if (inlined_info)
+ return inlined_info->GetCallSite().GetColumn();
+ }
+ return 0;
+}
+
+void
+SBBlock::AppendVariables (bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list)
+{
+ if (IsValid())
+ {
+ bool show_inline = true;
+ m_opaque_ptr->AppendVariables (can_create, get_parent_variables, show_inline, var_list);
+ }
+}
+
+SBBlock
+SBBlock::GetParent ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ptr)
+ sb_block.m_opaque_ptr = m_opaque_ptr->GetParent();
+ return sb_block;
+}
+
+lldb::SBBlock
+SBBlock::GetContainingInlinedBlock ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ptr)
+ sb_block.m_opaque_ptr = m_opaque_ptr->GetContainingInlinedBlock ();
+ return sb_block;
+}
+
+SBBlock
+SBBlock::GetSibling ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ptr)
+ sb_block.m_opaque_ptr = m_opaque_ptr->GetSibling();
+ return sb_block;
+}
+
+SBBlock
+SBBlock::GetFirstChild ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ptr)
+ sb_block.m_opaque_ptr = m_opaque_ptr->GetFirstChild();
+ return sb_block;
+}
+
+lldb_private::Block *
+SBBlock::GetPtr ()
+{
+ return m_opaque_ptr;
+}
+
+void
+SBBlock::SetPtr (lldb_private::Block *block)
+{
+ m_opaque_ptr = block;
+}
+
+bool
+SBBlock::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ptr)
+ {
+ lldb::user_id_t id = m_opaque_ptr->GetID();
+ strm.Printf ("Block: {id: %" PRIu64 "} ", id);
+ if (IsInlined())
+ {
+ strm.Printf (" (inlined, '%s') ", GetInlinedName());
+ }
+ lldb_private::SymbolContext sc;
+ m_opaque_ptr->CalculateSymbolContext (&sc);
+ if (sc.function)
+ {
+ m_opaque_ptr->DumpAddressRanges (&strm,
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress());
+ }
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+uint32_t
+SBBlock::GetNumRanges ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetNumRanges();
+ return 0;
+}
+
+lldb::SBAddress
+SBBlock::GetRangeStartAddress (uint32_t idx)
+{
+ lldb::SBAddress sb_addr;
+ if (m_opaque_ptr)
+ {
+ AddressRange range;
+ if (m_opaque_ptr->GetRangeAtIndex(idx, range))
+ {
+ sb_addr.ref() = range.GetBaseAddress();
+ }
+ }
+ return sb_addr;
+}
+
+lldb::SBAddress
+SBBlock::GetRangeEndAddress (uint32_t idx)
+{
+ lldb::SBAddress sb_addr;
+ if (m_opaque_ptr)
+ {
+ AddressRange range;
+ if (m_opaque_ptr->GetRangeAtIndex(idx, range))
+ {
+ sb_addr.ref() = range.GetBaseAddress();
+ sb_addr.ref().Slide(range.GetByteSize());
+ }
+ }
+ return sb_addr;
+}
+
+uint32_t
+SBBlock::GetRangeIndexForBlockAddress (lldb::SBAddress block_addr)
+{
+ if (m_opaque_ptr && block_addr.IsValid())
+ {
+ return m_opaque_ptr->GetRangeIndexContainingAddress (block_addr.ref());
+ }
+
+ return UINT32_MAX;
+}
+
+
+lldb::SBValueList
+SBBlock::GetVariables (lldb::SBFrame& frame,
+ bool arguments,
+ bool locals,
+ bool statics,
+ lldb::DynamicValueType use_dynamic)
+{
+ Block *block = GetPtr();
+ SBValueList value_list;
+ if (block)
+ {
+ StackFrameSP frame_sp(frame.GetFrameSP());
+ VariableListSP variable_list_sp (block->GetBlockVariableList (true));
+
+ if (variable_list_sp)
+ {
+ const size_t num_variables = variable_list_sp->GetSize();
+ if (num_variables)
+ {
+ for (size_t i = 0; i < num_variables; ++i)
+ {
+ VariableSP variable_sp (variable_list_sp->GetVariableAtIndex(i));
+ if (variable_sp)
+ {
+ bool add_variable = false;
+ switch (variable_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ case eValueTypeVariableStatic:
+ add_variable = statics;
+ break;
+
+ case eValueTypeVariableArgument:
+ add_variable = arguments;
+ break;
+
+ case eValueTypeVariableLocal:
+ add_variable = locals;
+ break;
+
+ default:
+ break;
+ }
+ if (add_variable)
+ {
+ if (frame_sp)
+ {
+ lldb::ValueObjectSP valobj_sp(frame_sp->GetValueObjectForFrameVariable (variable_sp,eNoDynamicValues));
+ SBValue value_sb;
+ value_sb.SetSP(valobj_sp, use_dynamic);
+ value_list.Append (value_sb);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return value_list;
+}
+
+lldb::SBValueList
+SBBlock::GetVariables (lldb::SBTarget& target,
+ bool arguments,
+ bool locals,
+ bool statics)
+{
+ Block *block = GetPtr();
+
+ SBValueList value_list;
+ if (block)
+ {
+ TargetSP target_sp(target.GetSP());
+
+ VariableListSP variable_list_sp (block->GetBlockVariableList (true));
+
+ if (variable_list_sp)
+ {
+ const size_t num_variables = variable_list_sp->GetSize();
+ if (num_variables)
+ {
+ for (size_t i = 0; i < num_variables; ++i)
+ {
+ VariableSP variable_sp (variable_list_sp->GetVariableAtIndex(i));
+ if (variable_sp)
+ {
+ bool add_variable = false;
+ switch (variable_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ case eValueTypeVariableStatic:
+ add_variable = statics;
+ break;
+
+ case eValueTypeVariableArgument:
+ add_variable = arguments;
+ break;
+
+ case eValueTypeVariableLocal:
+ add_variable = locals;
+ break;
+
+ default:
+ break;
+ }
+ if (add_variable)
+ {
+ if (target_sp)
+ value_list.Append (ValueObjectVariable::Create (target_sp.get(), variable_sp));
+ }
+ }
+ }
+ }
+ }
+ }
+ return value_list;
+}
+
diff --git a/source/API/SBBreakpoint.cpp b/source/API/SBBreakpoint.cpp
new file mode 100644
index 000000000000..11ad149fdddc
--- /dev/null
+++ b/source/API/SBBreakpoint.cpp
@@ -0,0 +1,648 @@
+//===-- SBBreakpoint.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/SBBreakpoint.h"
+#include "lldb/API/SBBreakpointLocation.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBThread.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+
+#include "lldb/lldb-enumerations.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+struct CallbackData
+{
+ SBBreakpoint::BreakpointHitCallback callback;
+ void *callback_baton;
+};
+
+class SBBreakpointCallbackBaton : public Baton
+{
+public:
+
+ SBBreakpointCallbackBaton (SBBreakpoint::BreakpointHitCallback callback, void *baton) :
+ Baton (new CallbackData)
+ {
+ CallbackData *data = (CallbackData *)m_data;
+ data->callback = callback;
+ data->callback_baton = baton;
+ }
+
+ virtual ~SBBreakpointCallbackBaton()
+ {
+ CallbackData *data = (CallbackData *)m_data;
+
+ if (data)
+ {
+ delete data;
+ m_data = NULL;
+ }
+ }
+};
+
+
+SBBreakpoint::SBBreakpoint () :
+ m_opaque_sp ()
+{
+}
+
+SBBreakpoint::SBBreakpoint (const SBBreakpoint& rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+
+SBBreakpoint::SBBreakpoint (const lldb::BreakpointSP &bp_sp) :
+ m_opaque_sp (bp_sp)
+{
+}
+
+SBBreakpoint::~SBBreakpoint()
+{
+}
+
+const SBBreakpoint &
+SBBreakpoint::operator = (const SBBreakpoint& rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+bool
+SBBreakpoint::operator == (const lldb::SBBreakpoint& rhs)
+{
+ if (m_opaque_sp && rhs.m_opaque_sp)
+ return m_opaque_sp.get() == rhs.m_opaque_sp.get();
+ return false;
+}
+
+bool
+SBBreakpoint::operator != (const lldb::SBBreakpoint& rhs)
+{
+ if (m_opaque_sp && rhs.m_opaque_sp)
+ return m_opaque_sp.get() != rhs.m_opaque_sp.get();
+ return (m_opaque_sp && !rhs.m_opaque_sp) || (rhs.m_opaque_sp && !m_opaque_sp);
+}
+
+break_id_t
+SBBreakpoint::GetID () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ break_id_t break_id = LLDB_INVALID_BREAK_ID;
+ if (m_opaque_sp)
+ break_id = m_opaque_sp->GetID();
+
+ if (log)
+ {
+ if (break_id == LLDB_INVALID_BREAK_ID)
+ log->Printf ("SBBreakpoint(%p)::GetID () => LLDB_INVALID_BREAK_ID", m_opaque_sp.get());
+ else
+ log->Printf ("SBBreakpoint(%p)::GetID () => %u", m_opaque_sp.get(), break_id);
+ }
+
+ return break_id;
+}
+
+
+bool
+SBBreakpoint::IsValid() const
+{
+ return (bool) m_opaque_sp;
+}
+
+void
+SBBreakpoint::ClearAllBreakpointSites ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->ClearAllBreakpointSites ();
+ }
+}
+
+SBBreakpointLocation
+SBBreakpoint::FindLocationByAddress (addr_t vm_addr)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_opaque_sp)
+ {
+ if (vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ Address address;
+ Target &target = m_opaque_sp->GetTarget();
+ if (target.GetSectionLoadList().ResolveLoadAddress (vm_addr, address) == false)
+ {
+ address.SetRawAddress (vm_addr);
+ }
+ sb_bp_location.SetLocation (m_opaque_sp->FindLocationByAddress (address));
+ }
+ }
+ return sb_bp_location;
+}
+
+break_id_t
+SBBreakpoint::FindLocationIDByAddress (addr_t vm_addr)
+{
+ break_id_t break_id = LLDB_INVALID_BREAK_ID;
+
+ if (m_opaque_sp && vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ Address address;
+ Target &target = m_opaque_sp->GetTarget();
+ if (target.GetSectionLoadList().ResolveLoadAddress (vm_addr, address) == false)
+ {
+ address.SetRawAddress (vm_addr);
+ }
+ break_id = m_opaque_sp->FindLocationIDByAddress (address);
+ }
+
+ return break_id;
+}
+
+SBBreakpointLocation
+SBBreakpoint::FindLocationByID (break_id_t bp_loc_id)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ sb_bp_location.SetLocation (m_opaque_sp->FindLocationByID (bp_loc_id));
+ }
+
+ return sb_bp_location;
+}
+
+SBBreakpointLocation
+SBBreakpoint::GetLocationAtIndex (uint32_t index)
+{
+ SBBreakpointLocation sb_bp_location;
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ sb_bp_location.SetLocation (m_opaque_sp->GetLocationAtIndex (index));
+ }
+
+ return sb_bp_location;
+}
+
+void
+SBBreakpoint::SetEnabled (bool enable)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetEnabled (enabled=%i)", m_opaque_sp.get(), enable);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetEnabled (enable);
+ }
+}
+
+bool
+SBBreakpoint::IsEnabled ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->IsEnabled();
+ }
+ else
+ return false;
+}
+
+void
+SBBreakpoint::SetOneShot (bool one_shot)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetOneShot (one_shot=%i)", m_opaque_sp.get(), one_shot);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetOneShot (one_shot);
+ }
+}
+
+bool
+SBBreakpoint::IsOneShot () const
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->IsOneShot();
+ }
+ else
+ return false;
+}
+
+bool
+SBBreakpoint::IsInternal ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->IsInternal();
+ }
+ else
+ return false;
+}
+
+void
+SBBreakpoint::SetIgnoreCount (uint32_t count)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetIgnoreCount (count=%u)", m_opaque_sp.get(), count);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetIgnoreCount (count);
+ }
+}
+
+void
+SBBreakpoint::SetCondition (const char *condition)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetCondition (condition);
+ }
+}
+
+const char *
+SBBreakpoint::GetCondition ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetConditionText ();
+ }
+ return NULL;
+}
+
+uint32_t
+SBBreakpoint::GetHitCount () const
+{
+ uint32_t count = 0;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ count = m_opaque_sp->GetHitCount();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetHitCount () => %u", m_opaque_sp.get(), count);
+
+ return count;
+}
+
+uint32_t
+SBBreakpoint::GetIgnoreCount () const
+{
+ uint32_t count = 0;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ count = m_opaque_sp->GetIgnoreCount();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetIgnoreCount () => %u", m_opaque_sp.get(), count);
+
+ return count;
+}
+
+void
+SBBreakpoint::SetThreadID (tid_t tid)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->SetThreadID (tid);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetThreadID (tid=0x%4.4" PRIx64 ")", m_opaque_sp.get(), tid);
+
+}
+
+tid_t
+SBBreakpoint::GetThreadID ()
+{
+ tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ tid = m_opaque_sp->GetThreadID();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetThreadID () => 0x%4.4" PRIx64, m_opaque_sp.get(), tid);
+ return tid;
+}
+
+void
+SBBreakpoint::SetThreadIndex (uint32_t index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetThreadIndex (%u)", m_opaque_sp.get(), index);
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->GetOptions()->GetThreadSpec()->SetIndex (index);
+ }
+}
+
+uint32_t
+SBBreakpoint::GetThreadIndex() const
+{
+ uint32_t thread_idx = UINT32_MAX;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ const ThreadSpec *thread_spec = m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ if (thread_spec != NULL)
+ thread_idx = thread_spec->GetIndex();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetThreadIndex () => %u", m_opaque_sp.get(), thread_idx);
+
+ return thread_idx;
+}
+
+
+void
+SBBreakpoint::SetThreadName (const char *thread_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetThreadName (%s)", m_opaque_sp.get(), thread_name);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->GetOptions()->GetThreadSpec()->SetName (thread_name);
+ }
+}
+
+const char *
+SBBreakpoint::GetThreadName () const
+{
+ const char *name = NULL;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ const ThreadSpec *thread_spec = m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ if (thread_spec != NULL)
+ name = thread_spec->GetName();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetThreadName () => %s", m_opaque_sp.get(), name);
+
+ return name;
+}
+
+void
+SBBreakpoint::SetQueueName (const char *queue_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetQueueName (%s)", m_opaque_sp.get(), queue_name);
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ m_opaque_sp->GetOptions()->GetThreadSpec()->SetQueueName (queue_name);
+ }
+}
+
+const char *
+SBBreakpoint::GetQueueName () const
+{
+ const char *name = NULL;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ const ThreadSpec *thread_spec = m_opaque_sp->GetOptions()->GetThreadSpecNoCreate();
+ if (thread_spec)
+ name = thread_spec->GetQueueName();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetQueueName () => %s", m_opaque_sp.get(), name);
+
+ return name;
+}
+
+size_t
+SBBreakpoint::GetNumResolvedLocations() const
+{
+ size_t num_resolved = 0;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ num_resolved = m_opaque_sp->GetNumResolvedLocations();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetNumResolvedLocations () => %" PRIu64, m_opaque_sp.get(), (uint64_t)num_resolved);
+ return num_resolved;
+}
+
+size_t
+SBBreakpoint::GetNumLocations() const
+{
+ size_t num_locs = 0;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ num_locs = m_opaque_sp->GetNumLocations();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::GetNumLocations () => %" PRIu64, m_opaque_sp.get(), (uint64_t)num_locs);
+ return num_locs;
+}
+
+bool
+SBBreakpoint::GetDescription (SBStream &s)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ s.Printf("SBBreakpoint: id = %i, ", m_opaque_sp->GetID());
+ m_opaque_sp->GetResolverDescription (s.get());
+ m_opaque_sp->GetFilterDescription (s.get());
+ const size_t num_locations = m_opaque_sp->GetNumLocations ();
+ s.Printf(", locations = %" PRIu64, (uint64_t)num_locations);
+ return true;
+ }
+ s.Printf ("No value");
+ return false;
+}
+
+bool
+SBBreakpoint::PrivateBreakpointHitCallback
+(
+ void *baton,
+ StoppointCallbackContext *ctx,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id
+)
+{
+ ExecutionContext exe_ctx (ctx->exe_ctx_ref);
+ BreakpointSP bp_sp(exe_ctx.GetTargetRef().GetBreakpointList().FindBreakpointByID(break_id));
+ if (baton && bp_sp)
+ {
+ CallbackData *data = (CallbackData *)baton;
+ lldb_private::Breakpoint *bp = bp_sp.get();
+ if (bp && data->callback)
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ SBProcess sb_process (process->shared_from_this());
+ SBThread sb_thread;
+ SBBreakpointLocation sb_location;
+ assert (bp_sp);
+ sb_location.SetLocation (bp_sp->FindLocationByID (break_loc_id));
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread)
+ sb_thread.SetThread(thread->shared_from_this());
+
+ return data->callback (data->callback_baton,
+ sb_process,
+ sb_thread,
+ sb_location);
+ }
+ }
+ }
+ return true; // Return true if we should stop at this breakpoint
+}
+
+void
+SBBreakpoint::SetCallback (BreakpointHitCallback callback, void *baton)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBreakpoint(%p)::SetCallback (callback=%p, baton=%p)", m_opaque_sp.get(), callback, baton);
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex());
+ BatonSP baton_sp(new SBBreakpointCallbackBaton (callback, baton));
+ m_opaque_sp->SetCallback (SBBreakpoint::PrivateBreakpointHitCallback, baton_sp, false);
+ }
+}
+
+
+lldb_private::Breakpoint *
+SBBreakpoint::operator->() const
+{
+ return m_opaque_sp.get();
+}
+
+lldb_private::Breakpoint *
+SBBreakpoint::get() const
+{
+ return m_opaque_sp.get();
+}
+
+lldb::BreakpointSP &
+SBBreakpoint::operator *()
+{
+ return m_opaque_sp;
+}
+
+const lldb::BreakpointSP &
+SBBreakpoint::operator *() const
+{
+ return m_opaque_sp;
+}
+
+bool
+SBBreakpoint::EventIsBreakpointEvent (const lldb::SBEvent &event)
+{
+ return Breakpoint::BreakpointEventData::GetEventDataFromEvent(event.get()) != NULL;
+
+}
+
+BreakpointEventType
+SBBreakpoint::GetBreakpointEventTypeFromEvent (const SBEvent& event)
+{
+ if (event.IsValid())
+ return Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (event.GetSP());
+ return eBreakpointEventTypeInvalidType;
+}
+
+SBBreakpoint
+SBBreakpoint::GetBreakpointFromEvent (const lldb::SBEvent& event)
+{
+ SBBreakpoint sb_breakpoint;
+ if (event.IsValid())
+ sb_breakpoint.m_opaque_sp = Breakpoint::BreakpointEventData::GetBreakpointFromEvent (event.GetSP());
+ return sb_breakpoint;
+}
+
+SBBreakpointLocation
+SBBreakpoint::GetBreakpointLocationAtIndexFromEvent (const lldb::SBEvent& event, uint32_t loc_idx)
+{
+ SBBreakpointLocation sb_breakpoint_loc;
+ if (event.IsValid())
+ sb_breakpoint_loc.SetLocation (Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent (event.GetSP(), loc_idx));
+ return sb_breakpoint_loc;
+}
+
+uint32_t
+SBBreakpoint::GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event)
+{
+ uint32_t num_locations = 0;
+ if (event.IsValid())
+ num_locations = (Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent (event.GetSP()));
+ return num_locations;
+}
+
+
diff --git a/source/API/SBBreakpointLocation.cpp b/source/API/SBBreakpointLocation.cpp
new file mode 100644
index 000000000000..6fdf59f38b4a
--- /dev/null
+++ b/source/API/SBBreakpointLocation.cpp
@@ -0,0 +1,320 @@
+//===-- SBBreakpointLocation.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/SBBreakpointLocation.h"
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBBreakpointLocation::SBBreakpointLocation () :
+ m_opaque_sp ()
+{
+}
+
+SBBreakpointLocation::SBBreakpointLocation (const lldb::BreakpointLocationSP &break_loc_sp) :
+ m_opaque_sp (break_loc_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream sstr;
+ GetDescription (sstr, lldb::eDescriptionLevelBrief);
+ log->Printf ("SBBreakpointLocation::SBBreakpointLocaiton (const lldb::BreakpointLocationsSP &break_loc_sp"
+ "=%p) => this.sp = %p (%s)", break_loc_sp.get(), m_opaque_sp.get(), sstr.GetData());
+ }
+}
+
+SBBreakpointLocation::SBBreakpointLocation(const SBBreakpointLocation &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBBreakpointLocation &
+SBBreakpointLocation::operator = (const SBBreakpointLocation &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+
+SBBreakpointLocation::~SBBreakpointLocation ()
+{
+}
+
+bool
+SBBreakpointLocation::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+SBAddress
+SBBreakpointLocation::GetAddress ()
+{
+ if (m_opaque_sp)
+ return SBAddress(&m_opaque_sp->GetAddress());
+ else
+ return SBAddress();
+}
+
+addr_t
+SBBreakpointLocation::GetLoadAddress ()
+{
+ addr_t ret_addr = LLDB_INVALID_ADDRESS;
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ ret_addr = m_opaque_sp->GetLoadAddress();
+ }
+
+ return ret_addr;
+}
+
+void
+SBBreakpointLocation::SetEnabled (bool enabled)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetEnabled (enabled);
+ }
+}
+
+bool
+SBBreakpointLocation::IsEnabled ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->IsEnabled();
+ }
+ else
+ return false;
+}
+
+uint32_t
+SBBreakpointLocation::GetIgnoreCount ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetIgnoreCount();
+ }
+ else
+ return 0;
+}
+
+void
+SBBreakpointLocation::SetIgnoreCount (uint32_t n)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetIgnoreCount (n);
+ }
+}
+
+void
+SBBreakpointLocation::SetCondition (const char *condition)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetCondition (condition);
+ }
+}
+
+const char *
+SBBreakpointLocation::GetCondition ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetConditionText ();
+ }
+ return NULL;
+}
+
+void
+SBBreakpointLocation::SetThreadID (tid_t thread_id)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetThreadID (thread_id);
+ }
+}
+
+tid_t
+SBBreakpointLocation::GetThreadID ()
+{
+ tid_t tid = LLDB_INVALID_THREAD_ID;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetThreadID();
+ }
+ return tid;
+}
+
+void
+SBBreakpointLocation::SetThreadIndex (uint32_t index)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetThreadIndex (index);
+ }
+}
+
+uint32_t
+SBBreakpointLocation::GetThreadIndex() const
+{
+ uint32_t thread_idx = UINT32_MAX;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetThreadIndex();
+ }
+ return thread_idx;
+}
+
+
+void
+SBBreakpointLocation::SetThreadName (const char *thread_name)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetThreadName (thread_name);
+ }
+}
+
+const char *
+SBBreakpointLocation::GetThreadName () const
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetThreadName();
+ }
+ return NULL;
+}
+
+void
+SBBreakpointLocation::SetQueueName (const char *queue_name)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->SetQueueName (queue_name);
+ }
+}
+
+const char *
+SBBreakpointLocation::GetQueueName () const
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->GetQueueName ();
+ }
+ return NULL;
+}
+
+bool
+SBBreakpointLocation::IsResolved ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->IsResolved();
+ }
+ return false;
+}
+
+void
+SBBreakpointLocation::SetLocation (const lldb::BreakpointLocationSP &break_loc_sp)
+{
+ // Uninstall the callbacks?
+ m_opaque_sp = break_loc_sp;
+}
+
+bool
+SBBreakpointLocation::GetDescription (SBStream &description, DescriptionLevel level)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ m_opaque_sp->GetDescription (&strm, level);
+ strm.EOL();
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+break_id_t
+SBBreakpointLocation::GetID ()
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ return m_opaque_sp->GetID ();
+ }
+ else
+ return LLDB_INVALID_BREAK_ID;
+}
+
+SBBreakpoint
+SBBreakpointLocation::GetBreakpoint ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ //if (log)
+ // log->Printf ("SBBreakpointLocation::GetBreakpoint ()");
+
+ SBBreakpoint sb_bp;
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex());
+ *sb_bp = m_opaque_sp->GetBreakpoint ().shared_from_this();
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_bp.GetDescription (sstr);
+ log->Printf ("SBBreakpointLocation(%p)::GetBreakpoint () => SBBreakpoint(%p) %s",
+ m_opaque_sp.get(), sb_bp.get(), sstr.GetData());
+ }
+ return sb_bp;
+}
+
diff --git a/source/API/SBBroadcaster.cpp b/source/API/SBBroadcaster.cpp
new file mode 100644
index 000000000000..7168305ac80b
--- /dev/null
+++ b/source/API/SBBroadcaster.cpp
@@ -0,0 +1,196 @@
+//===-- SBBroadcaster.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/Broadcaster.h"
+#include "lldb/Core/Log.h"
+
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBEvent.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBBroadcaster::SBBroadcaster () :
+ m_opaque_sp (),
+ m_opaque_ptr (NULL)
+{
+}
+
+SBBroadcaster::SBBroadcaster (const char *name) :
+ m_opaque_sp (new Broadcaster (NULL, name)),
+ m_opaque_ptr (NULL)
+{
+ m_opaque_ptr = m_opaque_sp.get();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API | LIBLLDB_LOG_VERBOSE));
+
+ if (log)
+ log->Printf ("SBBroadcaster::SBBroadcaster (name=\"%s\") => SBBroadcaster(%p)",
+ name, m_opaque_ptr);
+}
+
+SBBroadcaster::SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns) :
+ m_opaque_sp (owns ? broadcaster : NULL),
+ m_opaque_ptr (broadcaster)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API | LIBLLDB_LOG_VERBOSE));
+
+ if (log)
+ log->Printf ("SBBroadcaster::SBBroadcaster (broadcaster=%p, bool owns=%i) => SBBroadcaster(%p)",
+ broadcaster, owns, m_opaque_ptr);
+}
+
+SBBroadcaster::SBBroadcaster (const SBBroadcaster &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp),
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBBroadcaster &
+SBBroadcaster::operator = (const SBBroadcaster &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ }
+ return *this;
+}
+
+SBBroadcaster::~SBBroadcaster()
+{
+ reset (NULL, false);
+}
+
+void
+SBBroadcaster::BroadcastEventByType (uint32_t event_type, bool unique)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (event_type=0x%8.8x, unique=%i)", m_opaque_ptr, event_type, unique);
+
+ if (m_opaque_ptr == NULL)
+ return;
+
+ if (unique)
+ m_opaque_ptr->BroadcastEventIfUnique (event_type);
+ else
+ m_opaque_ptr->BroadcastEvent (event_type);
+}
+
+void
+SBBroadcaster::BroadcastEvent (const SBEvent &event, bool unique)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBBroadcaster(%p)::BroadcastEventByType (SBEvent(%p), unique=%i)", m_opaque_ptr, event.get(), unique);
+
+ if (m_opaque_ptr == NULL)
+ return;
+
+ EventSP event_sp = event.GetSP ();
+ if (unique)
+ m_opaque_ptr->BroadcastEventIfUnique (event_sp);
+ else
+ m_opaque_ptr->BroadcastEvent (event_sp);
+}
+
+void
+SBBroadcaster::AddInitialEventsToListener (const SBListener &listener, uint32_t requested_events)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBBroadcaster(%p)::AddInitialEventsToListener (SBListener(%p), event_mask=0x%8.8x)", m_opaque_ptr, listener.get(), requested_events);
+ if (m_opaque_ptr)
+ m_opaque_ptr->AddInitialEventsToListener (listener.get(), requested_events);
+}
+
+uint32_t
+SBBroadcaster::AddListener (const SBListener &listener, uint32_t event_mask)
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->AddListener (listener.get(), event_mask);
+ return 0;
+}
+
+const char *
+SBBroadcaster::GetName () const
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetBroadcasterName().GetCString();
+ return NULL;
+}
+
+bool
+SBBroadcaster::EventTypeHasListeners (uint32_t event_type)
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->EventTypeHasListeners (event_type);
+ return false;
+}
+
+bool
+SBBroadcaster::RemoveListener (const SBListener &listener, uint32_t event_mask)
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->RemoveListener (listener.get(), event_mask);
+ return false;
+}
+
+Broadcaster *
+SBBroadcaster::get () const
+{
+ return m_opaque_ptr;
+}
+
+void
+SBBroadcaster::reset (Broadcaster *broadcaster, bool owns)
+{
+ if (owns)
+ m_opaque_sp.reset (broadcaster);
+ else
+ m_opaque_sp.reset ();
+ m_opaque_ptr = broadcaster;
+}
+
+
+bool
+SBBroadcaster::IsValid () const
+{
+ return m_opaque_ptr != NULL;
+}
+
+void
+SBBroadcaster::Clear ()
+{
+ m_opaque_sp.reset();
+ m_opaque_ptr = NULL;
+}
+
+bool
+SBBroadcaster::operator == (const SBBroadcaster &rhs) const
+{
+ return m_opaque_ptr == rhs.m_opaque_ptr;
+
+}
+
+bool
+SBBroadcaster::operator != (const SBBroadcaster &rhs) const
+{
+ return m_opaque_ptr != rhs.m_opaque_ptr;
+}
+
+bool
+SBBroadcaster::operator < (const SBBroadcaster &rhs) const
+{
+ return m_opaque_ptr < rhs.m_opaque_ptr;
+}
diff --git a/source/API/SBCommandInterpreter.cpp b/source/API/SBCommandInterpreter.cpp
new file mode 100644
index 000000000000..0c839004601c
--- /dev/null
+++ b/source/API/SBCommandInterpreter.cpp
@@ -0,0 +1,490 @@
+//===-- SBCommandInterpreter.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/lldb-types.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CommandPluginInterfaceImplementation : public CommandObjectParsed
+{
+public:
+ CommandPluginInterfaceImplementation (CommandInterpreter &interpreter,
+ const char *name,
+ lldb::SBCommandPluginInterface* backend,
+ const char *help = NULL,
+ const char *syntax = NULL,
+ uint32_t flags = 0) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags),
+ m_backend(backend) {}
+
+ virtual bool
+ IsRemovable() const { return true; }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ SBCommandReturnObject sb_return(&result);
+ SBCommandInterpreter sb_interpreter(&m_interpreter);
+ SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this());
+ bool ret = m_backend->DoExecute (debugger_sb,(char**)command.GetArgumentVector(), sb_return);
+ sb_return.Release();
+ return ret;
+ }
+ lldb::SBCommandPluginInterface* m_backend;
+};
+
+SBCommandInterpreter::SBCommandInterpreter (CommandInterpreter *interpreter) :
+ m_opaque_ptr (interpreter)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter::SBCommandInterpreter (interpreter=%p)"
+ " => SBCommandInterpreter(%p)", interpreter, m_opaque_ptr);
+}
+
+SBCommandInterpreter::SBCommandInterpreter(const SBCommandInterpreter &rhs) :
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBCommandInterpreter &
+SBCommandInterpreter::operator = (const SBCommandInterpreter &rhs)
+{
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ return *this;
+}
+
+SBCommandInterpreter::~SBCommandInterpreter ()
+{
+}
+
+bool
+SBCommandInterpreter::IsValid() const
+{
+ return m_opaque_ptr != NULL;
+}
+
+
+bool
+SBCommandInterpreter::CommandExists (const char *cmd)
+{
+ if (cmd && m_opaque_ptr)
+ return m_opaque_ptr->CommandExists (cmd);
+ return false;
+}
+
+bool
+SBCommandInterpreter::AliasExists (const char *cmd)
+{
+ if (cmd && m_opaque_ptr)
+ return m_opaque_ptr->AliasExists (cmd);
+ return false;
+}
+
+lldb::ReturnStatus
+SBCommandInterpreter::HandleCommand (const char *command_line, SBCommandReturnObject &result, bool add_to_history)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p), add_to_history=%i)",
+ m_opaque_ptr, command_line, result.get(), add_to_history);
+
+ result.Clear();
+ if (command_line && m_opaque_ptr)
+ {
+ m_opaque_ptr->HandleCommand (command_line, add_to_history ? eLazyBoolYes : eLazyBoolNo, result.ref());
+ }
+ else
+ {
+ result->AppendError ("SBCommandInterpreter or the command line is not valid");
+ result->SetStatus (eReturnStatusFailed);
+ }
+
+ // We need to get the value again, in case the command disabled the log!
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
+ if (log)
+ {
+ SBStream sstr;
+ result.GetDescription (sstr);
+ log->Printf ("SBCommandInterpreter(%p)::HandleCommand (command=\"%s\", SBCommandReturnObject(%p): %s, add_to_history=%i) => %i",
+ m_opaque_ptr, command_line, result.get(), sstr.GetData(), add_to_history, result.GetStatus());
+ }
+
+ return result.GetStatus();
+}
+
+int
+SBCommandInterpreter::HandleCompletion (const char *current_line,
+ const char *cursor,
+ const char *last_char,
+ int match_start_point,
+ int max_return_elements,
+ SBStringList &matches)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ int num_completions = 0;
+
+ // Sanity check the arguments that are passed in:
+ // cursor & last_char have to be within the current_line.
+ if (current_line == NULL || cursor == NULL || last_char == NULL)
+ return 0;
+
+ if (cursor < current_line || last_char < current_line)
+ return 0;
+
+ size_t current_line_size = strlen (current_line);
+ if (cursor - current_line > current_line_size || last_char - current_line > current_line_size)
+ return 0;
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::HandleCompletion (current_line=\"%s\", cursor at: %" PRId64 ", last char at: %" PRId64 ", match_start_point: %d, max_return_elements: %d)",
+ m_opaque_ptr, current_line, (uint64_t) (cursor - current_line), (uint64_t) (last_char - current_line), match_start_point, max_return_elements);
+
+ if (m_opaque_ptr)
+ {
+ lldb_private::StringList lldb_matches;
+ num_completions = m_opaque_ptr->HandleCompletion (current_line, cursor, last_char, match_start_point,
+ max_return_elements, lldb_matches);
+
+ SBStringList temp_list (&lldb_matches);
+ matches.AppendList (temp_list);
+ }
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::HandleCompletion - Found %d completions.", m_opaque_ptr, num_completions);
+
+ return num_completions;
+}
+
+int
+SBCommandInterpreter::HandleCompletion (const char *current_line,
+ uint32_t cursor_pos,
+ int match_start_point,
+ int max_return_elements,
+ lldb::SBStringList &matches)
+{
+ const char *cursor = current_line + cursor_pos;
+ const char *last_char = current_line + strlen (current_line);
+ return HandleCompletion (current_line, cursor, last_char, match_start_point, max_return_elements, matches);
+}
+
+bool
+SBCommandInterpreter::HasCommands ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->HasCommands();
+ return false;
+}
+
+bool
+SBCommandInterpreter::HasAliases ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->HasAliases();
+ return false;
+}
+
+bool
+SBCommandInterpreter::HasAliasOptions ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->HasAliasOptions ();
+ return false;
+}
+
+SBProcess
+SBCommandInterpreter::GetProcess ()
+{
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ if (m_opaque_ptr)
+ {
+ TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker(target_sp->GetAPIMutex());
+ process_sp = target_sp->GetProcessSP();
+ sb_process.SetSP(process_sp);
+ }
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::GetProcess () => SBProcess(%p)",
+ m_opaque_ptr, process_sp.get());
+
+
+ return sb_process;
+}
+
+SBDebugger
+SBCommandInterpreter::GetDebugger ()
+{
+ SBDebugger sb_debugger;
+ if (m_opaque_ptr)
+ sb_debugger.reset(m_opaque_ptr->GetDebugger().shared_from_this());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::GetDebugger () => SBDebugger(%p)",
+ m_opaque_ptr, sb_debugger.get());
+
+
+ return sb_debugger;
+}
+
+CommandInterpreter *
+SBCommandInterpreter::get ()
+{
+ return m_opaque_ptr;
+}
+
+CommandInterpreter &
+SBCommandInterpreter::ref ()
+{
+ assert (m_opaque_ptr);
+ return *m_opaque_ptr;
+}
+
+void
+SBCommandInterpreter::reset (lldb_private::CommandInterpreter *interpreter)
+{
+ m_opaque_ptr = interpreter;
+}
+
+void
+SBCommandInterpreter::SourceInitFileInHomeDirectory (SBCommandReturnObject &result)
+{
+ result.Clear();
+ if (m_opaque_ptr)
+ {
+ TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
+ Mutex::Locker api_locker;
+ if (target_sp)
+ api_locker.Lock(target_sp->GetAPIMutex());
+ m_opaque_ptr->SourceInitFile (false, result.ref());
+ }
+ else
+ {
+ result->AppendError ("SBCommandInterpreter is not valid");
+ result->SetStatus (eReturnStatusFailed);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::SourceInitFileInHomeDirectory (&SBCommandReturnObject(%p))",
+ m_opaque_ptr, result.get());
+
+}
+
+void
+SBCommandInterpreter::SourceInitFileInCurrentWorkingDirectory (SBCommandReturnObject &result)
+{
+ result.Clear();
+ if (m_opaque_ptr)
+ {
+ TargetSP target_sp(m_opaque_ptr->GetDebugger().GetSelectedTarget());
+ Mutex::Locker api_locker;
+ if (target_sp)
+ api_locker.Lock(target_sp->GetAPIMutex());
+ m_opaque_ptr->SourceInitFile (true, result.ref());
+ }
+ else
+ {
+ result->AppendError ("SBCommandInterpreter is not valid");
+ result->SetStatus (eReturnStatusFailed);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::SourceInitFileInCurrentWorkingDirectory (&SBCommandReturnObject(%p))",
+ m_opaque_ptr, result.get());
+}
+
+SBBroadcaster
+SBCommandInterpreter::GetBroadcaster ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBroadcaster broadcaster (m_opaque_ptr, false);
+
+ if (log)
+ log->Printf ("SBCommandInterpreter(%p)::GetBroadcaster() => SBBroadcaster(%p)",
+ m_opaque_ptr, broadcaster.get());
+
+ return broadcaster;
+}
+
+const char *
+SBCommandInterpreter::GetBroadcasterClass ()
+{
+ return Communication::GetStaticBroadcasterClass().AsCString();
+}
+
+const char *
+SBCommandInterpreter::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
+{
+ return CommandObject::GetArgumentTypeAsCString (arg_type);
+}
+
+const char *
+SBCommandInterpreter::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type)
+{
+ return CommandObject::GetArgumentDescriptionAsCString (arg_type);
+}
+
+bool
+SBCommandInterpreter::SetCommandOverrideCallback (const char *command_name,
+ lldb::CommandOverrideCallback callback,
+ void *baton)
+{
+ if (command_name && command_name[0] && m_opaque_ptr)
+ {
+ std::string command_name_str (command_name);
+ CommandObject *cmd_obj = m_opaque_ptr->GetCommandObjectForCommand(command_name_str);
+ if (cmd_obj)
+ {
+ assert(command_name_str.empty());
+ cmd_obj->SetOverrideCallback (callback, baton);
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+
+// Defined in the SWIG source file
+extern "C" void
+init_lldb(void);
+
+#else
+
+extern "C" void init_lldb(void);
+
+// Usually defined in the SWIG source file, but we have sripting disabled
+extern "C" void
+init_lldb(void)
+{
+}
+
+#endif
+
+void
+SBCommandInterpreter::InitializeSWIG ()
+{
+ static bool g_initialized = false;
+ if (!g_initialized)
+ {
+ g_initialized = true;
+#ifndef LLDB_DISABLE_PYTHON
+ ScriptInterpreter::InitializeInterpreter (init_lldb);
+#endif
+ }
+}
+
+lldb::SBCommand
+SBCommandInterpreter::AddMultiwordCommand (const char* name, const char* help)
+{
+ CommandObjectMultiword *new_command = new CommandObjectMultiword(*m_opaque_ptr,name,help);
+ new_command->SetRemovable (true);
+ lldb::CommandObjectSP new_command_sp(new_command);
+ if (new_command_sp && m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
+ return lldb::SBCommand(new_command_sp);
+ return lldb::SBCommand();
+}
+
+lldb::SBCommand
+SBCommandInterpreter::AddCommand (const char* name, lldb::SBCommandPluginInterface* impl, const char* help)
+{
+ lldb::CommandObjectSP new_command_sp;
+ new_command_sp.reset(new CommandPluginInterfaceImplementation(*m_opaque_ptr,name,impl,help));
+
+ if (new_command_sp && m_opaque_ptr->AddUserCommand(name, new_command_sp, true))
+ return lldb::SBCommand(new_command_sp);
+ return lldb::SBCommand();
+}
+
+SBCommand::SBCommand ()
+{}
+
+SBCommand::SBCommand (lldb::CommandObjectSP cmd_sp) : m_opaque_sp (cmd_sp)
+{}
+
+bool
+SBCommand::IsValid ()
+{
+ return (bool)m_opaque_sp;
+}
+
+const char*
+SBCommand::GetName ()
+{
+ if (IsValid ())
+ return m_opaque_sp->GetCommandName ();
+ return NULL;
+}
+
+const char*
+SBCommand::GetHelp ()
+{
+ if (IsValid ())
+ return m_opaque_sp->GetHelp ();
+ return NULL;
+}
+
+lldb::SBCommand
+SBCommand::AddMultiwordCommand (const char* name, const char* help)
+{
+ if (!IsValid ())
+ return lldb::SBCommand();
+ if (m_opaque_sp->IsMultiwordObject() == false)
+ return lldb::SBCommand();
+ CommandObjectMultiword *new_command = new CommandObjectMultiword(m_opaque_sp->GetCommandInterpreter(),name,help);
+ new_command->SetRemovable (true);
+ lldb::CommandObjectSP new_command_sp(new_command);
+ if (new_command_sp && m_opaque_sp->LoadSubCommand(name,new_command_sp))
+ return lldb::SBCommand(new_command_sp);
+ return lldb::SBCommand();
+}
+
+lldb::SBCommand
+SBCommand::AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, const char* help)
+{
+ if (!IsValid ())
+ return lldb::SBCommand();
+ if (m_opaque_sp->IsMultiwordObject() == false)
+ return lldb::SBCommand();
+ lldb::CommandObjectSP new_command_sp;
+ new_command_sp.reset(new CommandPluginInterfaceImplementation(m_opaque_sp->GetCommandInterpreter(),name,impl,help));
+ if (new_command_sp && m_opaque_sp->LoadSubCommand(name,new_command_sp))
+ return lldb::SBCommand(new_command_sp);
+ return lldb::SBCommand();
+}
+
diff --git a/source/API/SBCommandReturnObject.cpp b/source/API/SBCommandReturnObject.cpp
new file mode 100644
index 000000000000..83d65637d3f2
--- /dev/null
+++ b/source/API/SBCommandReturnObject.cpp
@@ -0,0 +1,352 @@
+//===-- SBCommandReturnObject.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/SBCommandReturnObject.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBCommandReturnObject::SBCommandReturnObject () :
+ m_opaque_ap (new CommandReturnObject ())
+{
+}
+
+SBCommandReturnObject::SBCommandReturnObject (const SBCommandReturnObject &rhs):
+ m_opaque_ap ()
+{
+ if (rhs.m_opaque_ap.get())
+ m_opaque_ap.reset (new CommandReturnObject (*rhs.m_opaque_ap));
+}
+
+SBCommandReturnObject::SBCommandReturnObject (CommandReturnObject *ptr) :
+ m_opaque_ap (ptr)
+{
+}
+
+CommandReturnObject *
+SBCommandReturnObject::Release ()
+{
+ return m_opaque_ap.release();
+}
+
+const SBCommandReturnObject &
+SBCommandReturnObject::operator = (const SBCommandReturnObject &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.m_opaque_ap.get())
+ m_opaque_ap.reset (new CommandReturnObject (*rhs.m_opaque_ap));
+ else
+ m_opaque_ap.reset();
+ }
+ return *this;
+}
+
+
+SBCommandReturnObject::~SBCommandReturnObject ()
+{
+ // m_opaque_ap will automatically delete any pointer it owns
+}
+
+bool
+SBCommandReturnObject::IsValid() const
+{
+ return m_opaque_ap.get() != NULL;
+}
+
+
+const char *
+SBCommandReturnObject::GetOutput ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (m_opaque_ap.get())
+ {
+ if (log)
+ log->Printf ("SBCommandReturnObject(%p)::GetOutput () => \"%s\"", m_opaque_ap.get(),
+ m_opaque_ap->GetOutputData());
+
+ return m_opaque_ap->GetOutputData();
+ }
+
+ if (log)
+ log->Printf ("SBCommandReturnObject(%p)::GetOutput () => NULL", m_opaque_ap.get());
+
+ return NULL;
+}
+
+const char *
+SBCommandReturnObject::GetError ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (m_opaque_ap.get())
+ {
+ if (log)
+ log->Printf ("SBCommandReturnObject(%p)::GetError () => \"%s\"", m_opaque_ap.get(),
+ m_opaque_ap->GetErrorData());
+
+ return m_opaque_ap->GetErrorData();
+ }
+
+ if (log)
+ log->Printf ("SBCommandReturnObject(%p)::GetError () => NULL", m_opaque_ap.get());
+
+ return NULL;
+}
+
+size_t
+SBCommandReturnObject::GetOutputSize ()
+{
+ if (m_opaque_ap.get())
+ return strlen (m_opaque_ap->GetOutputData());
+ return 0;
+}
+
+size_t
+SBCommandReturnObject::GetErrorSize ()
+{
+ if (m_opaque_ap.get())
+ return strlen(m_opaque_ap->GetErrorData());
+ return 0;
+}
+
+size_t
+SBCommandReturnObject::PutOutput (FILE *fh)
+{
+ if (fh)
+ {
+ size_t num_bytes = GetOutputSize ();
+ if (num_bytes)
+ return ::fprintf (fh, "%s", GetOutput());
+ }
+ return 0;
+}
+
+size_t
+SBCommandReturnObject::PutError (FILE *fh)
+{
+ if (fh)
+ {
+ size_t num_bytes = GetErrorSize ();
+ if (num_bytes)
+ return ::fprintf (fh, "%s", GetError());
+ }
+ return 0;
+}
+
+void
+SBCommandReturnObject::Clear()
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->Clear();
+}
+
+lldb::ReturnStatus
+SBCommandReturnObject::GetStatus()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetStatus();
+ return lldb::eReturnStatusInvalid;
+}
+
+void
+SBCommandReturnObject::SetStatus(lldb::ReturnStatus status)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->SetStatus(status);
+}
+
+bool
+SBCommandReturnObject::Succeeded ()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->Succeeded();
+ return false;
+}
+
+bool
+SBCommandReturnObject::HasResult ()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->HasResult();
+ return false;
+}
+
+void
+SBCommandReturnObject::AppendMessage (const char *message)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->AppendMessage (message);
+}
+
+void
+SBCommandReturnObject::AppendWarning (const char *message)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->AppendWarning (message);
+}
+
+CommandReturnObject *
+SBCommandReturnObject::operator ->() const
+{
+ return m_opaque_ap.get();
+}
+
+CommandReturnObject *
+SBCommandReturnObject::get() const
+{
+ return m_opaque_ap.get();
+}
+
+CommandReturnObject &
+SBCommandReturnObject::operator *() const
+{
+ assert(m_opaque_ap.get());
+ return *(m_opaque_ap.get());
+}
+
+
+CommandReturnObject &
+SBCommandReturnObject::ref() const
+{
+ assert(m_opaque_ap.get());
+ return *(m_opaque_ap.get());
+}
+
+
+void
+SBCommandReturnObject::SetLLDBObjectPtr (CommandReturnObject *ptr)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap.reset (ptr);
+}
+
+bool
+SBCommandReturnObject::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ description.Printf ("Status: ");
+ lldb::ReturnStatus status = m_opaque_ap->GetStatus();
+ if (status == lldb::eReturnStatusStarted)
+ strm.PutCString ("Started");
+ else if (status == lldb::eReturnStatusInvalid)
+ strm.PutCString ("Invalid");
+ else if (m_opaque_ap->Succeeded())
+ strm.PutCString ("Success");
+ else
+ strm.PutCString ("Fail");
+
+ if (GetOutputSize() > 0)
+ strm.Printf ("\nOutput Message:\n%s", GetOutput());
+
+ if (GetErrorSize() > 0)
+ strm.Printf ("\nError Message:\n%s", GetError());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+void
+SBCommandReturnObject::SetImmediateOutputFile (FILE *fh)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->SetImmediateOutputFile (fh);
+}
+
+void
+SBCommandReturnObject::SetImmediateErrorFile (FILE *fh)
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->SetImmediateErrorFile (fh);
+}
+
+void
+SBCommandReturnObject::PutCString(const char* string, int len)
+{
+ if (m_opaque_ap.get())
+ {
+ if (len == 0 || string == NULL || *string == 0)
+ {
+ return;
+ }
+ else if (len > 0)
+ {
+ std::string buffer(string, len);
+ m_opaque_ap->AppendMessage(buffer.c_str());
+ }
+ else
+ m_opaque_ap->AppendMessage(string);
+ }
+}
+
+const char *
+SBCommandReturnObject::GetOutput (bool only_if_no_immediate)
+{
+ if (!m_opaque_ap.get())
+ return NULL;
+ if (only_if_no_immediate == false || m_opaque_ap->GetImmediateOutputStream().get() == NULL)
+ return GetOutput();
+ return NULL;
+}
+
+const char *
+SBCommandReturnObject::GetError (bool only_if_no_immediate)
+{
+ if (!m_opaque_ap.get())
+ return NULL;
+ if (only_if_no_immediate == false || m_opaque_ap->GetImmediateErrorStream().get() == NULL)
+ return GetError();
+ return NULL;
+}
+
+size_t
+SBCommandReturnObject::Printf(const char* format, ...)
+{
+ if (m_opaque_ap.get())
+ {
+ va_list args;
+ va_start (args, format);
+ size_t result = m_opaque_ap->GetOutputStream().PrintfVarArg(format, args);
+ va_end (args);
+ return result;
+ }
+ return 0;
+}
+
+void
+SBCommandReturnObject::SetError (lldb::SBError &error, const char *fallback_error_cstr)
+{
+ if (m_opaque_ap.get())
+ {
+ if (error.IsValid())
+ m_opaque_ap->SetError(error.ref(), fallback_error_cstr);
+ else if (fallback_error_cstr)
+ m_opaque_ap->SetError(Error(), fallback_error_cstr);
+ }
+}
+
+void
+SBCommandReturnObject::SetError (const char *error_cstr)
+{
+ if (m_opaque_ap.get() && error_cstr)
+ m_opaque_ap->SetError(error_cstr);
+}
+
diff --git a/source/API/SBCommunication.cpp b/source/API/SBCommunication.cpp
new file mode 100644
index 000000000000..10feae5d4ebb
--- /dev/null
+++ b/source/API/SBCommunication.cpp
@@ -0,0 +1,285 @@
+//===-- SBCommunication.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/SBCommunication.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBCommunication::SBCommunication() :
+ m_opaque (NULL),
+ m_opaque_owned (false)
+{
+}
+
+SBCommunication::SBCommunication(const char * broadcaster_name) :
+ m_opaque (new Communication (broadcaster_name)),
+ m_opaque_owned (true)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommunication::SBCommunication (broadcaster_name=\"%s\") => "
+ "SBCommunication(%p)", broadcaster_name, m_opaque);
+}
+
+SBCommunication::~SBCommunication()
+{
+ if (m_opaque && m_opaque_owned)
+ delete m_opaque;
+ m_opaque = NULL;
+ m_opaque_owned = false;
+}
+
+bool
+SBCommunication::IsValid () const
+{
+ return m_opaque != NULL;
+}
+
+bool
+SBCommunication::GetCloseOnEOF ()
+{
+ if (m_opaque)
+ return m_opaque->GetCloseOnEOF ();
+ return false;
+}
+
+void
+SBCommunication::SetCloseOnEOF (bool b)
+{
+ if (m_opaque)
+ m_opaque->SetCloseOnEOF (b);
+}
+
+ConnectionStatus
+SBCommunication::Connect (const char *url)
+{
+ if (m_opaque)
+ {
+ if (!m_opaque->HasConnection ())
+ m_opaque->SetConnection (new ConnectionFileDescriptor());
+ return m_opaque->Connect (url, NULL);
+ }
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+SBCommunication::AdoptFileDesriptor (int fd, bool owns_fd)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ConnectionStatus status = eConnectionStatusNoConnection;
+ if (m_opaque)
+ {
+ if (m_opaque->HasConnection ())
+ {
+ if (m_opaque->IsConnected())
+ m_opaque->Disconnect();
+ }
+ m_opaque->SetConnection (new ConnectionFileDescriptor (fd, owns_fd));
+ if (m_opaque->IsConnected())
+ status = eConnectionStatusSuccess;
+ else
+ status = eConnectionStatusLostConnection;
+ }
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::AdoptFileDescriptor (fd=%d, ownd_fd=%i) => %s",
+ m_opaque, fd, owns_fd, Communication::ConnectionStatusAsCString (status));
+
+ return status;
+}
+
+
+ConnectionStatus
+SBCommunication::Disconnect ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ConnectionStatus status= eConnectionStatusNoConnection;
+ if (m_opaque)
+ status = m_opaque->Disconnect ();
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::Disconnect () => %s", m_opaque,
+ Communication::ConnectionStatusAsCString (status));
+
+ return status;
+}
+
+bool
+SBCommunication::IsConnected () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool result = false;
+ if (m_opaque)
+ result = m_opaque->IsConnected ();
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::IsConnected () => %i", m_opaque, result);
+
+ return false;
+}
+
+size_t
+SBCommunication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBCommunication(%p)::Read (dst=%p, dst_len=%" PRIu64 ", timeout_usec=%u, &status)...",
+ m_opaque,
+ dst,
+ (uint64_t)dst_len,
+ timeout_usec);
+ size_t bytes_read = 0;
+ if (m_opaque)
+ bytes_read = m_opaque->Read (dst, dst_len, timeout_usec, status, NULL);
+ else
+ status = eConnectionStatusNoConnection;
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::Read (dst=%p, dst_len=%" PRIu64 ", timeout_usec=%u, &status=%s) => %" PRIu64,
+ m_opaque,
+ dst,
+ (uint64_t)dst_len,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ (uint64_t)bytes_read);
+ return bytes_read;
+}
+
+
+size_t
+SBCommunication::Write (const void *src, size_t src_len, ConnectionStatus &status)
+{
+ size_t bytes_written = 0;
+ if (m_opaque)
+ bytes_written = m_opaque->Write (src, src_len, status, NULL);
+ else
+ status = eConnectionStatusNoConnection;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBCommunication(%p)::Write (src=%p, src_len=%" PRIu64 ", &status=%s) => %" PRIu64,
+ m_opaque, src, (uint64_t)src_len, Communication::ConnectionStatusAsCString (status), (uint64_t)bytes_written);
+
+ return 0;
+}
+
+bool
+SBCommunication::ReadThreadStart ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool success = false;
+ if (m_opaque)
+ success = m_opaque->StartReadThread ();
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::ReadThreadStart () => %i", m_opaque, success);
+
+ return success;
+}
+
+
+bool
+SBCommunication::ReadThreadStop ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBCommunication(%p)::ReadThreadStop ()...", m_opaque);
+
+ bool success = false;
+ if (m_opaque)
+ success = m_opaque->StopReadThread ();
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::ReadThreadStop () => %i", m_opaque, success);
+
+ return success;
+}
+
+bool
+SBCommunication::ReadThreadIsRunning ()
+{
+ bool result = false;
+ if (m_opaque)
+ result = m_opaque->ReadThreadIsRunning ();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBCommunication(%p)::ReadThreadIsRunning () => %i", m_opaque, result);
+ return result;
+}
+
+bool
+SBCommunication::SetReadThreadBytesReceivedCallback
+(
+ ReadThreadBytesReceived callback,
+ void *callback_baton
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool result = false;
+ if (m_opaque)
+ {
+ m_opaque->SetReadThreadBytesReceivedCallback (callback, callback_baton);
+ result = true;
+ }
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::SetReadThreadBytesReceivedCallback (callback=%p, baton=%p) => %i",
+ m_opaque, callback, callback_baton, result);
+
+ return result;
+}
+
+SBBroadcaster
+SBCommunication::GetBroadcaster ()
+{
+ SBBroadcaster broadcaster (m_opaque, false);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBCommunication(%p)::GetBroadcaster () => SBBroadcaster (%p)",
+ m_opaque, broadcaster.get());
+
+ return broadcaster;
+}
+
+const char *
+SBCommunication::GetBroadcasterClass ()
+{
+ return Communication::GetStaticBroadcasterClass().AsCString();
+}
+
+//
+//void
+//SBCommunication::CreateIfNeeded ()
+//{
+// if (m_opaque == NULL)
+// {
+// static uint32_t g_broadcaster_num;
+// char broadcaster_name[256];
+// ::snprintf (name, broadcaster_name, "%p SBCommunication", this);
+// m_opaque = new Communication (broadcaster_name);
+// m_opaque_owned = true;
+// }
+// assert (m_opaque);
+//}
+//
+//
diff --git a/source/API/SBCompileUnit.cpp b/source/API/SBCompileUnit.cpp
new file mode 100644
index 000000000000..9f7487746a85
--- /dev/null
+++ b/source/API/SBCompileUnit.cpp
@@ -0,0 +1,278 @@
+//===-- SBCompileUnit.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/SBCompileUnit.h"
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBCompileUnit::SBCompileUnit () :
+ m_opaque_ptr (NULL)
+{
+}
+
+SBCompileUnit::SBCompileUnit (lldb_private::CompileUnit *lldb_object_ptr) :
+ m_opaque_ptr (lldb_object_ptr)
+{
+}
+
+SBCompileUnit::SBCompileUnit(const SBCompileUnit &rhs) :
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBCompileUnit &
+SBCompileUnit::operator = (const SBCompileUnit &rhs)
+{
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ return *this;
+}
+
+
+SBCompileUnit::~SBCompileUnit ()
+{
+ m_opaque_ptr = NULL;
+}
+
+SBFileSpec
+SBCompileUnit::GetFileSpec () const
+{
+ SBFileSpec file_spec;
+ if (m_opaque_ptr)
+ file_spec.SetFileSpec(*m_opaque_ptr);
+ return file_spec;
+}
+
+uint32_t
+SBCompileUnit::GetNumLineEntries () const
+{
+ if (m_opaque_ptr)
+ {
+ LineTable *line_table = m_opaque_ptr->GetLineTable ();
+ if (line_table)
+ return line_table->GetSize();
+ }
+ return 0;
+}
+
+SBLineEntry
+SBCompileUnit::GetLineEntryAtIndex (uint32_t idx) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBLineEntry sb_line_entry;
+ if (m_opaque_ptr)
+ {
+ LineTable *line_table = m_opaque_ptr->GetLineTable ();
+ if (line_table)
+ {
+ LineEntry line_entry;
+ if (line_table->GetLineEntryAtIndex(idx, line_entry))
+ sb_line_entry.SetLineEntry(line_entry);
+ }
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_line_entry.GetDescription (sstr);
+ log->Printf ("SBCompileUnit(%p)::GetLineEntryAtIndex (idx=%u) => SBLineEntry(%p): '%s'",
+ m_opaque_ptr, idx, sb_line_entry.get(), sstr.GetData());
+ }
+
+ return sb_line_entry;
+}
+
+uint32_t
+SBCompileUnit::FindLineEntryIndex (uint32_t start_idx, uint32_t line, SBFileSpec *inline_file_spec) const
+{
+ const bool exact = true;
+ return FindLineEntryIndex (start_idx, line, inline_file_spec, exact);
+}
+
+uint32_t
+SBCompileUnit::FindLineEntryIndex (uint32_t start_idx, uint32_t line, SBFileSpec *inline_file_spec, bool exact) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t index = UINT32_MAX;
+ if (m_opaque_ptr)
+ {
+ FileSpec file_spec;
+ if (inline_file_spec && inline_file_spec->IsValid())
+ file_spec = inline_file_spec->ref();
+ else
+ file_spec = *m_opaque_ptr;
+
+
+ index = m_opaque_ptr->FindLineEntry (start_idx,
+ line,
+ inline_file_spec ? inline_file_spec->get() : NULL,
+ exact,
+ NULL);
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ if (index == UINT32_MAX)
+ {
+ log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => NOT FOUND",
+ m_opaque_ptr, start_idx, line, inline_file_spec ? inline_file_spec->get() : NULL);
+ }
+ else
+ {
+ log->Printf ("SBCompileUnit(%p)::FindLineEntryIndex (start_idx=%u, line=%u, SBFileSpec(%p)) => %u",
+ m_opaque_ptr, start_idx, line, inline_file_spec ? inline_file_spec->get() : NULL, index);
+ }
+ }
+
+ return index;
+}
+
+uint32_t
+SBCompileUnit::GetNumSupportFiles () const
+{
+ if (m_opaque_ptr)
+ {
+ FileSpecList& support_files = m_opaque_ptr->GetSupportFiles ();
+ return support_files.GetSize();
+ }
+ return 0;
+}
+
+
+
+lldb::SBTypeList
+SBCompileUnit::GetTypes (uint32_t type_mask)
+{
+ SBTypeList sb_type_list;
+
+ if (m_opaque_ptr)
+ {
+ ModuleSP module_sp (m_opaque_ptr->GetModule());
+ if (module_sp)
+ {
+ SymbolVendor* vendor = module_sp->GetSymbolVendor();
+ if (vendor)
+ {
+ TypeList type_list;
+ vendor->GetTypes (m_opaque_ptr, type_mask, type_list);
+ sb_type_list.m_opaque_ap->Append(type_list);
+ }
+ }
+ }
+ return sb_type_list;
+}
+
+
+
+
+SBFileSpec
+SBCompileUnit::GetSupportFileAtIndex (uint32_t idx) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFileSpec sb_file_spec;
+ if (m_opaque_ptr)
+ {
+ FileSpecList &support_files = m_opaque_ptr->GetSupportFiles ();
+ FileSpec file_spec = support_files.GetFileSpecAtIndex(idx);
+ sb_file_spec.SetFileSpec(file_spec);
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_file_spec.GetDescription (sstr);
+ log->Printf ("SBCompileUnit(%p)::GetGetFileSpecAtIndex (idx=%u) => SBFileSpec(%p): '%s'",
+ m_opaque_ptr, idx, sb_file_spec.get(), sstr.GetData());
+ }
+
+ return sb_file_spec;
+}
+
+uint32_t
+SBCompileUnit::FindSupportFileIndex (uint32_t start_idx, const SBFileSpec &sb_file, bool full)
+{
+ if (m_opaque_ptr)
+ {
+ FileSpecList &support_files = m_opaque_ptr->GetSupportFiles ();
+ return support_files.FindFileIndex(start_idx, sb_file.ref(), full);
+ }
+ return 0;
+}
+
+bool
+SBCompileUnit::IsValid () const
+{
+ return m_opaque_ptr != NULL;
+}
+
+bool
+SBCompileUnit::operator == (const SBCompileUnit &rhs) const
+{
+ return m_opaque_ptr == rhs.m_opaque_ptr;
+}
+
+bool
+SBCompileUnit::operator != (const SBCompileUnit &rhs) const
+{
+ return m_opaque_ptr != rhs.m_opaque_ptr;
+}
+
+const lldb_private::CompileUnit *
+SBCompileUnit::operator->() const
+{
+ return m_opaque_ptr;
+}
+
+const lldb_private::CompileUnit &
+SBCompileUnit::operator*() const
+{
+ return *m_opaque_ptr;
+}
+
+lldb_private::CompileUnit *
+SBCompileUnit::get ()
+{
+ return m_opaque_ptr;
+}
+
+void
+SBCompileUnit::reset (lldb_private::CompileUnit *lldb_object_ptr)
+{
+ m_opaque_ptr = lldb_object_ptr;
+}
+
+
+bool
+SBCompileUnit::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ptr)
+ {
+ m_opaque_ptr->Dump (&strm, false);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
diff --git a/source/API/SBData.cpp b/source/API/SBData.cpp
new file mode 100644
index 000000000000..5b2f075158b8
--- /dev/null
+++ b/source/API/SBData.cpp
@@ -0,0 +1,785 @@
+//===-- SBData.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/SBData.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBData::SBData () :
+ m_opaque_sp(new DataExtractor())
+{
+}
+
+SBData::SBData (const lldb::DataExtractorSP& data_sp) :
+ m_opaque_sp (data_sp)
+{
+}
+
+SBData::SBData(const SBData &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBData &
+SBData::operator = (const SBData &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+SBData::~SBData ()
+{
+}
+
+void
+SBData::SetOpaque (const lldb::DataExtractorSP &data_sp)
+{
+ m_opaque_sp = data_sp;
+}
+
+lldb_private::DataExtractor *
+SBData::get() const
+{
+ return m_opaque_sp.get();
+}
+
+lldb_private::DataExtractor *
+SBData::operator->() const
+{
+ return m_opaque_sp.operator->();
+}
+
+lldb::DataExtractorSP &
+SBData::operator*()
+{
+ return m_opaque_sp;
+}
+
+const lldb::DataExtractorSP &
+SBData::operator*() const
+{
+ return m_opaque_sp;
+}
+
+bool
+SBData::IsValid()
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+uint8_t
+SBData::GetAddressByteSize ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ uint8_t value = 0;
+ if (m_opaque_sp.get())
+ value = m_opaque_sp->GetAddressByteSize();
+ if (log)
+ log->Printf ("SBData::GetAddressByteSize () => "
+ "(%i)", value);
+ return value;
+}
+
+void
+SBData::SetAddressByteSize (uint8_t addr_byte_size)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (m_opaque_sp.get())
+ m_opaque_sp->SetAddressByteSize(addr_byte_size);
+ if (log)
+ log->Printf ("SBData::SetAddressByteSize (%i)", addr_byte_size);
+}
+
+void
+SBData::Clear ()
+{
+ if (m_opaque_sp.get())
+ m_opaque_sp->Clear();
+}
+
+size_t
+SBData::GetByteSize ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ size_t value = 0;
+ if (m_opaque_sp.get())
+ value = m_opaque_sp->GetByteSize();
+ if (log)
+ log->Printf ("SBData::GetByteSize () => "
+ "(%lu)", value);
+ return value;
+}
+
+lldb::ByteOrder
+SBData::GetByteOrder ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::ByteOrder value = eByteOrderInvalid;
+ if (m_opaque_sp.get())
+ value = m_opaque_sp->GetByteOrder();
+ if (log)
+ log->Printf ("SBData::GetByteOrder () => "
+ "(%i)", value);
+ return value;
+}
+
+void
+SBData::SetByteOrder (lldb::ByteOrder endian)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (m_opaque_sp.get())
+ m_opaque_sp->SetByteOrder(endian);
+ if (log)
+ log->Printf ("SBData::GetByteOrder (%i)", endian);
+}
+
+
+float
+SBData::GetFloat (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ float value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetFloat(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetFloat (error=%p,offset=%" PRIu64 ") => "
+ "(%f)", error.get(), offset, value);
+ return value;
+}
+
+double
+SBData::GetDouble (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ double value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetDouble(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetDouble (error=%p,offset=%" PRIu64 ") => "
+ "(%f)", error.get(), offset, value);
+ return value;
+}
+
+long double
+SBData::GetLongDouble (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ long double value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetLongDouble(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetLongDouble (error=%p,offset=%" PRIu64 ") => "
+ "(%Lf)", error.get(), offset, value);
+ return value;
+}
+
+lldb::addr_t
+SBData::GetAddress (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::addr_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetAddress(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetAddress (error=%p,offset=%" PRIu64 ") => "
+ "(%p)", error.get(), offset, (void*)value);
+ return value;
+}
+
+uint8_t
+SBData::GetUnsignedInt8 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ uint8_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetU8(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetUnsignedInt8 (error=%p,offset=%" PRIu64 ") => "
+ "(%c)", error.get(), offset, value);
+ return value;
+}
+
+uint16_t
+SBData::GetUnsignedInt16 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ uint16_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetU16(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetUnsignedInt16 (error=%p,offset=%" PRIu64 ") => "
+ "(%hd)", error.get(), offset, value);
+ return value;
+}
+
+uint32_t
+SBData::GetUnsignedInt32 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ uint32_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetU32(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetUnsignedInt32 (error=%p,offset=%" PRIu64 ") => "
+ "(%d)", error.get(), offset, value);
+ return value;
+}
+
+uint64_t
+SBData::GetUnsignedInt64 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ uint64_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetU64(&offset);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetUnsignedInt64 (error=%p,offset=%" PRIu64 ") => "
+ "(%" PRId64 ")", error.get(), offset, value);
+ return value;
+}
+
+int8_t
+SBData::GetSignedInt8 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ int8_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = (int8_t)m_opaque_sp->GetMaxS64(&offset, 1);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetSignedInt8 (error=%p,offset=%" PRIu64 ") => "
+ "(%c)", error.get(), offset, value);
+ return value;
+}
+
+int16_t
+SBData::GetSignedInt16 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ int16_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = (int16_t)m_opaque_sp->GetMaxS64(&offset, 2);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetSignedInt16 (error=%p,offset=%" PRIu64 ") => "
+ "(%hd)", error.get(), offset, value);
+ return value;
+}
+
+int32_t
+SBData::GetSignedInt32 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ int32_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = (int32_t)m_opaque_sp->GetMaxS64(&offset, 4);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetSignedInt32 (error=%p,offset=%" PRIu64 ") => "
+ "(%d)", error.get(), offset, value);
+ return value;
+}
+
+int64_t
+SBData::GetSignedInt64 (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ int64_t value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = (int64_t)m_opaque_sp->GetMaxS64(&offset, 8);
+ if (offset == old_offset)
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetSignedInt64 (error=%p,offset=%" PRIu64 ") => "
+ "(%" PRId64 ")", error.get(), offset, value);
+ return value;
+}
+
+const char*
+SBData::GetString (lldb::SBError& error, lldb::offset_t offset)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char* value = 0;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ value = m_opaque_sp->GetCStr(&offset);
+ if (offset == old_offset || (value == NULL))
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::GetString (error=%p,offset=%" PRIu64 ") => "
+ "(%p)", error.get(), offset, value);
+ return value;
+}
+
+bool
+SBData::GetDescription (lldb::SBStream &description, lldb::addr_t base_addr)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->Dump (&strm,
+ 0,
+ lldb::eFormatBytesWithASCII,
+ 1,
+ m_opaque_sp->GetByteSize(),
+ 16,
+ base_addr,
+ 0,
+ 0);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+size_t
+SBData::ReadRawData (lldb::SBError& error,
+ lldb::offset_t offset,
+ void *buf,
+ size_t size)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ void* ok = NULL;
+ if (!m_opaque_sp.get())
+ {
+ error.SetErrorString("no value to read from");
+ }
+ else
+ {
+ uint32_t old_offset = offset;
+ ok = m_opaque_sp->GetU8(&offset, buf, size);
+ if ((offset == old_offset) || (ok == NULL))
+ error.SetErrorString("unable to read data");
+ }
+ if (log)
+ log->Printf ("SBData::ReadRawData (error=%p,offset=%" PRIu64 ",buf=%p,size=%lu) => "
+ "(%p)", error.get(), offset, buf, size, ok);
+ return ok ? size : 0;
+}
+
+void
+SBData::SetData (lldb::SBError& error,
+ const void *buf,
+ size_t size,
+ lldb::ByteOrder endian,
+ uint8_t addr_size)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buf, size, endian, addr_size));
+ else
+ m_opaque_sp->SetData(buf, size, endian);
+ if (log)
+ log->Printf ("SBData::SetData (error=%p,buf=%p,size=%lu,endian=%d,addr_size=%c) => "
+ "(%p)", error.get(), buf, size, endian, addr_size, m_opaque_sp.get());
+}
+
+bool
+SBData::Append (const SBData& rhs)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool value = false;
+ if (m_opaque_sp.get() && rhs.m_opaque_sp.get())
+ value = m_opaque_sp.get()->Append(*rhs.m_opaque_sp);
+ if (log)
+ log->Printf ("SBData::Append (rhs=%p) => "
+ "(%s)", rhs.get(), value ? "true" : "false");
+ return value;
+}
+
+lldb::SBData
+SBData::CreateDataFromCString (lldb::ByteOrder endian, uint32_t addr_byte_size, const char* data)
+{
+ if (!data || !data[0])
+ return SBData();
+
+ uint32_t data_len = strlen(data);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(data, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+lldb::SBData
+SBData::CreateDataFromUInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint64_t* array, size_t array_len)
+{
+ if (!array || array_len == 0)
+ return SBData();
+
+ size_t data_len = array_len * sizeof(uint64_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+lldb::SBData
+SBData::CreateDataFromUInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint32_t* array, size_t array_len)
+{
+ if (!array || array_len == 0)
+ return SBData();
+
+ size_t data_len = array_len * sizeof(uint32_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+lldb::SBData
+SBData::CreateDataFromSInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int64_t* array, size_t array_len)
+{
+ if (!array || array_len == 0)
+ return SBData();
+
+ size_t data_len = array_len * sizeof(int64_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+lldb::SBData
+SBData::CreateDataFromSInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int32_t* array, size_t array_len)
+{
+ if (!array || array_len == 0)
+ return SBData();
+
+ size_t data_len = array_len * sizeof(int32_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+lldb::SBData
+SBData::CreateDataFromDoubleArray (lldb::ByteOrder endian, uint32_t addr_byte_size, double* array, size_t array_len)
+{
+ if (!array || array_len == 0)
+ return SBData();
+
+ size_t data_len = array_len * sizeof(double);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+ lldb::DataExtractorSP data_sp(new DataExtractor(buffer_sp, endian, addr_byte_size));
+
+ SBData ret(data_sp);
+
+ return ret;
+}
+
+bool
+SBData::SetDataFromCString (const char* data)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!data)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromCString (data=%p) => "
+ "false", data);
+ return false;
+ }
+
+ size_t data_len = strlen(data);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(data, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromCString (data=%p) => "
+ "true", data);
+
+ return true;
+}
+
+bool
+SBData::SetDataFromUInt64Array (uint64_t* array, size_t array_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!array || array_len == 0)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromUInt64Array (array=%p, array_len = %lu) => "
+ "false", array, array_len);
+ return false;
+ }
+
+ size_t data_len = array_len * sizeof(uint64_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromUInt64Array (array=%p, array_len = %lu) => "
+ "true", array, array_len);
+
+ return true;
+}
+
+bool
+SBData::SetDataFromUInt32Array (uint32_t* array, size_t array_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!array || array_len == 0)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromUInt32Array (array=%p, array_len = %lu) => "
+ "false", array, array_len);
+ return false;
+ }
+
+ size_t data_len = array_len * sizeof(uint32_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromUInt32Array (array=%p, array_len = %lu) => "
+ "true", array, array_len);
+
+ return true;
+}
+
+bool
+SBData::SetDataFromSInt64Array (int64_t* array, size_t array_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!array || array_len == 0)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromSInt64Array (array=%p, array_len = %lu) => "
+ "false", array, array_len);
+ return false;
+ }
+
+ size_t data_len = array_len * sizeof(int64_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromSInt64Array (array=%p, array_len = %lu) => "
+ "true", array, array_len);
+
+ return true;
+}
+
+bool
+SBData::SetDataFromSInt32Array (int32_t* array, size_t array_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!array || array_len == 0)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromSInt32Array (array=%p, array_len = %lu) => "
+ "false", array, array_len);
+ return false;
+ }
+
+ size_t data_len = array_len * sizeof(int32_t);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromSInt32Array (array=%p, array_len = %lu) => "
+ "true", array, array_len);
+
+ return true;
+}
+
+bool
+SBData::SetDataFromDoubleArray (double* array, size_t array_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (!array || array_len == 0)
+ {
+ if (log)
+ log->Printf ("SBData::SetDataFromDoubleArray (array=%p, array_len = %lu) => "
+ "false", array, array_len);
+ return false;
+ }
+
+ size_t data_len = array_len * sizeof(double);
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(array, data_len));
+
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset(new DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()));
+ else
+ m_opaque_sp->SetData(buffer_sp);
+
+ if (log)
+ log->Printf ("SBData::SetDataFromDoubleArray (array=%p, array_len = %lu) => "
+ "true", array, array_len);
+
+ return true;
+}
diff --git a/source/API/SBDebugger.cpp b/source/API/SBDebugger.cpp
new file mode 100644
index 000000000000..f5e71d5f1a07
--- /dev/null
+++ b/source/API/SBDebugger.cpp
@@ -0,0 +1,1264 @@
+//===-- SBDebugger.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/SBDebugger.h"
+
+#include "lldb/lldb-private.h"
+
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBInputReader.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBSourceManager.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBTypeCategory.h"
+#include "lldb/API/SBTypeFormat.h"
+#include "lldb/API/SBTypeFilter.h"
+#include "lldb/API/SBTypeNameSpecifier.h"
+#include "lldb/API/SBTypeSummary.h"
+#include "lldb/API/SBTypeSynthetic.h"
+
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SBDebugger::Initialize ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger::Initialize ()");
+
+ SBCommandInterpreter::InitializeSWIG ();
+
+ Debugger::Initialize();
+}
+
+void
+SBDebugger::Terminate ()
+{
+ Debugger::Terminate();
+}
+
+void
+SBDebugger::Clear ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::Clear ()", m_opaque_sp.get());
+
+ if (m_opaque_sp)
+ m_opaque_sp->CleanUpInputReaders ();
+
+ m_opaque_sp.reset();
+}
+
+SBDebugger
+SBDebugger::Create()
+{
+ return SBDebugger::Create(false, NULL, NULL);
+}
+
+SBDebugger
+SBDebugger::Create(bool source_init_files)
+{
+ return SBDebugger::Create (source_init_files, NULL, NULL);
+}
+
+SBDebugger
+SBDebugger::Create(bool source_init_files, lldb::LogOutputCallback callback, void *baton)
+
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBDebugger debugger;
+ debugger.reset(Debugger::CreateInstance(callback, baton));
+
+ if (log)
+ {
+ SBStream sstr;
+ debugger.GetDescription (sstr);
+ log->Printf ("SBDebugger::Create () => SBDebugger(%p): %s", debugger.m_opaque_sp.get(), sstr.GetData());
+ }
+
+ SBCommandInterpreter interp = debugger.GetCommandInterpreter();
+ if (source_init_files)
+ {
+ interp.get()->SkipLLDBInitFiles(false);
+ interp.get()->SkipAppInitFiles (false);
+ SBCommandReturnObject result;
+ interp.SourceInitFileInHomeDirectory(result);
+ }
+ else
+ {
+ interp.get()->SkipLLDBInitFiles(true);
+ interp.get()->SkipAppInitFiles (true);
+ }
+ return debugger;
+}
+
+void
+SBDebugger::Destroy (SBDebugger &debugger)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream sstr;
+ debugger.GetDescription (sstr);
+ log->Printf ("SBDebugger::Destroy () => SBDebugger(%p): %s", debugger.m_opaque_sp.get(), sstr.GetData());
+ }
+
+ Debugger::Destroy (debugger.m_opaque_sp);
+
+ if (debugger.m_opaque_sp.get() != NULL)
+ debugger.m_opaque_sp.reset();
+}
+
+void
+SBDebugger::MemoryPressureDetected ()
+{
+ // Since this function can be call asynchronously, we allow it to be
+ // non-mandatory. We have seen deadlocks with this function when called
+ // so we need to safeguard against this until we can determine what is
+ // causing the deadlocks.
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const bool mandatory = false;
+ if (log)
+ {
+ log->Printf ("SBDebugger::MemoryPressureDetected (), mandatory = %d", mandatory);
+ }
+
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+}
+
+SBDebugger::SBDebugger () :
+ m_opaque_sp ()
+{
+}
+
+SBDebugger::SBDebugger(const lldb::DebuggerSP &debugger_sp) :
+ m_opaque_sp(debugger_sp)
+{
+}
+
+SBDebugger::SBDebugger(const SBDebugger &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+SBDebugger &
+SBDebugger::operator = (const SBDebugger &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+SBDebugger::~SBDebugger ()
+{
+}
+
+bool
+SBDebugger::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+
+void
+SBDebugger::SetAsync (bool b)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetAsyncExecution(b);
+}
+
+bool
+SBDebugger::GetAsync ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetAsyncExecution();
+ else
+ return false;
+}
+
+void
+SBDebugger::SkipLLDBInitFiles (bool b)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->GetCommandInterpreter().SkipLLDBInitFiles (b);
+}
+
+void
+SBDebugger::SkipAppInitFiles (bool b)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->GetCommandInterpreter().SkipAppInitFiles (b);
+}
+
+// Shouldn't really be settable after initialization as this could cause lots of problems; don't want users
+// trying to switch modes in the middle of a debugging session.
+void
+SBDebugger::SetInputFileHandle (FILE *fh, bool transfer_ownership)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::SetInputFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
+ fh, transfer_ownership);
+
+ if (m_opaque_sp)
+ m_opaque_sp->SetInputFileHandle (fh, transfer_ownership);
+}
+
+void
+SBDebugger::SetOutputFileHandle (FILE *fh, bool transfer_ownership)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::SetOutputFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
+ fh, transfer_ownership);
+
+ if (m_opaque_sp)
+ m_opaque_sp->SetOutputFileHandle (fh, transfer_ownership);
+}
+
+void
+SBDebugger::SetErrorFileHandle (FILE *fh, bool transfer_ownership)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::SetErrorFileHandle (fh=%p, transfer_ownership=%i)", m_opaque_sp.get(),
+ fh, transfer_ownership);
+
+ if (m_opaque_sp)
+ m_opaque_sp->SetErrorFileHandle (fh, transfer_ownership);
+}
+
+FILE *
+SBDebugger::GetInputFileHandle ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetInputFile().GetStream();
+ return NULL;
+}
+
+FILE *
+SBDebugger::GetOutputFileHandle ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetOutputFile().GetStream();
+ return NULL;
+}
+
+FILE *
+SBDebugger::GetErrorFileHandle ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetErrorFile().GetStream();
+ return NULL;
+}
+
+void
+SBDebugger::SaveInputTerminalState()
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SaveInputTerminalState();
+}
+
+void
+SBDebugger::RestoreInputTerminalState()
+{
+ if (m_opaque_sp)
+ m_opaque_sp->RestoreInputTerminalState();
+
+}
+SBCommandInterpreter
+SBDebugger::GetCommandInterpreter ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBCommandInterpreter sb_interpreter;
+ if (m_opaque_sp)
+ sb_interpreter.reset (&m_opaque_sp->GetCommandInterpreter());
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::GetCommandInterpreter () => SBCommandInterpreter(%p)",
+ m_opaque_sp.get(), sb_interpreter.get());
+
+ return sb_interpreter;
+}
+
+void
+SBDebugger::HandleCommand (const char *command)
+{
+ if (m_opaque_sp)
+ {
+ TargetSP target_sp (m_opaque_sp->GetSelectedTarget());
+ Mutex::Locker api_locker;
+ if (target_sp)
+ api_locker.Lock(target_sp->GetAPIMutex());
+
+ SBCommandInterpreter sb_interpreter(GetCommandInterpreter ());
+ SBCommandReturnObject result;
+
+ sb_interpreter.HandleCommand (command, result, false);
+
+ if (GetErrorFileHandle() != NULL)
+ result.PutError (GetErrorFileHandle());
+ if (GetOutputFileHandle() != NULL)
+ result.PutOutput (GetOutputFileHandle());
+
+ if (m_opaque_sp->GetAsyncExecution() == false)
+ {
+ SBProcess process(GetCommandInterpreter().GetProcess ());
+ ProcessSP process_sp (process.GetSP());
+ if (process_sp)
+ {
+ EventSP event_sp;
+ Listener &lldb_listener = m_opaque_sp->GetListener();
+ while (lldb_listener.GetNextEventForBroadcaster (process_sp.get(), event_sp))
+ {
+ SBEvent event(event_sp);
+ HandleProcessEvent (process, event, GetOutputFileHandle(), GetErrorFileHandle());
+ }
+ }
+ }
+ }
+}
+
+SBListener
+SBDebugger::GetListener ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBListener sb_listener;
+ if (m_opaque_sp)
+ sb_listener.reset(&m_opaque_sp->GetListener(), false);
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::GetListener () => SBListener(%p)", m_opaque_sp.get(),
+ sb_listener.get());
+
+ return sb_listener;
+}
+
+void
+SBDebugger::HandleProcessEvent (const SBProcess &process, const SBEvent &event, FILE *out, FILE *err)
+{
+ if (!process.IsValid())
+ return;
+
+ TargetSP target_sp (process.GetTarget().GetSP());
+ if (!target_sp)
+ return;
+
+ const uint32_t event_type = event.GetType();
+ char stdio_buffer[1024];
+ size_t len;
+
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ if (event_type & (Process::eBroadcastBitSTDOUT | Process::eBroadcastBitStateChanged))
+ {
+ // Drain stdout when we stop just in case we have any bytes
+ while ((len = process.GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (out != NULL)
+ ::fwrite (stdio_buffer, 1, len, out);
+ }
+
+ if (event_type & (Process::eBroadcastBitSTDERR | Process::eBroadcastBitStateChanged))
+ {
+ // Drain stderr when we stop just in case we have any bytes
+ while ((len = process.GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ if (err != NULL)
+ ::fwrite (stdio_buffer, 1, len, err);
+ }
+
+ if (event_type & Process::eBroadcastBitStateChanged)
+ {
+ StateType event_state = SBProcess::GetStateFromEvent (event);
+
+ if (event_state == eStateInvalid)
+ return;
+
+ bool is_stopped = StateIsStoppedState (event_state);
+ if (!is_stopped)
+ process.ReportEventState (event, out);
+ }
+}
+
+SBSourceManager
+SBDebugger::GetSourceManager ()
+{
+ SBSourceManager sb_source_manager (*this);
+ return sb_source_manager;
+}
+
+
+bool
+SBDebugger::GetDefaultArchitecture (char *arch_name, size_t arch_name_len)
+{
+ if (arch_name && arch_name_len)
+ {
+ ArchSpec default_arch = Target::GetDefaultArchitecture ();
+
+ if (default_arch.IsValid())
+ {
+ const std::string &triple_str = default_arch.GetTriple().str();
+ if (!triple_str.empty())
+ ::snprintf (arch_name, arch_name_len, "%s", triple_str.c_str());
+ else
+ ::snprintf (arch_name, arch_name_len, "%s", default_arch.GetArchitectureName());
+ return true;
+ }
+ }
+ if (arch_name && arch_name_len)
+ arch_name[0] = '\0';
+ return false;
+}
+
+
+bool
+SBDebugger::SetDefaultArchitecture (const char *arch_name)
+{
+ if (arch_name)
+ {
+ ArchSpec arch (arch_name);
+ if (arch.IsValid())
+ {
+ Target::SetDefaultArchitecture (arch);
+ return true;
+ }
+ }
+ return false;
+}
+
+ScriptLanguage
+SBDebugger::GetScriptingLanguage (const char *script_language_name)
+{
+
+ return Args::StringToScriptLanguage (script_language_name,
+ eScriptLanguageDefault,
+ NULL);
+}
+
+const char *
+SBDebugger::GetVersionString ()
+{
+ return GetVersion();
+}
+
+const char *
+SBDebugger::StateAsCString (StateType state)
+{
+ return lldb_private::StateAsCString (state);
+}
+
+bool
+SBDebugger::StateIsRunningState (StateType state)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const bool result = lldb_private::StateIsRunningState (state);
+ if (log)
+ log->Printf ("SBDebugger::StateIsRunningState (state=%s) => %i",
+ StateAsCString (state), result);
+
+ return result;
+}
+
+bool
+SBDebugger::StateIsStoppedState (StateType state)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const bool result = lldb_private::StateIsStoppedState (state, false);
+ if (log)
+ log->Printf ("SBDebugger::StateIsStoppedState (state=%s) => %i",
+ StateAsCString (state), result);
+
+ return result;
+}
+
+lldb::SBTarget
+SBDebugger::CreateTarget (const char *filename,
+ const char *target_triple,
+ const char *platform_name,
+ bool add_dependent_modules,
+ lldb::SBError& sb_error)
+{
+ SBTarget sb_target;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ {
+ sb_error.Clear();
+ OptionGroupPlatform platform_options (false);
+ platform_options.SetPlatformName (platform_name);
+
+ sb_error.ref() = m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
+ filename,
+ target_triple,
+ add_dependent_modules,
+ &platform_options,
+ target_sp);
+
+ if (sb_error.Success())
+ sb_target.SetSP (target_sp);
+ }
+ else
+ {
+ sb_error.SetErrorString("invalid target");
+ }
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\", triple=%s, platform_name=%s, add_dependent_modules=%u, error=%s) => SBTarget(%p)",
+ m_opaque_sp.get(),
+ filename,
+ target_triple,
+ platform_name,
+ add_dependent_modules,
+ sb_error.GetCString(),
+ target_sp.get());
+ }
+
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::CreateTargetWithFileAndTargetTriple (const char *filename,
+ const char *target_triple)
+{
+ SBTarget sb_target;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ {
+ const bool add_dependent_modules = true;
+ Error error (m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
+ filename,
+ target_triple,
+ add_dependent_modules,
+ NULL,
+ target_sp));
+ sb_target.SetSP (target_sp);
+ }
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndTargetTriple (filename=\"%s\", triple=%s) => SBTarget(%p)",
+ m_opaque_sp.get(), filename, target_triple, target_sp.get());
+ }
+
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::CreateTargetWithFileAndArch (const char *filename, const char *arch_cstr)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBTarget sb_target;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ {
+ Error error;
+ const bool add_dependent_modules = true;
+
+ error = m_opaque_sp->GetTargetList().CreateTarget (*m_opaque_sp,
+ filename,
+ arch_cstr,
+ add_dependent_modules,
+ NULL,
+ target_sp);
+
+ if (error.Success())
+ {
+ m_opaque_sp->GetTargetList().SetSelectedTarget (target_sp.get());
+ sb_target.SetSP (target_sp);
+ }
+ }
+
+ if (log)
+ {
+ log->Printf ("SBDebugger(%p)::CreateTargetWithFileAndArch (filename=\"%s\", arch=%s) => SBTarget(%p)",
+ m_opaque_sp.get(), filename, arch_cstr, target_sp.get());
+ }
+
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::CreateTarget (const char *filename)
+{
+ SBTarget sb_target;
+ 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,
+ filename,
+ arch,
+ add_dependent_modules,
+ platform_sp,
+ target_sp);
+
+ if (error.Success())
+ {
+ m_opaque_sp->GetTargetList().SetSelectedTarget (target_sp.get());
+ sb_target.SetSP (target_sp);
+ }
+ }
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBDebugger(%p)::CreateTarget (filename=\"%s\") => SBTarget(%p)",
+ m_opaque_sp.get(), filename, target_sp.get());
+ }
+ return sb_target;
+}
+
+bool
+SBDebugger::DeleteTarget (lldb::SBTarget &target)
+{
+ bool result = false;
+ if (m_opaque_sp)
+ {
+ TargetSP target_sp(target.GetSP());
+ if (target_sp)
+ {
+ // No need to lock, the target list is thread safe
+ result = m_opaque_sp->GetTargetList().DeleteTarget (target_sp);
+ target_sp->Destroy();
+ target.Clear();
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+ }
+ }
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBDebugger(%p)::DeleteTarget (SBTarget(%p)) => %i", m_opaque_sp.get(), target.m_opaque_sp.get(), result);
+ }
+
+ return result;
+}
+SBTarget
+SBDebugger::GetTargetAtIndex (uint32_t idx)
+{
+ SBTarget sb_target;
+ if (m_opaque_sp)
+ {
+ // No need to lock, the target list is thread safe
+ sb_target.SetSP (m_opaque_sp->GetTargetList().GetTargetAtIndex (idx));
+ }
+ return sb_target;
+}
+
+uint32_t
+SBDebugger::GetIndexOfTarget (lldb::SBTarget target)
+{
+
+ lldb::TargetSP target_sp = target.GetSP();
+ if (!target_sp)
+ return UINT32_MAX;
+
+ if (!m_opaque_sp)
+ return UINT32_MAX;
+
+ return m_opaque_sp->GetTargetList().GetIndexOfTarget (target.GetSP());
+}
+
+SBTarget
+SBDebugger::FindTargetWithProcessID (pid_t pid)
+{
+ SBTarget sb_target;
+ if (m_opaque_sp)
+ {
+ // No need to lock, the target list is thread safe
+ sb_target.SetSP (m_opaque_sp->GetTargetList().FindTargetWithProcessID (pid));
+ }
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::FindTargetWithFileAndArch (const char *filename, const char *arch_name)
+{
+ SBTarget sb_target;
+ if (m_opaque_sp && filename && filename[0])
+ {
+ // No need to lock, the target list is thread safe
+ ArchSpec arch (arch_name, m_opaque_sp->GetPlatformList().GetSelectedPlatform().get());
+ TargetSP target_sp (m_opaque_sp->GetTargetList().FindTargetWithExecutableAndArchitecture (FileSpec(filename, false), arch_name ? &arch : NULL));
+ sb_target.SetSP (target_sp);
+ }
+ return sb_target;
+}
+
+SBTarget
+SBDebugger::FindTargetWithLLDBProcess (const ProcessSP &process_sp)
+{
+ SBTarget sb_target;
+ if (m_opaque_sp)
+ {
+ // No need to lock, the target list is thread safe
+ sb_target.SetSP (m_opaque_sp->GetTargetList().FindTargetWithProcess (process_sp.get()));
+ }
+ return sb_target;
+}
+
+
+uint32_t
+SBDebugger::GetNumTargets ()
+{
+ if (m_opaque_sp)
+ {
+ // No need to lock, the target list is thread safe
+ return m_opaque_sp->GetTargetList().GetNumTargets ();
+ }
+ return 0;
+}
+
+SBTarget
+SBDebugger::GetSelectedTarget ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBTarget sb_target;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ {
+ // No need to lock, the target list is thread safe
+ target_sp = m_opaque_sp->GetTargetList().GetSelectedTarget ();
+ sb_target.SetSP (target_sp);
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_target.GetDescription (sstr, eDescriptionLevelBrief);
+ log->Printf ("SBDebugger(%p)::GetSelectedTarget () => SBTarget(%p): %s", m_opaque_sp.get(),
+ target_sp.get(), sstr.GetData());
+ }
+
+ return sb_target;
+}
+
+void
+SBDebugger::SetSelectedTarget (SBTarget &sb_target)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ TargetSP target_sp (sb_target.GetSP());
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->GetTargetList().SetSelectedTarget (target_sp.get());
+ }
+ if (log)
+ {
+ SBStream sstr;
+ sb_target.GetDescription (sstr, eDescriptionLevelBrief);
+ log->Printf ("SBDebugger(%p)::SetSelectedTarget () => SBTarget(%p): %s", m_opaque_sp.get(),
+ target_sp.get(), sstr.GetData());
+ }
+}
+
+void
+SBDebugger::DispatchInput (void* baton, const void *data, size_t data_len)
+{
+ DispatchInput (data,data_len);
+}
+
+void
+SBDebugger::DispatchInput (const void *data, size_t data_len)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::DispatchInput (data=\"%.*s\", size_t=%" PRIu64 ")",
+ m_opaque_sp.get(),
+ (int) data_len,
+ (const char *) data,
+ (uint64_t)data_len);
+
+ if (m_opaque_sp)
+ m_opaque_sp->DispatchInput ((const char *) data, data_len);
+}
+
+void
+SBDebugger::DispatchInputInterrupt ()
+{
+ if (m_opaque_sp)
+ m_opaque_sp->DispatchInputInterrupt ();
+}
+
+void
+SBDebugger::DispatchInputEndOfFile ()
+{
+ if (m_opaque_sp)
+ m_opaque_sp->DispatchInputEndOfFile ();
+}
+
+bool
+SBDebugger::InputReaderIsTopReader (const lldb::SBInputReader &reader)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::InputReaderIsTopReader (SBInputReader(%p))", m_opaque_sp.get(), &reader);
+
+ if (m_opaque_sp && reader.IsValid())
+ {
+ InputReaderSP reader_sp (*reader);
+ return m_opaque_sp->InputReaderIsTopReader (reader_sp);
+ }
+
+ return false;
+}
+
+
+void
+SBDebugger::PushInputReader (SBInputReader &reader)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::PushInputReader (SBInputReader(%p))", m_opaque_sp.get(), &reader);
+
+ if (m_opaque_sp && reader.IsValid())
+ {
+ TargetSP target_sp (m_opaque_sp->GetSelectedTarget());
+ Mutex::Locker api_locker;
+ if (target_sp)
+ api_locker.Lock(target_sp->GetAPIMutex());
+ InputReaderSP reader_sp(*reader);
+ m_opaque_sp->PushInputReader (reader_sp);
+ }
+}
+
+void
+SBDebugger::NotifyTopInputReader (InputReaderAction notification)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::NotifyTopInputReader (%d)", m_opaque_sp.get(), notification);
+
+ if (m_opaque_sp)
+ m_opaque_sp->NotifyTopInputReader (notification);
+}
+
+void
+SBDebugger::reset (const DebuggerSP &debugger_sp)
+{
+ m_opaque_sp = debugger_sp;
+}
+
+Debugger *
+SBDebugger::get () const
+{
+ return m_opaque_sp.get();
+}
+
+Debugger &
+SBDebugger::ref () const
+{
+ assert (m_opaque_sp.get());
+ return *m_opaque_sp;
+}
+
+const lldb::DebuggerSP &
+SBDebugger::get_sp () const
+{
+ return m_opaque_sp;
+}
+
+SBDebugger
+SBDebugger::FindDebuggerWithID (int id)
+{
+ // No need to lock, the debugger list is thread safe
+ SBDebugger sb_debugger;
+ DebuggerSP debugger_sp = Debugger::FindDebuggerWithID (id);
+ if (debugger_sp)
+ sb_debugger.reset (debugger_sp);
+ return sb_debugger;
+}
+
+const char *
+SBDebugger::GetInstanceName()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetInstanceName().AsCString();
+ else
+ return NULL;
+}
+
+SBError
+SBDebugger::SetInternalVariable (const char *var_name, const char *value, const char *debugger_instance_name)
+{
+ SBError sb_error;
+ DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName (ConstString(debugger_instance_name)));
+ Error error;
+ if (debugger_sp)
+ {
+ ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext());
+ error = debugger_sp->SetPropertyValue (&exe_ctx,
+ eVarSetOperationAssign,
+ var_name,
+ value);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid debugger instance name '%s'", debugger_instance_name);
+ }
+ if (error.Fail())
+ sb_error.SetError(error);
+ return sb_error;
+}
+
+SBStringList
+SBDebugger::GetInternalVariableValue (const char *var_name, const char *debugger_instance_name)
+{
+ SBStringList ret_value;
+ DebuggerSP debugger_sp(Debugger::FindDebuggerWithInstanceName (ConstString(debugger_instance_name)));
+ Error error;
+ if (debugger_sp)
+ {
+ ExecutionContext exe_ctx (debugger_sp->GetCommandInterpreter().GetExecutionContext());
+ lldb::OptionValueSP value_sp (debugger_sp->GetPropertyValue (&exe_ctx,
+ var_name,
+ false,
+ error));
+ if (value_sp)
+ {
+ StreamString value_strm;
+ value_sp->DumpValue (&exe_ctx, value_strm, OptionValue::eDumpOptionValue);
+ const std::string &value_str = value_strm.GetString();
+ if (!value_str.empty())
+ {
+ StringList string_list;
+ string_list.SplitIntoLines(value_str.c_str(), value_str.size());
+ return SBStringList(&string_list);
+ }
+ }
+ }
+ return SBStringList();
+}
+
+uint32_t
+SBDebugger::GetTerminalWidth () const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetTerminalWidth ();
+ return 0;
+}
+
+void
+SBDebugger::SetTerminalWidth (uint32_t term_width)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetTerminalWidth (term_width);
+}
+
+const char *
+SBDebugger::GetPrompt() const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBDebugger(%p)::GetPrompt () => \"%s\"", m_opaque_sp.get(),
+ (m_opaque_sp ? m_opaque_sp->GetPrompt() : ""));
+
+ if (m_opaque_sp)
+ return m_opaque_sp->GetPrompt ();
+ return 0;
+}
+
+void
+SBDebugger::SetPrompt (const char *prompt)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetPrompt (prompt);
+}
+
+
+ScriptLanguage
+SBDebugger::GetScriptLanguage() const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetScriptLanguage ();
+ return eScriptLanguageNone;
+}
+
+void
+SBDebugger::SetScriptLanguage (ScriptLanguage script_lang)
+{
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->SetScriptLanguage (script_lang);
+ }
+}
+
+bool
+SBDebugger::SetUseExternalEditor (bool value)
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->SetUseExternalEditor (value);
+ return false;
+}
+
+bool
+SBDebugger::GetUseExternalEditor ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetUseExternalEditor ();
+ return false;
+}
+
+bool
+SBDebugger::SetUseColor (bool value)
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->SetUseColor (value);
+ return false;
+}
+
+bool
+SBDebugger::GetUseColor () const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetUseColor ();
+ return false;
+}
+
+bool
+SBDebugger::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp)
+ {
+ const char *name = m_opaque_sp->GetInstanceName().AsCString();
+ user_id_t id = m_opaque_sp->GetID();
+ strm.Printf ("Debugger (instance: \"%s\", id: %" PRIu64 ")", name, id);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+user_id_t
+SBDebugger::GetID()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetID();
+ return LLDB_INVALID_UID;
+}
+
+
+SBError
+SBDebugger::SetCurrentPlatform (const char *platform_name)
+{
+ SBError sb_error;
+ if (m_opaque_sp)
+ {
+ PlatformSP platform_sp (Platform::Create (platform_name, sb_error.ref()));
+
+ if (platform_sp)
+ {
+ bool make_selected = true;
+ m_opaque_sp->GetPlatformList().Append (platform_sp, make_selected);
+ }
+ }
+ return sb_error;
+}
+
+bool
+SBDebugger::SetCurrentPlatformSDKRoot (const char *sysroot)
+{
+ if (m_opaque_sp)
+ {
+ PlatformSP platform_sp (m_opaque_sp->GetPlatformList().GetSelectedPlatform());
+
+ if (platform_sp)
+ {
+ platform_sp->SetSDKRootDirectory (ConstString (sysroot));
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+SBDebugger::GetCloseInputOnEOF () const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetCloseInputOnEOF ();
+ return false;
+}
+
+void
+SBDebugger::SetCloseInputOnEOF (bool b)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetCloseInputOnEOF (b);
+}
+
+SBTypeCategory
+SBDebugger::GetCategory (const char* category_name)
+{
+ if (!category_name || *category_name == 0)
+ return SBTypeCategory();
+
+ TypeCategoryImplSP category_sp;
+
+ if (DataVisualization::Categories::GetCategory(ConstString(category_name), category_sp, false))
+ return SBTypeCategory(category_sp);
+ else
+ return SBTypeCategory();
+}
+
+SBTypeCategory
+SBDebugger::CreateCategory (const char* category_name)
+{
+ if (!category_name || *category_name == 0)
+ return SBTypeCategory();
+
+ TypeCategoryImplSP category_sp;
+
+ if (DataVisualization::Categories::GetCategory(ConstString(category_name), category_sp, true))
+ return SBTypeCategory(category_sp);
+ else
+ return SBTypeCategory();
+}
+
+bool
+SBDebugger::DeleteCategory (const char* category_name)
+{
+ if (!category_name || *category_name == 0)
+ return false;
+
+ return DataVisualization::Categories::Delete(ConstString(category_name));
+}
+
+uint32_t
+SBDebugger::GetNumCategories()
+{
+ return DataVisualization::Categories::GetCount();
+}
+
+SBTypeCategory
+SBDebugger::GetCategoryAtIndex (uint32_t index)
+{
+ return SBTypeCategory(DataVisualization::Categories::GetCategoryAtIndex(index));
+}
+
+SBTypeCategory
+SBDebugger::GetDefaultCategory()
+{
+ return GetCategory("default");
+}
+
+SBTypeFormat
+SBDebugger::GetFormatForType (SBTypeNameSpecifier type_name)
+{
+ SBTypeCategory default_category_sb = GetDefaultCategory();
+ if (default_category_sb.GetEnabled())
+ return default_category_sb.GetFormatForType(type_name);
+ return SBTypeFormat();
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSummary
+SBDebugger::GetSummaryForType (SBTypeNameSpecifier type_name)
+{
+ if (type_name.IsValid() == false)
+ return SBTypeSummary();
+ return SBTypeSummary(DataVisualization::GetSummaryForType(type_name.GetSP()));
+}
+#endif // LLDB_DISABLE_PYTHON
+
+SBTypeFilter
+SBDebugger::GetFilterForType (SBTypeNameSpecifier type_name)
+{
+ if (type_name.IsValid() == false)
+ return SBTypeFilter();
+ return SBTypeFilter(DataVisualization::GetFilterForType(type_name.GetSP()));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSynthetic
+SBDebugger::GetSyntheticForType (SBTypeNameSpecifier type_name)
+{
+ if (type_name.IsValid() == false)
+ return SBTypeSynthetic();
+ return SBTypeSynthetic(DataVisualization::GetSyntheticForType(type_name.GetSP()));
+}
+#endif // LLDB_DISABLE_PYTHON
+
+bool
+SBDebugger::EnableLog (const char *channel, const char **categories)
+{
+ if (m_opaque_sp)
+ {
+ uint32_t log_options = LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
+ StreamString errors;
+ return m_opaque_sp->EnableLog (channel, categories, NULL, log_options, errors);
+
+ }
+ else
+ return false;
+}
+
+void
+SBDebugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
+{
+ if (m_opaque_sp)
+ {
+ return m_opaque_sp->SetLoggingCallback (log_callback, baton);
+ }
+}
+
+
diff --git a/source/API/SBDeclaration.cpp b/source/API/SBDeclaration.cpp
new file mode 100644
index 000000000000..fc90156e75ad
--- /dev/null
+++ b/source/API/SBDeclaration.cpp
@@ -0,0 +1,206 @@
+//===-- SBDeclaration.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/SBDeclaration.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Declaration.h"
+
+#include <limits.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBDeclaration::SBDeclaration () :
+ m_opaque_ap ()
+{
+}
+
+SBDeclaration::SBDeclaration (const SBDeclaration &rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+}
+
+SBDeclaration::SBDeclaration (const lldb_private::Declaration *lldb_object_ptr) :
+ m_opaque_ap ()
+{
+ if (lldb_object_ptr)
+ ref() = *lldb_object_ptr;
+}
+
+const SBDeclaration &
+SBDeclaration::operator = (const SBDeclaration &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+ else
+ m_opaque_ap.reset();
+ }
+ return *this;
+}
+
+void
+SBDeclaration::SetDeclaration (const lldb_private::Declaration &lldb_object_ref)
+{
+ ref() = lldb_object_ref;
+}
+
+
+SBDeclaration::~SBDeclaration ()
+{
+}
+
+
+bool
+SBDeclaration::IsValid () const
+{
+ return m_opaque_ap.get() && m_opaque_ap->IsValid();
+}
+
+
+SBFileSpec
+SBDeclaration::GetFileSpec () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFileSpec sb_file_spec;
+ if (m_opaque_ap.get() && m_opaque_ap->GetFile())
+ sb_file_spec.SetFileSpec(m_opaque_ap->GetFile());
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_file_spec.GetDescription (sstr);
+ log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s", m_opaque_ap.get(),
+ sb_file_spec.get(), sstr.GetData());
+ }
+
+ return sb_file_spec;
+}
+
+uint32_t
+SBDeclaration::GetLine () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t line = 0;
+ if (m_opaque_ap.get())
+ line = m_opaque_ap->GetLine();
+
+ if (log)
+ log->Printf ("SBLineEntry(%p)::GetLine () => %u", m_opaque_ap.get(), line);
+
+ return line;
+}
+
+
+uint32_t
+SBDeclaration::GetColumn () const
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetColumn();
+ return 0;
+}
+
+void
+SBDeclaration::SetFileSpec (lldb::SBFileSpec filespec)
+{
+ if (filespec.IsValid())
+ ref().SetFile(filespec.ref());
+ else
+ ref().SetFile(FileSpec());
+}
+void
+SBDeclaration::SetLine (uint32_t line)
+{
+ ref().SetLine(line);
+}
+
+void
+SBDeclaration::SetColumn (uint32_t column)
+{
+ ref().SetColumn(column);
+}
+
+
+
+bool
+SBDeclaration::operator == (const SBDeclaration &rhs) const
+{
+ lldb_private::Declaration *lhs_ptr = m_opaque_ap.get();
+ lldb_private::Declaration *rhs_ptr = rhs.m_opaque_ap.get();
+
+ if (lhs_ptr && rhs_ptr)
+ return lldb_private::Declaration::Compare (*lhs_ptr, *rhs_ptr) == 0;
+
+ return lhs_ptr == rhs_ptr;
+}
+
+bool
+SBDeclaration::operator != (const SBDeclaration &rhs) const
+{
+ lldb_private::Declaration *lhs_ptr = m_opaque_ap.get();
+ lldb_private::Declaration *rhs_ptr = rhs.m_opaque_ap.get();
+
+ if (lhs_ptr && rhs_ptr)
+ return lldb_private::Declaration::Compare (*lhs_ptr, *rhs_ptr) != 0;
+
+ return lhs_ptr != rhs_ptr;
+}
+
+const lldb_private::Declaration *
+SBDeclaration::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::Declaration &
+SBDeclaration::ref()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new lldb_private::Declaration ());
+ return *m_opaque_ap;
+}
+
+const lldb_private::Declaration &
+SBDeclaration::ref() const
+{
+ return *m_opaque_ap;
+}
+
+bool
+SBDeclaration::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ char file_path[PATH_MAX*2];
+ m_opaque_ap->GetFile().GetPath (file_path, sizeof (file_path));
+ strm.Printf ("%s:%u", file_path, GetLine());
+ if (GetColumn() > 0)
+ strm.Printf (":%u", GetColumn());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+lldb_private::Declaration *
+SBDeclaration::get ()
+{
+ return m_opaque_ap.get();
+}
diff --git a/source/API/SBError.cpp b/source/API/SBError.cpp
new file mode 100644
index 000000000000..bd6b54300f60
--- /dev/null
+++ b/source/API/SBError.cpp
@@ -0,0 +1,233 @@
+//===-- SBError.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/SBError.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+
+#include <stdarg.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBError::SBError () :
+ m_opaque_ap ()
+{
+}
+
+SBError::SBError (const SBError &rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ m_opaque_ap.reset (new Error(*rhs));
+}
+
+
+SBError::~SBError()
+{
+}
+
+const SBError &
+SBError::operator = (const SBError &rhs)
+{
+ if (rhs.IsValid())
+ {
+ if (m_opaque_ap.get())
+ *m_opaque_ap = *rhs;
+ else
+ m_opaque_ap.reset (new Error(*rhs));
+ }
+ else
+ m_opaque_ap.reset();
+
+ return *this;
+}
+
+
+const char *
+SBError::GetCString () const
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->AsCString();
+ return NULL;
+}
+
+void
+SBError::Clear ()
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->Clear();
+}
+
+bool
+SBError::Fail () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool ret_value = false;
+ if (m_opaque_ap.get())
+ ret_value = m_opaque_ap->Fail();
+
+ if (log)
+ log->Printf ("SBError(%p)::Fail () => %i", m_opaque_ap.get(), ret_value);
+
+ return ret_value;
+}
+
+bool
+SBError::Success () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool ret_value = true;
+ if (m_opaque_ap.get())
+ ret_value = m_opaque_ap->Success();
+
+ if (log)
+ log->Printf ("SBError(%p)::Success () => %i", m_opaque_ap.get(), ret_value);
+
+ return ret_value;
+}
+
+uint32_t
+SBError::GetError () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t err = 0;
+ if (m_opaque_ap.get())
+ err = m_opaque_ap->GetError();
+
+ if (log)
+ log->Printf ("SBError(%p)::GetError () => 0x%8.8x", m_opaque_ap.get(), err);
+
+
+ return err;
+}
+
+ErrorType
+SBError::GetType () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ErrorType err_type = eErrorTypeInvalid;
+ if (m_opaque_ap.get())
+ err_type = m_opaque_ap->GetType();
+
+ if (log)
+ log->Printf ("SBError(%p)::GetType () => %i", m_opaque_ap.get(), err_type);
+
+ return err_type;
+}
+
+void
+SBError::SetError (uint32_t err, ErrorType type)
+{
+ CreateIfNeeded ();
+ m_opaque_ap->SetError (err, type);
+}
+
+void
+SBError::SetError (const Error &lldb_error)
+{
+ CreateIfNeeded ();
+ *m_opaque_ap = lldb_error;
+}
+
+
+void
+SBError::SetErrorToErrno ()
+{
+ CreateIfNeeded ();
+ m_opaque_ap->SetErrorToErrno ();
+}
+
+void
+SBError::SetErrorToGenericError ()
+{
+ CreateIfNeeded ();
+ m_opaque_ap->SetErrorToErrno ();
+}
+
+void
+SBError::SetErrorString (const char *err_str)
+{
+ CreateIfNeeded ();
+ m_opaque_ap->SetErrorString (err_str);
+}
+
+int
+SBError::SetErrorStringWithFormat (const char *format, ...)
+{
+ CreateIfNeeded ();
+ va_list args;
+ va_start (args, format);
+ int num_chars = m_opaque_ap->SetErrorStringWithVarArg (format, args);
+ va_end (args);
+ return num_chars;
+}
+
+bool
+SBError::IsValid () const
+{
+ return m_opaque_ap.get() != NULL;
+}
+
+void
+SBError::CreateIfNeeded ()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset(new Error ());
+}
+
+
+lldb_private::Error *
+SBError::operator->()
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::Error *
+SBError::get()
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::Error &
+SBError::ref()
+{
+ CreateIfNeeded();
+ return *m_opaque_ap;
+}
+
+const lldb_private::Error &
+SBError::operator*() const
+{
+ // Be sure to call "IsValid()" before calling this function or it will crash
+ return *m_opaque_ap;
+}
+
+bool
+SBError::GetDescription (SBStream &description)
+{
+ if (m_opaque_ap.get())
+ {
+ if (m_opaque_ap->Success())
+ description.Printf ("success");
+ else
+ {
+ const char * err_string = GetCString();
+ description.Printf ("error: %s", (err_string != NULL ? err_string : ""));
+ }
+ }
+ else
+ description.Printf ("error: <NULL>");
+
+ return true;
+}
diff --git a/source/API/SBEvent.cpp b/source/API/SBEvent.cpp
new file mode 100644
index 000000000000..d5d4a84bc1fd
--- /dev/null
+++ b/source/API/SBEvent.cpp
@@ -0,0 +1,245 @@
+//===-- SBEvent.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/SBEvent.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBEvent::SBEvent () :
+ m_event_sp (),
+ m_opaque_ptr (NULL)
+{
+}
+
+SBEvent::SBEvent (uint32_t event_type, const char *cstr, uint32_t cstr_len) :
+ m_event_sp (new Event (event_type, new EventDataBytes (cstr, cstr_len))),
+ m_opaque_ptr (m_event_sp.get())
+{
+}
+
+SBEvent::SBEvent (EventSP &event_sp) :
+ m_event_sp (event_sp),
+ m_opaque_ptr (event_sp.get())
+{
+}
+
+SBEvent::SBEvent (const SBEvent &rhs) :
+ m_event_sp (rhs.m_event_sp),
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+
+}
+
+const SBEvent &
+SBEvent::operator = (const SBEvent &rhs)
+{
+ if (this != &rhs)
+ {
+ m_event_sp = rhs.m_event_sp;
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ }
+ return *this;
+}
+
+SBEvent::~SBEvent()
+{
+}
+
+const char *
+SBEvent::GetDataFlavor ()
+{
+ Event *lldb_event = get();
+ if (lldb_event)
+ {
+ EventData *event_data = lldb_event->GetData();
+ if (event_data)
+ return lldb_event->GetData()->GetFlavor().AsCString();
+ }
+ return NULL;
+}
+
+uint32_t
+SBEvent::GetType () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const Event *lldb_event = get();
+ uint32_t event_type = 0;
+ if (lldb_event)
+ event_type = lldb_event->GetType();
+
+ if (log)
+ {
+ StreamString sstr;
+ if (lldb_event && lldb_event->GetBroadcaster() && lldb_event->GetBroadcaster()->GetEventNames(sstr, event_type, true))
+ log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x (%s)", get(), event_type, sstr.GetData());
+ else
+ log->Printf ("SBEvent(%p)::GetType () => 0x%8.8x", get(), event_type);
+
+ }
+
+ return event_type;
+}
+
+SBBroadcaster
+SBEvent::GetBroadcaster () const
+{
+ SBBroadcaster broadcaster;
+ const Event *lldb_event = get();
+ if (lldb_event)
+ broadcaster.reset (lldb_event->GetBroadcaster(), false);
+ return broadcaster;
+}
+
+const char *
+SBEvent::GetBroadcasterClass () const
+{
+ const Event *lldb_event = get();
+ if (lldb_event)
+ return lldb_event->GetBroadcaster()->GetBroadcasterClass().AsCString();
+ else
+ return "unknown class";
+}
+
+bool
+SBEvent::BroadcasterMatchesPtr (const SBBroadcaster *broadcaster)
+{
+ if (broadcaster)
+ return BroadcasterMatchesRef (*broadcaster);
+ return false;
+}
+
+bool
+SBEvent::BroadcasterMatchesRef (const SBBroadcaster &broadcaster)
+{
+
+ Event *lldb_event = get();
+ bool success = false;
+ if (lldb_event)
+ success = lldb_event->BroadcasterIs (broadcaster.get());
+
+ // For logging, this gets a little chatty so only enable this when verbose logging is on
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API | LIBLLDB_LOG_VERBOSE));
+ if (log)
+ log->Printf ("SBEvent(%p)::BroadcasterMatchesRef (SBBroadcaster(%p): %s) => %i",
+ get(),
+ broadcaster.get(),
+ broadcaster.GetName(),
+ success);
+
+ return success;
+}
+
+void
+SBEvent::Clear()
+{
+ Event *lldb_event = get();
+ if (lldb_event)
+ lldb_event->Clear();
+}
+
+EventSP &
+SBEvent::GetSP () const
+{
+ return m_event_sp;
+}
+
+Event *
+SBEvent::get() const
+{
+ // There is a dangerous accessor call GetSharedPtr which can be used, so if
+ // we have anything valid in m_event_sp, we must use that since if it gets
+ // used by a function that puts something in there, then it won't update
+ // m_opaque_ptr...
+ if (m_event_sp)
+ m_opaque_ptr = m_event_sp.get();
+
+ return m_opaque_ptr;
+}
+
+void
+SBEvent::reset (EventSP &event_sp)
+{
+ m_event_sp = event_sp;
+ m_opaque_ptr = m_event_sp.get();
+}
+
+void
+SBEvent::reset (Event* event_ptr)
+{
+ m_opaque_ptr = event_ptr;
+ m_event_sp.reset();
+}
+
+bool
+SBEvent::IsValid() const
+{
+ // Do NOT use m_opaque_ptr directly!!! Must use the SBEvent::get()
+ // accessor. See comments in SBEvent::get()....
+ return SBEvent::get() != NULL;
+
+}
+
+const char *
+SBEvent::GetCStringFromEvent (const SBEvent &event)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBEvent(%p)::GetCStringFromEvent () => \"%s\"",
+ event.get(),
+ reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event.get())));
+
+ return reinterpret_cast<const char *>(EventDataBytes::GetBytesFromEvent (event.get()));
+}
+
+
+bool
+SBEvent::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (get())
+ {
+ m_opaque_ptr->Dump (&strm);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+bool
+SBEvent::GetDescription (SBStream &description) const
+{
+ Stream &strm = description.ref();
+
+ if (get())
+ {
+ m_opaque_ptr->Dump (&strm);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
diff --git a/source/API/SBExpressionOptions.cpp b/source/API/SBExpressionOptions.cpp
new file mode 100644
index 000000000000..127b0cf13cdc
--- /dev/null
+++ b/source/API/SBExpressionOptions.cpp
@@ -0,0 +1,126 @@
+//===-- SBExpressionOptions.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/SBExpressionOptions.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBExpressionOptions::SBExpressionOptions () :
+ m_opaque_ap(new EvaluateExpressionOptions())
+{
+}
+
+SBExpressionOptions::SBExpressionOptions (const SBExpressionOptions &rhs)
+{
+ m_opaque_ap.reset(new EvaluateExpressionOptions());
+ *(m_opaque_ap.get()) = rhs.ref();
+}
+
+const SBExpressionOptions &
+SBExpressionOptions::operator = (const SBExpressionOptions &rhs)
+{
+ if (this != &rhs)
+ {
+ this->ref() = rhs.ref();
+ }
+ return *this;
+}
+
+SBExpressionOptions::~SBExpressionOptions()
+{
+}
+
+bool
+SBExpressionOptions::GetCoerceResultToId () const
+{
+ return m_opaque_ap->DoesCoerceToId ();
+}
+
+void
+SBExpressionOptions::SetCoerceResultToId (bool coerce)
+{
+ m_opaque_ap->SetCoerceToId (coerce);
+}
+
+bool
+SBExpressionOptions::GetUnwindOnError () const
+{
+ return m_opaque_ap->DoesUnwindOnError ();
+}
+
+void
+SBExpressionOptions::SetUnwindOnError (bool unwind)
+{
+ m_opaque_ap->SetUnwindOnError (unwind);
+}
+
+bool
+SBExpressionOptions::GetIgnoreBreakpoints () const
+{
+ return m_opaque_ap->DoesIgnoreBreakpoints ();
+}
+
+void
+SBExpressionOptions::SetIgnoreBreakpoints (bool ignore)
+{
+ m_opaque_ap->SetIgnoreBreakpoints (ignore);
+}
+
+lldb::DynamicValueType
+SBExpressionOptions::GetFetchDynamicValue () const
+{
+ return m_opaque_ap->GetUseDynamic ();
+}
+
+void
+SBExpressionOptions::SetFetchDynamicValue (lldb::DynamicValueType dynamic)
+{
+ m_opaque_ap->SetUseDynamic (dynamic);
+}
+
+uint32_t
+SBExpressionOptions::GetTimeoutInMicroSeconds () const
+{
+ return m_opaque_ap->GetTimeoutUsec ();
+}
+
+void
+SBExpressionOptions::SetTimeoutInMicroSeconds (uint32_t timeout)
+{
+ m_opaque_ap->SetTimeoutUsec (timeout);
+}
+
+bool
+SBExpressionOptions::GetTryAllThreads () const
+{
+ return m_opaque_ap->GetRunOthers ();
+}
+
+void
+SBExpressionOptions::SetTryAllThreads (bool run_others)
+{
+ m_opaque_ap->SetRunOthers (run_others);
+}
+
+EvaluateExpressionOptions *
+SBExpressionOptions::get() const
+{
+ return m_opaque_ap.get();
+}
+
+EvaluateExpressionOptions &
+SBExpressionOptions::ref () const
+{
+ return *(m_opaque_ap.get());
+}
diff --git a/source/API/SBFileSpec.cpp b/source/API/SBFileSpec.cpp
new file mode 100644
index 000000000000..4413689501a8
--- /dev/null
+++ b/source/API/SBFileSpec.cpp
@@ -0,0 +1,181 @@
+//===-- SBFileSpec.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <limits.h>
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBFileSpec::SBFileSpec () :
+ m_opaque_ap(new lldb_private::FileSpec())
+{
+}
+
+SBFileSpec::SBFileSpec (const SBFileSpec &rhs) :
+ m_opaque_ap(new lldb_private::FileSpec(*rhs.m_opaque_ap))
+{
+}
+
+SBFileSpec::SBFileSpec (const lldb_private::FileSpec& fspec) :
+ m_opaque_ap(new lldb_private::FileSpec(fspec))
+{
+}
+
+// Deprected!!!
+SBFileSpec::SBFileSpec (const char *path) :
+ m_opaque_ap(new FileSpec (path, true))
+{
+}
+
+SBFileSpec::SBFileSpec (const char *path, bool resolve) :
+ m_opaque_ap(new FileSpec (path, resolve))
+{
+}
+
+SBFileSpec::~SBFileSpec ()
+{
+}
+
+const SBFileSpec &
+SBFileSpec::operator = (const SBFileSpec &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_ap = *rhs.m_opaque_ap;
+ return *this;
+}
+
+bool
+SBFileSpec::IsValid() const
+{
+ return *m_opaque_ap;
+}
+
+bool
+SBFileSpec::Exists () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool result = m_opaque_ap->Exists();
+
+ if (log)
+ log->Printf ("SBFileSpec(%p)::Exists () => %s", m_opaque_ap.get(), (result ? "true" : "false"));
+
+ return result;
+}
+
+bool
+SBFileSpec::ResolveExecutableLocation ()
+{
+ return m_opaque_ap->ResolveExecutableLocation ();
+}
+
+int
+SBFileSpec::ResolvePath (const char *src_path, char *dst_path, size_t dst_len)
+{
+ return lldb_private::FileSpec::Resolve (src_path, dst_path, dst_len);
+}
+
+const char *
+SBFileSpec::GetFilename() const
+{
+ const char *s = m_opaque_ap->GetFilename().AsCString();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (s)
+ log->Printf ("SBFileSpec(%p)::GetFilename () => \"%s\"", m_opaque_ap.get(), s);
+ else
+ log->Printf ("SBFileSpec(%p)::GetFilename () => NULL", m_opaque_ap.get());
+ }
+
+ return s;
+}
+
+const char *
+SBFileSpec::GetDirectory() const
+{
+ const char *s = m_opaque_ap->GetDirectory().AsCString();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (s)
+ log->Printf ("SBFileSpec(%p)::GetDirectory () => \"%s\"", m_opaque_ap.get(), s);
+ else
+ log->Printf ("SBFileSpec(%p)::GetDirectory () => NULL", m_opaque_ap.get());
+ }
+ return s;
+}
+
+uint32_t
+SBFileSpec::GetPath (char *dst_path, size_t dst_len) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t result = m_opaque_ap->GetPath (dst_path, dst_len);
+
+ if (log)
+ log->Printf ("SBFileSpec(%p)::GetPath (dst_path=\"%.*s\", dst_len=%" PRIu64 ") => %u",
+ m_opaque_ap.get(), result, dst_path, (uint64_t)dst_len, result);
+
+ if (result == 0 && dst_path && dst_len > 0)
+ *dst_path = '\0';
+ return result;
+}
+
+
+const lldb_private::FileSpec *
+SBFileSpec::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+const lldb_private::FileSpec *
+SBFileSpec::get() const
+{
+ return m_opaque_ap.get();
+}
+
+
+const lldb_private::FileSpec &
+SBFileSpec::operator*() const
+{
+ return *m_opaque_ap.get();
+}
+
+const lldb_private::FileSpec &
+SBFileSpec::ref() const
+{
+ return *m_opaque_ap.get();
+}
+
+
+void
+SBFileSpec::SetFileSpec (const lldb_private::FileSpec& fs)
+{
+ *m_opaque_ap = fs;
+}
+
+bool
+SBFileSpec::GetDescription (SBStream &description) const
+{
+ Stream &strm = description.ref();
+ char path[PATH_MAX];
+ if (m_opaque_ap->GetPath(path, sizeof(path)))
+ strm.PutCString (path);
+ return true;
+}
diff --git a/source/API/SBFileSpecList.cpp b/source/API/SBFileSpecList.cpp
new file mode 100644
index 000000000000..3ebf3cc80a2a
--- /dev/null
+++ b/source/API/SBFileSpecList.cpp
@@ -0,0 +1,142 @@
+//===-- SBFileSpecListList.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <limits.h>
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBFileSpecList.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/FileSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBFileSpecList::SBFileSpecList () :
+ m_opaque_ap(new FileSpecList())
+{
+}
+
+SBFileSpecList::SBFileSpecList (const SBFileSpecList &rhs) :
+ m_opaque_ap()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (rhs.m_opaque_ap.get())
+ m_opaque_ap.reset (new FileSpecList (*(rhs.get())));
+
+ if (log)
+ {
+ log->Printf ("SBFileSpecList::SBFileSpecList (const SBFileSpecList rhs.ap=%p) => SBFileSpecList(%p)",
+ rhs.m_opaque_ap.get(), m_opaque_ap.get());
+ }
+}
+
+SBFileSpecList::~SBFileSpecList ()
+{
+}
+
+const SBFileSpecList &
+SBFileSpecList::operator = (const SBFileSpecList &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_ap.reset (new lldb_private::FileSpecList(*(rhs.get())));
+ }
+ return *this;
+}
+
+uint32_t
+SBFileSpecList::GetSize () const
+{
+ return m_opaque_ap->GetSize();
+}
+
+void
+SBFileSpecList::Append (const SBFileSpec &sb_file)
+{
+ m_opaque_ap->Append (sb_file.ref());
+}
+
+bool
+SBFileSpecList::AppendIfUnique (const SBFileSpec &sb_file)
+{
+ return m_opaque_ap->AppendIfUnique (sb_file.ref());
+}
+
+void
+SBFileSpecList::Clear()
+{
+ m_opaque_ap->Clear();
+}
+
+uint32_t
+SBFileSpecList::FindFileIndex (uint32_t idx, const SBFileSpec &sb_file, bool full)
+{
+ return m_opaque_ap->FindFileIndex (idx, sb_file.ref(), full);
+}
+
+const SBFileSpec
+SBFileSpecList::GetFileSpecAtIndex (uint32_t idx) const
+{
+ SBFileSpec new_spec;
+ new_spec.SetFileSpec(m_opaque_ap->GetFileSpecAtIndex(idx));
+ return new_spec;
+}
+
+const lldb_private::FileSpecList *
+SBFileSpecList::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+const lldb_private::FileSpecList *
+SBFileSpecList::get() const
+{
+ return m_opaque_ap.get();
+}
+
+
+const lldb_private::FileSpecList &
+SBFileSpecList::operator*() const
+{
+ return *m_opaque_ap.get();
+}
+
+const lldb_private::FileSpecList &
+SBFileSpecList::ref() const
+{
+ return *m_opaque_ap.get();
+}
+
+bool
+SBFileSpecList::GetDescription (SBStream &description) const
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ uint32_t num_files = m_opaque_ap->GetSize();
+ strm.Printf ("%d files: ", num_files);
+ for (uint32_t i = 0; i < num_files; i++)
+ {
+ char path[PATH_MAX];
+ if (m_opaque_ap->GetFileSpecAtIndex(i).GetPath(path, sizeof(path)))
+ strm.Printf ("\n %s", path);
+ }
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp
new file mode 100644
index 000000000000..1a1a63bd0671
--- /dev/null
+++ b/source/API/SBFrame.cpp
@@ -0,0 +1,1526 @@
+//===-- SBFrame.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/SBFrame.h"
+
+#include <string>
+#include <algorithm>
+
+#include "lldb/lldb-types.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackID.h"
+#include "lldb/Target/Thread.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBSymbolContext.h"
+#include "lldb/API/SBThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBFrame::SBFrame () :
+ m_opaque_sp (new ExecutionContextRef())
+{
+}
+
+SBFrame::SBFrame (const StackFrameSP &lldb_object_sp) :
+ m_opaque_sp (new ExecutionContextRef (lldb_object_sp))
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream sstr;
+ GetDescription (sstr);
+ log->Printf ("SBFrame::SBFrame (sp=%p) => SBFrame(%p): %s",
+ lldb_object_sp.get(), lldb_object_sp.get(), sstr.GetData());
+
+ }
+}
+
+SBFrame::SBFrame(const SBFrame &rhs) :
+ m_opaque_sp (new ExecutionContextRef (*rhs.m_opaque_sp))
+{
+}
+
+const SBFrame &
+SBFrame::operator = (const SBFrame &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_sp = *rhs.m_opaque_sp;
+ return *this;
+}
+
+SBFrame::~SBFrame()
+{
+}
+
+StackFrameSP
+SBFrame::GetFrameSP() const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetFrameSP();
+ return StackFrameSP();
+}
+
+void
+SBFrame::SetFrameSP (const StackFrameSP &lldb_object_sp)
+{
+ return m_opaque_sp->SetFrameSP(lldb_object_sp);
+}
+
+bool
+SBFrame::IsValid() const
+{
+ return GetFrameSP().get() != NULL;
+}
+
+SBSymbolContext
+SBFrame::GetSymbolContext (uint32_t resolve_scope) const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBSymbolContext sb_sym_ctx;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_sym_ctx.SetSymbolContext(&frame->GetSymbolContext (resolve_scope));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetVariables () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetSymbolContext () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::GetSymbolContext (resolve_scope=0x%8.8x) => SBSymbolContext(%p)",
+ frame, resolve_scope, sb_sym_ctx.get());
+
+ return sb_sym_ctx;
+}
+
+SBModule
+SBFrame::GetModule () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBModule sb_module;
+ ModuleSP module_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ module_sp = frame->GetSymbolContext (eSymbolContextModule).module_sp;
+ sb_module.SetSP (module_sp);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetModule () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetModule () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::GetModule () => SBModule(%p)",
+ frame, module_sp.get());
+
+ return sb_module;
+}
+
+SBCompileUnit
+SBFrame::GetCompileUnit () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBCompileUnit sb_comp_unit;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_comp_unit.reset (frame->GetSymbolContext (eSymbolContextCompUnit).comp_unit);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetCompileUnit () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetCompileUnit () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetCompileUnit () => SBCompileUnit(%p)",
+ frame, sb_comp_unit.get());
+
+ return sb_comp_unit;
+}
+
+SBFunction
+SBFrame::GetFunction () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBFunction sb_function;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_function.reset(frame->GetSymbolContext (eSymbolContextFunction).function);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFunction () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFunction () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetFunction () => SBFunction(%p)",
+ frame, sb_function.get());
+
+ return sb_function;
+}
+
+SBSymbol
+SBFrame::GetSymbol () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBSymbol sb_symbol;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_symbol.reset(frame->GetSymbolContext (eSymbolContextSymbol).symbol);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetSymbol () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetSymbol () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetSymbol () => SBSymbol(%p)",
+ frame, sb_symbol.get());
+ return sb_symbol;
+}
+
+SBBlock
+SBFrame::GetBlock () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBBlock sb_block;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_block.SetPtr (frame->GetSymbolContext (eSymbolContextBlock).block);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetBlock () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame(%p)::GetBlock () => error: process is running", frame);
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetBlock () => SBBlock(%p)",
+ frame, sb_block.GetPtr());
+ return sb_block;
+}
+
+SBBlock
+SBFrame::GetFrameBlock () const
+{
+ SBBlock sb_block;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_block.SetPtr(frame->GetFrameBlock ());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFrameBlock () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFrameBlock () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetFrameBlock () => SBBlock(%p)",
+ frame, sb_block.GetPtr());
+ return sb_block;
+}
+
+SBLineEntry
+SBFrame::GetLineEntry () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBLineEntry sb_line_entry;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_line_entry.SetLineEntry (frame->GetSymbolContext (eSymbolContextLineEntry).line_entry);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetLineEntry () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetLineEntry () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetLineEntry () => SBLineEntry(%p)",
+ frame, sb_line_entry.get());
+ return sb_line_entry;
+}
+
+uint32_t
+SBFrame::GetFrameID () const
+{
+ uint32_t frame_idx = UINT32_MAX;
+
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ frame_idx = frame->GetFrameIndex ();
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBFrame(%p)::GetFrameID () => %u",
+ frame, frame_idx);
+ return frame_idx;
+}
+
+addr_t
+SBFrame::GetPC () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ addr = frame->GetFrameCodeAddress().GetOpcodeLoadAddress (target);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetPC () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetPC () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::GetPC () => 0x%" PRIx64, frame, addr);
+
+ return addr;
+}
+
+bool
+SBFrame::SetPC (addr_t new_pc)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool ret_val = false;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ ret_val = frame->GetRegisterContext()->SetPC (new_pc);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::SetPC () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::SetPC () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::SetPC (new_pc=0x%" PRIx64 ") => %i",
+ frame, new_pc, ret_val);
+
+ return ret_val;
+}
+
+addr_t
+SBFrame::GetSP () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ addr = frame->GetRegisterContext()->GetSP();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetSP () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetSP () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetSP () => 0x%" PRIx64, frame, addr);
+
+ return addr;
+}
+
+
+addr_t
+SBFrame::GetFP () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ addr = frame->GetRegisterContext()->GetFP();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFP () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFP () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::GetFP () => 0x%" PRIx64, frame, addr);
+ return addr;
+}
+
+
+SBAddress
+SBFrame::GetPCAddress () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBAddress sb_addr;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sb_addr.SetAddress (&frame->GetFrameCodeAddress());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetPCAddress () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetPCAddress () => error: process is running");
+ }
+ }
+ if (log)
+ log->Printf ("SBFrame(%p)::GetPCAddress () => SBAddress(%p)", frame, sb_addr.get());
+ return sb_addr;
+}
+
+void
+SBFrame::Clear()
+{
+ m_opaque_sp->Clear();
+}
+
+lldb::SBValue
+SBFrame::GetValueForVariablePath (const char *var_path)
+{
+ SBValue sb_value;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ if (frame && target)
+ {
+ lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
+ sb_value = GetValueForVariablePath (var_path, use_dynamic);
+ }
+ return sb_value;
+}
+
+lldb::SBValue
+SBFrame::GetValueForVariablePath (const char *var_path, DynamicValueType use_dynamic)
+{
+ SBValue sb_value;
+ Mutex::Locker api_locker;
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (var_path == NULL || var_path[0] == '\0')
+ {
+ if (log)
+ log->Printf ("SBFrame::GetValueForVariablePath called with empty variable path.");
+ return sb_value;
+ }
+
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ VariableSP var_sp;
+ Error error;
+ ValueObjectSP value_sp (frame->GetValueForVariableExpressionPath (var_path,
+ eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember | StackFrame::eExpressionPathOptionsAllowDirectIVarAccess,
+ var_sp,
+ error));
+ sb_value.SetSP(value_sp, use_dynamic);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetValueForVariablePath () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetValueForVariablePath () => error: process is running");
+ }
+ }
+ return sb_value;
+}
+
+SBValue
+SBFrame::FindVariable (const char *name)
+{
+ SBValue value;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ if (frame && target)
+ {
+ lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
+ value = FindVariable (name, use_dynamic);
+ }
+ return value;
+}
+
+
+SBValue
+SBFrame::FindVariable (const char *name, lldb::DynamicValueType use_dynamic)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ VariableSP var_sp;
+ SBValue sb_value;
+
+ if (name == NULL || name[0] == '\0')
+ {
+ if (log)
+ log->Printf ("SBFrame::FindVariable called with empty name");
+ return sb_value;
+ }
+
+ ValueObjectSP value_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ VariableList variable_list;
+ SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock));
+
+ if (sc.block)
+ {
+ const bool can_create = true;
+ const bool get_parent_variables = true;
+ const bool stop_if_block_is_inlined_function = true;
+
+ if (sc.block->AppendVariables (can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ &variable_list))
+ {
+ var_sp = variable_list.FindVariable (ConstString(name));
+ }
+ }
+
+ if (var_sp)
+ {
+ value_sp = frame->GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
+ sb_value.SetSP(value_sp, use_dynamic);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindVariable () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindVariable () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::FindVariable (name=\"%s\") => SBValue(%p)",
+ frame, name, value_sp.get());
+
+ return sb_value;
+}
+
+SBValue
+SBFrame::FindValue (const char *name, ValueType value_type)
+{
+ SBValue value;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ if (frame && target)
+ {
+ lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
+ value = FindValue (name, value_type, use_dynamic);
+ }
+ return value;
+}
+
+SBValue
+SBFrame::FindValue (const char *name, ValueType value_type, lldb::DynamicValueType use_dynamic)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBValue sb_value;
+
+ if (name == NULL || name[0] == '\0')
+ {
+ if (log)
+ log->Printf ("SBFrame::FindValue called with empty name.");
+ return sb_value;
+ }
+
+ ValueObjectSP value_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ switch (value_type)
+ {
+ case eValueTypeVariableGlobal: // global variable
+ case eValueTypeVariableStatic: // static variable
+ case eValueTypeVariableArgument: // function argument variables
+ case eValueTypeVariableLocal: // function local variables
+ {
+ VariableList *variable_list = frame->GetVariableList(true);
+
+ SymbolContext sc (frame->GetSymbolContext (eSymbolContextBlock));
+
+ const bool can_create = true;
+ const bool get_parent_variables = true;
+ const bool stop_if_block_is_inlined_function = true;
+
+ if (sc.block && sc.block->AppendVariables (can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ variable_list))
+ {
+ ConstString const_name(name);
+ const uint32_t num_variables = variable_list->GetSize();
+ for (uint32_t i = 0; i < num_variables; ++i)
+ {
+ VariableSP variable_sp (variable_list->GetVariableAtIndex(i));
+ if (variable_sp &&
+ variable_sp->GetScope() == value_type &&
+ variable_sp->GetName() == const_name)
+ {
+ value_sp = frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues);
+ sb_value.SetSP (value_sp, use_dynamic);
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case eValueTypeRegister: // stack frame register value
+ {
+ RegisterContextSP reg_ctx (frame->GetRegisterContext());
+ if (reg_ctx)
+ {
+ const uint32_t num_regs = reg_ctx->GetRegisterCount();
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx);
+ if (reg_info &&
+ ((reg_info->name && strcasecmp (reg_info->name, name) == 0) ||
+ (reg_info->alt_name && strcasecmp (reg_info->alt_name, name) == 0)))
+ {
+ value_sp = ValueObjectRegister::Create (frame, reg_ctx, reg_idx);
+ sb_value.SetSP (value_sp);
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case eValueTypeRegisterSet: // A collection of stack frame register values
+ {
+ RegisterContextSP reg_ctx (frame->GetRegisterContext());
+ if (reg_ctx)
+ {
+ const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
+ for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx)
+ {
+ const RegisterSet *reg_set = reg_ctx->GetRegisterSet (set_idx);
+ if (reg_set &&
+ ((reg_set->name && strcasecmp (reg_set->name, name) == 0) ||
+ (reg_set->short_name && strcasecmp (reg_set->short_name, name) == 0)))
+ {
+ value_sp = ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx);
+ sb_value.SetSP (value_sp);
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case eValueTypeConstResult: // constant result variables
+ {
+ ConstString const_name(name);
+ ClangExpressionVariableSP expr_var_sp (target->GetPersistentVariables().GetVariable (const_name));
+ if (expr_var_sp)
+ {
+ value_sp = expr_var_sp->GetValueObject();
+ sb_value.SetSP (value_sp, use_dynamic);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindValue () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindValue () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::FindVariableInScope (name=\"%s\", value_type=%i) => SBValue(%p)",
+ frame, name, value_type, value_sp.get());
+
+
+ return sb_value;
+}
+
+bool
+SBFrame::IsEqual (const SBFrame &that) const
+{
+ lldb::StackFrameSP this_sp = GetFrameSP();
+ lldb::StackFrameSP that_sp = that.GetFrameSP();
+ return (this_sp && that_sp && this_sp->GetStackID() == that_sp->GetStackID());
+}
+
+bool
+SBFrame::operator == (const SBFrame &rhs) const
+{
+ return IsEqual(rhs);
+}
+
+bool
+SBFrame::operator != (const SBFrame &rhs) const
+{
+ return !IsEqual(rhs);
+}
+
+SBThread
+SBFrame::GetThread () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ ThreadSP thread_sp (exe_ctx.GetThreadSP());
+ SBThread sb_thread (thread_sp);
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_thread.GetDescription (sstr);
+ log->Printf ("SBFrame(%p)::GetThread () => SBThread(%p): %s",
+ exe_ctx.GetFramePtr(),
+ thread_sp.get(),
+ sstr.GetData());
+ }
+
+ return sb_thread;
+}
+
+const char *
+SBFrame::Disassemble () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *disassembly = NULL;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ disassembly = frame->Disassemble();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::Disassemble () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::Disassemble () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::Disassemble () => %s", frame, disassembly);
+
+ return disassembly;
+}
+
+
+SBValueList
+SBFrame::GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only)
+{
+ SBValueList value_list;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ if (frame && target)
+ {
+ lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue();
+ value_list = GetVariables (arguments, locals, statics, in_scope_only, use_dynamic);
+ }
+ return value_list;
+}
+
+SBValueList
+SBFrame::GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only,
+ lldb::DynamicValueType use_dynamic)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBValueList value_list;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (log)
+ log->Printf ("SBFrame::GetVariables (arguments=%i, locals=%i, statics=%i, in_scope_only=%i)",
+ arguments,
+ locals,
+ statics,
+ in_scope_only);
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ size_t i;
+ VariableList *variable_list = NULL;
+ variable_list = frame->GetVariableList(true);
+ if (variable_list)
+ {
+ const size_t num_variables = variable_list->GetSize();
+ if (num_variables)
+ {
+ for (i = 0; i < num_variables; ++i)
+ {
+ VariableSP variable_sp (variable_list->GetVariableAtIndex(i));
+ if (variable_sp)
+ {
+ bool add_variable = false;
+ switch (variable_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ case eValueTypeVariableStatic:
+ add_variable = statics;
+ break;
+
+ case eValueTypeVariableArgument:
+ add_variable = arguments;
+ break;
+
+ case eValueTypeVariableLocal:
+ add_variable = locals;
+ break;
+
+ default:
+ break;
+ }
+ if (add_variable)
+ {
+ if (in_scope_only && !variable_sp->IsInScope(frame))
+ continue;
+
+ ValueObjectSP valobj_sp(frame->GetValueObjectForFrameVariable (variable_sp, eNoDynamicValues));
+ SBValue value_sb;
+ value_sb.SetSP(valobj_sp,use_dynamic);
+ value_list.Append(value_sb);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetVariables () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetVariables () => error: process is running");
+ }
+ }
+
+ if (log)
+ {
+ log->Printf ("SBFrame(%p)::GetVariables (...) => SBValueList(%p)", frame, value_list.opaque_ptr());
+ }
+
+ return value_list;
+}
+
+SBValueList
+SBFrame::GetRegisters ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBValueList value_list;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ RegisterContextSP reg_ctx (frame->GetRegisterContext());
+ if (reg_ctx)
+ {
+ const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
+ for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx)
+ {
+ value_list.Append(ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx));
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetRegisters () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetRegisters () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::GetRegisters () => SBValueList(%p)", frame, value_list.opaque_ptr());
+
+ return value_list;
+}
+
+SBValue
+SBFrame::FindRegister (const char *name)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBValue result;
+ ValueObjectSP value_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ RegisterContextSP reg_ctx (frame->GetRegisterContext());
+ if (reg_ctx)
+ {
+ const uint32_t num_regs = reg_ctx->GetRegisterCount();
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx);
+ if (reg_info &&
+ ((reg_info->name && strcasecmp (reg_info->name, name) == 0) ||
+ (reg_info->alt_name && strcasecmp (reg_info->alt_name, name) == 0)))
+ {
+ value_sp = ValueObjectRegister::Create (frame, reg_ctx, reg_idx);
+ result.SetSP (value_sp);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindRegister () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::FindRegister () => error: process is running");
+ }
+ }
+
+ if (log)
+ log->Printf ("SBFrame(%p)::FindRegister () => SBValue(%p)", frame, value_sp.get());
+
+ return result;
+}
+
+bool
+SBFrame::GetDescription (SBStream &description)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ Stream &strm = description.ref();
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrame *frame;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ frame->DumpUsingSettingsFormat (&strm);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetDescription () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetDescription () => error: process is running");
+ }
+
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+SBValue
+SBFrame::EvaluateExpression (const char *expr)
+{
+ SBValue result;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+ if (frame && target)
+ {
+ SBExpressionOptions options;
+ lldb::DynamicValueType fetch_dynamic_value = frame->CalculateTarget()->GetPreferDynamicValue();
+ options.SetFetchDynamicValue (fetch_dynamic_value);
+ options.SetUnwindOnError (true);
+ return EvaluateExpression (expr, options);
+ }
+ return result;
+}
+
+SBValue
+SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value)
+{
+ SBExpressionOptions options;
+ options.SetFetchDynamicValue (fetch_dynamic_value);
+ options.SetUnwindOnError (true);
+ return EvaluateExpression (expr, options);
+}
+
+SBValue
+SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value, bool unwind_on_error)
+{
+ SBExpressionOptions options;
+ options.SetFetchDynamicValue (fetch_dynamic_value);
+ options.SetUnwindOnError (unwind_on_error);
+ return EvaluateExpression (expr, options);
+}
+
+lldb::SBValue
+SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &options)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Log *expr_log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ExecutionResults exe_results = eExecutionSetupError;
+ SBValue expr_result;
+
+ if (expr == NULL || expr[0] == '\0')
+ {
+ if (log)
+ log->Printf ("SBFrame::EvaluateExpression called with an empty expression");
+ return expr_result;
+ }
+
+ ValueObjectSP expr_value_sp;
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (log)
+ log->Printf ("SBFrame()::EvaluateExpression (expr=\"%s\")...", expr);
+
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ StreamString frame_description;
+ frame->DumpUsingSettingsFormat (&frame_description);
+ Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s",
+ expr, options.GetFetchDynamicValue(), frame_description.GetString().c_str());
+#endif
+ exe_results = target->EvaluateExpression (expr,
+ frame,
+ expr_value_sp,
+ options.ref());
+ expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
+#ifdef LLDB_CONFIGURATION_DEBUG
+ Host::SetCrashDescription (NULL);
+#endif
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::EvaluateExpression () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::EvaluateExpression () => error: process is running");
+ }
+ }
+
+#ifndef LLDB_DISABLE_PYTHON
+ if (expr_log)
+ expr_log->Printf("** [SBFrame::EvaluateExpression] Expression result is %s, summary %s **",
+ expr_result.GetValue(),
+ expr_result.GetSummary());
+
+ if (log)
+ log->Printf ("SBFrame(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) (execution result=%d)",
+ frame,
+ expr,
+ expr_value_sp.get(),
+ exe_results);
+#endif
+
+ return expr_result;
+}
+
+bool
+SBFrame::IsInlined()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+
+ Block *block = frame->GetSymbolContext(eSymbolContextBlock).block;
+ if (block)
+ return block->GetContainingInlinedBlock () != NULL;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::IsInlined () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::IsInlined () => error: process is running");
+ }
+
+ }
+ return false;
+}
+
+const char *
+SBFrame::GetFunctionName()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *name = NULL;
+ ExecutionContext exe_ctx(m_opaque_sp.get());
+ StackFrame *frame = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ if (target && process)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process->GetRunLock()))
+ {
+ frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ SymbolContext sc (frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol));
+ if (sc.block)
+ {
+ Block *inlined_block = sc.block->GetContainingInlinedBlock ();
+ if (inlined_block)
+ {
+ const InlineFunctionInfo* inlined_info = inlined_block->GetInlinedFunctionInfo();
+ name = inlined_info->GetName().AsCString();
+ }
+ }
+
+ if (name == NULL)
+ {
+ if (sc.function)
+ name = sc.function->GetName().GetCString();
+ }
+
+ if (name == NULL)
+ {
+ if (sc.symbol)
+ name = sc.symbol->GetName().GetCString();
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFunctionName () => error: could not reconstruct frame object for this SBFrame.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBFrame::GetFunctionName() => error: process is running");
+
+ }
+ }
+ return name;
+}
+
diff --git a/source/API/SBFunction.cpp b/source/API/SBFunction.cpp
new file mode 100644
index 000000000000..914d2d77f3ec
--- /dev/null
+++ b/source/API/SBFunction.cpp
@@ -0,0 +1,225 @@
+//===-- SBFunction.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/SBFunction.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBFunction::SBFunction () :
+ m_opaque_ptr (NULL)
+{
+}
+
+SBFunction::SBFunction (lldb_private::Function *lldb_object_ptr) :
+ m_opaque_ptr (lldb_object_ptr)
+{
+}
+
+SBFunction::SBFunction (const lldb::SBFunction &rhs) :
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBFunction &
+SBFunction::operator = (const SBFunction &rhs)
+{
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ return *this;
+}
+
+SBFunction::~SBFunction ()
+{
+ m_opaque_ptr = NULL;
+}
+
+bool
+SBFunction::IsValid () const
+{
+ return m_opaque_ptr != NULL;
+}
+
+const char *
+SBFunction::GetName() const
+{
+ const char *cstr = NULL;
+ if (m_opaque_ptr)
+ cstr = m_opaque_ptr->GetMangled().GetName().AsCString();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBFunction(%p)::GetName () => \"%s\"", m_opaque_ptr, cstr);
+ else
+ log->Printf ("SBFunction(%p)::GetName () => NULL", m_opaque_ptr);
+ }
+ return cstr;
+}
+
+const char *
+SBFunction::GetMangledName () const
+{
+ const char *cstr = NULL;
+ if (m_opaque_ptr)
+ cstr = m_opaque_ptr->GetMangled().GetMangledName().AsCString();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBFunction(%p)::GetMangledName () => \"%s\"", m_opaque_ptr, cstr);
+ else
+ log->Printf ("SBFunction(%p)::GetMangledName () => NULL", m_opaque_ptr);
+ }
+ return cstr;
+}
+
+bool
+SBFunction::operator == (const SBFunction &rhs) const
+{
+ return m_opaque_ptr == rhs.m_opaque_ptr;
+}
+
+bool
+SBFunction::operator != (const SBFunction &rhs) const
+{
+ return m_opaque_ptr != rhs.m_opaque_ptr;
+}
+
+bool
+SBFunction::GetDescription (SBStream &s)
+{
+ if (m_opaque_ptr)
+ {
+ s.Printf ("SBFunction: id = 0x%8.8" PRIx64 ", name = %s",
+ m_opaque_ptr->GetID(),
+ m_opaque_ptr->GetName().AsCString());
+ Type *func_type = m_opaque_ptr->GetType();
+ if (func_type)
+ s.Printf(", type = %s", func_type->GetName().AsCString());
+ return true;
+ }
+ s.Printf ("No value");
+ return false;
+}
+
+SBInstructionList
+SBFunction::GetInstructions (SBTarget target)
+{
+ return GetInstructions (target, NULL);
+}
+
+SBInstructionList
+SBFunction::GetInstructions (SBTarget target, const char *flavor)
+{
+ SBInstructionList sb_instructions;
+ if (m_opaque_ptr)
+ {
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ api_locker.Lock (target_sp->GetAPIMutex());
+ target_sp->CalculateExecutionContext (exe_ctx);
+ exe_ctx.SetProcessSP(target_sp->GetProcessSP());
+ }
+ ModuleSP module_sp (m_opaque_ptr->GetAddressRange().GetBaseAddress().GetModule());
+ if (module_sp)
+ {
+ sb_instructions.SetDisassembler (Disassembler::DisassembleRange (module_sp->GetArchitecture(),
+ NULL,
+ flavor,
+ exe_ctx,
+ m_opaque_ptr->GetAddressRange()));
+ }
+ }
+ return sb_instructions;
+}
+
+lldb_private::Function *
+SBFunction::get ()
+{
+ return m_opaque_ptr;
+}
+
+void
+SBFunction::reset (lldb_private::Function *lldb_object_ptr)
+{
+ m_opaque_ptr = lldb_object_ptr;
+}
+
+SBAddress
+SBFunction::GetStartAddress ()
+{
+ SBAddress addr;
+ if (m_opaque_ptr)
+ addr.SetAddress (&m_opaque_ptr->GetAddressRange().GetBaseAddress());
+ return addr;
+}
+
+SBAddress
+SBFunction::GetEndAddress ()
+{
+ SBAddress addr;
+ if (m_opaque_ptr)
+ {
+ addr_t byte_size = m_opaque_ptr->GetAddressRange().GetByteSize();
+ if (byte_size > 0)
+ {
+ addr.SetAddress (&m_opaque_ptr->GetAddressRange().GetBaseAddress());
+ addr->Slide (byte_size);
+ }
+ }
+ return addr;
+}
+
+
+uint32_t
+SBFunction::GetPrologueByteSize ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetPrologueByteSize();
+ return 0;
+}
+
+SBType
+SBFunction::GetType ()
+{
+ SBType sb_type;
+ if (m_opaque_ptr)
+ {
+ Type *function_type = m_opaque_ptr->GetType();
+ if (function_type)
+ sb_type.ref().SetType (function_type->shared_from_this());
+ }
+ return sb_type;
+}
+
+SBBlock
+SBFunction::GetBlock ()
+{
+ SBBlock sb_block;
+ if (m_opaque_ptr)
+ sb_block.SetPtr (&m_opaque_ptr->GetBlock (true));
+ return sb_block;
+}
+
+
+
diff --git a/source/API/SBHostOS.cpp b/source/API/SBHostOS.cpp
new file mode 100644
index 000000000000..a8f7db90a150
--- /dev/null
+++ b/source/API/SBHostOS.cpp
@@ -0,0 +1,85 @@
+//===-- SBHostOS.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/SBHostOS.h"
+#include "lldb/API/SBError.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBFileSpec
+SBHostOS::GetProgramFileSpec ()
+{
+ SBFileSpec sb_filespec;
+ sb_filespec.SetFileSpec (Host::GetProgramFileSpec ());
+ return sb_filespec;
+}
+
+SBFileSpec
+SBHostOS::GetLLDBPythonPath ()
+{
+ SBFileSpec sb_lldb_python_filespec;
+ FileSpec lldb_python_spec;
+ if (Host::GetLLDBPath (ePathTypePythonDir, lldb_python_spec))
+ {
+ sb_lldb_python_filespec.SetFileSpec (lldb_python_spec);
+ }
+ return sb_lldb_python_filespec;
+}
+
+lldb::thread_t
+SBHostOS::ThreadCreate
+(
+ const char *name,
+ void *(*thread_function)(void *),
+ void *thread_arg,
+ SBError *error_ptr
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBHostOS::ThreadCreate (name=\"%s\", thread_function=%p, thread_arg=%p, error_ptr=%p)", name,
+ thread_function, thread_arg, error_ptr);
+
+ // FIXME: You should log the return value?
+
+ return Host::ThreadCreate (name, thread_function, thread_arg, error_ptr ? error_ptr->get() : NULL);
+}
+
+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);
+}
+
+bool
+SBHostOS::ThreadDetach (lldb::thread_t thread, SBError *error_ptr)
+{
+ return Host::ThreadDetach (thread, error_ptr ? error_ptr->get() : NULL);
+}
+
+bool
+SBHostOS::ThreadJoin (lldb::thread_t thread, void **result, SBError *error_ptr)
+{
+ return Host::ThreadJoin (thread, result, error_ptr ? error_ptr->get() : NULL);
+}
+
+
diff --git a/source/API/SBInputReader.cpp b/source/API/SBInputReader.cpp
new file mode 100644
index 000000000000..82b75c869f08
--- /dev/null
+++ b/source/API/SBInputReader.cpp
@@ -0,0 +1,216 @@
+//===-- SBInputReader.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-enumerations.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBInputReader.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Log.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBInputReader::SBInputReader () :
+ m_opaque_sp (),
+ m_callback_function (NULL),
+ m_callback_baton (NULL)
+
+{
+}
+
+SBInputReader::SBInputReader (const lldb::InputReaderSP &reader_sp) :
+ m_opaque_sp (reader_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBInputReader::SBInputReader (reader_sp=%p) => SBInputReader(%p)", reader_sp.get(),
+ m_opaque_sp.get());
+}
+
+SBInputReader::SBInputReader (const SBInputReader &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf("SBInputReader::SBInputReader (rhs.sp=%p) => SBInputReader(%p)",
+ rhs.m_opaque_sp.get(), m_opaque_sp.get());
+}
+
+SBInputReader::~SBInputReader ()
+{
+}
+
+size_t
+SBInputReader::PrivateCallback
+(
+ void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ SBInputReader *sb_reader = (SBInputReader *)baton;
+ return sb_reader->m_callback_function (sb_reader->m_callback_baton,
+ sb_reader,
+ notification,
+ bytes,
+ bytes_len);
+}
+
+SBError
+SBInputReader::Initialize
+(
+ SBDebugger &debugger,
+ Callback callback_function,
+ void *callback_baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf("SBInputReader(%p)::Initialize (SBDebugger(%p), callback_function=%p, callback_baton=%p, "
+ "granularity=%s, end_token=\"%s\", prompt=\"%s\", echo=%i)",
+ m_opaque_sp.get(),
+ debugger.get(),
+ callback_function,
+ callback_baton,
+ InputReader::GranularityAsCString (granularity), end_token, prompt,
+ echo);
+
+ SBError sb_error;
+ m_opaque_sp.reset (new InputReader (debugger.ref()));
+
+ m_callback_function = callback_function;
+ m_callback_baton = callback_baton;
+
+ if (m_opaque_sp)
+ {
+ sb_error.SetError (m_opaque_sp->Initialize (SBInputReader::PrivateCallback,
+ this,
+ granularity,
+ end_token,
+ prompt,
+ echo));
+ }
+
+ if (sb_error.Fail())
+ {
+ m_opaque_sp.reset ();
+ m_callback_function = NULL;
+ m_callback_baton = NULL;
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBInputReader(%p)::Initialize (...) => SBError(%p): %s", m_opaque_sp.get(),
+ sb_error.get(), sstr.GetData());
+ }
+
+ return sb_error;
+}
+
+bool
+SBInputReader::IsValid () const
+{
+ return (m_opaque_sp.get() != NULL);
+}
+
+const SBInputReader &
+SBInputReader::operator = (const SBInputReader &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+InputReader *
+SBInputReader::operator->() const
+{
+ return m_opaque_sp.get();
+}
+
+lldb::InputReaderSP &
+SBInputReader::operator *()
+{
+ return m_opaque_sp;
+}
+
+const lldb::InputReaderSP &
+SBInputReader::operator *() const
+{
+ return m_opaque_sp;
+}
+
+InputReader *
+SBInputReader::get() const
+{
+ return m_opaque_sp.get();
+}
+
+InputReader &
+SBInputReader::ref() const
+{
+ assert (m_opaque_sp.get());
+ return *m_opaque_sp;
+}
+
+bool
+SBInputReader::IsDone () const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->IsDone();
+ else
+ return true;
+}
+
+void
+SBInputReader::SetIsDone (bool value)
+{
+ if (m_opaque_sp)
+ m_opaque_sp->SetIsDone (value);
+}
+
+bool
+SBInputReader::IsActive () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool ret_value = false;
+ if (m_opaque_sp)
+ ret_value = m_opaque_sp->IsActive();
+
+ if (log)
+ log->Printf ("SBInputReader(%p)::IsActive () => %i", m_opaque_sp.get(), ret_value);
+
+ return ret_value;
+}
+
+InputReaderGranularity
+SBInputReader::GetGranularity ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetGranularity();
+ else
+ return eInputReaderGranularityInvalid;
+}
diff --git a/source/API/SBInstruction.cpp b/source/API/SBInstruction.cpp
new file mode 100644
index 000000000000..2334cc0d124a
--- /dev/null
+++ b/source/API/SBInstruction.cpp
@@ -0,0 +1,248 @@
+//===-- SBInstruction.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/SBInstruction.h"
+
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBInstruction::SBInstruction ()
+{
+}
+
+SBInstruction::SBInstruction (const lldb::InstructionSP& inst_sp) :
+ m_opaque_sp (inst_sp)
+{
+}
+
+SBInstruction::SBInstruction(const SBInstruction &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBInstruction &
+SBInstruction::operator = (const SBInstruction &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+SBInstruction::~SBInstruction ()
+{
+}
+
+bool
+SBInstruction::IsValid()
+{
+ return (m_opaque_sp.get() != NULL);
+}
+
+SBAddress
+SBInstruction::GetAddress()
+{
+ SBAddress sb_addr;
+ if (m_opaque_sp && m_opaque_sp->GetAddress().IsValid())
+ sb_addr.SetAddress(&m_opaque_sp->GetAddress());
+ return sb_addr;
+}
+
+const char *
+SBInstruction::GetMnemonic(SBTarget target)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ api_locker.Lock (target_sp->GetAPIMutex());
+ target_sp->CalculateExecutionContext (exe_ctx);
+ exe_ctx.SetProcessSP(target_sp->GetProcessSP());
+ }
+ return m_opaque_sp->GetMnemonic(&exe_ctx);
+ }
+ return NULL;
+}
+
+const char *
+SBInstruction::GetOperands(SBTarget target)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ api_locker.Lock (target_sp->GetAPIMutex());
+ target_sp->CalculateExecutionContext (exe_ctx);
+ exe_ctx.SetProcessSP(target_sp->GetProcessSP());
+ }
+ return m_opaque_sp->GetOperands(&exe_ctx);
+ }
+ return NULL;
+}
+
+const char *
+SBInstruction::GetComment(SBTarget target)
+{
+ if (m_opaque_sp)
+ {
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ api_locker.Lock (target_sp->GetAPIMutex());
+ target_sp->CalculateExecutionContext (exe_ctx);
+ exe_ctx.SetProcessSP(target_sp->GetProcessSP());
+ }
+ return m_opaque_sp->GetComment(&exe_ctx);
+ }
+ return NULL;
+}
+
+size_t
+SBInstruction::GetByteSize ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetOpcode().GetByteSize();
+ return 0;
+}
+
+SBData
+SBInstruction::GetData (SBTarget target)
+{
+ lldb::SBData sb_data;
+ if (m_opaque_sp)
+ {
+ DataExtractorSP data_extractor_sp (new DataExtractor());
+ if (m_opaque_sp->GetData (*data_extractor_sp))
+ {
+ sb_data.SetOpaque (data_extractor_sp);
+ }
+ }
+ return sb_data;
+}
+
+
+
+bool
+SBInstruction::DoesBranch ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->DoesBranch ();
+ return false;
+}
+
+void
+SBInstruction::SetOpaque (const lldb::InstructionSP &inst_sp)
+{
+ m_opaque_sp = inst_sp;
+}
+
+bool
+SBInstruction::GetDescription (lldb::SBStream &s)
+{
+ if (m_opaque_sp)
+ {
+ // 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);
+ return true;
+ }
+ return false;
+}
+
+void
+SBInstruction::Print (FILE *out)
+{
+ if (out == NULL)
+ return;
+
+ if (m_opaque_sp)
+ {
+ StreamFile out_stream (out, false);
+ m_opaque_sp->Dump (&out_stream, 0, true, false, NULL);
+ }
+}
+
+bool
+SBInstruction::EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options)
+{
+ if (m_opaque_sp)
+ {
+ lldb::StackFrameSP frame_sp (frame.GetFrameSP());
+
+ if (frame_sp)
+ {
+ lldb_private::ExecutionContext exe_ctx;
+ frame_sp->CalculateExecutionContext (exe_ctx);
+ lldb_private::Target *target = exe_ctx.GetTargetPtr();
+ lldb_private::ArchSpec arch = target->GetArchitecture();
+
+ return m_opaque_sp->Emulate (arch,
+ evaluate_options,
+ (void *) frame_sp.get(),
+ &lldb_private::EmulateInstruction::ReadMemoryFrame,
+ &lldb_private::EmulateInstruction::WriteMemoryFrame,
+ &lldb_private::EmulateInstruction::ReadRegisterFrame,
+ &lldb_private::EmulateInstruction::WriteRegisterFrame);
+ }
+ }
+ return false;
+}
+
+bool
+SBInstruction::DumpEmulation (const char *triple)
+{
+ if (m_opaque_sp && triple)
+ {
+ lldb_private::ArchSpec arch (triple, NULL);
+
+ return m_opaque_sp->DumpEmulation (arch);
+
+ }
+ return false;
+}
+
+bool
+SBInstruction::TestEmulation (lldb::SBStream &output_stream, const char *test_file)
+{
+ if (!m_opaque_sp.get())
+ m_opaque_sp.reset (new PseudoInstruction());
+
+ return m_opaque_sp->TestEmulation (output_stream.get(), test_file);
+}
+
+lldb::AddressClass
+SBInstruction::GetAddressClass ()
+{
+ if (m_opaque_sp.get())
+ return m_opaque_sp->GetAddressClass();
+ return eAddressClassInvalid;
+}
diff --git a/source/API/SBInstructionList.cpp b/source/API/SBInstructionList.cpp
new file mode 100644
index 000000000000..fe22d9c29e4a
--- /dev/null
+++ b/source/API/SBInstructionList.cpp
@@ -0,0 +1,132 @@
+//===-- SBInstructionList.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/SBInstructionList.h"
+#include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBInstructionList::SBInstructionList () :
+ m_opaque_sp()
+{
+}
+
+SBInstructionList::SBInstructionList(const SBInstructionList &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBInstructionList &
+SBInstructionList::operator = (const SBInstructionList &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+
+SBInstructionList::~SBInstructionList ()
+{
+}
+
+bool
+SBInstructionList::IsValid () const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+size_t
+SBInstructionList::GetSize ()
+{
+ if (m_opaque_sp)
+ return m_opaque_sp->GetInstructionList().GetSize();
+ return 0;
+}
+
+SBInstruction
+SBInstructionList::GetInstructionAtIndex (uint32_t idx)
+{
+ SBInstruction inst;
+ if (m_opaque_sp && idx < m_opaque_sp->GetInstructionList().GetSize())
+ inst.SetOpaque (m_opaque_sp->GetInstructionList().GetInstructionAtIndex (idx));
+ return inst;
+}
+
+void
+SBInstructionList::Clear ()
+{
+ m_opaque_sp.reset();
+}
+
+void
+SBInstructionList::AppendInstruction (SBInstruction insn)
+{
+}
+
+void
+SBInstructionList::SetDisassembler (const lldb::DisassemblerSP &opaque_sp)
+{
+ m_opaque_sp = opaque_sp;
+}
+
+void
+SBInstructionList::Print (FILE *out)
+{
+ if (out == NULL)
+ return;
+}
+
+
+bool
+SBInstructionList::GetDescription (lldb::SBStream &description)
+{
+ if (m_opaque_sp)
+ {
+ size_t num_instructions = GetSize ();
+ if (num_instructions)
+ {
+ // Call the ref() to make sure a stream is created if one deesn't
+ // exist already inside description...
+ Stream &sref = description.ref();
+ const uint32_t max_opcode_byte_size = m_opaque_sp->GetInstructionList().GetMaxOpcocdeByteSize();
+ 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);
+ sref.EOL();
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+SBInstructionList::DumpEmulationForAllInstructions (const char *triple)
+{
+ if (m_opaque_sp)
+ {
+ size_t len = GetSize();
+ for (size_t i = 0; i < len; ++i)
+ {
+ if (!GetInstructionAtIndex((uint32_t) i).DumpEmulation (triple))
+ return false;
+ }
+ }
+ return true;
+}
+
diff --git a/source/API/SBLineEntry.cpp b/source/API/SBLineEntry.cpp
new file mode 100644
index 000000000000..0864a2e006c3
--- /dev/null
+++ b/source/API/SBLineEntry.cpp
@@ -0,0 +1,250 @@
+//===-- SBLineEntry.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <limits.h>
+
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/LineEntry.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBLineEntry::SBLineEntry () :
+ m_opaque_ap ()
+{
+}
+
+SBLineEntry::SBLineEntry (const SBLineEntry &rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+}
+
+SBLineEntry::SBLineEntry (const lldb_private::LineEntry *lldb_object_ptr) :
+ m_opaque_ap ()
+{
+ if (lldb_object_ptr)
+ ref() = *lldb_object_ptr;
+}
+
+const SBLineEntry &
+SBLineEntry::operator = (const SBLineEntry &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ ref() = rhs.ref();
+ else
+ m_opaque_ap.reset();
+ }
+ return *this;
+}
+
+void
+SBLineEntry::SetLineEntry (const lldb_private::LineEntry &lldb_object_ref)
+{
+ ref() = lldb_object_ref;
+}
+
+
+SBLineEntry::~SBLineEntry ()
+{
+}
+
+
+SBAddress
+SBLineEntry::GetStartAddress () const
+{
+
+ SBAddress sb_address;
+ if (m_opaque_ap.get())
+ sb_address.SetAddress(&m_opaque_ap->range.GetBaseAddress());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ StreamString sstr;
+ const Address *addr = sb_address.get();
+ if (addr)
+ addr->Dump (&sstr, NULL, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleInvalid, 4);
+ log->Printf ("SBLineEntry(%p)::GetStartAddress () => SBAddress (%p): %s",
+ m_opaque_ap.get(), sb_address.get(), sstr.GetData());
+ }
+
+ return sb_address;
+}
+
+SBAddress
+SBLineEntry::GetEndAddress () const
+{
+ SBAddress sb_address;
+ if (m_opaque_ap.get())
+ {
+ sb_address.SetAddress(&m_opaque_ap->range.GetBaseAddress());
+ sb_address.OffsetAddress(m_opaque_ap->range.GetByteSize());
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ StreamString sstr;
+ const Address *addr = sb_address.get();
+ if (addr)
+ addr->Dump (&sstr, NULL, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleInvalid, 4);
+ log->Printf ("SBLineEntry(%p)::GetEndAddress () => SBAddress (%p): %s",
+ m_opaque_ap.get(), sb_address.get(), sstr.GetData());
+ }
+ return sb_address;
+}
+
+bool
+SBLineEntry::IsValid () const
+{
+ return m_opaque_ap.get() && m_opaque_ap->IsValid();
+}
+
+
+SBFileSpec
+SBLineEntry::GetFileSpec () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFileSpec sb_file_spec;
+ if (m_opaque_ap.get() && m_opaque_ap->file)
+ sb_file_spec.SetFileSpec(m_opaque_ap->file);
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_file_spec.GetDescription (sstr);
+ log->Printf ("SBLineEntry(%p)::GetFileSpec () => SBFileSpec(%p): %s", m_opaque_ap.get(),
+ sb_file_spec.get(), sstr.GetData());
+ }
+
+ return sb_file_spec;
+}
+
+uint32_t
+SBLineEntry::GetLine () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t line = 0;
+ if (m_opaque_ap.get())
+ line = m_opaque_ap->line;
+
+ if (log)
+ log->Printf ("SBLineEntry(%p)::GetLine () => %u", m_opaque_ap.get(), line);
+
+ return line;
+}
+
+
+uint32_t
+SBLineEntry::GetColumn () const
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->column;
+ return 0;
+}
+
+void
+SBLineEntry::SetFileSpec (lldb::SBFileSpec filespec)
+{
+ if (filespec.IsValid())
+ ref().file = filespec.ref();
+ else
+ ref().file.Clear();
+}
+void
+SBLineEntry::SetLine (uint32_t line)
+{
+ ref().line = line;
+}
+
+void
+SBLineEntry::SetColumn (uint32_t column)
+{
+ ref().line = column;
+}
+
+
+
+bool
+SBLineEntry::operator == (const SBLineEntry &rhs) const
+{
+ lldb_private::LineEntry *lhs_ptr = m_opaque_ap.get();
+ lldb_private::LineEntry *rhs_ptr = rhs.m_opaque_ap.get();
+
+ if (lhs_ptr && rhs_ptr)
+ return lldb_private::LineEntry::Compare (*lhs_ptr, *rhs_ptr) == 0;
+
+ return lhs_ptr == rhs_ptr;
+}
+
+bool
+SBLineEntry::operator != (const SBLineEntry &rhs) const
+{
+ lldb_private::LineEntry *lhs_ptr = m_opaque_ap.get();
+ lldb_private::LineEntry *rhs_ptr = rhs.m_opaque_ap.get();
+
+ if (lhs_ptr && rhs_ptr)
+ return lldb_private::LineEntry::Compare (*lhs_ptr, *rhs_ptr) != 0;
+
+ return lhs_ptr != rhs_ptr;
+}
+
+const lldb_private::LineEntry *
+SBLineEntry::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::LineEntry &
+SBLineEntry::ref()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new lldb_private::LineEntry ());
+ return *m_opaque_ap;
+}
+
+const lldb_private::LineEntry &
+SBLineEntry::ref() const
+{
+ return *m_opaque_ap;
+}
+
+bool
+SBLineEntry::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ char file_path[PATH_MAX*2];
+ m_opaque_ap->file.GetPath (file_path, sizeof (file_path));
+ strm.Printf ("%s:%u", file_path, GetLine());
+ if (GetColumn() > 0)
+ strm.Printf (":%u", GetColumn());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+lldb_private::LineEntry *
+SBLineEntry::get ()
+{
+ return m_opaque_ap.get();
+}
diff --git a/source/API/SBListener.cpp b/source/API/SBListener.cpp
new file mode 100644
index 000000000000..2e67b4c24e86
--- /dev/null
+++ b/source/API/SBListener.cpp
@@ -0,0 +1,443 @@
+//===-- SBListener.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/SBListener.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/TimeValue.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBListener::SBListener () :
+ m_opaque_sp (),
+ m_opaque_ptr (NULL)
+{
+}
+
+SBListener::SBListener (const char *name) :
+ m_opaque_sp (new Listener (name)),
+ m_opaque_ptr (NULL)
+{
+ m_opaque_ptr = m_opaque_sp.get();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBListener::SBListener (name=\"%s\") => SBListener(%p)",
+ name, m_opaque_ptr);
+}
+
+
+SBListener::SBListener (const SBListener &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp),
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const lldb::SBListener &
+SBListener::operator = (const lldb::SBListener &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ }
+ return *this;
+}
+
+SBListener::SBListener (Listener &listener) :
+ m_opaque_sp (),
+ m_opaque_ptr (&listener)
+{
+}
+
+SBListener::~SBListener ()
+{
+}
+
+bool
+SBListener::IsValid() const
+{
+ return m_opaque_ptr != NULL;
+}
+
+void
+SBListener::AddEvent (const SBEvent &event)
+{
+ EventSP &event_sp = event.GetSP ();
+ if (event_sp)
+ m_opaque_ptr->AddEvent (event_sp);
+}
+
+void
+SBListener::Clear ()
+{
+ if (m_opaque_ptr)
+ m_opaque_ptr->Clear ();
+}
+
+uint32_t
+SBListener::StartListeningForEventClass (SBDebugger &debugger,
+ const char *broadcaster_class,
+ uint32_t event_mask)
+{
+ if (m_opaque_ptr)
+ {
+ Debugger *lldb_debugger = debugger.get();
+ if (!lldb_debugger)
+ return 0;
+ BroadcastEventSpec event_spec (ConstString (broadcaster_class), event_mask);
+ return m_opaque_ptr->StartListeningForEventSpec (*lldb_debugger, event_spec);
+ }
+ else
+ return 0;
+}
+
+bool
+SBListener::StopListeningForEventClass (SBDebugger &debugger,
+ const char *broadcaster_class,
+ uint32_t event_mask)
+{
+ if (m_opaque_ptr)
+ {
+ Debugger *lldb_debugger = debugger.get();
+ if (!lldb_debugger)
+ return false;
+ BroadcastEventSpec event_spec (ConstString (broadcaster_class), event_mask);
+ return m_opaque_ptr->StopListeningForEventSpec (*lldb_debugger, event_spec);
+ }
+ else
+ return false;
+}
+
+uint32_t
+SBListener::StartListeningForEvents (const SBBroadcaster& broadcaster, uint32_t event_mask)
+{
+ uint32_t acquired_event_mask = 0;
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ acquired_event_mask = m_opaque_ptr->StartListeningForEvents (broadcaster.get(), event_mask);
+ }
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
+ if (log)
+ {
+ StreamString sstr_requested;
+ StreamString sstr_acquired;
+
+ Broadcaster *lldb_broadcaster = broadcaster.get();
+ if (lldb_broadcaster)
+ {
+ const bool got_requested_names = lldb_broadcaster->GetEventNames (sstr_requested, event_mask, false);
+ const bool got_acquired_names = lldb_broadcaster->GetEventNames (sstr_acquired, acquired_event_mask, false);
+ log->Printf ("SBListener(%p)::StartListeneingForEvents (SBBroadcaster(%p): %s, event_mask=0x%8.8x%s%s%s) => 0x%8.8x%s%s%s",
+ m_opaque_ptr,
+ lldb_broadcaster,
+ lldb_broadcaster->GetBroadcasterName().GetCString(),
+ event_mask,
+ got_requested_names ? " (" : "",
+ sstr_requested.GetData(),
+ got_requested_names ? ")" : "",
+ acquired_event_mask,
+ got_acquired_names ? " (" : "",
+ sstr_acquired.GetData(),
+ got_acquired_names ? ")" : "");
+ }
+ else
+ {
+ log->Printf ("SBListener(%p)::StartListeneingForEvents (SBBroadcaster(%p), event_mask=0x%8.8x) => 0x%8.8x",
+ m_opaque_ptr,
+ lldb_broadcaster,
+ event_mask,
+ acquired_event_mask);
+
+ }
+ }
+
+ return acquired_event_mask;
+}
+
+bool
+SBListener::StopListeningForEvents (const SBBroadcaster& broadcaster, uint32_t event_mask)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ return m_opaque_ptr->StopListeningForEvents (broadcaster.get(), event_mask);
+ }
+ return false;
+}
+
+bool
+SBListener::WaitForEvent (uint32_t timeout_secs, SBEvent &event)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (timeout_secs == UINT32_MAX)
+ {
+ log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=INFINITE, SBEvent(%p))...",
+ m_opaque_ptr, event.get());
+ }
+ else
+ {
+ log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=%d, SBEvent(%p))...",
+ m_opaque_ptr, timeout_secs, event.get());
+ }
+ }
+ bool success = false;
+
+ if (m_opaque_ptr)
+ {
+ TimeValue time_value;
+ if (timeout_secs != UINT32_MAX)
+ {
+ assert (timeout_secs != 0); // Take this out after all calls with timeout set to zero have been removed....
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (timeout_secs);
+ }
+ EventSP event_sp;
+ if (m_opaque_ptr->WaitForEvent (time_value.IsValid() ? &time_value : NULL, event_sp))
+ {
+ event.reset (event_sp);
+ success = true;
+ }
+ }
+
+ if (log)
+ {
+ if (timeout_secs == UINT32_MAX)
+ {
+ log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=INFINITE, SBEvent(%p)) => %i",
+ m_opaque_ptr, event.get(), success);
+ }
+ else
+ {
+ log->Printf ("SBListener(%p)::WaitForEvent (timeout_secs=%d, SBEvent(%p)) => %i",
+ m_opaque_ptr, timeout_secs, event.get(), success);
+ }
+ }
+ if (!success)
+ event.reset (NULL);
+ return success;
+}
+
+bool
+SBListener::WaitForEventForBroadcaster
+(
+ uint32_t num_seconds,
+ const SBBroadcaster &broadcaster,
+ SBEvent &event
+)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ TimeValue time_value;
+ if (num_seconds != UINT32_MAX)
+ {
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (num_seconds);
+ }
+ EventSP event_sp;
+ if (m_opaque_ptr->WaitForEventForBroadcaster (time_value.IsValid() ? &time_value : NULL,
+ broadcaster.get(),
+ event_sp))
+ {
+ event.reset (event_sp);
+ return true;
+ }
+
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::WaitForEventForBroadcasterWithType
+(
+ uint32_t num_seconds,
+ const SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ SBEvent &event
+)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ TimeValue time_value;
+ if (num_seconds != UINT32_MAX)
+ {
+ time_value = TimeValue::Now();
+ time_value.OffsetWithSeconds (num_seconds);
+ }
+ EventSP event_sp;
+ if (m_opaque_ptr->WaitForEventForBroadcasterWithType (time_value.IsValid() ? &time_value : NULL,
+ broadcaster.get(),
+ event_type_mask,
+ event_sp))
+ {
+ event.reset (event_sp);
+ return true;
+ }
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEvent (SBEvent &event)
+{
+ if (m_opaque_ptr)
+ {
+ event.reset (m_opaque_ptr->PeekAtNextEvent ());
+ return event.IsValid();
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEventForBroadcaster (const SBBroadcaster &broadcaster, SBEvent &event)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ event.reset (m_opaque_ptr->PeekAtNextEventForBroadcaster (broadcaster.get()));
+ return event.IsValid();
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::PeekAtNextEventForBroadcasterWithType (const SBBroadcaster &broadcaster, uint32_t event_type_mask,
+ SBEvent &event)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ event.reset(m_opaque_ptr->PeekAtNextEventForBroadcasterWithType (broadcaster.get(), event_type_mask));
+ return event.IsValid();
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEvent (SBEvent &event)
+{
+ if (m_opaque_ptr)
+ {
+ EventSP event_sp;
+ if (m_opaque_ptr->GetNextEvent (event_sp))
+ {
+ event.reset (event_sp);
+ return true;
+ }
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEventForBroadcaster (const SBBroadcaster &broadcaster, SBEvent &event)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ EventSP event_sp;
+ if (m_opaque_ptr->GetNextEventForBroadcaster (broadcaster.get(), event_sp))
+ {
+ event.reset (event_sp);
+ return true;
+ }
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::GetNextEventForBroadcasterWithType
+(
+ const SBBroadcaster &broadcaster,
+ uint32_t event_type_mask,
+ SBEvent &event
+)
+{
+ if (m_opaque_ptr && broadcaster.IsValid())
+ {
+ EventSP event_sp;
+ if (m_opaque_ptr->GetNextEventForBroadcasterWithType (broadcaster.get(),
+ event_type_mask,
+ event_sp))
+ {
+ event.reset (event_sp);
+ return true;
+ }
+ }
+ event.reset (NULL);
+ return false;
+}
+
+bool
+SBListener::HandleBroadcastEvent (const SBEvent &event)
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->HandleBroadcastEvent (event.GetSP());
+ return false;
+}
+
+Listener *
+SBListener::operator->() const
+{
+ return m_opaque_ptr;
+}
+
+Listener *
+SBListener::get() const
+{
+ return m_opaque_ptr;
+}
+
+void
+SBListener::reset(Listener *listener, bool owns)
+{
+ if (owns)
+ m_opaque_sp.reset (listener);
+ else
+ m_opaque_sp.reset ();
+ m_opaque_ptr = listener;
+}
+
+Listener &
+SBListener::ref() const
+{
+ return *m_opaque_ptr;
+}
+
+Listener &
+SBListener::operator *()
+{
+ return *m_opaque_ptr;
+}
+
+const Listener &
+SBListener::operator *() const
+{
+ return *m_opaque_ptr;
+}
+
+
diff --git a/source/API/SBModule.cpp b/source/API/SBModule.cpp
new file mode 100644
index 000000000000..5f5fc9292cdb
--- /dev/null
+++ b/source/API/SBModule.cpp
@@ -0,0 +1,655 @@
+//===-- SBModule.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/SBModule.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBModuleSpec.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBSymbolContextList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBModule::SBModule () :
+ m_opaque_sp ()
+{
+}
+
+SBModule::SBModule (const lldb::ModuleSP& module_sp) :
+ m_opaque_sp (module_sp)
+{
+}
+
+SBModule::SBModule(const SBModuleSpec &module_spec) :
+ m_opaque_sp ()
+{
+ ModuleSP module_sp;
+ Error error = ModuleList::GetSharedModule (*module_spec.m_opaque_ap,
+ module_sp,
+ NULL,
+ NULL,
+ NULL);
+ if (module_sp)
+ SetSP(module_sp);
+}
+
+SBModule::SBModule(const SBModule &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+SBModule::SBModule (lldb::SBProcess &process, lldb::addr_t header_addr) :
+ m_opaque_sp ()
+{
+ ProcessSP process_sp (process.GetSP());
+ if (process_sp)
+ {
+ m_opaque_sp = process_sp->ReadModuleFromMemory (FileSpec(), header_addr);
+ if (m_opaque_sp)
+ {
+ Target &target = process_sp->GetTarget();
+ bool changed = false;
+ m_opaque_sp->SetLoadAddress(target, 0, changed);
+ target.GetImages().Append(m_opaque_sp);
+ }
+ }
+}
+
+const SBModule &
+SBModule::operator = (const SBModule &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+SBModule::~SBModule ()
+{
+}
+
+bool
+SBModule::IsValid () const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+void
+SBModule::Clear()
+{
+ m_opaque_sp.reset();
+}
+
+SBFileSpec
+SBModule::GetFileSpec () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFileSpec file_spec;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ file_spec.SetFileSpec(module_sp->GetFileSpec());
+
+ if (log)
+ {
+ log->Printf ("SBModule(%p)::GetFileSpec () => SBFileSpec(%p)",
+ module_sp.get(), file_spec.get());
+ }
+
+ return file_spec;
+}
+
+lldb::SBFileSpec
+SBModule::GetPlatformFileSpec () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFileSpec file_spec;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ file_spec.SetFileSpec(module_sp->GetPlatformFileSpec());
+
+ if (log)
+ {
+ log->Printf ("SBModule(%p)::GetPlatformFileSpec () => SBFileSpec(%p)",
+ module_sp.get(), file_spec.get());
+ }
+
+ return file_spec;
+
+}
+
+bool
+SBModule::SetPlatformFileSpec (const lldb::SBFileSpec &platform_file)
+{
+ bool result = false;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ module_sp->SetPlatformFileSpec(*platform_file);
+ result = true;
+ }
+
+ if (log)
+ {
+ log->Printf ("SBModule(%p)::SetPlatformFileSpec (SBFileSpec(%p (%s)) => %i",
+ module_sp.get(),
+ platform_file.get(),
+ platform_file->GetPath().c_str(),
+ result);
+ }
+ return result;
+}
+
+
+
+const uint8_t *
+SBModule::GetUUIDBytes () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const uint8_t *uuid_bytes = NULL;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ uuid_bytes = (const uint8_t *)module_sp->GetUUID().GetBytes();
+
+ if (log)
+ {
+ if (uuid_bytes)
+ {
+ StreamString s;
+ module_sp->GetUUID().Dump (&s);
+ log->Printf ("SBModule(%p)::GetUUIDBytes () => %s", module_sp.get(), s.GetData());
+ }
+ else
+ log->Printf ("SBModule(%p)::GetUUIDBytes () => NULL", module_sp.get());
+ }
+ return uuid_bytes;
+}
+
+
+const char *
+SBModule::GetUUIDString () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ static char uuid_string_buffer[80];
+ const char *uuid_c_string = NULL;
+ std::string uuid_string;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ uuid_string = module_sp->GetUUID().GetAsString();
+
+ if (!uuid_string.empty())
+ {
+ strncpy (uuid_string_buffer, uuid_string.c_str(), sizeof (uuid_string_buffer));
+ uuid_c_string = uuid_string_buffer;
+ }
+
+ if (log)
+ {
+ if (!uuid_string.empty())
+ {
+ StreamString s;
+ module_sp->GetUUID().Dump (&s);
+ log->Printf ("SBModule(%p)::GetUUIDString () => %s", module_sp.get(), s.GetData());
+ }
+ else
+ log->Printf ("SBModule(%p)::GetUUIDString () => NULL", module_sp.get());
+ }
+ return uuid_c_string;
+}
+
+
+bool
+SBModule::operator == (const SBModule &rhs) const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp.get() == rhs.m_opaque_sp.get();
+ return false;
+}
+
+bool
+SBModule::operator != (const SBModule &rhs) const
+{
+ if (m_opaque_sp)
+ return m_opaque_sp.get() != rhs.m_opaque_sp.get();
+ return false;
+}
+
+ModuleSP
+SBModule::GetSP () const
+{
+ return m_opaque_sp;
+}
+
+void
+SBModule::SetSP (const ModuleSP &module_sp)
+{
+ m_opaque_sp = module_sp;
+}
+
+SBAddress
+SBModule::ResolveFileAddress (lldb::addr_t vm_addr)
+{
+ lldb::SBAddress sb_addr;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ Address addr;
+ if (module_sp->ResolveFileAddress (vm_addr, addr))
+ sb_addr.ref() = addr;
+ }
+ return sb_addr;
+}
+
+SBSymbolContext
+SBModule::ResolveSymbolContextForAddress (const SBAddress& addr, uint32_t resolve_scope)
+{
+ SBSymbolContext sb_sc;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp && addr.IsValid())
+ module_sp->ResolveSymbolContextForAddress (addr.ref(), resolve_scope, *sb_sc);
+ return sb_sc;
+}
+
+bool
+SBModule::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ module_sp->GetDescription (&strm);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+uint32_t
+SBModule::GetNumCompileUnits()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ return module_sp->GetNumCompileUnits ();
+ }
+ return 0;
+}
+
+SBCompileUnit
+SBModule::GetCompileUnitAtIndex (uint32_t index)
+{
+ SBCompileUnit sb_cu;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex (index);
+ sb_cu.reset(cu_sp.get());
+ }
+ return sb_cu;
+}
+
+static Symtab *
+GetUnifiedSymbolTable (const lldb::ModuleSP& module_sp)
+{
+ if (module_sp)
+ {
+ SymbolVendor *symbols = module_sp->GetSymbolVendor();
+ if (symbols)
+ return symbols->GetSymtab();
+ }
+ return NULL;
+}
+
+size_t
+SBModule::GetNumSymbols ()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ Symtab *symtab = GetUnifiedSymbolTable (module_sp);
+ if (symtab)
+ return symtab->GetNumSymbols();
+ }
+ return 0;
+}
+
+SBSymbol
+SBModule::GetSymbolAtIndex (size_t idx)
+{
+ SBSymbol sb_symbol;
+ ModuleSP module_sp (GetSP ());
+ Symtab *symtab = GetUnifiedSymbolTable (module_sp);
+ if (symtab)
+ sb_symbol.SetSymbol(symtab->SymbolAtIndex (idx));
+ return sb_symbol;
+}
+
+lldb::SBSymbol
+SBModule::FindSymbol (const char *name,
+ lldb::SymbolType symbol_type)
+{
+ SBSymbol sb_symbol;
+ if (name && name[0])
+ {
+ ModuleSP module_sp (GetSP ());
+ Symtab *symtab = GetUnifiedSymbolTable (module_sp);
+ if (symtab)
+ sb_symbol.SetSymbol(symtab->FindFirstSymbolWithNameAndType(ConstString(name), symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny));
+ }
+ return sb_symbol;
+}
+
+
+lldb::SBSymbolContextList
+SBModule::FindSymbols (const char *name, lldb::SymbolType symbol_type)
+{
+ SBSymbolContextList sb_sc_list;
+ if (name && name[0])
+ {
+ ModuleSP module_sp (GetSP ());
+ Symtab *symtab = GetUnifiedSymbolTable (module_sp);
+ if (symtab)
+ {
+ std::vector<uint32_t> matching_symbol_indexes;
+ const size_t num_matches = symtab->FindAllSymbolsWithNameAndType(ConstString(name), symbol_type, matching_symbol_indexes);
+ if (num_matches)
+ {
+ SymbolContext sc;
+ sc.module_sp = module_sp;
+ SymbolContextList &sc_list = *sb_sc_list;
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ sc.symbol = symtab->SymbolAtIndex (matching_symbol_indexes[i]);
+ if (sc.symbol)
+ sc_list.Append(sc);
+ }
+ }
+ }
+ }
+ return sb_sc_list;
+
+}
+
+
+
+size_t
+SBModule::GetNumSections ()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ // Give the symbol vendor a chance to add to the unified section list.
+ module_sp->GetSymbolVendor();
+ SectionList *section_list = module_sp->GetSectionList();
+ if (section_list)
+ return section_list->GetSize();
+ }
+ return 0;
+}
+
+SBSection
+SBModule::GetSectionAtIndex (size_t idx)
+{
+ SBSection sb_section;
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ // Give the symbol vendor a chance to add to the unified section list.
+ module_sp->GetSymbolVendor();
+ SectionList *section_list = module_sp->GetSectionList ();
+
+ if (section_list)
+ sb_section.SetSP(section_list->GetSectionAtIndex (idx));
+ }
+ return sb_section;
+}
+
+lldb::SBSymbolContextList
+SBModule::FindFunctions (const char *name,
+ uint32_t name_type_mask)
+{
+ lldb::SBSymbolContextList sb_sc_list;
+ ModuleSP module_sp (GetSP ());
+ if (name && module_sp)
+ {
+ const bool append = true;
+ const bool symbols_ok = true;
+ const bool inlines_ok = true;
+ module_sp->FindFunctions (ConstString(name),
+ NULL,
+ name_type_mask,
+ symbols_ok,
+ inlines_ok,
+ append,
+ *sb_sc_list);
+ }
+ return sb_sc_list;
+}
+
+
+SBValueList
+SBModule::FindGlobalVariables (SBTarget &target, const char *name, uint32_t max_matches)
+{
+ SBValueList sb_value_list;
+ ModuleSP module_sp (GetSP ());
+ if (name && module_sp)
+ {
+ VariableList variable_list;
+ const uint32_t match_count = module_sp->FindGlobalVariables (ConstString (name),
+ NULL,
+ false,
+ max_matches,
+ variable_list);
+
+ if (match_count > 0)
+ {
+ for (uint32_t i=0; i<match_count; ++i)
+ {
+ lldb::ValueObjectSP valobj_sp;
+ TargetSP target_sp (target.GetSP());
+ valobj_sp = ValueObjectVariable::Create (target_sp.get(), variable_list.GetVariableAtIndex(i));
+ if (valobj_sp)
+ sb_value_list.Append(SBValue(valobj_sp));
+ }
+ }
+ }
+
+ return sb_value_list;
+}
+
+lldb::SBValue
+SBModule::FindFirstGlobalVariable (lldb::SBTarget &target, const char *name)
+{
+ SBValueList sb_value_list(FindGlobalVariables(target, name, 1));
+ if (sb_value_list.IsValid() && sb_value_list.GetSize() > 0)
+ return sb_value_list.GetValueAtIndex(0);
+ return SBValue();
+}
+
+lldb::SBType
+SBModule::FindFirstType (const char *name_cstr)
+{
+ SBType sb_type;
+ ModuleSP module_sp (GetSP ());
+ if (name_cstr && module_sp)
+ {
+ SymbolContext sc;
+ const bool exact_match = false;
+ ConstString name(name_cstr);
+
+ sb_type = SBType (module_sp->FindFirstType(sc, name, exact_match));
+
+ if (!sb_type.IsValid())
+ sb_type = SBType (ClangASTContext::GetBasicType (module_sp->GetClangASTContext().getASTContext(), name));
+ }
+ return sb_type;
+}
+
+lldb::SBType
+SBModule::GetBasicType(lldb::BasicType type)
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ return SBType (ClangASTContext::GetBasicType (module_sp->GetClangASTContext().getASTContext(), type));
+ return SBType();
+}
+
+lldb::SBTypeList
+SBModule::FindTypes (const char *type)
+{
+ SBTypeList retval;
+
+ ModuleSP module_sp (GetSP ());
+ if (type && module_sp)
+ {
+ SymbolContext sc;
+ TypeList type_list;
+ const bool exact_match = false;
+ ConstString name(type);
+ const uint32_t num_matches = module_sp->FindTypes (sc,
+ name,
+ exact_match,
+ UINT32_MAX,
+ type_list);
+
+ if (num_matches > 0)
+ {
+ for (size_t idx = 0; idx < num_matches; idx++)
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(idx));
+ if (type_sp)
+ retval.Append(SBType(type_sp));
+ }
+ }
+ else
+ {
+ SBType sb_type(ClangASTContext::GetBasicType (module_sp->GetClangASTContext().getASTContext(), name));
+ if (sb_type.IsValid())
+ retval.Append(sb_type);
+ }
+ }
+
+ return retval;
+}
+
+lldb::SBTypeList
+SBModule::GetTypes (uint32_t type_mask)
+{
+ SBTypeList sb_type_list;
+
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ SymbolVendor* vendor = module_sp->GetSymbolVendor();
+ if (vendor)
+ {
+ TypeList type_list;
+ vendor->GetTypes (NULL, type_mask, type_list);
+ sb_type_list.m_opaque_ap->Append(type_list);
+ }
+ }
+ return sb_type_list;
+}
+
+SBSection
+SBModule::FindSection (const char *sect_name)
+{
+ SBSection sb_section;
+
+ ModuleSP module_sp (GetSP ());
+ if (sect_name && module_sp)
+ {
+ // Give the symbol vendor a chance to add to the unified section list.
+ module_sp->GetSymbolVendor();
+ SectionList *section_list = module_sp->GetSectionList();
+ if (section_list)
+ {
+ ConstString const_sect_name(sect_name);
+ SectionSP section_sp (section_list->FindSectionByName(const_sect_name));
+ if (section_sp)
+ {
+ sb_section.SetSP (section_sp);
+ }
+ }
+ }
+ return sb_section;
+}
+
+lldb::ByteOrder
+SBModule::GetByteOrder ()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ return module_sp->GetArchitecture().GetByteOrder();
+ return eByteOrderInvalid;
+}
+
+const char *
+SBModule::GetTriple ()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ {
+ std::string triple (module_sp->GetArchitecture().GetTriple().str());
+ // Unique the string so we don't run into ownership issues since
+ // the const strings put the string into the string pool once and
+ // the strings never comes out
+ ConstString const_triple (triple.c_str());
+ return const_triple.GetCString();
+ }
+ return NULL;
+}
+
+uint32_t
+SBModule::GetAddressByteSize()
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ return module_sp->GetArchitecture().GetAddressByteSize();
+ return sizeof(void*);
+}
+
+
+uint32_t
+SBModule::GetVersion (uint32_t *versions, uint32_t num_versions)
+{
+ ModuleSP module_sp (GetSP ());
+ if (module_sp)
+ return module_sp->GetVersion(versions, num_versions);
+ else
+ {
+ if (versions && num_versions)
+ {
+ for (uint32_t i=0; i<num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ return 0;
+ }
+}
+
diff --git a/source/API/SBModuleSpec.cpp b/source/API/SBModuleSpec.cpp
new file mode 100644
index 000000000000..654a8ca6ec86
--- /dev/null
+++ b/source/API/SBModuleSpec.cpp
@@ -0,0 +1,230 @@
+//===-- SBModuleSpec.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/SBModuleSpec.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBModuleSpec::SBModuleSpec () :
+ m_opaque_ap (new lldb_private::ModuleSpec())
+{
+}
+
+SBModuleSpec::SBModuleSpec(const SBModuleSpec &rhs) :
+ m_opaque_ap (new lldb_private::ModuleSpec(*rhs.m_opaque_ap))
+{
+}
+
+const SBModuleSpec &
+SBModuleSpec::operator = (const SBModuleSpec &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_ap = *(rhs.m_opaque_ap);
+ return *this;
+}
+
+SBModuleSpec::~SBModuleSpec ()
+{
+}
+
+bool
+SBModuleSpec::IsValid () const
+{
+ return *m_opaque_ap;
+}
+
+void
+SBModuleSpec::Clear()
+{
+ m_opaque_ap->Clear();
+}
+
+SBFileSpec
+SBModuleSpec::GetFileSpec ()
+{
+ SBFileSpec sb_spec(m_opaque_ap->GetFileSpec());
+ return sb_spec;
+}
+
+void
+SBModuleSpec::SetFileSpec (const lldb::SBFileSpec &sb_spec)
+{
+ m_opaque_ap->GetFileSpec() = *sb_spec;
+}
+
+lldb::SBFileSpec
+SBModuleSpec::GetPlatformFileSpec ()
+{
+ return SBFileSpec(m_opaque_ap->GetPlatformFileSpec());
+}
+
+void
+SBModuleSpec::SetPlatformFileSpec (const lldb::SBFileSpec &sb_spec)
+{
+ m_opaque_ap->GetPlatformFileSpec() = *sb_spec;
+}
+
+lldb::SBFileSpec
+SBModuleSpec::GetSymbolFileSpec ()
+{
+ return SBFileSpec(m_opaque_ap->GetSymbolFileSpec());
+}
+
+void
+SBModuleSpec::SetSymbolFileSpec (const lldb::SBFileSpec &sb_spec)
+{
+ m_opaque_ap->GetSymbolFileSpec() = *sb_spec;
+}
+
+const char *
+SBModuleSpec::GetObjectName ()
+{
+ return m_opaque_ap->GetObjectName().GetCString();
+}
+
+void
+SBModuleSpec::SetObjectName (const char *name)
+{
+ m_opaque_ap->GetObjectName().SetCString(name);
+}
+
+const char *
+SBModuleSpec::GetTriple ()
+{
+ std::string triple (m_opaque_ap->GetArchitecture().GetTriple().str());
+ // Unique the string so we don't run into ownership issues since
+ // the const strings put the string into the string pool once and
+ // the strings never comes out
+ ConstString const_triple (triple.c_str());
+ return const_triple.GetCString();
+}
+
+void
+SBModuleSpec::SetTriple (const char *triple)
+{
+ m_opaque_ap->GetArchitecture().SetTriple(triple);
+}
+
+const uint8_t *
+SBModuleSpec::GetUUIDBytes ()
+{
+ return (const uint8_t *)m_opaque_ap->GetUUID().GetBytes();
+}
+
+size_t
+SBModuleSpec::GetUUIDLength ()
+{
+ return m_opaque_ap->GetUUID().GetByteSize();
+}
+
+bool
+SBModuleSpec::SetUUIDBytes (const uint8_t *uuid, size_t uuid_len)
+{
+ return m_opaque_ap->GetUUID().SetBytes(uuid, uuid_len);
+}
+
+bool
+SBModuleSpec::GetDescription (lldb::SBStream &description)
+{
+ m_opaque_ap->Dump (description.ref());
+ return true;
+}
+
+SBModuleSpecList::SBModuleSpecList() :
+ m_opaque_ap(new ModuleSpecList())
+{
+
+}
+
+SBModuleSpecList::SBModuleSpecList (const SBModuleSpecList &rhs) :
+ m_opaque_ap(new ModuleSpecList(*rhs.m_opaque_ap))
+{
+
+}
+
+SBModuleSpecList &
+SBModuleSpecList::operator = (const SBModuleSpecList &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_ap = *rhs.m_opaque_ap;
+ return *this;
+}
+
+SBModuleSpecList::~SBModuleSpecList()
+{
+
+}
+
+SBModuleSpecList
+SBModuleSpecList::GetModuleSpecifications (const char *path)
+{
+ SBModuleSpecList specs;
+ FileSpec file_spec(path, true);
+ Host::ResolveExecutableInBundle(file_spec);
+ ObjectFile::GetModuleSpecifications(file_spec, 0, 0, *specs.m_opaque_ap);
+ return specs;
+}
+
+void
+SBModuleSpecList::Append (const SBModuleSpec &spec)
+{
+ m_opaque_ap->Append (*spec.m_opaque_ap);
+}
+
+void
+SBModuleSpecList::Append (const SBModuleSpecList &spec_list)
+{
+ m_opaque_ap->Append (*spec_list.m_opaque_ap);
+}
+
+size_t
+SBModuleSpecList::GetSize()
+{
+ return m_opaque_ap->GetSize();
+}
+
+SBModuleSpec
+SBModuleSpecList::GetSpecAtIndex (size_t i)
+{
+ SBModuleSpec sb_module_spec;
+ m_opaque_ap->GetModuleSpecAtIndex(i, *sb_module_spec.m_opaque_ap);
+ return sb_module_spec;
+}
+
+SBModuleSpec
+SBModuleSpecList::FindFirstMatchingSpec (const SBModuleSpec &match_spec)
+{
+ SBModuleSpec sb_module_spec;
+ m_opaque_ap->FindMatchingModuleSpec(*match_spec.m_opaque_ap, *sb_module_spec.m_opaque_ap);
+ return sb_module_spec;
+}
+
+SBModuleSpecList
+SBModuleSpecList::FindMatchingSpecs (const SBModuleSpec &match_spec)
+{
+ SBModuleSpecList specs;
+ m_opaque_ap->FindMatchingModuleSpecs(*match_spec.m_opaque_ap, *specs.m_opaque_ap);
+ return specs;
+
+}
+
+bool
+SBModuleSpecList::GetDescription (lldb::SBStream &description)
+{
+ m_opaque_ap->Dump (description.ref());
+ return true;
+}
diff --git a/source/API/SBProcess.cpp b/source/API/SBProcess.cpp
new file mode 100644
index 000000000000..259eb5e97034
--- /dev/null
+++ b/source/API/SBProcess.cpp
@@ -0,0 +1,1256 @@
+//===-- SBProcess.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/SBProcess.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+// Project includes
+
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBProcess::SBProcess () :
+ m_opaque_wp()
+{
+}
+
+
+//----------------------------------------------------------------------
+// SBProcess constructor
+//----------------------------------------------------------------------
+
+SBProcess::SBProcess (const SBProcess& rhs) :
+ m_opaque_wp (rhs.m_opaque_wp)
+{
+}
+
+
+SBProcess::SBProcess (const lldb::ProcessSP &process_sp) :
+ m_opaque_wp (process_sp)
+{
+}
+
+const SBProcess&
+SBProcess::operator = (const SBProcess& rhs)
+{
+ if (this != &rhs)
+ m_opaque_wp = rhs.m_opaque_wp;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBProcess::~SBProcess()
+{
+}
+
+const char *
+SBProcess::GetBroadcasterClassName ()
+{
+ return Process::GetStaticBroadcasterClass().AsCString();
+}
+
+const char *
+SBProcess::GetPluginName ()
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ return process_sp->GetPluginName().GetCString();
+ }
+ return "<Unknown>";
+}
+
+const char *
+SBProcess::GetShortPluginName ()
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ return process_sp->GetPluginName().GetCString();
+ }
+ return "<Unknown>";
+}
+
+
+lldb::ProcessSP
+SBProcess::GetSP() const
+{
+ return m_opaque_wp.lock();
+}
+
+void
+SBProcess::SetSP (const ProcessSP &process_sp)
+{
+ m_opaque_wp = process_sp;
+}
+
+void
+SBProcess::Clear ()
+{
+ m_opaque_wp.reset();
+}
+
+
+bool
+SBProcess::IsValid() const
+{
+ ProcessSP process_sp(m_opaque_wp.lock());
+ return ((bool) process_sp && process_sp->IsValid());
+}
+
+bool
+SBProcess::RemoteLaunch (char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_directory,
+ uint32_t launch_flags,
+ bool stop_at_entry,
+ lldb::SBError& error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log) {
+ log->Printf ("SBProcess(%p)::RemoteLaunch (argv=%p, envp=%p, stdin=%s, stdout=%s, stderr=%s, working-dir=%s, launch_flags=0x%x, stop_at_entry=%i, &error (%p))...",
+ m_opaque_wp.lock().get(),
+ argv,
+ envp,
+ stdin_path ? stdin_path : "NULL",
+ stdout_path ? stdout_path : "NULL",
+ stderr_path ? stderr_path : "NULL",
+ working_directory ? working_directory : "NULL",
+ launch_flags,
+ stop_at_entry,
+ error.get());
+ }
+
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ if (process_sp->GetState() == eStateConnected)
+ {
+ if (stop_at_entry)
+ launch_flags |= eLaunchFlagStopAtEntry;
+ ProcessLaunchInfo launch_info (stdin_path,
+ stdout_path,
+ stderr_path,
+ working_directory,
+ launch_flags);
+ Module *exe_module = process_sp->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ if (argv)
+ launch_info.GetArguments().AppendArguments (argv);
+ if (envp)
+ launch_info.GetEnvironmentEntries ().SetArguments (envp);
+ error.SetError (process_sp->Launch (launch_info));
+ }
+ else
+ {
+ error.SetErrorString ("must be in eStateConnected to call RemoteLaunch");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to attach pid");
+ }
+
+ if (log) {
+ SBStream sstr;
+ error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::RemoteLaunch (...) => SBError (%p): %s", process_sp.get(), error.get(), sstr.GetData());
+ }
+
+ return error.Success();
+}
+
+bool
+SBProcess::RemoteAttachToProcessWithID (lldb::pid_t pid, lldb::SBError& error)
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ if (process_sp->GetState() == eStateConnected)
+ {
+ ProcessAttachInfo attach_info;
+ attach_info.SetProcessID (pid);
+ error.SetError (process_sp->Attach (attach_info));
+ }
+ else
+ {
+ error.SetErrorString ("must be in eStateConnected to call RemoteAttachToProcessWithID");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to attach pid");
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log) {
+ SBStream sstr;
+ error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::RemoteAttachToProcessWithID (%" PRIu64 ") => SBError (%p): %s", process_sp.get(), pid, error.get(), sstr.GetData());
+ }
+
+ return error.Success();
+}
+
+
+uint32_t
+SBProcess::GetNumThreads ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t num_threads = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+
+ const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ num_threads = process_sp->GetThreadList().GetSize(can_update);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::GetNumThreads () => %d", process_sp.get(), num_threads);
+
+ return num_threads;
+}
+
+SBThread
+SBProcess::GetSelectedThread () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ thread_sp = process_sp->GetThreadList().GetSelectedThread();
+ sb_thread.SetThread (thread_sp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::GetSelectedThread () => SBThread(%p)", process_sp.get(), thread_sp.get());
+ }
+
+ return sb_thread;
+}
+
+SBThread
+SBProcess::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ thread_sp = process_sp->CreateOSPluginThread(tid, context);
+ sb_thread.SetThread (thread_sp);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::CreateOSPluginThread (tid=0x%" PRIx64 ", context=0x%" PRIx64 ") => SBThread(%p)", process_sp.get(), tid, context, thread_sp.get());
+
+ return sb_thread;
+}
+
+SBTarget
+SBProcess::GetTarget() const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBTarget sb_target;
+ TargetSP target_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ target_sp = process_sp->GetTarget().shared_from_this();
+ sb_target.SetSP (target_sp);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::GetTarget () => SBTarget(%p)", process_sp.get(), target_sp.get());
+
+ return sb_target;
+}
+
+
+size_t
+SBProcess::PutSTDIN (const char *src, size_t src_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ size_t ret_val = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Error error;
+ ret_val = process_sp->PutSTDIN (src, src_len, error);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::PutSTDIN (src=\"%s\", src_len=%d) => %lu",
+ process_sp.get(),
+ src,
+ (uint32_t) src_len,
+ ret_val);
+
+ return ret_val;
+}
+
+size_t
+SBProcess::GetSTDOUT (char *dst, size_t dst_len) const
+{
+ size_t bytes_read = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Error error;
+ bytes_read = process_sp->GetSTDOUT (dst, dst_len, error);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetSTDOUT (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
+ process_sp.get(),
+ (int) bytes_read,
+ dst,
+ (uint64_t)dst_len,
+ (uint64_t)bytes_read);
+
+ return bytes_read;
+}
+
+size_t
+SBProcess::GetSTDERR (char *dst, size_t dst_len) const
+{
+ size_t bytes_read = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Error error;
+ bytes_read = process_sp->GetSTDERR (dst, dst_len, error);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetSTDERR (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
+ process_sp.get(),
+ (int) bytes_read,
+ dst,
+ (uint64_t)dst_len,
+ (uint64_t)bytes_read);
+
+ return bytes_read;
+}
+
+size_t
+SBProcess::GetAsyncProfileData(char *dst, size_t dst_len) const
+{
+ size_t bytes_read = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Error error;
+ bytes_read = process_sp->GetAsyncProfileData (dst, dst_len, error);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetProfileData (dst=\"%.*s\", dst_len=%" PRIu64 ") => %" PRIu64,
+ process_sp.get(),
+ (int) bytes_read,
+ dst,
+ (uint64_t)dst_len,
+ (uint64_t)bytes_read);
+
+ return bytes_read;
+}
+
+void
+SBProcess::ReportEventState (const SBEvent &event, FILE *out) const
+{
+ if (out == NULL)
+ return;
+
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ const StateType event_state = SBProcess::GetStateFromEvent (event);
+ char message[1024];
+ int message_len = ::snprintf (message,
+ sizeof (message),
+ "Process %" PRIu64 " %s\n",
+ process_sp->GetID(),
+ SBDebugger::StateAsCString (event_state));
+
+ if (message_len > 0)
+ ::fwrite (message, 1, message_len, out);
+ }
+}
+
+void
+SBProcess::AppendEventStateReport (const SBEvent &event, SBCommandReturnObject &result)
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ const StateType event_state = SBProcess::GetStateFromEvent (event);
+ char message[1024];
+ ::snprintf (message,
+ sizeof (message),
+ "Process %" PRIu64 " %s\n",
+ process_sp->GetID(),
+ SBDebugger::StateAsCString (event_state));
+
+ result.AppendMessage (message);
+ }
+}
+
+bool
+SBProcess::SetSelectedThread (const SBThread &thread)
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ return process_sp->GetThreadList().SetSelectedThreadByID (thread.GetThreadID());
+ }
+ return false;
+}
+
+bool
+SBProcess::SetSelectedThreadByID (lldb::tid_t tid)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool ret_val = false;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ ret_val = process_sp->GetThreadList().SetSelectedThreadByID (tid);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::SetSelectedThreadByID (tid=0x%4.4" PRIx64 ") => %s",
+ process_sp.get(), tid, (ret_val ? "true" : "false"));
+
+ return ret_val;
+}
+
+bool
+SBProcess::SetSelectedThreadByIndexID (uint32_t index_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool ret_val = false;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ ret_val = process_sp->GetThreadList().SetSelectedThreadByIndexID (index_id);
+ }
+
+ if (log)
+ log->Printf ("SBProcess(%p)::SetSelectedThreadByID (tid=0x%x) => %s",
+ process_sp.get(), index_id, (ret_val ? "true" : "false"));
+
+ return ret_val;
+}
+
+SBThread
+SBProcess::GetThreadAtIndex (size_t index)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ thread_sp = process_sp->GetThreadList().GetThreadAtIndex(index, can_update);
+ sb_thread.SetThread (thread_sp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::GetThreadAtIndex (index=%d) => SBThread(%p)",
+ process_sp.get(), (uint32_t) index, thread_sp.get());
+ }
+
+ return sb_thread;
+}
+
+uint32_t
+SBProcess::GetStopID(bool include_expression_stops)
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ if (include_expression_stops)
+ return process_sp->GetStopID();
+ else
+ return process_sp->GetLastNaturalStopID();
+ }
+ return 0;
+}
+
+StateType
+SBProcess::GetState ()
+{
+
+ StateType ret_val = eStateInvalid;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ ret_val = process_sp->GetState();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetState () => %s",
+ process_sp.get(),
+ lldb_private::StateAsCString (ret_val));
+
+ return ret_val;
+}
+
+
+int
+SBProcess::GetExitStatus ()
+{
+ int exit_status = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ exit_status = process_sp->GetExitStatus ();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetExitStatus () => %i (0x%8.8x)",
+ process_sp.get(), exit_status, exit_status);
+
+ return exit_status;
+}
+
+const char *
+SBProcess::GetExitDescription ()
+{
+ const char *exit_desc = NULL;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ exit_desc = process_sp->GetExitDescription ();
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetExitDescription () => %s",
+ process_sp.get(), exit_desc);
+ return exit_desc;
+}
+
+lldb::pid_t
+SBProcess::GetProcessID ()
+{
+ lldb::pid_t ret_val = LLDB_INVALID_PROCESS_ID;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ ret_val = process_sp->GetID();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetProcessID () => %" PRIu64, process_sp.get(), ret_val);
+
+ return ret_val;
+}
+
+uint32_t
+SBProcess::GetUniqueID()
+{
+ uint32_t ret_val = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ ret_val = process_sp->GetUniqueID();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetUniqueID () => %" PRIu32, process_sp.get(), ret_val);
+ return ret_val;
+}
+
+ByteOrder
+SBProcess::GetByteOrder () const
+{
+ ByteOrder byteOrder = eByteOrderInvalid;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ byteOrder = process_sp->GetTarget().GetArchitecture().GetByteOrder();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetByteOrder () => %d", process_sp.get(), byteOrder);
+
+ return byteOrder;
+}
+
+uint32_t
+SBProcess::GetAddressByteSize () const
+{
+ uint32_t size = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ size = process_sp->GetTarget().GetArchitecture().GetAddressByteSize();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetAddressByteSize () => %d", process_sp.get(), size);
+
+ return size;
+}
+
+SBError
+SBProcess::Continue ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ log->Printf ("SBProcess(%p)::Continue ()...", process_sp.get());
+
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+
+ Error error (process_sp->Resume());
+ if (error.Success())
+ {
+ if (process_sp->GetTarget().GetDebugger().GetAsyncExecution () == false)
+ {
+ if (log)
+ log->Printf ("SBProcess(%p)::Continue () waiting for process to stop...", process_sp.get());
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ sb_error.SetError(error);
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::Continue () => SBError (%p): %s", process_sp.get(), sb_error.get(), sstr.GetData());
+ }
+
+ return sb_error;
+}
+
+
+SBError
+SBProcess::Destroy ()
+{
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError(process_sp->Destroy());
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::Destroy () => SBError (%p): %s",
+ process_sp.get(),
+ sb_error.get(),
+ sstr.GetData());
+ }
+
+ return sb_error;
+}
+
+
+SBError
+SBProcess::Stop ()
+{
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->Halt());
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::Stop () => SBError (%p): %s",
+ process_sp.get(),
+ sb_error.get(),
+ sstr.GetData());
+ }
+
+ return sb_error;
+}
+
+SBError
+SBProcess::Kill ()
+{
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->Destroy());
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::Kill () => SBError (%p): %s",
+ process_sp.get(),
+ sb_error.get(),
+ sstr.GetData());
+ }
+
+ return sb_error;
+}
+
+SBError
+SBProcess::Detach ()
+{
+ // FIXME: This should come from a process default.
+ bool keep_stopped = false;
+ return Detach (keep_stopped);
+}
+
+SBError
+SBProcess::Detach (bool keep_stopped)
+{
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->Detach(keep_stopped));
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+
+ return sb_error;
+}
+
+SBError
+SBProcess::Signal (int signo)
+{
+ SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->Signal (signo));
+ }
+ else
+ sb_error.SetErrorString ("SBProcess is invalid");
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::Signal (signo=%i) => SBError (%p): %s",
+ process_sp.get(),
+ signo,
+ sb_error.get(),
+ sstr.GetData());
+ }
+ return sb_error;
+}
+
+void
+SBProcess::SendAsyncInterrupt ()
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ process_sp->SendAsyncInterrupt ();
+ }
+}
+
+SBThread
+SBProcess::GetThreadByID (tid_t tid)
+{
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ Process::StopLocker stop_locker;
+ const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ thread_sp = process_sp->GetThreadList().FindThreadByID (tid, can_update);
+ sb_thread.SetThread (thread_sp);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::GetThreadByID (tid=0x%4.4" PRIx64 ") => SBThread (%p)",
+ process_sp.get(),
+ tid,
+ thread_sp.get());
+ }
+
+ return sb_thread;
+}
+
+SBThread
+SBProcess::GetThreadByIndexID (uint32_t index_id)
+{
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ Process::StopLocker stop_locker;
+ const bool can_update = stop_locker.TryLock(&process_sp->GetRunLock());
+ thread_sp = process_sp->GetThreadList().FindThreadByIndexID (index_id, can_update);
+ sb_thread.SetThread (thread_sp);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::GetThreadByID (tid=0x%x) => SBThread (%p)",
+ process_sp.get(),
+ index_id,
+ thread_sp.get());
+ }
+
+ return sb_thread;
+}
+
+StateType
+SBProcess::GetStateFromEvent (const SBEvent &event)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ StateType ret_val = Process::ProcessEventData::GetStateFromEvent (event.get());
+
+ if (log)
+ log->Printf ("SBProcess::GetStateFromEvent (event.sp=%p) => %s", event.get(),
+ lldb_private::StateAsCString (ret_val));
+
+ return ret_val;
+}
+
+bool
+SBProcess::GetRestartedFromEvent (const SBEvent &event)
+{
+ return Process::ProcessEventData::GetRestartedFromEvent (event.get());
+}
+
+size_t
+SBProcess::GetNumRestartedReasonsFromEvent (const lldb::SBEvent &event)
+{
+ return Process::ProcessEventData::GetNumRestartedReasons(event.get());
+}
+
+const char *
+SBProcess::GetRestartedReasonAtIndexFromEvent (const lldb::SBEvent &event, size_t idx)
+{
+ return Process::ProcessEventData::GetRestartedReasonAtIndex(event.get(), idx);
+}
+
+SBProcess
+SBProcess::GetProcessFromEvent (const SBEvent &event)
+{
+ SBProcess process(Process::ProcessEventData::GetProcessFromEvent (event.get()));
+ return process;
+}
+
+bool
+SBProcess::EventIsProcessEvent (const SBEvent &event)
+{
+ return strcmp (event.GetBroadcasterClass(), SBProcess::GetBroadcasterClass()) == 0;
+}
+
+SBBroadcaster
+SBProcess::GetBroadcaster () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ProcessSP process_sp(GetSP());
+
+ SBBroadcaster broadcaster(process_sp.get(), false);
+
+ if (log)
+ log->Printf ("SBProcess(%p)::GetBroadcaster () => SBBroadcaster (%p)", process_sp.get(),
+ broadcaster.get());
+
+ return broadcaster;
+}
+
+const char *
+SBProcess::GetBroadcasterClass ()
+{
+ return Process::GetStaticBroadcasterClass().AsCString();
+}
+
+size_t
+SBProcess::ReadMemory (addr_t addr, void *dst, size_t dst_len, SBError &sb_error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ size_t bytes_read = 0;
+
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::ReadMemory (addr=0x%" PRIx64 ", dst=%p, dst_len=%" PRIu64 ", SBError (%p))...",
+ process_sp.get(),
+ addr,
+ dst,
+ (uint64_t)dst_len,
+ sb_error.get());
+ }
+
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ bytes_read = process_sp->ReadMemory (addr, dst, dst_len, sb_error.ref());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBProcess(%p)::ReadMemory() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::ReadMemory (addr=0x%" PRIx64 ", dst=%p, dst_len=%" PRIu64 ", SBError (%p): %s) => %" PRIu64,
+ process_sp.get(),
+ addr,
+ dst,
+ (uint64_t)dst_len,
+ sb_error.get(),
+ sstr.GetData(),
+ (uint64_t)bytes_read);
+ }
+
+ return bytes_read;
+}
+
+size_t
+SBProcess::ReadCStringFromMemory (addr_t addr, void *buf, size_t size, lldb::SBError &sb_error)
+{
+ size_t bytes_read = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ bytes_read = process_sp->ReadCStringFromMemory (addr, (char *)buf, size, sb_error.ref());
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::ReadCStringFromMemory() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+ return bytes_read;
+}
+
+uint64_t
+SBProcess::ReadUnsignedFromMemory (addr_t addr, uint32_t byte_size, lldb::SBError &sb_error)
+{
+ uint64_t value = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ value = process_sp->ReadUnsignedIntegerFromMemory (addr, byte_size, 0, sb_error.ref());
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::ReadUnsignedFromMemory() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+ return value;
+}
+
+lldb::addr_t
+SBProcess::ReadPointerFromMemory (addr_t addr, lldb::SBError &sb_error)
+{
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ ptr = process_sp->ReadPointerFromMemory (addr, sb_error.ref());
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::ReadPointerFromMemory() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+ return ptr;
+}
+
+size_t
+SBProcess::WriteMemory (addr_t addr, const void *src, size_t src_len, SBError &sb_error)
+{
+ size_t bytes_written = 0;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ProcessSP process_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBProcess(%p)::WriteMemory (addr=0x%" PRIx64 ", src=%p, src_len=%" PRIu64 ", SBError (%p))...",
+ process_sp.get(),
+ addr,
+ src,
+ (uint64_t)src_len,
+ sb_error.get());
+ }
+
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ bytes_written = process_sp->WriteMemory (addr, src, src_len, sb_error.ref());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBProcess(%p)::WriteMemory() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_error.GetDescription (sstr);
+ log->Printf ("SBProcess(%p)::WriteMemory (addr=0x%" PRIx64 ", src=%p, src_len=%" PRIu64 ", SBError (%p): %s) => %" PRIu64,
+ process_sp.get(),
+ addr,
+ src,
+ (uint64_t)src_len,
+ sb_error.get(),
+ sstr.GetData(),
+ (uint64_t)bytes_written);
+ }
+
+ return bytes_written;
+}
+
+bool
+SBProcess::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ char path[PATH_MAX];
+ GetTarget().GetExecutable().GetPath (path, sizeof(path));
+ Module *exe_module = process_sp->GetTarget().GetExecutableModulePointer();
+ const char *exe_name = NULL;
+ if (exe_module)
+ exe_name = exe_module->GetFileSpec().GetFilename().AsCString();
+
+ strm.Printf ("SBProcess: pid = %" PRIu64 ", state = %s, threads = %d%s%s",
+ process_sp->GetID(),
+ lldb_private::StateAsCString (GetState()),
+ GetNumThreads(),
+ exe_name ? ", executable = " : "",
+ exe_name ? exe_name : "");
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+uint32_t
+SBProcess::GetNumSupportedHardwareWatchpoints (lldb::SBError &sb_error) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t num = 0;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError(process_sp->GetWatchpointSupportInfo (num));
+ if (log)
+ log->Printf ("SBProcess(%p)::GetNumSupportedHardwareWatchpoints () => %u",
+ process_sp.get(), num);
+ }
+ else
+ {
+ sb_error.SetErrorString ("SBProcess is invalid");
+ }
+ return num;
+}
+
+uint32_t
+SBProcess::LoadImage (lldb::SBFileSpec &sb_image_spec, lldb::SBError &sb_error)
+{
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ return process_sp->LoadImage (*sb_image_spec, sb_error.ref());
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::LoadImage() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ return LLDB_INVALID_IMAGE_TOKEN;
+}
+
+lldb::SBError
+SBProcess::UnloadImage (uint32_t image_token)
+{
+ lldb::SBError sb_error;
+ ProcessSP process_sp(GetSP());
+ if (process_sp)
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&process_sp->GetRunLock()))
+ {
+ Mutex::Locker api_locker (process_sp->GetTarget().GetAPIMutex());
+ sb_error.SetError (process_sp->UnloadImage (image_token));
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBProcess(%p)::UnloadImage() => error: process is running", process_sp.get());
+ sb_error.SetErrorString("process is running");
+ }
+ }
+ else
+ sb_error.SetErrorString("invalid process");
+ return sb_error;
+}
diff --git a/source/API/SBSection.cpp b/source/API/SBSection.cpp
new file mode 100644
index 000000000000..3fb84e81465c
--- /dev/null
+++ b/source/API/SBSection.cpp
@@ -0,0 +1,291 @@
+//===-- SBSection.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/SBSection.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBSection::SBSection () :
+ m_opaque_wp ()
+{
+}
+
+SBSection::SBSection (const SBSection &rhs) :
+ m_opaque_wp (rhs.m_opaque_wp)
+{
+}
+
+
+
+SBSection::SBSection (const lldb::SectionSP &section_sp) :
+ m_opaque_wp () // Don't init with section_sp otherwise this will throw if section_sp doesn't contain a valid Section *
+{
+ if (section_sp)
+ m_opaque_wp = section_sp;
+}
+
+const SBSection &
+SBSection::operator = (const SBSection &rhs)
+{
+ m_opaque_wp = rhs.m_opaque_wp;
+ return *this;
+}
+
+SBSection::~SBSection ()
+{
+}
+
+bool
+SBSection::IsValid () const
+{
+ SectionSP section_sp (GetSP());
+ return section_sp && section_sp->GetModule().get() != NULL;
+}
+
+const char *
+SBSection::GetName ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetName().GetCString();
+ return NULL;
+}
+
+lldb::SBSection
+SBSection::GetParent()
+{
+ lldb::SBSection sb_section;
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ {
+ SectionSP parent_section_sp (section_sp->GetParent());
+ if (parent_section_sp)
+ sb_section.SetSP(parent_section_sp);
+ }
+ return sb_section;
+}
+
+
+lldb::SBSection
+SBSection::FindSubSection (const char *sect_name)
+{
+ lldb::SBSection sb_section;
+ if (sect_name)
+ {
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ {
+ ConstString const_sect_name(sect_name);
+ sb_section.SetSP(section_sp->GetChildren ().FindSectionByName(const_sect_name));
+ }
+ }
+ return sb_section;
+}
+
+size_t
+SBSection::GetNumSubSections ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetChildren ().GetSize();
+ return 0;
+}
+
+lldb::SBSection
+SBSection::GetSubSectionAtIndex (size_t idx)
+{
+ lldb::SBSection sb_section;
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ sb_section.SetSP (section_sp->GetChildren ().GetSectionAtIndex(idx));
+ return sb_section;
+}
+
+lldb::SectionSP
+SBSection::GetSP() const
+{
+ return m_opaque_wp.lock();
+}
+
+void
+SBSection::SetSP(const lldb::SectionSP &section_sp)
+{
+ m_opaque_wp = section_sp;
+}
+
+lldb::addr_t
+SBSection::GetFileAddress ()
+{
+ lldb::addr_t file_addr = LLDB_INVALID_ADDRESS;
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetFileAddress();
+ return file_addr;
+}
+
+lldb::addr_t
+SBSection::GetLoadAddress (lldb::SBTarget &sb_target)
+{
+ TargetSP target_sp(sb_target.GetSP());
+ if (target_sp)
+ {
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetLoadBaseAddress(target_sp.get());
+ }
+ return LLDB_INVALID_ADDRESS;
+
+}
+
+
+
+lldb::addr_t
+SBSection::GetByteSize ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetByteSize();
+ return 0;
+}
+
+uint64_t
+SBSection::GetFileOffset ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ {
+ ModuleSP module_sp (section_sp->GetModule());
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ return objfile->GetFileOffset() + section_sp->GetFileOffset();
+ }
+ }
+ return UINT64_MAX;
+}
+
+uint64_t
+SBSection::GetFileByteSize ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ return section_sp->GetFileSize();
+ return 0;
+}
+
+SBData
+SBSection::GetSectionData ()
+{
+ return GetSectionData (0, UINT64_MAX);
+}
+
+SBData
+SBSection::GetSectionData (uint64_t offset, uint64_t size)
+{
+ SBData sb_data;
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ {
+ const uint64_t sect_file_size = section_sp->GetFileSize();
+ if (sect_file_size > 0)
+ {
+ ModuleSP module_sp (section_sp->GetModule());
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ const uint64_t sect_file_offset = objfile->GetFileOffset() + section_sp->GetFileOffset();
+ const uint64_t file_offset = sect_file_offset + offset;
+ uint64_t file_size = size;
+ if (file_size == UINT64_MAX)
+ {
+ file_size = section_sp->GetByteSize();
+ if (file_size > offset)
+ file_size -= offset;
+ else
+ file_size = 0;
+ }
+ DataBufferSP data_buffer_sp (objfile->GetFileSpec().ReadFileContents (file_offset, file_size));
+ if (data_buffer_sp && data_buffer_sp->GetByteSize() > 0)
+ {
+ DataExtractorSP data_extractor_sp (new DataExtractor (data_buffer_sp,
+ objfile->GetByteOrder(),
+ objfile->GetAddressByteSize()));
+
+ sb_data.SetOpaque (data_extractor_sp);
+ }
+ }
+ }
+ }
+ }
+ return sb_data;
+}
+
+SectionType
+SBSection::GetSectionType ()
+{
+ SectionSP section_sp (GetSP());
+ if (section_sp.get())
+ return section_sp->GetType();
+ return eSectionTypeInvalid;
+}
+
+
+bool
+SBSection::operator == (const SBSection &rhs)
+{
+ SectionSP lhs_section_sp (GetSP());
+ SectionSP rhs_section_sp (rhs.GetSP());
+ if (lhs_section_sp && rhs_section_sp)
+ return lhs_section_sp == rhs_section_sp;
+ return false;
+}
+
+bool
+SBSection::operator != (const SBSection &rhs)
+{
+ SectionSP lhs_section_sp (GetSP());
+ SectionSP rhs_section_sp (rhs.GetSP());
+ return lhs_section_sp != rhs_section_sp;
+}
+
+bool
+SBSection::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ SectionSP section_sp (GetSP());
+ if (section_sp)
+ {
+ const addr_t file_addr = section_sp->GetFileAddress();
+ strm.Printf ("[0x%16.16" PRIx64 "-0x%16.16" PRIx64 ") ", file_addr, file_addr + section_sp->GetByteSize());
+ section_sp->DumpName(&strm);
+ }
+ else
+ {
+ strm.PutCString ("No value");
+ }
+
+ return true;
+}
+
diff --git a/source/API/SBSourceManager.cpp b/source/API/SBSourceManager.cpp
new file mode 100644
index 000000000000..0b8cbfceda0f
--- /dev/null
+++ b/source/API/SBSourceManager.cpp
@@ -0,0 +1,146 @@
+//===-- SBSourceManager.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/SBDebugger.h"
+#include "lldb/API/SBSourceManager.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/SourceManager.h"
+
+#include "lldb/Target/Target.h"
+
+namespace lldb_private
+{
+ class SourceManagerImpl
+ {
+ public:
+ SourceManagerImpl (const lldb::DebuggerSP &debugger_sp) :
+ m_debugger_wp (debugger_sp),
+ m_target_wp ()
+ {
+ }
+
+ SourceManagerImpl (const lldb::TargetSP &target_sp) :
+ m_debugger_wp (),
+ m_target_wp (target_sp)
+ {
+ }
+
+ SourceManagerImpl (const SourceManagerImpl &rhs)
+ {
+ if (&rhs == this)
+ return;
+ m_debugger_wp = rhs.m_debugger_wp;
+ m_target_wp = rhs.m_target_wp;
+ }
+
+ size_t
+ DisplaySourceLinesWithLineNumbers (const lldb_private::FileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char *current_line_cstr,
+ lldb_private::Stream *s)
+ {
+ if (!file)
+ return 0;
+
+ lldb::TargetSP target_sp (m_target_wp.lock());
+ if (target_sp)
+ {
+ return target_sp->GetSourceManager().DisplaySourceLinesWithLineNumbers (file,
+ line,
+ context_before,
+ context_after,
+ current_line_cstr,
+ s);
+ }
+ else
+ {
+ lldb::DebuggerSP debugger_sp (m_debugger_wp.lock());
+ if (debugger_sp)
+ {
+ return debugger_sp->GetSourceManager().DisplaySourceLinesWithLineNumbers (file,
+ line,
+ context_before,
+ context_after,
+ current_line_cstr,
+ s);
+ }
+ }
+ return 0;
+ }
+
+ private:
+ lldb::DebuggerWP m_debugger_wp;
+ lldb::TargetWP m_target_wp;
+
+ };
+}
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBSourceManager::SBSourceManager (const SBDebugger &debugger)
+{
+ m_opaque_ap.reset(new SourceManagerImpl (debugger.get_sp()));
+}
+
+SBSourceManager::SBSourceManager (const SBTarget &target)
+{
+ m_opaque_ap.reset(new SourceManagerImpl (target.GetSP()));
+}
+
+SBSourceManager::SBSourceManager (const SBSourceManager &rhs)
+{
+ if (&rhs == this)
+ return;
+
+ m_opaque_ap.reset(new SourceManagerImpl (*(rhs.m_opaque_ap.get())));
+}
+
+const lldb::SBSourceManager &
+SBSourceManager::operator = (const lldb::SBSourceManager &rhs)
+{
+ m_opaque_ap.reset (new SourceManagerImpl (*(rhs.m_opaque_ap.get())));
+ return *this;
+}
+
+SBSourceManager::~SBSourceManager()
+{
+}
+
+size_t
+SBSourceManager::DisplaySourceLinesWithLineNumbers
+(
+ const SBFileSpec &file,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char *current_line_cstr,
+ SBStream &s
+)
+{
+ if (m_opaque_ap.get() == NULL)
+ return 0;
+
+ return m_opaque_ap->DisplaySourceLinesWithLineNumbers (file.ref(),
+ line,
+ context_before,
+ context_after,
+ current_line_cstr,
+ s.get());
+}
diff --git a/source/API/SBStream.cpp b/source/API/SBStream.cpp
new file mode 100644
index 000000000000..dc8eb05ab0ba
--- /dev/null
+++ b/source/API/SBStream.cpp
@@ -0,0 +1,187 @@
+//===-- SBStream.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/SBStream.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBStream::SBStream () :
+ m_opaque_ap (new StreamString()),
+ m_is_file (false)
+{
+}
+
+SBStream::~SBStream ()
+{
+}
+
+bool
+SBStream::IsValid() const
+{
+ return (m_opaque_ap.get() != NULL);
+}
+
+// If this stream is not redirected to a file, it will maintain a local
+// cache for the stream data which can be accessed using this accessor.
+const char *
+SBStream::GetData ()
+{
+ if (m_is_file || m_opaque_ap.get() == NULL)
+ return NULL;
+
+ return static_cast<StreamString *>(m_opaque_ap.get())->GetData();
+}
+
+// If this stream is not redirected to a file, it will maintain a local
+// cache for the stream output whose length can be accessed using this
+// accessor.
+size_t
+SBStream::GetSize()
+{
+ if (m_is_file || m_opaque_ap.get() == NULL)
+ return 0;
+
+ return static_cast<StreamString *>(m_opaque_ap.get())->GetSize();
+}
+
+void
+SBStream::Printf (const char *format, ...)
+{
+ if (!format)
+ return;
+ va_list args;
+ va_start (args, format);
+ ref().PrintfVarArg (format, args);
+ va_end (args);
+}
+
+void
+SBStream::RedirectToFile (const char *path, bool append)
+{
+ std::string local_data;
+ if (m_opaque_ap.get())
+ {
+ // See if we have any locally backed data. If so, copy it so we can then
+ // redirect it to the file so we don't lose the data
+ if (!m_is_file)
+ local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
+ }
+ StreamFile *stream_file = new StreamFile;
+ uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
+ if (append)
+ open_options |= File::eOpenOptionAppend;
+ stream_file->GetFile().Open (path, open_options, File::ePermissionsDefault);
+
+ m_opaque_ap.reset (stream_file);
+
+ if (m_opaque_ap.get())
+ {
+ m_is_file = true;
+
+ // If we had any data locally in our StreamString, then pass that along to
+ // the to new file we are redirecting to.
+ if (!local_data.empty())
+ m_opaque_ap->Write (&local_data[0], local_data.size());
+ }
+ else
+ m_is_file = false;
+}
+
+void
+SBStream::RedirectToFileHandle (FILE *fh, bool transfer_fh_ownership)
+{
+ std::string local_data;
+ if (m_opaque_ap.get())
+ {
+ // See if we have any locally backed data. If so, copy it so we can then
+ // redirect it to the file so we don't lose the data
+ if (!m_is_file)
+ local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
+ }
+ m_opaque_ap.reset (new StreamFile (fh, transfer_fh_ownership));
+
+ if (m_opaque_ap.get())
+ {
+ m_is_file = true;
+
+ // If we had any data locally in our StreamString, then pass that along to
+ // the to new file we are redirecting to.
+ if (!local_data.empty())
+ m_opaque_ap->Write (&local_data[0], local_data.size());
+ }
+ else
+ m_is_file = false;
+}
+
+void
+SBStream::RedirectToFileDescriptor (int fd, bool transfer_fh_ownership)
+{
+ std::string local_data;
+ if (m_opaque_ap.get())
+ {
+ // See if we have any locally backed data. If so, copy it so we can then
+ // redirect it to the file so we don't lose the data
+ if (!m_is_file)
+ local_data.swap(static_cast<StreamString *>(m_opaque_ap.get())->GetString());
+ }
+
+ m_opaque_ap.reset (new StreamFile (::fdopen (fd, "w"), transfer_fh_ownership));
+ if (m_opaque_ap.get())
+ {
+ m_is_file = true;
+
+ // If we had any data locally in our StreamString, then pass that along to
+ // the to new file we are redirecting to.
+ if (!local_data.empty())
+ m_opaque_ap->Write (&local_data[0], local_data.size());
+ }
+ else
+ m_is_file = false;
+
+}
+
+lldb_private::Stream *
+SBStream::operator->()
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::Stream *
+SBStream::get()
+{
+ return m_opaque_ap.get();
+}
+
+lldb_private::Stream &
+SBStream::ref()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new StreamString());
+ return *m_opaque_ap.get();
+}
+
+void
+SBStream::Clear ()
+{
+ if (m_opaque_ap.get())
+ {
+ // See if we have any locally backed data. If so, copy it so we can then
+ // redirect it to the file so we don't lose the data
+ if (m_is_file)
+ m_opaque_ap.reset();
+ else
+ static_cast<StreamString *>(m_opaque_ap.get())->GetString().clear();
+ }
+}
diff --git a/source/API/SBStringList.cpp b/source/API/SBStringList.cpp
new file mode 100644
index 000000000000..129d2f4c11f0
--- /dev/null
+++ b/source/API/SBStringList.cpp
@@ -0,0 +1,136 @@
+//===-- SBStringList.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/SBStringList.h"
+
+#include "lldb/Core/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBStringList::SBStringList () :
+ m_opaque_ap ()
+{
+}
+
+SBStringList::SBStringList (const lldb_private::StringList *lldb_strings_ptr) :
+ m_opaque_ap ()
+{
+ if (lldb_strings_ptr)
+ m_opaque_ap.reset (new lldb_private::StringList (*lldb_strings_ptr));
+}
+
+SBStringList::SBStringList (const SBStringList &rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ m_opaque_ap.reset (new lldb_private::StringList(*rhs));
+}
+
+
+const SBStringList &
+SBStringList::operator = (const SBStringList &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_ap.reset(new lldb_private::StringList(*rhs));
+ else
+ m_opaque_ap.reset();
+ }
+ return *this;
+}
+
+SBStringList::~SBStringList ()
+{
+}
+
+const lldb_private::StringList *
+SBStringList::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+const lldb_private::StringList &
+SBStringList::operator*() const
+{
+ return *m_opaque_ap;
+}
+
+bool
+SBStringList::IsValid() const
+{
+ return (m_opaque_ap.get() != NULL);
+}
+
+void
+SBStringList::AppendString (const char *str)
+{
+ if (str != NULL)
+ {
+ if (IsValid())
+ m_opaque_ap->AppendString (str);
+ else
+ m_opaque_ap.reset (new lldb_private::StringList (str));
+ }
+
+}
+
+void
+SBStringList::AppendList (const char **strv, int strc)
+{
+ if ((strv != NULL)
+ && (strc > 0))
+ {
+ if (IsValid())
+ m_opaque_ap->AppendList (strv, strc);
+ else
+ m_opaque_ap.reset (new lldb_private::StringList (strv, strc));
+ }
+}
+
+void
+SBStringList::AppendList (const SBStringList &strings)
+{
+ if (strings.IsValid())
+ {
+ if (! IsValid())
+ m_opaque_ap.reset (new lldb_private::StringList());
+ m_opaque_ap->AppendList (*(strings.m_opaque_ap));
+ }
+}
+
+uint32_t
+SBStringList::GetSize () const
+{
+ if (IsValid())
+ {
+ return m_opaque_ap->GetSize();
+ }
+ return 0;
+}
+
+const char *
+SBStringList::GetStringAtIndex (size_t idx)
+{
+ if (IsValid())
+ {
+ return m_opaque_ap->GetStringAtIndex (idx);
+ }
+ return NULL;
+}
+
+void
+SBStringList::Clear ()
+{
+ if (IsValid())
+ {
+ m_opaque_ap->Clear();
+ }
+}
diff --git a/source/API/SBSymbol.cpp b/source/API/SBSymbol.cpp
new file mode 100644
index 000000000000..dd057e81a559
--- /dev/null
+++ b/source/API/SBSymbol.cpp
@@ -0,0 +1,223 @@
+//===-- SBSymbol.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/SBSymbol.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBSymbol::SBSymbol () :
+ m_opaque_ptr (NULL)
+{
+}
+
+SBSymbol::SBSymbol (lldb_private::Symbol *lldb_object_ptr) :
+ m_opaque_ptr (lldb_object_ptr)
+{
+}
+
+SBSymbol::SBSymbol (const lldb::SBSymbol &rhs) :
+ m_opaque_ptr (rhs.m_opaque_ptr)
+{
+}
+
+const SBSymbol &
+SBSymbol::operator = (const SBSymbol &rhs)
+{
+ m_opaque_ptr = rhs.m_opaque_ptr;
+ return *this;
+}
+
+SBSymbol::~SBSymbol ()
+{
+ m_opaque_ptr = NULL;
+}
+
+void
+SBSymbol::SetSymbol (lldb_private::Symbol *lldb_object_ptr)
+{
+ m_opaque_ptr = lldb_object_ptr;
+}
+
+bool
+SBSymbol::IsValid () const
+{
+ return m_opaque_ptr != NULL;
+}
+
+const char *
+SBSymbol::GetName() const
+{
+ const char *name = NULL;
+ if (m_opaque_ptr)
+ name = m_opaque_ptr->GetMangled().GetName().AsCString();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBSymbol(%p)::GetName () => \"%s\"", m_opaque_ptr, name ? name : "");
+ return name;
+}
+
+const char *
+SBSymbol::GetMangledName () const
+{
+ const char *name = NULL;
+ if (m_opaque_ptr)
+ name = m_opaque_ptr->GetMangled().GetMangledName().AsCString();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBSymbol(%p)::GetMangledName () => \"%s\"", m_opaque_ptr, name ? name : "");
+
+ return name;
+}
+
+
+bool
+SBSymbol::operator == (const SBSymbol &rhs) const
+{
+ return m_opaque_ptr == rhs.m_opaque_ptr;
+}
+
+bool
+SBSymbol::operator != (const SBSymbol &rhs) const
+{
+ return m_opaque_ptr != rhs.m_opaque_ptr;
+}
+
+bool
+SBSymbol::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ptr)
+ {
+ m_opaque_ptr->GetDescription (&strm,
+ lldb::eDescriptionLevelFull, NULL);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+SBInstructionList
+SBSymbol::GetInstructions (SBTarget target)
+{
+ return GetInstructions (target, NULL);
+}
+
+SBInstructionList
+SBSymbol::GetInstructions (SBTarget target, const char *flavor_string)
+{
+ SBInstructionList sb_instructions;
+ if (m_opaque_ptr)
+ {
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx;
+ TargetSP target_sp (target.GetSP());
+ if (target_sp)
+ {
+ api_locker.Lock (target_sp->GetAPIMutex());
+ target_sp->CalculateExecutionContext (exe_ctx);
+ }
+ if (m_opaque_ptr->ValueIsAddress())
+ {
+ ModuleSP module_sp (m_opaque_ptr->GetAddress().GetModule());
+ if (module_sp)
+ {
+ AddressRange symbol_range (m_opaque_ptr->GetAddress(), m_opaque_ptr->GetByteSize());
+ sb_instructions.SetDisassembler (Disassembler::DisassembleRange (module_sp->GetArchitecture (),
+ NULL,
+ flavor_string,
+ exe_ctx,
+ symbol_range));
+ }
+ }
+ }
+ return sb_instructions;
+}
+
+lldb_private::Symbol *
+SBSymbol::get ()
+{
+ return m_opaque_ptr;
+}
+
+void
+SBSymbol::reset (lldb_private::Symbol *symbol)
+{
+ m_opaque_ptr = symbol;
+}
+
+SBAddress
+SBSymbol::GetStartAddress ()
+{
+ SBAddress addr;
+ if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress())
+ {
+ addr.SetAddress (&m_opaque_ptr->GetAddress());
+ }
+ return addr;
+}
+
+SBAddress
+SBSymbol::GetEndAddress ()
+{
+ SBAddress addr;
+ if (m_opaque_ptr && m_opaque_ptr->ValueIsAddress())
+ {
+ lldb::addr_t range_size = m_opaque_ptr->GetByteSize();
+ if (range_size > 0)
+ {
+ addr.SetAddress (&m_opaque_ptr->GetAddress());
+ addr->Slide (m_opaque_ptr->GetByteSize());
+ }
+ }
+ return addr;
+}
+
+uint32_t
+SBSymbol::GetPrologueByteSize ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetPrologueByteSize();
+ return 0;
+}
+
+SymbolType
+SBSymbol::GetType ()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->GetType();
+ return eSymbolTypeInvalid;
+}
+
+bool
+SBSymbol::IsExternal()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->IsExternal();
+ return false;
+}
+
+bool
+SBSymbol::IsSynthetic()
+{
+ if (m_opaque_ptr)
+ return m_opaque_ptr->IsSynthetic();
+ return false;
+}
+
diff --git a/source/API/SBSymbolContext.cpp b/source/API/SBSymbolContext.cpp
new file mode 100644
index 000000000000..479b0f75bfe9
--- /dev/null
+++ b/source/API/SBSymbolContext.cpp
@@ -0,0 +1,285 @@
+//===-- SBSymbolContext.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/SBSymbolContext.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+SBSymbolContext::SBSymbolContext () :
+ m_opaque_ap ()
+{
+}
+
+SBSymbolContext::SBSymbolContext (const SymbolContext *sc_ptr) :
+ m_opaque_ap ()
+{
+ if (sc_ptr)
+ m_opaque_ap.reset (new SymbolContext (*sc_ptr));
+}
+
+SBSymbolContext::SBSymbolContext (const SBSymbolContext& rhs) :
+ m_opaque_ap ()
+{
+ if (rhs.IsValid())
+ {
+ if (m_opaque_ap.get())
+ *m_opaque_ap = *rhs.m_opaque_ap;
+ else
+ ref() = *rhs.m_opaque_ap;
+ }
+}
+
+SBSymbolContext::~SBSymbolContext ()
+{
+}
+
+const SBSymbolContext &
+SBSymbolContext::operator = (const SBSymbolContext &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_ap.reset (new lldb_private::SymbolContext(*rhs.m_opaque_ap.get()));
+ }
+ return *this;
+}
+
+void
+SBSymbolContext::SetSymbolContext (const SymbolContext *sc_ptr)
+{
+ if (sc_ptr)
+ {
+ if (m_opaque_ap.get())
+ *m_opaque_ap = *sc_ptr;
+ else
+ m_opaque_ap.reset (new SymbolContext (*sc_ptr));
+ }
+ else
+ {
+ if (m_opaque_ap.get())
+ m_opaque_ap->Clear(true);
+ }
+}
+
+bool
+SBSymbolContext::IsValid () const
+{
+ return m_opaque_ap.get() != NULL;
+}
+
+
+
+SBModule
+SBSymbolContext::GetModule ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBModule sb_module;
+ ModuleSP module_sp;
+ if (m_opaque_ap.get())
+ {
+ module_sp = m_opaque_ap->module_sp;
+ sb_module.SetSP (module_sp);
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_module.GetDescription (sstr);
+ log->Printf ("SBSymbolContext(%p)::GetModule () => SBModule(%p): %s",
+ m_opaque_ap.get(), module_sp.get(), sstr.GetData());
+ }
+
+ return sb_module;
+}
+
+SBCompileUnit
+SBSymbolContext::GetCompileUnit ()
+{
+ return SBCompileUnit (m_opaque_ap.get() ? m_opaque_ap->comp_unit : NULL);
+}
+
+SBFunction
+SBSymbolContext::GetFunction ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Function *function = NULL;
+
+ if (m_opaque_ap.get())
+ function = m_opaque_ap->function;
+
+ SBFunction sb_function (function);
+
+ if (log)
+ log->Printf ("SBSymbolContext(%p)::GetFunction () => SBFunction(%p)",
+ m_opaque_ap.get(), function);
+
+ return sb_function;
+}
+
+SBBlock
+SBSymbolContext::GetBlock ()
+{
+ return SBBlock (m_opaque_ap.get() ? m_opaque_ap->block : NULL);
+}
+
+SBLineEntry
+SBSymbolContext::GetLineEntry ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBLineEntry sb_line_entry;
+ if (m_opaque_ap.get())
+ sb_line_entry.SetLineEntry (m_opaque_ap->line_entry);
+
+ if (log)
+ {
+ log->Printf ("SBSymbolContext(%p)::GetLineEntry () => SBLineEntry(%p)",
+ m_opaque_ap.get(), sb_line_entry.get());
+ }
+
+ return sb_line_entry;
+}
+
+SBSymbol
+SBSymbolContext::GetSymbol ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Symbol *symbol = NULL;
+
+ if (m_opaque_ap.get())
+ symbol = m_opaque_ap->symbol;
+
+ SBSymbol sb_symbol (symbol);
+
+ if (log)
+ {
+ log->Printf ("SBSymbolContext(%p)::GetSymbol () => SBSymbol(%p)",
+ m_opaque_ap.get(), symbol);
+ }
+
+ return sb_symbol;
+}
+
+void
+SBSymbolContext::SetModule (lldb::SBModule module)
+{
+ ref().module_sp = module.GetSP();
+}
+
+void
+SBSymbolContext::SetCompileUnit (lldb::SBCompileUnit compile_unit)
+{
+ ref().comp_unit = compile_unit.get();
+}
+
+void
+SBSymbolContext::SetFunction (lldb::SBFunction function)
+{
+ ref().function = function.get();
+}
+
+void
+SBSymbolContext::SetBlock (lldb::SBBlock block)
+{
+ ref().block = block.GetPtr();
+}
+
+void
+SBSymbolContext::SetLineEntry (lldb::SBLineEntry line_entry)
+{
+ if (line_entry.IsValid())
+ ref().line_entry = line_entry.ref();
+ else
+ ref().line_entry.Clear();
+}
+
+void
+SBSymbolContext::SetSymbol (lldb::SBSymbol symbol)
+{
+ ref().symbol = symbol.get();
+}
+
+
+lldb_private::SymbolContext*
+SBSymbolContext::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+
+const lldb_private::SymbolContext&
+SBSymbolContext::operator*() const
+{
+ assert (m_opaque_ap.get());
+ return *m_opaque_ap.get();
+}
+
+
+lldb_private::SymbolContext&
+SBSymbolContext::operator*()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new SymbolContext);
+ return *m_opaque_ap.get();
+}
+
+lldb_private::SymbolContext&
+SBSymbolContext::ref()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new SymbolContext);
+ return *m_opaque_ap.get();
+}
+
+lldb_private::SymbolContext *
+SBSymbolContext::get() const
+{
+ return m_opaque_ap.get();
+}
+
+bool
+SBSymbolContext::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ m_opaque_ap->GetDescription (&strm, lldb::eDescriptionLevelFull, NULL);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+SBSymbolContext
+SBSymbolContext::GetParentOfInlinedScope (const SBAddress &curr_frame_pc,
+ SBAddress &parent_frame_addr) const
+{
+ SBSymbolContext sb_sc;
+ if (m_opaque_ap.get() && curr_frame_pc.IsValid())
+ {
+ if (m_opaque_ap->GetParentOfInlinedScope (curr_frame_pc.ref(), sb_sc.ref(), parent_frame_addr.ref()))
+ return sb_sc;
+ }
+ return SBSymbolContext();
+}
+
diff --git a/source/API/SBSymbolContextList.cpp b/source/API/SBSymbolContextList.cpp
new file mode 100644
index 000000000000..0730096c5f3c
--- /dev/null
+++ b/source/API/SBSymbolContextList.cpp
@@ -0,0 +1,117 @@
+//===-- SBSymbolContextList.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/SBSymbolContextList.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBSymbolContextList::SBSymbolContextList () :
+ m_opaque_ap (new SymbolContextList())
+{
+}
+
+SBSymbolContextList::SBSymbolContextList (const SBSymbolContextList& rhs) :
+ m_opaque_ap (new SymbolContextList(*rhs.m_opaque_ap))
+{
+}
+
+SBSymbolContextList::~SBSymbolContextList ()
+{
+}
+
+const SBSymbolContextList &
+SBSymbolContextList::operator = (const SBSymbolContextList &rhs)
+{
+ if (this != &rhs)
+ {
+ *m_opaque_ap = *rhs.m_opaque_ap;
+ }
+ return *this;
+}
+
+uint32_t
+SBSymbolContextList::GetSize() const
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetSize();
+ return 0;
+}
+
+SBSymbolContext
+SBSymbolContextList::GetContextAtIndex (uint32_t idx)
+{
+ SBSymbolContext sb_sc;
+ if (m_opaque_ap.get())
+ {
+ SymbolContext sc;
+ if (m_opaque_ap->GetContextAtIndex (idx, sc))
+ {
+ sb_sc.SetSymbolContext(&sc);
+ }
+ }
+ return sb_sc;
+}
+
+void
+SBSymbolContextList::Clear()
+{
+ if (m_opaque_ap.get())
+ m_opaque_ap->Clear();
+}
+
+void
+SBSymbolContextList::Append(SBSymbolContext &sc)
+{
+ if (sc.IsValid() && m_opaque_ap.get())
+ m_opaque_ap->Append(*sc);
+}
+
+void
+SBSymbolContextList::Append(SBSymbolContextList &sc_list)
+{
+ if (sc_list.IsValid() && m_opaque_ap.get())
+ m_opaque_ap->Append(*sc_list);
+}
+
+
+bool
+SBSymbolContextList::IsValid () const
+{
+ return m_opaque_ap.get() != NULL;
+}
+
+
+
+lldb_private::SymbolContextList*
+SBSymbolContextList::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+
+lldb_private::SymbolContextList&
+SBSymbolContextList::operator*() const
+{
+ assert (m_opaque_ap.get());
+ return *m_opaque_ap.get();
+}
+
+bool
+SBSymbolContextList::GetDescription (lldb::SBStream &description)
+{
+ Stream &strm = description.ref();
+ if (m_opaque_ap.get())
+ m_opaque_ap->GetDescription (&strm, lldb::eDescriptionLevelFull, NULL);
+ return true;
+}
+
+
diff --git a/source/API/SBTarget.cpp b/source/API/SBTarget.cpp
new file mode 100644
index 000000000000..f37c8f8a614b
--- /dev/null
+++ b/source/API/SBTarget.cpp
@@ -0,0 +1,2660 @@
+//===-- SBTarget.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/SBTarget.h"
+
+#include "lldb/lldb-public.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBModule.h"
+#include "lldb/API/SBModuleSpec.h"
+#include "lldb/API/SBSourceManager.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBSymbolContextList.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/BreakpointList.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressResolver.h"
+#include "lldb/Core/AddressResolverName.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/STLUtils.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "../source/Commands/CommandObjectBreakpoint.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+SBLaunchInfo::SBLaunchInfo (const char **argv) :
+ m_opaque_sp(new ProcessLaunchInfo())
+{
+ m_opaque_sp->GetFlags().Reset (eLaunchFlagDebug | eLaunchFlagDisableASLR);
+ if (argv && argv[0])
+ m_opaque_sp->GetArguments().SetArguments(argv);
+}
+
+SBLaunchInfo::~SBLaunchInfo()
+{
+}
+
+lldb_private::ProcessLaunchInfo &
+SBLaunchInfo::ref ()
+{
+ return *m_opaque_sp;
+}
+
+
+uint32_t
+SBLaunchInfo::GetUserID()
+{
+ return m_opaque_sp->GetUserID();
+}
+
+uint32_t
+SBLaunchInfo::GetGroupID()
+{
+ return m_opaque_sp->GetGroupID();
+}
+
+bool
+SBLaunchInfo::UserIDIsValid ()
+{
+ return m_opaque_sp->UserIDIsValid();
+}
+
+bool
+SBLaunchInfo::GroupIDIsValid ()
+{
+ return m_opaque_sp->GroupIDIsValid();
+}
+
+void
+SBLaunchInfo::SetUserID (uint32_t uid)
+{
+ m_opaque_sp->SetUserID (uid);
+}
+
+void
+SBLaunchInfo::SetGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetGroupID (gid);
+}
+
+uint32_t
+SBLaunchInfo::GetNumArguments ()
+{
+ return m_opaque_sp->GetArguments().GetArgumentCount();
+}
+
+const char *
+SBLaunchInfo::GetArgumentAtIndex (uint32_t idx)
+{
+ return m_opaque_sp->GetArguments().GetArgumentAtIndex(idx);
+}
+
+void
+SBLaunchInfo::SetArguments (const char **argv, bool append)
+{
+ if (append)
+ {
+ if (argv)
+ m_opaque_sp->GetArguments().AppendArguments(argv);
+ }
+ else
+ {
+ if (argv)
+ m_opaque_sp->GetArguments().SetArguments(argv);
+ else
+ m_opaque_sp->GetArguments().Clear();
+ }
+}
+
+uint32_t
+SBLaunchInfo::GetNumEnvironmentEntries ()
+{
+ return m_opaque_sp->GetEnvironmentEntries().GetArgumentCount();
+}
+
+const char *
+SBLaunchInfo::GetEnvironmentEntryAtIndex (uint32_t idx)
+{
+ return m_opaque_sp->GetEnvironmentEntries().GetArgumentAtIndex(idx);
+}
+
+void
+SBLaunchInfo::SetEnvironmentEntries (const char **envp, bool append)
+{
+ if (append)
+ {
+ if (envp)
+ m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp);
+ }
+ else
+ {
+ if (envp)
+ m_opaque_sp->GetEnvironmentEntries().SetArguments(envp);
+ else
+ m_opaque_sp->GetEnvironmentEntries().Clear();
+ }
+}
+
+void
+SBLaunchInfo::Clear ()
+{
+ m_opaque_sp->Clear();
+}
+
+const char *
+SBLaunchInfo::GetWorkingDirectory () const
+{
+ return m_opaque_sp->GetWorkingDirectory();
+}
+
+void
+SBLaunchInfo::SetWorkingDirectory (const char *working_dir)
+{
+ m_opaque_sp->SetWorkingDirectory(working_dir);
+}
+
+uint32_t
+SBLaunchInfo::GetLaunchFlags ()
+{
+ return m_opaque_sp->GetFlags().Get();
+}
+
+void
+SBLaunchInfo::SetLaunchFlags (uint32_t flags)
+{
+ m_opaque_sp->GetFlags().Reset(flags);
+}
+
+const char *
+SBLaunchInfo::GetProcessPluginName ()
+{
+ return m_opaque_sp->GetProcessPluginName();
+}
+
+void
+SBLaunchInfo::SetProcessPluginName (const char *plugin_name)
+{
+ return m_opaque_sp->SetProcessPluginName (plugin_name);
+}
+
+const char *
+SBLaunchInfo::GetShell ()
+{
+ return m_opaque_sp->GetShell();
+}
+
+void
+SBLaunchInfo::SetShell (const char * path)
+{
+ m_opaque_sp->SetShell (path);
+}
+
+uint32_t
+SBLaunchInfo::GetResumeCount ()
+{
+ return m_opaque_sp->GetResumeCount();
+}
+
+void
+SBLaunchInfo::SetResumeCount (uint32_t c)
+{
+ m_opaque_sp->SetResumeCount (c);
+}
+
+bool
+SBLaunchInfo::AddCloseFileAction (int fd)
+{
+ return m_opaque_sp->AppendCloseFileAction(fd);
+}
+
+bool
+SBLaunchInfo::AddDuplicateFileAction (int fd, int dup_fd)
+{
+ return m_opaque_sp->AppendDuplicateFileAction(fd, dup_fd);
+}
+
+bool
+SBLaunchInfo::AddOpenFileAction (int fd, const char *path, bool read, bool write)
+{
+ return m_opaque_sp->AppendOpenFileAction(fd, path, read, write);
+}
+
+bool
+SBLaunchInfo::AddSuppressFileAction (int fd, bool read, bool write)
+{
+ return m_opaque_sp->AppendSuppressFileAction(fd, read, write);
+}
+
+
+SBAttachInfo::SBAttachInfo () :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+}
+
+SBAttachInfo::SBAttachInfo (lldb::pid_t pid) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+SBAttachInfo::SBAttachInfo (const char *path, bool wait_for) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ m_opaque_sp->SetWaitForLaunch (wait_for);
+}
+
+SBAttachInfo::SBAttachInfo (const SBAttachInfo &rhs) :
+ m_opaque_sp (new ProcessAttachInfo())
+{
+ *m_opaque_sp = *rhs.m_opaque_sp;
+}
+
+SBAttachInfo::~SBAttachInfo()
+{
+}
+
+lldb_private::ProcessAttachInfo &
+SBAttachInfo::ref ()
+{
+ return *m_opaque_sp;
+}
+
+SBAttachInfo &
+SBAttachInfo::operator = (const SBAttachInfo &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_sp = *rhs.m_opaque_sp;
+ return *this;
+}
+
+lldb::pid_t
+SBAttachInfo::GetProcessID ()
+{
+ return m_opaque_sp->GetProcessID();
+}
+
+void
+SBAttachInfo::SetProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetProcessID (pid);
+}
+
+
+uint32_t
+SBAttachInfo::GetResumeCount ()
+{
+ return m_opaque_sp->GetResumeCount();
+}
+
+void
+SBAttachInfo::SetResumeCount (uint32_t c)
+{
+ m_opaque_sp->SetResumeCount (c);
+}
+
+const char *
+SBAttachInfo::GetProcessPluginName ()
+{
+ return m_opaque_sp->GetProcessPluginName();
+}
+
+void
+SBAttachInfo::SetProcessPluginName (const char *plugin_name)
+{
+ return m_opaque_sp->SetProcessPluginName (plugin_name);
+}
+
+void
+SBAttachInfo::SetExecutable (const char *path)
+{
+ if (path && path[0])
+ m_opaque_sp->GetExecutableFile().SetFile(path, false);
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+void
+SBAttachInfo::SetExecutable (SBFileSpec exe_file)
+{
+ if (exe_file.IsValid())
+ m_opaque_sp->GetExecutableFile() = exe_file.ref();
+ else
+ m_opaque_sp->GetExecutableFile().Clear();
+}
+
+bool
+SBAttachInfo::GetWaitForLaunch ()
+{
+ return m_opaque_sp->GetWaitForLaunch();
+}
+
+void
+SBAttachInfo::SetWaitForLaunch (bool b)
+{
+ m_opaque_sp->SetWaitForLaunch (b);
+}
+
+bool
+SBAttachInfo::GetIgnoreExisting ()
+{
+ return m_opaque_sp->GetIgnoreExisting();
+}
+
+void
+SBAttachInfo::SetIgnoreExisting (bool b)
+{
+ m_opaque_sp->SetIgnoreExisting (b);
+}
+
+uint32_t
+SBAttachInfo::GetUserID()
+{
+ return m_opaque_sp->GetUserID();
+}
+
+uint32_t
+SBAttachInfo::GetGroupID()
+{
+ return m_opaque_sp->GetGroupID();
+}
+
+bool
+SBAttachInfo::UserIDIsValid ()
+{
+ return m_opaque_sp->UserIDIsValid();
+}
+
+bool
+SBAttachInfo::GroupIDIsValid ()
+{
+ return m_opaque_sp->GroupIDIsValid();
+}
+
+void
+SBAttachInfo::SetUserID (uint32_t uid)
+{
+ m_opaque_sp->SetUserID (uid);
+}
+
+void
+SBAttachInfo::SetGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetGroupID (gid);
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveUserID()
+{
+ return m_opaque_sp->GetEffectiveUserID();
+}
+
+uint32_t
+SBAttachInfo::GetEffectiveGroupID()
+{
+ return m_opaque_sp->GetEffectiveGroupID();
+}
+
+bool
+SBAttachInfo::EffectiveUserIDIsValid ()
+{
+ return m_opaque_sp->EffectiveUserIDIsValid();
+}
+
+bool
+SBAttachInfo::EffectiveGroupIDIsValid ()
+{
+ return m_opaque_sp->EffectiveGroupIDIsValid ();
+}
+
+void
+SBAttachInfo::SetEffectiveUserID (uint32_t uid)
+{
+ m_opaque_sp->SetEffectiveUserID(uid);
+}
+
+void
+SBAttachInfo::SetEffectiveGroupID (uint32_t gid)
+{
+ m_opaque_sp->SetEffectiveGroupID(gid);
+}
+
+lldb::pid_t
+SBAttachInfo::GetParentProcessID ()
+{
+ return m_opaque_sp->GetParentProcessID();
+}
+
+void
+SBAttachInfo::SetParentProcessID (lldb::pid_t pid)
+{
+ m_opaque_sp->SetParentProcessID (pid);
+}
+
+bool
+SBAttachInfo::ParentProcessIDIsValid()
+{
+ return m_opaque_sp->ParentProcessIDIsValid();
+}
+
+
+//----------------------------------------------------------------------
+// SBTarget constructor
+//----------------------------------------------------------------------
+SBTarget::SBTarget () :
+ m_opaque_sp ()
+{
+}
+
+SBTarget::SBTarget (const SBTarget& rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+SBTarget::SBTarget(const TargetSP& target_sp) :
+ m_opaque_sp (target_sp)
+{
+}
+
+const SBTarget&
+SBTarget::operator = (const SBTarget& rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBTarget::~SBTarget()
+{
+}
+
+const char *
+SBTarget::GetBroadcasterClassName ()
+{
+ return Target::GetStaticBroadcasterClass().AsCString();
+}
+
+bool
+SBTarget::IsValid () const
+{
+ return m_opaque_sp.get() != NULL && m_opaque_sp->IsValid();
+}
+
+SBProcess
+SBTarget::GetProcess ()
+{
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ process_sp = target_sp->GetProcessSP();
+ sb_process.SetSP (process_sp);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::GetProcess () => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+
+ return sb_process;
+}
+
+SBDebugger
+SBTarget::GetDebugger () const
+{
+ SBDebugger debugger;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ debugger.reset (target_sp->GetDebugger().shared_from_this());
+ return debugger;
+}
+
+SBProcess
+SBTarget::LoadCore (const char *core_file)
+{
+ SBProcess sb_process;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ FileSpec filespec(core_file, true);
+ ProcessSP process_sp (target_sp->CreateProcess(target_sp->GetDebugger().GetListener(),
+ NULL,
+ &filespec));
+ if (process_sp)
+ {
+ process_sp->LoadCore();
+ sb_process.SetSP (process_sp);
+ }
+ }
+ return sb_process;
+}
+
+SBProcess
+SBTarget::LaunchSimple
+(
+ char const **argv,
+ char const **envp,
+ const char *working_directory
+)
+{
+ char *stdin_path = NULL;
+ char *stdout_path = NULL;
+ char *stderr_path = NULL;
+ uint32_t launch_flags = 0;
+ bool stop_at_entry = false;
+ SBError error;
+ SBListener listener = GetDebugger().GetListener();
+ return Launch (listener,
+ argv,
+ envp,
+ stdin_path,
+ stdout_path,
+ stderr_path,
+ working_directory,
+ launch_flags,
+ stop_at_entry,
+ error);
+}
+
+SBProcess
+SBTarget::Launch
+(
+ SBListener &listener,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_directory,
+ uint32_t launch_flags, // See LaunchFlags
+ bool stop_at_entry,
+ lldb::SBError& error
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Launch (argv=%p, envp=%p, stdin=%s, stdout=%s, stderr=%s, working-dir=%s, launch_flags=0x%x, stop_at_entry=%i, &error (%p))...",
+ target_sp.get(),
+ argv,
+ envp,
+ stdin_path ? stdin_path : "NULL",
+ stdout_path ? stdout_path : "NULL",
+ stderr_path ? stderr_path : "NULL",
+ working_directory ? working_directory : "NULL",
+ launch_flags,
+ stop_at_entry,
+ error.get());
+ }
+
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ if (getenv("LLDB_LAUNCH_FLAG_DISABLE_ASLR"))
+ launch_flags |= eLaunchFlagDisableASLR;
+
+ StateType state = eStateInvalid;
+ process_sp = target_sp->GetProcessSP();
+ if (process_sp)
+ {
+ state = process_sp->GetState();
+
+ if (process_sp->IsAlive() && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ error.SetErrorString ("process attach is in progress");
+ else
+ error.SetErrorString ("a process is already being debugged");
+ return sb_process;
+ }
+ }
+
+ if (state == eStateConnected)
+ {
+ // If we are already connected, then we have already specified the
+ // listener, so if a valid listener is supplied, we need to error out
+ // to let the client know.
+ if (listener.IsValid())
+ {
+ error.SetErrorString ("process is connected and already has a listener, pass empty listener");
+ return sb_process;
+ }
+ }
+ else
+ {
+ if (listener.IsValid())
+ process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
+ else
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
+ }
+
+ if (process_sp)
+ {
+ sb_process.SetSP (process_sp);
+ if (getenv("LLDB_LAUNCH_FLAG_DISABLE_STDIO"))
+ launch_flags |= eLaunchFlagDisableSTDIO;
+
+ ProcessLaunchInfo launch_info (stdin_path, stdout_path, stderr_path, working_directory, launch_flags);
+
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ if (argv)
+ launch_info.GetArguments().AppendArguments (argv);
+ if (envp)
+ launch_info.GetEnvironmentEntries ().SetArguments (envp);
+
+ error.SetError (process_sp->Launch (launch_info));
+ if (error.Success())
+ {
+ // We we are stopping at the entry point, we can return now!
+ if (stop_at_entry)
+ return sb_process;
+
+ // Make sure we are stopped at the entry
+ StateType state = process_sp->WaitForProcessToStop (NULL);
+ if (state == eStateStopped)
+ {
+ // resume the process to skip the entry point
+ error.SetError (process_sp->Resume());
+ if (error.Success())
+ {
+ // If we are doing synchronous mode, then wait for the
+ // process to stop yet again!
+ if (target_sp->GetDebugger().GetAsyncExecution () == false)
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+
+ return sb_process;
+}
+
+SBProcess
+SBTarget::Launch (SBLaunchInfo &sb_launch_info, SBError& error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Launch (launch_info, error)...", target_sp.get());
+ }
+
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ StateType state = eStateInvalid;
+ process_sp = target_sp->GetProcessSP();
+ if (process_sp)
+ {
+ state = process_sp->GetState();
+
+ if (process_sp->IsAlive() && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ error.SetErrorString ("process attach is in progress");
+ else
+ error.SetErrorString ("a process is already being debugged");
+ return sb_process;
+ }
+ }
+
+ if (state != eStateConnected)
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
+
+ if (process_sp)
+ {
+ sb_process.SetSP (process_sp);
+ lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref();
+
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+
+ const ArchSpec &arch_spec = target_sp->GetArchitecture();
+ if (arch_spec.IsValid())
+ launch_info.GetArchitecture () = arch_spec;
+
+ error.SetError (process_sp->Launch (launch_info));
+ const bool synchronous_execution = target_sp->GetDebugger().GetAsyncExecution () == false;
+ if (error.Success())
+ {
+ if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
+ {
+ // If we are doing synchronous mode, then wait for the initial
+ // stop to happen, else, return and let the caller watch for
+ // the stop
+ if (synchronous_execution)
+ process_sp->WaitForProcessToStop (NULL);
+ // We we are stopping at the entry point, we can return now!
+ return sb_process;
+ }
+
+ // Make sure we are stopped at the entry
+ StateType state = process_sp->WaitForProcessToStop (NULL);
+ if (state == eStateStopped)
+ {
+ // resume the process to skip the entry point
+ error.SetError (process_sp->Resume());
+ if (error.Success())
+ {
+ // If we are doing synchronous mode, then wait for the
+ // process to stop yet again!
+ if (synchronous_execution)
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API);
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Launch (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+
+ return sb_process;
+}
+
+lldb::SBProcess
+SBTarget::Attach (SBAttachInfo &sb_attach_info, SBError& error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Attach (sb_attach_info, error)...", target_sp.get());
+ }
+
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ StateType state = eStateInvalid;
+ process_sp = target_sp->GetProcessSP();
+ if (process_sp)
+ {
+ state = process_sp->GetState();
+
+ if (process_sp->IsAlive() && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ error.SetErrorString ("process attach is in progress");
+ else
+ error.SetErrorString ("a process is already being debugged");
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Attach (...) => error %s",
+ target_sp.get(), error.GetCString());
+ }
+ return sb_process;
+ }
+ }
+
+ if (state != eStateConnected)
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
+
+ if (process_sp)
+ {
+ ProcessAttachInfo &attach_info = sb_attach_info.ref();
+ if (attach_info.ProcessIDIsValid() && !attach_info.UserIDIsValid())
+ {
+ PlatformSP platform_sp = target_sp->GetPlatform();
+ // See if we can pre-verify if a process exists or not
+ if (platform_sp && platform_sp->IsConnected())
+ {
+ lldb::pid_t attach_pid = attach_info.GetProcessID();
+ ProcessInstanceInfo instance_info;
+ if (platform_sp->GetProcessInfo(attach_pid, instance_info))
+ {
+ attach_info.SetUserID(instance_info.GetEffectiveUserID());
+ }
+ else
+ {
+ error.ref().SetErrorStringWithFormat("no process found with process ID %" PRIu64, attach_pid);
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Attach (...) => error %s",
+ target_sp.get(), error.GetCString());
+ }
+ return sb_process;
+ }
+ }
+ }
+ error.SetError (process_sp->Attach (attach_info));
+ if (error.Success())
+ {
+ sb_process.SetSP (process_sp);
+ // If we are doing synchronous mode, then wait for the
+ // process to stop!
+ if (target_sp->GetDebugger().GetAsyncExecution () == false)
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::Attach (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+
+ return sb_process;
+}
+
+
+#if defined(__APPLE__)
+
+lldb::SBProcess
+SBTarget::AttachToProcessWithID (SBListener &listener,
+ ::pid_t pid,
+ lldb::SBError& error)
+{
+ return AttachToProcessWithID (listener, (lldb::pid_t)pid, error);
+}
+
+#endif // #if defined(__APPLE__)
+
+lldb::SBProcess
+SBTarget::AttachToProcessWithID
+(
+ SBListener &listener,
+ lldb::pid_t pid,// The process ID to attach to
+ SBError& error // An error explaining what went wrong if attach fails
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::AttachToProcessWithID (listener, pid=%" PRId64 ", error)...", target_sp.get(), pid);
+ }
+
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ StateType state = eStateInvalid;
+ process_sp = target_sp->GetProcessSP();
+ if (process_sp)
+ {
+ state = process_sp->GetState();
+
+ if (process_sp->IsAlive() && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ error.SetErrorString ("process attach is in progress");
+ else
+ error.SetErrorString ("a process is already being debugged");
+ return sb_process;
+ }
+ }
+
+ if (state == eStateConnected)
+ {
+ // If we are already connected, then we have already specified the
+ // listener, so if a valid listener is supplied, we need to error out
+ // to let the client know.
+ if (listener.IsValid())
+ {
+ error.SetErrorString ("process is connected and already has a listener, pass empty listener");
+ return sb_process;
+ }
+ }
+ else
+ {
+ if (listener.IsValid())
+ process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
+ else
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
+ }
+ if (process_sp)
+ {
+ sb_process.SetSP (process_sp);
+
+ ProcessAttachInfo attach_info;
+ attach_info.SetProcessID (pid);
+
+ PlatformSP platform_sp = target_sp->GetPlatform();
+ ProcessInstanceInfo instance_info;
+ if (platform_sp->GetProcessInfo(pid, instance_info))
+ {
+ attach_info.SetUserID(instance_info.GetEffectiveUserID());
+ }
+ error.SetError (process_sp->Attach (attach_info));
+ if (error.Success())
+ {
+ // If we are doing synchronous mode, then wait for the
+ // process to stop!
+ if (target_sp->GetDebugger().GetAsyncExecution () == false)
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::AttachToProcessWithID (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+ return sb_process;
+}
+
+lldb::SBProcess
+SBTarget::AttachToProcessWithName
+(
+ SBListener &listener,
+ const char *name, // basename of process to attach to
+ bool wait_for, // if true wait for a new instance of "name" to be launched
+ SBError& error // An error explaining what went wrong if attach fails
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::AttachToProcessWithName (listener, name=%s, wait_for=%s, error)...", target_sp.get(), name, wait_for ? "true" : "false");
+ }
+
+ if (name && target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ StateType state = eStateInvalid;
+ process_sp = target_sp->GetProcessSP();
+ if (process_sp)
+ {
+ state = process_sp->GetState();
+
+ if (process_sp->IsAlive() && state != eStateConnected)
+ {
+ if (state == eStateAttaching)
+ error.SetErrorString ("process attach is in progress");
+ else
+ error.SetErrorString ("a process is already being debugged");
+ return sb_process;
+ }
+ }
+
+ if (state == eStateConnected)
+ {
+ // If we are already connected, then we have already specified the
+ // listener, so if a valid listener is supplied, we need to error out
+ // to let the client know.
+ if (listener.IsValid())
+ {
+ error.SetErrorString ("process is connected and already has a listener, pass empty listener");
+ return sb_process;
+ }
+ }
+ else
+ {
+ if (listener.IsValid())
+ process_sp = target_sp->CreateProcess (listener.ref(), NULL, NULL);
+ else
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), NULL, NULL);
+ }
+
+ if (process_sp)
+ {
+ sb_process.SetSP (process_sp);
+ ProcessAttachInfo attach_info;
+ attach_info.GetExecutableFile().SetFile(name, false);
+ attach_info.SetWaitForLaunch(wait_for);
+ error.SetError (process_sp->Attach (attach_info));
+ if (error.Success())
+ {
+ // If we are doing synchronous mode, then wait for the
+ // process to stop!
+ if (target_sp->GetDebugger().GetAsyncExecution () == false)
+ process_sp->WaitForProcessToStop (NULL);
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::AttachToPorcessWithName (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+ return sb_process;
+}
+
+lldb::SBProcess
+SBTarget::ConnectRemote
+(
+ SBListener &listener,
+ const char *url,
+ const char *plugin_name,
+ SBError& error
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ TargetSP target_sp(GetSP());
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::ConnectRemote (listener, url=%s, plugin_name=%s, error)...", target_sp.get(), url, plugin_name);
+ }
+
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ if (listener.IsValid())
+ process_sp = target_sp->CreateProcess (listener.ref(), plugin_name, NULL);
+ else
+ process_sp = target_sp->CreateProcess (target_sp->GetDebugger().GetListener(), plugin_name, NULL);
+
+
+ if (process_sp)
+ {
+ sb_process.SetSP (process_sp);
+ error.SetError (process_sp->ConnectRemote (NULL, url));
+ }
+ else
+ {
+ error.SetErrorString ("unable to create lldb_private::Process");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("SBTarget is invalid");
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::ConnectRemote (...) => SBProcess(%p)",
+ target_sp.get(), process_sp.get());
+ }
+ return sb_process;
+}
+
+SBFileSpec
+SBTarget::GetExecutable ()
+{
+
+ SBFileSpec exe_file_spec;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module)
+ exe_file_spec.SetFileSpec (exe_module->GetFileSpec());
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::GetExecutable () => SBFileSpec(%p)",
+ target_sp.get(), exe_file_spec.get());
+ }
+
+ return exe_file_spec;
+}
+
+bool
+SBTarget::operator == (const SBTarget &rhs) const
+{
+ return m_opaque_sp.get() == rhs.m_opaque_sp.get();
+}
+
+bool
+SBTarget::operator != (const SBTarget &rhs) const
+{
+ return m_opaque_sp.get() != rhs.m_opaque_sp.get();
+}
+
+lldb::TargetSP
+SBTarget::GetSP () const
+{
+ return m_opaque_sp;
+}
+
+void
+SBTarget::SetSP (const lldb::TargetSP& target_sp)
+{
+ m_opaque_sp = target_sp;
+}
+
+lldb::SBAddress
+SBTarget::ResolveLoadAddress (lldb::addr_t vm_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->GetSectionLoadList().ResolveLoadAddress (vm_addr, addr))
+ return sb_addr;
+ }
+
+ // We have a load address that isn't in a section, just return an address
+ // with the offset filled in (the address) and the section set to NULL
+ addr.SetRawAddress(vm_addr);
+ return sb_addr;
+}
+
+SBSymbolContext
+SBTarget::ResolveSymbolContextForAddress (const SBAddress& addr, uint32_t resolve_scope)
+{
+ SBSymbolContext sc;
+ if (addr.IsValid())
+ {
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ target_sp->GetImages().ResolveSymbolContextForAddress (addr.ref(), resolve_scope, sc.ref());
+ }
+ return sc;
+}
+
+
+SBBreakpoint
+SBTarget::BreakpointCreateByLocation (const char *file, uint32_t line)
+{
+ return SBBreakpoint(BreakpointCreateByLocation (SBFileSpec (file, false), line));
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByLocation (const SBFileSpec &sb_file_spec, uint32_t line)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && line != 0)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ const LazyBool check_inlines = eLazyBoolCalculate;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+ const bool internal = false;
+ *sb_bp = target_sp->CreateBreakpoint (NULL, *sb_file_spec, line, check_inlines, skip_prologue, internal);
+ }
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_bp.GetDescription (sstr);
+ char path[PATH_MAX];
+ sb_file_spec->GetPath (path, sizeof(path));
+ log->Printf ("SBTarget(%p)::BreakpointCreateByLocation ( %s:%u ) => SBBreakpoint(%p): %s",
+ target_sp.get(),
+ path,
+ line,
+ sb_bp.get(),
+ sstr.GetData());
+ }
+
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByName (const char *symbol_name, const char *module_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp.get())
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+
+ const bool internal = false;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+ if (module_name && module_name[0])
+ {
+ FileSpecList module_spec_list;
+ module_spec_list.Append (FileSpec (module_name, false));
+ *sb_bp = target_sp->CreateBreakpoint (&module_spec_list, NULL, symbol_name, eFunctionNameTypeAuto, skip_prologue, internal);
+ }
+ else
+ {
+ *sb_bp = target_sp->CreateBreakpoint (NULL, NULL, symbol_name, eFunctionNameTypeAuto, skip_prologue, internal);
+ }
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", module=\"%s\") => SBBreakpoint(%p)",
+ target_sp.get(), symbol_name, module_name, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateByName (const char *symbol_name,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list)
+{
+ uint32_t name_type_mask = eFunctionNameTypeAuto;
+ return BreakpointCreateByName (symbol_name, name_type_mask, module_list, comp_unit_list);
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateByName (const char *symbol_name,
+ uint32_t name_type_mask,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && symbol_name && symbol_name[0])
+ {
+ const bool internal = false;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ *sb_bp = target_sp->CreateBreakpoint (module_list.get(),
+ comp_unit_list.get(),
+ symbol_name,
+ name_type_mask,
+ skip_prologue,
+ internal);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbol=\"%s\", name_type: %d) => SBBreakpoint(%p)",
+ target_sp.get(), symbol_name, name_type_mask, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateByNames (const char *symbol_names[],
+ uint32_t num_names,
+ uint32_t name_type_mask,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && num_names > 0)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ const bool internal = false;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+ *sb_bp = target_sp->CreateBreakpoint (module_list.get(),
+ comp_unit_list.get(),
+ symbol_names,
+ num_names,
+ name_type_mask,
+ skip_prologue,
+ internal);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByName (symbols={", target_sp.get());
+ for (uint32_t i = 0 ; i < num_names; i++)
+ {
+ char sep;
+ if (i < num_names - 1)
+ sep = ',';
+ else
+ sep = '}';
+ if (symbol_names[i] != NULL)
+ log->Printf ("\"%s\"%c ", symbol_names[i], sep);
+ else
+ log->Printf ("\"<NULL>\"%c ", sep);
+
+ }
+ log->Printf ("name_type: %d) => SBBreakpoint(%p)", name_type_mask, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex, const char *module_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && symbol_name_regex && symbol_name_regex[0])
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ RegularExpression regexp(symbol_name_regex);
+ const bool internal = false;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+
+ if (module_name && module_name[0])
+ {
+ FileSpecList module_spec_list;
+ module_spec_list.Append (FileSpec (module_name, false));
+
+ *sb_bp = target_sp->CreateFuncRegexBreakpoint (&module_spec_list, NULL, regexp, skip_prologue, internal);
+ }
+ else
+ {
+ *sb_bp = target_sp->CreateFuncRegexBreakpoint (NULL, NULL, regexp, skip_prologue, internal);
+ }
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
+ target_sp.get(), symbol_name_regex, module_name, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateByRegex (const char *symbol_name_regex,
+ const SBFileSpecList &module_list,
+ const SBFileSpecList &comp_unit_list)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && symbol_name_regex && symbol_name_regex[0])
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ RegularExpression regexp(symbol_name_regex);
+ const bool internal = false;
+ const LazyBool skip_prologue = eLazyBoolCalculate;
+
+ *sb_bp = target_sp->CreateFuncRegexBreakpoint (module_list.get(), comp_unit_list.get(), regexp, skip_prologue, internal);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (symbol_regex=\"%s\") => SBBreakpoint(%p)",
+ target_sp.get(), symbol_name_regex, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+SBBreakpoint
+SBTarget::BreakpointCreateByAddress (addr_t address)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ *sb_bp = target_sp->CreateBreakpoint (address, false);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByAddress (address=%" PRIu64 ") => SBBreakpoint(%p)", target_sp.get(), (uint64_t) address, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateBySourceRegex (const char *source_regex, const lldb::SBFileSpec &source_file, const char *module_name)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && source_regex && source_regex[0])
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ RegularExpression regexp(source_regex);
+ FileSpecList source_file_spec_list;
+ source_file_spec_list.Append (source_file.ref());
+
+ if (module_name && module_name[0])
+ {
+ FileSpecList module_spec_list;
+ module_spec_list.Append (FileSpec (module_name, false));
+
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (&module_spec_list, &source_file_spec_list, regexp, false);
+ }
+ else
+ {
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (NULL, &source_file_spec_list, regexp, false);
+ }
+ }
+
+ if (log)
+ {
+ char path[PATH_MAX];
+ source_file->GetPath (path, sizeof(path));
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\", file=\"%s\", module_name=\"%s\") => SBBreakpoint(%p)",
+ target_sp.get(), source_regex, path, module_name, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateBySourceRegex (const char *source_regex,
+ const SBFileSpecList &module_list,
+ const lldb::SBFileSpecList &source_file_list)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && source_regex && source_regex[0])
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ RegularExpression regexp(source_regex);
+ *sb_bp = target_sp->CreateSourceRegexBreakpoint (module_list.get(), source_file_list.get(), regexp, false);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (source_regex=\"%s\") => SBBreakpoint(%p)",
+ target_sp.get(), source_regex, sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+lldb::SBBreakpoint
+SBTarget::BreakpointCreateForException (lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_bp;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ *sb_bp = target_sp->CreateExceptionBreakpoint (language, catch_bp, throw_bp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointCreateByRegex (Language: %s, catch: %s throw: %s) => SBBreakpoint(%p)",
+ target_sp.get(),
+ LanguageRuntime::GetNameForLanguageType(language),
+ catch_bp ? "on" : "off",
+ throw_bp ? "on" : "off",
+ sb_bp.get());
+ }
+
+ return sb_bp;
+}
+
+uint32_t
+SBTarget::GetNumBreakpoints () const
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The breakpoint list is thread safe, no need to lock
+ return target_sp->GetBreakpointList().GetSize();
+ }
+ return 0;
+}
+
+SBBreakpoint
+SBTarget::GetBreakpointAtIndex (uint32_t idx) const
+{
+ SBBreakpoint sb_breakpoint;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The breakpoint list is thread safe, no need to lock
+ *sb_breakpoint = target_sp->GetBreakpointList().GetBreakpointAtIndex(idx);
+ }
+ return sb_breakpoint;
+}
+
+bool
+SBTarget::BreakpointDelete (break_id_t bp_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool result = false;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ result = target_sp->RemoveBreakpointByID (bp_id);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::BreakpointDelete (bp_id=%d) => %i", target_sp.get(), (uint32_t) bp_id, result);
+ }
+
+ return result;
+}
+
+SBBreakpoint
+SBTarget::FindBreakpointByID (break_id_t bp_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBBreakpoint sb_breakpoint;
+ TargetSP target_sp(GetSP());
+ if (target_sp && bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ *sb_breakpoint = target_sp->GetBreakpointByID (bp_id);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::FindBreakpointByID (bp_id=%d) => SBBreakpoint(%p)",
+ target_sp.get(), (uint32_t) bp_id, sb_breakpoint.get());
+ }
+
+ return sb_breakpoint;
+}
+
+bool
+SBTarget::EnableAllBreakpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ target_sp->EnableAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DisableAllBreakpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ target_sp->DisableAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DeleteAllBreakpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ target_sp->RemoveAllBreakpoints ();
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+SBTarget::GetNumWatchpoints () const
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The watchpoint list is thread safe, no need to lock
+ return target_sp->GetWatchpointList().GetSize();
+ }
+ return 0;
+}
+
+SBWatchpoint
+SBTarget::GetWatchpointAtIndex (uint32_t idx) const
+{
+ SBWatchpoint sb_watchpoint;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The watchpoint list is thread safe, no need to lock
+ sb_watchpoint.SetSP (target_sp->GetWatchpointList().GetByIndex(idx));
+ }
+ return sb_watchpoint;
+}
+
+bool
+SBTarget::DeleteWatchpoint (watch_id_t wp_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ bool result = false;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ Mutex::Locker locker;
+ target_sp->GetWatchpointList().GetListMutex(locker);
+ result = target_sp->RemoveWatchpointByID (wp_id);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::WatchpointDelete (wp_id=%d) => %i", target_sp.get(), (uint32_t) wp_id, result);
+ }
+
+ return result;
+}
+
+SBWatchpoint
+SBTarget::FindWatchpointByID (lldb::watch_id_t wp_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBWatchpoint sb_watchpoint;
+ lldb::WatchpointSP watchpoint_sp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ Mutex::Locker locker;
+ target_sp->GetWatchpointList().GetListMutex(locker);
+ watchpoint_sp = target_sp->GetWatchpointList().FindByID(wp_id);
+ sb_watchpoint.SetSP (watchpoint_sp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::FindWatchpointByID (bp_id=%d) => SBWatchpoint(%p)",
+ target_sp.get(), (uint32_t) wp_id, watchpoint_sp.get());
+ }
+
+ return sb_watchpoint;
+}
+
+lldb::SBWatchpoint
+SBTarget::WatchAddress (lldb::addr_t addr, size_t size, bool read, bool write, SBError &error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBWatchpoint sb_watchpoint;
+ lldb::WatchpointSP watchpoint_sp;
+ TargetSP target_sp(GetSP());
+ if (target_sp && (read || write) && addr != LLDB_INVALID_ADDRESS && size > 0)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ uint32_t watch_type = 0;
+ if (read)
+ watch_type |= LLDB_WATCH_TYPE_READ;
+ if (write)
+ watch_type |= LLDB_WATCH_TYPE_WRITE;
+ if (watch_type == 0)
+ {
+ error.SetErrorString("Can't create a watchpoint that is neither read nor write.");
+ return sb_watchpoint;
+ }
+
+ // Target::CreateWatchpoint() is thread safe.
+ Error cw_error;
+ // This API doesn't take in a type, so we can't figure out what it is.
+ ClangASTType *type = NULL;
+ watchpoint_sp = target_sp->CreateWatchpoint(addr, size, type, watch_type, cw_error);
+ error.SetError(cw_error);
+ sb_watchpoint.SetSP (watchpoint_sp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::WatchAddress (addr=0x%" PRIx64 ", 0x%u) => SBWatchpoint(%p)",
+ target_sp.get(), addr, (uint32_t) size, watchpoint_sp.get());
+ }
+
+ return sb_watchpoint;
+}
+
+bool
+SBTarget::EnableAllWatchpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ Mutex::Locker locker;
+ target_sp->GetWatchpointList().GetListMutex(locker);
+ target_sp->EnableAllWatchpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DisableAllWatchpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ Mutex::Locker locker;
+ target_sp->GetWatchpointList().GetListMutex(locker);
+ target_sp->DisableAllWatchpoints ();
+ return true;
+ }
+ return false;
+}
+
+bool
+SBTarget::DeleteAllWatchpoints ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ Mutex::Locker locker;
+ target_sp->GetWatchpointList().GetListMutex(locker);
+ target_sp->RemoveAllWatchpoints ();
+ return true;
+ }
+ return false;
+}
+
+
+lldb::SBModule
+SBTarget::AddModule (const char *path,
+ const char *triple,
+ const char *uuid_cstr)
+{
+ return AddModule (path, triple, uuid_cstr, NULL);
+}
+
+lldb::SBModule
+SBTarget::AddModule (const char *path,
+ const char *triple,
+ const char *uuid_cstr,
+ const char *symfile)
+{
+ lldb::SBModule sb_module;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ModuleSpec module_spec;
+ if (path)
+ module_spec.GetFileSpec().SetFile(path, false);
+
+ if (uuid_cstr)
+ module_spec.GetUUID().SetFromCString(uuid_cstr);
+
+ if (triple)
+ module_spec.GetArchitecture().SetTriple (triple, target_sp->GetPlatform ().get());
+
+ if (symfile)
+ module_spec.GetSymbolFileSpec ().SetFile(symfile, false);
+
+ sb_module.SetSP(target_sp->GetSharedModule (module_spec));
+ }
+ return sb_module;
+}
+
+lldb::SBModule
+SBTarget::AddModule (const SBModuleSpec &module_spec)
+{
+ lldb::SBModule sb_module;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ sb_module.SetSP(target_sp->GetSharedModule (*module_spec.m_opaque_ap));
+ return sb_module;
+}
+
+bool
+SBTarget::AddModule (lldb::SBModule &module)
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ target_sp->GetImages().AppendIfNeeded (module.GetSP());
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+SBTarget::GetNumModules () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t num = 0;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The module list is thread safe, no need to lock
+ num = target_sp->GetImages().GetSize();
+ }
+
+ if (log)
+ log->Printf ("SBTarget(%p)::GetNumModules () => %d", target_sp.get(), num);
+
+ return num;
+}
+
+void
+SBTarget::Clear ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ log->Printf ("SBTarget(%p)::Clear ()", m_opaque_sp.get());
+
+ m_opaque_sp.reset();
+}
+
+
+SBModule
+SBTarget::FindModule (const SBFileSpec &sb_file_spec)
+{
+ SBModule sb_module;
+ TargetSP target_sp(GetSP());
+ if (target_sp && sb_file_spec.IsValid())
+ {
+ ModuleSpec module_spec(*sb_file_spec);
+ // The module list is thread safe, no need to lock
+ sb_module.SetSP (target_sp->GetImages().FindFirstModule (module_spec));
+ }
+ return sb_module;
+}
+
+lldb::ByteOrder
+SBTarget::GetByteOrder ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ return target_sp->GetArchitecture().GetByteOrder();
+ return eByteOrderInvalid;
+}
+
+const char *
+SBTarget::GetTriple ()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ std::string triple (target_sp->GetArchitecture().GetTriple().str());
+ // Unique the string so we don't run into ownership issues since
+ // the const strings put the string into the string pool once and
+ // the strings never comes out
+ ConstString const_triple (triple.c_str());
+ return const_triple.GetCString();
+ }
+ return NULL;
+}
+
+uint32_t
+SBTarget::GetAddressByteSize()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ return target_sp->GetArchitecture().GetAddressByteSize();
+ return sizeof(void*);
+}
+
+
+SBModule
+SBTarget::GetModuleAtIndex (uint32_t idx)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBModule sb_module;
+ ModuleSP module_sp;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ // The module list is thread safe, no need to lock
+ module_sp = target_sp->GetImages().GetModuleAtIndex(idx);
+ sb_module.SetSP (module_sp);
+ }
+
+ if (log)
+ {
+ log->Printf ("SBTarget(%p)::GetModuleAtIndex (idx=%d) => SBModule(%p)",
+ target_sp.get(), idx, module_sp.get());
+ }
+
+ return sb_module;
+}
+
+bool
+SBTarget::RemoveModule (lldb::SBModule module)
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ return target_sp->GetImages().Remove(module.GetSP());
+ return false;
+}
+
+
+SBBroadcaster
+SBTarget::GetBroadcaster () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ TargetSP target_sp(GetSP());
+ SBBroadcaster broadcaster(target_sp.get(), false);
+
+ if (log)
+ log->Printf ("SBTarget(%p)::GetBroadcaster () => SBBroadcaster(%p)",
+ target_sp.get(), broadcaster.get());
+
+ return broadcaster;
+}
+
+bool
+SBTarget::GetDescription (SBStream &description, lldb::DescriptionLevel description_level)
+{
+ Stream &strm = description.ref();
+
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ target_sp->Dump (&strm, description_level);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+lldb::SBSymbolContextList
+SBTarget::FindFunctions (const char *name, uint32_t name_type_mask)
+{
+ lldb::SBSymbolContextList sb_sc_list;
+ if (name && name[0])
+ {
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ const bool symbols_ok = true;
+ const bool inlines_ok = true;
+ const bool append = true;
+ target_sp->GetImages().FindFunctions (ConstString(name),
+ name_type_mask,
+ symbols_ok,
+ inlines_ok,
+ append,
+ *sb_sc_list);
+ }
+ }
+ return sb_sc_list;
+}
+
+lldb::SBType
+SBTarget::FindFirstType (const char* typename_cstr)
+{
+ TargetSP target_sp(GetSP());
+ if (typename_cstr && typename_cstr[0] && target_sp)
+ {
+ ConstString const_typename(typename_cstr);
+ SymbolContext sc;
+ const bool exact_match = false;
+
+ const ModuleList &module_list = target_sp->GetImages();
+ size_t count = module_list.GetSize();
+ for (size_t idx = 0; idx < count; idx++)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndex(idx));
+ if (module_sp)
+ {
+ TypeSP type_sp (module_sp->FindFirstType(sc, const_typename, exact_match));
+ if (type_sp)
+ return SBType(type_sp);
+ }
+ }
+
+ // Didn't find the type in the symbols; try the Objective-C runtime
+ // if one is installed
+
+ ProcessSP process_sp(target_sp->GetProcessSP());
+
+ if (process_sp)
+ {
+ ObjCLanguageRuntime *objc_language_runtime = process_sp->GetObjCLanguageRuntime();
+
+ if (objc_language_runtime)
+ {
+ TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
+
+ if (objc_type_vendor)
+ {
+ std::vector <ClangASTType> types;
+
+ if (objc_type_vendor->FindTypes(const_typename, true, 1, types) > 0)
+ return SBType(types[0]);
+ }
+ }
+ }
+
+ // No matches, search for basic typename matches
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast)
+ return SBType (ClangASTContext::GetBasicType (clang_ast->getASTContext(), const_typename));
+ }
+ return SBType();
+}
+
+SBType
+SBTarget::GetBasicType(lldb::BasicType type)
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast)
+ return SBType (ClangASTContext::GetBasicType (clang_ast->getASTContext(), type));
+ }
+ return SBType();
+}
+
+
+lldb::SBTypeList
+SBTarget::FindTypes (const char* typename_cstr)
+{
+ SBTypeList sb_type_list;
+ TargetSP target_sp(GetSP());
+ if (typename_cstr && typename_cstr[0] && target_sp)
+ {
+ ModuleList& images = target_sp->GetImages();
+ ConstString const_typename(typename_cstr);
+ bool exact_match = false;
+ SymbolContext sc;
+ TypeList type_list;
+
+ uint32_t num_matches = images.FindTypes (sc,
+ const_typename,
+ exact_match,
+ UINT32_MAX,
+ type_list);
+
+ if (num_matches > 0)
+ {
+ for (size_t idx = 0; idx < num_matches; idx++)
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(idx));
+ if (type_sp)
+ sb_type_list.Append(SBType(type_sp));
+ }
+ }
+
+ // Try the Objective-C runtime if one is installed
+
+ ProcessSP process_sp(target_sp->GetProcessSP());
+
+ if (process_sp)
+ {
+ ObjCLanguageRuntime *objc_language_runtime = process_sp->GetObjCLanguageRuntime();
+
+ if (objc_language_runtime)
+ {
+ TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
+
+ if (objc_type_vendor)
+ {
+ std::vector <ClangASTType> types;
+
+ if (objc_type_vendor->FindTypes(const_typename, true, UINT32_MAX, types))
+ {
+ for (ClangASTType &type : types)
+ {
+ sb_type_list.Append(SBType(type));
+ }
+ }
+ }
+ }
+ }
+
+ if (sb_type_list.GetSize() == 0)
+ {
+ // No matches, search for basic typename matches
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast)
+ sb_type_list.Append (SBType (ClangASTContext::GetBasicType (clang_ast->getASTContext(), const_typename)));
+ }
+ }
+ return sb_type_list;
+}
+
+SBValueList
+SBTarget::FindGlobalVariables (const char *name, uint32_t max_matches)
+{
+ SBValueList sb_value_list;
+
+ TargetSP target_sp(GetSP());
+ if (name && target_sp)
+ {
+ VariableList variable_list;
+ const bool append = true;
+ const uint32_t match_count = target_sp->GetImages().FindGlobalVariables (ConstString (name),
+ append,
+ max_matches,
+ variable_list);
+
+ 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)
+{
+ SBValueList sb_value_list(FindGlobalVariables(name, 1));
+ if (sb_value_list.IsValid() && sb_value_list.GetSize() > 0)
+ return sb_value_list.GetValueAtIndex(0);
+ return SBValue();
+}
+
+SBSourceManager
+SBTarget::GetSourceManager()
+{
+ SBSourceManager source_manager (*this);
+ return source_manager;
+}
+
+lldb::SBInstructionList
+SBTarget::ReadInstructions (lldb::SBAddress base_addr, uint32_t count)
+{
+ return ReadInstructions (base_addr, count, NULL);
+}
+
+lldb::SBInstructionList
+SBTarget::ReadInstructions (lldb::SBAddress base_addr, uint32_t count, const char *flavor_string)
+{
+ SBInstructionList sb_instructions;
+
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Address *addr_ptr = base_addr.get();
+
+ if (addr_ptr)
+ {
+ DataBufferHeap data (target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0);
+ bool prefer_file_cache = false;
+ lldb_private::Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target_sp->ReadMemory(*addr_ptr,
+ prefer_file_cache,
+ data.GetBytes(),
+ data.GetByteSize(),
+ error,
+ &load_addr);
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+ sb_instructions.SetDisassembler (Disassembler::DisassembleBytes (target_sp->GetArchitecture(),
+ NULL,
+ flavor_string,
+ *addr_ptr,
+ data.GetBytes(),
+ bytes_read,
+ count,
+ data_from_file));
+ }
+ }
+
+ return sb_instructions;
+
+}
+
+lldb::SBInstructionList
+SBTarget::GetInstructions (lldb::SBAddress base_addr, const void *buf, size_t size)
+{
+ return GetInstructionsWithFlavor (base_addr, NULL, buf, size);
+}
+
+lldb::SBInstructionList
+SBTarget::GetInstructionsWithFlavor (lldb::SBAddress base_addr, const char *flavor_string, const void *buf, size_t size)
+{
+ SBInstructionList sb_instructions;
+
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ Address addr;
+
+ if (base_addr.get())
+ addr = *base_addr.get();
+
+ const bool data_from_file = true;
+
+ sb_instructions.SetDisassembler (Disassembler::DisassembleBytes (target_sp->GetArchitecture(),
+ NULL,
+ flavor_string,
+ addr,
+ buf,
+ size,
+ UINT32_MAX,
+ data_from_file));
+ }
+
+ return sb_instructions;
+}
+
+lldb::SBInstructionList
+SBTarget::GetInstructions (lldb::addr_t base_addr, const void *buf, size_t size)
+{
+ return GetInstructionsWithFlavor (ResolveLoadAddress(base_addr), NULL, buf, size);
+}
+
+lldb::SBInstructionList
+SBTarget::GetInstructionsWithFlavor (lldb::addr_t base_addr, const char *flavor_string, const void *buf, size_t size)
+{
+ return GetInstructionsWithFlavor (ResolveLoadAddress(base_addr), flavor_string, buf, size);
+}
+
+SBError
+SBTarget::SetSectionLoadAddress (lldb::SBSection section,
+ lldb::addr_t section_base_addr)
+{
+ SBError sb_error;
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ if (!section.IsValid())
+ {
+ sb_error.SetErrorStringWithFormat ("invalid section");
+ }
+ else
+ {
+ SectionSP section_sp (section.GetSP());
+ if (section_sp)
+ {
+ if (section_sp->IsThreadSpecific())
+ {
+ sb_error.SetErrorString ("thread specific sections are not yet supported");
+ }
+ else
+ {
+ if (target_sp->GetSectionLoadList().SetSectionLoadAddress (section_sp, section_base_addr))
+ {
+ // Flush info in the process (stack frames, etc)
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Flush();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString ("invalid target");
+ }
+ return sb_error;
+}
+
+SBError
+SBTarget::ClearSectionLoadAddress (lldb::SBSection section)
+{
+ SBError sb_error;
+
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ if (!section.IsValid())
+ {
+ sb_error.SetErrorStringWithFormat ("invalid section");
+ }
+ else
+ {
+ if (target_sp->GetSectionLoadList().SetSectionUnloaded (section.GetSP()))
+ {
+ // Flush info in the process (stack frames, etc)
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Flush();
+ }
+ }
+ }
+ else
+ {
+ sb_error.SetErrorStringWithFormat ("invalid target");
+ }
+ return sb_error;
+}
+
+SBError
+SBTarget::SetModuleLoadAddress (lldb::SBModule module, int64_t slide_offset)
+{
+ SBError sb_error;
+
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ModuleSP module_sp (module.GetSP());
+ if (module_sp)
+ {
+ bool changed = false;
+ if (module_sp->SetLoadAddress (*target_sp, slide_offset, changed))
+ {
+ // The load was successful, make sure that at least some sections
+ // changed before we notify that our module was loaded.
+ if (changed)
+ {
+ ModuleList module_list;
+ module_list.Append(module_sp);
+ target_sp->ModulesDidLoad (module_list);
+ // Flush info in the process (stack frames, etc)
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Flush();
+ }
+ }
+ }
+ else
+ {
+ sb_error.SetErrorStringWithFormat ("invalid module");
+ }
+
+ }
+ else
+ {
+ sb_error.SetErrorStringWithFormat ("invalid target");
+ }
+ return sb_error;
+}
+
+SBError
+SBTarget::ClearModuleLoadAddress (lldb::SBModule module)
+{
+ SBError sb_error;
+
+ char path[PATH_MAX];
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ModuleSP module_sp (module.GetSP());
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ SectionList *section_list = objfile->GetSectionList();
+ if (section_list)
+ {
+ bool changed = false;
+ const size_t num_sections = section_list->GetSize();
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ SectionSP section_sp (section_list->GetSectionAtIndex(sect_idx));
+ if (section_sp)
+ changed |= target_sp->GetSectionLoadList().SetSectionUnloaded (section_sp) > 0;
+ }
+ if (changed)
+ {
+ // Flush info in the process (stack frames, etc)
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Flush();
+ }
+ }
+ else
+ {
+ module_sp->GetFileSpec().GetPath (path, sizeof(path));
+ sb_error.SetErrorStringWithFormat ("no sections in object file '%s'", path);
+ }
+ }
+ else
+ {
+ module_sp->GetFileSpec().GetPath (path, sizeof(path));
+ sb_error.SetErrorStringWithFormat ("no object file for module '%s'", path);
+ }
+ }
+ else
+ {
+ sb_error.SetErrorStringWithFormat ("invalid module");
+ }
+ }
+ else
+ {
+ sb_error.SetErrorStringWithFormat ("invalid target");
+ }
+ return sb_error;
+}
+
+
+lldb::SBSymbolContextList
+SBTarget::FindSymbols (const char *name, lldb::SymbolType symbol_type)
+{
+ SBSymbolContextList sb_sc_list;
+ if (name && name[0])
+ {
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ bool append = true;
+ target_sp->GetImages().FindSymbolsWithNameAndType (ConstString(name),
+ symbol_type,
+ *sb_sc_list,
+ append);
+ }
+ }
+ return sb_sc_list;
+
+}
+
+
+lldb::SBValue
+SBTarget::EvaluateExpression (const char *expr, const SBExpressionOptions &options)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ Log * expr_log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ SBValue expr_result;
+ ExecutionResults exe_results = eExecutionSetupError;
+ ValueObjectSP expr_value_sp;
+ TargetSP target_sp(GetSP());
+ StackFrame *frame = NULL;
+ if (target_sp)
+ {
+ if (expr == NULL || expr[0] == '\0')
+ {
+ if (log)
+ log->Printf ("SBTarget::EvaluateExpression called with an empty expression");
+ return expr_result;
+ }
+
+ Mutex::Locker api_locker (target_sp->GetAPIMutex());
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+
+ if (log)
+ log->Printf ("SBTarget()::EvaluateExpression (expr=\"%s\")...", expr);
+
+ frame = exe_ctx.GetFramePtr();
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (target)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ StreamString frame_description;
+ if (frame)
+ frame->DumpUsingSettingsFormat (&frame_description);
+ Host::SetCrashDescriptionWithFormat ("SBTarget::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s",
+ expr, options.GetFetchDynamicValue(), frame_description.GetString().c_str());
+#endif
+ exe_results = target->EvaluateExpression (expr,
+ frame,
+ expr_value_sp,
+ options.ref());
+
+ expr_result.SetSP(expr_value_sp, options.GetFetchDynamicValue());
+#ifdef LLDB_CONFIGURATION_DEBUG
+ Host::SetCrashDescription (NULL);
+#endif
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBTarget::EvaluateExpression () => error: could not reconstruct frame object for this SBTarget.");
+ }
+ }
+#ifndef LLDB_DISABLE_PYTHON
+ if (expr_log)
+ expr_log->Printf("** [SBTarget::EvaluateExpression] Expression result is %s, summary %s **",
+ expr_result.GetValue(),
+ expr_result.GetSummary());
+
+ if (log)
+ log->Printf ("SBTarget(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) (execution result=%d)",
+ frame,
+ expr,
+ expr_value_sp.get(),
+ exe_results);
+#endif
+
+ return expr_result;
+}
+
+
+lldb::addr_t
+SBTarget::GetStackRedZoneSize()
+{
+ TargetSP target_sp(GetSP());
+ if (target_sp)
+ {
+ ABISP abi_sp;
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ abi_sp = process_sp->GetABI();
+ else
+ abi_sp = ABI::FindPlugin(target_sp->GetArchitecture());
+ if (abi_sp)
+ return abi_sp->GetRedZoneSize();
+ }
+ return 0;
+}
+
diff --git a/source/API/SBThread.cpp b/source/API/SBThread.cpp
new file mode 100644
index 000000000000..2752620c9baf
--- /dev/null
+++ b/source/API/SBThread.cpp
@@ -0,0 +1,1229 @@
+//===-- 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/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.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/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/SBValue.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+SBThread::GetBroadcasterClassName ()
+{
+ return Thread::GetStaticBroadcasterClass().AsCString();
+}
+
+//----------------------------------------------------------------------
+// Constructors
+//----------------------------------------------------------------------
+SBThread::SBThread () :
+ m_opaque_sp (new ExecutionContextRef())
+{
+}
+
+SBThread::SBThread (const ThreadSP& lldb_object_sp) :
+ m_opaque_sp (new ExecutionContextRef(lldb_object_sp))
+{
+}
+
+SBThread::SBThread (const SBThread &rhs) :
+ m_opaque_sp (new ExecutionContextRef(*rhs.m_opaque_sp))
+{
+
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+
+const lldb::SBThread &
+SBThread::operator = (const SBThread &rhs)
+{
+ if (this != &rhs)
+ *m_opaque_sp = *rhs.m_opaque_sp;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SBThread::~SBThread()
+{
+}
+
+bool
+SBThread::IsValid() const
+{
+ return m_opaque_sp->GetThreadSP().get() != NULL;
+}
+
+void
+SBThread::Clear ()
+{
+ m_opaque_sp->Clear();
+}
+
+
+StopReason
+SBThread::GetStopReason()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ StopReason reason = eStopReasonInvalid;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ return exe_ctx.GetThreadPtr()->GetStopReason();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReason() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReason () => %s", exe_ctx.GetThreadPtr(),
+ Thread::StopReasonAsCString (reason));
+
+ return reason;
+}
+
+size_t
+SBThread::GetStopReasonDataCount ()
+{
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+ switch (reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ case eStopReasonTrace:
+ case eStopReasonExec:
+ case eStopReasonPlanComplete:
+ case eStopReasonThreadExiting:
+ // There is no data for these stop reasons.
+ return 0;
+
+ case eStopReasonBreakpoint:
+ {
+ break_id_t site_id = stop_info_sp->GetValue();
+ lldb::BreakpointSiteSP bp_site_sp (exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID (site_id));
+ if (bp_site_sp)
+ return bp_site_sp->GetNumberOfOwners () * 2;
+ else
+ return 0; // Breakpoint must have cleared itself...
+ }
+ break;
+
+ case eStopReasonWatchpoint:
+ return 1;
+
+ case eStopReasonSignal:
+ return 1;
+
+ case eStopReasonException:
+ return 1;
+ }
+ }
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReasonDataCount() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+ return 0;
+}
+
+uint64_t
+SBThread::GetStopReasonDataAtIndex (uint32_t idx)
+{
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+ switch (reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ case eStopReasonTrace:
+ case eStopReasonExec:
+ case eStopReasonPlanComplete:
+ case eStopReasonThreadExiting:
+ // There is no data for these stop reasons.
+ return 0;
+
+ case eStopReasonBreakpoint:
+ {
+ break_id_t site_id = stop_info_sp->GetValue();
+ lldb::BreakpointSiteSP bp_site_sp (exe_ctx.GetProcessPtr()->GetBreakpointSiteList().FindByID (site_id));
+ if (bp_site_sp)
+ {
+ uint32_t bp_index = idx / 2;
+ BreakpointLocationSP bp_loc_sp (bp_site_sp->GetOwnerAtIndex (bp_index));
+ if (bp_loc_sp)
+ {
+ if (bp_index & 1)
+ {
+ // Odd idx, return the breakpoint location ID
+ return bp_loc_sp->GetID();
+ }
+ else
+ {
+ // Even idx, return the breakpoint ID
+ return bp_loc_sp->GetBreakpoint().GetID();
+ }
+ }
+ }
+ return LLDB_INVALID_BREAK_ID;
+ }
+ break;
+
+ case eStopReasonWatchpoint:
+ return stop_info_sp->GetValue();
+
+ case eStopReasonSignal:
+ return stop_info_sp->GetValue();
+
+ case eStopReasonException:
+ return stop_info_sp->GetValue();
+ }
+ }
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReasonDataAtIndex() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+ return 0;
+}
+
+size_t
+SBThread::GetStopDescription (char *dst, size_t dst_len)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+
+ StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo ();
+ if (stop_info_sp)
+ {
+ const char *stop_desc = stop_info_sp->GetDescription();
+ if (stop_desc)
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => \"%s\"",
+ exe_ctx.GetThreadPtr(), stop_desc);
+ if (dst)
+ return ::snprintf (dst, dst_len, "%s", stop_desc);
+ else
+ {
+ // NULL dst passed in, return the length needed to contain the description
+ return ::strlen (stop_desc) + 1; // Include the NULL byte for size
+ }
+ }
+ else
+ {
+ size_t stop_desc_len = 0;
+ switch (stop_info_sp->GetStopReason())
+ {
+ case eStopReasonTrace:
+ case eStopReasonPlanComplete:
+ {
+ static char trace_desc[] = "step";
+ stop_desc = trace_desc;
+ stop_desc_len = sizeof(trace_desc); // Include the NULL byte for size
+ }
+ break;
+
+ case eStopReasonBreakpoint:
+ {
+ static char bp_desc[] = "breakpoint hit";
+ stop_desc = bp_desc;
+ stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size
+ }
+ break;
+
+ case eStopReasonWatchpoint:
+ {
+ static char wp_desc[] = "watchpoint hit";
+ stop_desc = wp_desc;
+ stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size
+ }
+ break;
+
+ case eStopReasonSignal:
+ {
+ stop_desc = exe_ctx.GetProcessPtr()->GetUnixSignals ().GetSignalAsCString (stop_info_sp->GetValue());
+ if (stop_desc == NULL || stop_desc[0] == '\0')
+ {
+ static char signal_desc[] = "signal";
+ stop_desc = signal_desc;
+ stop_desc_len = sizeof(signal_desc); // Include the NULL byte for size
+ }
+ }
+ break;
+
+ case eStopReasonException:
+ {
+ char exc_desc[] = "exception";
+ stop_desc = exc_desc;
+ stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
+ }
+ break;
+
+ case eStopReasonExec:
+ {
+ char exc_desc[] = "exec";
+ stop_desc = exc_desc;
+ stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size
+ }
+ break;
+
+ case eStopReasonThreadExiting:
+ {
+ char limbo_desc[] = "thread exiting";
+ stop_desc = limbo_desc;
+ stop_desc_len = sizeof(limbo_desc);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (stop_desc && stop_desc[0])
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopDescription (dst, dst_len) => '%s'",
+ exe_ctx.GetThreadPtr(), stop_desc);
+
+ if (dst)
+ return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte
+
+ if (stop_desc_len == 0)
+ stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte
+
+ return stop_desc_len;
+ }
+ }
+ }
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopDescription() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+ if (dst)
+ *dst = 0;
+ return 0;
+}
+
+SBValue
+SBThread::GetStopReturnValue ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ValueObjectSP return_valobj_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ StopInfoSP stop_info_sp = exe_ctx.GetThreadPtr()->GetStopInfo ();
+ if (stop_info_sp)
+ {
+ return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReturnValue() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetStopReturnValue () => %s", exe_ctx.GetThreadPtr(),
+ return_valobj_sp.get()
+ ? return_valobj_sp->GetValueAsCString()
+ : "<no return value>");
+
+ return SBValue (return_valobj_sp);
+}
+
+void
+SBThread::SetThread (const ThreadSP& lldb_object_sp)
+{
+ m_opaque_sp->SetThreadSP (lldb_object_sp);
+}
+
+
+lldb::tid_t
+SBThread::GetThreadID () const
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp->GetID();
+ return LLDB_INVALID_THREAD_ID;
+}
+
+uint32_t
+SBThread::GetIndexID () const
+{
+ ThreadSP thread_sp(m_opaque_sp->GetThreadSP());
+ if (thread_sp)
+ return thread_sp->GetIndexID();
+ return LLDB_INVALID_INDEX32;
+}
+
+const char *
+SBThread::GetName () const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *name = NULL;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ name = exe_ctx.GetThreadPtr()->GetName();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetName() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL");
+
+ return name;
+}
+
+const char *
+SBThread::GetQueueName () const
+{
+ const char *name = NULL;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ name = exe_ctx.GetThreadPtr()->GetQueueName();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetQueueName() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetQueueName () => %s", exe_ctx.GetThreadPtr(), name ? name : "NULL");
+
+ return name;
+}
+
+SBError
+SBThread::ResumeNewPlan (ExecutionContext &exe_ctx, ThreadPlan *new_plan)
+{
+ SBError sb_error;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!process)
+ {
+ sb_error.SetErrorString("No process in SBThread::ResumeNewPlan");
+ return sb_error;
+ }
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (!thread)
+ {
+ sb_error.SetErrorString("No thread in SBThread::ResumeNewPlan");
+ return sb_error;
+ }
+
+ // User level plans should be Master Plans so they can be interrupted, other plans executed, and
+ // then a "continue" will resume the plan.
+ if (new_plan != NULL)
+ {
+ new_plan->SetIsMasterPlan(true);
+ new_plan->SetOkayToDiscard(false);
+ }
+
+ // 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);
+ }
+
+ return sb_error;
+}
+
+void
+SBThread::StepOver (lldb::RunMode stop_other_threads)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+
+ if (log)
+ log->Printf ("SBThread(%p)::StepOver (stop_other_threads='%s')", exe_ctx.GetThreadPtr(),
+ Thread::RunModeAsCString (stop_other_threads));
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ bool abort_other_plans = false;
+ StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0));
+
+ ThreadPlanSP new_plan_sp;
+ if (frame_sp)
+ {
+ if (frame_sp->HasDebugInformation ())
+ {
+ SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
+ new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
+ sc.line_entry.range,
+ sc,
+ stop_other_threads);
+ }
+ else
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
+ abort_other_plans,
+ stop_other_threads);
+ }
+ }
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+void
+SBThread::StepInto (lldb::RunMode stop_other_threads)
+{
+ StepInto (NULL, stop_other_threads);
+}
+
+void
+SBThread::StepInto (const char *target_name, lldb::RunMode stop_other_threads)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (log)
+ log->Printf ("SBThread(%p)::StepInto (target_name='%s', stop_other_threads='%s')",
+ exe_ctx.GetThreadPtr(),
+ target_name? target_name: "<NULL>",
+ Thread::RunModeAsCString (stop_other_threads));
+
+ if (exe_ctx.HasThreadScope())
+ {
+ bool abort_other_plans = false;
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ StackFrameSP frame_sp(thread->GetStackFrameAtIndex (0));
+ ThreadPlanSP new_plan_sp;
+
+ if (frame_sp && frame_sp->HasDebugInformation ())
+ {
+ bool avoid_code_without_debug_info = true;
+ SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything));
+ new_plan_sp = thread->QueueThreadPlanForStepInRange (abort_other_plans,
+ sc.line_entry.range,
+ sc,
+ target_name,
+ stop_other_threads,
+ avoid_code_without_debug_info);
+ }
+ else
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false,
+ abort_other_plans,
+ stop_other_threads);
+ }
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+void
+SBThread::StepOut ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+
+ if (log)
+ log->Printf ("SBThread(%p)::StepOut ()", exe_ctx.GetThreadPtr());
+
+ if (exe_ctx.HasThreadScope())
+ {
+ bool abort_other_plans = false;
+ bool stop_other_threads = false;
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut (abort_other_plans,
+ NULL,
+ false,
+ stop_other_threads,
+ eVoteYes,
+ eVoteNoOpinion,
+ 0));
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+void
+SBThread::StepOutOfFrame (lldb::SBFrame &sb_frame)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrameSP frame_sp (sb_frame.GetFrameSP());
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_frame.GetDescription (frame_desc_strm);
+ log->Printf ("SBThread(%p)::StepOutOfFrame (frame = SBFrame(%p): %s)", exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData());
+ }
+
+ if (exe_ctx.HasThreadScope())
+ {
+ bool abort_other_plans = false;
+ bool stop_other_threads = false;
+ Thread *thread = exe_ctx.GetThreadPtr();
+
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepOut (abort_other_plans,
+ NULL,
+ false,
+ stop_other_threads,
+ eVoteYes,
+ eVoteNoOpinion,
+ frame_sp->GetFrameIndex()));
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+void
+SBThread::StepInstruction (bool step_over)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+
+
+ if (log)
+ log->Printf ("SBThread(%p)::StepInstruction (step_over=%i)", exe_ctx.GetThreadPtr(), step_over);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction (step_over, true, true));
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+void
+SBThread::RunToAddress (lldb::addr_t addr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+
+ if (log)
+ log->Printf ("SBThread(%p)::RunToAddress (addr=0x%" PRIx64 ")", exe_ctx.GetThreadPtr(), addr);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ bool abort_other_plans = false;
+ bool stop_other_threads = true;
+
+ Address target_addr (addr);
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads));
+
+ // This returns an error, we should use it!
+ ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+}
+
+SBError
+SBThread::StepOverUntil (lldb::SBFrame &sb_frame,
+ lldb::SBFileSpec &sb_file_spec,
+ uint32_t line)
+{
+ SBError sb_error;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ char path[PATH_MAX];
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ StackFrameSP frame_sp (sb_frame.GetFrameSP());
+
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_frame.GetDescription (frame_desc_strm);
+ sb_file_spec->GetPath (path, sizeof(path));
+ log->Printf ("SBThread(%p)::StepOverUntil (frame = SBFrame(%p): %s, file+line = %s:%u)",
+ exe_ctx.GetThreadPtr(),
+ frame_sp.get(),
+ frame_desc_strm.GetData(),
+ path, line);
+ }
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Target *target = exe_ctx.GetTargetPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+
+ if (line == 0)
+ {
+ sb_error.SetErrorString("invalid line argument");
+ return sb_error;
+ }
+
+ if (!frame_sp)
+ {
+ frame_sp = thread->GetSelectedFrame ();
+ if (!frame_sp)
+ frame_sp = thread->GetStackFrameAtIndex (0);
+ }
+
+ SymbolContext frame_sc;
+ if (!frame_sp)
+ {
+ sb_error.SetErrorString("no valid frames in thread to step");
+ return sb_error;
+ }
+
+ // If we have a frame, get its line
+ frame_sc = frame_sp->GetSymbolContext (eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextLineEntry |
+ eSymbolContextSymbol );
+
+ if (frame_sc.comp_unit == NULL)
+ {
+ sb_error.SetErrorStringWithFormat("frame %u doesn't have debug information", frame_sp->GetFrameIndex());
+ return sb_error;
+ }
+
+ FileSpec step_file_spec;
+ if (sb_file_spec.IsValid())
+ {
+ // The file spec passed in was valid, so use it
+ step_file_spec = sb_file_spec.ref();
+ }
+ else
+ {
+ if (frame_sc.line_entry.IsValid())
+ step_file_spec = frame_sc.line_entry.file;
+ else
+ {
+ sb_error.SetErrorString("invalid file argument or no file for frame");
+ return sb_error;
+ }
+ }
+
+ // Grab the current function, then we will make sure the "until" address is
+ // within the function. We discard addresses that are out of the current
+ // function, and then if there are no addresses remaining, give an appropriate
+ // error message.
+
+ bool all_in_function = true;
+ AddressRange fun_range = frame_sc.function->GetAddressRange();
+
+ std::vector<addr_t> step_over_until_addrs;
+ const bool abort_other_plans = false;
+ const bool stop_other_threads = false;
+ const bool check_inlines = true;
+ const bool exact = false;
+
+ SymbolContextList sc_list;
+ const uint32_t num_matches = frame_sc.comp_unit->ResolveSymbolContext (step_file_spec,
+ line,
+ check_inlines,
+ exact,
+ eSymbolContextLineEntry,
+ sc_list);
+ if (num_matches > 0)
+ {
+ SymbolContext sc;
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ addr_t step_addr = sc.line_entry.range.GetBaseAddress().GetLoadAddress(target);
+ if (step_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (fun_range.ContainsLoadAddress(step_addr, target))
+ step_over_until_addrs.push_back(step_addr);
+ else
+ all_in_function = false;
+ }
+ }
+ }
+ }
+
+ if (step_over_until_addrs.empty())
+ {
+ if (all_in_function)
+ {
+ step_file_spec.GetPath (path, sizeof(path));
+ sb_error.SetErrorStringWithFormat("No line entries for %s:%u", path, line);
+ }
+ else
+ sb_error.SetErrorString ("step until target not in current function");
+ }
+ else
+ {
+ ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepUntil (abort_other_plans,
+ &step_over_until_addrs[0],
+ step_over_until_addrs.size(),
+ stop_other_threads,
+ frame_sp->GetFrameIndex()));
+
+ sb_error = ResumeNewPlan (exe_ctx, new_plan_sp.get());
+ }
+ }
+ else
+ {
+ sb_error.SetErrorString("this SBThread object is invalid");
+ }
+ return sb_error;
+}
+
+SBError
+SBThread::ReturnFromFrame (SBFrame &frame, SBValue &return_value)
+{
+ SBError sb_error;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+
+ if (log)
+ log->Printf ("SBThread(%p)::ReturnFromFrame (frame=%d)", exe_ctx.GetThreadPtr(), frame.GetFrameID());
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ sb_error.SetError (thread->ReturnFromFrame(frame.GetFrameSP(), return_value.GetSP()));
+ }
+
+ return sb_error;
+}
+
+
+bool
+SBThread::Suspend()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ bool result = false;
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ exe_ctx.GetThreadPtr()->SetResumeState (eStateSuspended);
+ result = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::Suspend() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+ if (log)
+ log->Printf ("SBThread(%p)::Suspend() => %i", exe_ctx.GetThreadPtr(), result);
+ return result;
+}
+
+bool
+SBThread::Resume ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ bool result = false;
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ exe_ctx.GetThreadPtr()->SetResumeState (eStateRunning);
+ result = true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::Resume() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+ if (log)
+ log->Printf ("SBThread(%p)::Resume() => %i", exe_ctx.GetThreadPtr(), result);
+ return result;
+}
+
+bool
+SBThread::IsSuspended()
+{
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (exe_ctx.HasThreadScope())
+ return exe_ctx.GetThreadPtr()->GetResumeState () == eStateSuspended;
+ return false;
+}
+
+bool
+SBThread::IsStopped()
+{
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (exe_ctx.HasThreadScope())
+ return StateIsStoppedState(exe_ctx.GetThreadPtr()->GetState(), true);
+ return false;
+}
+
+SBProcess
+SBThread::GetProcess ()
+{
+ SBProcess sb_process;
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (exe_ctx.HasThreadScope())
+ {
+ // Have to go up to the target so we can get a shared pointer to our process...
+ sb_process.SetSP (exe_ctx.GetProcessSP());
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_process.GetDescription (frame_desc_strm);
+ log->Printf ("SBThread(%p)::GetProcess () => SBProcess(%p): %s", exe_ctx.GetThreadPtr(),
+ sb_process.GetSP().get(), frame_desc_strm.GetData());
+ }
+
+ return sb_process;
+}
+
+uint32_t
+SBThread::GetNumFrames ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ uint32_t num_frames = 0;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ num_frames = exe_ctx.GetThreadPtr()->GetStackFrameCount();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetNumFrames() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ log->Printf ("SBThread(%p)::GetNumFrames () => %u", exe_ctx.GetThreadPtr(), num_frames);
+
+ return num_frames;
+}
+
+SBFrame
+SBThread::GetFrameAtIndex (uint32_t idx)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFrame sb_frame;
+ StackFrameSP frame_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ frame_sp = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex (idx);
+ sb_frame.SetFrameSP (frame_sp);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetFrameAtIndex() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_frame.GetDescription (frame_desc_strm);
+ log->Printf ("SBThread(%p)::GetFrameAtIndex (idx=%d) => SBFrame(%p): %s",
+ exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData());
+ }
+
+ return sb_frame;
+}
+
+lldb::SBFrame
+SBThread::GetSelectedFrame ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFrame sb_frame;
+ StackFrameSP frame_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ frame_sp = exe_ctx.GetThreadPtr()->GetSelectedFrame ();
+ sb_frame.SetFrameSP (frame_sp);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::GetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_frame.GetDescription (frame_desc_strm);
+ log->Printf ("SBThread(%p)::GetSelectedFrame () => SBFrame(%p): %s",
+ exe_ctx.GetThreadPtr(), frame_sp.get(), frame_desc_strm.GetData());
+ }
+
+ return sb_frame;
+}
+
+lldb::SBFrame
+SBThread::SetSelectedFrame (uint32_t idx)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ SBFrame sb_frame;
+ StackFrameSP frame_sp;
+ Mutex::Locker api_locker;
+ ExecutionContext exe_ctx (m_opaque_sp.get(), api_locker);
+
+ if (exe_ctx.HasThreadScope())
+ {
+ Process::StopLocker stop_locker;
+ if (stop_locker.TryLock(&exe_ctx.GetProcessPtr()->GetRunLock()))
+ {
+ Thread *thread = exe_ctx.GetThreadPtr();
+ frame_sp = thread->GetStackFrameAtIndex (idx);
+ if (frame_sp)
+ {
+ thread->SetSelectedFrame (frame_sp.get());
+ sb_frame.SetFrameSP (frame_sp);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SBThread(%p)::SetSelectedFrame() => error: process is running", exe_ctx.GetThreadPtr());
+ }
+ }
+
+ if (log)
+ {
+ SBStream frame_desc_strm;
+ sb_frame.GetDescription (frame_desc_strm);
+ log->Printf ("SBThread(%p)::SetSelectedFrame (idx=%u) => SBFrame(%p): %s",
+ exe_ctx.GetThreadPtr(), idx, frame_sp.get(), frame_desc_strm.GetData());
+ }
+ return sb_frame;
+}
+
+bool
+SBThread::EventIsThreadEvent (const SBEvent &event)
+{
+ return Thread::ThreadEventData::GetEventDataFromEvent(event.get()) != NULL;
+}
+
+SBFrame
+SBThread::GetStackFrameFromEvent (const SBEvent &event)
+{
+ return Thread::ThreadEventData::GetStackFrameFromEvent (event.get());
+
+}
+
+SBThread
+SBThread::GetThreadFromEvent (const SBEvent &event)
+{
+ return Thread::ThreadEventData::GetThreadFromEvent (event.get());
+}
+
+bool
+SBThread::operator == (const SBThread &rhs) const
+{
+ return m_opaque_sp->GetThreadSP().get() == rhs.m_opaque_sp->GetThreadSP().get();
+}
+
+bool
+SBThread::operator != (const SBThread &rhs) const
+{
+ return m_opaque_sp->GetThreadSP().get() != rhs.m_opaque_sp->GetThreadSP().get();
+}
+
+bool
+SBThread::GetStatus (SBStream &status) const
+{
+ Stream &strm = status.ref();
+
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (exe_ctx.HasThreadScope())
+ {
+ exe_ctx.GetThreadPtr()->GetStatus(strm, 0, 1, 1);
+ }
+ else
+ strm.PutCString ("No status");
+
+ return true;
+}
+
+bool
+SBThread::GetDescription (SBStream &description) const
+{
+ Stream &strm = description.ref();
+
+ ExecutionContext exe_ctx (m_opaque_sp.get());
+ if (exe_ctx.HasThreadScope())
+ {
+ strm.Printf("SBThread: tid = 0x%4.4" PRIx64, exe_ctx.GetThreadPtr()->GetID());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
diff --git a/source/API/SBType.cpp b/source/API/SBType.cpp
new file mode 100644
index 000000000000..372d073acf12
--- /dev/null
+++ b/source/API/SBType.cpp
@@ -0,0 +1,648 @@
+//===-- SBType.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <string.h>
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/TemplateBase.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBType.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/Type.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+SBType::SBType() :
+ m_opaque_sp()
+{
+}
+
+SBType::SBType (const ClangASTType &type) :
+ m_opaque_sp(new TypeImpl(ClangASTType(type.GetASTContext(),
+ type.GetOpaqueQualType())))
+{
+}
+
+SBType::SBType (const lldb::TypeSP &type_sp) :
+ m_opaque_sp(new TypeImpl(type_sp))
+{
+}
+
+SBType::SBType (const lldb::TypeImplSP &type_impl_sp) :
+ m_opaque_sp(type_impl_sp)
+{
+}
+
+
+SBType::SBType (const SBType &rhs) :
+ m_opaque_sp()
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+}
+
+
+//SBType::SBType (TypeImpl* impl) :
+// m_opaque_ap(impl)
+//{}
+//
+bool
+SBType::operator == (SBType &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ return (rhs.m_opaque_sp->GetASTContext() == m_opaque_sp->GetASTContext()) &&
+ (rhs.m_opaque_sp->GetOpaqueQualType() == m_opaque_sp->GetOpaqueQualType());
+}
+
+bool
+SBType::operator != (SBType &rhs)
+{
+ if (IsValid() == false)
+ return rhs.IsValid();
+
+ return (rhs.m_opaque_sp->GetASTContext() != m_opaque_sp->GetASTContext()) ||
+ (rhs.m_opaque_sp->GetOpaqueQualType() != m_opaque_sp->GetOpaqueQualType());
+}
+
+lldb::TypeImplSP
+SBType::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+
+void
+SBType::SetSP (const lldb::TypeImplSP &type_impl_sp)
+{
+ m_opaque_sp = type_impl_sp;
+}
+
+SBType &
+SBType::operator = (const SBType &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+SBType::~SBType ()
+{}
+
+TypeImpl &
+SBType::ref ()
+{
+ if (m_opaque_sp.get() == NULL)
+ m_opaque_sp.reset (new TypeImpl());
+ return *m_opaque_sp;
+}
+
+const TypeImpl &
+SBType::ref () const
+{
+ // "const SBAddress &addr" should already have checked "addr.IsValid()"
+ // prior to calling this function. In case you didn't we will assert
+ // and die to let you know.
+ assert (m_opaque_sp.get());
+ return *m_opaque_sp;
+}
+
+bool
+SBType::IsValid() const
+{
+ if (m_opaque_sp.get() == NULL)
+ return false;
+
+ return m_opaque_sp->IsValid();
+}
+
+uint64_t
+SBType::GetByteSize()
+{
+ if (!IsValid())
+ return 0;
+
+ return m_opaque_sp->GetClangASTType().GetByteSize();
+
+}
+
+bool
+SBType::IsPointerType()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType().IsPointerType();
+}
+
+bool
+SBType::IsReferenceType()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType().IsReferenceType();
+}
+
+SBType
+SBType::GetPointerType()
+{
+ if (!IsValid())
+ return SBType();
+
+ return SBType(ClangASTType(m_opaque_sp->GetClangASTType().GetPointerType()));
+}
+
+SBType
+SBType::GetPointeeType()
+{
+ if (!IsValid())
+ return SBType();
+ return SBType(ClangASTType(m_opaque_sp->GetClangASTType().GetPointeeType()));
+}
+
+SBType
+SBType::GetReferenceType()
+{
+ if (!IsValid())
+ return SBType();
+ return SBType(ClangASTType(m_opaque_sp->GetClangASTType().GetLValueReferenceType()));
+}
+
+SBType
+SBType::GetDereferencedType()
+{
+ if (!IsValid())
+ return SBType();
+ return SBType(ClangASTType(m_opaque_sp->GetClangASTType().GetNonReferenceType()));
+}
+
+bool
+SBType::IsFunctionType ()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType().IsFunctionType();
+}
+
+bool
+SBType::IsPolymorphicClass ()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType().IsPolymorphicClass();
+}
+
+
+
+lldb::SBType
+SBType::GetFunctionReturnType ()
+{
+ if (IsValid())
+ {
+ ClangASTType return_clang_type (m_opaque_sp->GetClangASTType().GetFunctionReturnType());
+ if (return_clang_type.IsValid())
+ return SBType(return_clang_type);
+ }
+ return lldb::SBType();
+}
+
+lldb::SBTypeList
+SBType::GetFunctionArgumentTypes ()
+{
+ SBTypeList sb_type_list;
+ if (IsValid())
+ {
+ QualType qual_type(QualType::getFromOpaquePtr(m_opaque_sp->GetOpaqueQualType()));
+ const FunctionProtoType* func = dyn_cast<FunctionProtoType>(qual_type.getTypePtr());
+ if (func)
+ {
+ const uint32_t num_args = func->getNumArgs();
+ for (uint32_t i=0; i<num_args; ++i)
+ sb_type_list.Append (SBType(ClangASTType(m_opaque_sp->GetASTContext(), func->getArgType(i).getAsOpaquePtr())));
+ }
+ }
+ return sb_type_list;
+}
+
+lldb::SBType
+SBType::GetUnqualifiedType()
+{
+ if (!IsValid())
+ return SBType();
+ return SBType(m_opaque_sp->GetClangASTType().GetFullyUnqualifiedType());
+}
+
+lldb::SBType
+SBType::GetCanonicalType()
+{
+ if (IsValid())
+ return SBType(m_opaque_sp->GetClangASTType().GetCanonicalType());
+ return SBType();
+}
+
+
+lldb::BasicType
+SBType::GetBasicType()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetBasicTypeEnumeration ();
+ return eBasicTypeInvalid;
+}
+
+SBType
+SBType::GetBasicType(lldb::BasicType basic_type)
+{
+ if (IsValid())
+ return SBType (ClangASTContext::GetBasicType (m_opaque_sp->GetASTContext(), basic_type));
+ return SBType();
+}
+
+uint32_t
+SBType::GetNumberOfDirectBaseClasses ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetNumDirectBaseClasses();
+ return 0;
+}
+
+uint32_t
+SBType::GetNumberOfVirtualBaseClasses ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetNumVirtualBaseClasses();
+ return 0;
+}
+
+uint32_t
+SBType::GetNumberOfFields ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetNumFields();
+ return 0;
+}
+
+bool
+SBType::GetDescription (SBStream &description, lldb::DescriptionLevel description_level)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_sp)
+ {
+ m_opaque_sp->GetDescription (strm, description_level);
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+
+
+SBTypeMember
+SBType::GetDirectBaseClassAtIndex (uint32_t idx)
+{
+ SBTypeMember sb_type_member;
+ if (IsValid())
+ {
+ ClangASTType this_type (m_opaque_sp->GetClangASTType ());
+ if (this_type.IsValid())
+ {
+ uint32_t bit_offset = 0;
+ ClangASTType base_class_type (this_type.GetDirectBaseClassAtIndex(idx, &bit_offset));
+ if (base_class_type.IsValid())
+ {
+ sb_type_member.reset (new TypeMemberImpl (TypeImplSP(new TypeImpl(base_class_type)), bit_offset));
+ }
+ }
+ }
+ return sb_type_member;
+
+}
+
+SBTypeMember
+SBType::GetVirtualBaseClassAtIndex (uint32_t idx)
+{
+ SBTypeMember sb_type_member;
+ if (IsValid())
+ {
+ ClangASTType this_type (m_opaque_sp->GetClangASTType ());
+ if (this_type.IsValid())
+ {
+ uint32_t bit_offset = 0;
+ ClangASTType base_class_type (this_type.GetVirtualBaseClassAtIndex(idx, &bit_offset));
+ if (base_class_type.IsValid())
+ {
+ sb_type_member.reset (new TypeMemberImpl (TypeImplSP(new TypeImpl(base_class_type)), bit_offset));
+ }
+ }
+ }
+ return sb_type_member;
+}
+
+SBTypeMember
+SBType::GetFieldAtIndex (uint32_t idx)
+{
+ SBTypeMember sb_type_member;
+ if (IsValid())
+ {
+ ClangASTType this_type (m_opaque_sp->GetClangASTType ());
+ if (this_type.IsValid())
+ {
+ uint64_t bit_offset = 0;
+ uint32_t bitfield_bit_size = 0;
+ bool is_bitfield = false;
+ std::string name_sstr;
+ ClangASTType field_type (this_type.GetFieldAtIndex (idx,
+ name_sstr,
+ &bit_offset,
+ &bitfield_bit_size,
+ &is_bitfield));
+ if (field_type.IsValid())
+ {
+ ConstString name;
+ if (!name_sstr.empty())
+ name.SetCString(name_sstr.c_str());
+ sb_type_member.reset (new TypeMemberImpl (TypeImplSP (new TypeImpl(field_type)),
+ bit_offset,
+ name,
+ bitfield_bit_size,
+ is_bitfield));
+ }
+ }
+ }
+ return sb_type_member;
+}
+
+bool
+SBType::IsTypeComplete()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetClangASTType().IsCompleteType();
+}
+
+const char*
+SBType::GetName()
+{
+ if (!IsValid())
+ return "";
+ return m_opaque_sp->GetClangASTType().GetConstTypeName().GetCString();
+}
+
+lldb::TypeClass
+SBType::GetTypeClass ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetTypeClass();
+ return lldb::eTypeClassInvalid;
+}
+
+uint32_t
+SBType::GetNumberOfTemplateArguments ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetClangASTType().GetNumTemplateArguments();
+ return 0;
+}
+
+lldb::SBType
+SBType::GetTemplateArgumentType (uint32_t idx)
+{
+ if (IsValid())
+ {
+ TemplateArgumentKind kind = eTemplateArgumentKindNull;
+ ClangASTType template_arg_type = m_opaque_sp->GetClangASTType().GetTemplateArgument (idx, kind);
+ if (template_arg_type.IsValid())
+ return SBType(template_arg_type);
+ }
+ return SBType();
+}
+
+
+lldb::TemplateArgumentKind
+SBType::GetTemplateArgumentKind (uint32_t idx)
+{
+ TemplateArgumentKind kind = eTemplateArgumentKindNull;
+ if (IsValid())
+ m_opaque_sp->GetClangASTType().GetTemplateArgument (idx, kind);
+ return kind;
+}
+
+
+SBTypeList::SBTypeList() :
+ m_opaque_ap(new TypeListImpl())
+{
+}
+
+SBTypeList::SBTypeList(const SBTypeList& rhs) :
+ m_opaque_ap(new TypeListImpl())
+{
+ for (uint32_t i = 0, rhs_size = const_cast<SBTypeList&>(rhs).GetSize(); i < rhs_size; i++)
+ Append(const_cast<SBTypeList&>(rhs).GetTypeAtIndex(i));
+}
+
+bool
+SBTypeList::IsValid ()
+{
+ return (m_opaque_ap.get() != NULL);
+}
+
+SBTypeList&
+SBTypeList::operator = (const SBTypeList& rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_ap.reset (new TypeListImpl());
+ for (uint32_t i = 0, rhs_size = const_cast<SBTypeList&>(rhs).GetSize(); i < rhs_size; i++)
+ Append(const_cast<SBTypeList&>(rhs).GetTypeAtIndex(i));
+ }
+ return *this;
+}
+
+void
+SBTypeList::Append (SBType type)
+{
+ if (type.IsValid())
+ m_opaque_ap->Append (type.m_opaque_sp);
+}
+
+SBType
+SBTypeList::GetTypeAtIndex(uint32_t index)
+{
+ if (m_opaque_ap.get())
+ return SBType(m_opaque_ap->GetTypeAtIndex(index));
+ return SBType();
+}
+
+uint32_t
+SBTypeList::GetSize()
+{
+ return m_opaque_ap->GetSize();
+}
+
+SBTypeList::~SBTypeList()
+{
+}
+
+SBTypeMember::SBTypeMember() :
+ m_opaque_ap()
+{
+}
+
+SBTypeMember::~SBTypeMember()
+{
+}
+
+SBTypeMember::SBTypeMember (const SBTypeMember& rhs) :
+ m_opaque_ap()
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_ap.reset(new TypeMemberImpl(rhs.ref()));
+ }
+}
+
+lldb::SBTypeMember&
+SBTypeMember::operator = (const lldb::SBTypeMember& rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_ap.reset(new TypeMemberImpl(rhs.ref()));
+ }
+ return *this;
+}
+
+bool
+SBTypeMember::IsValid() const
+{
+ return m_opaque_ap.get();
+}
+
+const char *
+SBTypeMember::GetName ()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetName().GetCString();
+ return NULL;
+}
+
+SBType
+SBTypeMember::GetType ()
+{
+ SBType sb_type;
+ if (m_opaque_ap.get())
+ {
+ sb_type.SetSP (m_opaque_ap->GetTypeImpl());
+ }
+ return sb_type;
+
+}
+
+uint64_t
+SBTypeMember::GetOffsetInBytes()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetBitOffset() / 8u;
+ return 0;
+}
+
+uint64_t
+SBTypeMember::GetOffsetInBits()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetBitOffset();
+ return 0;
+}
+
+bool
+SBTypeMember::IsBitfield()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetIsBitfield();
+ return false;
+}
+
+uint32_t
+SBTypeMember::GetBitfieldSizeInBits()
+{
+ if (m_opaque_ap.get())
+ return m_opaque_ap->GetBitfieldBitSize();
+ return 0;
+}
+
+
+bool
+SBTypeMember::GetDescription (lldb::SBStream &description, lldb::DescriptionLevel description_level)
+{
+ Stream &strm = description.ref();
+
+ if (m_opaque_ap.get())
+ {
+ const uint32_t bit_offset = m_opaque_ap->GetBitOffset();
+ const uint32_t byte_offset = bit_offset / 8u;
+ const uint32_t byte_bit_offset = bit_offset % 8u;
+ const char *name = m_opaque_ap->GetName().GetCString();
+ if (byte_bit_offset)
+ strm.Printf ("+%u + %u bits: (", byte_offset, byte_bit_offset);
+ else
+ strm.Printf ("+%u: (", byte_offset);
+
+ TypeImplSP type_impl_sp (m_opaque_ap->GetTypeImpl());
+ if (type_impl_sp)
+ type_impl_sp->GetDescription(strm, description_level);
+
+ strm.Printf (") %s", name);
+ if (m_opaque_ap->GetIsBitfield())
+ {
+ const uint32_t bitfield_bit_size = m_opaque_ap->GetBitfieldBitSize();
+ strm.Printf (" : %u", bitfield_bit_size);
+ }
+ }
+ else
+ {
+ strm.PutCString ("No value");
+ }
+ return true;
+}
+
+
+void
+SBTypeMember::reset(TypeMemberImpl *type_member_impl)
+{
+ m_opaque_ap.reset(type_member_impl);
+}
+
+TypeMemberImpl &
+SBTypeMember::ref ()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new TypeMemberImpl());
+ return *m_opaque_ap.get();
+}
+
+const TypeMemberImpl &
+SBTypeMember::ref () const
+{
+ return *m_opaque_ap.get();
+}
diff --git a/source/API/SBTypeCategory.cpp b/source/API/SBTypeCategory.cpp
new file mode 100644
index 000000000000..e3978693c81c
--- /dev/null
+++ b/source/API/SBTypeCategory.cpp
@@ -0,0 +1,576 @@
+//===-- SBTypeCategory.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/SBTypeCategory.h"
+
+#include "lldb/API/SBTypeFilter.h"
+#include "lldb/API/SBTypeFormat.h"
+#include "lldb/API/SBTypeSummary.h"
+#include "lldb/API/SBTypeSynthetic.h"
+#include "lldb/API/SBTypeNameSpecifier.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+typedef std::pair<lldb::TypeCategoryImplSP,user_id_t> ImplType;
+
+SBTypeCategory::SBTypeCategory() :
+m_opaque_sp()
+{
+}
+
+SBTypeCategory::SBTypeCategory (const char* name) :
+m_opaque_sp()
+{
+ DataVisualization::Categories::GetCategory(ConstString(name), m_opaque_sp);
+}
+
+SBTypeCategory::SBTypeCategory (const lldb::SBTypeCategory &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+SBTypeCategory::~SBTypeCategory ()
+{
+}
+
+bool
+SBTypeCategory::IsValid() const
+{
+ return (m_opaque_sp.get() != NULL);
+}
+
+bool
+SBTypeCategory::GetEnabled ()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->IsEnabled();
+}
+
+void
+SBTypeCategory::SetEnabled (bool enabled)
+{
+ if (!IsValid())
+ return;
+ if (enabled)
+ DataVisualization::Categories::Enable(m_opaque_sp);
+ else
+ DataVisualization::Categories::Disable(m_opaque_sp);
+}
+
+const char*
+SBTypeCategory::GetName()
+{
+ if (!IsValid())
+ return NULL;
+ return m_opaque_sp->GetName();
+}
+
+uint32_t
+SBTypeCategory::GetNumFormats ()
+{
+ if (!IsDefaultCategory())
+ return 0;
+
+ return DataVisualization::ValueFormats::GetCount();
+}
+
+uint32_t
+SBTypeCategory::GetNumSummaries ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetSummaryNavigator()->GetCount() + m_opaque_sp->GetRegexSummaryNavigator()->GetCount();
+}
+
+uint32_t
+SBTypeCategory::GetNumFilters ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetFilterNavigator()->GetCount() + m_opaque_sp->GetRegexFilterNavigator()->GetCount();
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+uint32_t
+SBTypeCategory::GetNumSynthetics ()
+{
+ if (!IsValid())
+ return 0;
+ return m_opaque_sp->GetSyntheticNavigator()->GetCount() + m_opaque_sp->GetRegexSyntheticNavigator()->GetCount();
+}
+#endif
+
+lldb::SBTypeNameSpecifier
+SBTypeCategory::GetTypeNameSpecifierForFilterAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeNameSpecifier();
+ return SBTypeNameSpecifier(m_opaque_sp->GetTypeNameSpecifierForFilterAtIndex(index));
+}
+
+lldb::SBTypeNameSpecifier
+SBTypeCategory::GetTypeNameSpecifierForFormatAtIndex (uint32_t index)
+{
+ if (!IsDefaultCategory())
+ return SBTypeNameSpecifier();
+ return SBTypeNameSpecifier(DataVisualization::ValueFormats::GetTypeNameSpecifierForFormatAtIndex(index));
+}
+
+lldb::SBTypeNameSpecifier
+SBTypeCategory::GetTypeNameSpecifierForSummaryAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeNameSpecifier();
+ return SBTypeNameSpecifier(m_opaque_sp->GetTypeNameSpecifierForSummaryAtIndex(index));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SBTypeNameSpecifier
+SBTypeCategory::GetTypeNameSpecifierForSyntheticAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeNameSpecifier();
+ return SBTypeNameSpecifier(m_opaque_sp->GetTypeNameSpecifierForSyntheticAtIndex(index));
+}
+#endif
+
+SBTypeFilter
+SBTypeCategory::GetFilterForType (SBTypeNameSpecifier spec)
+{
+ if (!IsValid())
+ return SBTypeFilter();
+
+ if (!spec.IsValid())
+ return SBTypeFilter();
+
+ lldb::SyntheticChildrenSP children_sp;
+
+ if (spec.IsRegex())
+ m_opaque_sp->GetRegexFilterNavigator()->GetExact(ConstString(spec.GetName()), children_sp);
+ else
+ m_opaque_sp->GetFilterNavigator()->GetExact(ConstString(spec.GetName()), children_sp);
+
+ if (!children_sp)
+ return lldb::SBTypeFilter();
+
+ TypeFilterImplSP filter_sp = std::static_pointer_cast<TypeFilterImpl>(children_sp);
+
+ return lldb::SBTypeFilter(filter_sp);
+
+}
+SBTypeFormat
+SBTypeCategory::GetFormatForType (SBTypeNameSpecifier spec)
+{
+ if (!IsDefaultCategory())
+ return SBTypeFormat();
+
+ if (!spec.IsValid())
+ return SBTypeFormat();
+
+ if (spec.IsRegex())
+ return SBTypeFormat();
+
+ return SBTypeFormat(DataVisualization::ValueFormats::GetFormat(ConstString(spec.GetName())));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSummary
+SBTypeCategory::GetSummaryForType (SBTypeNameSpecifier spec)
+{
+ if (!IsValid())
+ return SBTypeSummary();
+
+ if (!spec.IsValid())
+ return SBTypeSummary();
+
+ lldb::TypeSummaryImplSP summary_sp;
+
+ if (spec.IsRegex())
+ m_opaque_sp->GetRegexSummaryNavigator()->GetExact(ConstString(spec.GetName()), summary_sp);
+ else
+ m_opaque_sp->GetSummaryNavigator()->GetExact(ConstString(spec.GetName()), summary_sp);
+
+ if (!summary_sp)
+ return lldb::SBTypeSummary();
+
+ return lldb::SBTypeSummary(summary_sp);
+}
+#endif // LLDB_DISABLE_PYTHON
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSynthetic
+SBTypeCategory::GetSyntheticForType (SBTypeNameSpecifier spec)
+{
+ if (!IsValid())
+ return SBTypeSynthetic();
+
+ if (!spec.IsValid())
+ return SBTypeSynthetic();
+
+ lldb::SyntheticChildrenSP children_sp;
+
+ if (spec.IsRegex())
+ m_opaque_sp->GetRegexSyntheticNavigator()->GetExact(ConstString(spec.GetName()), children_sp);
+ else
+ m_opaque_sp->GetSyntheticNavigator()->GetExact(ConstString(spec.GetName()), children_sp);
+
+ if (!children_sp)
+ return lldb::SBTypeSynthetic();
+
+ ScriptedSyntheticChildrenSP synth_sp = std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp);
+
+ return lldb::SBTypeSynthetic(synth_sp);
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeFilter
+SBTypeCategory::GetFilterAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeFilter();
+ lldb::SyntheticChildrenSP children_sp = m_opaque_sp->GetSyntheticAtIndex((index));
+
+ if (!children_sp.get())
+ return lldb::SBTypeFilter();
+
+ TypeFilterImplSP filter_sp = std::static_pointer_cast<TypeFilterImpl>(children_sp);
+
+ return lldb::SBTypeFilter(filter_sp);
+}
+#endif
+
+SBTypeFormat
+SBTypeCategory::GetFormatAtIndex (uint32_t index)
+{
+ if (!IsDefaultCategory())
+ return SBTypeFormat();
+ return SBTypeFormat(DataVisualization::ValueFormats::GetFormatAtIndex((index)));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSummary
+SBTypeCategory::GetSummaryAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeSummary();
+ return SBTypeSummary(m_opaque_sp->GetSummaryAtIndex((index)));
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+SBTypeSynthetic
+SBTypeCategory::GetSyntheticAtIndex (uint32_t index)
+{
+ if (!IsValid())
+ return SBTypeSynthetic();
+ lldb::SyntheticChildrenSP children_sp = m_opaque_sp->GetSyntheticAtIndex((index));
+
+ if (!children_sp.get())
+ return lldb::SBTypeSynthetic();
+
+ ScriptedSyntheticChildrenSP synth_sp = std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp);
+
+ return lldb::SBTypeSynthetic(synth_sp);
+}
+#endif
+
+bool
+SBTypeCategory::AddTypeFormat (SBTypeNameSpecifier type_name,
+ SBTypeFormat format)
+{
+ if (!IsDefaultCategory())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (!format.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ return false;
+
+ DataVisualization::ValueFormats::Add(ConstString(type_name.GetName()), format.GetSP());
+
+ return true;
+}
+
+bool
+SBTypeCategory::DeleteTypeFormat (SBTypeNameSpecifier type_name)
+{
+ if (!IsDefaultCategory())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ return false;
+
+ return DataVisualization::ValueFormats::Delete(ConstString(type_name.GetName()));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+bool
+SBTypeCategory::AddTypeSummary (SBTypeNameSpecifier type_name,
+ SBTypeSummary summary)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (!summary.IsValid())
+ return false;
+
+ // FIXME: we need to iterate over all the Debugger objects and have each of them contain a copy of the function
+ // since we currently have formatters live in a global space, while Python code lives in a specific Debugger-related environment
+ // this should eventually be fixed by deciding a final location in the LLDB object space for formatters
+ if (summary.IsFunctionCode())
+ {
+ void *name_token = (void*)ConstString(type_name.GetName()).GetCString();
+ const char* script = summary.GetData();
+ StringList input; input.SplitIntoLines(script, strlen(script));
+ uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers();
+ bool need_set = true;
+ for (uint32_t j = 0;
+ j < num_debuggers;
+ j++)
+ {
+ DebuggerSP debugger_sp = lldb_private::Debugger::GetDebuggerAtIndex(j);
+ if (debugger_sp)
+ {
+ ScriptInterpreter* interpreter_ptr = debugger_sp->GetCommandInterpreter().GetScriptInterpreter();
+ if (interpreter_ptr)
+ {
+ std::string output;
+ if (interpreter_ptr->GenerateTypeScriptFunction(input, output, name_token) && !output.empty())
+ {
+ if (need_set)
+ {
+ need_set = false;
+ summary.SetFunctionName(output.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (type_name.IsRegex())
+ m_opaque_sp->GetRegexSummaryNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), summary.GetSP());
+ else
+ m_opaque_sp->GetSummaryNavigator()->Add(ConstString(type_name.GetName()), summary.GetSP());
+
+ return true;
+}
+#endif
+
+bool
+SBTypeCategory::DeleteTypeSummary (SBTypeNameSpecifier type_name)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ return m_opaque_sp->GetRegexSummaryNavigator()->Delete(ConstString(type_name.GetName()));
+ else
+ return m_opaque_sp->GetSummaryNavigator()->Delete(ConstString(type_name.GetName()));
+}
+
+bool
+SBTypeCategory::AddTypeFilter (SBTypeNameSpecifier type_name,
+ SBTypeFilter filter)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (!filter.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ m_opaque_sp->GetRegexFilterNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), filter.GetSP());
+ else
+ m_opaque_sp->GetFilterNavigator()->Add(ConstString(type_name.GetName()), filter.GetSP());
+
+ return true;
+}
+
+bool
+SBTypeCategory::DeleteTypeFilter (SBTypeNameSpecifier type_name)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ return m_opaque_sp->GetRegexFilterNavigator()->Delete(ConstString(type_name.GetName()));
+ else
+ return m_opaque_sp->GetFilterNavigator()->Delete(ConstString(type_name.GetName()));
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+bool
+SBTypeCategory::AddTypeSynthetic (SBTypeNameSpecifier type_name,
+ SBTypeSynthetic synth)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (!synth.IsValid())
+ return false;
+
+ // FIXME: we need to iterate over all the Debugger objects and have each of them contain a copy of the function
+ // since we currently have formatters live in a global space, while Python code lives in a specific Debugger-related environment
+ // this should eventually be fixed by deciding a final location in the LLDB object space for formatters
+ if (synth.IsClassCode())
+ {
+ void *name_token = (void*)ConstString(type_name.GetName()).GetCString();
+ const char* script = synth.GetData();
+ StringList input; input.SplitIntoLines(script, strlen(script));
+ uint32_t num_debuggers = lldb_private::Debugger::GetNumDebuggers();
+ bool need_set = true;
+ for (uint32_t j = 0;
+ j < num_debuggers;
+ j++)
+ {
+ DebuggerSP debugger_sp = lldb_private::Debugger::GetDebuggerAtIndex(j);
+ if (debugger_sp)
+ {
+ ScriptInterpreter* interpreter_ptr = debugger_sp->GetCommandInterpreter().GetScriptInterpreter();
+ if (interpreter_ptr)
+ {
+ std::string output;
+ if (interpreter_ptr->GenerateTypeSynthClass(input, output, name_token) && !output.empty())
+ {
+ if (need_set)
+ {
+ need_set = false;
+ synth.SetClassName(output.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (type_name.IsRegex())
+ m_opaque_sp->GetRegexSyntheticNavigator()->Add(lldb::RegularExpressionSP(new RegularExpression(type_name.GetName())), synth.GetSP());
+ else
+ m_opaque_sp->GetSyntheticNavigator()->Add(ConstString(type_name.GetName()), synth.GetSP());
+
+ return true;
+}
+
+bool
+SBTypeCategory::DeleteTypeSynthetic (SBTypeNameSpecifier type_name)
+{
+ if (!IsValid())
+ return false;
+
+ if (!type_name.IsValid())
+ return false;
+
+ if (type_name.IsRegex())
+ return m_opaque_sp->GetRegexSyntheticNavigator()->Delete(ConstString(type_name.GetName()));
+ else
+ return m_opaque_sp->GetSyntheticNavigator()->Delete(ConstString(type_name.GetName()));
+}
+#endif // LLDB_DISABLE_PYTHON
+
+bool
+SBTypeCategory::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (!IsValid())
+ return false;
+ description.Printf("Category name: %s\n",GetName());
+ return true;
+}
+
+lldb::SBTypeCategory &
+SBTypeCategory::operator = (const lldb::SBTypeCategory &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeCategory::operator == (lldb::SBTypeCategory &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ return m_opaque_sp.get() == rhs.m_opaque_sp.get();
+
+}
+
+bool
+SBTypeCategory::operator != (lldb::SBTypeCategory &rhs)
+{
+ if (IsValid() == false)
+ return rhs.IsValid();
+
+ return m_opaque_sp.get() != rhs.m_opaque_sp.get();
+}
+
+lldb::TypeCategoryImplSP
+SBTypeCategory::GetSP ()
+{
+ if (!IsValid())
+ return lldb::TypeCategoryImplSP();
+ return m_opaque_sp;
+}
+
+void
+SBTypeCategory::SetSP (const lldb::TypeCategoryImplSP &typecategory_impl_sp)
+{
+ m_opaque_sp = typecategory_impl_sp;
+}
+
+SBTypeCategory::SBTypeCategory (const lldb::TypeCategoryImplSP &typecategory_impl_sp) :
+m_opaque_sp(typecategory_impl_sp)
+{
+}
+
+bool
+SBTypeCategory::IsDefaultCategory()
+{
+ if (!IsValid())
+ return false;
+
+ return (strcmp(m_opaque_sp->GetName(),"default") == 0);
+}
+
diff --git a/source/API/SBTypeFilter.cpp b/source/API/SBTypeFilter.cpp
new file mode 100644
index 000000000000..605e92de6991
--- /dev/null
+++ b/source/API/SBTypeFilter.cpp
@@ -0,0 +1,199 @@
+//===-- SBTypeFilter.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/SBTypeFilter.h"
+
+#include "lldb/API/SBStream.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBTypeFilter::SBTypeFilter() :
+m_opaque_sp()
+{
+}
+
+SBTypeFilter::SBTypeFilter (uint32_t options)
+: m_opaque_sp(TypeFilterImplSP(new TypeFilterImpl(options)))
+{
+}
+
+SBTypeFilter::SBTypeFilter (const lldb::SBTypeFilter &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+SBTypeFilter::~SBTypeFilter ()
+{
+}
+
+bool
+SBTypeFilter::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+uint32_t
+SBTypeFilter::GetOptions()
+{
+ if (IsValid())
+ return m_opaque_sp->GetOptions();
+ return 0;
+}
+
+void
+SBTypeFilter::SetOptions (uint32_t value)
+{
+ if (CopyOnWrite_Impl())
+ m_opaque_sp->SetOptions(value);
+}
+
+bool
+SBTypeFilter::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (!IsValid())
+ return false;
+ else {
+ description.Printf("%s\n",
+ m_opaque_sp->GetDescription().c_str());
+ return true;
+ }
+}
+
+void
+SBTypeFilter::Clear()
+{
+ if (CopyOnWrite_Impl())
+ m_opaque_sp->Clear();
+}
+
+uint32_t
+SBTypeFilter::GetNumberOfExpressionPaths()
+{
+ if (IsValid())
+ return m_opaque_sp->GetCount();
+ return 0;
+}
+
+const char*
+SBTypeFilter::GetExpressionPathAtIndex (uint32_t i)
+{
+ if (IsValid())
+ {
+ const char* item = m_opaque_sp->GetExpressionPathAtIndex(i);
+ if (item && *item == '.')
+ item++;
+ return item;
+ }
+ return NULL;
+}
+
+bool
+SBTypeFilter::ReplaceExpressionPathAtIndex (uint32_t i, const char* item)
+{
+ if (CopyOnWrite_Impl())
+ return m_opaque_sp->SetExpressionPathAtIndex(i, item);
+ else
+ return false;
+}
+
+void
+SBTypeFilter::AppendExpressionPath (const char* item)
+{
+ if (CopyOnWrite_Impl())
+ m_opaque_sp->AddExpressionPath(item);
+}
+
+lldb::SBTypeFilter &
+SBTypeFilter::operator = (const lldb::SBTypeFilter &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeFilter::operator == (lldb::SBTypeFilter &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ return m_opaque_sp == rhs.m_opaque_sp;
+}
+
+bool
+SBTypeFilter::IsEqualTo (lldb::SBTypeFilter &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ if (GetNumberOfExpressionPaths() != rhs.GetNumberOfExpressionPaths())
+ return false;
+
+ for (uint32_t j = 0;
+ j < GetNumberOfExpressionPaths();
+ j++)
+ if ( strcmp(GetExpressionPathAtIndex(j),rhs.GetExpressionPathAtIndex(j)) != 0)
+ return false;
+
+ return GetOptions() == rhs.GetOptions();
+}
+
+bool
+SBTypeFilter::operator != (lldb::SBTypeFilter &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ return m_opaque_sp != rhs.m_opaque_sp;
+}
+
+lldb::TypeFilterImplSP
+SBTypeFilter::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+void
+SBTypeFilter::SetSP (const lldb::TypeFilterImplSP &typefilter_impl_sp)
+{
+ m_opaque_sp = typefilter_impl_sp;
+}
+
+SBTypeFilter::SBTypeFilter (const lldb::TypeFilterImplSP &typefilter_impl_sp) :
+m_opaque_sp(typefilter_impl_sp)
+{
+}
+
+bool
+SBTypeFilter::CopyOnWrite_Impl()
+{
+ if (!IsValid())
+ return false;
+ if (m_opaque_sp.unique())
+ return true;
+
+ TypeFilterImplSP new_sp(new TypeFilterImpl(GetOptions()));
+
+ for (uint32_t j = 0;
+ j < GetNumberOfExpressionPaths();
+ j++)
+ new_sp->AddExpressionPath(GetExpressionPathAtIndex(j));
+
+ SetSP(new_sp);
+
+ return true;
+}
diff --git a/source/API/SBTypeFormat.cpp b/source/API/SBTypeFormat.cpp
new file mode 100644
index 000000000000..34ab404a206a
--- /dev/null
+++ b/source/API/SBTypeFormat.cpp
@@ -0,0 +1,155 @@
+//===-- SBTypeFormat.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/SBTypeFormat.h"
+
+#include "lldb/API/SBStream.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBTypeFormat::SBTypeFormat() :
+m_opaque_sp()
+{
+}
+
+SBTypeFormat::SBTypeFormat (lldb::Format format,
+ uint32_t options)
+: m_opaque_sp(TypeFormatImplSP(new TypeFormatImpl(format,options)))
+{
+}
+
+SBTypeFormat::SBTypeFormat (const lldb::SBTypeFormat &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+SBTypeFormat::~SBTypeFormat ()
+{
+}
+
+bool
+SBTypeFormat::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+lldb::Format
+SBTypeFormat::GetFormat ()
+{
+ if (IsValid())
+ return m_opaque_sp->GetFormat();
+ return lldb::eFormatInvalid;
+}
+
+uint32_t
+SBTypeFormat::GetOptions()
+{
+ if (IsValid())
+ return m_opaque_sp->GetOptions();
+ return 0;
+}
+
+void
+SBTypeFormat::SetFormat (lldb::Format fmt)
+{
+ if (CopyOnWrite_Impl())
+ m_opaque_sp->SetFormat(fmt);
+}
+
+void
+SBTypeFormat::SetOptions (uint32_t value)
+{
+ if (CopyOnWrite_Impl())
+ m_opaque_sp->SetOptions(value);
+}
+
+bool
+SBTypeFormat::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (!IsValid())
+ return false;
+ else {
+ description.Printf("%s\n",
+ m_opaque_sp->GetDescription().c_str());
+ return true;
+ }
+}
+
+lldb::SBTypeFormat &
+SBTypeFormat::operator = (const lldb::SBTypeFormat &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeFormat::operator == (lldb::SBTypeFormat &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp == rhs.m_opaque_sp;
+}
+
+bool
+SBTypeFormat::IsEqualTo (lldb::SBTypeFormat &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ if (GetFormat() == rhs.GetFormat())
+ return GetOptions() == rhs.GetOptions();
+ else
+ return false;
+}
+
+bool
+SBTypeFormat::operator != (lldb::SBTypeFormat &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp != rhs.m_opaque_sp;
+}
+
+lldb::TypeFormatImplSP
+SBTypeFormat::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+void
+SBTypeFormat::SetSP (const lldb::TypeFormatImplSP &typeformat_impl_sp)
+{
+ m_opaque_sp = typeformat_impl_sp;
+}
+
+SBTypeFormat::SBTypeFormat (const lldb::TypeFormatImplSP &typeformat_impl_sp) :
+ m_opaque_sp(typeformat_impl_sp)
+{
+}
+
+bool
+SBTypeFormat::CopyOnWrite_Impl()
+{
+ if (!IsValid())
+ return false;
+ if (m_opaque_sp.unique())
+ return true;
+
+ SetSP(TypeFormatImplSP(new TypeFormatImpl(GetFormat(),GetOptions())));
+ return true;
+}
diff --git a/source/API/SBTypeNameSpecifier.cpp b/source/API/SBTypeNameSpecifier.cpp
new file mode 100644
index 000000000000..d417499ecbd3
--- /dev/null
+++ b/source/API/SBTypeNameSpecifier.cpp
@@ -0,0 +1,150 @@
+//===-- SBTypeNameSpecifier.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/SBTypeNameSpecifier.h"
+
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBType.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBTypeNameSpecifier::SBTypeNameSpecifier() :
+m_opaque_sp()
+{
+}
+
+SBTypeNameSpecifier::SBTypeNameSpecifier (const char* name,
+ bool is_regex) :
+m_opaque_sp(new TypeNameSpecifierImpl(name, is_regex))
+{
+ if (name == NULL || (*name) == 0)
+ m_opaque_sp.reset();
+}
+
+SBTypeNameSpecifier::SBTypeNameSpecifier (SBType type) :
+m_opaque_sp()
+{
+ if (type.IsValid())
+ m_opaque_sp = TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(type.m_opaque_sp->GetClangASTType()));
+}
+
+SBTypeNameSpecifier::SBTypeNameSpecifier (const lldb::SBTypeNameSpecifier &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{}
+
+SBTypeNameSpecifier::~SBTypeNameSpecifier ()
+{
+}
+
+bool
+SBTypeNameSpecifier::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+const char*
+SBTypeNameSpecifier::GetName ()
+{
+ if (!IsValid())
+ return NULL;
+
+ return m_opaque_sp->GetName();
+}
+
+SBType
+SBTypeNameSpecifier::GetType ()
+{
+ if (!IsValid())
+ return SBType();
+ lldb_private::ClangASTType c_type = m_opaque_sp->GetClangASTType();
+ if (c_type.IsValid())
+ return SBType(c_type);
+ return SBType();
+}
+
+bool
+SBTypeNameSpecifier::IsRegex ()
+{
+ if (!IsValid())
+ return false;
+
+ return m_opaque_sp->IsRegex();
+}
+
+bool
+SBTypeNameSpecifier::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (!IsValid())
+ return false;
+ description.Printf("SBTypeNameSpecifier(%s,%s)", GetName(), IsRegex() ? "regex" : "plain");
+ return true;
+}
+
+lldb::SBTypeNameSpecifier &
+SBTypeNameSpecifier::operator = (const lldb::SBTypeNameSpecifier &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeNameSpecifier::operator == (lldb::SBTypeNameSpecifier &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp == rhs.m_opaque_sp;
+}
+
+bool
+SBTypeNameSpecifier::IsEqualTo (lldb::SBTypeNameSpecifier &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ if (IsRegex() != rhs.IsRegex())
+ return false;
+ if (GetName() == NULL || rhs.GetName() == NULL)
+ return false;
+
+ return (strcmp(GetName(), rhs.GetName()) == 0);
+}
+
+bool
+SBTypeNameSpecifier::operator != (lldb::SBTypeNameSpecifier &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp != rhs.m_opaque_sp;
+}
+
+lldb::TypeNameSpecifierImplSP
+SBTypeNameSpecifier::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+void
+SBTypeNameSpecifier::SetSP (const lldb::TypeNameSpecifierImplSP &type_namespec_sp)
+{
+ m_opaque_sp = type_namespec_sp;
+}
+
+SBTypeNameSpecifier::SBTypeNameSpecifier (const lldb::TypeNameSpecifierImplSP &type_namespec_sp) :
+m_opaque_sp(type_namespec_sp)
+{
+}
diff --git a/source/API/SBTypeSummary.cpp b/source/API/SBTypeSummary.cpp
new file mode 100644
index 000000000000..aaa09c289cb1
--- /dev/null
+++ b/source/API/SBTypeSummary.cpp
@@ -0,0 +1,335 @@
+//===-- SBTypeSummary.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/SBTypeSummary.h"
+
+#include "lldb/API/SBStream.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef LLDB_DISABLE_PYTHON
+
+SBTypeSummary::SBTypeSummary() :
+m_opaque_sp()
+{
+}
+
+SBTypeSummary
+SBTypeSummary::CreateWithSummaryString (const char* data, uint32_t options)
+{
+ if (!data || data[0] == 0)
+ return SBTypeSummary();
+
+ return SBTypeSummary(TypeSummaryImplSP(new StringSummaryFormat(options, data)));
+}
+
+SBTypeSummary
+SBTypeSummary::CreateWithFunctionName (const char* data, uint32_t options)
+{
+ if (!data || data[0] == 0)
+ return SBTypeSummary();
+
+ return SBTypeSummary(TypeSummaryImplSP(new ScriptSummaryFormat(options, data)));
+}
+
+SBTypeSummary
+SBTypeSummary::CreateWithScriptCode (const char* data, uint32_t options)
+{
+ if (!data || data[0] == 0)
+ return SBTypeSummary();
+
+ return SBTypeSummary(TypeSummaryImplSP(new ScriptSummaryFormat(options, "", data)));
+}
+
+SBTypeSummary::SBTypeSummary (const lldb::SBTypeSummary &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+SBTypeSummary::~SBTypeSummary ()
+{
+}
+
+bool
+SBTypeSummary::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+bool
+SBTypeSummary::IsFunctionCode()
+{
+ if (!IsValid())
+ return false;
+ if (m_opaque_sp->IsScripted())
+ {
+ ScriptSummaryFormat* script_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
+ const char* ftext = script_summary_ptr->GetPythonScript();
+ return (ftext && *ftext != 0);
+ }
+ return false;
+}
+
+bool
+SBTypeSummary::IsFunctionName()
+{
+ if (!IsValid())
+ return false;
+ if (m_opaque_sp->IsScripted())
+ {
+ ScriptSummaryFormat* script_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
+ const char* ftext = script_summary_ptr->GetPythonScript();
+ return (!ftext || *ftext == 0);
+ }
+ return false;
+}
+
+bool
+SBTypeSummary::IsSummaryString()
+{
+ if (!IsValid())
+ return false;
+
+ if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+ return false;
+
+ return !m_opaque_sp->IsScripted();
+}
+
+const char*
+SBTypeSummary::GetData ()
+{
+ if (!IsValid())
+ return NULL;
+ if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+ return NULL;
+ if (m_opaque_sp->IsScripted())
+ {
+ ScriptSummaryFormat* script_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
+ const char* fname = script_summary_ptr->GetFunctionName();
+ const char* ftext = script_summary_ptr->GetPythonScript();
+ if (ftext && *ftext)
+ return ftext;
+ return fname;
+ }
+ else
+ {
+ StringSummaryFormat* string_summary_ptr = (StringSummaryFormat*)m_opaque_sp.get();
+ return string_summary_ptr->GetSummaryString();
+ }
+}
+
+uint32_t
+SBTypeSummary::GetOptions ()
+{
+ if (!IsValid())
+ return lldb::eTypeOptionNone;
+ return m_opaque_sp->GetOptions();
+}
+
+void
+SBTypeSummary::SetOptions (uint32_t value)
+{
+ if (!CopyOnWrite_Impl())
+ return;
+ m_opaque_sp->SetOptions(value);
+}
+
+void
+SBTypeSummary::SetSummaryString (const char* data)
+{
+ if (!IsValid())
+ return;
+ if (m_opaque_sp->IsScripted() || (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback))
+ ChangeSummaryType(false);
+ ((StringSummaryFormat*)m_opaque_sp.get())->SetSummaryString(data);
+}
+
+void
+SBTypeSummary::SetFunctionName (const char* data)
+{
+ if (!IsValid())
+ return;
+ if (!m_opaque_sp->IsScripted())
+ ChangeSummaryType(true);
+ ((ScriptSummaryFormat*)m_opaque_sp.get())->SetFunctionName(data);
+}
+
+void
+SBTypeSummary::SetFunctionCode (const char* data)
+{
+ if (!IsValid())
+ return;
+ if (!m_opaque_sp->IsScripted())
+ ChangeSummaryType(true);
+ ((ScriptSummaryFormat*)m_opaque_sp.get())->SetPythonScript(data);
+}
+
+bool
+SBTypeSummary::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (!CopyOnWrite_Impl())
+ return false;
+ else {
+ description.Printf("%s\n",
+ m_opaque_sp->GetDescription().c_str());
+ return true;
+ }
+}
+
+lldb::SBTypeSummary &
+SBTypeSummary::operator = (const lldb::SBTypeSummary &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeSummary::operator == (lldb::SBTypeSummary &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp == rhs.m_opaque_sp;
+}
+
+bool
+SBTypeSummary::IsEqualTo (lldb::SBTypeSummary &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ if (m_opaque_sp->GetType() != rhs.m_opaque_sp->GetType())
+ return false;
+
+ if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+ {
+ lldb_private::CXXFunctionSummaryFormat *self_cxx = (lldb_private::CXXFunctionSummaryFormat*)m_opaque_sp.get();
+ lldb_private::CXXFunctionSummaryFormat *other_cxx = (lldb_private::CXXFunctionSummaryFormat*)rhs.m_opaque_sp.get();
+ return (self_cxx->m_impl == other_cxx->m_impl);
+ }
+
+ if (m_opaque_sp->IsScripted() != rhs.m_opaque_sp->IsScripted())
+ return false;
+
+ if (IsFunctionCode() != rhs.IsFunctionCode())
+ return false;
+
+ if (IsSummaryString() != rhs.IsSummaryString())
+ return false;
+
+ if (IsFunctionName() != rhs.IsFunctionName())
+ return false;
+
+ if ( GetData() == NULL || rhs.GetData() == NULL || strcmp(GetData(), rhs.GetData()) )
+ return false;
+
+ return GetOptions() == rhs.GetOptions();
+
+}
+
+bool
+SBTypeSummary::operator != (lldb::SBTypeSummary &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp != rhs.m_opaque_sp;
+}
+
+lldb::TypeSummaryImplSP
+SBTypeSummary::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+void
+SBTypeSummary::SetSP (const lldb::TypeSummaryImplSP &typesummary_impl_sp)
+{
+ m_opaque_sp = typesummary_impl_sp;
+}
+
+SBTypeSummary::SBTypeSummary (const lldb::TypeSummaryImplSP &typesummary_impl_sp) :
+m_opaque_sp(typesummary_impl_sp)
+{
+}
+
+bool
+SBTypeSummary::CopyOnWrite_Impl()
+{
+ if (!IsValid())
+ return false;
+
+ if (m_opaque_sp.unique())
+ return true;
+
+ TypeSummaryImplSP new_sp;
+
+ if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback)
+ {
+ CXXFunctionSummaryFormat* current_summary_ptr = (CXXFunctionSummaryFormat*)m_opaque_sp.get();
+ new_sp = TypeSummaryImplSP(new CXXFunctionSummaryFormat(GetOptions(),
+ current_summary_ptr->m_impl,
+ current_summary_ptr->m_description.c_str()));
+ }
+ else if (m_opaque_sp->IsScripted())
+ {
+ ScriptSummaryFormat* current_summary_ptr = (ScriptSummaryFormat*)m_opaque_sp.get();
+ new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(),
+ current_summary_ptr->GetFunctionName(),
+ current_summary_ptr->GetPythonScript()));
+ }
+ else {
+ StringSummaryFormat* current_summary_ptr = (StringSummaryFormat*)m_opaque_sp.get();
+ new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(),
+ current_summary_ptr->GetSummaryString()));
+ }
+
+ SetSP(new_sp);
+
+ return true;
+}
+
+bool
+SBTypeSummary::ChangeSummaryType (bool want_script)
+{
+ if (!IsValid())
+ return false;
+
+ TypeSummaryImplSP new_sp;
+
+ if (want_script == m_opaque_sp->IsScripted())
+ {
+ if (m_opaque_sp->GetType() == lldb_private::TypeSummaryImpl::eTypeCallback && !want_script)
+ new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
+ else
+ return CopyOnWrite_Impl();
+ }
+
+ if (!new_sp)
+ {
+ if (want_script)
+ new_sp = TypeSummaryImplSP(new ScriptSummaryFormat(GetOptions(), "", ""));
+ else
+ new_sp = TypeSummaryImplSP(new StringSummaryFormat(GetOptions(), ""));
+ }
+
+ SetSP(new_sp);
+
+ return true;
+}
+
+#endif // LLDB_DISABLE_PYTHON
diff --git a/source/API/SBTypeSynthetic.cpp b/source/API/SBTypeSynthetic.cpp
new file mode 100644
index 000000000000..681ed6c032ab
--- /dev/null
+++ b/source/API/SBTypeSynthetic.cpp
@@ -0,0 +1,209 @@
+//===-- SBTypeSynthetic.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/SBTypeSynthetic.h"
+
+#include "lldb/API/SBStream.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#ifndef LLDB_DISABLE_PYTHON
+
+SBTypeSynthetic::SBTypeSynthetic() :
+m_opaque_sp()
+{
+}
+
+SBTypeSynthetic
+SBTypeSynthetic::CreateWithClassName (const char* data, uint32_t options)
+{
+ if (!data || data[0] == 0)
+ return SBTypeSynthetic();
+ return SBTypeSynthetic(ScriptedSyntheticChildrenSP(new ScriptedSyntheticChildren(options, data, "")));
+}
+
+SBTypeSynthetic
+SBTypeSynthetic::CreateWithScriptCode (const char* data, uint32_t options)
+{
+ if (!data || data[0] == 0)
+ return SBTypeSynthetic();
+ return SBTypeSynthetic(ScriptedSyntheticChildrenSP(new ScriptedSyntheticChildren(options, "", data)));
+}
+
+SBTypeSynthetic::SBTypeSynthetic (const lldb::SBTypeSynthetic &rhs) :
+m_opaque_sp(rhs.m_opaque_sp)
+{
+}
+
+SBTypeSynthetic::~SBTypeSynthetic ()
+{
+}
+
+bool
+SBTypeSynthetic::IsValid() const
+{
+ return m_opaque_sp.get() != NULL;
+}
+
+bool
+SBTypeSynthetic::IsClassCode()
+{
+ if (!IsValid())
+ return false;
+ const char* code = m_opaque_sp->GetPythonCode();
+ return (code && *code);
+}
+
+bool
+SBTypeSynthetic::IsClassName()
+{
+ if (!IsValid())
+ return false;
+ return !IsClassCode();
+}
+
+const char*
+SBTypeSynthetic::GetData ()
+{
+ if (!IsValid())
+ return NULL;
+ if (IsClassCode())
+ return m_opaque_sp->GetPythonCode();
+ else
+ return m_opaque_sp->GetPythonClassName();
+}
+
+void
+SBTypeSynthetic::SetClassName (const char* data)
+{
+ if (IsValid() && data && *data)
+ m_opaque_sp->SetPythonClassName(data);
+}
+
+void
+SBTypeSynthetic::SetClassCode (const char* data)
+{
+ if (IsValid() && data && *data)
+ m_opaque_sp->SetPythonCode(data);
+}
+
+uint32_t
+SBTypeSynthetic::GetOptions ()
+{
+ if (!IsValid())
+ return lldb::eTypeOptionNone;
+ return m_opaque_sp->GetOptions();
+}
+
+void
+SBTypeSynthetic::SetOptions (uint32_t value)
+{
+ if (!CopyOnWrite_Impl())
+ return;
+ m_opaque_sp->SetOptions(value);
+}
+
+bool
+SBTypeSynthetic::GetDescription (lldb::SBStream &description,
+ lldb::DescriptionLevel description_level)
+{
+ if (m_opaque_sp)
+ {
+ description.Printf("%s\n",
+ m_opaque_sp->GetDescription().c_str());
+ return true;
+ }
+ return false;
+}
+
+lldb::SBTypeSynthetic &
+SBTypeSynthetic::operator = (const lldb::SBTypeSynthetic &rhs)
+{
+ if (this != &rhs)
+ {
+ m_opaque_sp = rhs.m_opaque_sp;
+ }
+ return *this;
+}
+
+bool
+SBTypeSynthetic::operator == (lldb::SBTypeSynthetic &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp == rhs.m_opaque_sp;
+}
+
+bool
+SBTypeSynthetic::IsEqualTo (lldb::SBTypeSynthetic &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+
+ if (m_opaque_sp->IsScripted() != rhs.m_opaque_sp->IsScripted())
+ return false;
+
+ if (IsClassCode() != rhs.IsClassCode())
+ return false;
+
+ if ( strcmp(GetData(), rhs.GetData()) )
+ return false;
+
+ return GetOptions() == rhs.GetOptions();
+
+}
+
+bool
+SBTypeSynthetic::operator != (lldb::SBTypeSynthetic &rhs)
+{
+ if (IsValid() == false)
+ return !rhs.IsValid();
+ return m_opaque_sp != rhs.m_opaque_sp;
+}
+
+lldb::ScriptedSyntheticChildrenSP
+SBTypeSynthetic::GetSP ()
+{
+ return m_opaque_sp;
+}
+
+void
+SBTypeSynthetic::SetSP (const lldb::ScriptedSyntheticChildrenSP &TypeSynthetic_impl_sp)
+{
+ m_opaque_sp = TypeSynthetic_impl_sp;
+}
+
+SBTypeSynthetic::SBTypeSynthetic (const lldb::ScriptedSyntheticChildrenSP &TypeSynthetic_impl_sp) :
+m_opaque_sp(TypeSynthetic_impl_sp)
+{
+}
+
+bool
+SBTypeSynthetic::CopyOnWrite_Impl()
+{
+ if (!IsValid())
+ return false;
+ if (m_opaque_sp.unique())
+ return true;
+
+ ScriptedSyntheticChildrenSP new_sp(new ScriptedSyntheticChildren(m_opaque_sp->GetOptions(),
+ m_opaque_sp->GetPythonClassName(),
+ m_opaque_sp->GetPythonCode()));
+
+ SetSP(new_sp);
+
+ return true;
+}
+
+#endif // LLDB_DISABLE_PYTHON
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
new file mode 100644
index 000000000000..aa9b23ac7c69
--- /dev/null
+++ b/source/API/SBValue.cpp
@@ -0,0 +1,1719 @@
+//===-- SBValue.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/SBValue.h"
+
+#include "lldb/API/SBDeclaration.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTypeFilter.h"
+#include "lldb/API/SBTypeFormat.h"
+#include "lldb/API/SBTypeSummary.h"
+#include "lldb/API/SBTypeSynthetic.h"
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Declaration.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBExpressionOptions.h"
+#include "lldb/API/SBFrame.h"
+#include "lldb/API/SBProcess.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueImpl
+{
+public:
+ ValueImpl ()
+ {
+ }
+
+ ValueImpl (lldb::ValueObjectSP in_valobj_sp,
+ lldb::DynamicValueType use_dynamic,
+ bool use_synthetic,
+ const char *name = NULL) :
+ m_valobj_sp(in_valobj_sp),
+ m_use_dynamic(use_dynamic),
+ m_use_synthetic(use_synthetic),
+ m_name (name)
+ {
+ if (!m_name.IsEmpty() && m_valobj_sp)
+ m_valobj_sp->SetName(m_name);
+ }
+
+ ValueImpl (const ValueImpl& rhs) :
+ m_valobj_sp(rhs.m_valobj_sp),
+ m_use_dynamic(rhs.m_use_dynamic),
+ m_use_synthetic(rhs.m_use_synthetic),
+ m_name (rhs.m_name)
+ {
+ }
+
+ ValueImpl &
+ operator = (const ValueImpl &rhs)
+ {
+ if (this != &rhs)
+ {
+ m_valobj_sp = rhs.m_valobj_sp;
+ m_use_dynamic = rhs.m_use_dynamic;
+ m_use_synthetic = rhs.m_use_synthetic;
+ m_name = rhs.m_name;
+ }
+ return *this;
+ }
+
+ bool
+ IsValid ()
+ {
+ return m_valobj_sp.get() != NULL;
+ }
+
+ lldb::ValueObjectSP
+ GetRootSP ()
+ {
+ return m_valobj_sp;
+ }
+
+ lldb::ValueObjectSP
+ GetSP (Process::StopLocker &stop_locker, Mutex::Locker &api_locker, Error &error)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (!m_valobj_sp)
+ {
+ error.SetErrorString("invalid value object");
+ return m_valobj_sp;
+ }
+
+ lldb::ValueObjectSP value_sp = m_valobj_sp;
+
+ Target *target = value_sp->GetTargetSP().get();
+ if (target)
+ api_locker.Lock(target->GetAPIMutex());
+
+ ProcessSP process_sp(value_sp->GetProcessSP());
+ if (process_sp && !stop_locker.TryLock (&process_sp->GetRunLock()))
+ {
+ // We don't allow people to play around with ValueObject if the process is running.
+ // If you want to look at values, pause the process, then look.
+ if (log)
+ log->Printf ("SBValue(%p)::GetSP() => error: process is running", value_sp.get());
+ error.SetErrorString ("process must be stopped.");
+ return ValueObjectSP();
+ }
+
+ if (value_sp->GetDynamicValue(m_use_dynamic))
+ value_sp = value_sp->GetDynamicValue(m_use_dynamic);
+ if (value_sp->GetSyntheticValue(m_use_synthetic))
+ value_sp = value_sp->GetSyntheticValue(m_use_synthetic);
+ if (!value_sp)
+ error.SetErrorString("invalid value object");
+ if (!m_name.IsEmpty())
+ value_sp->SetName(m_name);
+
+ return value_sp;
+ }
+
+ void
+ SetUseDynamic (lldb::DynamicValueType use_dynamic)
+ {
+ m_use_dynamic = use_dynamic;
+ }
+
+ void
+ SetUseSynthetic (bool use_synthetic)
+ {
+ m_use_synthetic = use_synthetic;
+ }
+
+ lldb::DynamicValueType
+ GetUseDynamic ()
+ {
+ return m_use_dynamic;
+ }
+
+ bool
+ GetUseSynthetic ()
+ {
+ return m_use_synthetic;
+ }
+
+ // All the derived values that we would make from the m_valobj_sp will share
+ // the ExecutionContext with m_valobj_sp, so we don't need to do the calculations
+ // in GetSP to return the Target, Process, Thread or Frame. It is convenient to
+ // provide simple accessors for these, which I do here.
+ TargetSP
+ GetTargetSP ()
+ {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetTargetSP();
+ else
+ return TargetSP();
+ }
+
+ ProcessSP
+ GetProcessSP ()
+ {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetProcessSP();
+ else
+ return ProcessSP();
+ }
+
+ ThreadSP
+ GetThreadSP ()
+ {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetThreadSP();
+ else
+ return ThreadSP();
+ }
+
+ StackFrameSP
+ GetFrameSP ()
+ {
+ if (m_valobj_sp)
+ return m_valobj_sp->GetFrameSP();
+ else
+ return StackFrameSP();
+ }
+
+private:
+ lldb::ValueObjectSP m_valobj_sp;
+ lldb::DynamicValueType m_use_dynamic;
+ bool m_use_synthetic;
+ ConstString m_name;
+};
+
+class ValueLocker
+{
+public:
+ ValueLocker ()
+ {
+ }
+
+ ValueObjectSP
+ GetLockedSP(ValueImpl &in_value)
+ {
+ return in_value.GetSP(m_stop_locker, m_api_locker, m_lock_error);
+ }
+
+ Error &
+ GetError()
+ {
+ return m_lock_error;
+ }
+
+private:
+ Process::StopLocker m_stop_locker;
+ Mutex::Locker m_api_locker;
+ Error m_lock_error;
+
+};
+
+SBValue::SBValue () :
+ m_opaque_sp ()
+{
+}
+
+SBValue::SBValue (const lldb::ValueObjectSP &value_sp)
+{
+ SetSP(value_sp);
+}
+
+SBValue::SBValue(const SBValue &rhs)
+{
+ SetSP(rhs.m_opaque_sp);
+}
+
+SBValue &
+SBValue::operator = (const SBValue &rhs)
+{
+ if (this != &rhs)
+ {
+ SetSP(rhs.m_opaque_sp);
+ }
+ return *this;
+}
+
+SBValue::~SBValue()
+{
+}
+
+bool
+SBValue::IsValid ()
+{
+ // If this function ever changes to anything that does more than just
+ // check if the opaque shared pointer is non NULL, then we need to update
+ // all "if (m_opaque_sp)" code in this file.
+ return m_opaque_sp.get() != NULL && m_opaque_sp->GetRootSP().get() != NULL;
+}
+
+void
+SBValue::Clear()
+{
+ m_opaque_sp.reset();
+}
+
+SBError
+SBValue::GetError()
+{
+ SBError sb_error;
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ sb_error.SetError(value_sp->GetError());
+ else
+ sb_error.SetErrorStringWithFormat ("error: %s", locker.GetError().AsCString());
+
+ return sb_error;
+}
+
+user_id_t
+SBValue::GetID()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ return value_sp->GetID();
+ return LLDB_INVALID_UID;
+}
+
+const char *
+SBValue::GetName()
+{
+ const char *name = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ name = value_sp->GetName().GetCString();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (name)
+ log->Printf ("SBValue(%p)::GetName () => \"%s\"", value_sp.get(), name);
+ else
+ log->Printf ("SBValue(%p)::GetName () => NULL", value_sp.get());
+ }
+
+ return name;
+}
+
+const char *
+SBValue::GetTypeName ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *name = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ name = value_sp->GetQualifiedTypeName().GetCString();
+ }
+
+ if (log)
+ {
+ if (name)
+ log->Printf ("SBValue(%p)::GetTypeName () => \"%s\"", value_sp.get(), name);
+ else
+ log->Printf ("SBValue(%p)::GetTypeName () => NULL", value_sp.get());
+ }
+
+ return name;
+}
+
+size_t
+SBValue::GetByteSize ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ size_t result = 0;
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ result = value_sp->GetByteSize();
+ }
+
+ if (log)
+ log->Printf ("SBValue(%p)::GetByteSize () => %" PRIu64, value_sp.get(), (uint64_t)result);
+
+ return result;
+}
+
+bool
+SBValue::IsInScope ()
+{
+ bool result = false;
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ result = value_sp->IsInScope ();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::IsInScope () => %i", value_sp.get(), result);
+
+ return result;
+}
+
+const char *
+SBValue::GetValue ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ const char *cstr = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ cstr = value_sp->GetValueAsCString ();
+ }
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetValue() => \"%s\"", value_sp.get(), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetValue() => NULL", value_sp.get());
+ }
+
+ return cstr;
+}
+
+ValueType
+SBValue::GetValueType ()
+{
+ ValueType result = eValueTypeInvalid;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ result = value_sp->GetValueType();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ switch (result)
+ {
+ case eValueTypeInvalid: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeInvalid", value_sp.get()); break;
+ case eValueTypeVariableGlobal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableGlobal", value_sp.get()); break;
+ case eValueTypeVariableStatic: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableStatic", value_sp.get()); break;
+ case eValueTypeVariableArgument:log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableArgument", value_sp.get()); break;
+ case eValueTypeVariableLocal: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeVariableLocal", value_sp.get()); break;
+ case eValueTypeRegister: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegister", value_sp.get()); break;
+ case eValueTypeRegisterSet: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeRegisterSet", value_sp.get()); break;
+ case eValueTypeConstResult: log->Printf ("SBValue(%p)::GetValueType () => eValueTypeConstResult", value_sp.get()); break;
+ }
+ }
+ return result;
+}
+
+const char *
+SBValue::GetObjectDescription ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *cstr = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ cstr = value_sp->GetObjectDescription ();
+ }
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetObjectDescription() => \"%s\"", value_sp.get(), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetObjectDescription() => NULL", value_sp.get());
+ }
+ return cstr;
+}
+
+SBType
+SBValue::GetType()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ SBType sb_type;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ TypeImplSP type_sp;
+ if (value_sp)
+ {
+ type_sp.reset (new TypeImpl(value_sp->GetClangType()));
+ sb_type.SetSP(type_sp);
+ }
+ if (log)
+ {
+ if (type_sp)
+ log->Printf ("SBValue(%p)::GetType => SBType(%p)", value_sp.get(), type_sp.get());
+ else
+ log->Printf ("SBValue(%p)::GetType => NULL", value_sp.get());
+ }
+ return sb_type;
+}
+
+bool
+SBValue::GetValueDidChange ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool result = false;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ result = value_sp->GetValueDidChange ();
+ }
+ if (log)
+ log->Printf ("SBValue(%p)::GetValueDidChange() => %i", value_sp.get(), result);
+
+ return result;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+const char *
+SBValue::GetSummary ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *cstr = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ cstr = value_sp->GetSummaryAsCString();
+ }
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetSummary() => \"%s\"", value_sp.get(), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetSummary() => NULL", value_sp.get());
+ }
+ return cstr;
+}
+#endif // LLDB_DISABLE_PYTHON
+
+const char *
+SBValue::GetLocation ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ const char *cstr = NULL;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ cstr = value_sp->GetLocationAsCString();
+ }
+ if (log)
+ {
+ if (cstr)
+ log->Printf ("SBValue(%p)::GetLocation() => \"%s\"", value_sp.get(), cstr);
+ else
+ log->Printf ("SBValue(%p)::GetLocation() => NULL", value_sp.get());
+ }
+ return cstr;
+}
+
+// Deprecated - use the one that takes an lldb::SBError
+bool
+SBValue::SetValueFromCString (const char *value_str)
+{
+ lldb::SBError dummy;
+ return SetValueFromCString(value_str,dummy);
+}
+
+bool
+SBValue::SetValueFromCString (const char *value_str, lldb::SBError& error)
+{
+ bool success = false;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (value_sp)
+ {
+ success = value_sp->SetValueFromCString (value_str,error.ref());
+ }
+ else
+ error.SetErrorStringWithFormat ("Could not get value: %s", locker.GetError().AsCString());
+
+ if (log)
+ log->Printf ("SBValue(%p)::SetValueFromCString(\"%s\") => %i", value_sp.get(), value_str, success);
+
+ return success;
+}
+
+lldb::SBTypeFormat
+SBValue::GetTypeFormat ()
+{
+ lldb::SBTypeFormat format;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ if (value_sp->UpdateValueIfNeeded(true))
+ {
+ lldb::TypeFormatImplSP format_sp = value_sp->GetValueFormat();
+ if (format_sp)
+ format.SetSP(format_sp);
+ }
+ }
+ return format;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SBTypeSummary
+SBValue::GetTypeSummary ()
+{
+ lldb::SBTypeSummary summary;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ if (value_sp->UpdateValueIfNeeded(true))
+ {
+ lldb::TypeSummaryImplSP summary_sp = value_sp->GetSummaryFormat();
+ if (summary_sp)
+ summary.SetSP(summary_sp);
+ }
+ }
+ return summary;
+}
+#endif // LLDB_DISABLE_PYTHON
+
+lldb::SBTypeFilter
+SBValue::GetTypeFilter ()
+{
+ lldb::SBTypeFilter filter;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ if (value_sp->UpdateValueIfNeeded(true))
+ {
+ lldb::SyntheticChildrenSP synthetic_sp = value_sp->GetSyntheticChildren();
+
+ if (synthetic_sp && !synthetic_sp->IsScripted())
+ {
+ TypeFilterImplSP filter_sp = std::static_pointer_cast<TypeFilterImpl>(synthetic_sp);
+ filter.SetSP(filter_sp);
+ }
+ }
+ }
+ return filter;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SBTypeSynthetic
+SBValue::GetTypeSynthetic ()
+{
+ lldb::SBTypeSynthetic synthetic;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ if (value_sp->UpdateValueIfNeeded(true))
+ {
+ lldb::SyntheticChildrenSP children_sp = value_sp->GetSyntheticChildren();
+
+ if (children_sp && children_sp->IsScripted())
+ {
+ ScriptedSyntheticChildrenSP synth_sp = std::static_pointer_cast<ScriptedSyntheticChildren>(children_sp);
+ synthetic.SetSP(synth_sp);
+ }
+ }
+ }
+ return synthetic;
+}
+#endif
+
+lldb::SBValue
+SBValue::CreateChildAtOffset (const char *name, uint32_t offset, SBType type)
+{
+ lldb::SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ lldb::ValueObjectSP new_value_sp;
+ if (value_sp)
+ {
+ TypeImplSP type_sp (type.GetSP());
+ if (type.IsValid())
+ {
+ sb_value.SetSP(value_sp->GetSyntheticChildAtOffset(offset, type_sp->GetClangASTType(), true),GetPreferDynamicValue(),GetPreferSyntheticValue(), name);
+ }
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"",
+ value_sp.get(),
+ new_value_sp->GetName().AsCString());
+ else
+ log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL",
+ value_sp.get());
+ }
+ return sb_value;
+}
+
+lldb::SBValue
+SBValue::Cast (SBType type)
+{
+ lldb::SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ TypeImplSP type_sp (type.GetSP());
+ if (value_sp && type_sp)
+ sb_value.SetSP(value_sp->Cast(type_sp->GetClangASTType()),GetPreferDynamicValue(),GetPreferSyntheticValue());
+ return sb_value;
+}
+
+lldb::SBValue
+SBValue::CreateValueFromExpression (const char *name, const char* expression)
+{
+ SBExpressionOptions options;
+ options.ref().SetKeepInMemory(true);
+ return CreateValueFromExpression (name, expression, options);
+}
+
+lldb::SBValue
+SBValue::CreateValueFromExpression (const char *name, const char *expression, SBExpressionOptions &options)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ lldb::ValueObjectSP new_value_sp;
+ 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);
+ }
+ }
+ }
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBValue(%p)::CreateValueFromExpression(name=\"%s\", expression=\"%s\") => SBValue (%p)",
+ value_sp.get(),
+ name,
+ expression,
+ new_value_sp.get());
+ else
+ log->Printf ("SBValue(%p)::CreateValueFromExpression(name=\"%s\", expression=\"%s\") => NULL",
+ value_sp.get(),
+ name,
+ expression);
+ }
+ return sb_value;
+}
+
+lldb::SBValue
+SBValue::CreateValueFromAddress(const char* name, lldb::addr_t address, SBType sb_type)
+{
+ lldb::SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ lldb::ValueObjectSP new_value_sp;
+ lldb::TypeImplSP type_impl_sp (sb_type.GetSP());
+ if (value_sp && type_impl_sp)
+ {
+ ClangASTType pointee_ast_type(type_impl_sp->GetClangASTType().GetPointerType ());
+ if (pointee_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(),
+ pointee_ast_type,
+ ConstString(name),
+ buffer,
+ lldb::endian::InlHostByteOrder(),
+ 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);
+ }
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBValue(%p)::CreateValueFromAddress => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString());
+ else
+ log->Printf ("SBValue(%p)::CreateValueFromAddress => NULL", value_sp.get());
+ }
+ return sb_value;
+}
+
+lldb::SBValue
+SBValue::CreateValueFromData (const char* name, SBData data, SBType type)
+{
+ lldb::SBValue sb_value;
+ lldb::ValueObjectSP new_value_sp;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ ExecutionContext exe_ctx (value_sp->GetExecutionContextRef());
+
+ new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ type.m_opaque_sp->GetClangASTType(),
+ ConstString(name),
+ *data.m_opaque_sp,
+ LLDB_INVALID_ADDRESS);
+ new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
+ sb_value.SetSP(new_value_sp);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (new_value_sp)
+ log->Printf ("SBValue(%p)::CreateValueFromData => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString());
+ else
+ log->Printf ("SBValue(%p)::CreateValueFromData => NULL", value_sp.get());
+ }
+ return sb_value;
+}
+
+SBValue
+SBValue::GetChildAtIndex (uint32_t idx)
+{
+ const bool can_create_synthetic = false;
+ lldb::DynamicValueType use_dynamic = eNoDynamicValues;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ target_sp = m_opaque_sp->GetTargetSP();
+
+ if (target_sp)
+ use_dynamic = target_sp->GetPreferDynamicValue();
+
+ return GetChildAtIndex (idx, use_dynamic, can_create_synthetic);
+}
+
+SBValue
+SBValue::GetChildAtIndex (uint32_t idx, lldb::DynamicValueType use_dynamic, bool can_create_synthetic)
+{
+ lldb::ValueObjectSP child_sp;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ const bool can_create = true;
+ child_sp = value_sp->GetChildAtIndex (idx, can_create);
+ if (can_create_synthetic && !child_sp)
+ {
+ if (value_sp->IsPointerType())
+ {
+ child_sp = value_sp->GetSyntheticArrayMemberFromPointer(idx, can_create);
+ }
+ else if (value_sp->IsArrayType())
+ {
+ child_sp = value_sp->GetSyntheticArrayMemberFromArray(idx, can_create);
+ }
+ }
+ }
+
+ SBValue sb_value;
+ sb_value.SetSP (child_sp, use_dynamic, GetPreferSyntheticValue());
+ if (log)
+ log->Printf ("SBValue(%p)::GetChildAtIndex (%u) => SBValue(%p)", value_sp.get(), idx, value_sp.get());
+
+ return sb_value;
+}
+
+uint32_t
+SBValue::GetIndexOfChildWithName (const char *name)
+{
+ uint32_t idx = UINT32_MAX;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ idx = value_sp->GetIndexOfChildWithName (ConstString(name));
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (idx == UINT32_MAX)
+ log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => NOT FOUND", value_sp.get(), name);
+ else
+ log->Printf ("SBValue(%p)::GetIndexOfChildWithName (name=\"%s\") => %u", value_sp.get(), name, idx);
+ }
+ return idx;
+}
+
+SBValue
+SBValue::GetChildMemberWithName (const char *name)
+{
+ lldb::DynamicValueType use_dynamic_value = eNoDynamicValues;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ target_sp = m_opaque_sp->GetTargetSP();
+
+ if (target_sp)
+ use_dynamic_value = target_sp->GetPreferDynamicValue();
+ return GetChildMemberWithName (name, use_dynamic_value);
+}
+
+SBValue
+SBValue::GetChildMemberWithName (const char *name, lldb::DynamicValueType use_dynamic_value)
+{
+ lldb::ValueObjectSP child_sp;
+ const ConstString str_name (name);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ child_sp = value_sp->GetChildMemberWithName (str_name, true);
+ }
+
+ SBValue sb_value;
+ sb_value.SetSP(child_sp, use_dynamic_value, GetPreferSyntheticValue());
+
+ if (log)
+ log->Printf ("SBValue(%p)::GetChildMemberWithName (name=\"%s\") => SBValue(%p)", value_sp.get(), name, value_sp.get());
+
+ return sb_value;
+}
+
+lldb::SBValue
+SBValue::GetDynamicValue (lldb::DynamicValueType use_dynamic)
+{
+ SBValue value_sb;
+ if (IsValid())
+ {
+ ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),use_dynamic,m_opaque_sp->GetUseSynthetic()));
+ value_sb.SetSP(proxy_sp);
+ }
+ return value_sb;
+}
+
+lldb::SBValue
+SBValue::GetStaticValue ()
+{
+ SBValue value_sb;
+ if (IsValid())
+ {
+ ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),eNoDynamicValues,m_opaque_sp->GetUseSynthetic()));
+ value_sb.SetSP(proxy_sp);
+ }
+ return value_sb;
+}
+
+lldb::SBValue
+SBValue::GetNonSyntheticValue ()
+{
+ SBValue value_sb;
+ if (IsValid())
+ {
+ ValueImplSP proxy_sp(new ValueImpl(m_opaque_sp->GetRootSP(),m_opaque_sp->GetUseDynamic(),false));
+ value_sb.SetSP(proxy_sp);
+ }
+ return value_sb;
+}
+
+lldb::DynamicValueType
+SBValue::GetPreferDynamicValue ()
+{
+ if (!IsValid())
+ return eNoDynamicValues;
+ return m_opaque_sp->GetUseDynamic();
+}
+
+void
+SBValue::SetPreferDynamicValue (lldb::DynamicValueType use_dynamic)
+{
+ if (IsValid())
+ return m_opaque_sp->SetUseDynamic (use_dynamic);
+}
+
+bool
+SBValue::GetPreferSyntheticValue ()
+{
+ if (!IsValid())
+ return false;
+ return m_opaque_sp->GetUseSynthetic();
+}
+
+void
+SBValue::SetPreferSyntheticValue (bool use_synthetic)
+{
+ if (IsValid())
+ return m_opaque_sp->SetUseSynthetic (use_synthetic);
+}
+
+bool
+SBValue::IsDynamic()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ return value_sp->IsDynamic();
+ return false;
+}
+
+bool
+SBValue::IsSynthetic ()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ return value_sp->IsSynthetic();
+ return false;
+}
+
+lldb::SBValue
+SBValue::GetValueForExpressionPath(const char* expr_path)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::ValueObjectSP child_sp;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ // using default values for all the fancy options, just do it if you can
+ child_sp = value_sp->GetValueForExpressionPath(expr_path);
+ }
+
+ SBValue sb_value;
+ sb_value.SetSP(child_sp,GetPreferDynamicValue(),GetPreferSyntheticValue());
+
+ if (log)
+ log->Printf ("SBValue(%p)::GetValueForExpressionPath (expr_path=\"%s\") => SBValue(%p)", value_sp.get(), expr_path, value_sp.get());
+
+ return sb_value;
+}
+
+int64_t
+SBValue::GetValueAsSigned(SBError& error, int64_t fail_value)
+{
+ error.Clear();
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Scalar scalar;
+ if (value_sp->ResolveValue (scalar))
+ return scalar.SLongLong (fail_value);
+ else
+ error.SetErrorString ("could not resolve value");
+ }
+ else
+ error.SetErrorStringWithFormat ("could not get SBValue: %s", locker.GetError().AsCString());
+
+ return fail_value;
+}
+
+uint64_t
+SBValue::GetValueAsUnsigned(SBError& error, uint64_t fail_value)
+{
+ error.Clear();
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Scalar scalar;
+ if (value_sp->ResolveValue (scalar))
+ return scalar.ULongLong(fail_value);
+ else
+ error.SetErrorString("could not resolve value");
+ }
+ else
+ error.SetErrorStringWithFormat ("could not get SBValue: %s", locker.GetError().AsCString());
+
+ return fail_value;
+}
+
+int64_t
+SBValue::GetValueAsSigned(int64_t fail_value)
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Scalar scalar;
+ if (value_sp->ResolveValue (scalar))
+ return scalar.SLongLong(fail_value);
+ }
+ return fail_value;
+}
+
+uint64_t
+SBValue::GetValueAsUnsigned(uint64_t fail_value)
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Scalar scalar;
+ if (value_sp->ResolveValue (scalar))
+ return scalar.ULongLong(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+SBValue::MightHaveChildren ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ bool has_children = false;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ has_children = value_sp->MightHaveChildren();
+
+ if (log)
+ log->Printf ("SBValue(%p)::MightHaveChildren() => %i", value_sp.get(), has_children);
+ return has_children;
+}
+
+uint32_t
+SBValue::GetNumChildren ()
+{
+ uint32_t num_children = 0;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ num_children = value_sp->GetNumChildren();
+
+ if (log)
+ log->Printf ("SBValue(%p)::GetNumChildren () => %u", value_sp.get(), num_children);
+
+ return num_children;
+}
+
+
+SBValue
+SBValue::Dereference ()
+{
+ SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Error error;
+ sb_value = value_sp->Dereference (error);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::Dereference () => SBValue(%p)", value_sp.get(), value_sp.get());
+
+ return sb_value;
+}
+
+bool
+SBValue::TypeIsPointerType ()
+{
+ bool is_ptr_type = false;
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ is_ptr_type = value_sp->IsPointerType();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::TypeIsPointerType () => %i", value_sp.get(), is_ptr_type);
+
+
+ return is_ptr_type;
+}
+
+void *
+SBValue::GetOpaqueType()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ return value_sp->GetClangType().GetOpaqueQualType();
+ return NULL;
+}
+
+lldb::SBTarget
+SBValue::GetTarget()
+{
+ SBTarget sb_target;
+ TargetSP target_sp;
+ if (m_opaque_sp)
+ {
+ target_sp = m_opaque_sp->GetTargetSP();
+ sb_target.SetSP (target_sp);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (target_sp.get() == NULL)
+ log->Printf ("SBValue(%p)::GetTarget () => NULL", m_opaque_sp.get());
+ else
+ log->Printf ("SBValue(%p)::GetTarget () => %p", m_opaque_sp.get(), target_sp.get());
+ }
+ return sb_target;
+}
+
+lldb::SBProcess
+SBValue::GetProcess()
+{
+ SBProcess sb_process;
+ ProcessSP process_sp;
+ if (m_opaque_sp)
+ {
+ process_sp = m_opaque_sp->GetProcessSP();
+ sb_process.SetSP (process_sp);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (process_sp.get() == NULL)
+ log->Printf ("SBValue(%p)::GetProcess () => NULL", m_opaque_sp.get());
+ else
+ log->Printf ("SBValue(%p)::GetProcess () => %p", m_opaque_sp.get(), process_sp.get());
+ }
+ return sb_process;
+}
+
+lldb::SBThread
+SBValue::GetThread()
+{
+ SBThread sb_thread;
+ ThreadSP thread_sp;
+ if (m_opaque_sp)
+ {
+ thread_sp = m_opaque_sp->GetThreadSP();
+ sb_thread.SetThread(thread_sp);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (thread_sp.get() == NULL)
+ log->Printf ("SBValue(%p)::GetThread () => NULL", m_opaque_sp.get());
+ else
+ log->Printf ("SBValue(%p)::GetThread () => %p", m_opaque_sp.get(), thread_sp.get());
+ }
+ return sb_thread;
+}
+
+lldb::SBFrame
+SBValue::GetFrame()
+{
+ SBFrame sb_frame;
+ StackFrameSP frame_sp;
+ if (m_opaque_sp)
+ {
+ frame_sp = m_opaque_sp->GetFrameSP();
+ sb_frame.SetFrameSP (frame_sp);
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ {
+ if (frame_sp.get() == NULL)
+ log->Printf ("SBValue(%p)::GetFrame () => NULL", m_opaque_sp.get());
+ else
+ log->Printf ("SBValue(%p)::GetFrame () => %p", m_opaque_sp.get(), frame_sp.get());
+ }
+ return sb_frame;
+}
+
+
+lldb::ValueObjectSP
+SBValue::GetSP (ValueLocker &locker) const
+{
+ if (!m_opaque_sp || !m_opaque_sp->IsValid())
+ return ValueObjectSP();
+ return locker.GetLockedSP(*m_opaque_sp.get());
+}
+
+lldb::ValueObjectSP
+SBValue::GetSP () const
+{
+ ValueLocker locker;
+ return GetSP(locker);
+}
+
+void
+SBValue::SetSP (ValueImplSP impl_sp)
+{
+ m_opaque_sp = impl_sp;
+}
+
+void
+SBValue::SetSP (const lldb::ValueObjectSP &sp)
+{
+ if (sp)
+ {
+ lldb::TargetSP target_sp(sp->GetTargetSP());
+ if (target_sp)
+ {
+ lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue();
+ bool use_synthetic = target_sp->TargetProperties::GetEnableSyntheticValue();
+ m_opaque_sp = ValueImplSP(new ValueImpl(sp, use_dynamic, use_synthetic));
+ }
+ else
+ m_opaque_sp = ValueImplSP(new ValueImpl(sp,eNoDynamicValues,true));
+ }
+ else
+ m_opaque_sp = ValueImplSP(new ValueImpl(sp,eNoDynamicValues,false));
+}
+
+void
+SBValue::SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic)
+{
+ if (sp)
+ {
+ lldb::TargetSP target_sp(sp->GetTargetSP());
+ if (target_sp)
+ {
+ bool use_synthetic = target_sp->TargetProperties::GetEnableSyntheticValue();
+ SetSP (sp, use_dynamic, use_synthetic);
+ }
+ else
+ SetSP (sp, use_dynamic, true);
+ }
+ else
+ SetSP (sp, use_dynamic, false);
+}
+
+void
+SBValue::SetSP (const lldb::ValueObjectSP &sp, bool use_synthetic)
+{
+ if (sp)
+ {
+ lldb::TargetSP target_sp(sp->GetTargetSP());
+ if (target_sp)
+ {
+ lldb::DynamicValueType use_dynamic = target_sp->GetPreferDynamicValue();
+ SetSP (sp, use_dynamic, use_synthetic);
+ }
+ else
+ SetSP (sp, eNoDynamicValues, use_synthetic);
+ }
+ else
+ SetSP (sp, eNoDynamicValues, use_synthetic);
+}
+
+void
+SBValue::SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic)
+{
+ m_opaque_sp = ValueImplSP(new ValueImpl(sp,use_dynamic,use_synthetic));
+}
+
+void
+SBValue::SetSP (const lldb::ValueObjectSP &sp, lldb::DynamicValueType use_dynamic, bool use_synthetic, const char *name)
+{
+ m_opaque_sp = ValueImplSP(new ValueImpl(sp,use_dynamic,use_synthetic, name));
+}
+
+bool
+SBValue::GetExpressionPath (SBStream &description)
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ value_sp->GetExpressionPath (description.ref(), false);
+ return true;
+ }
+ return false;
+}
+
+bool
+SBValue::GetExpressionPath (SBStream &description, bool qualify_cxx_base_classes)
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ value_sp->GetExpressionPath (description.ref(), qualify_cxx_base_classes);
+ return true;
+ }
+ return false;
+}
+
+bool
+SBValue::GetDescription (SBStream &description)
+{
+ Stream &strm = description.ref();
+
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ ValueObject::DumpValueObject (strm, value_sp.get());
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+lldb::Format
+SBValue::GetFormat ()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ return value_sp->GetFormat();
+ return eFormatDefault;
+}
+
+void
+SBValue::SetFormat (lldb::Format format)
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ value_sp->SetFormat(format);
+}
+
+lldb::SBValue
+SBValue::AddressOf()
+{
+ SBValue sb_value;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ Error error;
+ sb_value.SetSP(value_sp->AddressOf (error),GetPreferDynamicValue(), GetPreferSyntheticValue());
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::AddressOf () => SBValue(%p)", value_sp.get(), value_sp.get());
+
+ return sb_value;
+}
+
+lldb::addr_t
+SBValue::GetLoadAddress()
+{
+ lldb::addr_t value = LLDB_INVALID_ADDRESS;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ TargetSP target_sp (value_sp->GetTargetSP());
+ if (target_sp)
+ {
+ const bool scalar_is_load_address = true;
+ AddressType addr_type;
+ value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
+ if (addr_type == eAddressTypeFile)
+ {
+ ModuleSP module_sp (value_sp->GetModule());
+ if (!module_sp)
+ value = LLDB_INVALID_ADDRESS;
+ else
+ {
+ Address addr;
+ module_sp->ResolveFileAddress(value, addr);
+ value = addr.GetLoadAddress(target_sp.get());
+ }
+ }
+ else if (addr_type == eAddressTypeHost || addr_type == eAddressTypeInvalid)
+ value = LLDB_INVALID_ADDRESS;
+ }
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::GetLoadAddress () => (%" PRIu64 ")", value_sp.get(), value);
+
+ return value;
+}
+
+lldb::SBAddress
+SBValue::GetAddress()
+{
+ Address addr;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ TargetSP target_sp (value_sp->GetTargetSP());
+ if (target_sp)
+ {
+ lldb::addr_t value = LLDB_INVALID_ADDRESS;
+ const bool scalar_is_load_address = true;
+ AddressType addr_type;
+ value = value_sp->GetAddressOf(scalar_is_load_address, &addr_type);
+ if (addr_type == eAddressTypeFile)
+ {
+ ModuleSP module_sp (value_sp->GetModule());
+ if (module_sp)
+ module_sp->ResolveFileAddress(value, addr);
+ }
+ else if (addr_type == eAddressTypeLoad)
+ {
+ // no need to check the return value on this.. if it can actually do the resolve
+ // addr will be in the form (section,offset), otherwise it will simply be returned
+ // as (NULL, value)
+ addr.SetLoadAddress(value, target_sp.get());
+ }
+ }
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::GetAddress () => (%s,%" PRIu64 ")", value_sp.get(),
+ (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"),
+ addr.GetOffset());
+ return SBAddress(new Address(addr));
+}
+
+lldb::SBData
+SBValue::GetPointeeData (uint32_t item_idx,
+ uint32_t item_count)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::SBData sb_data;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ TargetSP target_sp (value_sp->GetTargetSP());
+ if (target_sp)
+ {
+ DataExtractorSP data_sp(new DataExtractor());
+ value_sp->GetPointeeData(*data_sp, item_idx, item_count);
+ if (data_sp->GetByteSize() > 0)
+ *sb_data = data_sp;
+ }
+ }
+ if (log)
+ log->Printf ("SBValue(%p)::GetPointeeData (%d, %d) => SBData(%p)",
+ value_sp.get(),
+ item_idx,
+ item_count,
+ sb_data.get());
+
+ return sb_data;
+}
+
+lldb::SBData
+SBValue::GetData ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ lldb::SBData sb_data;
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ if (value_sp)
+ {
+ DataExtractorSP data_sp(new DataExtractor());
+ value_sp->GetData(*data_sp);
+ if (data_sp->GetByteSize() > 0)
+ *sb_data = data_sp;
+ }
+ if (log)
+ log->Printf ("SBValue(%p)::GetData () => SBData(%p)",
+ value_sp.get(),
+ sb_data.get());
+
+ return sb_data;
+}
+
+bool
+SBValue::SetData (lldb::SBData &data, SBError &error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ bool ret = true;
+
+ if (value_sp)
+ {
+ DataExtractor *data_extractor = data.get();
+
+ if (!data_extractor)
+ {
+ if (log)
+ log->Printf ("SBValue(%p)::SetData() => error: no data to set", value_sp.get());
+
+ error.SetErrorString("No data to set");
+ ret = false;
+ }
+ else
+ {
+ Error set_error;
+
+ value_sp->SetData(*data_extractor, set_error);
+
+ if (!set_error.Success())
+ {
+ error.SetErrorStringWithFormat("Couldn't set data: %s", set_error.AsCString());
+ ret = false;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("Couldn't set data: could not get SBValue: %s", locker.GetError().AsCString());
+ ret = false;
+ }
+
+ if (log)
+ log->Printf ("SBValue(%p)::SetData (%p) => %s",
+ value_sp.get(),
+ data.get(),
+ ret ? "true" : "false");
+ return ret;
+}
+
+lldb::SBDeclaration
+SBValue::GetDeclaration ()
+{
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ SBDeclaration decl_sb;
+ if (value_sp)
+ {
+ Declaration decl;
+ if (value_sp->GetDeclaration(decl))
+ decl_sb.SetDeclaration(decl);
+ }
+ return decl_sb;
+}
+
+lldb::SBWatchpoint
+SBValue::Watch (bool resolve_location, bool read, bool write, SBError &error)
+{
+ SBWatchpoint sb_watchpoint;
+
+ // If the SBValue is not valid, there's no point in even trying to watch it.
+ ValueLocker locker;
+ lldb::ValueObjectSP value_sp(GetSP(locker));
+ TargetSP target_sp (GetTarget().GetSP());
+ if (value_sp && target_sp)
+ {
+ // Read and Write cannot both be false.
+ if (!read && !write)
+ return sb_watchpoint;
+
+ // If the value is not in scope, don't try and watch and invalid value
+ if (!IsInScope())
+ return sb_watchpoint;
+
+ addr_t addr = GetLoadAddress();
+ if (addr == LLDB_INVALID_ADDRESS)
+ return sb_watchpoint;
+ size_t byte_size = GetByteSize();
+ if (byte_size == 0)
+ return sb_watchpoint;
+
+ uint32_t watch_type = 0;
+ if (read)
+ watch_type |= LLDB_WATCH_TYPE_READ;
+ if (write)
+ watch_type |= LLDB_WATCH_TYPE_WRITE;
+
+ Error rc;
+ ClangASTType type (value_sp->GetClangType());
+ WatchpointSP watchpoint_sp = target_sp->CreateWatchpoint(addr, byte_size, &type, watch_type, rc);
+ error.SetError(rc);
+
+ if (watchpoint_sp)
+ {
+ sb_watchpoint.SetSP (watchpoint_sp);
+ Declaration decl;
+ if (value_sp->GetDeclaration (decl))
+ {
+ if (decl.GetFile())
+ {
+ StreamString ss;
+ // True to show fullpath for declaration file.
+ decl.DumpStopContext(&ss, true);
+ watchpoint_sp->SetDeclInfo(ss.GetString());
+ }
+ }
+ }
+ }
+ else if (target_sp)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::Watch() => error getting SBValue: %s", value_sp.get(), locker.GetError().AsCString());
+
+ error.SetErrorStringWithFormat("could not get SBValue: %s", locker.GetError().AsCString());
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBValue(%p)::Watch() => error getting SBValue: no target", value_sp.get());
+ error.SetErrorString("could not set watchpoint, a target is required");
+ }
+
+ return sb_watchpoint;
+}
+
+// FIXME: Remove this method impl (as well as the decl in .h) once it is no longer needed.
+// Backward compatibility fix in the interim.
+lldb::SBWatchpoint
+SBValue::Watch (bool resolve_location, bool read, bool write)
+{
+ SBError error;
+ return Watch(resolve_location, read, write, error);
+}
+
+lldb::SBWatchpoint
+SBValue::WatchPointee (bool resolve_location, bool read, bool write, SBError &error)
+{
+ SBWatchpoint sb_watchpoint;
+ if (IsInScope() && GetType().IsPointerType())
+ sb_watchpoint = Dereference().Watch (resolve_location, read, write, error);
+ return sb_watchpoint;
+}
diff --git a/source/API/SBValueList.cpp b/source/API/SBValueList.cpp
new file mode 100644
index 000000000000..46866eb37424
--- /dev/null
+++ b/source/API/SBValueList.cpp
@@ -0,0 +1,275 @@
+//===-- SBValueList.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/SBValueList.h"
+#include "lldb/API/SBValue.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+class ValueListImpl
+{
+public:
+ ValueListImpl () :
+ m_values()
+ {
+ }
+
+ ValueListImpl (const ValueListImpl& rhs) :
+ m_values(rhs.m_values)
+ {
+ }
+
+ ValueListImpl&
+ operator = (const ValueListImpl& rhs)
+ {
+ if (this == &rhs)
+ return *this;
+ m_values = rhs.m_values;
+ return *this;
+ };
+
+ uint32_t
+ GetSize ()
+ {
+ return m_values.size();
+ }
+
+ void
+ Append (const lldb::SBValue& sb_value)
+ {
+ m_values.push_back(sb_value);
+ }
+
+ void
+ Append (const ValueListImpl& list)
+ {
+ for (auto val : list.m_values)
+ Append (val);
+ }
+
+ lldb::SBValue
+ GetValueAtIndex (uint32_t index)
+ {
+ if (index >= GetSize())
+ return lldb::SBValue();
+ return m_values[index];
+ }
+
+ lldb::SBValue
+ FindValueByUID (lldb::user_id_t uid)
+ {
+ for (auto val : m_values)
+ {
+ if (val.IsValid() && val.GetID() == uid)
+ return val;
+ }
+ return lldb::SBValue();
+ }
+
+private:
+ std::vector<lldb::SBValue> m_values;
+};
+
+SBValueList::SBValueList () :
+ m_opaque_ap ()
+{
+}
+
+SBValueList::SBValueList (const SBValueList &rhs) :
+ m_opaque_ap ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (rhs.IsValid())
+ m_opaque_ap.reset (new ValueListImpl (*rhs));
+
+ if (log)
+ {
+ log->Printf ("SBValueList::SBValueList (rhs.ap=%p) => this.ap = %p",
+ (rhs.IsValid() ? rhs.m_opaque_ap.get() : NULL),
+ m_opaque_ap.get());
+ }
+}
+
+SBValueList::SBValueList (const ValueListImpl *lldb_object_ptr) :
+ m_opaque_ap ()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (lldb_object_ptr)
+ m_opaque_ap.reset (new ValueListImpl (*lldb_object_ptr));
+
+ if (log)
+ {
+ log->Printf ("SBValueList::SBValueList (lldb_object_ptr=%p) => this.ap = %p",
+ lldb_object_ptr,
+ m_opaque_ap.get());
+ }
+}
+
+SBValueList::~SBValueList ()
+{
+}
+
+bool
+SBValueList::IsValid () const
+{
+ return (m_opaque_ap.get() != NULL);
+}
+
+void
+SBValueList::Clear()
+{
+ m_opaque_ap.reset();
+}
+
+const SBValueList &
+SBValueList::operator = (const SBValueList &rhs)
+{
+ if (this != &rhs)
+ {
+ if (rhs.IsValid())
+ m_opaque_ap.reset (new ValueListImpl (*rhs));
+ else
+ m_opaque_ap.reset ();
+ }
+ return *this;
+}
+
+ValueListImpl *
+SBValueList::operator->()
+{
+ return m_opaque_ap.get();
+}
+
+ValueListImpl &
+SBValueList::operator*()
+{
+ return *m_opaque_ap;
+}
+
+const ValueListImpl *
+SBValueList::operator->() const
+{
+ return m_opaque_ap.get();
+}
+
+const ValueListImpl &
+SBValueList::operator*() const
+{
+ return *m_opaque_ap;
+}
+
+void
+SBValueList::Append (const SBValue &val_obj)
+{
+ CreateIfNeeded ();
+ m_opaque_ap->Append (val_obj);
+}
+
+void
+SBValueList::Append (lldb::ValueObjectSP& val_obj_sp)
+{
+ if (val_obj_sp)
+ {
+ CreateIfNeeded ();
+ m_opaque_ap->Append (SBValue(val_obj_sp));
+ }
+}
+
+void
+SBValueList::Append (const lldb::SBValueList& value_list)
+{
+ if (value_list.IsValid())
+ {
+ CreateIfNeeded ();
+ m_opaque_ap->Append (*value_list);
+ }
+}
+
+
+SBValue
+SBValueList::GetValueAtIndex (uint32_t idx) const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ //if (log)
+ // log->Printf ("SBValueList::GetValueAtIndex (uint32_t idx) idx = %d", idx);
+
+ SBValue sb_value;
+ if (m_opaque_ap.get())
+ sb_value = m_opaque_ap->GetValueAtIndex (idx);
+
+ if (log)
+ {
+ SBStream sstr;
+ sb_value.GetDescription (sstr);
+ log->Printf ("SBValueList::GetValueAtIndex (this.ap=%p, idx=%d) => SBValue (this.sp = %p, '%s')",
+ m_opaque_ap.get(), idx, sb_value.GetSP().get(), sstr.GetData());
+ }
+
+ return sb_value;
+}
+
+uint32_t
+SBValueList::GetSize () const
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ //if (log)
+ // log->Printf ("SBValueList::GetSize ()");
+
+ uint32_t size = 0;
+ if (m_opaque_ap.get())
+ size = m_opaque_ap->GetSize();
+
+ if (log)
+ log->Printf ("SBValueList::GetSize (this.ap=%p) => %d", m_opaque_ap.get(), size);
+
+ return size;
+}
+
+void
+SBValueList::CreateIfNeeded ()
+{
+ if (m_opaque_ap.get() == NULL)
+ m_opaque_ap.reset (new ValueListImpl());
+}
+
+
+SBValue
+SBValueList::FindValueObjectByUID (lldb::user_id_t uid)
+{
+ SBValue sb_value;
+ if (m_opaque_ap.get())
+ sb_value = m_opaque_ap->FindValueByUID(uid);
+ return sb_value;
+}
+
+void *
+SBValueList::opaque_ptr ()
+{
+ return m_opaque_ap.get();
+}
+
+ValueListImpl &
+SBValueList::ref ()
+{
+ CreateIfNeeded();
+ return *m_opaque_ap.get();
+}
+
+
diff --git a/source/API/SBWatchpoint.cpp b/source/API/SBWatchpoint.cpp
new file mode 100644
index 000000000000..194695c31d5b
--- /dev/null
+++ b/source/API/SBWatchpoint.cpp
@@ -0,0 +1,298 @@
+//===-- SBWatchpoint.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/SBWatchpoint.h"
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBAddress.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBStream.h"
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-defines.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+SBWatchpoint::SBWatchpoint () :
+ m_opaque_sp ()
+{
+}
+
+SBWatchpoint::SBWatchpoint (const lldb::WatchpointSP &wp_sp) :
+ m_opaque_sp (wp_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ if (log)
+ {
+ SBStream sstr;
+ GetDescription (sstr, lldb::eDescriptionLevelBrief);
+ log->Printf ("SBWatchpoint::SBWatchpoint (const lldb::WatchpointSP &wp_sp"
+ "=%p) => this.sp = %p (%s)", wp_sp.get(), m_opaque_sp.get(), sstr.GetData());
+ }
+}
+
+SBWatchpoint::SBWatchpoint(const SBWatchpoint &rhs) :
+ m_opaque_sp (rhs.m_opaque_sp)
+{
+}
+
+const SBWatchpoint &
+SBWatchpoint::operator = (const SBWatchpoint &rhs)
+{
+ if (this != &rhs)
+ m_opaque_sp = rhs.m_opaque_sp;
+ return *this;
+}
+
+
+SBWatchpoint::~SBWatchpoint ()
+{
+}
+
+watch_id_t
+SBWatchpoint::GetID ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+
+ watch_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ watch_id = watchpoint_sp->GetID();
+
+ if (log)
+ {
+ if (watch_id == LLDB_INVALID_WATCH_ID)
+ log->Printf ("SBWatchpoint(%p)::GetID () => LLDB_INVALID_WATCH_ID", watchpoint_sp.get());
+ else
+ log->Printf ("SBWatchpoint(%p)::GetID () => %u", watchpoint_sp.get(), watch_id);
+ }
+
+ return watch_id;
+}
+
+bool
+SBWatchpoint::IsValid() const
+{
+ return (bool) m_opaque_sp;
+}
+
+SBError
+SBWatchpoint::GetError ()
+{
+ SBError sb_error;
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ sb_error.SetError(watchpoint_sp->GetError());
+ }
+ return sb_error;
+}
+
+int32_t
+SBWatchpoint::GetHardwareIndex ()
+{
+ int32_t hw_index = -1;
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ hw_index = watchpoint_sp->GetHardwareIndex();
+ }
+
+ return hw_index;
+}
+
+addr_t
+SBWatchpoint::GetWatchAddress ()
+{
+ addr_t ret_addr = LLDB_INVALID_ADDRESS;
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ ret_addr = watchpoint_sp->GetLoadAddress();
+ }
+
+ return ret_addr;
+}
+
+size_t
+SBWatchpoint::GetWatchSize ()
+{
+ size_t watch_size = 0;
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ watch_size = watchpoint_sp->GetByteSize();
+ }
+
+ return watch_size;
+}
+
+void
+SBWatchpoint::SetEnabled (bool enabled)
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ watchpoint_sp->GetTarget().DisableWatchpointByID(watchpoint_sp->GetID());
+ }
+}
+
+bool
+SBWatchpoint::IsEnabled ()
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ return watchpoint_sp->IsEnabled();
+ }
+ else
+ return false;
+}
+
+uint32_t
+SBWatchpoint::GetHitCount ()
+{
+ uint32_t count = 0;
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ count = watchpoint_sp->GetHitCount();
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+ if (log)
+ log->Printf ("SBWatchpoint(%p)::GetHitCount () => %u", watchpoint_sp.get(), count);
+
+ return count;
+}
+
+uint32_t
+SBWatchpoint::GetIgnoreCount ()
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ return watchpoint_sp->GetIgnoreCount();
+ }
+ else
+ return 0;
+}
+
+void
+SBWatchpoint::SetIgnoreCount (uint32_t n)
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ watchpoint_sp->SetIgnoreCount (n);
+ }
+}
+
+const char *
+SBWatchpoint::GetCondition ()
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ return watchpoint_sp->GetConditionText ();
+ }
+ return NULL;
+}
+
+void
+SBWatchpoint::SetCondition (const char *condition)
+{
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ watchpoint_sp->SetCondition (condition);
+ }
+}
+
+bool
+SBWatchpoint::GetDescription (SBStream &description, DescriptionLevel level)
+{
+ Stream &strm = description.ref();
+
+ lldb::WatchpointSP watchpoint_sp(GetSP());
+ if (watchpoint_sp)
+ {
+ Mutex::Locker api_locker (watchpoint_sp->GetTarget().GetAPIMutex());
+ watchpoint_sp->GetDescription (&strm, level);
+ strm.EOL();
+ }
+ else
+ strm.PutCString ("No value");
+
+ return true;
+}
+
+void
+SBWatchpoint::Clear ()
+{
+ m_opaque_sp.reset();
+}
+
+lldb::WatchpointSP
+SBWatchpoint::GetSP () const
+{
+ return m_opaque_sp;
+}
+
+void
+SBWatchpoint::SetSP (const lldb::WatchpointSP &sp)
+{
+ m_opaque_sp = sp;
+}
+
+bool
+SBWatchpoint::EventIsWatchpointEvent (const lldb::SBEvent &event)
+{
+ return Watchpoint::WatchpointEventData::GetEventDataFromEvent(event.get()) != NULL;
+
+}
+
+WatchpointEventType
+SBWatchpoint::GetWatchpointEventTypeFromEvent (const SBEvent& event)
+{
+ if (event.IsValid())
+ return Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (event.GetSP());
+ return eWatchpointEventTypeInvalidType;
+}
+
+SBWatchpoint
+SBWatchpoint::GetWatchpointFromEvent (const lldb::SBEvent& event)
+{
+ SBWatchpoint sb_watchpoint;
+ if (event.IsValid())
+ sb_watchpoint.m_opaque_sp = Watchpoint::WatchpointEventData::GetWatchpointFromEvent (event.GetSP());
+ return sb_watchpoint;
+}
diff --git a/source/Breakpoint/Breakpoint.cpp b/source/Breakpoint/Breakpoint.cpp
new file mode 100644
index 000000000000..9bc43814b48a
--- /dev/null
+++ b/source/Breakpoint/Breakpoint.cpp
@@ -0,0 +1,794 @@
+//===-- Breakpoint.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/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Core/Log.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/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/lldb-private-log.h"
+#include "llvm/Support/Casting.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+
+const ConstString &
+Breakpoint::GetEventIdentifier ()
+{
+ static ConstString g_identifier("event-identifier.breakpoint.changed");
+ return g_identifier;
+}
+
+//----------------------------------------------------------------------
+// Breakpoint constructor
+//----------------------------------------------------------------------
+Breakpoint::Breakpoint(Target &target, SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp) :
+ m_being_created(true),
+ m_target (target),
+ m_filter_sp (filter_sp),
+ m_resolver_sp (resolver_sp),
+ m_options (),
+ m_locations (*this)
+{
+ m_being_created = false;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Breakpoint::~Breakpoint()
+{
+}
+
+bool
+Breakpoint::IsInternal () const
+{
+ return LLDB_BREAK_ID_IS_INTERNAL(m_bid);
+}
+
+
+
+Target&
+Breakpoint::GetTarget ()
+{
+ return m_target;
+}
+
+const Target&
+Breakpoint::GetTarget () const
+{
+ return m_target;
+}
+
+BreakpointLocationSP
+Breakpoint::AddLocation (const Address &addr, bool *new_location)
+{
+ return m_locations.AddLocation (addr, new_location);
+}
+
+BreakpointLocationSP
+Breakpoint::FindLocationByAddress (const Address &addr)
+{
+ return m_locations.FindByAddress(addr);
+}
+
+break_id_t
+Breakpoint::FindLocationIDByAddress (const Address &addr)
+{
+ return m_locations.FindIDByAddress(addr);
+}
+
+BreakpointLocationSP
+Breakpoint::FindLocationByID (break_id_t bp_loc_id)
+{
+ return m_locations.FindByID(bp_loc_id);
+}
+
+BreakpointLocationSP
+Breakpoint::GetLocationAtIndex (size_t index)
+{
+ return m_locations.GetByIndex(index);
+}
+
+// For each of the overall options we need to decide how they propagate to
+// the location options. This will determine the precedence of options on
+// the breakpoint vs. its locations.
+
+// Disable at the breakpoint level should override the location settings.
+// That way you can conveniently turn off a whole breakpoint without messing
+// up the individual settings.
+
+void
+Breakpoint::SetEnabled (bool enable)
+{
+ if (enable == m_options.IsEnabled())
+ return;
+
+ m_options.SetEnabled(enable);
+ if (enable)
+ m_locations.ResolveAllBreakpointSites();
+ else
+ m_locations.ClearAllBreakpointSites();
+
+ SendBreakpointChangedEvent (enable ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled);
+
+}
+
+bool
+Breakpoint::IsEnabled ()
+{
+ return m_options.IsEnabled();
+}
+
+void
+Breakpoint::SetIgnoreCount (uint32_t n)
+{
+ if (m_options.GetIgnoreCount() == n)
+ return;
+
+ m_options.SetIgnoreCount(n);
+ SendBreakpointChangedEvent (eBreakpointEventTypeIgnoreChanged);
+}
+
+void
+Breakpoint::DecrementIgnoreCount ()
+{
+ uint32_t ignore = m_options.GetIgnoreCount();
+ if (ignore != 0)
+ m_options.SetIgnoreCount(ignore - 1);
+}
+
+uint32_t
+Breakpoint::GetIgnoreCount () const
+{
+ return m_options.GetIgnoreCount();
+}
+
+bool
+Breakpoint::IgnoreCountShouldStop ()
+{
+ uint32_t ignore = GetIgnoreCount();
+ if (ignore != 0)
+ {
+ // When we get here we know the location that caused the stop doesn't have an ignore count,
+ // since by contract we call it first... So we don't have to find & decrement it, we only have
+ // to decrement our own ignore count.
+ DecrementIgnoreCount();
+ return false;
+ }
+ else
+ return true;
+}
+
+uint32_t
+Breakpoint::GetHitCount () const
+{
+ return m_locations.GetHitCount();
+}
+
+bool
+Breakpoint::IsOneShot () const
+{
+ return m_options.IsOneShot();
+}
+
+void
+Breakpoint::SetOneShot (bool one_shot)
+{
+ m_options.SetOneShot (one_shot);
+}
+
+void
+Breakpoint::SetThreadID (lldb::tid_t thread_id)
+{
+ if (m_options.GetThreadSpec()->GetTID() == thread_id)
+ return;
+
+ m_options.GetThreadSpec()->SetTID(thread_id);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t
+Breakpoint::GetThreadID () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return LLDB_INVALID_THREAD_ID;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetTID();
+}
+
+void
+Breakpoint::SetThreadIndex (uint32_t index)
+{
+ if (m_options.GetThreadSpec()->GetIndex() == index)
+ return;
+
+ m_options.GetThreadSpec()->SetIndex(index);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+uint32_t
+Breakpoint::GetThreadIndex() const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return 0;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetIndex();
+}
+
+void
+Breakpoint::SetThreadName (const char *thread_name)
+{
+ if (m_options.GetThreadSpec()->GetName() != NULL
+ && ::strcmp (m_options.GetThreadSpec()->GetName(), thread_name) == 0)
+ return;
+
+ m_options.GetThreadSpec()->SetName (thread_name);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+Breakpoint::GetThreadName () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return NULL;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetName();
+}
+
+void
+Breakpoint::SetQueueName (const char *queue_name)
+{
+ if (m_options.GetThreadSpec()->GetQueueName() != NULL
+ && ::strcmp (m_options.GetThreadSpec()->GetQueueName(), queue_name) == 0)
+ return;
+
+ m_options.GetThreadSpec()->SetQueueName (queue_name);
+ SendBreakpointChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+Breakpoint::GetQueueName () const
+{
+ if (m_options.GetThreadSpecNoCreate() == NULL)
+ return NULL;
+ else
+ return m_options.GetThreadSpecNoCreate()->GetQueueName();
+}
+
+void
+Breakpoint::SetCondition (const char *condition)
+{
+ m_options.SetCondition (condition);
+ SendBreakpointChangedEvent (eBreakpointEventTypeConditionChanged);
+}
+
+const char *
+Breakpoint::GetConditionText () const
+{
+ return m_options.GetConditionText();
+}
+
+// This function is used when "baton" doesn't need to be freed
+void
+Breakpoint::SetCallback (BreakpointHitCallback callback, void *baton, bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+
+ SendBreakpointChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void
+Breakpoint::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
+{
+ m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+}
+
+void
+Breakpoint::ClearCallback ()
+{
+ m_options.ClearCallback ();
+}
+
+bool
+Breakpoint::InvokeCallback (StoppointCallbackContext *context, break_id_t bp_loc_id)
+{
+ return m_options.InvokeCallback (context, GetID(), bp_loc_id);
+}
+
+BreakpointOptions *
+Breakpoint::GetOptions ()
+{
+ return &m_options;
+}
+
+void
+Breakpoint::ResolveBreakpoint ()
+{
+ if (m_resolver_sp)
+ m_resolver_sp->ResolveBreakpoint(*m_filter_sp);
+}
+
+void
+Breakpoint::ResolveBreakpointInModules (ModuleList &module_list)
+{
+ if (m_resolver_sp)
+ m_resolver_sp->ResolveBreakpointInModules(*m_filter_sp, module_list);
+}
+
+void
+Breakpoint::ClearAllBreakpointSites ()
+{
+ m_locations.ClearAllBreakpointSites();
+}
+
+//----------------------------------------------------------------------
+// ModulesChanged: Pass in a list of new modules, and
+//----------------------------------------------------------------------
+
+void
+Breakpoint::ModulesChanged (ModuleList &module_list, bool load, bool delete_locations)
+{
+ Mutex::Locker modules_mutex(module_list.GetMutex());
+ if (load)
+ {
+ // The logic for handling new modules is:
+ // 1) If the filter rejects this module, then skip it.
+ // 2) Run through the current location list and if there are any locations
+ // for that module, we mark the module as "seen" and we don't try to re-resolve
+ // breakpoint locations for that module.
+ // However, we do add breakpoint sites to these locations if needed.
+ // 3) If we don't see this module in our breakpoint location list, call ResolveInModules.
+
+ ModuleList new_modules; // We'll stuff the "unseen" modules in this list, and then resolve
+ // 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++)
+ {
+ 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++)
+ {
+ BreakpointLocationSP break_loc = m_locations.GetByIndex(loc_idx);
+ if (!break_loc->IsEnabled())
+ continue;
+ SectionSP section_sp (break_loc->GetAddress().GetSection());
+ if (!section_sp || section_sp->GetModule() == module_sp)
+ {
+ if (!seen)
+ seen = true;
+
+ if (!break_loc->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());
+ }
+ }
+ }
+
+ if (!seen)
+ new_modules.AppendIfNeeded (module_sp);
+
+ }
+
+ 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);
+
+ }
+ }
+ else
+ {
+ // Go through the currently set locations and if any have breakpoints in
+ // the module list, then remove their breakpoint sites, and their locations if asked to.
+
+ BreakpointEventData *removed_locations_event;
+ if (!IsInternal())
+ removed_locations_event = new BreakpointEventData (eBreakpointEventTypeLocationsRemoved,
+ shared_from_this());
+ else
+ removed_locations_event = NULL;
+
+ size_t num_modules = module_list.GetSize();
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (i));
+ if (m_filter_sp->ModulePasses (module_sp))
+ {
+ size_t loc_idx = 0;
+ size_t num_locations = m_locations.GetSize();
+ BreakpointLocationCollection locations_to_remove;
+ for (loc_idx = 0; loc_idx < num_locations; loc_idx++)
+ {
+ BreakpointLocationSP break_loc_sp (m_locations.GetByIndex(loc_idx));
+ SectionSP section_sp (break_loc_sp->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule() == module_sp)
+ {
+ // Remove this breakpoint since the shared library is
+ // unloaded, but keep the breakpoint location around
+ // so we always get complete hit count and breakpoint
+ // lifetime info
+ break_loc_sp->ClearBreakpointSite();
+ if (removed_locations_event)
+ {
+ removed_locations_event->GetBreakpointLocationCollection().Add(break_loc_sp);
+ }
+ if (delete_locations)
+ locations_to_remove.Add (break_loc_sp);
+
+ }
+ }
+
+ if (delete_locations)
+ {
+ size_t num_locations_to_remove = locations_to_remove.GetSize();
+ for (loc_idx = 0; loc_idx < num_locations_to_remove; loc_idx++)
+ m_locations.RemoveLocation (locations_to_remove.GetByIndex(loc_idx));
+ }
+ }
+ }
+ SendBreakpointChangedEvent (removed_locations_event);
+ }
+}
+
+void
+Breakpoint::ModuleReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
+{
+ ModuleList temp_list;
+ temp_list.Append (new_module_sp);
+ ModulesChanged (temp_list, true);
+
+ // 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.
+
+ temp_list.Clear();
+ temp_list.Append (old_module_sp);
+ ModulesChanged (temp_list, false, true);
+}
+
+void
+Breakpoint::Dump (Stream *)
+{
+}
+
+size_t
+Breakpoint::GetNumResolvedLocations() const
+{
+ // Return the number of breakpoints that are actually resolved and set
+ // down in the inferior process.
+ return m_locations.GetNumResolvedLocations();
+}
+
+size_t
+Breakpoint::GetNumLocations() const
+{
+ return m_locations.GetSize();
+}
+
+void
+Breakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_locations)
+{
+ assert (s != NULL);
+
+ if (!m_kind_description.empty())
+ {
+ if (eDescriptionLevelBrief)
+ {
+ s->PutCString (GetBreakpointKind());
+ return;
+ }
+ else
+ s->Printf("Kind: %s\n", GetBreakpointKind ());
+ }
+
+ const size_t num_locations = GetNumLocations ();
+ const size_t num_resolved_locations = GetNumResolvedLocations ();
+
+ // They just made the breakpoint, they don't need to be told HOW they made it...
+ // Also, we'll print the breakpoint number differently depending on whether there is 1 or more locations.
+ if (level != eDescriptionLevelInitial)
+ {
+ s->Printf("%i: ", GetID());
+ GetResolverDescription (s);
+ GetFilterDescription (s);
+ }
+
+ switch (level)
+ {
+ case lldb::eDescriptionLevelBrief:
+ case lldb::eDescriptionLevelFull:
+ if (num_locations > 0)
+ {
+ s->Printf(", locations = %" PRIu64, (uint64_t)num_locations);
+ if (num_resolved_locations > 0)
+ s->Printf(", resolved = %" PRIu64, (uint64_t)num_resolved_locations);
+ }
+ else
+ {
+ // Don't print the pending notification for exception resolvers since we don't generally
+ // know how to set them until the target is run.
+ if (m_resolver_sp->getResolverID() != BreakpointResolver::ExceptionResolver)
+ s->Printf(", locations = 0 (pending)");
+ }
+
+ GetOptions()->GetDescription(s, level);
+
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ s->IndentLess();
+ s->EOL();
+ }
+ break;
+
+ case lldb::eDescriptionLevelInitial:
+ s->Printf ("Breakpoint %i: ", GetID());
+ if (num_locations == 0)
+ {
+ s->Printf ("no locations (pending).");
+ }
+ else if (num_locations == 1)
+ {
+ // If there is one location only, we'll just print that location information. But don't do this if
+ // show locations is true, then that will be handled below.
+ if (show_locations == false)
+ {
+ GetLocationAtIndex(0)->GetDescription(s, level);
+ }
+ else
+ {
+ s->Printf ("%zd locations.", num_locations);
+ }
+ }
+ else
+ {
+ s->Printf ("%zd locations.", num_locations);
+ }
+ s->EOL();
+ break;
+ case lldb::eDescriptionLevelVerbose:
+ // Verbose mode does a debug dump of the breakpoint
+ Dump (s);
+ s->EOL ();
+ //s->Indent();
+ GetOptions()->GetDescription(s, level);
+ break;
+
+ default:
+ break;
+ }
+
+ // The brief description is just the location name (1.2 or whatever). That's pointless to
+ // show in the breakpoint's description, so suppress it.
+ if (show_locations && level != lldb::eDescriptionLevelBrief)
+ {
+ s->IndentMore();
+ for (size_t i = 0; i < num_locations; ++i)
+ {
+ BreakpointLocation *loc = GetLocationAtIndex(i).get();
+ loc->GetDescription(s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ }
+}
+
+void
+Breakpoint::GetResolverDescription (Stream *s)
+{
+ if (m_resolver_sp)
+ m_resolver_sp->GetDescription (s);
+}
+
+
+bool
+Breakpoint::GetMatchingFileLine (const ConstString &filename, uint32_t line_number, BreakpointLocationCollection &loc_coll)
+{
+ // TODO: To be correct, this method needs to fill the breakpoint location collection
+ // with the location IDs which match the filename and line_number.
+ //
+
+ if (m_resolver_sp)
+ {
+ BreakpointResolverFileLine *resolverFileLine = dyn_cast<BreakpointResolverFileLine>(m_resolver_sp.get());
+ if (resolverFileLine &&
+ resolverFileLine->m_file_spec.GetFilename() == filename &&
+ resolverFileLine->m_line_number == line_number)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Breakpoint::GetFilterDescription (Stream *s)
+{
+ m_filter_sp->GetDescription (s);
+}
+
+void
+Breakpoint::SendBreakpointChangedEvent (lldb::BreakpointEventType eventKind)
+{
+ if (!m_being_created
+ && !IsInternal()
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind, shared_from_this());
+
+ GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ }
+}
+
+void
+Breakpoint::SendBreakpointChangedEvent (BreakpointEventData *data)
+{
+
+ if (data == NULL)
+ return;
+
+ if (!m_being_created
+ && !IsInternal()
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ else
+ delete data;
+}
+
+Breakpoint::BreakpointEventData::BreakpointEventData (BreakpointEventType sub_type,
+ const BreakpointSP &new_breakpoint_sp) :
+ EventData (),
+ m_breakpoint_event (sub_type),
+ m_new_breakpoint_sp (new_breakpoint_sp)
+{
+}
+
+Breakpoint::BreakpointEventData::~BreakpointEventData ()
+{
+}
+
+const ConstString &
+Breakpoint::BreakpointEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Breakpoint::BreakpointEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Breakpoint::BreakpointEventData::GetFlavor () const
+{
+ return BreakpointEventData::GetFlavorString ();
+}
+
+
+BreakpointSP &
+Breakpoint::BreakpointEventData::GetBreakpoint ()
+{
+ return m_new_breakpoint_sp;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventType () const
+{
+ return m_breakpoint_event;
+}
+
+void
+Breakpoint::BreakpointEventData::Dump (Stream *s) const
+{
+}
+
+const Breakpoint::BreakpointEventData *
+Breakpoint::BreakpointEventData::GetEventDataFromEvent (const Event *event)
+{
+ if (event)
+ {
+ const EventData *event_data = event->GetData();
+ if (event_data && event_data->GetFlavor() == BreakpointEventData::GetFlavorString())
+ return static_cast <const BreakpointEventData *> (event->GetData());
+ }
+ return NULL;
+}
+
+BreakpointEventType
+Breakpoint::BreakpointEventData::GetBreakpointEventTypeFromEvent (const EventSP &event_sp)
+{
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+
+ if (data == NULL)
+ return eBreakpointEventTypeInvalidType;
+ else
+ return data->GetBreakpointEventType();
+}
+
+BreakpointSP
+Breakpoint::BreakpointEventData::GetBreakpointFromEvent (const EventSP &event_sp)
+{
+ BreakpointSP bp_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ bp_sp = data->m_new_breakpoint_sp;
+
+ return bp_sp;
+}
+
+size_t
+Breakpoint::BreakpointEventData::GetNumBreakpointLocationsFromEvent (const EventSP &event_sp)
+{
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ return data->m_locations.GetSize();
+
+ return 0;
+}
+
+lldb::BreakpointLocationSP
+Breakpoint::BreakpointEventData::GetBreakpointLocationAtIndexFromEvent (const lldb::EventSP &event_sp, uint32_t bp_loc_idx)
+{
+ lldb::BreakpointLocationSP bp_loc_sp;
+
+ const BreakpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ {
+ bp_loc_sp = data->m_locations.GetByIndex(bp_loc_idx);
+ }
+
+ return bp_loc_sp;
+}
diff --git a/source/Breakpoint/BreakpointID.cpp b/source/Breakpoint/BreakpointID.cpp
new file mode 100644
index 000000000000..9a59e29d007d
--- /dev/null
+++ b/source/Breakpoint/BreakpointID.cpp
@@ -0,0 +1,123 @@
+//===-- BreakpointID.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stdio.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointID::BreakpointID (break_id_t bp_id, break_id_t loc_id) :
+ m_break_id (bp_id),
+ m_location_id (loc_id)
+{
+}
+
+BreakpointID::~BreakpointID ()
+{
+}
+
+const char *BreakpointID::g_range_specifiers[] = { "-", "to", "To", "TO", NULL };
+
+// Tells whether or not STR is valid to use between two strings representing breakpoint IDs, to
+// indicate a range of breakpoint IDs. This is broken out into a separate function so that we can
+// easily change or add to the format for specifying ID ranges at a later date.
+
+bool
+BreakpointID::IsRangeIdentifier (const char *str)
+{
+ int specifier_count = 0;
+ for (int i = 0; g_range_specifiers[i] != NULL; ++i)
+ ++specifier_count;
+
+ for (int i = 0; i < specifier_count; ++i)
+ {
+ if (strcmp (g_range_specifiers[i], str) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+bool
+BreakpointID::IsValidIDExpression (const char *str)
+{
+ break_id_t bp_id;
+ break_id_t loc_id;
+ BreakpointID::ParseCanonicalReference (str, &bp_id, &loc_id);
+
+ if (bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ return true;
+}
+
+void
+BreakpointID::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == eDescriptionLevelVerbose)
+ s->Printf("%p BreakpointID:", this);
+
+ if (m_break_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString ("<invalid>");
+ else if (m_location_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", m_break_id);
+ else
+ s->Printf("%i.%i", m_break_id, m_location_id);
+}
+
+void
+BreakpointID::GetCanonicalReference (Stream *s, break_id_t bp_id, break_id_t loc_id)
+{
+ if (bp_id == LLDB_INVALID_BREAK_ID)
+ s->PutCString ("<invalid>");
+ else if (loc_id == LLDB_INVALID_BREAK_ID)
+ s->Printf("%i", bp_id);
+ else
+ s->Printf("%i.%i", bp_id, loc_id);
+}
+
+bool
+BreakpointID::ParseCanonicalReference (const char *input, break_id_t *break_id_ptr, break_id_t *break_loc_id_ptr)
+{
+ *break_id_ptr = LLDB_INVALID_BREAK_ID;
+ *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
+
+ if (input == NULL || *input == '\0')
+ return false;
+
+ const char *format = "%i%n.%i%n";
+ int chars_consumed_1 = 0;
+ int chars_consumed_2 = 0;
+ int n_items_parsed = ::sscanf (input,
+ format,
+ break_id_ptr, // %i parse the breakpoint ID
+ &chars_consumed_1, // %n gets the number of characters parsed so far
+ break_loc_id_ptr, // %i parse the breakpoint location ID
+ &chars_consumed_2); // %n gets the number of characters parsed so far
+
+ if ((n_items_parsed == 1 && input[chars_consumed_1] == '\0') ||
+ (n_items_parsed == 2 && input[chars_consumed_2] == '\0'))
+ return true;
+
+ // Badly formatted canonical reference.
+ *break_id_ptr = LLDB_INVALID_BREAK_ID;
+ *break_loc_id_ptr = LLDB_INVALID_BREAK_ID;
+ return false;
+}
+
diff --git a/source/Breakpoint/BreakpointIDList.cpp b/source/Breakpoint/BreakpointIDList.cpp
new file mode 100644
index 000000000000..24101b1442fb
--- /dev/null
+++ b/source/Breakpoint/BreakpointIDList.cpp
@@ -0,0 +1,397 @@
+//===-- BreakpointIDList.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/Breakpoint/BreakpointIDList.h"
+
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// class BreakpointIDList
+//----------------------------------------------------------------------
+
+BreakpointIDList::BreakpointIDList () :
+m_invalid_id (LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID)
+{
+}
+
+BreakpointIDList::~BreakpointIDList ()
+{
+}
+
+size_t
+BreakpointIDList::GetSize()
+{
+ return m_breakpoint_ids.size();
+}
+
+BreakpointID &
+BreakpointIDList::GetBreakpointIDAtIndex (size_t index)
+{
+ if (index < m_breakpoint_ids.size())
+ return m_breakpoint_ids[index];
+ else
+ return m_invalid_id;
+}
+
+bool
+BreakpointIDList::RemoveBreakpointIDAtIndex (size_t index)
+{
+ if (index >= m_breakpoint_ids.size())
+ return false;
+
+ m_breakpoint_ids.erase (m_breakpoint_ids.begin() + index);
+ return true;
+}
+
+void
+BreakpointIDList::Clear()
+{
+ m_breakpoint_ids.clear ();
+}
+
+bool
+BreakpointIDList::AddBreakpointID (BreakpointID bp_id)
+{
+ m_breakpoint_ids.push_back (bp_id);
+
+ return true; // We don't do any verification in this function, so always return true.
+}
+
+bool
+BreakpointIDList::AddBreakpointID (const char *bp_id_str)
+{
+ BreakpointID temp_bp_id;
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ bool success = BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id);
+
+ if (success)
+ {
+ temp_bp_id.SetID (bp_id, loc_id);
+ m_breakpoint_ids.push_back (temp_bp_id);
+ }
+
+ return success;
+}
+
+bool
+BreakpointIDList::FindBreakpointID (BreakpointID &bp_id, size_t *position)
+{
+ for (size_t i = 0; i < m_breakpoint_ids.size(); ++i)
+ {
+ BreakpointID tmp_id = m_breakpoint_ids[i];
+ if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID()
+ && tmp_id.GetLocationID() == bp_id.GetLocationID())
+ {
+ *position = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+BreakpointIDList::FindBreakpointID (const char *bp_id_str, size_t *position)
+{
+ BreakpointID temp_bp_id;
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ if (BreakpointID::ParseCanonicalReference (bp_id_str, &bp_id, &loc_id))
+ {
+ temp_bp_id.SetID (bp_id, loc_id);
+ return FindBreakpointID (temp_bp_id, position);
+ }
+ else
+ return false;
+}
+
+void
+BreakpointIDList::InsertStringArray (const char **string_array, size_t array_size, CommandReturnObject &result)
+{
+ if (string_array == NULL)
+ return;
+
+ for (uint32_t i = 0; i < array_size; ++i)
+ {
+ break_id_t bp_id;
+ break_id_t loc_id;
+
+ if (BreakpointID::ParseCanonicalReference (string_array[i], &bp_id, &loc_id))
+ {
+ if (bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointID temp_bp_id(bp_id, loc_id);
+ m_breakpoint_ids.push_back (temp_bp_id);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", string_array[i]);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+}
+
+
+// This function takes OLD_ARGS, which is usually the result of breaking the command string arguments into
+// an array of space-separated strings, and searches through the arguments for any breakpoint ID range specifiers.
+// Any string in the array that is not part of an ID range specifier is copied directly into NEW_ARGS. If any
+// ID range specifiers are found, the range is interpreted and a list of canonical breakpoint IDs corresponding to
+// all the current breakpoints and locations in the range are added to NEW_ARGS. When this function is done,
+// 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,
+ Args &new_args)
+{
+ std::string range_start;
+ const char *range_end;
+ const char *current_arg;
+ const size_t num_old_args = old_args.GetArgumentCount();
+
+ for (size_t i = 0; i < num_old_args; ++i)
+ {
+ bool is_range = false;
+ current_arg = old_args.GetArgumentAtIndex (i);
+
+ size_t range_start_len = 0;
+ size_t range_end_pos = 0;
+ 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 ((i + 2 < num_old_args)
+ && BreakpointID::IsRangeIdentifier (old_args.GetArgumentAtIndex (i+1))
+ && BreakpointID::IsValidIDExpression (current_arg)
+ && BreakpointID::IsValidIDExpression (old_args.GetArgumentAtIndex (i+2)))
+ {
+ range_start.assign (current_arg);
+ range_end = old_args.GetArgumentAtIndex (i+2);
+ is_range = true;
+ i = i+2;
+ }
+ else
+ {
+ // See if user has specified id.*
+ std::string tmp_str = old_args.GetArgumentAtIndex (i);
+ size_t pos = tmp_str.find ('.');
+ if (pos != std::string::npos)
+ {
+ std::string bp_id_str = tmp_str.substr (0, pos);
+ if (BreakpointID::IsValidIDExpression (bp_id_str.c_str())
+ && tmp_str[pos+1] == '*'
+ && tmp_str.length() == (pos + 2))
+ {
+ break_id_t bp_id;
+ break_id_t bp_loc_id;
+
+ BreakpointID::ParseCanonicalReference (bp_id_str.c_str(), &bp_id, &bp_loc_id);
+ BreakpointSP breakpoint_sp = target->GetBreakpointByID (bp_id);
+ if (! breakpoint_sp)
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%d' is not a valid breakpoint ID.\n", bp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ const size_t num_locations = breakpoint_sp->GetNumLocations();
+ for (size_t j = 0; j < num_locations; ++j)
+ {
+ BreakpointLocation *bp_loc = breakpoint_sp->GetLocationAtIndex(j).get();
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+
+ }
+ }
+
+ if (is_range)
+ {
+ break_id_t start_bp_id;
+ break_id_t end_bp_id;
+ break_id_t start_loc_id;
+ break_id_t end_loc_id;
+
+ BreakpointID::ParseCanonicalReference (range_start.c_str(), &start_bp_id, &start_loc_id);
+ BreakpointID::ParseCanonicalReference (range_end, &end_bp_id, &end_loc_id);
+
+ if ((start_bp_id == LLDB_INVALID_BREAK_ID)
+ || (! target->GetBreakpointByID (start_bp_id)))
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_start.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ if ((end_bp_id == LLDB_INVALID_BREAK_ID)
+ || (! target->GetBreakpointByID (end_bp_id)))
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("'%s' is not a valid breakpoint ID.\n", range_end);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+
+ if (((start_loc_id == LLDB_INVALID_BREAK_ID)
+ && (end_loc_id != LLDB_INVALID_BREAK_ID))
+ || ((start_loc_id != LLDB_INVALID_BREAK_ID)
+ && (end_loc_id == LLDB_INVALID_BREAK_ID)))
+ {
+ new_args.Clear ();
+ result.AppendErrorWithFormat ("Invalid breakpoint id range: Either both ends of range must specify"
+ " a breakpoint location, or neither can specify a breakpoint location.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ // We have valid range starting & ending breakpoint IDs. Go through all the breakpoints in the
+ // target and find all the breakpoints that fit into this range, and add them to new_args.
+
+ // Next check to see if we have location id's. If so, make sure the start_bp_id and end_bp_id are
+ // for the same breakpoint; otherwise we have an illegal range: breakpoint id ranges that specify
+ // bp locations are NOT allowed to cross major bp id numbers.
+
+ if ((start_loc_id != LLDB_INVALID_BREAK_ID)
+ || (end_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ if (start_bp_id != end_bp_id)
+ {
+ new_args.Clear();
+ result.AppendErrorWithFormat ("Invalid range: Ranges that specify particular breakpoint locations"
+ " must be within the same major breakpoint; you specified two"
+ " different major breakpoints, %d and %d.\n",
+ start_bp_id, end_bp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ }
+
+ const BreakpointList& breakpoints = target->GetBreakpointList();
+ const size_t num_breakpoints = breakpoints.GetSize();
+ for (size_t j = 0; j < num_breakpoints; ++j)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (j).get();
+ break_id_t cur_bp_id = breakpoint->GetID();
+
+ if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
+ continue;
+
+ const size_t num_locations = breakpoint->GetNumLocations();
+
+ if ((cur_bp_id == start_bp_id) && (start_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ for (size_t k = 0; k < num_locations; ++k)
+ {
+ BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if ((bp_loc->GetID() >= start_loc_id) && (bp_loc->GetID() <= end_loc_id))
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else if ((cur_bp_id == end_bp_id) && (end_loc_id != LLDB_INVALID_BREAK_ID))
+ {
+ for (size_t k = 0; k < num_locations; ++k)
+ {
+ BreakpointLocation * bp_loc = breakpoint->GetLocationAtIndex(k).get();
+ if (bp_loc->GetID() <= end_loc_id)
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, bp_loc->GetID());
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else
+ {
+ StreamString canonical_id_str;
+ BreakpointID::GetCanonicalReference (&canonical_id_str, cur_bp_id, LLDB_INVALID_BREAK_ID);
+ new_args.AppendArgument (canonical_id_str.GetData());
+ }
+ }
+ }
+ else // else is_range was false
+ {
+ new_args.AppendArgument (current_arg);
+ }
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return;
+}
+
+bool
+BreakpointIDList::StringContainsIDRangeExpression (const char *in_string,
+ size_t *range_start_len,
+ size_t *range_end_pos)
+{
+ bool is_range_expression = false;
+ std::string arg_str = in_string;
+ std::string::size_type idx;
+ std::string::size_type start_pos = 0;
+
+ *range_start_len = 0;
+ *range_end_pos = 0;
+
+ int specifiers_size = 0;
+ for (int i = 0; BreakpointID::g_range_specifiers[i] != NULL; ++i)
+ ++specifiers_size;
+
+ for (int i = 0; i < specifiers_size && !is_range_expression; ++i)
+ {
+ const char *specifier_str = BreakpointID::g_range_specifiers[i];
+ size_t len = strlen (specifier_str);
+ idx = arg_str.find (BreakpointID::g_range_specifiers[i]);
+ if (idx != std::string::npos)
+ {
+ *range_start_len = idx - start_pos;
+ std::string start_str = arg_str.substr (start_pos, *range_start_len);
+ if (idx + len < arg_str.length())
+ {
+ *range_end_pos = idx + len;
+ std::string end_str = arg_str.substr (*range_end_pos);
+ if (BreakpointID::IsValidIDExpression (start_str.c_str())
+ && BreakpointID::IsValidIDExpression (end_str.c_str()))
+ {
+ is_range_expression = true;
+ //*range_start = start_str;
+ //*range_end = end_str;
+ }
+ }
+ }
+ }
+
+ if (!is_range_expression)
+ {
+ *range_start_len = 0;
+ *range_end_pos = 0;
+ }
+
+ return is_range_expression;
+}
diff --git a/source/Breakpoint/BreakpointList.cpp b/source/Breakpoint/BreakpointList.cpp
new file mode 100644
index 000000000000..5926663af7b1
--- /dev/null
+++ b/source/Breakpoint/BreakpointList.cpp
@@ -0,0 +1,243 @@
+//===-- BreakpointList.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/Breakpoint/BreakpointList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointList::BreakpointList (bool is_internal) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_breakpoints(),
+ m_next_break_id (0),
+ m_is_internal (is_internal)
+{
+}
+
+BreakpointList::~BreakpointList()
+{
+}
+
+
+break_id_t
+BreakpointList::Add (BreakpointSP &bp_sp, bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ // Internal breakpoint IDs are negative, normal ones are positive
+ bp_sp->SetID (m_is_internal ? --m_next_break_id : ++m_next_break_id);
+
+ m_breakpoints.push_back(bp_sp);
+ if (notify)
+ {
+ if (bp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ bp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeAdded, bp_sp));
+ }
+ return bp_sp->GetID();
+}
+
+bool
+BreakpointList::Remove (break_id_t break_id, bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
+ if (pos != m_breakpoints.end())
+ {
+ BreakpointSP bp_sp (*pos);
+ m_breakpoints.erase(pos);
+ if (notify)
+ {
+ if (bp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ bp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeRemoved, bp_sp));
+ }
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointList::SetEnabledAll (bool enabled)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator pos, end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->SetEnabled (enabled);
+}
+
+
+void
+BreakpointList::RemoveAll (bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ ClearAllBreakpointSites ();
+
+ if (notify)
+ {
+ bp_collection::iterator pos, end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged,
+ new Breakpoint::BreakpointEventData (eBreakpointEventTypeRemoved,
+ *pos));
+ }
+ }
+ }
+ m_breakpoints.erase (m_breakpoints.begin(), m_breakpoints.end());
+}
+
+class BreakpointIDMatches
+{
+public:
+ BreakpointIDMatches (break_id_t break_id) :
+ m_break_id(break_id)
+ {
+ }
+
+ bool operator() (const BreakpointSP &bp) const
+ {
+ return m_break_id == bp->GetID();
+ }
+
+private:
+ const break_id_t m_break_id;
+};
+
+BreakpointList::bp_collection::iterator
+BreakpointList::GetBreakpointIDIterator (break_id_t break_id)
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(break_id)); // Predicate
+}
+
+BreakpointList::bp_collection::const_iterator
+BreakpointList::GetBreakpointIDConstIterator (break_id_t break_id) const
+{
+ return std::find_if(m_breakpoints.begin(), m_breakpoints.end(), // Search full range
+ BreakpointIDMatches(break_id)); // Predicate
+}
+
+BreakpointSP
+BreakpointList::FindBreakpointByID (break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::iterator pos = GetBreakpointIDIterator(break_id);
+ if (pos != m_breakpoints.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointSP
+BreakpointList::FindBreakpointByID (break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id);
+ if (pos != m_breakpoints.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+void
+BreakpointList::Dump (Stream *s) const
+{
+ Mutex::Locker locker(m_mutex);
+ s->Printf("%p: ", this);
+ s->Indent();
+ s->Printf("BreakpointList with %u Breakpoints:\n", (uint32_t)m_breakpoints.size());
+ s->IndentMore();
+ bp_collection::const_iterator pos;
+ bp_collection::const_iterator end = m_breakpoints.end();
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->Dump(s);
+ s->IndentLess();
+}
+
+
+BreakpointSP
+BreakpointList::GetBreakpointAtIndex (size_t i)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ size_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = *pos;
+ }
+ return stop_sp;
+}
+
+const BreakpointSP
+BreakpointList::GetBreakpointAtIndex (size_t i) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSP stop_sp;
+ bp_collection::const_iterator end = m_breakpoints.end();
+ bp_collection::const_iterator pos;
+ size_t curr_i = 0;
+ for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i)
+ {
+ if (curr_i == i)
+ stop_sp = *pos;
+ }
+ return stop_sp;
+}
+
+void
+BreakpointList::UpdateBreakpoints (ModuleList& module_list, bool added)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ModulesChanged (module_list, added);
+
+}
+
+void
+BreakpointList::UpdateBreakpointsWhenModuleIsReplaced (ModuleSP old_module_sp, ModuleSP new_module_sp)
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ModuleReplaced (old_module_sp, new_module_sp);
+
+}
+
+void
+BreakpointList::ClearAllBreakpointSites ()
+{
+ Mutex::Locker locker(m_mutex);
+ bp_collection::iterator end = m_breakpoints.end();
+ bp_collection::iterator pos;
+ for (pos = m_breakpoints.begin(); pos != end; ++pos)
+ (*pos)->ClearAllBreakpointSites ();
+
+}
+
+void
+BreakpointList::GetListMutex (Mutex::Locker &locker)
+{
+ return locker.Lock (m_mutex);
+}
diff --git a/source/Breakpoint/BreakpointLocation.cpp b/source/Breakpoint/BreakpointLocation.cpp
new file mode 100644
index 000000000000..1ec726dd52b1
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocation.cpp
@@ -0,0 +1,677 @@
+//===-- BreakpointLocation.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"
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointID.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocation::BreakpointLocation
+(
+ break_id_t loc_id,
+ Breakpoint &owner,
+ const Address &addr,
+ lldb::tid_t tid,
+ bool hardware
+) :
+ StoppointLocation (loc_id, addr.GetOpcodeLoadAddress(&owner.GetTarget()), hardware),
+ m_being_created(true),
+ m_address (addr),
+ m_owner (owner),
+ m_options_ap (),
+ m_bp_site_sp (),
+ m_condition_mutex ()
+{
+ SetThreadID (tid);
+ m_being_created = false;
+}
+
+BreakpointLocation::~BreakpointLocation()
+{
+ ClearBreakpointSite();
+}
+
+lldb::addr_t
+BreakpointLocation::GetLoadAddress () const
+{
+ return m_address.GetOpcodeLoadAddress (&m_owner.GetTarget());
+}
+
+Address &
+BreakpointLocation::GetAddress ()
+{
+ return m_address;
+}
+
+Breakpoint &
+BreakpointLocation::GetBreakpoint ()
+{
+ return m_owner;
+}
+
+bool
+BreakpointLocation::IsEnabled () const
+{
+ if (!m_owner.IsEnabled())
+ return false;
+ else if (m_options_ap.get() != NULL)
+ return m_options_ap->IsEnabled();
+ else
+ return true;
+}
+
+void
+BreakpointLocation::SetEnabled (bool enabled)
+{
+ GetLocationOptions()->SetEnabled(enabled);
+ if (enabled)
+ {
+ ResolveBreakpointSite();
+ }
+ else
+ {
+ ClearBreakpointSite();
+ }
+ SendBreakpointLocationChangedEvent (enabled ? eBreakpointEventTypeEnabled : eBreakpointEventTypeDisabled);
+}
+
+void
+BreakpointLocation::SetThreadID (lldb::tid_t thread_id)
+{
+ if (thread_id != LLDB_INVALID_THREAD_ID)
+ GetLocationOptions()->SetThreadID(thread_id);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->SetThreadID (thread_id);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+lldb::tid_t
+BreakpointLocation::GetThreadID ()
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID();
+ else
+ return LLDB_INVALID_THREAD_ID;
+}
+
+void
+BreakpointLocation::SetThreadIndex (uint32_t index)
+{
+ if (index != 0)
+ GetLocationOptions()->GetThreadSpec()->SetIndex(index);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetIndex(index);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+
+}
+
+uint32_t
+BreakpointLocation::GetThreadIndex() const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetIndex();
+ else
+ return 0;
+}
+
+void
+BreakpointLocation::SetThreadName (const char *thread_name)
+{
+ if (thread_name != NULL)
+ GetLocationOptions()->GetThreadSpec()->SetName(thread_name);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetName(thread_name);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+BreakpointLocation::GetThreadName () const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetName();
+ else
+ return NULL;
+}
+
+void
+BreakpointLocation::SetQueueName (const char *queue_name)
+{
+ if (queue_name != NULL)
+ GetLocationOptions()->GetThreadSpec()->SetQueueName(queue_name);
+ else
+ {
+ // If we're resetting this to an invalid thread id, then
+ // don't make an options pointer just to do that.
+ if (m_options_ap.get() != NULL)
+ m_options_ap->GetThreadSpec()->SetQueueName(queue_name);
+ }
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeThreadChanged);
+}
+
+const char *
+BreakpointLocation::GetQueueName () const
+{
+ if (GetOptionsNoCreate()->GetThreadSpecNoCreate())
+ return GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetQueueName();
+ else
+ return NULL;
+}
+
+bool
+BreakpointLocation::InvokeCallback (StoppointCallbackContext *context)
+{
+ if (m_options_ap.get() != NULL && m_options_ap->HasCallback())
+ return m_options_ap->InvokeCallback (context, m_owner.GetID(), GetID());
+ else
+ return m_owner.InvokeCallback (context, GetID());
+}
+
+void
+BreakpointLocation::SetCallback (BreakpointHitCallback callback, void *baton,
+ bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ GetLocationOptions()->SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+void
+BreakpointLocation::SetCallback (BreakpointHitCallback callback, const BatonSP &baton_sp,
+ bool is_synchronous)
+{
+ GetLocationOptions()->SetCallback (callback, baton_sp, is_synchronous);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeCommandChanged);
+}
+
+
+void
+BreakpointLocation::ClearCallback ()
+{
+ GetLocationOptions()->ClearCallback();
+}
+
+void
+BreakpointLocation::SetCondition (const char *condition)
+{
+ GetLocationOptions()->SetCondition (condition);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeConditionChanged);
+}
+
+const char *
+BreakpointLocation::GetConditionText (size_t *hash) const
+{
+ return GetOptionsNoCreate()->GetConditionText(hash);
+}
+
+bool
+BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ Mutex::Locker evaluation_locker(m_condition_mutex);
+
+ size_t condition_hash;
+ const char *condition_text = GetConditionText(&condition_hash);
+
+ if (!condition_text)
+ {
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ if (condition_hash != m_condition_hash ||
+ !m_user_expression_sp ||
+ !m_user_expression_sp->MatchesContext(exe_ctx))
+ {
+ m_user_expression_sp.reset(new ClangUserExpression(condition_text,
+ NULL,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny));
+
+ StreamString errors;
+
+ if (!m_user_expression_sp->Parse(errors,
+ exe_ctx,
+ eExecutionPolicyOnlyWhenNeeded,
+ true))
+ {
+ error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s",
+ errors.GetData());
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ m_condition_hash = condition_hash;
+ }
+
+ // We need to make sure the user sees any parse errors in their condition, so we'll hook the
+ // constructor errors up to the debugger's Async I/O.
+
+ ValueObjectSP result_value_sp;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+
+ Error expr_error;
+
+ StreamString execution_errors;
+
+ ClangExpressionVariableSP result_variable_sp;
+
+ ExecutionResults result_code =
+ m_user_expression_sp->Execute(execution_errors,
+ exe_ctx,
+ unwind_on_error,
+ ignore_breakpoints,
+ m_user_expression_sp,
+ result_variable_sp,
+ try_all_threads,
+ ClangUserExpression::kDefaultTimeout);
+
+ bool ret;
+
+ if (result_code == eExecutionCompleted)
+ {
+ if (!result_variable_sp)
+ {
+ ret = false;
+ error.SetErrorString("Expression did not return a result");
+ return false;
+ }
+
+ result_value_sp = result_variable_sp->GetValueObject();
+
+ if (result_value_sp)
+ {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue (scalar_value))
+ {
+ if (scalar_value.ULongLong(1) == 0)
+ ret = false;
+ else
+ ret = true;
+ if (log)
+ log->Printf("Condition successfully evaluated, result is %s.\n",
+ ret ? "true" : "false");
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get an integer result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get any result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorStringWithFormat("Couldn't execute expression:\n%s", execution_errors.GetData());
+ }
+
+ return ret;
+}
+
+uint32_t
+BreakpointLocation::GetIgnoreCount ()
+{
+ return GetOptionsNoCreate()->GetIgnoreCount();
+}
+
+void
+BreakpointLocation::SetIgnoreCount (uint32_t n)
+{
+ GetLocationOptions()->SetIgnoreCount(n);
+ SendBreakpointLocationChangedEvent (eBreakpointEventTypeIgnoreChanged);
+}
+
+void
+BreakpointLocation::DecrementIgnoreCount()
+{
+ if (m_options_ap.get() != NULL)
+ {
+ uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
+ if (loc_ignore != 0)
+ m_options_ap->SetIgnoreCount(loc_ignore - 1);
+ }
+}
+
+bool
+BreakpointLocation::IgnoreCountShouldStop()
+{
+ if (m_options_ap.get() != NULL)
+ {
+ uint32_t loc_ignore = m_options_ap->GetIgnoreCount();
+ if (loc_ignore != 0)
+ {
+ m_owner.DecrementIgnoreCount();
+ DecrementIgnoreCount(); // Have to decrement our owners' ignore count, since it won't get a
+ // chance to.
+ return false;
+ }
+ }
+ return true;
+}
+
+const BreakpointOptions *
+BreakpointLocation::GetOptionsNoCreate () const
+{
+ if (m_options_ap.get() != NULL)
+ return m_options_ap.get();
+ else
+ return m_owner.GetOptions ();
+}
+
+BreakpointOptions *
+BreakpointLocation::GetLocationOptions ()
+{
+ // If we make the copy we don't copy the callbacks because that is potentially
+ // expensive and we don't want to do that for the simple case where someone is
+ // just disabling the location.
+ if (m_options_ap.get() == NULL)
+ m_options_ap.reset(BreakpointOptions::CopyOptionsNoCallback(*m_owner.GetOptions ()));
+
+ return m_options_ap.get();
+}
+
+bool
+BreakpointLocation::ValidForThisThread (Thread *thread)
+{
+ return thread->MatchesSpec(GetOptionsNoCreate()->GetThreadSpecNoCreate());
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue. Note, we don't check the thread spec for the breakpoint
+// here, since if the breakpoint is not for this thread, then the event won't
+// even get reported, so the check is redundant.
+
+bool
+BreakpointLocation::ShouldStop (StoppointCallbackContext *context)
+{
+ bool should_stop = true;
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ IncrementHitCount();
+
+ if (!IsEnabled())
+ return false;
+
+ if (!IgnoreCountShouldStop())
+ return false;
+
+ if (!m_owner.IgnoreCountShouldStop())
+ return false;
+
+ // We only run synchronous callbacks in ShouldStop:
+ context->is_synchronous = true;
+ should_stop = InvokeCallback (context);
+
+ if (log)
+ {
+ StreamString s;
+ GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Hit breakpoint location: %s, %s.\n", s.GetData(), should_stop ? "stopping" : "continuing");
+ }
+
+ return should_stop;
+}
+
+bool
+BreakpointLocation::IsResolved () const
+{
+ return m_bp_site_sp.get() != NULL;
+}
+
+lldb::BreakpointSiteSP
+BreakpointLocation::GetBreakpointSite() const
+{
+ return m_bp_site_sp;
+}
+
+bool
+BreakpointLocation::ResolveBreakpointSite ()
+{
+ if (m_bp_site_sp)
+ return true;
+
+ Process *process = m_owner.GetTarget().GetProcessSP().get();
+ if (process == NULL)
+ return false;
+
+ lldb::break_id_t new_id = process->CreateBreakpointSite (shared_from_this(), false);
+
+ if (new_id == LLDB_INVALID_BREAK_ID)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+ if (log)
+ log->Warning ("Tried to add breakpoint site at 0x%" PRIx64 " but it was already present.\n",
+ m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+BreakpointLocation::SetBreakpointSite (BreakpointSiteSP& bp_site_sp)
+{
+ m_bp_site_sp = bp_site_sp;
+ return true;
+}
+
+bool
+BreakpointLocation::ClearBreakpointSite ()
+{
+ if (m_bp_site_sp.get())
+ {
+ m_owner.GetTarget().GetProcessSP()->RemoveOwnerFromBreakpointSite (GetBreakpoint().GetID(),
+ GetID(), m_bp_site_sp);
+ m_bp_site_sp.reset();
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointLocation::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ SymbolContext sc;
+
+ // If the description level is "initial" then the breakpoint is printing out our initial state,
+ // and we should let it decide how it wants to print our label.
+ if (level != eDescriptionLevelInitial)
+ {
+ s->Indent();
+ BreakpointID::GetCanonicalReference(s, m_owner.GetID(), GetID());
+ }
+
+ if (level == lldb::eDescriptionLevelBrief)
+ return;
+
+ if (level != eDescriptionLevelInitial)
+ s->PutCString(": ");
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ s->IndentMore();
+
+ if (m_address.IsSectionOffset())
+ {
+ m_address.CalculateSymbolContext(&sc);
+
+ if (level == lldb::eDescriptionLevelFull || level == eDescriptionLevelInitial)
+ {
+ s->PutCString("where = ");
+ sc.DumpStopContext (s, m_owner.GetTarget().GetProcessSP().get(), m_address, false, true, false);
+ }
+ else
+ {
+ if (sc.module_sp)
+ {
+ s->EOL();
+ s->Indent("module = ");
+ sc.module_sp->GetFileSpec().Dump (s);
+ }
+
+ if (sc.comp_unit != NULL)
+ {
+ s->EOL();
+ s->Indent("compile unit = ");
+ static_cast<FileSpec*>(sc.comp_unit)->GetFilename().Dump (s);
+
+ if (sc.function != NULL)
+ {
+ s->EOL();
+ s->Indent("function = ");
+ s->PutCString (sc.function->GetMangled().GetName().AsCString("<unknown>"));
+ }
+
+ if (sc.line_entry.line > 0)
+ {
+ s->EOL();
+ s->Indent("location = ");
+ sc.line_entry.DumpStopContext (s, true);
+ }
+
+ }
+ else
+ {
+ // If we don't have a comp unit, see if we have a symbol we can print.
+ if (sc.symbol)
+ {
+ s->EOL();
+ s->Indent("symbol = ");
+ s->PutCString(sc.symbol->GetMangled().GetName().AsCString("<unknown>"));
+ }
+ }
+ }
+ }
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL();
+ s->Indent();
+ }
+
+ if (m_address.IsSectionOffset() && (level == eDescriptionLevelFull || level == eDescriptionLevelInitial))
+ s->Printf (", ");
+ s->Printf ("address = ");
+
+ ExecutionContextScope *exe_scope = NULL;
+ Target *target = &m_owner.GetTarget();
+ if (target)
+ exe_scope = target->GetProcessSP().get();
+ if (exe_scope == NULL)
+ exe_scope = target;
+
+ if (eDescriptionLevelInitial)
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ else
+ m_address.Dump(s, exe_scope, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL();
+ s->Indent();
+ s->Printf("resolved = %s\n", IsResolved() ? "true" : "false");
+
+ s->Indent();
+ s->Printf ("hit count = %-4u\n", GetHitCount());
+
+ if (m_options_ap.get())
+ {
+ s->Indent();
+ m_options_ap->GetDescription (s, level);
+ s->EOL();
+ }
+ s->IndentLess();
+ }
+ else if (level != eDescriptionLevelInitial)
+ {
+ s->Printf(", %sresolved, hit count = %u ",
+ (IsResolved() ? "" : "un"),
+ GetHitCount());
+ if (m_options_ap.get())
+ {
+ m_options_ap->GetDescription (s, level);
+ }
+ }
+}
+
+void
+BreakpointLocation::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("BreakpointLocation %u: tid = %4.4" PRIx64 " load addr = 0x%8.8" PRIx64 " state = %s type = %s breakpoint "
+ "hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetID(),
+ GetOptionsNoCreate()->GetThreadSpecNoCreate()->GetTID(),
+ (uint64_t) m_address.GetOpcodeLoadAddress (&m_owner.GetTarget()),
+ (m_options_ap.get() ? m_options_ap->IsEnabled() : m_owner.IsEnabled()) ? "enabled " : "disabled",
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetOptionsNoCreate()->GetIgnoreCount());
+}
+
+void
+BreakpointLocation::SendBreakpointLocationChangedEvent (lldb::BreakpointEventType eventKind)
+{
+ if (!m_being_created
+ && !m_owner.IsInternal()
+ && m_owner.GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ Breakpoint::BreakpointEventData *data = new Breakpoint::BreakpointEventData (eventKind,
+ m_owner.shared_from_this());
+ data->GetBreakpointLocationCollection().Add (shared_from_this());
+ m_owner.GetTarget().BroadcastEvent (Target::eBroadcastBitBreakpointChanged, data);
+ }
+}
+
diff --git a/source/Breakpoint/BreakpointLocationCollection.cpp b/source/Breakpoint/BreakpointLocationCollection.cpp
new file mode 100644
index 000000000000..ee3f56f928d5
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocationCollection.cpp
@@ -0,0 +1,198 @@
+//===-- BreakpointLocationCollection.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/Breakpoint/BreakpointLocationCollection.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointLocationCollection constructor
+//----------------------------------------------------------------------
+BreakpointLocationCollection::BreakpointLocationCollection() :
+ m_break_loc_collection()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+BreakpointLocationCollection::~BreakpointLocationCollection()
+{
+}
+
+void
+BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc)
+{
+ BreakpointLocationSP old_bp_loc = FindByIDPair (bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
+ if (!old_bp_loc.get())
+ m_break_loc_collection.push_back(bp_loc);
+}
+
+bool
+BreakpointLocationCollection::Remove (lldb::break_id_t bp_id, lldb::break_id_t bp_loc_id)
+{
+ collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
+ if (pos != m_break_loc_collection.end())
+ {
+ m_break_loc_collection.erase(pos);
+ return true;
+ }
+ return false;
+
+}
+
+class BreakpointIDPairMatches
+{
+public:
+ BreakpointIDPairMatches (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) :
+ m_break_id(break_id),
+ m_break_loc_id (break_loc_id)
+ {
+ }
+
+ bool operator() (const BreakpointLocationSP &bp_loc) const
+ {
+ return m_break_id == bp_loc->GetBreakpoint().GetID()
+ && m_break_loc_id == bp_loc->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+ const lldb::break_id_t m_break_loc_id;
+};
+
+BreakpointLocationCollection::collection::iterator
+BreakpointLocationCollection::GetIDPairIterator (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ return std::find_if(m_break_loc_collection.begin(), m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationCollection::collection::const_iterator
+BreakpointLocationCollection::GetIDPairConstIterator (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const
+{
+ return std::find_if(m_break_loc_collection.begin(), m_break_loc_collection.end(), // Search full range
+ BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
+}
+
+BreakpointLocationSP
+BreakpointLocationCollection::FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ BreakpointLocationSP stop_sp;
+ collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::FindByIDPair (lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const
+{
+ BreakpointLocationSP stop_sp;
+ collection::const_iterator pos = GetIDPairConstIterator(break_id, break_loc_id);
+ if (pos != m_break_loc_collection.end())
+ stop_sp = *pos;
+
+ return stop_sp;
+}
+
+BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex (size_t i)
+{
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationCollection::GetByIndex (size_t i) const
+{
+ BreakpointLocationSP stop_sp;
+ if (i < m_break_loc_collection.size())
+ stop_sp = m_break_loc_collection[i];
+
+ return stop_sp;
+}
+
+bool
+BreakpointLocationCollection::ShouldStop (StoppointCallbackContext *context)
+{
+ bool shouldStop = false;
+ const size_t count = GetSize();
+ for (size_t i = 0; i < count; i++)
+ {
+ if (GetByIndex(i)->ShouldStop(context))
+ shouldStop = true;
+ }
+ return shouldStop;
+}
+
+bool
+BreakpointLocationCollection::ValidForThisThread (Thread *thread)
+{
+ collection::iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((*pos)->ValidForThisThread (thread))
+ return true;
+ }
+ return false;
+}
+
+bool
+BreakpointLocationCollection::IsInternal () const
+{
+ collection::const_iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ bool is_internal = true;
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (!(*pos)->GetBreakpoint().IsInternal ())
+ {
+ is_internal = false;
+ break;
+ }
+ }
+ return is_internal;
+}
+
+void
+BreakpointLocationCollection::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ collection::iterator pos,
+ begin = m_break_loc_collection.begin(),
+ end = m_break_loc_collection.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos != begin)
+ s->PutChar(' ');
+ (*pos)->GetDescription(s, level);
+ }
+}
diff --git a/source/Breakpoint/BreakpointLocationList.cpp b/source/Breakpoint/BreakpointLocationList.cpp
new file mode 100644
index 000000000000..22a4ff0c68ee
--- /dev/null
+++ b/source/Breakpoint/BreakpointLocationList.cpp
@@ -0,0 +1,305 @@
+//===-- BreakpointLocationList.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/Breakpoint/BreakpointLocationList.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointLocationList::BreakpointLocationList(Breakpoint &owner) :
+ m_owner (owner),
+ m_locations(),
+ m_address_to_location (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_next_id (0),
+ m_new_location_recorder (NULL)
+{
+}
+
+BreakpointLocationList::~BreakpointLocationList()
+{
+}
+
+BreakpointLocationSP
+BreakpointLocationList::Create (const Address &addr)
+{
+ Mutex::Locker locker (m_mutex);
+ // The location ID is just the size of the location list + 1
+ lldb::break_id_t bp_loc_id = ++m_next_id;
+ BreakpointLocationSP bp_loc_sp (new BreakpointLocation (bp_loc_id, m_owner, addr));
+ m_locations.push_back (bp_loc_sp);
+ m_address_to_location[addr] = bp_loc_sp;
+ return bp_loc_sp;
+}
+
+bool
+BreakpointLocationList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t break_id)
+{
+ BreakpointLocationSP bp = FindByID (break_id);
+ if (bp)
+ {
+ // Let the BreakpointLocation decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop (shared library loads/unloads).
+ return bp->ShouldStop (context);
+ }
+ // We should stop here since this BreakpointLocation isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+lldb::break_id_t
+BreakpointLocationList::FindIDByAddress (const Address &addr)
+{
+ BreakpointLocationSP bp_loc_sp = FindByAddress (addr);
+ if (bp_loc_sp)
+ {
+ return bp_loc_sp->GetID();
+ }
+ return LLDB_INVALID_BREAK_ID;
+}
+
+BreakpointLocationSP
+BreakpointLocationList::FindByID (lldb::break_id_t break_id) const
+{
+ BreakpointLocationSP bp_loc_sp;
+ Mutex::Locker locker (m_mutex);
+ // We never remove a breakpoint locations, so the ID can be translated into
+ // the location index by subtracting 1
+ uint32_t idx = break_id - 1;
+ if (idx <= m_locations.size())
+ {
+ bp_loc_sp = m_locations[idx];
+ }
+ return bp_loc_sp;
+}
+
+size_t
+BreakpointLocationList::FindInModule (Module *module,
+ BreakpointLocationCollection& bp_loc_list)
+{
+ Mutex::Locker locker (m_mutex);
+ const size_t orig_size = bp_loc_list.GetSize();
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ BreakpointLocationSP break_loc = (*pos);
+ SectionSP section_sp (break_loc->GetAddress().GetSection());
+ if (section_sp && section_sp->GetModule().get() == module)
+ {
+ bp_loc_list.Add (break_loc);
+ }
+ }
+ return bp_loc_list.GetSize() - orig_size;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::FindByAddress (const Address &addr) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (!m_locations.empty())
+ {
+ Address so_addr;
+
+ if (addr.IsSectionOffset())
+ {
+ so_addr = addr;
+ }
+ else
+ {
+ // Try and resolve as a load address if possible.
+ m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), so_addr);
+ if (!so_addr.IsValid())
+ {
+ // The address didn't resolve, so just set to passed in addr.
+ so_addr = addr;
+ }
+ }
+
+ addr_map::const_iterator pos = m_address_to_location.find (so_addr);
+ if (pos != m_address_to_location.end())
+ bp_loc_sp = pos->second;
+ }
+
+ return bp_loc_sp;
+}
+
+void
+BreakpointLocationList::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ //s->Indent();
+ Mutex::Locker locker (m_mutex);
+ s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n", (uint64_t)m_locations.size());
+ s->IndentMore();
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos).get()->Dump(s);
+ s->IndentLess();
+}
+
+
+BreakpointLocationSP
+BreakpointLocationList::GetByIndex (size_t i)
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+const BreakpointLocationSP
+BreakpointLocationList::GetByIndex (size_t i) const
+{
+ Mutex::Locker locker (m_mutex);
+ BreakpointLocationSP bp_loc_sp;
+ if (i < m_locations.size())
+ bp_loc_sp = m_locations[i];
+
+ return bp_loc_sp;
+}
+
+void
+BreakpointLocationList::ClearAllBreakpointSites ()
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ (*pos)->ClearBreakpointSite();
+}
+
+void
+BreakpointLocationList::ResolveAllBreakpointSites ()
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->IsEnabled())
+ (*pos)->ResolveBreakpointSite();
+ }
+}
+
+uint32_t
+BreakpointLocationList::GetHitCount () const
+{
+ uint32_t hit_count = 0;
+ Mutex::Locker locker (m_mutex);
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+size_t
+BreakpointLocationList::GetNumResolvedLocations() const
+{
+ Mutex::Locker locker (m_mutex);
+ size_t resolve_count = 0;
+ collection::const_iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->IsResolved())
+ ++resolve_count;
+ }
+ return resolve_count;
+}
+
+void
+BreakpointLocationList::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+ collection::iterator pos, end = m_locations.end();
+
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ s->Printf(" ");
+ (*pos)->GetDescription(s, level);
+ }
+}
+
+BreakpointLocationSP
+BreakpointLocationList::AddLocation (const Address &addr, bool *new_location)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (new_location)
+ *new_location = false;
+ BreakpointLocationSP bp_loc_sp (FindByAddress(addr));
+ if (!bp_loc_sp)
+ {
+ bp_loc_sp = Create (addr);
+ if (bp_loc_sp)
+ {
+ bp_loc_sp->ResolveBreakpointSite();
+
+ if (new_location)
+ *new_location = true;
+ if(m_new_location_recorder)
+ {
+ m_new_location_recorder->Add(bp_loc_sp);
+ }
+ }
+ }
+ return bp_loc_sp;
+}
+
+bool
+BreakpointLocationList::RemoveLocation (const lldb::BreakpointLocationSP &bp_loc_sp)
+{
+ if (bp_loc_sp)
+ {
+ Mutex::Locker locker (m_mutex);
+
+ m_address_to_location.erase (bp_loc_sp->GetAddress());
+
+ collection::iterator pos, end = m_locations.end();
+ for (pos = m_locations.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == bp_loc_sp.get())
+ {
+ m_locations.erase (pos);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+void
+BreakpointLocationList::StartRecordingNewLocations (BreakpointLocationCollection &new_locations)
+{
+ Mutex::Locker locker (m_mutex);
+ assert (m_new_location_recorder == NULL);
+ m_new_location_recorder = &new_locations;
+}
+
+void
+BreakpointLocationList::StopRecordingNewLocations ()
+{
+ Mutex::Locker locker (m_mutex);
+ m_new_location_recorder = NULL;
+}
+
diff --git a/source/Breakpoint/BreakpointOptions.cpp b/source/Breakpoint/BreakpointOptions.cpp
new file mode 100644
index 000000000000..3a4a117695fc
--- /dev/null
+++ b/source/Breakpoint/BreakpointOptions.cpp
@@ -0,0 +1,298 @@
+//===-- BreakpointOptions.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/Breakpoint/BreakpointOptions.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+BreakpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id)
+{
+ return true;
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions constructor
+//----------------------------------------------------------------------
+BreakpointOptions::BreakpointOptions() :
+ m_callback (BreakpointOptions::NullCallback),
+ m_callback_baton_sp (),
+ m_callback_is_synchronous (false),
+ m_enabled (true),
+ m_one_shot (false),
+ m_ignore_count (0),
+ m_thread_spec_ap (),
+ m_condition_text (),
+ m_condition_text_hash (0)
+{
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions copy constructor
+//----------------------------------------------------------------------
+BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) :
+ m_callback (rhs.m_callback),
+ m_callback_baton_sp (rhs.m_callback_baton_sp),
+ m_callback_is_synchronous (rhs.m_callback_is_synchronous),
+ m_enabled (rhs.m_enabled),
+ m_one_shot (rhs.m_one_shot),
+ m_ignore_count (rhs.m_ignore_count),
+ m_thread_spec_ap ()
+{
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+}
+
+//----------------------------------------------------------------------
+// BreakpointOptions assignment operator
+//----------------------------------------------------------------------
+const BreakpointOptions&
+BreakpointOptions::operator=(const BreakpointOptions& rhs)
+{
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ m_enabled = rhs.m_enabled;
+ m_one_shot = rhs.m_one_shot;
+ m_ignore_count = rhs.m_ignore_count;
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
+ return *this;
+}
+
+BreakpointOptions *
+BreakpointOptions::CopyOptionsNoCallback (BreakpointOptions &orig)
+{
+ BreakpointHitCallback orig_callback = orig.m_callback;
+ lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+ bool orig_is_sync = orig.m_callback_is_synchronous;
+
+ orig.ClearCallback();
+ BreakpointOptions *ret_val = new BreakpointOptions(orig);
+
+ orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
+
+ return ret_val;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+BreakpointOptions::~BreakpointOptions()
+{
+}
+
+//------------------------------------------------------------------
+// Callbacks
+//------------------------------------------------------------------
+void
+BreakpointOptions::SetCallback (BreakpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
+{
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+}
+
+void
+BreakpointOptions::ClearCallback ()
+{
+ m_callback = BreakpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+}
+
+Baton *
+BreakpointOptions::GetBaton ()
+{
+ return m_callback_baton_sp.get();
+}
+
+const Baton *
+BreakpointOptions::GetBaton () const
+{
+ return m_callback_baton_sp.get();
+}
+
+bool
+BreakpointOptions::InvokeCallback (StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ if (m_callback && context->is_synchronous == IsCallbackSynchronous())
+ {
+ return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
+ context,
+ break_id,
+ break_loc_id);
+ }
+ else
+ return true;
+}
+
+bool
+BreakpointOptions::HasCallback ()
+{
+ return m_callback != BreakpointOptions::NullCallback;
+}
+
+void
+BreakpointOptions::SetCondition (const char *condition)
+{
+ if (!condition)
+ condition = "";
+
+ m_condition_text.assign(condition);
+ std::hash<std::string> hasher;
+ m_condition_text_hash = hasher(m_condition_text);
+}
+
+const char *
+BreakpointOptions::GetConditionText (size_t *hash) const
+{
+ if (!m_condition_text.empty())
+ {
+ if (hash)
+ *hash = m_condition_text_hash;
+
+ return m_condition_text.c_str();
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+const ThreadSpec *
+BreakpointOptions::GetThreadSpecNoCreate () const
+{
+ return m_thread_spec_ap.get();
+}
+
+ThreadSpec *
+BreakpointOptions::GetThreadSpec ()
+{
+ if (m_thread_spec_ap.get() == NULL)
+ m_thread_spec_ap.reset (new ThreadSpec());
+
+ return m_thread_spec_ap.get();
+}
+
+void
+BreakpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+ GetThreadSpec()->SetTID(thread_id);
+}
+
+void
+BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+
+ // Figure out if there are any options not at their default value, and only print
+ // anything if there are:
+
+ if (m_ignore_count != 0 || !m_enabled || m_one_shot || (GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
+ {
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL ();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Breakpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ }
+ else
+ s->PutCString(" Options: ");
+
+ if (m_ignore_count > 0)
+ s->Printf("ignore: %d ", m_ignore_count);
+ s->Printf("%sabled ", m_enabled ? "en" : "dis");
+
+ if (m_one_shot)
+ s->Printf ("one-shot ");
+
+ 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();
+ s->IndentMore();
+ }
+ }
+
+ if (m_callback_baton_sp.get())
+ {
+ if (level != eDescriptionLevelBrief)
+ {
+ s->EOL();
+ m_callback_baton_sp->GetDescription (s, level);
+ }
+ }
+ if (!m_condition_text.empty())
+ {
+ if (level != eDescriptionLevelBrief)
+ {
+ s->EOL();
+ s->Printf("Condition: %s\n", m_condition_text.c_str());
+ }
+ }
+}
+
+void
+BreakpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ CommandData *data = (CommandData *)m_data;
+
+ if (level == eDescriptionLevelBrief)
+ {
+ s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ s->IndentMore ();
+ s->Indent("Breakpoint commands:\n");
+
+ s->IndentMore ();
+ if (data && data->user_source.GetSize() > 0)
+ {
+ const size_t num_strings = data->user_source.GetSize();
+ for (size_t i = 0; i < num_strings; ++i)
+ {
+ s->Indent(data->user_source.GetStringAtIndex(i));
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString ("No commands.\n");
+ }
+ s->IndentLess ();
+ s->IndentLess ();
+}
+
diff --git a/source/Breakpoint/BreakpointResolver.cpp b/source/Breakpoint/BreakpointResolver.cpp
new file mode 100644
index 000000000000..b22fa1e6dbcc
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolver.cpp
@@ -0,0 +1,61 @@
+//===-- BreakpointResolver.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/Breakpoint/BreakpointResolver.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Address.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolver:
+//----------------------------------------------------------------------
+BreakpointResolver::BreakpointResolver (Breakpoint *bkpt, const unsigned char resolverTy) :
+ m_breakpoint (bkpt),
+ SubclassID (resolverTy)
+{
+}
+
+BreakpointResolver::~BreakpointResolver ()
+{
+
+}
+
+void
+BreakpointResolver::SetBreakpoint (Breakpoint *bkpt)
+{
+ m_breakpoint = bkpt;
+}
+
+void
+BreakpointResolver::ResolveBreakpointInModules (SearchFilter &filter, ModuleList &modules)
+{
+ filter.SearchInModuleList(*this, modules);
+}
+
+void
+BreakpointResolver::ResolveBreakpoint (SearchFilter &filter)
+{
+ filter.Search (*this);
+}
+
diff --git a/source/Breakpoint/BreakpointResolverAddress.cpp b/source/Breakpoint/BreakpointResolverAddress.cpp
new file mode 100644
index 000000000000..1bcef93aedad
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverAddress.cpp
@@ -0,0 +1,111 @@
+//===-- BreakpointResolverAddress.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/Breakpoint/BreakpointResolverAddress.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverAddress:
+//----------------------------------------------------------------------
+BreakpointResolverAddress::BreakpointResolverAddress
+(
+ Breakpoint *bkpt,
+ const Address &addr
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::AddressResolver),
+ m_addr (addr)
+{
+}
+
+BreakpointResolverAddress::~BreakpointResolverAddress ()
+{
+
+}
+
+void
+BreakpointResolverAddress::ResolveBreakpoint (SearchFilter &filter)
+{
+ // The address breakpoint only takes once, so if we've already set it we're done.
+ if (m_breakpoint->GetNumLocations() > 0)
+ return;
+ else
+ BreakpointResolver::ResolveBreakpoint(filter);
+}
+
+void
+BreakpointResolverAddress::ResolveBreakpointInModules
+(
+ SearchFilter &filter,
+ ModuleList &modules
+)
+{
+ // The address breakpoint only takes once, so if we've already set it we're done.
+ if (m_breakpoint->GetNumLocations() > 0)
+ return;
+ else
+ BreakpointResolver::ResolveBreakpointInModules (filter, modules);
+}
+
+Searcher::CallbackReturn
+BreakpointResolverAddress::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ assert (m_breakpoint != NULL);
+
+ if (filter.AddressPasses (m_addr))
+ {
+ BreakpointLocationSP bp_loc_sp(m_breakpoint->AddLocation(m_addr));
+ if (bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ return Searcher::eCallbackReturnStop;
+}
+
+Searcher::Depth
+BreakpointResolverAddress::GetDepth()
+{
+ return Searcher::eDepthTarget;
+}
+
+void
+BreakpointResolverAddress::GetDescription (Stream *s)
+{
+ s->PutCString ("address = ");
+ m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(), Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+}
+
+void
+BreakpointResolverAddress::Dump (Stream *s) const
+{
+
+}
diff --git a/source/Breakpoint/BreakpointResolverFileLine.cpp b/source/Breakpoint/BreakpointResolverFileLine.cpp
new file mode 100644
index 000000000000..91a218fdb80a
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverFileLine.cpp
@@ -0,0 +1,246 @@
+//===-- BreakpointResolverFileLine.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/Breakpoint/BreakpointResolverFileLine.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverFileLine:
+//----------------------------------------------------------------------
+BreakpointResolverFileLine::BreakpointResolverFileLine
+(
+ Breakpoint *bkpt,
+ const FileSpec &file_spec,
+ uint32_t line_no,
+ bool check_inlines,
+ bool skip_prologue
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
+ m_file_spec (file_spec),
+ m_line_number (line_no),
+ m_inlines (check_inlines),
+ m_skip_prologue(skip_prologue)
+{
+}
+
+BreakpointResolverFileLine::~BreakpointResolverFileLine ()
+{
+}
+
+Searcher::CallbackReturn
+BreakpointResolverFileLine::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList sc_list;
+
+ assert (m_breakpoint != NULL);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ // There is a tricky bit here. You can have two compilation units that #include the same file, and
+ // in one of them the function at m_line_number is used (and so code and a line entry for it is generated) but in the
+ // other it isn't. If we considered the CU's independently, then in the second inclusion, we'd move the breakpoint
+ // to the next function that actually generated code in the header file. That would end up being confusing.
+ // So instead, we do the CU iterations by hand here, then scan through the complete list of matches, and figure out
+ // the closest line number match, and only set breakpoints on that match.
+
+ // Note also that if file_spec only had a file name and not a directory, there may be many different file spec's in
+ // the resultant list. The closest line match for one will not be right for some totally different file.
+ // So we go through the match list and pull out the sets that have the same file spec in their line_entry
+ // and treat each set separately.
+
+ const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (context.module_sp->GetCompileUnitAtIndex (i));
+ if (cu_sp)
+ {
+ if (filter.CompUnitPasses(*cu_sp))
+ cu_sp->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything, sc_list);
+ }
+ }
+
+ while (sc_list.GetSize() > 0)
+ {
+ SymbolContextList tmp_sc_list;
+ unsigned current_idx = 0;
+ SymbolContext sc;
+ bool first_entry = true;
+
+ FileSpec match_file_spec;
+ uint32_t closest_line_number = UINT32_MAX;
+
+ // Pull out the first entry, and all the others that match its file spec, and stuff them in the tmp list.
+ while (current_idx < sc_list.GetSize())
+ {
+ bool matches;
+
+ sc_list.GetContextAtIndex (current_idx, sc);
+ if (first_entry)
+ {
+ match_file_spec = sc.line_entry.file;
+ matches = true;
+ first_entry = false;
+ }
+ else
+ matches = (sc.line_entry.file == match_file_spec);
+
+ if (matches)
+ {
+ tmp_sc_list.Append (sc);
+ sc_list.RemoveContextAtIndex(current_idx);
+
+ // ResolveSymbolContext will always return a number that is >= the line number you pass in.
+ // So the smaller line number is always better.
+ if (sc.line_entry.line < closest_line_number)
+ closest_line_number = sc.line_entry.line;
+ }
+ else
+ current_idx++;
+ }
+
+ // Okay, we've found the closest line number match, now throw away all the others:
+
+ current_idx = 0;
+ while (current_idx < tmp_sc_list.GetSize())
+ {
+ if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
+ {
+ if (sc.line_entry.line != closest_line_number)
+ tmp_sc_list.RemoveContextAtIndex(current_idx);
+ else
+ current_idx++;
+ }
+ }
+
+ // Next go through and see if there are line table entries that are contiguous, and if so keep only the
+ // first of the contiguous range:
+
+ lldb::addr_t last_end_addr = LLDB_INVALID_ADDRESS;
+ current_idx = 0;
+ while (current_idx < tmp_sc_list.GetSize())
+ {
+ if (tmp_sc_list.GetContextAtIndex(current_idx, sc))
+ {
+ lldb::addr_t start_file_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ lldb::addr_t end_file_addr = start_file_addr + sc.line_entry.range.GetByteSize();
+
+ if (start_file_addr == last_end_addr)
+ tmp_sc_list.RemoveContextAtIndex(current_idx);
+ else
+ current_idx++;
+
+ last_end_addr = end_file_addr;
+ }
+ }
+
+ // and make breakpoints out of the closest line number match.
+
+ uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
+
+ for (uint32_t i = 0; i < tmp_sc_list_size; i++)
+ {
+ if (tmp_sc_list.GetContextAtIndex(i, sc))
+ {
+ Address line_start = sc.line_entry.range.GetBaseAddress();
+ if (line_start.IsValid())
+ {
+ if (filter.AddressPasses(line_start))
+ {
+ // If the line number is before the prologue end, move it there...
+ bool skipped_prologue = false;
+ if (m_skip_prologue)
+ {
+ if (sc.function)
+ {
+ Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
+ if (prologue_addr.IsValid() && (line_start == prologue_addr))
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ {
+ prologue_addr.Slide(prologue_byte_size);
+
+ if (filter.AddressPasses(prologue_addr))
+ {
+ skipped_prologue = true;
+ line_start = prologue_addr;
+ }
+ }
+ }
+ }
+ }
+
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
+ if (log && bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location (skipped prologue: %s): %s \n", skipped_prologue ? "yes" : "no", s.GetData());
+ }
+ }
+ else if (log)
+ {
+ log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass the filter.\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverFileLine::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverFileLine::GetDescription (Stream *s)
+{
+ s->Printf ("file = '%s', line = %u", m_file_spec.GetPath().c_str(), m_line_number);
+}
+
+void
+BreakpointResolverFileLine::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointResolverFileRegex.cpp b/source/Breakpoint/BreakpointResolverFileRegex.cpp
new file mode 100644
index 000000000000..de974d04894a
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverFileRegex.cpp
@@ -0,0 +1,134 @@
+//===-- BreakpointResolverFileRegex.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/Breakpoint/BreakpointResolverFileRegex.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// BreakpointResolverFileRegex:
+//----------------------------------------------------------------------
+BreakpointResolverFileRegex::BreakpointResolverFileRegex
+(
+ Breakpoint *bkpt,
+ RegularExpression &regex
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::FileLineResolver),
+ m_regex (regex)
+{
+}
+
+BreakpointResolverFileRegex::~BreakpointResolverFileRegex ()
+{
+}
+
+Searcher::CallbackReturn
+BreakpointResolverFileRegex::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+
+ assert (m_breakpoint != NULL);
+ if (!context.target_sp)
+ return eCallbackReturnContinue;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ CompileUnit *cu = context.comp_unit;
+ FileSpec cu_file_spec = *(static_cast<FileSpec *>(cu));
+ std::vector<uint32_t> line_matches;
+ context.target_sp->GetSourceManager().FindLinesMatchingRegex(cu_file_spec, m_regex, 1, UINT32_MAX, line_matches);
+ uint32_t num_matches = line_matches.size();
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ uint32_t start_idx = 0;
+ bool exact = false;
+ while (1)
+ {
+ LineEntry line_entry;
+
+ // Cycle through all the line entries that might match this one:
+ start_idx = cu->FindLineEntry (start_idx, line_matches[i], NULL, exact, &line_entry);
+ if (start_idx == UINT32_MAX)
+ break;
+ exact = true;
+ start_idx++;
+
+ Address line_start = line_entry.range.GetBaseAddress();
+ if (line_start.IsValid())
+ {
+ if (filter.AddressPasses(line_start))
+ {
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(line_start));
+ if (log && bp_loc_sp && !m_breakpoint->IsInternal())
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ else if (log)
+ {
+ log->Printf ("Breakpoint at file address 0x%" PRIx64 " for %s:%d didn't pass filter.\n",
+ line_start.GetFileAddress(),
+ cu_file_spec.GetFilename().AsCString("<Unknown>"),
+ line_matches[i]);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: Unable to set breakpoint at file address 0x%" PRIx64 " for %s:%d\n",
+ line_start.GetFileAddress(),
+ cu_file_spec.GetFilename().AsCString("<Unknown>"),
+ line_matches[i]);
+ }
+
+ }
+ }
+ assert (m_breakpoint != NULL);
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverFileRegex::GetDepth()
+{
+ return Searcher::eDepthCompUnit;
+}
+
+void
+BreakpointResolverFileRegex::GetDescription (Stream *s)
+{
+ s->Printf ("source regex = \"%s\"", m_regex.GetText());
+}
+
+void
+BreakpointResolverFileRegex::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointResolverName.cpp b/source/Breakpoint/BreakpointResolverName.cpp
new file mode 100644
index 000000000000..27f85653d648
--- /dev/null
+++ b/source/Breakpoint/BreakpointResolverName.cpp
@@ -0,0 +1,357 @@
+//===-- BreakpointResolverName.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/Breakpoint/BreakpointResolverName.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *name_cstr,
+ uint32_t name_type_mask,
+ Breakpoint::MatchType type,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (),
+ m_regex (),
+ m_match_type (type),
+ m_skip_prologue (skip_prologue)
+{
+
+ if (m_match_type == Breakpoint::Regexp)
+ {
+ if (!m_regex.Compile (name_cstr))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Warning ("function name regexp: \"%s\" did not compile.", name_cstr);
+ }
+ }
+ else
+ {
+ AddNameLookup (ConstString(name_cstr), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ const char *names[],
+ size_t num_names,
+ uint32_t name_type_mask,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_skip_prologue (skip_prologue)
+{
+ for (size_t i = 0; i < num_names; i++)
+ {
+ AddNameLookup (ConstString (names[i]), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ std::vector<std::string> names,
+ uint32_t name_type_mask,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_match_type (Breakpoint::Exact),
+ m_skip_prologue (skip_prologue)
+{
+ for (const std::string& name : names)
+ {
+ AddNameLookup (ConstString (name.c_str(), name.size()), name_type_mask);
+ }
+}
+
+BreakpointResolverName::BreakpointResolverName (Breakpoint *bkpt,
+ RegularExpression &func_regex,
+ bool skip_prologue) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (NULL),
+ m_regex (func_regex),
+ m_match_type (Breakpoint::Regexp),
+ m_skip_prologue (skip_prologue)
+{
+}
+
+BreakpointResolverName::BreakpointResolverName
+(
+ Breakpoint *bkpt,
+ const char *class_name,
+ const char *method,
+ Breakpoint::MatchType type,
+ bool skip_prologue
+) :
+ BreakpointResolver (bkpt, BreakpointResolver::NameResolver),
+ m_class_name (class_name),
+ m_regex (),
+ m_match_type (type),
+ m_skip_prologue (skip_prologue)
+{
+ LookupInfo lookup;
+ lookup.name.SetCString(method);
+ lookup.lookup_name = lookup.name;
+ lookup.name_type_mask = eFunctionNameTypeMethod;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+}
+
+BreakpointResolverName::~BreakpointResolverName ()
+{
+}
+
+void
+BreakpointResolverName::AddNameLookup (const ConstString &name, uint32_t name_type_mask)
+{
+ ObjCLanguageRuntime::MethodName objc_method(name.GetCString(), false);
+ if (objc_method.IsValid(false))
+ {
+ std::vector<ConstString> objc_names;
+ objc_method.GetFullNames(objc_names, true);
+ for (ConstString objc_name : objc_names)
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ lookup.lookup_name = objc_name;
+ lookup.name_type_mask = eFunctionNameTypeFull;
+ lookup.match_name_after_lookup = false;
+ m_lookups.push_back (lookup);
+ }
+ }
+ else
+ {
+ LookupInfo lookup;
+ lookup.name = name;
+ Module::PrepareForFunctionNameLookup(lookup.name, name_type_mask, lookup.lookup_name, lookup.name_type_mask, lookup.match_name_after_lookup);
+ m_lookups.push_back (lookup);
+ }
+}
+
+
+void
+BreakpointResolverName::LookupInfo::Prune (SymbolContextList &sc_list, size_t start_idx) const
+{
+ if (match_name_after_lookup && name)
+ {
+ SymbolContext sc;
+ size_t i = start_idx;
+ while (i < sc_list.GetSize())
+ {
+ if (!sc_list.GetContextAtIndex(i, sc))
+ break;
+ ConstString full_name (sc.GetFunctionName());
+ if (full_name && ::strstr(full_name.GetCString(), name.GetCString()) == NULL)
+ {
+ sc_list.RemoveContextAtIndex(i);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ }
+}
+
+
+// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
+// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
+// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
+
+Searcher::CallbackReturn
+BreakpointResolverName::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList func_list;
+ //SymbolContextList sym_list;
+
+ uint32_t i;
+ bool new_location;
+ Address break_addr;
+ assert (m_breakpoint != NULL);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_class_name)
+ {
+ if (log)
+ log->Warning ("Class/method function specification not supported yet.\n");
+ return Searcher::eCallbackReturnStop;
+ }
+ bool filter_by_cu = (filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
+ const bool include_symbols = filter_by_cu == false;
+ const bool include_inlines = true;
+ const bool append = true;
+
+ switch (m_match_type)
+ {
+ case Breakpoint::Exact:
+ if (context.module_sp)
+ {
+ for (const LookupInfo &lookup : m_lookups)
+ {
+ const size_t start_func_idx = func_list.GetSize();
+ context.module_sp->FindFunctions (lookup.lookup_name,
+ NULL,
+ lookup.name_type_mask,
+ include_symbols,
+ include_inlines,
+ append,
+ func_list);
+ const size_t end_func_idx = func_list.GetSize();
+
+ if (start_func_idx < end_func_idx)
+ lookup.Prune (func_list, start_func_idx);
+ }
+ }
+ break;
+ case Breakpoint::Regexp:
+ if (context.module_sp)
+ {
+ context.module_sp->FindFunctions (m_regex,
+ !filter_by_cu, // include symbols only if we aren't filterning by CU
+ include_inlines,
+ append,
+ func_list);
+ }
+ break;
+ case Breakpoint::Glob:
+ if (log)
+ log->Warning ("glob is not supported yet.");
+ break;
+ }
+
+ // If the filter specifies a Compilation Unit, remove the ones that don't pass at this point.
+ if (filter_by_cu)
+ {
+ uint32_t num_functions = func_list.GetSize();
+
+ for (size_t idx = 0; idx < num_functions; idx++)
+ {
+ SymbolContext sc;
+ func_list.GetContextAtIndex(idx, sc);
+ if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
+ {
+ func_list.RemoveContextAtIndex(idx);
+ num_functions--;
+ idx--;
+ }
+ }
+ }
+
+ // Remove any duplicates between the funcion list and the symbol list
+ SymbolContext sc;
+ if (func_list.GetSize())
+ {
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.block && sc.block->GetInlinedFunctionInfo())
+ {
+ if (!sc.block->GetStartAddress(break_addr))
+ break_addr.Clear();
+ }
+ else if (sc.function)
+ {
+ break_addr = sc.function->GetAddressRange().GetBaseAddress();
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+ else if (sc.symbol)
+ {
+ break_addr = sc.symbol->GetAddress();
+ if (m_skip_prologue && break_addr.IsValid())
+ {
+ const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
+ }
+ }
+
+ if (break_addr.IsValid())
+ {
+ if (filter.AddressPasses(break_addr))
+ {
+ BreakpointLocationSP bp_loc_sp (m_breakpoint->AddLocation(break_addr, &new_location));
+ if (bp_loc_sp && new_location && !m_breakpoint->IsInternal())
+ {
+ if (log)
+ {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Added location: %s\n", s.GetData());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+BreakpointResolverName::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+BreakpointResolverName::GetDescription (Stream *s)
+{
+ if (m_match_type == Breakpoint::Regexp)
+ s->Printf("regex = '%s'", m_regex.GetText());
+ else
+ {
+ size_t num_names = m_lookups.size();
+ if (num_names == 1)
+ s->Printf("name = '%s'", m_lookups[0].name.GetCString());
+ else
+ {
+ s->Printf("names = {");
+ for (size_t i = 0; i < num_names - 1; i++)
+ {
+ s->Printf ("'%s', ", m_lookups[i].name.GetCString());
+ }
+ s->Printf ("'%s'}", m_lookups[num_names - 1].name.GetCString());
+ }
+ }
+}
+
+void
+BreakpointResolverName::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Breakpoint/BreakpointSite.cpp b/source/Breakpoint/BreakpointSite.cpp
new file mode 100644
index 000000000000..fa5d8c1f9f81
--- /dev/null
+++ b/source/Breakpoint/BreakpointSite.cpp
@@ -0,0 +1,234 @@
+//===-- BreakpointSite.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/Breakpoint/BreakpointSite.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSiteList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSite::BreakpointSite
+(
+ BreakpointSiteList *list,
+ const BreakpointLocationSP& owner,
+ lldb::addr_t addr,
+ bool use_hardware
+) :
+ StoppointLocation(GetNextID(), addr, 0, use_hardware),
+ m_type (eSoftware), // Process subclasses need to set this correctly using SetType()
+ m_saved_opcode(),
+ m_trap_opcode(),
+ m_enabled(false), // Need to create it disabled, so the first enable turns it on.
+ m_owners()
+{
+ m_owners.Add(owner);
+}
+
+BreakpointSite::~BreakpointSite()
+{
+ BreakpointLocationSP bp_loc_sp;
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++)
+ {
+ m_owners.GetByIndex(i)->ClearBreakpointSite();
+ }
+}
+
+break_id_t
+BreakpointSite::GetNextID()
+{
+ static break_id_t g_next_id = 0;
+ return ++g_next_id;
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+BreakpointSite::ShouldStop (StoppointCallbackContext *context)
+{
+ IncrementHitCount();
+ return m_owners.ShouldStop (context);
+}
+
+bool
+BreakpointSite::IsBreakpointAtThisSite (lldb::break_id_t bp_id)
+{
+ const size_t owner_count = m_owners.GetSize();
+ for (size_t i = 0; i < owner_count; i++)
+ {
+ if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
+ return true;
+ }
+ return false;
+}
+
+void
+BreakpointSite::Dump(Stream *s) const
+{
+ if (s == NULL)
+ return;
+
+ s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64 " type = %s breakpoint hw_index = %i hit_count = %-4u",
+ GetID(),
+ (uint64_t)m_addr,
+ IsHardware() ? "hardware" : "software",
+ GetHardwareIndex(),
+ GetHitCount());
+}
+
+void
+BreakpointSite::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level != lldb::eDescriptionLevelBrief)
+ s->Printf ("breakpoint site: %d at 0x%8.8" PRIx64, GetID(), GetLoadAddress());
+ m_owners.GetDescription (s, level);
+}
+
+bool
+BreakpointSite::IsInternal() const
+{
+ return m_owners.IsInternal();
+}
+
+uint8_t *
+BreakpointSite::GetTrapOpcodeBytes()
+{
+ return &m_trap_opcode[0];
+}
+
+const uint8_t *
+BreakpointSite::GetTrapOpcodeBytes() const
+{
+ return &m_trap_opcode[0];
+}
+
+size_t
+BreakpointSite::GetTrapOpcodeMaxByteSize() const
+{
+ return sizeof(m_trap_opcode);
+}
+
+bool
+BreakpointSite::SetTrapOpcode (const uint8_t *trap_opcode, uint32_t trap_opcode_size)
+{
+ if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode))
+ {
+ m_byte_size = trap_opcode_size;
+ ::memcpy (m_trap_opcode, trap_opcode, trap_opcode_size);
+ return true;
+ }
+ m_byte_size = 0;
+ return false;
+}
+
+uint8_t *
+BreakpointSite::GetSavedOpcodeBytes()
+{
+ return &m_saved_opcode[0];
+}
+
+const uint8_t *
+BreakpointSite::GetSavedOpcodeBytes() const
+{
+ return &m_saved_opcode[0];
+}
+
+bool
+BreakpointSite::IsEnabled () const
+{
+ return m_enabled;
+}
+
+void
+BreakpointSite::SetEnabled (bool enabled)
+{
+ m_enabled = enabled;
+}
+
+void
+BreakpointSite::AddOwner (const BreakpointLocationSP &owner)
+{
+ m_owners.Add(owner);
+}
+
+size_t
+BreakpointSite::RemoveOwner (lldb::break_id_t break_id, lldb::break_id_t break_loc_id)
+{
+ m_owners.Remove(break_id, break_loc_id);
+ return m_owners.GetSize();
+}
+
+size_t
+BreakpointSite::GetNumberOfOwners ()
+{
+ return m_owners.GetSize();
+}
+
+BreakpointLocationSP
+BreakpointSite::GetOwnerAtIndex (size_t index)
+{
+ return m_owners.GetByIndex (index);
+}
+
+bool
+BreakpointSite::ValidForThisThread (Thread *thread)
+{
+ return m_owners.ValidForThisThread(thread);
+}
+
+bool
+BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size, lldb::addr_t *intersect_addr, size_t *intersect_size, size_t *opcode_offset) const
+{
+ // We only use software traps for software breakpoints
+ if (!IsHardware())
+ {
+ if (m_byte_size > 0)
+ {
+ const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
+ const lldb::addr_t end_addr = addr + size;
+ // Is the breakpoint end address before the passed in start address?
+ if (bp_end_addr <= addr)
+ return false;
+ // Is the breakpoint start address after passed in end address?
+ if (end_addr <= m_addr)
+ return false;
+ if (intersect_addr || intersect_size || opcode_offset)
+ {
+ if (m_addr < addr)
+ {
+ if (intersect_addr)
+ *intersect_addr = addr;
+ if (intersect_size)
+ *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
+ if (opcode_offset)
+ *opcode_offset = addr - m_addr;
+ }
+ else
+ {
+ if (intersect_addr)
+ *intersect_addr = m_addr;
+ if (intersect_size)
+ *intersect_size = std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
+ if (opcode_offset)
+ *opcode_offset = 0;
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Breakpoint/BreakpointSiteList.cpp b/source/Breakpoint/BreakpointSiteList.cpp
new file mode 100644
index 000000000000..68c4af18ec5e
--- /dev/null
+++ b/source/Breakpoint/BreakpointSiteList.cpp
@@ -0,0 +1,240 @@
+//===-- BreakpointSiteList.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/Breakpoint/BreakpointSiteList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+BreakpointSiteList::BreakpointSiteList() :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_bp_site_list()
+{
+}
+
+BreakpointSiteList::~BreakpointSiteList()
+{
+}
+
+// Add breakpoint site to the list. However, if the element already exists in the
+// list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
+
+lldb::break_id_t
+BreakpointSiteList::Add(const BreakpointSiteSP &bp)
+{
+ lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
+ Mutex::Locker locker(m_mutex);
+ collection::iterator iter = m_bp_site_list.find (bp_site_load_addr);
+
+ if (iter == m_bp_site_list.end())
+ {
+ m_bp_site_list.insert (iter, collection::value_type (bp_site_load_addr, bp));
+ return bp->GetID();
+ }
+ else
+ {
+ return LLDB_INVALID_BREAK_ID;
+ }
+}
+
+bool
+BreakpointSiteList::ShouldStop (StoppointCallbackContext *context, lldb::break_id_t site_id)
+{
+ BreakpointSiteSP site_sp (FindByID (site_id));
+ if (site_sp)
+ {
+ // Let the BreakpointSite decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop (shared library loads/unloads).
+ return site_sp->ShouldStop (context);
+ }
+ // We should stop here since this BreakpointSite isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+lldb::break_id_t
+BreakpointSiteList::FindIDByAddress (lldb::addr_t addr)
+{
+ BreakpointSiteSP bp = FindByAddress (addr);
+ if (bp)
+ {
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
+ return bp.get()->GetID();
+ }
+ //DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64 " ) => NONE", __FUNCTION__, (uint64_t)addr);
+ return LLDB_INVALID_BREAK_ID;
+}
+
+bool
+BreakpointSiteList::Remove (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::iterator pos = GetIDIterator(break_id); // Predicate
+ if (pos != m_bp_site_list.end())
+ {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+bool
+BreakpointSiteList::RemoveByAddress (lldb::addr_t address)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::iterator pos = m_bp_site_list.find(address);
+ if (pos != m_bp_site_list.end())
+ {
+ m_bp_site_list.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+class BreakpointSiteIDMatches
+{
+public:
+ BreakpointSiteIDMatches (lldb::break_id_t break_id) :
+ m_break_id(break_id)
+ {
+ }
+
+ bool operator() (std::pair <lldb::addr_t, BreakpointSiteSP> val_pair) const
+ {
+ return m_break_id == val_pair.second.get()->GetID();
+ }
+
+private:
+ const lldb::break_id_t m_break_id;
+};
+
+BreakpointSiteList::collection::iterator
+BreakpointSiteList::GetIDIterator (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteList::collection::const_iterator
+BreakpointSiteList::GetIDConstIterator (lldb::break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ return std::find_if(m_bp_site_list.begin(), m_bp_site_list.end(), // Search full range
+ BreakpointSiteIDMatches(break_id)); // Predicate
+}
+
+BreakpointSiteSP
+BreakpointSiteList::FindByID (lldb::break_id_t break_id)
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::iterator pos = GetIDIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+const BreakpointSiteSP
+BreakpointSiteList::FindByID (lldb::break_id_t break_id) const
+{
+ Mutex::Locker locker(m_mutex);
+ BreakpointSiteSP stop_sp;
+ collection::const_iterator pos = GetIDConstIterator(break_id);
+ if (pos != m_bp_site_list.end())
+ stop_sp = pos->second;
+
+ return stop_sp;
+}
+
+BreakpointSiteSP
+BreakpointSiteList::FindByAddress (lldb::addr_t addr)
+{
+ BreakpointSiteSP found_sp;
+ Mutex::Locker locker(m_mutex);
+ collection::iterator iter = m_bp_site_list.find(addr);
+ if (iter != m_bp_site_list.end())
+ found_sp = iter->second;
+ return found_sp;
+}
+
+bool
+BreakpointSiteList::BreakpointSiteContainsBreakpoint (lldb::break_id_t bp_site_id, lldb::break_id_t bp_id)
+{
+ Mutex::Locker locker(m_mutex);
+ collection::const_iterator pos = GetIDConstIterator(bp_site_id);
+ if (pos != m_bp_site_list.end())
+ return pos->second->IsBreakpointAtThisSite (bp_id);
+
+ return false;
+}
+
+void
+BreakpointSiteList::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ //s->Indent();
+ s->Printf("BreakpointSiteList with %u BreakpointSites:\n", (uint32_t)m_bp_site_list.size());
+ s->IndentMore();
+ collection::const_iterator pos;
+ collection::const_iterator end = m_bp_site_list.end();
+ for (pos = m_bp_site_list.begin(); pos != end; ++pos)
+ pos->second.get()->Dump(s);
+ s->IndentLess();
+}
+
+void
+BreakpointSiteList::ForEach (std::function <void(BreakpointSite *)> const &callback)
+{
+ Mutex::Locker locker(m_mutex);
+ for (auto pair : m_bp_site_list)
+ callback (pair.second.get());
+}
+
+bool
+BreakpointSiteList::FindInRange (lldb::addr_t lower_bound, lldb::addr_t upper_bound, BreakpointSiteList &bp_site_list) const
+{
+ if (lower_bound > upper_bound)
+ return false;
+
+ Mutex::Locker locker(m_mutex);
+ collection::const_iterator lower, upper, pos;
+ lower = m_bp_site_list.lower_bound(lower_bound);
+ if (lower == m_bp_site_list.end()
+ || (*lower).first >= upper_bound)
+ return false;
+
+ // This is one tricky bit. The breakpoint might overlap the bottom end of the range. So we grab the
+ // breakpoint prior to the lower bound, and check that that + its byte size isn't in our range.
+ if (lower != m_bp_site_list.begin())
+ {
+ collection::const_iterator prev_pos = lower;
+ prev_pos--;
+ const BreakpointSiteSP &prev_bp = (*prev_pos).second;
+ if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
+ bp_site_list.Add (prev_bp);
+
+ }
+
+ upper = m_bp_site_list.upper_bound(upper_bound);
+
+ for (pos = lower; pos != upper; pos++)
+ {
+ bp_site_list.Add ((*pos).second);
+ }
+ return true;
+}
diff --git a/source/Breakpoint/Stoppoint.cpp b/source/Breakpoint/Stoppoint.cpp
new file mode 100644
index 000000000000..583ab47005f5
--- /dev/null
+++ b/source/Breakpoint/Stoppoint.cpp
@@ -0,0 +1,46 @@
+//===-- Stoppoint.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/Breakpoint/Stoppoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Stoppoint constructor
+//----------------------------------------------------------------------
+Stoppoint::Stoppoint() :
+ m_bid (LLDB_INVALID_BREAK_ID)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Stoppoint::~Stoppoint()
+{
+}
+
+break_id_t
+Stoppoint::GetID () const
+{
+ return m_bid;
+}
+
+void
+Stoppoint::SetID (break_id_t bid)
+{
+ m_bid = bid;
+}
diff --git a/source/Breakpoint/StoppointCallbackContext.cpp b/source/Breakpoint/StoppointCallbackContext.cpp
new file mode 100644
index 000000000000..2266c3e429c6
--- /dev/null
+++ b/source/Breakpoint/StoppointCallbackContext.cpp
@@ -0,0 +1,39 @@
+//===-- StoppointCallbackContext.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/Breakpoint/StoppointCallbackContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+StoppointCallbackContext::StoppointCallbackContext() :
+ event (NULL),
+ exe_ctx_ref (),
+ is_synchronous (false)
+{
+}
+
+StoppointCallbackContext::StoppointCallbackContext(Event *e, const ExecutionContext &exe_ctx, bool synchronously) :
+ event (e),
+ exe_ctx_ref (exe_ctx),
+ is_synchronous(synchronously)
+{
+}
+
+void
+StoppointCallbackContext::Clear()
+{
+ event = NULL;
+ exe_ctx_ref.Clear();
+ is_synchronous = false;
+}
diff --git a/source/Breakpoint/StoppointLocation.cpp b/source/Breakpoint/StoppointLocation.cpp
new file mode 100644
index 000000000000..092caa5a9322
--- /dev/null
+++ b/source/Breakpoint/StoppointLocation.cpp
@@ -0,0 +1,48 @@
+//===-- StoppointLocation.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/Breakpoint/StoppointLocation.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StoppointLocation constructor
+//----------------------------------------------------------------------
+StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, bool hardware) :
+ m_loc_id(bid),
+ m_addr(addr),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32),
+ m_byte_size(0),
+ m_hit_count(0)
+{
+}
+
+StoppointLocation::StoppointLocation (break_id_t bid, addr_t addr, uint32_t byte_size, bool hardware) :
+ m_loc_id(bid),
+ m_addr(addr),
+ m_hw_preferred(hardware),
+ m_hw_index(LLDB_INVALID_INDEX32),
+ m_byte_size(byte_size),
+ m_hit_count(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StoppointLocation::~StoppointLocation()
+{
+}
diff --git a/source/Breakpoint/Watchpoint.cpp b/source/Breakpoint/Watchpoint.cpp
new file mode 100644
index 000000000000..45559b1901ad
--- /dev/null
+++ b/source/Breakpoint/Watchpoint.cpp
@@ -0,0 +1,489 @@
+//===-- Watchpoint.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/Breakpoint/Watchpoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Watchpoint::Watchpoint (Target& target, lldb::addr_t addr, uint32_t size, const ClangASTType *type, bool hardware) :
+ StoppointLocation (0, addr, size, hardware),
+ m_target(target),
+ m_enabled(false),
+ m_is_hardware(hardware),
+ m_is_watch_variable(false),
+ m_is_ephemeral(false),
+ m_disabled_count(0),
+ m_watch_read(0),
+ m_watch_write(0),
+ m_watch_was_read(0),
+ m_watch_was_written(0),
+ m_ignore_count(0),
+ m_false_alarms(0),
+ m_decl_str(),
+ m_watch_spec_str(),
+ m_type(),
+ m_error(),
+ m_options (),
+ m_being_created(true)
+{
+ if (type && type->IsValid())
+ m_type = *type;
+ else
+ {
+ // If we don't have a known type, then we force it to unsigned int of the right size.
+ ClangASTContext *ast_context = target.GetScratchClangASTContext();
+ m_type = ast_context->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 8 * size);
+ }
+
+ // Set the initial value of the watched variable:
+ if (m_target.GetProcessSP())
+ {
+ ExecutionContext exe_ctx;
+ m_target.GetProcessSP()->CalculateExecutionContext(exe_ctx);
+ CaptureWatchedValue (exe_ctx);
+ }
+ m_being_created = false;
+}
+
+Watchpoint::~Watchpoint()
+{
+}
+
+// This function is used when "baton" doesn't need to be freed
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, void *baton, bool is_synchronous)
+{
+ // The default "Baton" class will keep a copy of "baton" and won't free
+ // or delete it when it goes goes out of scope.
+ m_options.SetCallback(callback, BatonSP (new Baton(baton)), is_synchronous);
+
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+// This function is used when a baton needs to be freed and therefore is
+// contained in a "Baton" subclass.
+void
+Watchpoint::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool is_synchronous)
+{
+ m_options.SetCallback(callback, callback_baton_sp, is_synchronous);
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+void
+Watchpoint::ClearCallback ()
+{
+ m_options.ClearCallback ();
+ SendWatchpointChangedEvent (eWatchpointEventTypeCommandChanged);
+}
+
+void
+Watchpoint::SetDeclInfo (const std::string &str)
+{
+ m_decl_str = str;
+ return;
+}
+
+std::string
+Watchpoint::GetWatchSpec()
+{
+ return m_watch_spec_str;
+}
+
+void
+Watchpoint::SetWatchSpec (const std::string &str)
+{
+ m_watch_spec_str = str;
+ return;
+}
+
+// Override default impl of StoppointLocation::IsHardware() since m_is_hardware
+// member field is more accurate.
+bool
+Watchpoint::IsHardware () const
+{
+ return m_is_hardware;
+}
+
+bool
+Watchpoint::IsWatchVariable() const
+{
+ return m_is_watch_variable;
+}
+
+void
+Watchpoint::SetWatchVariable(bool val)
+{
+ m_is_watch_variable = val;
+}
+
+bool
+Watchpoint::CaptureWatchedValue (const ExecutionContext &exe_ctx)
+{
+ ConstString watch_name("$__lldb__watch_value");
+ m_old_value_sp = m_new_value_sp;
+ Address watch_address(GetLoadAddress());
+ if (!m_type.IsValid())
+ {
+ // Don't know how to report new & old values, since we couldn't make a scalar type for this watchpoint.
+ // This works around an assert in ValueObjectMemory::Create.
+ // FIXME: This should not happen, but if it does in some case we care about,
+ // we can go grab the value raw and print it as unsigned.
+ return false;
+ }
+ m_new_value_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(), watch_name.AsCString(), watch_address, m_type);
+ m_new_value_sp = m_new_value_sp->CreateConstantValue(watch_name);
+ if (m_new_value_sp && m_new_value_sp->GetError().Success())
+ return true;
+ else
+ return false;
+}
+
+void
+Watchpoint::IncrementFalseAlarmsAndReviseHitCount()
+{
+ ++m_false_alarms;
+ if (m_false_alarms)
+ {
+ if (m_hit_count >= m_false_alarms)
+ {
+ m_hit_count -= m_false_alarms;
+ m_false_alarms = 0;
+ }
+ else
+ {
+ m_false_alarms -= m_hit_count;
+ m_hit_count = 0;
+ }
+ }
+}
+
+// RETURNS - true if we should stop at this breakpoint, false if we
+// should continue.
+
+bool
+Watchpoint::ShouldStop (StoppointCallbackContext *context)
+{
+ IncrementHitCount();
+
+ if (!IsEnabled())
+ return false;
+
+ if (GetHitCount() <= GetIgnoreCount())
+ return false;
+
+ return true;
+}
+
+void
+Watchpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ DumpWithLevel(s, level);
+ return;
+}
+
+void
+Watchpoint::Dump(Stream *s) const
+{
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+// If prefix is NULL, we display the watch id and ignore the prefix altogether.
+void
+Watchpoint::DumpSnapshots(Stream *s, const char *prefix) const
+{
+ if (!prefix)
+ {
+ s->Printf("\nWatchpoint %u hit:", GetID());
+ prefix = "";
+ }
+
+ if (m_old_value_sp)
+ {
+ s->Printf("\n%sold value: %s", prefix, m_old_value_sp->GetValueAsCString());
+ }
+ if (m_new_value_sp)
+ {
+ s->Printf("\n%snew value: %s", prefix, m_new_value_sp->GetValueAsCString());
+ }
+}
+
+void
+Watchpoint::DumpWithLevel(Stream *s, lldb::DescriptionLevel description_level) const
+{
+ if (s == NULL)
+ return;
+
+ assert(description_level >= lldb::eDescriptionLevelBrief &&
+ description_level <= lldb::eDescriptionLevelVerbose);
+
+ s->Printf("Watchpoint %u: addr = 0x%8.8" PRIx64 " size = %u state = %s type = %s%s",
+ GetID(),
+ GetLoadAddress(),
+ m_byte_size,
+ IsEnabled() ? "enabled" : "disabled",
+ m_watch_read ? "r" : "",
+ m_watch_write ? "w" : "");
+
+ if (description_level >= lldb::eDescriptionLevelFull) {
+ if (!m_decl_str.empty())
+ s->Printf("\n declare @ '%s'", m_decl_str.c_str());
+ if (!m_watch_spec_str.empty())
+ s->Printf("\n watchpoint spec = '%s'", m_watch_spec_str.c_str());
+
+ // Dump the snapshots we have taken.
+ DumpSnapshots(s, " ");
+
+ if (GetConditionText())
+ s->Printf("\n condition = '%s'", GetConditionText());
+ m_options.GetCallbackDescription(s, description_level);
+ }
+
+ if (description_level >= lldb::eDescriptionLevelVerbose)
+ {
+ s->Printf("\n hw_index = %i hit_count = %-4u ignore_count = %-4u",
+ GetHardwareIndex(),
+ GetHitCount(),
+ GetIgnoreCount());
+ }
+}
+
+bool
+Watchpoint::IsEnabled() const
+{
+ return m_enabled;
+}
+
+// Within StopInfo.cpp, we purposely turn on the ephemeral mode right before temporarily disable the watchpoint
+// in order to perform possible watchpoint actions without triggering further watchpoint events.
+// After the temporary disabled watchpoint is enabled, we then turn off the ephemeral mode.
+
+void
+Watchpoint::TurnOnEphemeralMode()
+{
+ m_is_ephemeral = true;
+}
+
+void
+Watchpoint::TurnOffEphemeralMode()
+{
+ m_is_ephemeral = false;
+ // Leaving ephemeral mode, reset the m_disabled_count!
+ m_disabled_count = 0;
+}
+
+bool
+Watchpoint::IsDisabledDuringEphemeralMode()
+{
+ return m_disabled_count > 1;
+}
+
+void
+Watchpoint::SetEnabled(bool enabled, bool notify)
+{
+ if (!enabled)
+ {
+ if (!m_is_ephemeral)
+ SetHardwareIndex(LLDB_INVALID_INDEX32);
+ else
+ ++m_disabled_count;
+
+ // Don't clear the snapshots for now.
+ // Within StopInfo.cpp, we purposely do disable/enable watchpoint while performing watchpoint actions.
+ }
+ bool changed = enabled != m_enabled;
+ m_enabled = enabled;
+ if (notify && !m_is_ephemeral && changed)
+ SendWatchpointChangedEvent (enabled ? eWatchpointEventTypeEnabled : eWatchpointEventTypeDisabled);
+}
+
+void
+Watchpoint::SetWatchpointType (uint32_t type, bool notify)
+{
+ int old_watch_read = m_watch_read;
+ int old_watch_write = m_watch_write;
+ m_watch_read = (type & LLDB_WATCH_TYPE_READ) != 0;
+ m_watch_write = (type & LLDB_WATCH_TYPE_WRITE) != 0;
+ if (notify && (old_watch_read != m_watch_read || old_watch_write != m_watch_write))
+ SendWatchpointChangedEvent (eWatchpointEventTypeTypeChanged);
+}
+
+bool
+Watchpoint::WatchpointRead () const
+{
+ return m_watch_read != 0;
+}
+bool
+Watchpoint::WatchpointWrite () const
+{
+ return m_watch_write != 0;
+}
+uint32_t
+Watchpoint::GetIgnoreCount () const
+{
+ return m_ignore_count;
+}
+
+void
+Watchpoint::SetIgnoreCount (uint32_t n)
+{
+ bool changed = m_ignore_count != n;
+ m_ignore_count = n;
+ if (changed)
+ SendWatchpointChangedEvent (eWatchpointEventTypeIgnoreChanged);
+}
+
+bool
+Watchpoint::InvokeCallback (StoppointCallbackContext *context)
+{
+ return m_options.InvokeCallback (context, GetID());
+}
+
+void
+Watchpoint::SetCondition (const char *condition)
+{
+ if (condition == NULL || condition[0] == '\0')
+ {
+ if (m_condition_ap.get())
+ m_condition_ap.reset();
+ }
+ else
+ {
+ // Pass NULL for expr_prefix (no translation-unit level definitions).
+ m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
+ }
+ SendWatchpointChangedEvent (eWatchpointEventTypeConditionChanged);
+}
+
+const char *
+Watchpoint::GetConditionText () const
+{
+ if (m_condition_ap.get())
+ return m_condition_ap->GetUserText();
+ else
+ return NULL;
+}
+
+void
+Watchpoint::SendWatchpointChangedEvent (lldb::WatchpointEventType eventKind)
+{
+ if (!m_being_created
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ {
+ WatchpointEventData *data = new Watchpoint::WatchpointEventData (eventKind, shared_from_this());
+ GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
+ }
+}
+
+void
+Watchpoint::SendWatchpointChangedEvent (WatchpointEventData *data)
+{
+
+ if (data == NULL)
+ return;
+
+ if (!m_being_created
+ && GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged, data);
+ else
+ delete data;
+}
+
+Watchpoint::WatchpointEventData::WatchpointEventData (WatchpointEventType sub_type,
+ const WatchpointSP &new_watchpoint_sp) :
+ EventData (),
+ m_watchpoint_event (sub_type),
+ m_new_watchpoint_sp (new_watchpoint_sp)
+{
+}
+
+Watchpoint::WatchpointEventData::~WatchpointEventData ()
+{
+}
+
+const ConstString &
+Watchpoint::WatchpointEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Watchpoint::WatchpointEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Watchpoint::WatchpointEventData::GetFlavor () const
+{
+ return WatchpointEventData::GetFlavorString ();
+}
+
+
+WatchpointSP &
+Watchpoint::WatchpointEventData::GetWatchpoint ()
+{
+ return m_new_watchpoint_sp;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventType () const
+{
+ return m_watchpoint_event;
+}
+
+void
+Watchpoint::WatchpointEventData::Dump (Stream *s) const
+{
+}
+
+const Watchpoint::WatchpointEventData *
+Watchpoint::WatchpointEventData::GetEventDataFromEvent (const Event *event)
+{
+ if (event)
+ {
+ const EventData *event_data = event->GetData();
+ if (event_data && event_data->GetFlavor() == WatchpointEventData::GetFlavorString())
+ return static_cast <const WatchpointEventData *> (event->GetData());
+ }
+ return NULL;
+}
+
+WatchpointEventType
+Watchpoint::WatchpointEventData::GetWatchpointEventTypeFromEvent (const EventSP &event_sp)
+{
+ const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
+
+ if (data == NULL)
+ return eWatchpointEventTypeInvalidType;
+ else
+ return data->GetWatchpointEventType();
+}
+
+WatchpointSP
+Watchpoint::WatchpointEventData::GetWatchpointFromEvent (const EventSP &event_sp)
+{
+ WatchpointSP wp_sp;
+
+ const WatchpointEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ wp_sp = data->m_new_watchpoint_sp;
+
+ return wp_sp;
+}
diff --git a/source/Breakpoint/WatchpointList.cpp b/source/Breakpoint/WatchpointList.cpp
new file mode 100644
index 000000000000..6d62dffd22cc
--- /dev/null
+++ b/source/Breakpoint/WatchpointList.cpp
@@ -0,0 +1,306 @@
+//===-- WatchpointList.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/Breakpoint/WatchpointList.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+WatchpointList::WatchpointList() :
+ m_watchpoints (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_next_wp_id (0)
+{
+}
+
+WatchpointList::~WatchpointList()
+{
+}
+
+// Add a watchpoint to the list.
+lldb::watch_id_t
+WatchpointList::Add (const WatchpointSP &wp_sp, bool notify)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_sp->SetID(++m_next_wp_id);
+ m_watchpoints.push_back(wp_sp);
+ if (notify)
+ {
+ if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeAdded, wp_sp));
+ }
+ return wp_sp->GetID();
+}
+
+void
+WatchpointList::Dump (Stream *s) const
+{
+ DumpWithLevel(s, lldb::eDescriptionLevelBrief);
+}
+
+void
+WatchpointList::DumpWithLevel (Stream *s, lldb::DescriptionLevel description_level) const
+{
+ Mutex::Locker locker (m_mutex);
+ s->Printf("%p: ", this);
+ //s->Indent();
+ s->Printf("WatchpointList with %" PRIu64 " Watchpoints:\n",
+ (uint64_t)m_watchpoints.size());
+ s->IndentMore();
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->DumpWithLevel(s, description_level);
+ s->IndentLess();
+}
+
+const WatchpointSP
+WatchpointList::FindByAddress (lldb::addr_t addr) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ if (!m_watchpoints.empty())
+ {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ if ((*pos)->GetLoadAddress() == addr) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+
+ return wp_sp;
+}
+
+const WatchpointSP
+WatchpointList::FindBySpec (std::string spec) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ if (!m_watchpoints.empty())
+ {
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ if ((*pos)->GetWatchSpec() == spec) {
+ wp_sp = *pos;
+ break;
+ }
+ }
+
+ return wp_sp;
+}
+
+class WatchpointIDMatches
+{
+public:
+ WatchpointIDMatches (lldb::watch_id_t watch_id) :
+ m_watch_id(watch_id)
+ {
+ }
+
+ bool operator() (const WatchpointSP &wp) const
+ {
+ return m_watch_id == wp->GetID();
+ }
+
+private:
+ const lldb::watch_id_t m_watch_id;
+};
+
+WatchpointList::wp_collection::iterator
+WatchpointList::GetIDIterator (lldb::watch_id_t watch_id)
+{
+ return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointList::wp_collection::const_iterator
+WatchpointList::GetIDConstIterator (lldb::watch_id_t watch_id) const
+{
+ return std::find_if(m_watchpoints.begin(), m_watchpoints.end(), // Search full range
+ WatchpointIDMatches(watch_id)); // Predicate
+}
+
+WatchpointSP
+WatchpointList::FindByID (lldb::watch_id_t watch_id) const
+{
+ WatchpointSP wp_sp;
+ Mutex::Locker locker (m_mutex);
+ wp_collection::const_iterator pos = GetIDConstIterator(watch_id);
+ if (pos != m_watchpoints.end())
+ wp_sp = *pos;
+
+ return wp_sp;
+}
+
+lldb::watch_id_t
+WatchpointList::FindIDByAddress (lldb::addr_t addr)
+{
+ WatchpointSP wp_sp = FindByAddress (addr);
+ if (wp_sp)
+ {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+lldb::watch_id_t
+WatchpointList::FindIDBySpec (std::string spec)
+{
+ WatchpointSP wp_sp = FindBySpec (spec);
+ if (wp_sp)
+ {
+ return wp_sp->GetID();
+ }
+ return LLDB_INVALID_WATCH_ID;
+}
+
+WatchpointSP
+WatchpointList::GetByIndex (uint32_t i)
+{
+ Mutex::Locker locker (m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size())
+ {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+const WatchpointSP
+WatchpointList::GetByIndex (uint32_t i) const
+{
+ Mutex::Locker locker (m_mutex);
+ WatchpointSP wp_sp;
+ if (i < m_watchpoints.size())
+ {
+ wp_collection::const_iterator pos = m_watchpoints.begin();
+ std::advance(pos, i);
+ wp_sp = *pos;
+ }
+ return wp_sp;
+}
+
+std::vector<lldb::watch_id_t>
+WatchpointList::GetWatchpointIDs() const
+{
+ std::vector<lldb::watch_id_t> IDs;
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ IDs.push_back((*pos)->GetID());
+ return IDs;
+}
+
+bool
+WatchpointList::Remove (lldb::watch_id_t watch_id, bool notify)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_collection::iterator pos = GetIDIterator(watch_id);
+ if (pos != m_watchpoints.end())
+ {
+ WatchpointSP wp_sp = *pos;
+ if (notify)
+ {
+ if (wp_sp->GetTarget().EventTypeHasListeners(Target::eBroadcastBitWatchpointChanged))
+ wp_sp->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved, wp_sp));
+ }
+ m_watchpoints.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+WatchpointList::GetHitCount () const
+{
+ uint32_t hit_count = 0;
+ Mutex::Locker locker (m_mutex);
+ wp_collection::const_iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ hit_count += (*pos)->GetHitCount();
+ return hit_count;
+}
+
+bool
+WatchpointList::ShouldStop (StoppointCallbackContext *context, lldb::watch_id_t watch_id)
+{
+
+ WatchpointSP wp_sp = FindByID (watch_id);
+ if (wp_sp)
+ {
+ // Let the Watchpoint decide if it should stop here (could not have
+ // reached it's target hit count yet, or it could have a callback
+ // that decided it shouldn't stop.
+ return wp_sp->ShouldStop (context);
+ }
+ // We should stop here since this Watchpoint isn't valid anymore or it
+ // doesn't exist.
+ return true;
+}
+
+void
+WatchpointList::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+ wp_collection::iterator pos, end = m_watchpoints.end();
+
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ {
+ s->Printf(" ");
+ (*pos)->Dump(s);
+ }
+}
+
+void
+WatchpointList::SetEnabledAll (bool enabled)
+{
+ Mutex::Locker locker(m_mutex);
+
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ (*pos)->SetEnabled (enabled);
+}
+
+void
+WatchpointList::RemoveAll (bool notify)
+{
+ Mutex::Locker locker(m_mutex);
+ if (notify)
+ {
+
+ {
+ wp_collection::iterator pos, end = m_watchpoints.end();
+ for (pos = m_watchpoints.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetTarget().EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged))
+ {
+ (*pos)->GetTarget().BroadcastEvent (Target::eBroadcastBitWatchpointChanged,
+ new Watchpoint::WatchpointEventData (eWatchpointEventTypeRemoved,
+ *pos));
+ }
+ }
+ }
+ }
+ m_watchpoints.clear();
+}
+
+void
+WatchpointList::GetListMutex (Mutex::Locker &locker)
+{
+ return locker.Lock (m_mutex);
+}
diff --git a/source/Breakpoint/WatchpointOptions.cpp b/source/Breakpoint/WatchpointOptions.cpp
new file mode 100644
index 000000000000..c2c9696c4ce7
--- /dev/null
+++ b/source/Breakpoint/WatchpointOptions.cpp
@@ -0,0 +1,241 @@
+//===-- WatchpointOptions.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/Breakpoint/WatchpointOptions.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Expression/ClangUserExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+WatchpointOptions::NullCallback (void *baton, StoppointCallbackContext *context, lldb::user_id_t watch_id)
+{
+ return true;
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions() :
+ m_callback (WatchpointOptions::NullCallback),
+ m_callback_baton_sp (),
+ m_callback_is_synchronous (false),
+ m_thread_spec_ap ()
+{
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions copy constructor
+//----------------------------------------------------------------------
+WatchpointOptions::WatchpointOptions(const WatchpointOptions& rhs) :
+ m_callback (rhs.m_callback),
+ m_callback_baton_sp (rhs.m_callback_baton_sp),
+ m_callback_is_synchronous (rhs.m_callback_is_synchronous),
+ m_thread_spec_ap ()
+{
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+}
+
+//----------------------------------------------------------------------
+// WatchpointOptions assignment operator
+//----------------------------------------------------------------------
+const WatchpointOptions&
+WatchpointOptions::operator=(const WatchpointOptions& rhs)
+{
+ m_callback = rhs.m_callback;
+ m_callback_baton_sp = rhs.m_callback_baton_sp;
+ m_callback_is_synchronous = rhs.m_callback_is_synchronous;
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+ return *this;
+}
+
+WatchpointOptions *
+WatchpointOptions::CopyOptionsNoCallback (WatchpointOptions &orig)
+{
+ WatchpointHitCallback orig_callback = orig.m_callback;
+ lldb::BatonSP orig_callback_baton_sp = orig.m_callback_baton_sp;
+ bool orig_is_sync = orig.m_callback_is_synchronous;
+
+ orig.ClearCallback();
+ WatchpointOptions *ret_val = new WatchpointOptions(orig);
+
+ orig.SetCallback (orig_callback, orig_callback_baton_sp, orig_is_sync);
+
+ return ret_val;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+WatchpointOptions::~WatchpointOptions()
+{
+}
+
+//------------------------------------------------------------------
+// Callbacks
+//------------------------------------------------------------------
+void
+WatchpointOptions::SetCallback (WatchpointHitCallback callback, const BatonSP &callback_baton_sp, bool callback_is_synchronous)
+{
+ m_callback_is_synchronous = callback_is_synchronous;
+ m_callback = callback;
+ m_callback_baton_sp = callback_baton_sp;
+}
+
+void
+WatchpointOptions::ClearCallback ()
+{
+ m_callback = WatchpointOptions::NullCallback;
+ m_callback_is_synchronous = false;
+ m_callback_baton_sp.reset();
+}
+
+Baton *
+WatchpointOptions::GetBaton ()
+{
+ return m_callback_baton_sp.get();
+}
+
+const Baton *
+WatchpointOptions::GetBaton () const
+{
+ return m_callback_baton_sp.get();
+}
+
+bool
+WatchpointOptions::InvokeCallback (StoppointCallbackContext *context,
+ lldb::user_id_t watch_id)
+{
+ if (m_callback && context->is_synchronous == IsCallbackSynchronous())
+ {
+ return m_callback (m_callback_baton_sp ? m_callback_baton_sp->m_data : NULL,
+ context,
+ watch_id);
+ }
+ else
+ return true;
+}
+
+bool
+WatchpointOptions::HasCallback ()
+{
+ return m_callback != WatchpointOptions::NullCallback;
+}
+
+const ThreadSpec *
+WatchpointOptions::GetThreadSpecNoCreate () const
+{
+ return m_thread_spec_ap.get();
+}
+
+ThreadSpec *
+WatchpointOptions::GetThreadSpec ()
+{
+ if (m_thread_spec_ap.get() == NULL)
+ m_thread_spec_ap.reset (new ThreadSpec());
+
+ return m_thread_spec_ap.get();
+}
+
+void
+WatchpointOptions::SetThreadID (lldb::tid_t thread_id)
+{
+ GetThreadSpec()->SetTID(thread_id);
+}
+
+void
+WatchpointOptions::GetCallbackDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ if (m_callback_baton_sp.get())
+ {
+ s->EOL();
+ m_callback_baton_sp->GetDescription (s, level);
+ }
+}
+void
+WatchpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+
+ // Figure out if there are any options not at their default value, and only print
+ // anything if there are:
+
+ if ((GetThreadSpecNoCreate() != NULL && GetThreadSpecNoCreate()->HasSpecification ()))
+ {
+ if (level == lldb::eDescriptionLevelVerbose)
+ {
+ s->EOL ();
+ s->IndentMore();
+ s->Indent();
+ s->PutCString("Watchpoint Options:\n");
+ s->IndentMore();
+ s->Indent();
+ }
+ else
+ s->PutCString(" Options: ");
+
+ 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();
+ s->IndentMore();
+ }
+ }
+
+ GetCallbackDescription(s, level);
+}
+
+void
+WatchpointOptions::CommandBaton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ CommandData *data = (CommandData *)m_data;
+
+ if (level == eDescriptionLevelBrief)
+ {
+ s->Printf (", commands = %s", (data && data->user_source.GetSize() > 0) ? "yes" : "no");
+ return;
+ }
+
+ s->IndentMore ();
+ s->Indent("watchpoint commands:\n");
+
+ s->IndentMore ();
+ if (data && data->user_source.GetSize() > 0)
+ {
+ const size_t num_strings = data->user_source.GetSize();
+ for (size_t i = 0; i < num_strings; ++i)
+ {
+ s->Indent(data->user_source.GetStringAtIndex(i));
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString ("No commands.\n");
+ }
+ s->IndentLess ();
+ s->IndentLess ();
+}
+
diff --git a/source/Commands/CommandCompletions.cpp b/source/Commands/CommandCompletions.cpp
new file mode 100644
index 000000000000..a9d2f21b9bac
--- /dev/null
+++ b/source/Commands/CommandCompletions.cpp
@@ -0,0 +1,754 @@
+//===-- CommandCompletions.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"
+
+// C Includes
+#include <sys/stat.h>
+#include <dirent.h>
+#if defined(__APPLE__) || defined(__linux__)
+#include <pwd.h>
+#endif
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/CleanUp.h"
+
+using namespace lldb_private;
+
+CommandCompletions::CommonCompletionElement
+CommandCompletions::g_common_completions[] =
+{
+ {eCustomCompletion, NULL},
+ {eSourceFileCompletion, CommandCompletions::SourceFiles},
+ {eDiskFileCompletion, CommandCompletions::DiskFiles},
+ {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
+ {eSymbolCompletion, CommandCompletions::Symbols},
+ {eModuleCompletion, CommandCompletions::Modules},
+ {eSettingsNameCompletion, CommandCompletions::SettingsNames},
+ {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
+ {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
+ {eVariablePathCompletion, CommandCompletions::VariablePath},
+ {eNoCompletion, NULL} // This one has to be last in the list.
+};
+
+bool
+CommandCompletions::InvokeCommonCompletionCallbacks
+(
+ CommandInterpreter &interpreter,
+ uint32_t completion_mask,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ bool handled = false;
+
+ if (completion_mask & eCustomCompletion)
+ return false;
+
+ for (int i = 0; ; i++)
+ {
+ if (g_common_completions[i].type == eNoCompletion)
+ break;
+ else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
+ && g_common_completions[i].callback != NULL)
+ {
+ handled = true;
+ g_common_completions[i].callback (interpreter,
+ completion_str,
+ match_start_point,
+ max_return_elements,
+ searcher,
+ word_complete,
+ matches);
+ }
+ }
+ return handled;
+}
+
+int
+CommandCompletions::SourceFiles
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ word_complete = true;
+ // Find some way to switch "include support files..."
+ SourceFileCompleter completer (interpreter,
+ false,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+static int
+DiskFilesOrDirectories
+(
+ const char *partial_file_name,
+ bool only_directories,
+ bool &saw_directory,
+ StringList &matches
+)
+{
+ // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
+ // If it is not defined on your host system, you'll need to implement it yourself...
+
+ size_t partial_name_len = strlen(partial_file_name);
+
+ if (partial_name_len >= PATH_MAX)
+ return matches.GetSize();
+
+ // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
+ // below will point to the place of the remainder in this string. Then when we've resolved the
+ // containing directory, and opened it, we'll read the directory contents and overwrite the
+ // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
+ // the form the user originally typed.
+
+ char partial_name_copy[PATH_MAX];
+ memcpy(partial_name_copy, partial_file_name, partial_name_len);
+ partial_name_copy[partial_name_len] = '\0';
+
+ // We'll need to save a copy of the remainder for comparison, which we do here.
+ char remainder[PATH_MAX];
+
+ // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
+ char *end_ptr;
+
+ end_ptr = strrchr(partial_name_copy, '/');
+
+ // This will store the resolved form of the containing directory
+ char containing_part[PATH_MAX];
+
+ if (end_ptr == NULL)
+ {
+ // There's no directory. If the thing begins with a "~" then this is a bare
+ // user name.
+ if (*partial_name_copy == '~')
+ {
+ // Nothing here but the user name. We could just put a slash on the end,
+ // but for completeness sake we'll resolve the user name and only put a slash
+ // on the end if it exists.
+ char resolved_username[PATH_MAX];
+ size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
+ sizeof (resolved_username));
+
+ // Not sure how this would happen, a username longer than PATH_MAX? Still...
+ if (resolved_username_len >= sizeof (resolved_username))
+ return matches.GetSize();
+ else if (resolved_username_len == 0)
+ {
+ // The user name didn't resolve, let's look in the password database for matches.
+ // The user name database contains duplicates, and is not in alphabetical order, so
+ // we'll use a set to manage that for us.
+ FileSpec::ResolvePartialUsername (partial_name_copy, matches);
+ if (matches.GetSize() > 0)
+ saw_directory = true;
+ return matches.GetSize();
+ }
+ else
+ {
+ //The thing exists, put a '/' on the end, and return it...
+ // FIXME: complete user names here:
+ partial_name_copy[partial_name_len] = '/';
+ partial_name_copy[partial_name_len+1] = '\0';
+ matches.AppendString(partial_name_copy);
+ saw_directory = true;
+ return matches.GetSize();
+ }
+ }
+ else
+ {
+ // The containing part is the CWD, and the whole string is the remainder.
+ containing_part[0] = '.';
+ containing_part[1] = '\0';
+ strcpy(remainder, partial_name_copy);
+ end_ptr = partial_name_copy;
+ }
+ }
+ else
+ {
+ if (end_ptr == partial_name_copy)
+ {
+ // We're completing a file or directory in the root volume.
+ containing_part[0] = '/';
+ containing_part[1] = '\0';
+ }
+ else
+ {
+ size_t len = end_ptr - partial_name_copy;
+ memcpy(containing_part, partial_name_copy, len);
+ containing_part[len] = '\0';
+ }
+ // Push end_ptr past the final "/" and set remainder.
+ end_ptr++;
+ strcpy(remainder, end_ptr);
+ }
+
+ // Look for a user name in the containing part, and if it's there, resolve it and stick the
+ // result back into the containing_part:
+
+ if (*partial_name_copy == '~')
+ {
+ size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
+ containing_part,
+ sizeof (containing_part));
+ // User name doesn't exist, we're not getting any further...
+ if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
+ return matches.GetSize();
+ }
+
+ // Okay, containing_part is now the directory we want to open and look for files:
+
+ lldb_utility::CleanUp <DIR *, int> dir_stream (opendir(containing_part), NULL, closedir);
+ if (!dir_stream.is_valid())
+ return matches.GetSize();
+
+ struct dirent *dirent_buf;
+
+ size_t baselen = end_ptr - partial_name_copy;
+
+ while ((dirent_buf = readdir(dir_stream.get())) != NULL)
+ {
+ char *name = dirent_buf->d_name;
+
+ // Omit ".", ".." and any . files if the match string doesn't start with .
+ if (name[0] == '.')
+ {
+ if (name[1] == '\0')
+ continue;
+ else if (name[1] == '.' && name[2] == '\0')
+ continue;
+ else if (remainder[0] != '.')
+ continue;
+ }
+
+ // If we found a directory, we put a "/" at the end of the name.
+
+ if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name)
+ {
+ if (strlen(name) + baselen >= PATH_MAX)
+ continue;
+
+ strcpy(end_ptr, name);
+
+ bool isa_directory = false;
+ if (dirent_buf->d_type & DT_DIR)
+ isa_directory = true;
+ else if (dirent_buf->d_type & DT_LNK)
+ {
+ struct stat stat_buf;
+ if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
+ isa_directory = true;
+ }
+
+ if (isa_directory)
+ {
+ saw_directory = true;
+ size_t len = strlen(partial_name_copy);
+ partial_name_copy[len] = '/';
+ partial_name_copy[len + 1] = '\0';
+ }
+ if (only_directories && !isa_directory)
+ continue;
+ matches.AppendString(partial_name_copy);
+ }
+ }
+
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::DiskFiles
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+
+ int ret_val = DiskFilesOrDirectories (partial_file_name,
+ false,
+ word_complete,
+ matches);
+ word_complete = !word_complete;
+ return ret_val;
+}
+
+int
+CommandCompletions::DiskDirectories
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ int ret_val = DiskFilesOrDirectories (partial_file_name,
+ true,
+ word_complete,
+ matches);
+ word_complete = false;
+ return ret_val;
+}
+
+int
+CommandCompletions::Modules
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ word_complete = true;
+ ModuleCompleter completer (interpreter,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::Symbols
+(
+ CommandInterpreter &interpreter,
+ const char *partial_file_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = true;
+ SymbolCompleter completer (interpreter,
+ partial_file_name,
+ match_start_point,
+ max_return_elements,
+ matches);
+
+ if (searcher == NULL)
+ {
+ lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
+ SearchFilter null_searcher (target_sp);
+ completer.DoCompletion (&null_searcher);
+ }
+ else
+ {
+ completer.DoCompletion (searcher);
+ }
+ return matches.GetSize();
+}
+
+int
+CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
+ const char *partial_setting_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ StringList &matches)
+{
+ // Cache the full setting name list
+ static StringList g_property_names;
+ if (g_property_names.GetSize() == 0)
+ {
+ // Generate the full setting name list on demand
+ lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
+ if (properties_sp)
+ {
+ StreamString strm;
+ properties_sp->DumpValue(NULL, strm, OptionValue::eDumpOptionName);
+ const std::string &str = strm.GetString();
+ g_property_names.SplitIntoLines(str.c_str(), str.size());
+ }
+ }
+
+ size_t exact_matches_idx = SIZE_MAX;
+ const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
+ word_complete = exact_matches_idx != SIZE_MAX;
+ return num_matches;
+}
+
+
+int
+CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
+ word_complete = num_matches == 1;
+ return num_matches;
+}
+
+int
+CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
+ word_complete = num_matches == 1;
+ return num_matches;
+}
+
+
+int
+CommandCompletions::VariablePath (CommandInterpreter &interpreter,
+ const char *partial_name,
+ int match_start_point,
+ int max_return_elements,
+ SearchFilter *searcher,
+ bool &word_complete,
+ lldb_private::StringList &matches)
+{
+ return Variable::AutoComplete (interpreter.GetExecutionContext(), partial_name, matches, word_complete);
+}
+
+
+CommandCompletions::Completer::Completer
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ m_interpreter (interpreter),
+ m_completion_str (completion_str),
+ m_match_start_point (match_start_point),
+ m_max_return_elements (max_return_elements),
+ m_matches (matches)
+{
+}
+
+CommandCompletions::Completer::~Completer ()
+{
+
+}
+
+//----------------------------------------------------------------------
+// SourceFileCompleter
+//----------------------------------------------------------------------
+
+CommandCompletions::SourceFileCompleter::SourceFileCompleter
+(
+ CommandInterpreter &interpreter,
+ bool include_support_files,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
+ m_include_support_files (include_support_files),
+ m_matching_files()
+{
+ FileSpec partial_spec (m_completion_str.c_str(), false);
+ m_file_name = partial_spec.GetFilename().GetCString();
+ m_dir_name = partial_spec.GetDirectory().GetCString();
+}
+
+Searcher::Depth
+CommandCompletions::SourceFileCompleter::GetDepth()
+{
+ return eDepthCompUnit;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::SourceFileCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.comp_unit != NULL)
+ {
+ if (m_include_support_files)
+ {
+ FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
+ for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
+ {
+ const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
+ const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
+ const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
+ bool match = false;
+ if (m_file_name && sfile_file_name
+ && strstr (sfile_file_name, m_file_name) == sfile_file_name)
+ match = true;
+ if (match && m_dir_name && sfile_dir_name
+ && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matching_files.AppendIfUnique(sfile_spec);
+ }
+ }
+
+ }
+ else
+ {
+ const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
+ const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
+
+ bool match = false;
+ if (m_file_name && cur_file_name
+ && strstr (cur_file_name, m_file_name) == cur_file_name)
+ match = true;
+
+ if (match && m_dir_name && cur_dir_name
+ && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matching_files.AppendIfUnique(context.comp_unit);
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ // Now convert the filelist to completions:
+ for (size_t i = 0; i < m_matching_files.GetSize(); i++)
+ {
+ m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
+ }
+ return m_matches.GetSize();
+
+}
+
+//----------------------------------------------------------------------
+// SymbolCompleter
+//----------------------------------------------------------------------
+
+static bool
+regex_chars (const char comp)
+{
+ if (comp == '[' || comp == ']' ||
+ comp == '(' || comp == ')' ||
+ comp == '{' || comp == '}' ||
+ comp == '+' ||
+ comp == '.' ||
+ comp == '*' ||
+ comp == '|' ||
+ comp == '^' ||
+ comp == '$' ||
+ comp == '\\' ||
+ comp == '?')
+ return true;
+ else
+ return false;
+}
+CommandCompletions::SymbolCompleter::SymbolCompleter
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
+{
+ std::string regex_str;
+ if (completion_str && completion_str[0])
+ {
+ regex_str.append("^");
+ regex_str.append(completion_str);
+ }
+ else
+ {
+ // Match anything since the completion string is empty
+ regex_str.append(".");
+ }
+ std::string::iterator pos = find_if(regex_str.begin() + 1, regex_str.end(), regex_chars);
+ while (pos < regex_str.end())
+ {
+ pos = regex_str.insert(pos, '\\');
+ pos = find_if(pos + 2, regex_str.end(), regex_chars);
+ }
+ m_regex.Compile(regex_str.c_str());
+}
+
+Searcher::Depth
+CommandCompletions::SymbolCompleter::GetDepth()
+{
+ return eDepthModule;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::SymbolCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.module_sp)
+ {
+ SymbolContextList sc_list;
+ const bool include_symbols = true;
+ const bool include_inlines = true;
+ const bool append = true;
+ context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
+
+ SymbolContext sc;
+ // Now add the functions & symbols to the list - only add if unique:
+ for (uint32_t i = 0; i < sc_list.GetSize(); i++)
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
+ if (!func_name.IsEmpty())
+ m_match_set.insert (func_name);
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
+ for (pos = m_match_set.begin(); pos != end; pos++)
+ m_matches.AppendString((*pos).GetCString());
+
+ return m_matches.GetSize();
+}
+
+//----------------------------------------------------------------------
+// ModuleCompleter
+//----------------------------------------------------------------------
+CommandCompletions::ModuleCompleter::ModuleCompleter
+(
+ CommandInterpreter &interpreter,
+ const char *completion_str,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches
+) :
+ CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
+{
+ FileSpec partial_spec (m_completion_str.c_str(), false);
+ m_file_name = partial_spec.GetFilename().GetCString();
+ m_dir_name = partial_spec.GetDirectory().GetCString();
+}
+
+Searcher::Depth
+CommandCompletions::ModuleCompleter::GetDepth()
+{
+ return eDepthModule;
+}
+
+Searcher::CallbackReturn
+CommandCompletions::ModuleCompleter::SearchCallback (
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool complete
+)
+{
+ if (context.module_sp)
+ {
+ const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
+ const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
+
+ bool match = false;
+ if (m_file_name && cur_file_name
+ && strstr (cur_file_name, m_file_name) == cur_file_name)
+ match = true;
+
+ if (match && m_dir_name && cur_dir_name
+ && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
+ match = false;
+
+ if (match)
+ {
+ m_matches.AppendString (cur_file_name);
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+size_t
+CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
+{
+ filter->Search (*this);
+ return m_matches.GetSize();
+}
diff --git a/source/Commands/CommandObjectApropos.cpp b/source/Commands/CommandObjectApropos.cpp
new file mode 100644
index 000000000000..02dc7269775d
--- /dev/null
+++ b/source/Commands/CommandObjectApropos.cpp
@@ -0,0 +1,154 @@
+//===-- CommandObjectApropos.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 "CommandObjectApropos.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectApropos
+//-------------------------------------------------------------------------
+
+CommandObjectApropos::CommandObjectApropos (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "apropos",
+ "Find a list of debugger commands related to a particular word/subject.",
+ NULL)
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData search_word_arg;
+
+ // Define the first (and only) variant of this arg.
+ search_word_arg.arg_type = eArgTypeSearchWord;
+ search_word_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (search_word_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectApropos::~CommandObjectApropos()
+{
+}
+
+
+bool
+CommandObjectApropos::DoExecute (Args& args, CommandReturnObject &result)
+{
+ const size_t argc = args.GetArgumentCount ();
+
+ if (argc == 1)
+ {
+ const char *search_word = args.GetArgumentAtIndex(0);
+ if ((search_word != NULL)
+ && (strlen (search_word) > 0))
+ {
+ // The bulk of the work must be done inside the Command Interpreter, since the command dictionary
+ // is private.
+ StringList commands_found;
+ StringList commands_help;
+ StringList user_commands_found;
+ StringList user_commands_help;
+
+ m_interpreter.FindCommandsForApropos (search_word, commands_found, commands_help, true, false);
+ m_interpreter.FindCommandsForApropos (search_word, user_commands_found, user_commands_help, false, true);
+
+ if (commands_found.GetSize() == 0 && user_commands_found.GetSize() == 0)
+ {
+ result.AppendMessageWithFormat ("No commands found pertaining to '%s'. Try 'help' to see a complete list of debugger commands.\n", search_word);
+ }
+ else
+ {
+ if (commands_found.GetSize() > 0)
+ {
+ result.AppendMessageWithFormat ("The following built-in commands may relate to '%s':\n", search_word);
+ size_t max_len = 0;
+
+ for (size_t i = 0; i < commands_found.GetSize(); ++i)
+ {
+ size_t len = strlen (commands_found.GetStringAtIndex (i));
+ if (len > max_len)
+ max_len = len;
+ }
+
+ for (size_t i = 0; i < commands_found.GetSize(); ++i)
+ m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
+ commands_found.GetStringAtIndex(i),
+ "--",
+ commands_help.GetStringAtIndex(i),
+ max_len);
+ if (user_commands_found.GetSize() > 0)
+ result.AppendMessage("");
+ }
+
+ if (user_commands_found.GetSize() > 0)
+ {
+ result.AppendMessageWithFormat ("The following user commands may relate to '%s':\n", search_word);
+ size_t max_len = 0;
+
+ for (size_t i = 0; i < user_commands_found.GetSize(); ++i)
+ {
+ size_t len = strlen (user_commands_found.GetStringAtIndex (i));
+ if (len > max_len)
+ max_len = len;
+ }
+
+ for (size_t i = 0; i < user_commands_found.GetSize(); ++i)
+ m_interpreter.OutputFormattedHelpText (result.GetOutputStream(),
+ user_commands_found.GetStringAtIndex(i),
+ "--",
+ user_commands_help.GetStringAtIndex(i),
+ max_len);
+ }
+
+ }
+
+
+ std::vector<const Property *> properties;
+ const size_t num_properties = m_interpreter.GetDebugger().Apropos(search_word, properties);
+ if (num_properties)
+ {
+ const bool dump_qualified_name = true;
+ result.AppendMessageWithFormat ("\nThe following settings variables may relate to '%s': \n\n", search_word);
+ for (size_t i=0; i<num_properties; ++i)
+ properties[i]->DumpDescription (m_interpreter, result.GetOutputStream(), 0, dump_qualified_name);
+
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("'' is not a valid search word.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("'apropos' must be called with exactly one argument.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
diff --git a/source/Commands/CommandObjectApropos.h b/source/Commands/CommandObjectApropos.h
new file mode 100644
index 000000000000..f5154177bb29
--- /dev/null
+++ b/source/Commands/CommandObjectApropos.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectApropos.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_CommandObjectApropos_h_
+#define liblldb_CommandObjectApropos_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectApropos
+//-------------------------------------------------------------------------
+
+class CommandObjectApropos : public CommandObjectParsed
+{
+public:
+
+ CommandObjectApropos (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectApropos ();
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectApropos_h_
diff --git a/source/Commands/CommandObjectArgs.cpp b/source/Commands/CommandObjectArgs.cpp
new file mode 100644
index 000000000000..05fd53bbe89a
--- /dev/null
+++ b/source/Commands/CommandObjectArgs.cpp
@@ -0,0 +1,272 @@
+//===-- CommandObjectArgs.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 "CommandObjectArgs.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// This command is a toy. I'm just using it to have a way to construct the arguments to
+// calling functions.
+//
+
+CommandObjectArgs::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+{
+ // Keep only one place to reset the values to their defaults
+ OptionParsingStarting();
+}
+
+
+CommandObjectArgs::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectArgs::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectArgs::CommandOptions::OptionParsingStarting ()
+{
+}
+
+const OptionDefinition*
+CommandObjectArgs::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectArgs::CommandObjectArgs (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "args",
+ "When stopped at the start of a function, reads function arguments of type (u?)int(8|16|32|64)_t, (void|char)*",
+ "args"),
+ m_options (interpreter)
+{
+}
+
+CommandObjectArgs::~CommandObjectArgs ()
+{
+}
+
+Options *
+CommandObjectArgs::GetOptions ()
+{
+ return &m_options;
+}
+
+bool
+CommandObjectArgs::DoExecute (Args& args, CommandReturnObject &result)
+{
+ ConstString target_triple;
+
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (!process)
+ {
+ result.AppendError ("Args found no process.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const ABI *abi = process->GetABI().get();
+ if (!abi)
+ {
+ result.AppendError ("The current process has no ABI.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const size_t num_args = args.GetArgumentCount ();
+ size_t arg_index;
+
+ if (!num_args)
+ {
+ result.AppendError ("args requires at least one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+
+ if (!thread)
+ {
+ result.AppendError ("args found no thread.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::StackFrameSP thread_cur_frame = thread->GetSelectedFrame ();
+ if (!thread_cur_frame)
+ {
+ result.AppendError ("The current thread has no current frame.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ModuleSP thread_module_sp (thread_cur_frame->GetFrameCodeAddress ().GetModule());
+ if (!thread_module_sp)
+ {
+ result.AppendError ("The PC has no associated module.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ClangASTContext &ast_context = thread_module_sp->GetClangASTContext();
+
+ ValueList value_list;
+
+ for (arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ const char *arg_type_cstr = args.GetArgumentAtIndex(arg_index);
+ Value value;
+ value.SetValueType(Value::eValueTypeScalar);
+ ClangASTType clang_type;
+
+ char *int_pos;
+ if ((int_pos = strstr (const_cast<char*>(arg_type_cstr), "int")))
+ {
+ Encoding encoding = eEncodingSint;
+
+ int width = 0;
+
+ if (int_pos > arg_type_cstr + 1)
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (int_pos == arg_type_cstr + 1 && arg_type_cstr[0] != 'u')
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (arg_type_cstr[0] == 'u')
+ {
+ encoding = eEncodingUint;
+ }
+
+ char *width_pos = int_pos + 3;
+
+ if (!strcmp (width_pos, "8_t"))
+ width = 8;
+ else if (!strcmp (width_pos, "16_t"))
+ width = 16;
+ else if (!strcmp (width_pos, "32_t"))
+ width = 32;
+ else if (!strcmp (width_pos, "64_t"))
+ width = 64;
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ clang_type = ast_context.GetBuiltinTypeForEncodingAndBitSize(encoding, width);
+
+ if (!clang_type.IsValid())
+ {
+ result.AppendErrorWithFormat ("Couldn't get Clang type for format %s (%s integer, width %d).\n",
+ arg_type_cstr,
+ (encoding == eEncodingSint ? "signed" : "unsigned"),
+ width);
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (strchr (arg_type_cstr, '*'))
+ {
+ if (!strcmp (arg_type_cstr, "void*"))
+ clang_type = ast_context.GetBasicType(eBasicTypeVoid).GetPointerType();
+ else if (!strcmp (arg_type_cstr, "char*"))
+ clang_type = ast_context.GetCStringType (false);
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid format: %s.\n", arg_type_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ value.SetClangType (clang_type);
+ value_list.PushValue(value);
+ }
+
+ if (!abi->GetArgumentValues (*thread, value_list))
+ {
+ result.AppendError ("Couldn't get argument values");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ result.GetOutputStream ().Printf("Arguments : \n");
+
+ for (arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ result.GetOutputStream ().Printf ("%zu (%s): ", arg_index, args.GetArgumentAtIndex (arg_index));
+ value_list.GetValueAtIndex (arg_index)->Dump (&result.GetOutputStream ());
+ result.GetOutputStream ().Printf("\n");
+ }
+
+ return result.Succeeded();
+}
+
+OptionDefinition
+CommandObjectArgs::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
diff --git a/source/Commands/CommandObjectArgs.h b/source/Commands/CommandObjectArgs.h
new file mode 100644
index 000000000000..6691283ce099
--- /dev/null
+++ b/source/Commands/CommandObjectArgs.h
@@ -0,0 +1,72 @@
+//===-- CommandObjectArgs.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_CommandObjectArgs_h_
+#define liblldb_CommandObjectArgs_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/Language.h"
+
+namespace lldb_private {
+
+ class CommandObjectArgs : public CommandObjectParsed
+ {
+ public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ();
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ };
+
+ CommandObjectArgs (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectArgs ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+
+ protected:
+
+ CommandOptions m_options;
+
+ virtual bool
+ DoExecute ( Args& command,
+ CommandReturnObject &result);
+
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectArgs_h_
diff --git a/source/Commands/CommandObjectBreakpoint.cpp b/source/Commands/CommandObjectBreakpoint.cpp
new file mode 100644
index 000000000000..cb70c99a1955
--- /dev/null
+++ b/source/Commands/CommandObjectBreakpoint.cpp
@@ -0,0 +1,1843 @@
+//===-- CommandObjectBreakpoint.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 "CommandObjectBreakpoint.h"
+#include "CommandObjectBreakpointCommand.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+AddBreakpointDescription (Stream *s, Breakpoint *bp, lldb::DescriptionLevel level)
+{
+ s->IndentMore();
+ bp->GetDescription (s, level, true);
+ s->IndentLess();
+ s->EOL();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointSet
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointSet : public CommandObjectParsed
+{
+public:
+
+ typedef enum BreakpointSetType
+ {
+ eSetTypeInvalid,
+ eSetTypeFileAndLine,
+ eSetTypeAddress,
+ eSetTypeFunctionName,
+ eSetTypeFunctionRegexp,
+ eSetTypeSourceRegexp,
+ eSetTypeException
+ } BreakpointSetType;
+
+ CommandObjectBreakpointSet (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint set",
+ "Sets a breakpoint or set of breakpoints in the executable.",
+ "breakpoint set <cmd-options>"),
+ m_options (interpreter)
+ {
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointSet () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_condition (),
+ m_filenames (),
+ m_line_num (0),
+ m_column (0),
+ m_func_names (),
+ m_func_name_type_mask (eFunctionNameTypeNone),
+ m_func_regexp (),
+ m_source_text_regexp(),
+ m_modules (),
+ m_load_addr(),
+ m_ignore_count (0),
+ m_thread_id(LLDB_INVALID_THREAD_ID),
+ m_thread_index (UINT32_MAX),
+ m_thread_name(),
+ m_queue_name(),
+ m_catch_bp (false),
+ m_throw_bp (true),
+ m_language (eLanguageTypeUnknown),
+ m_skip_prologue (eLazyBoolCalculate),
+ m_one_shot (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 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_load_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+
+ case 'b':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeBase;
+ break;
+
+ case 'C':
+ m_column = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ case 'c':
+ m_condition.assign(option_arg);
+ break;
+
+ case 'E':
+ {
+ LanguageType language = LanguageRuntime::GetLanguageTypeFromString (option_arg);
+
+ switch (language)
+ {
+ case eLanguageTypeC89:
+ case eLanguageTypeC:
+ case eLanguageTypeC99:
+ m_language = eLanguageTypeC;
+ break;
+ case eLanguageTypeC_plus_plus:
+ m_language = eLanguageTypeC_plus_plus;
+ break;
+ case eLanguageTypeObjC:
+ m_language = eLanguageTypeObjC;
+ break;
+ case eLanguageTypeObjC_plus_plus:
+ error.SetErrorStringWithFormat ("Set exception breakpoints separately for c++ and objective-c");
+ break;
+ case eLanguageTypeUnknown:
+ error.SetErrorStringWithFormat ("Unknown language type: '%s' for exception breakpoint", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unsupported language type: '%s' for exception breakpoint", option_arg);
+ }
+ }
+ break;
+
+ case 'f':
+ m_filenames.AppendIfUnique (FileSpec(option_arg, false));
+ break;
+
+ case 'F':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeFull;
+ break;
+
+ case 'h':
+ {
+ bool success;
+ m_catch_bp = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for on-catch option: '%s'", option_arg);
+ }
+ break;
+ case 'i':
+ {
+ m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ break;
+ }
+
+ case 'K':
+ {
+ bool success;
+ bool value;
+ value = Args::StringToBoolean (option_arg, true, &success);
+ if (value)
+ m_skip_prologue = eLazyBoolYes;
+ else
+ m_skip_prologue = eLazyBoolNo;
+
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for skip prologue option: '%s'", option_arg);
+ }
+ break;
+
+ case 'l':
+ m_line_num = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ case 'M':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeMethod;
+ break;
+
+ case 'n':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeAuto;
+ break;
+
+ case 'o':
+ m_one_shot = true;
+ break;
+
+ case 'p':
+ m_source_text_regexp.assign (option_arg);
+ break;
+
+ case 'q':
+ m_queue_name.assign (option_arg);
+ break;
+
+ case 'r':
+ m_func_regexp.assign (option_arg);
+ break;
+
+ case 's':
+ {
+ m_modules.AppendIfUnique (FileSpec (option_arg, false));
+ break;
+ }
+
+ case 'S':
+ m_func_names.push_back (option_arg);
+ m_func_name_type_mask |= eFunctionNameTypeSelector;
+ break;
+
+ case 't' :
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ }
+ break;
+
+ case 'T':
+ m_thread_name.assign (option_arg);
+ break;
+
+ case 'w':
+ {
+ bool success;
+ m_throw_bp = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("Invalid boolean value for on-throw option: '%s'", option_arg);
+ }
+ break;
+
+ case 'x':
+ {
+ m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_condition.clear();
+ m_filenames.Clear();
+ m_line_num = 0;
+ m_column = 0;
+ m_func_names.clear();
+ m_func_name_type_mask = eFunctionNameTypeNone;
+ m_func_regexp.clear();
+ m_source_text_regexp.clear();
+ m_modules.Clear();
+ m_load_addr = LLDB_INVALID_ADDRESS;
+ m_ignore_count = 0;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_index = UINT32_MAX;
+ m_thread_name.clear();
+ m_queue_name.clear();
+ m_catch_bp = false;
+ m_throw_bp = true;
+ m_language = eLanguageTypeUnknown;
+ m_skip_prologue = eLazyBoolCalculate;
+ m_one_shot = 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.
+
+ std::string m_condition;
+ FileSpecList m_filenames;
+ uint32_t m_line_num;
+ uint32_t m_column;
+ std::vector<std::string> m_func_names;
+ uint32_t m_func_name_type_mask;
+ std::string m_func_regexp;
+ std::string m_source_text_regexp;
+ FileSpecList m_modules;
+ lldb::addr_t m_load_addr;
+ uint32_t m_ignore_count;
+ lldb::tid_t m_thread_id;
+ uint32_t m_thread_index;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ bool m_catch_bp;
+ bool m_throw_bp;
+ lldb::LanguageType m_language;
+ LazyBool m_skip_prologue;
+ bool m_one_shot;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. Must set target before setting breakpoints (see 'target create' command).");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // The following are the various types of breakpoints that could be set:
+ // 1). -f -l -p [-s -g] (setting breakpoint by source location)
+ // 2). -a [-s -g] (setting breakpoint by address)
+ // 3). -n [-s -g] (setting breakpoint by function name)
+ // 4). -r [-s -g] (setting breakpoint by function name regular expression)
+ // 5). -p -f (setting a breakpoint by comparing a reg-exp to source text)
+ // 6). -E [-w -h] (setting a breakpoint for exceptions for a given language.)
+
+ BreakpointSetType break_type = eSetTypeInvalid;
+
+ if (m_options.m_line_num != 0)
+ break_type = eSetTypeFileAndLine;
+ else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
+ break_type = eSetTypeAddress;
+ else if (!m_options.m_func_names.empty())
+ break_type = eSetTypeFunctionName;
+ else if (!m_options.m_func_regexp.empty())
+ break_type = eSetTypeFunctionRegexp;
+ else if (!m_options.m_source_text_regexp.empty())
+ break_type = eSetTypeSourceRegexp;
+ else if (m_options.m_language != eLanguageTypeUnknown)
+ break_type = eSetTypeException;
+
+ Breakpoint *bp = NULL;
+ FileSpec module_spec;
+ const bool internal = false;
+
+ switch (break_type)
+ {
+ case eSetTypeFileAndLine: // Breakpoint by source position
+ {
+ FileSpec file;
+ const size_t num_files = m_options.m_filenames.GetSize();
+ if (num_files == 0)
+ {
+ if (!GetDefaultFile (target, file, result))
+ {
+ result.AppendError("No file supplied and no default file available.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (num_files > 1)
+ {
+ result.AppendError("Only one file at a time is allowed for file and line breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ file = m_options.m_filenames.GetFileSpecAtIndex(0);
+
+ // Only check for inline functions if
+ LazyBool check_inlines = eLazyBoolCalculate;
+
+ bp = target->CreateBreakpoint (&(m_options.m_modules),
+ file,
+ m_options.m_line_num,
+ check_inlines,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+
+ case eSetTypeAddress: // Breakpoint by address
+ bp = target->CreateBreakpoint (m_options.m_load_addr, false).get();
+ break;
+
+ case eSetTypeFunctionName: // Breakpoint by function name
+ {
+ uint32_t name_type_mask = m_options.m_func_name_type_mask;
+
+ if (name_type_mask == 0)
+ name_type_mask = eFunctionNameTypeAuto;
+
+ bp = target->CreateBreakpoint (&(m_options.m_modules),
+ &(m_options.m_filenames),
+ m_options.m_func_names,
+ name_type_mask,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+
+ case eSetTypeFunctionRegexp: // Breakpoint by regular expression function name
+ {
+ RegularExpression regexp(m_options.m_func_regexp.c_str());
+ if (!regexp.IsValid())
+ {
+ char err_str[1024];
+ regexp.GetErrorAsCString(err_str, sizeof(err_str));
+ result.AppendErrorWithFormat("Function name regular expression could not be compiled: \"%s\"",
+ err_str);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ bp = target->CreateFuncRegexBreakpoint (&(m_options.m_modules),
+ &(m_options.m_filenames),
+ regexp,
+ m_options.m_skip_prologue,
+ internal).get();
+ }
+ break;
+ case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
+ {
+ const size_t num_files = m_options.m_filenames.GetSize();
+
+ if (num_files == 0)
+ {
+ FileSpec file;
+ if (!GetDefaultFile (target, file, result))
+ {
+ result.AppendError ("No files provided and could not find default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ m_options.m_filenames.Append (file);
+ }
+ }
+
+ RegularExpression regexp(m_options.m_source_text_regexp.c_str());
+ if (!regexp.IsValid())
+ {
+ char err_str[1024];
+ regexp.GetErrorAsCString(err_str, sizeof(err_str));
+ result.AppendErrorWithFormat("Source text regular expression could not be compiled: \"%s\"",
+ err_str);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ bp = target->CreateSourceRegexBreakpoint (&(m_options.m_modules), &(m_options.m_filenames), regexp).get();
+ }
+ break;
+ case eSetTypeException:
+ {
+ bp = target->CreateExceptionBreakpoint (m_options.m_language, m_options.m_catch_bp, m_options.m_throw_bp).get();
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Now set the various options that were passed in:
+ if (bp)
+ {
+ if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
+ bp->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index != UINT32_MAX)
+ bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index);
+
+ if (!m_options.m_thread_name.empty())
+ bp->GetOptions()->GetThreadSpec()->SetName(m_options.m_thread_name.c_str());
+
+ if (!m_options.m_queue_name.empty())
+ bp->GetOptions()->GetThreadSpec()->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (!m_options.m_condition.empty())
+ bp->GetOptions()->SetCondition(m_options.m_condition.c_str());
+
+ bp->SetOneShot (m_options.m_one_shot);
+ }
+
+ if (bp)
+ {
+ 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");
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else if (!bp)
+ {
+ result.AppendError ("Breakpoint creation failed: No breakpoint created.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ bool
+ GetDefaultFile (Target *target, FileSpec &file, CommandReturnObject &result)
+ {
+ uint32_t default_line;
+ // First use the Source Manager's default file.
+ // Then use the current stack frame's file.
+ if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line))
+ {
+ StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
+ if (cur_frame == NULL)
+ {
+ result.AppendError ("No selected frame to use to find the default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!cur_frame->HasDebugInformation())
+ {
+ result.AppendError ("Cannot use the selected frame to find the default file, it has no debug info.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ const SymbolContext &sc = cur_frame->GetSymbolContext (eSymbolContextLineEntry);
+ if (sc.line_entry.file)
+ {
+ file = sc.line_entry.file;
+ }
+ else
+ {
+ result.AppendError ("Can't find the file for the selected frame to use as the default file.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ CommandOptions m_options;
+};
+// If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
+// update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
+#define LLDB_OPT_FILE ( LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2 )
+#define LLDB_OPT_NOT_10 ( LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10 )
+#define LLDB_OPT_SKIP_PROLOGUE ( LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3,8) )
+
+OptionDefinition
+CommandObjectBreakpointSet::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_NOT_10, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ "Set the breakpoint only in this shared library. "
+ "Can repeat this option multiple times to specify multiple shared libraries."},
+
+ { LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount,
+ "Set the number of times this breakpoint is skipped before stopping." },
+
+ { LLDB_OPT_SET_ALL, false, "one-shot", 'o', no_argument, NULL, 0, eArgTypeNone,
+ "The breakpoint is deleted the first time it causes a stop." },
+
+ { LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression,
+ "The breakpoint stops only if this condition expression evaluates to true."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex,
+ "The breakpoint stops only for the thread whose indeX matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID,
+ "The breakpoint stops only for the thread whose TID matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName,
+ "The breakpoint stops only for the thread whose thread name matches this argument."},
+
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName,
+ "The breakpoint stops only for threads in the queue whose name is given by this argument."},
+
+ { LLDB_OPT_FILE, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specifies the source file in which to set this breakpoint. "
+ "Note, by default lldb only looks for files that are #included if they use the standard include file extensions. "
+ "To set breakpoints on .c/.cpp/.m/.mm files that are #included, set target.inline-breakpoint-strategy"
+ " to \"always\"."},
+
+ { LLDB_OPT_SET_1, true, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Specifies the line number on which to set this breakpoint."},
+
+ // Comment out this option for the moment, as we don't actually use it, but will in the future.
+ // This way users won't see it, but the infrastructure is left in place.
+ // { 0, false, "column", 'C', required_argument, NULL, "<column>",
+ // "Set the breakpoint by source location at this particular column."},
+
+ { LLDB_OPT_SET_2, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression,
+ "Set the breakpoint by address, at the specified address."},
+
+ { LLDB_OPT_SET_3, true, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the breakpoint by function name. Can be repeated multiple times to make one breakpoint for multiple names" },
+
+ { LLDB_OPT_SET_4, true, "fullname", 'F', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFullName,
+ "Set the breakpoint by fully qualified function names. For C++ this means namespaces and all arguments, and "
+ "for Objective C this means a full function prototype with class and selector. "
+ "Can be repeated multiple times to make one breakpoint for multiple names." },
+
+ { LLDB_OPT_SET_5, true, "selector", 'S', required_argument, NULL, 0, eArgTypeSelector,
+ "Set the breakpoint by ObjC selector name. Can be repeated multiple times to make one breakpoint for multiple Selectors." },
+
+ { LLDB_OPT_SET_6, true, "method", 'M', required_argument, NULL, 0, eArgTypeMethod,
+ "Set the breakpoint by C++ method names. Can be repeated multiple times to make one breakpoint for multiple methods." },
+
+ { LLDB_OPT_SET_7, true, "func-regex", 'r', required_argument, NULL, 0, eArgTypeRegularExpression,
+ "Set the breakpoint by function name, evaluating a regular-expression to find the function name(s)." },
+
+ { LLDB_OPT_SET_8, true, "basename", 'b', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the breakpoint by function basename (C++ namespaces and arguments will be ignored). "
+ "Can be repeated multiple times to make one breakpoint for multiple symbols." },
+
+ { LLDB_OPT_SET_9, true, "source-pattern-regexp", 'p', required_argument, NULL, 0, eArgTypeRegularExpression,
+ "Set the breakpoint by specifying a regular expression which is matched against the source text in a source file or files "
+ "specified with the -f option. The -f option can be specified more than once. "
+ "If no source files are specified, uses the current \"default source file\"" },
+
+ { LLDB_OPT_SET_10, true, "language-exception", 'E', required_argument, NULL, 0, eArgTypeLanguage,
+ "Set the breakpoint on exceptions thrown by the specified language (without options, on throw but not catch.)" },
+
+ { LLDB_OPT_SET_10, false, "on-throw", 'w', required_argument, NULL, 0, eArgTypeBoolean,
+ "Set the breakpoint on exception throW." },
+
+ { LLDB_OPT_SET_10, false, "on-catch", 'h', required_argument, NULL, 0, eArgTypeBoolean,
+ "Set the breakpoint on exception catcH." },
+
+ { LLDB_OPT_SKIP_PROLOGUE, false, "skip-prologue", 'K', required_argument, NULL, 0, eArgTypeBoolean,
+ "sKip the prologue if the breakpoint is at the beginning of a function. If not set the target.skip-prologue setting is used." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointModify
+//-------------------------------------------------------------------------
+#pragma mark Modify
+
+class CommandObjectBreakpointModify : public CommandObjectParsed
+{
+public:
+
+ CommandObjectBreakpointModify (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint modify",
+ "Modify the options on a breakpoint or set of breakpoints in the executable. "
+ "If no breakpoint is specified, acts on the last created breakpoint. "
+ "With the exception of -e, -d and -i, passing an empty argument clears the modification.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointModify () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_ignore_count (0),
+ m_thread_id(LLDB_INVALID_THREAD_ID),
+ m_thread_id_passed(false),
+ m_thread_index (UINT32_MAX),
+ m_thread_index_passed(false),
+ m_thread_name(),
+ m_queue_name(),
+ m_condition (),
+ m_one_shot (false),
+ m_enable_passed (false),
+ m_enable_value (false),
+ m_name_passed (false),
+ m_queue_passed (false),
+ m_condition_passed (false),
+ m_one_shot_passed (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 'c':
+ if (option_arg != NULL)
+ m_condition.assign (option_arg);
+ else
+ m_condition.clear();
+ m_condition_passed = true;
+ break;
+ case 'd':
+ m_enable_passed = true;
+ m_enable_value = false;
+ break;
+ case 'e':
+ m_enable_passed = true;
+ m_enable_value = true;
+ break;
+ case 'i':
+ {
+ m_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ }
+ break;
+ case 'o':
+ {
+ bool value, success;
+ value = Args::StringToBoolean(option_arg, false, &success);
+ if (success)
+ {
+ m_one_shot_passed = true;
+ m_one_shot = value;
+ }
+ else
+ error.SetErrorStringWithFormat("invalid boolean value '%s' passed for -o option", option_arg);
+ }
+ break;
+ case 't' :
+ {
+ if (option_arg[0] == '\0')
+ {
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_id_passed = true;
+ }
+ else
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ else
+ m_thread_id_passed = true;
+ }
+ }
+ break;
+ case 'T':
+ if (option_arg != NULL)
+ m_thread_name.assign (option_arg);
+ else
+ m_thread_name.clear();
+ m_name_passed = true;
+ break;
+ case 'q':
+ if (option_arg != NULL)
+ m_queue_name.assign (option_arg);
+ else
+ m_queue_name.clear();
+ m_queue_passed = true;
+ break;
+ case 'x':
+ {
+ if (option_arg[0] == '\n')
+ {
+ m_thread_index = UINT32_MAX;
+ m_thread_index_passed = true;
+ }
+ else
+ {
+ m_thread_index = Args::StringToUInt32 (option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+ else
+ m_thread_index_passed = true;
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore_count = 0;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_id_passed = false;
+ m_thread_index = UINT32_MAX;
+ m_thread_index_passed = false;
+ m_thread_name.clear();
+ m_queue_name.clear();
+ m_condition.clear();
+ m_one_shot = false;
+ m_enable_passed = false;
+ m_queue_passed = false;
+ m_name_passed = false;
+ m_condition_passed = false;
+ m_one_shot_passed = 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.
+
+ uint32_t m_ignore_count;
+ lldb::tid_t m_thread_id;
+ bool m_thread_id_passed;
+ uint32_t m_thread_index;
+ bool m_thread_index_passed;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ std::string m_condition;
+ bool m_one_shot;
+ bool m_enable_passed;
+ bool m_enable_value;
+ bool m_name_passed;
+ bool m_queue_passed;
+ bool m_condition_passed;
+ bool m_one_shot_passed;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ BreakpointIDList valid_bp_ids;
+
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = bp->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ if (m_options.m_thread_id_passed)
+ location->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index_passed)
+ location->SetThreadIndex(m_options.m_thread_index);
+
+ if (m_options.m_name_passed)
+ location->SetThreadName(m_options.m_thread_name.c_str());
+
+ if (m_options.m_queue_passed)
+ location->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ location->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (m_options.m_enable_passed)
+ location->SetEnabled (m_options.m_enable_value);
+
+ if (m_options.m_condition_passed)
+ location->SetCondition (m_options.m_condition.c_str());
+ }
+ }
+ else
+ {
+ if (m_options.m_thread_id_passed)
+ bp->SetThreadID (m_options.m_thread_id);
+
+ if (m_options.m_thread_index_passed)
+ bp->SetThreadIndex(m_options.m_thread_index);
+
+ if (m_options.m_name_passed)
+ bp->SetThreadName(m_options.m_thread_name.c_str());
+
+ if (m_options.m_queue_passed)
+ bp->SetQueueName(m_options.m_queue_name.c_str());
+
+ if (m_options.m_ignore_count != 0)
+ bp->SetIgnoreCount(m_options.m_ignore_count);
+
+ if (m_options.m_enable_passed)
+ bp->SetEnabled (m_options.m_enable_value);
+
+ if (m_options.m_condition_passed)
+ bp->SetCondition (m_options.m_condition.c_str());
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Modify::CommandOptions
+OptionDefinition
+CommandObjectBreakpointModify::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this breakpoint is skipped before stopping." },
+{ LLDB_OPT_SET_ALL, false, "one-shot", 'o', required_argument, NULL, 0, eArgTypeBoolean, "The breakpoint is deleted the first time it stop causes a stop." },
+{ LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID, "The breakpoint stops only for the thread whose TID matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName, "The breakpoint stops only for the thread whose thread name matches this argument."},
+{ LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName, "The breakpoint stops only for threads in the queue whose name is given by this argument."},
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."},
+{ LLDB_OPT_SET_1, false, "enable", 'e', no_argument, NULL, 0, eArgTypeNone, "Enable the breakpoint."},
+{ LLDB_OPT_SET_2, false, "disable", 'd', no_argument, NULL, 0, eArgTypeNone, "Disable the breakpoint."},
+{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointEnable
+//-------------------------------------------------------------------------
+#pragma mark Enable
+
+class CommandObjectBreakpointEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "enable",
+ "Enable the specified disabled breakpoint(s). If no breakpoints are specified, enable all of them.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointEnable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ 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.AppendError ("No breakpoints exist to be enabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; enable all currently set breakpoints.
+ target->EnableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints enabled. (%lu breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; enable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int enable_count = 0;
+ int loc_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ location->SetEnabled (true);
+ ++loc_count;
+ }
+ }
+ else
+ {
+ breakpoint->SetEnabled (true);
+ ++enable_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints enabled.\n", enable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDisable
+//-------------------------------------------------------------------------
+#pragma mark Disable
+
+class CommandObjectBreakpointDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint disable",
+ "Disable the specified breakpoint(s) without removing it/them. If no breakpoints are specified, disable them all.",
+ NULL)
+ {
+ SetHelpLong(
+"Disable the specified breakpoint(s) without removing it/them. \n\
+If no breakpoints are specified, disable them all.\n\
+\n\
+Note: disabling a breakpoint will cause none of its locations to be hit\n\
+regardless of whether they are enabled or disabled. So the sequence: \n\
+\n\
+ (lldb) break disable 1\n\
+ (lldb) break enable 1.1\n\
+\n\
+will NOT cause location 1.1 to get hit. To achieve that, do:\n\
+\n\
+ (lldb) break disable 1.*\n\
+ (lldb) break enable 1.1\n\
+\n\
+The first command disables all the locations of breakpoint 1, \n\
+the second re-enables the first location."
+ );
+
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointDisable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ 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.AppendError ("No breakpoints exist to be disabled.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; disable all currently set breakpoints.
+ target->DisableAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints disabled. (%lu breakpoints)\n", num_breakpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int disable_count = 0;
+ int loc_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ if (location)
+ {
+ location->SetEnabled (false);
+ ++loc_count;
+ }
+ }
+ else
+ {
+ breakpoint->SetEnabled (false);
+ ++disable_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints disabled.\n", disable_count + loc_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointList
+//-------------------------------------------------------------------------
+#pragma mark List
+
+class CommandObjectBreakpointList : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint list",
+ "List some or all breakpoints at configurable levels of detail.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointList () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_level (lldb::eDescriptionLevelBrief) // Breakpoint List defaults to brief descriptions
+ {
+ }
+
+ 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 'b':
+ m_level = lldb::eDescriptionLevelBrief;
+ break;
+ case 'f':
+ m_level = lldb::eDescriptionLevelFull;
+ break;
+ case 'v':
+ m_level = lldb::eDescriptionLevelVerbose;
+ break;
+ case 'i':
+ m_internal = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_level = lldb::eDescriptionLevelFull;
+ 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.
+
+ lldb::DescriptionLevel m_level;
+
+ bool m_internal;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No current target or breakpoints.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList(m_options.m_internal);
+ Mutex::Locker locker;
+ target->GetBreakpointList(m_options.m_internal).GetListMutex(locker);
+
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendMessage ("No breakpoints currently set.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ Stream &output_stream = result.GetOutputStream();
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No breakpoint selected; show info about all currently set breakpoints.
+ result.AppendMessage ("Current breakpoints:");
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ {
+ Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex (i).get();
+ AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoints selected; show info about that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ AddBreakpointDescription (&output_stream, breakpoint, m_options.m_level);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Invalid breakpoint id.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark List::CommandOptions
+OptionDefinition
+CommandObjectBreakpointList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "internal", 'i', no_argument, NULL, 0, eArgTypeNone,
+ "Show debugger internal breakpoints" },
+
+ { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone,
+ "Give a brief description of the breakpoint (no location info)."},
+
+ // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
+ // But I need to see it for now, and don't want to wait.
+ { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone,
+ "Give a full description of the breakpoint and its locations."},
+
+ { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone,
+ "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointClear
+//-------------------------------------------------------------------------
+#pragma mark Clear
+
+class CommandObjectBreakpointClear : public CommandObjectParsed
+{
+public:
+
+ typedef enum BreakpointClearType
+ {
+ eClearTypeInvalid,
+ eClearTypeFileAndLine
+ } BreakpointClearType;
+
+ CommandObjectBreakpointClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint clear",
+ "Clears a breakpoint or set of breakpoints in the executable.",
+ "breakpoint clear <cmd-options>"),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectBreakpointClear () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_filename (),
+ m_line_num (0)
+ {
+ }
+
+ 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_filename.assign (option_arg);
+ break;
+
+ case 'l':
+ m_line_num = Args::StringToUInt32 (option_arg, 0);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_filename.clear();
+ m_line_num = 0;
+ }
+
+ 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.
+
+ std::string m_filename;
+ uint32_t m_line_num;
+
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or breakpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // The following are the various types of breakpoints that could be cleared:
+ // 1). -f -l (clearing breakpoint by source location)
+
+ BreakpointClearType break_type = eClearTypeInvalid;
+
+ if (m_options.m_line_num != 0)
+ break_type = eClearTypeFileAndLine;
+
+ Mutex::Locker locker;
+ target->GetBreakpointList().GetListMutex(locker);
+
+ BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ // Early return if there's no breakpoint at all.
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("Breakpoint clear: No breakpoint cleared.");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ // Find matching breakpoints and delete them.
+
+ // First create a copy of all the IDs.
+ std::vector<break_id_t> BreakIDs;
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i).get()->GetID());
+
+ int num_cleared = 0;
+ StreamString ss;
+ switch (break_type)
+ {
+ case eClearTypeFileAndLine: // Breakpoint by source position
+ {
+ const ConstString filename(m_options.m_filename.c_str());
+ BreakpointLocationCollection loc_coll;
+
+ for (size_t i = 0; i < num_breakpoints; ++i)
+ {
+ Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
+
+ if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll))
+ {
+ // If the collection size is 0, it's a full match and we can just remove the breakpoint.
+ if (loc_coll.GetSize() == 0)
+ {
+ bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
+ ss.EOL();
+ target->RemoveBreakpointByID (bp->GetID());
+ ++num_cleared;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (num_cleared > 0)
+ {
+ Stream &output_stream = result.GetOutputStream();
+ output_stream.Printf ("%d breakpoints cleared:\n", num_cleared);
+ output_stream << ss.GetData();
+ output_stream.EOL();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Breakpoint clear: No breakpoint cleared.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Clear::CommandOptions
+
+OptionDefinition
+CommandObjectBreakpointClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specify the breakpoint by source location in this particular file."},
+
+ { LLDB_OPT_SET_1, true, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Specify the breakpoint by source location at this particular line."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointDelete
+//-------------------------------------------------------------------------
+#pragma mark Delete
+
+class CommandObjectBreakpointDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "breakpoint delete",
+ "Delete the specified breakpoint(s). If no breakpoints are specified, delete them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, eArgTypeBreakpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ 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.AppendError ("No breakpoints exist to be deleted.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ if (!m_interpreter.Confirm ("About to delete all breakpoints, do you want to do that?", true))
+ {
+ result.AppendMessage("Operation cancelled...");
+ }
+ else
+ {
+ target->RemoveAllBreakpoints ();
+ result.AppendMessageWithFormat ("All breakpoints removed. (%lu %s)\n", num_breakpoints, num_breakpoints > 1 ? "breakpoints" : "breakpoint");
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular breakpoint selected; disable that breakpoint.
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ int delete_count = 0;
+ int disable_count = 0;
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ BreakpointLocation *location = breakpoint->FindLocationByID (cur_bp_id.GetLocationID()).get();
+ // It makes no sense to try to delete individual locations, so we disable them instead.
+ if (location)
+ {
+ location->SetEnabled (false);
+ ++disable_count;
+ }
+ }
+ else
+ {
+ target->RemoveBreakpointByID (cur_bp_id.GetBreakpointID());
+ ++delete_count;
+ }
+ }
+ }
+ result.AppendMessageWithFormat ("%d breakpoints deleted; %d breakpoint locations disabled.\n",
+ delete_count, disable_count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+#pragma mark MultiwordBreakpoint
+
+CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "breakpoint",
+ "A set of commands for operating on breakpoints. Also see _regexp-break.",
+ "breakpoint <command> [<command-options>]")
+{
+ CommandObjectSP list_command_object (new CommandObjectBreakpointList (interpreter));
+ CommandObjectSP enable_command_object (new CommandObjectBreakpointEnable (interpreter));
+ CommandObjectSP disable_command_object (new CommandObjectBreakpointDisable (interpreter));
+ CommandObjectSP clear_command_object (new CommandObjectBreakpointClear (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointDelete (interpreter));
+ CommandObjectSP set_command_object (new CommandObjectBreakpointSet (interpreter));
+ CommandObjectSP command_command_object (new CommandObjectBreakpointCommand (interpreter));
+ CommandObjectSP modify_command_object (new CommandObjectBreakpointModify(interpreter));
+
+ list_command_object->SetCommandName ("breakpoint list");
+ enable_command_object->SetCommandName("breakpoint enable");
+ disable_command_object->SetCommandName("breakpoint disable");
+ clear_command_object->SetCommandName("breakpoint clear");
+ delete_command_object->SetCommandName("breakpoint delete");
+ set_command_object->SetCommandName("breakpoint set");
+ command_command_object->SetCommandName ("breakpoint command");
+ modify_command_object->SetCommandName ("breakpoint modify");
+
+ LoadSubCommand ("list", list_command_object);
+ LoadSubCommand ("enable", enable_command_object);
+ LoadSubCommand ("disable", disable_command_object);
+ LoadSubCommand ("clear", clear_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("set", set_command_object);
+ LoadSubCommand ("command", command_command_object);
+ LoadSubCommand ("modify", modify_command_object);
+}
+
+CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint ()
+{
+}
+
+void
+CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (Args &args, Target *target, 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.
+ // If args is empty, we will use the last created breakpoint (if there is one.)
+
+ Args temp_args;
+
+ if (args.GetArgumentCount() == 0)
+ {
+ if (target->GetLastCreatedBreakpoint())
+ {
+ valid_ids->AddBreakpointID (BreakpointID(target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("No breakpoint specified and no last created breakpoint.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return;
+ }
+
+ // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff directly from the old ARGS to
+ // 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);
+
+ // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual BreakpointIDList:
+
+ valid_ids->InsertStringArray (temp_args.GetConstArgumentVector(), temp_args.GetArgumentCount(), result);
+
+ // At this point, all of the breakpoint ids that the user passed in have been converted to breakpoint IDs
+ // and put into valid_ids.
+
+ if (result.Succeeded())
+ {
+ // Now that we've converted everything from args into a list of breakpoint ids, go through our tentative list
+ // of breakpoint id's and verify that they correspond to valid/currently set breakpoints.
+
+ const size_t count = valid_ids->GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex (i);
+ Breakpoint *breakpoint = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (breakpoint != NULL)
+ {
+ const size_t num_locations = breakpoint->GetNumLocations();
+ if (cur_bp_id.GetLocationID() > num_locations)
+ {
+ StreamString id_str;
+ BreakpointID::GetCanonicalReference (&id_str,
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ i = valid_ids->GetSize() + 1;
+ result.AppendErrorWithFormat ("'%s' is not a currently valid breakpoint/location id.\n",
+ id_str.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ i = valid_ids->GetSize() + 1;
+ result.AppendErrorWithFormat ("'%d' is not a currently valid breakpoint id.\n", cur_bp_id.GetBreakpointID());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+}
diff --git a/source/Commands/CommandObjectBreakpoint.h b/source/Commands/CommandObjectBreakpoint.h
new file mode 100644
index 000000000000..2d674b22d704
--- /dev/null
+++ b/source/Commands/CommandObjectBreakpoint.h
@@ -0,0 +1,47 @@
+//===-- CommandObjectBreakpoint.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_CommandObjectBreakpoint_h_
+#define liblldb_CommandObjectBreakpoint_h_
+
+// C Includes
+// C++ Includes
+
+#include <utility>
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Address.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordBreakpoint : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordBreakpoint (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordBreakpoint ();
+
+ static void
+ VerifyBreakpointIDs (Args &args, Target *target, CommandReturnObject &result, BreakpointIDList *valid_ids);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpoint_h_
diff --git a/source/Commands/CommandObjectBreakpointCommand.cpp b/source/Commands/CommandObjectBreakpointCommand.cpp
new file mode 100644
index 000000000000..c4504a4c6516
--- /dev/null
+++ b/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -0,0 +1,915 @@
+//===-- CommandObjectBreakpointCommand.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"
+
+// C Includes
+// C++ Includes
+
+
+#include "CommandObjectBreakpointCommand.h"
+#include "CommandObjectBreakpoint.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/State.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectBreakpointCommandAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "add",
+ "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong (
+"\nGeneral information about entering breakpoint commands\n\
+------------------------------------------------------\n\
+\n\
+This command will cause you to be prompted to enter the command or set of\n\
+commands you wish to be executed when the specified breakpoint is hit. You\n\
+will be told to enter your command(s), and will see a '> 'prompt. Because\n\
+you can enter one or many commands to be executed when a breakpoint is hit,\n\
+you will continue to be prompted after each new-line that you enter, until you\n\
+enter the word 'DONE', which will cause the commands you have entered to be\n\
+stored with the breakpoint and executed when the breakpoint is hit.\n\
+\n\
+Syntax checking is not necessarily done when breakpoint commands are entered.\n\
+An improperly written breakpoint command will attempt to get executed when the\n\
+breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\
+not appear to be getting executed, go back and check your syntax.\n\
+\n\
+Special information about PYTHON breakpoint commands\n\
+----------------------------------------------------\n\
+\n\
+You may enter either one line of Python, multiple lines of Python (including\n\
+function definitions), or specify a Python function in a module that has already,\n\
+or will be imported. If you enter a single line of Python, that will be passed\n\
+to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\
+function definitions, they will be passed to the Python interpreter as soon as\n\
+you finish entering the breakpoint command, and they can be called later (don't\n\
+forget to add calls to them, if you want them called when the breakpoint is\n\
+hit). If you enter multiple lines of Python that are not function definitions,\n\
+they will be collected into a new, automatically generated Python function, and\n\
+a call to the newly generated function will be attached to the breakpoint.\n\
+\n\
+\n\
+This auto-generated function is passed in three arguments:\n\
+\n\
+ frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\
+ bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\
+ location that was hit.\n\
+ dict: the python session dictionary hit.\n\
+\n\
+When specifying a python function with the --python-function option, you need\n\
+to supply the function name prepended by the module name. So if you import a\n\
+module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\
+specify the option as:\n\
+\n\
+ --python-function myutils.breakpoint_callback\n\
+\n\
+The function itself must have the following prototype:\n\
+\n\
+def breakpoint_callback(frame, bp_loc, dict):\n\
+ # Your code goes here\n\
+\n\
+The arguments are the same as the 3 auto generation function arguments listed\n\
+above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\
+function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\
+can get you to the thread (frame.GetThread()), the thread can get you to the\n\
+process (thread.GetProcess()), and the process can get you back to the target\n\
+(process.GetTarget()).\n\
+\n\
+Important Note: Because loose Python code gets collected into functions, if you\n\
+want to access global variables in the 'loose' code, you need to specify that\n\
+they are global, using the 'global' keyword. Be sure to use correct Python\n\
+syntax, including indentation, when entering Python breakpoint commands.\n\
+\n\
+As a third option, you can pass the name of an already existing Python function\n\
+and that function will be attached to the breakpoint. It will get passed the\n\
+frame and bp_loc arguments mentioned above.\n\
+\n\
+Example Python one-line breakpoint command:\n\
+\n\
+(lldb) breakpoint command add -s python 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> print \"Hit this breakpoint!\"\n\
+> DONE\n\
+\n\
+As a convenience, this also works for a short Python one-liner:\n\
+(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\
+(lldb) run\n\
+Launching '.../a.out' (x86_64)\n\
+(lldb) Fri Sep 10 12:17:45 2010\n\
+Process 21778 Stopped\n\
+* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\
+ 36 \n\
+ 37 int c(int val)\n\
+ 38 {\n\
+ 39 -> return val + 3;\n\
+ 40 }\n\
+ 41 \n\
+ 42 int main (int argc, char const *argv[])\n\
+(lldb)\n\
+\n\
+Example multiple line Python breakpoint command, using function definition:\n\
+\n\
+(lldb) breakpoint command add -s python 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> def breakpoint_output (bp_no):\n\
+> out_string = \"Hit breakpoint number \" + repr (bp_no)\n\
+> print out_string\n\
+> return True\n\
+> breakpoint_output (1)\n\
+> DONE\n\
+\n\
+\n\
+Example multiple line Python breakpoint command, using 'loose' Python:\n\
+\n\
+(lldb) breakpoint command add -s p 1\n\
+Enter your Python command(s). Type 'DONE' to end.\n\
+> global bp_count\n\
+> bp_count = bp_count + 1\n\
+> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\
+> DONE\n\
+\n\
+In this case, since there is a reference to a global variable,\n\
+'bp_count', you will also need to make sure 'bp_count' exists and is\n\
+initialized:\n\
+\n\
+(lldb) script\n\
+>>> bp_count = 0\n\
+>>> quit()\n\
+\n\
+(lldb)\n\
+\n\
+\n\
+Your Python code, however organized, can optionally return a value.\n\
+If the returned value is False, that tells LLDB not to stop at the breakpoint\n\
+to which the code is associated. Returning anything other than False, or even\n\
+returning None, or even omitting a return statement entirely, will cause\n\
+LLDB to stop.\n\
+\n\
+Final Note: If you get a warning that no breakpoint command was generated, but\n\
+you did not get any syntax errors, you probably forgot to add a call to your\n\
+functions.\n\
+\n\
+Special information about debugger command breakpoint commands\n\
+--------------------------------------------------------------\n\
+\n\
+You may enter any debugger command, exactly as you would at the debugger prompt.\n\
+You may enter as many debugger commands as you like, but do NOT enter more than\n\
+one command per line.\n" );
+
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointCommandAdd () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ if (reader_sp && data_ap.get())
+ {
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+
+ Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
+ bp_options, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+
+ /// Set a one-liner as the callback for the breakpoint.
+ void
+ SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ const char *oneliner)
+ {
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in breakpoint command list)
+ // while the latter is used for Python to interpret during the actual callback.
+ data_ap->user_source.AppendString (oneliner);
+ data_ap->script_source.assign (oneliner);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
+
+ return;
+ }
+
+ static size_t
+ GenerateBreakpointCommandCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_reader_instructions);
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && baton)
+ {
+ BreakpointOptions *bp_options = (BreakpointOptions *) baton;
+ if (bp_options)
+ {
+ Baton *bp_options_baton = bp_options->GetBaton();
+ if (bp_options_baton)
+ ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the breakpoint command.
+ reader.SetIsDone (true);
+ BreakpointOptions *bp_options = (BreakpointOptions *) baton;
+ if (bp_options)
+ {
+ Baton *bp_options_baton = bp_options->GetBaton ();
+ if (bp_options_baton)
+ {
+ ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
+ ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear();
+ }
+ }
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+ }
+
+ static bool
+ BreakpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+ {
+ bool ret_value = true;
+ if (baton == NULL)
+ return true;
+
+
+ BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0)
+ {
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
+ // if the debugger is set up that way.
+
+ StreamSP output_stream (debugger.GetAsyncOutputStream());
+ StreamSP error_stream (debugger.GetAsyncErrorStream());
+ 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,
+ &exe_ctx,
+ stop_on_continue,
+ data->stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolNo,
+ result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
+ }
+ return ret_value;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_commands (false),
+ m_use_script_language (false),
+ m_script_language (eScriptLanguageNone),
+ m_use_one_liner (false),
+ m_one_liner(),
+ m_function_name()
+ {
+ }
+
+ 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 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+
+ case 's':
+ m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eScriptLanguageNone,
+ error);
+
+ if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
+ {
+ m_use_script_language = true;
+ }
+ else
+ {
+ m_use_script_language = false;
+ }
+ break;
+
+ case 'e':
+ {
+ bool success = false;
+ m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
+ }
+ break;
+
+ case 'F':
+ {
+ m_use_one_liner = false;
+ m_use_script_language = true;
+ m_function_name.assign(option_arg);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+
+ m_use_one_liner = false;
+ m_stop_on_error = true;
+ m_one_liner.clear();
+ m_function_name.clear();
+ }
+
+ 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_commands;
+ bool m_use_script_language;
+ lldb::ScriptLanguage m_script_language;
+
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ bool m_stop_on_error;
+ std::string m_function_name;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to have commands added");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_use_script_language == false && m_options.m_function_name.size())
+ {
+ result.AppendError ("need to enable scripting to have a function run as a breakpoint command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ if (count > 1)
+ {
+ result.AppendError ("can only add commands to one breakpoint at a time.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ BreakpointOptions *bp_options = NULL;
+ if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
+ {
+ // This breakpoint does not have an associated location.
+ bp_options = bp->GetOptions();
+ }
+ else
+ {
+ BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ // This breakpoint does have an associated location.
+ // Get its breakpoint options.
+ if (bp_loc_sp)
+ bp_options = bp_loc_sp->GetLocationOptions();
+ }
+
+ // Skip this breakpoint if bp_options is not good.
+ if (bp_options == NULL) continue;
+
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language)
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ {
+ m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ m_options.m_one_liner.c_str());
+ }
+ // Special handling for using a Python function by name
+ // instead of extending the breakpoint callback data structures, we just automatize
+ // what the user would do manually: make their breakpoint command be a function call
+ else if (m_options.m_function_name.size())
+ {
+ std::string oneliner("return ");
+ oneliner += m_options.m_function_name;
+ oneliner += "(frame, bp_loc, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
+ oneliner.c_str());
+ }
+ else
+ {
+ m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
+ result);
+ }
+ }
+ else
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetBreakpointCommandCallback (bp_options,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForBreakpointCommandCallback (bp_options,
+ result);
+ }
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+ static const char *g_reader_instructions;
+
+};
+
+const char *
+CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
+
+// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement
+g_script_option_enumeration[4] =
+{
+ { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
+ { eScriptLanguagePython, "python", "Commands are in the Python language."},
+ { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
+
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
+ "Specify whether breakpoint command execution should terminate on error." },
+
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
+ "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+
+ { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
+ "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "delete",
+ "Delete the set of commands from a breakpoint.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectBreakpointCommandDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist to have commands deleted");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified from which to delete the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ if (bp_loc_sp)
+ bp_loc_sp->ClearCallback();
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ bp->ClearCallback();
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommandList : public CommandObjectParsed
+{
+public:
+ CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "list",
+ "List the script or set of commands to be executed when the breakpoint is hit.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData bp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ bp_id_arg.arg_type = eArgTypeBreakpointID;
+ bp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (bp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectBreakpointCommandList () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const BreakpointList &breakpoints = target->GetBreakpointList();
+ size_t num_breakpoints = breakpoints.GetSize();
+
+ if (num_breakpoints == 0)
+ {
+ result.AppendError ("No breakpoints exist for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No breakpoint specified for which to list the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ BreakpointIDList valid_bp_ids;
+ CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
+
+ if (result.Succeeded())
+ {
+ const size_t count = valid_bp_ids.GetSize();
+ for (size_t i = 0; i < count; ++i)
+ {
+ BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
+ if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
+
+ if (bp)
+ {
+ const BreakpointOptions *bp_options = NULL;
+ if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
+ if (bp_loc_sp)
+ bp_options = bp_loc_sp->GetOptionsNoCreate();
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ bp_options = bp->GetOptions();
+ }
+
+ if (bp_options)
+ {
+ StreamString id_str;
+ BreakpointID::GetCanonicalReference (&id_str,
+ cur_bp_id.GetBreakpointID(),
+ cur_bp_id.GetLocationID());
+ const Baton *baton = bp_options->GetBaton();
+ if (baton)
+ {
+ result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
+ result.GetOutputStream().IndentMore ();
+ baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
+ result.GetOutputStream().IndentLess ();
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n",
+ id_str.GetData());
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectBreakpointCommand
+//-------------------------------------------------------------------------
+
+CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
+ "command <sub-command> [<sub-command-options>] <breakpoint-id>")
+{
+ CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter));
+ CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
+
+ add_command_object->SetCommandName ("breakpoint command add");
+ delete_command_object->SetCommandName ("breakpoint command delete");
+ list_command_object->SetCommandName ("breakpoint command list");
+
+ LoadSubCommand ("add", add_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("list", list_command_object);
+}
+
+CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
+{
+}
+
+
diff --git a/source/Commands/CommandObjectBreakpointCommand.h b/source/Commands/CommandObjectBreakpointCommand.h
new file mode 100644
index 000000000000..afedb7602cdd
--- /dev/null
+++ b/source/Commands/CommandObjectBreakpointCommand.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectBreakpointCommand.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_CommandObjectBreakpointCommand_h_
+#define liblldb_CommandObjectBreakpointCommand_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordBreakpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectBreakpointCommand : public CommandObjectMultiword
+{
+public:
+ CommandObjectBreakpointCommand (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectBreakpointCommand ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectBreakpointCommand_h_
diff --git a/source/Commands/CommandObjectCommands.cpp b/source/Commands/CommandObjectCommands.cpp
new file mode 100644
index 000000000000..4699aa6d9c4a
--- /dev/null
+++ b/source/Commands/CommandObjectCommands.cpp
@@ -0,0 +1,2021 @@
+//===-- CommandObjectSource.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 "CommandObjectCommands.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/InputReaderEZ.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandHistory.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObjectRegexCommand.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionValueBoolean.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsSource
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsHistory : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsHistory(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command history",
+ "Dump the history of commands in this session.",
+ NULL),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectCommandsHistory () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_start_idx(0),
+ m_stop_idx(0),
+ m_count(0),
+ m_clear(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 'c':
+ error = m_count.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 's':
+ if (option_arg && strcmp("end", option_arg) == 0)
+ {
+ m_start_idx.SetCurrentValue(UINT64_MAX);
+ m_start_idx.SetOptionWasSet();
+ }
+ else
+ error = m_start_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 'e':
+ error = m_stop_idx.SetValueFromCString(option_arg,eVarSetOperationAssign);
+ break;
+ case 'C':
+ m_clear.SetCurrentValue(true);
+ m_clear.SetOptionWasSet();
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_start_idx.Clear();
+ m_stop_idx.Clear();
+ m_count.Clear();
+ m_clear.Clear();
+ }
+
+ 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.
+
+ OptionValueUInt64 m_start_idx;
+ OptionValueUInt64 m_stop_idx;
+ OptionValueUInt64 m_count;
+ OptionValueBoolean m_clear;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ if (m_options.m_clear.GetCurrentValue() && m_options.m_clear.OptionWasSet())
+ {
+ m_interpreter.GetCommandHistory().Clear();
+ result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (m_options.m_start_idx.OptionWasSet() && m_options.m_stop_idx.OptionWasSet() && m_options.m_count.OptionWasSet())
+ {
+ result.AppendError("--count, --start-index and --end-index cannot be all specified in the same invocation");
+ result.SetStatus(lldb::eReturnStatusFailed);
+ }
+ else
+ {
+ std::pair<bool,uint64_t> start_idx = {m_options.m_start_idx.OptionWasSet(),m_options.m_start_idx.GetCurrentValue()};
+ std::pair<bool,uint64_t> stop_idx = {m_options.m_stop_idx.OptionWasSet(),m_options.m_stop_idx.GetCurrentValue()};
+ std::pair<bool,uint64_t> count = {m_options.m_count.OptionWasSet(),m_options.m_count.GetCurrentValue()};
+
+ const CommandHistory& history(m_interpreter.GetCommandHistory());
+
+ if (start_idx.first && start_idx.second == UINT64_MAX)
+ {
+ if (count.first)
+ {
+ start_idx.second = history.GetSize() - count.second;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else if (stop_idx.first)
+ {
+ start_idx.second = stop_idx.second;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else
+ {
+ start_idx.second = 0;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ }
+ else
+ {
+ if (!start_idx.first && !stop_idx.first && !count.first)
+ {
+ start_idx.second = 0;
+ stop_idx.second = history.GetSize() - 1;
+ }
+ else if (start_idx.first)
+ {
+ if (count.first)
+ {
+ stop_idx.second = start_idx.second + count.second - 1;
+ }
+ else if (!stop_idx.first)
+ {
+ stop_idx.second = history.GetSize() - 1;
+ }
+ }
+ else if (stop_idx.first)
+ {
+ if (count.first)
+ {
+ if (stop_idx.second >= count.second)
+ start_idx.second = stop_idx.second - count.second + 1;
+ else
+ start_idx.second = 0;
+ }
+ }
+ else /* if (count.first) */
+ {
+ start_idx.second = 0;
+ stop_idx.second = count.second - 1;
+ }
+ }
+ history.Dump(result.GetOutputStream(), start_idx.second, stop_idx.second);
+ }
+ }
+ return result.Succeeded();
+
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsHistory::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeUnsignedInteger, "How many history commands to print."},
+{ LLDB_OPT_SET_1, false, "start-index", 's', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to start printing history commands (or end to mean tail mode)."},
+{ LLDB_OPT_SET_1, false, "end-index", 'e', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Index at which to stop printing history commands."},
+{ LLDB_OPT_SET_2, false, "clear", 'C', no_argument, NULL, 0, eArgTypeBoolean, "Clears the current command history."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsSource
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsSource : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsSource(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command source",
+ "Read in debugger commands from the file <filename> and execute them.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectCommandsSource () {}
+
+ virtual const char*
+ GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ return "";
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_stop_on_error (true)
+ {
+ }
+
+ 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;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'e':
+ error = m_stop_on_error.SetValueFromCString(option_arg);
+ break;
+ case 'c':
+ m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-continue: %s", option_arg);
+ break;
+ case 's':
+ m_silent_run = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for silent-run: %s", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_stop_on_error.Clear();
+ m_silent_run = false;
+ m_stop_on_continue = true;
+ }
+
+ 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.
+
+ OptionValueBoolean m_stop_on_error;
+ bool m_silent_run;
+ bool m_stop_on_continue;
+ };
+
+ bool
+ DoExecute(Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 1)
+ {
+ const char *filename = command.GetArgumentAtIndex(0);
+
+ result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
+
+ FileSpec cmd_file (filename, true);
+ ExecutionContext *exe_ctx = NULL; // Just use the default context.
+ bool echo_commands = !m_options.m_silent_run;
+ bool print_results = true;
+ bool stop_on_error = m_options.m_stop_on_error.OptionWasSet() ? (bool)m_options.m_stop_on_error : m_interpreter.GetStopCmdSourceOnError();
+
+ m_interpreter.HandleCommandsFromFile (cmd_file,
+ exe_ctx,
+ m_options.m_stop_on_continue,
+ stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolCalculate,
+ result);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+ }
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsSource::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
+{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
+{ LLDB_OPT_SET_ALL, false, "silent-run", 's', required_argument, NULL, 0, eArgTypeBoolean, "If true don't echo commands while executing."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectCommandsAlias
+//-------------------------------------------------------------------------
+// CommandObjectCommandsAlias
+//-------------------------------------------------------------------------
+
+static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "You must define a Python function with this signature:\n"
+ "def my_command_impl(debugger, args, result, internal_dict):";
+
+
+class CommandObjectCommandsAlias : public CommandObjectRaw
+{
+
+
+public:
+ CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "command alias",
+ "Allow users to define their own debugger command abbreviations.",
+ NULL)
+ {
+ SetHelpLong(
+ "'alias' allows the user to create a short-cut or abbreviation for long \n\
+ commands, multi-word commands, and commands that take particular options. \n\
+ Below are some simple examples of how one might use the 'alias' command: \n\
+ \n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
+ // command. \n\
+ 'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
+ // command. Since breakpoint commands are two-word \n\
+ // commands, the user will still need to enter the \n\
+ // second word after 'bp', e.g. 'bp enable' or \n\
+ // 'bp delete'. \n\
+ 'command alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
+ // two-word command 'breakpoint list'. \n\
+ \nAn alias can include some options for the command, with the values either \n\
+ filled in at the time the alias is created, or specified as positional \n\
+ arguments, to be filled in when the alias is invoked. The following example \n\
+ shows how to create aliases with options: \n\
+ \n\
+ 'command alias bfl breakpoint set -f %1 -l %2' \n\
+ \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
+ options already part of the alias. So if the user wants to set a breakpoint \n\
+ by file and line without explicitly having to use the -f and -l options, the \n\
+ user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
+ for the actual arguments that will be passed when the alias command is used. \n\
+ The number in the placeholder refers to the position/order the actual value \n\
+ occupies when the alias is used. All the occurrences of '%1' in the alias \n\
+ will be replaced with the first argument, all the occurrences of '%2' in the \n\
+ alias will be replaced with the second argument, and so on. This also allows \n\
+ actual arguments to be used multiple times within an alias (see 'process \n\
+ launch' example below). \n\
+ Note: the positional arguments must substitute as whole words in the resultant\n\
+ command, so you can't at present do something like:\n\
+ \n\
+ command alias bcppfl breakpoint set -f %1.cpp -l %2\n\
+ \n\
+ to get the file extension \".cpp\" automatically appended. For more complex\n\
+ aliasing, use the \"command regex\" command instead.\n\
+ \nSo in the 'bfl' case, the actual file value will be \n\
+ filled in with the first argument following 'bfl' and the actual line number \n\
+ value will be filled in with the second argument. The user would use this \n\
+ alias as follows: \n\
+ \n (lldb) command alias bfl breakpoint set -f %1 -l %2 \n\
+ <... some time later ...> \n\
+ (lldb) bfl my-file.c 137 \n\
+ \nThis would be the same as if the user had entered \n\
+ 'breakpoint set -f my-file.c -l 137'. \n\
+ \nAnother example: \n\
+ \n (lldb) command alias pltty process launch -s -o %1 -e %1 \n\
+ (lldb) pltty /dev/tty0 \n\
+ // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
+ \nIf the user always wanted to pass the same value to a particular option, the \n\
+ alias could be defined with that value directly in the alias as a constant, \n\
+ rather than using a positional placeholder: \n\
+ \n command alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
+ // 3 of whatever file is indicated. \n");
+
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData alias_arg;
+ CommandArgumentData cmd_arg;
+ CommandArgumentData options_arg;
+
+ // Define the first (and only) variant of this arg.
+ alias_arg.arg_type = eArgTypeAliasName;
+ alias_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (alias_arg);
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (cmd_arg);
+
+ // Define the first (and only) variant of this arg.
+ options_arg.arg_type = eArgTypeAliasOptions;
+ options_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (options_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ ~CommandObjectCommandsAlias ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ Args args (raw_command_line);
+ std::string raw_command_string (raw_command_line);
+
+ size_t argc = args.GetArgumentCount();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'alias' requires at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Get the alias command.
+
+ const std::string alias_command = args.GetArgumentAtIndex (0);
+
+ // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which
+ // does the stripping itself.
+ size_t pos = raw_command_string.find (alias_command);
+ if (pos == 0)
+ {
+ raw_command_string = raw_command_string.substr (alias_command.size());
+ pos = raw_command_string.find_first_not_of (' ');
+ if ((pos != std::string::npos) && (pos > 0))
+ raw_command_string = raw_command_string.substr (pos);
+ }
+ else
+ {
+ result.AppendError ("Error parsing command string. No alias created.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+
+ // Verify that the command is alias-able.
+ if (m_interpreter.CommandExists (alias_command.c_str()))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
+ alias_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string.
+ // raw_command_string is returned with the name of the command object stripped off the front.
+ CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string);
+
+ if (!cmd_obj)
+ {
+ result.AppendErrorWithFormat ("invalid command given to 'alias'. '%s' does not begin with a valid command."
+ " No alias created.", raw_command_string.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!cmd_obj->WantsRawCommandString ())
+ {
+ // Note that args was initialized with the original command, and has not been updated to this point.
+ // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias.
+ return HandleAliasingNormalCommand (args, result);
+ }
+ else
+ {
+ return HandleAliasingRawCommand (alias_command, raw_command_string, *cmd_obj, result);
+ }
+ return result.Succeeded();
+ }
+
+ bool
+ HandleAliasingRawCommand (const std::string &alias_command, std::string &raw_command_string, CommandObject &cmd_obj, CommandReturnObject &result)
+ {
+ // Verify & handle any options/arguments passed to the alias command
+
+ OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj.GetCommandName(), false);
+
+ if (!m_interpreter.ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp))
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Create the alias
+ if (m_interpreter.AliasExists (alias_command.c_str())
+ || m_interpreter.UserCommandExists (alias_command.c_str()))
+ {
+ OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
+ if (temp_option_arg_sp.get())
+ {
+ if (option_arg_vector->size() == 0)
+ m_interpreter.RemoveAliasOptions (alias_command.c_str());
+ }
+ result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
+ alias_command.c_str());
+ }
+
+ if (cmd_obj_sp)
+ {
+ m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp);
+ if (option_arg_vector->size() > 0)
+ m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded ();
+ }
+
+ bool
+ HandleAliasingNormalCommand (Args& args, CommandReturnObject &result)
+ {
+ size_t argc = args.GetArgumentCount();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'alias' requires at least two arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const std::string alias_command = args.GetArgumentAtIndex(0);
+ const std::string actual_command = args.GetArgumentAtIndex(1);
+
+ args.Shift(); // Shift the alias command word off the argument vector.
+ args.Shift(); // Shift the old command word off the argument vector.
+
+ // Verify that the command is alias'able, and get the appropriate command object.
+
+ if (m_interpreter.CommandExists (alias_command.c_str()))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
+ alias_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
+ CommandObjectSP subcommand_obj_sp;
+ bool use_subcommand = false;
+ if (command_obj_sp.get())
+ {
+ CommandObject *cmd_obj = command_obj_sp.get();
+ CommandObject *sub_cmd_obj = NULL;
+ OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
+ {
+ if (argc >= 3)
+ {
+ const std::string sub_command = args.GetArgumentAtIndex(0);
+ assert (sub_command.length() != 0);
+ subcommand_obj_sp = cmd_obj->GetSubcommandSP (sub_command.c_str());
+ if (subcommand_obj_sp.get())
+ {
+ sub_cmd_obj = subcommand_obj_sp.get();
+ use_subcommand = true;
+ args.Shift(); // Shift the sub_command word off the argument vector.
+ cmd_obj = sub_cmd_obj;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. "
+ "Unable to create alias.\n",
+ sub_command.c_str(), actual_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ // Verify & handle any options/arguments passed to the alias command
+
+ if (args.GetArgumentCount () > 0)
+ {
+ CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
+ if (use_subcommand)
+ tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false);
+
+ std::string args_string;
+ args.GetCommandString (args_string);
+
+ if (!m_interpreter.ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp))
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ // Create the alias.
+
+ if (m_interpreter.AliasExists (alias_command.c_str())
+ || m_interpreter.UserCommandExists (alias_command.c_str()))
+ {
+ OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
+ if (tmp_option_arg_sp.get())
+ {
+ if (option_arg_vector->size() == 0)
+ m_interpreter.RemoveAliasOptions (alias_command.c_str());
+ }
+ result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
+ alias_command.c_str());
+ }
+
+ if (use_subcommand)
+ m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
+ else
+ m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
+ if (option_arg_vector->size() > 0)
+ m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+#pragma mark CommandObjectCommandsUnalias
+//-------------------------------------------------------------------------
+// CommandObjectCommandsUnalias
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsUnalias : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command unalias",
+ "Allow the user to remove/delete a user-defined command abbreviation.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData alias_arg;
+
+ // Define the first (and only) variant of this arg.
+ alias_arg.arg_type = eArgTypeAliasName;
+ 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);
+ }
+
+ ~CommandObjectCommandsUnalias()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+
+ if (args.GetArgumentCount() != 0)
+ {
+ const char *command_name = args.GetArgumentAtIndex(0);
+ cmd_obj = m_interpreter.GetCommandObject(command_name);
+ if (cmd_obj)
+ {
+ if (m_interpreter.CommandExists (command_name))
+ {
+ result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
+ command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+
+ if (m_interpreter.RemoveAlias (command_name) == false)
+ {
+ if (m_interpreter.AliasExists (command_name))
+ result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
+ command_name);
+ else
+ result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ 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.AppendError ("must call 'unalias' with a valid alias");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsAddRegex
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectCommandsAddRegex
+
+class CommandObjectCommandsAddRegex : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command regex",
+ "Allow the user to create a regular expression command.",
+ "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
+ m_options (interpreter)
+ {
+ SetHelpLong(
+"This command allows the user to create powerful regular expression commands\n"
+"with substitutions. The regular expressions and substitutions are specified\n"
+"using the regular exression substitution format of:\n"
+"\n"
+" s/<regex>/<subst>/\n"
+"\n"
+"<regex> is a regular expression that can use parenthesis to capture regular\n"
+"expression input and substitute the captured matches in the output using %1\n"
+"for the first match, %2 for the second, and so on.\n"
+"\n"
+"The regular expressions can all be specified on the command line if more than\n"
+"one argument is provided. If just the command name is provided on the command\n"
+"line, then the regular expressions and substitutions can be entered on separate\n"
+" lines, followed by an empty line to terminate the command definition.\n"
+"\n"
+"EXAMPLES\n"
+"\n"
+"The following example will define a regular expression command named 'f' that\n"
+"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n"
+"a number follows 'f':\n"
+"\n"
+" (lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n"
+"\n"
+ );
+ }
+
+ ~CommandObjectCommandsAddRegex()
+ {
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendError ("usage: 'command regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ Error error;
+ const char *name = command.GetArgumentAtIndex(0);
+ m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
+ name,
+ m_options.GetHelp (),
+ m_options.GetSyntax (),
+ 10));
+
+ if (argc == 1)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (reader_sp)
+ {
+ error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
+ this, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ "> ", // prompt
+ true); // echo input
+ if (error.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx)
+ {
+ llvm::StringRef arg_strref (command.GetArgumentAtIndex(arg_idx));
+ error = AppendRegexSubstitution (arg_strref);
+ if (error.Fail())
+ break;
+ }
+
+ if (error.Success())
+ {
+ AddRegexCommandToInterpreter();
+ }
+ }
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+ Error
+ AppendRegexSubstitution (const llvm::StringRef &regex_sed)
+ {
+ Error error;
+
+ if (m_regex_cmd_ap.get() == NULL)
+ {
+ error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+
+ size_t regex_sed_size = regex_sed.size();
+
+ if (regex_sed_size <= 1)
+ {
+ error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+
+ if (regex_sed[0] != 's')
+ {
+ error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'",
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ const size_t first_separator_char_pos = 1;
+ // use the char that follows 's' as the regex separator character
+ // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
+ const char separator_char = regex_sed[first_separator_char_pos];
+ const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
+
+ if (second_separator_char_pos == std::string::npos)
+ {
+ error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'",
+ separator_char,
+ (int)(regex_sed.size() - first_separator_char_pos - 1),
+ regex_sed.data() + (first_separator_char_pos + 1));
+ 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'",
+ separator_char,
+ (int)(regex_sed.size() - second_separator_char_pos - 1),
+ regex_sed.data() + (second_separator_char_pos + 1));
+ return error;
+ }
+
+ if (third_separator_char_pos != regex_sed_size - 1)
+ {
+ // Make sure that everything that follows the last regex
+ // separator char
+ if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos)
+ {
+ error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'",
+ (int)third_separator_char_pos + 1,
+ regex_sed.data(),
+ (int)(regex_sed.size() - third_separator_char_pos - 1),
+ regex_sed.data() + (third_separator_char_pos + 1));
+ return error;
+ }
+
+ }
+ else if (first_separator_char_pos + 1 == second_separator_char_pos)
+ {
+ error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
+ separator_char,
+ separator_char,
+ separator_char,
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ else if (second_separator_char_pos + 1 == third_separator_char_pos)
+ {
+ error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
+ separator_char,
+ separator_char,
+ separator_char,
+ (int)regex_sed.size(),
+ regex_sed.data());
+ return error;
+ }
+ std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
+ std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
+ m_regex_cmd_ap->AddRegexCommand (regex.c_str(),
+ subst.c_str());
+ return error;
+ }
+
+ void
+ AddRegexCommandToInterpreter()
+ {
+ if (m_regex_cmd_ap.get())
+ {
+ if (m_regex_cmd_ap->HasRegexEntries())
+ {
+ CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
+ m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
+ }
+ }
+ }
+
+ void
+ InputReaderDidCancel()
+ {
+ m_regex_cmd_ap.reset();
+ }
+
+ static size_t
+ InputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream ();
+ out_stream->Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:");
+ out_stream->Flush();
+ }
+ break;
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
+ --bytes_len;
+ if (bytes_len == 0)
+ reader.SetIsDone(true);
+ else if (bytes)
+ {
+ llvm::StringRef bytes_strref (bytes, bytes_len);
+ Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref));
+ if (error.Fail())
+ {
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf("error: %s\n", error.AsCString());
+ out_stream->Flush();
+ }
+ add_regex_cmd->InputReaderDidCancel ();
+ reader.SetIsDone (true);
+ }
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->PutCString("Regular expression command creations was cancelled.\n");
+ out_stream->Flush();
+ }
+ add_regex_cmd->InputReaderDidCancel ();
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ add_regex_cmd->AddRegexCommandToInterpreter();
+ break;
+ }
+
+ return bytes_len;
+ }
+
+private:
+ std::unique_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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 'h':
+ m_help.assign (option_arg);
+ break;
+ case 's':
+ m_syntax.assign (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_help.clear();
+ m_syntax.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ const char *
+ GetHelp ()
+ {
+ if (m_help.empty())
+ return NULL;
+ return m_help.c_str();
+ }
+ const char *
+ GetSyntax ()
+ {
+ if (m_syntax.empty())
+ return NULL;
+ return m_syntax.c_str();
+ }
+ // Instance variables to hold the values for command options.
+ protected:
+ std::string m_help;
+ std::string m_syntax;
+ };
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
+{ LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
+{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL }
+};
+
+
+class CommandObjectPythonFunction : public CommandObjectRaw
+{
+private:
+ std::string m_function_name;
+ ScriptedCommandSynchronicity m_synchro;
+ bool m_fetched_help_long;
+
+public:
+
+ CommandObjectPythonFunction (CommandInterpreter &interpreter,
+ std::string name,
+ std::string funct,
+ ScriptedCommandSynchronicity synch) :
+ CommandObjectRaw (interpreter,
+ name.c_str(),
+ (std::string("Run Python function ") + funct).c_str(),
+ NULL),
+ m_function_name(funct),
+ m_synchro(synch),
+ m_fetched_help_long(false)
+ {
+ }
+
+ virtual
+ ~CommandObjectPythonFunction ()
+ {
+ }
+
+ virtual bool
+ IsRemovable () const
+ {
+ return true;
+ }
+
+ const std::string&
+ GetFunctionName ()
+ {
+ return m_function_name;
+ }
+
+ ScriptedCommandSynchronicity
+ GetSynchronicity ()
+ {
+ return m_synchro;
+ }
+
+ virtual const char *
+ GetHelpLong ()
+ {
+ if (!m_fetched_help_long)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+ if (scripter)
+ {
+ std::string docstring;
+ m_fetched_help_long = scripter->GetDocumentationForItem(m_function_name.c_str(),docstring);
+ if (!docstring.empty())
+ SetHelpLong(docstring);
+ }
+ }
+ return CommandObjectRaw::GetHelpLong();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
+
+ Error error;
+
+ result.SetStatus(eReturnStatusInvalid);
+
+ if (!scripter || scripter->RunScriptBasedCommand(m_function_name.c_str(),
+ raw_command_line,
+ m_synchro,
+ result,
+ error) == false)
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ else
+ {
+ // Don't change the status if the command already set it...
+ if (result.GetStatus() == eReturnStatusInvalid)
+ {
+ if (result.GetOutputData() == NULL || result.GetOutputData()[0] == '\0')
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptImport
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptImport : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptImport (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script import",
+ "Import a scripting module in LLDB.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeFilename;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptImport ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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 'r':
+ m_allow_reload = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_allow_reload = true;
+ }
+
+ 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_allow_reload;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
+ {
+ result.AppendError ("only scripting language supported for module importing is currently Python");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script import' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string path = command.GetArgumentAtIndex(0);
+ Error error;
+
+ const bool init_session = true;
+ // FIXME: this is necessary because CommandObject::CheckRequirements() assumes that
+ // commands won't ever be recursively invoked, but it's actually possible to craft
+ // a Python script that does other "command script imports" in __lldb_init_module
+ // the real fix is to have recursive commands possible with a CommandInvocation object
+ // separate from the CommandObject itself, so that recursive command invocations
+ // won't stomp on each other (wrt to execution contents, options, and more)
+ m_exe_ctx.Clear();
+ if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
+ m_options.m_allow_reload,
+ init_session,
+ error))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("module importing failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectCommandsScriptImport::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "allow-reload", 'r', no_argument, NULL, 0, eArgTypeNone, "Allow the script to be loaded even if it was already loaded before. This argument exists for backwards compatibility, but reloading is always allowed, whether you specify it or not."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptAdd(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script add",
+ "Add a scripted function as an LLDB command.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptAdd ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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_funct_name = std::string(option_arg);
+ break;
+ case 's':
+ m_synchronous = (ScriptedCommandSynchronicity) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
+ if (!error.Success())
+ error.SetErrorStringWithFormat ("unrecognized value for synchronicity '%s'", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_funct_name = "";
+ m_synchronous = eScriptedCommandSynchronicitySynchronous;
+ }
+
+ 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.
+
+ std::string m_funct_name;
+ ScriptedCommandSynchronicity m_synchronous;
+ };
+
+private:
+ class PythonAliasReader : public InputReaderEZ
+ {
+ private:
+ CommandInterpreter& m_interpreter;
+ std::string m_cmd_name;
+ ScriptedCommandSynchronicity m_synchronous;
+ StringList m_user_input;
+ DISALLOW_COPY_AND_ASSIGN (PythonAliasReader);
+ public:
+ PythonAliasReader(Debugger& debugger,
+ CommandInterpreter& interpreter,
+ std::string cmd_name,
+ ScriptedCommandSynchronicity synch) :
+ InputReaderEZ(debugger),
+ m_interpreter(interpreter),
+ m_cmd_name(cmd_name),
+ m_synchronous(synch),
+ m_user_input()
+ {}
+
+ virtual
+ ~PythonAliasReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_python_command_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.bytes && data.bytes_len)
+ {
+ m_user_input.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No script attached.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("Script interpreter missing: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string funct_name_str;
+ if (!interpreter->GenerateScriptAliasFunction (m_user_input,
+ funct_name_str))
+ {
+ out_stream->Printf ("Unable to create function: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (funct_name_str.empty())
+ {
+ out_stream->Printf ("Unable to obtain a function name: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ // everything should be fine now, let's add this alias
+
+ CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(m_interpreter,
+ m_cmd_name,
+ funct_name_str.c_str(),
+ m_synchronous));
+
+ if (!m_interpreter.AddUserCommand(m_cmd_name, command_obj_sp, true))
+ {
+ out_stream->Printf ("Unable to add selected command: no script attached.\n");
+ out_stream->Flush();
+ return;
+ }
+ }
+ };
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_interpreter.GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython)
+ {
+ result.AppendError ("only scripting language supported for scripted commands is currently Python");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script add' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string cmd_name = command.GetArgumentAtIndex(0);
+
+ if (m_options.m_funct_name.empty())
+ {
+ InputReaderSP reader_sp (new PythonAliasReader (m_interpreter.GetDebugger(),
+ m_interpreter,
+ cmd_name,
+ m_options.m_synchronous));
+
+ if (reader_sp)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(NULL).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ CommandObjectSP new_cmd(new CommandObjectPythonFunction(m_interpreter,
+ cmd_name,
+ m_options.m_funct_name,
+ m_options.m_synchronous));
+ if (m_interpreter.AddUserCommand(cmd_name, new_cmd, true))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("cannot add command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+
+ return result.Succeeded();
+
+ }
+
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement g_script_synchro_type[] =
+{
+ { eScriptedCommandSynchronicitySynchronous, "synchronous", "Run synchronous"},
+ { eScriptedCommandSynchronicityAsynchronous, "asynchronous", "Run asynchronous"},
+ { eScriptedCommandSynchronicityCurrentValue, "current", "Do not alter current setting"},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectCommandsScriptAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "function", 'f', required_argument, NULL, 0, eArgTypePythonFunction, "Name of the Python function to bind to this command name."},
+ { LLDB_OPT_SET_1, false, "synchronicity", 's', required_argument, g_script_synchro_type, 0, eArgTypeScriptedCommandSynchronicity, "Set the synchronicity of this command's executions with regard to LLDB event system."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptList
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptList : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectCommandsScriptList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script list",
+ "List defined scripted commands.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectCommandsScriptList ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ m_interpreter.GetHelp(result,
+ CommandInterpreter::eCommandTypesUserDef);
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ return true;
+
+
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptClear
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptClear : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectCommandsScriptClear(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script clear",
+ "Delete all scripted commands.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectCommandsScriptClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ m_interpreter.RemoveAllUser();
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ return true;
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectCommandsScriptDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectCommandsScriptDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectCommandsScriptDelete(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "command script delete",
+ "Delete a scripted command.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeCommandName;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectCommandsScriptDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'command script delete' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char* cmd_name = command.GetArgumentAtIndex(0);
+
+ if (cmd_name && *cmd_name && m_interpreter.HasUserCommands() && m_interpreter.UserCommandExists(cmd_name))
+ {
+ m_interpreter.RemoveUser(cmd_name);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("command %s not found", cmd_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+
+ }
+};
+
+#pragma mark CommandObjectMultiwordCommandsScript
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommandsScript
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordCommandsScript : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordCommandsScript (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command script",
+ "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 ("list", CommandObjectSP (new CommandObjectCommandsScriptList (interpreter)));
+ LoadSubCommand ("import", CommandObjectSP (new CommandObjectCommandsScriptImport (interpreter)));
+ }
+
+ ~CommandObjectMultiwordCommandsScript ()
+ {
+ }
+
+};
+
+
+#pragma mark CommandObjectMultiwordCommands
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommands
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for managing or customizing the debugger commands.",
+ "command <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
+ LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
+ LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
+ LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectCommandsHistory (interpreter)));
+ LoadSubCommand ("script", CommandObjectSP (new CommandObjectMultiwordCommandsScript (interpreter)));
+}
+
+CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
+{
+}
+
diff --git a/source/Commands/CommandObjectCommands.h b/source/Commands/CommandObjectCommands.h
new file mode 100644
index 000000000000..8a56e8dae6ff
--- /dev/null
+++ b/source/Commands/CommandObjectCommands.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectCommands.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_CommandObjectCommands_h_
+#define liblldb_CommandObjectCommands_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordCommands
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordCommands : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordCommands (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordCommands ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectCommands_h_
diff --git a/source/Commands/CommandObjectDisassemble.cpp b/source/Commands/CommandObjectDisassemble.cpp
new file mode 100644
index 000000000000..0d40fcd7c0b5
--- /dev/null
+++ b/source/Commands/CommandObjectDisassemble.cpp
@@ -0,0 +1,574 @@
+//===-- CommandObjectDisassemble.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 "CommandObjectDisassemble.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+#define DEFAULT_DISASM_NUM_INS 4
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectDisassemble::CommandOptions::CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ num_lines_context(0),
+ num_instructions (0),
+ func_name(),
+ current_function (false),
+ start_addr(),
+ end_addr (),
+ at_pc (false),
+ frame_line (false),
+ plugin_name (),
+ flavor_string(),
+ arch(),
+ some_location_specified (false),
+ symbol_containing_addr ()
+{
+ OptionParsingStarting();
+}
+
+CommandObjectDisassemble::CommandOptions::~CommandOptions ()
+{
+}
+
+Error
+CommandObjectDisassemble::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ bool success;
+
+ switch (short_option)
+ {
+ case 'm':
+ show_mixed = true;
+ break;
+
+ case 'C':
+ num_lines_context = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid num context lines string: \"%s\"", option_arg);
+ break;
+
+ case 'c':
+ num_instructions = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid num of instructions string: \"%s\"", option_arg);
+ break;
+
+ case 'b':
+ show_bytes = true;
+ break;
+
+ case 's':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ start_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (start_addr != LLDB_INVALID_ADDRESS)
+ some_location_specified = true;
+ }
+ break;
+ case 'e':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ end_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (end_addr != LLDB_INVALID_ADDRESS)
+ some_location_specified = true;
+ }
+ break;
+ case 'n':
+ func_name.assign (option_arg);
+ some_location_specified = true;
+ break;
+
+ case 'p':
+ at_pc = true;
+ some_location_specified = true;
+ break;
+
+ case 'l':
+ frame_line = true;
+ // Disassemble the current source line kind of implies showing mixed
+ // source code context.
+ show_mixed = true;
+ some_location_specified = true;
+ break;
+
+ case 'P':
+ plugin_name.assign (option_arg);
+ break;
+
+ case 'F':
+ {
+ Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
+ if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
+ || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ flavor_string.assign (option_arg);
+ }
+ else
+ error.SetErrorStringWithFormat("Disassembler flavors are currently only supported for x86 and x86_64 targets.");
+ break;
+ }
+ case 'r':
+ raw = true;
+ break;
+
+ case 'f':
+ current_function = true;
+ some_location_specified = true;
+ break;
+
+ case 'A':
+ if (!arch.SetTriple (option_arg, m_interpreter.GetPlatform (true).get()))
+ arch.SetTriple (option_arg);
+ break;
+
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ symbol_containing_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (symbol_containing_addr != LLDB_INVALID_ADDRESS)
+ {
+ some_location_specified = true;
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectDisassemble::CommandOptions::OptionParsingStarting ()
+{
+ show_mixed = false;
+ show_bytes = false;
+ num_lines_context = 0;
+ num_instructions = 0;
+ func_name.clear();
+ current_function = false;
+ at_pc = false;
+ frame_line = false;
+ start_addr = LLDB_INVALID_ADDRESS;
+ end_addr = LLDB_INVALID_ADDRESS;
+ symbol_containing_addr = LLDB_INVALID_ADDRESS;
+ raw = false;
+ plugin_name.clear();
+
+ Target *target = m_interpreter.GetExecutionContext().GetTargetPtr();
+
+ // This is a hack till we get the ability to specify features based on architecture. For now GetDisassemblyFlavor
+ // is really only valid for x86 (and for the llvm assembler plugin, but I'm papering over that since that is the
+ // only disassembler plugin we have...
+ if (target)
+ {
+ if (target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86
+ || target->GetArchitecture().GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ flavor_string.assign(target->GetDisassemblyFlavor());
+ }
+ else
+ flavor_string.assign ("default");
+
+ }
+ else
+ flavor_string.assign("default");
+
+ arch.Clear();
+ some_location_specified = false;
+}
+
+Error
+CommandObjectDisassemble::CommandOptions::OptionParsingFinished ()
+{
+ if (!some_location_specified)
+ current_function = true;
+ return Error();
+
+}
+
+const OptionDefinition*
+CommandObjectDisassemble::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+OptionDefinition
+CommandObjectDisassemble::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "bytes" , 'b', no_argument , NULL, 0, eArgTypeNone, "Show opcode bytes when disassembling."},
+{ LLDB_OPT_SET_ALL, false, "context" , 'C', required_argument , NULL, 0, eArgTypeNumLines, "Number of context lines of source to show."},
+{ LLDB_OPT_SET_ALL, false, "mixed" , 'm', no_argument , NULL, 0, eArgTypeNone, "Enable mixed source and assembly display."},
+{ LLDB_OPT_SET_ALL, false, "raw" , 'r', no_argument , NULL, 0, eArgTypeNone, "Print raw disassembly with no symbol information."},
+{ LLDB_OPT_SET_ALL, false, "plugin" , 'P', required_argument , NULL, 0, eArgTypePlugin, "Name of the disassembler plugin you want to use."},
+{ LLDB_OPT_SET_ALL, false, "flavor" , 'F', required_argument , NULL, 0, eArgTypeDisassemblyFlavor, "Name of the disassembly flavor you want to use. "
+ "Currently the only valid options are default, and for Intel"
+ " architectures, att and intel."},
+{ LLDB_OPT_SET_ALL, false, "arch" , 'A', required_argument , NULL, 0, eArgTypeArchitecture,"Specify the architecture to use from cross disassembly."},
+{ LLDB_OPT_SET_1 |
+ LLDB_OPT_SET_2 , true , "start-address", 's', required_argument , NULL, 0, eArgTypeAddressOrExpression,"Address at which to start disassembling."},
+{ LLDB_OPT_SET_1 , false, "end-address" , 'e', required_argument , NULL, 0, eArgTypeAddressOrExpression, "Address at which to end disassembling."},
+{ LLDB_OPT_SET_2 |
+ LLDB_OPT_SET_3 |
+ LLDB_OPT_SET_4 |
+ LLDB_OPT_SET_5 , false, "count" , 'c', required_argument , NULL, 0, eArgTypeNumLines, "Number of instructions to display."},
+{ LLDB_OPT_SET_3 , false, "name" , 'n', required_argument , NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Disassemble entire contents of the given function name."},
+{ LLDB_OPT_SET_4 , false, "frame" , 'f', no_argument , NULL, 0, eArgTypeNone, "Disassemble from the start of the current frame's function."},
+{ LLDB_OPT_SET_5 , false, "pc" , 'p', no_argument , NULL, 0, eArgTypeNone, "Disassemble around the current pc."},
+{ LLDB_OPT_SET_6 , false, "line" , 'l', no_argument , NULL, 0, eArgTypeNone, "Disassemble the current frame's current source line instructions if there debug line table information, else disasemble around the pc."},
+{ LLDB_OPT_SET_7 , false, "address" , 'a', required_argument , NULL, 0, eArgTypeAddressOrExpression, "Disassemble function containing this address."},
+{ 0 , false, NULL , 0, 0 , NULL, 0, eArgTypeNone, NULL }
+};
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+CommandObjectDisassemble::CommandObjectDisassemble (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "disassemble",
+ "Disassemble bytes in the current function, or elsewhere in the executable program as specified by the user.",
+ "disassemble [<cmd-options>]"),
+ m_options (interpreter)
+{
+}
+
+CommandObjectDisassemble::~CommandObjectDisassemble()
+{
+}
+
+bool
+CommandObjectDisassemble::DoExecute (Args& command, CommandReturnObject &result)
+{
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (!m_options.arch.IsValid())
+ m_options.arch = target->GetArchitecture();
+
+ if (!m_options.arch.IsValid())
+ {
+ result.AppendError ("use the --arch option or set the target architecure to disassemble");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *plugin_name = m_options.GetPluginName ();
+ const char *flavor_string = m_options.GetFlavorString();
+
+ DisassemblerSP disassembler = Disassembler::FindPlugin(m_options.arch, flavor_string, plugin_name);
+
+ if (!disassembler)
+ {
+ if (plugin_name)
+ {
+ result.AppendErrorWithFormat ("Unable to find Disassembler plug-in named '%s' that supports the '%s' architecture.\n",
+ plugin_name,
+ m_options.arch.GetArchitectureName());
+ }
+ else
+ result.AppendErrorWithFormat ("Unable to find Disassembler plug-in for the '%s' architecture.\n",
+ m_options.arch.GetArchitectureName());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (flavor_string != NULL && !disassembler->FlavorValidForArchSpec(m_options.arch, flavor_string))
+ result.AppendWarningWithFormat("invalid disassembler flavor \"%s\", using default.\n", flavor_string);
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendErrorWithFormat ("\"disassemble\" arguments are specified as options.\n");
+ GetOptions()->GenerateOptionUsage (result.GetErrorStream(), this);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.show_mixed && m_options.num_lines_context == 0)
+ m_options.num_lines_context = 1;
+
+ // Always show the PC in the disassembly
+ uint32_t options = Disassembler::eOptionMarkPCAddress;
+
+ // Mark the source line for the current PC only if we are doing mixed source and assembly
+ if (m_options.show_mixed)
+ options |= Disassembler::eOptionMarkPCSourceLine;
+
+ if (m_options.show_bytes)
+ options |= Disassembler::eOptionShowBytes;
+
+ if (m_options.raw)
+ options |= Disassembler::eOptionRawOuput;
+
+ if (!m_options.func_name.empty())
+ {
+ ConstString name(m_options.func_name.c_str());
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ name,
+ NULL, // Module *
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find symbol with name '%s'.\n", name.GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ AddressRange range;
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (m_options.frame_line)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current line without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ LineEntry pc_line_entry (frame->GetSymbolContext(eSymbolContextLineEntry).line_entry);
+ if (pc_line_entry.IsValid())
+ {
+ range = pc_line_entry.range;
+ }
+ else
+ {
+ m_options.at_pc = true; // No line entry, so just disassemble around the current pc
+ m_options.show_mixed = false;
+ }
+ }
+ else if (m_options.current_function)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current function without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ Symbol *symbol = frame->GetSymbolContext(eSymbolContextSymbol).symbol;
+ if (symbol)
+ {
+ range.GetBaseAddress() = symbol->GetAddress();
+ range.SetByteSize(symbol->GetByteSize());
+ }
+ }
+
+ // Did the "m_options.frame_line" find a valid range already? If so
+ // skip the rest...
+ if (range.GetByteSize() == 0)
+ {
+ if (m_options.at_pc)
+ {
+ if (frame == NULL)
+ {
+ result.AppendError ("Cannot disassemble around the current PC without a selected frame.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ if (m_options.num_instructions == 0)
+ {
+ // Disassembling at the PC always disassembles some number of instructions (not the whole function).
+ m_options.num_instructions = DEFAULT_DISASM_NUM_INS;
+ }
+ }
+ else
+ {
+ range.GetBaseAddress().SetOffset (m_options.start_addr);
+ if (range.GetBaseAddress().IsValid())
+ {
+ if (m_options.end_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (m_options.end_addr <= m_options.start_addr)
+ {
+ result.AppendErrorWithFormat ("End address before start address.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ range.SetByteSize (m_options.end_addr - m_options.start_addr);
+ }
+ }
+ else
+ {
+ if (m_options.symbol_containing_addr != LLDB_INVALID_ADDRESS
+ && target
+ && !target->GetSectionLoadList().IsEmpty())
+ {
+ bool failed = false;
+ Address symbol_containing_address;
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.symbol_containing_addr, symbol_containing_address))
+ {
+ ModuleSP module_sp (symbol_containing_address.GetModule());
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress (symbol_containing_address, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range);
+ }
+ else
+ {
+ failed = true;
+ }
+ }
+ else
+ {
+ failed = true;
+ }
+ if (failed)
+ {
+ result.AppendErrorWithFormat ("Could not find function bounds for address 0x%" PRIx64 "\n", m_options.symbol_containing_addr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ if (m_options.num_instructions != 0)
+ {
+ if (!range.GetBaseAddress().IsValid())
+ {
+ // The default action is to disassemble the current frame function.
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ range.GetBaseAddress() = sc.function->GetAddressRange().GetBaseAddress();
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ else
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+
+ if (!range.GetBaseAddress().IsValid())
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ range.GetBaseAddress(),
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ if (!range.GetBaseAddress().IsValid())
+ {
+ // The default action is to disassemble the current frame function.
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ range = sc.function->GetAddressRange();
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.SetByteSize (sc.symbol->GetByteSize());
+ }
+ else
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+ else
+ {
+ result.AppendError ("invalid frame");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ if (range.GetByteSize() == 0)
+ range.SetByteSize(DEFAULT_DISASM_BYTE_SIZE);
+
+ if (Disassembler::Disassemble (m_interpreter.GetDebugger(),
+ m_options.arch,
+ plugin_name,
+ flavor_string,
+ m_exe_ctx,
+ range,
+ m_options.num_instructions,
+ m_options.show_mixed ? m_options.num_lines_context : 0,
+ options,
+ result.GetOutputStream()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to disassemble memory at 0x%8.8" PRIx64 ".\n", m_options.start_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
diff --git a/source/Commands/CommandObjectDisassemble.h b/source/Commands/CommandObjectDisassemble.h
new file mode 100644
index 000000000000..7a7509858b98
--- /dev/null
+++ b/source/Commands/CommandObjectDisassemble.h
@@ -0,0 +1,110 @@
+//===-- CommandObjectDisassemble.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_CommandObjectDisassemble_h_
+#define liblldb_CommandObjectDisassemble_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectDisassemble
+//-------------------------------------------------------------------------
+
+class CommandObjectDisassemble : public CommandObjectParsed
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandOptions ();
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ const OptionDefinition*
+ GetDefinitions ();
+
+ const char *
+ GetPluginName ()
+ {
+ if (plugin_name.empty())
+ return NULL;
+ return plugin_name.c_str();
+ }
+
+ const char *
+ GetFlavorString ()
+ {
+ if (flavor_string.empty() || flavor_string == "default")
+ return NULL;
+ return flavor_string.c_str();
+ }
+
+ virtual Error
+ OptionParsingFinished ();
+
+ bool show_mixed; // Show mixed source/assembly
+ bool show_bytes;
+ uint32_t num_lines_context;
+ uint32_t num_instructions;
+ bool raw;
+ std::string func_name;
+ bool current_function;
+ lldb::addr_t start_addr;
+ lldb::addr_t end_addr;
+ bool at_pc;
+ bool frame_line;
+ std::string plugin_name;
+ std::string flavor_string;
+ ArchSpec arch;
+ bool some_location_specified; // If no location was specified, we'll select "at_pc". This should be set
+ // in SetOptionValue if anything the selects a location is set.
+ lldb::addr_t symbol_containing_addr;
+ static OptionDefinition g_option_table[];
+ };
+
+ CommandObjectDisassemble (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectDisassemble ();
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+ CommandOptions m_options;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectDisassemble_h_
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
new file mode 100644
index 000000000000..da472d17331b
--- /dev/null
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -0,0 +1,505 @@
+//===-- CommandObjectExpression.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 "CommandObjectExpression.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CommandObjectExpression::CommandOptions::CommandOptions () :
+ OptionGroup()
+{
+}
+
+
+CommandObjectExpression::CommandOptions::~CommandOptions ()
+{
+}
+
+OptionDefinition
+CommandObjectExpression::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', required_argument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "ignore-breakpoints", 'i', required_argument, NULL, 0, eArgTypeBoolean, "Ignore breakpoint hits while running expressions"},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value (in microseconds) for running the expression."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, or raises a signal. Note, unlike gdb hitting a breakpoint is controlled by another option (-i)."},
+};
+
+
+uint32_t
+CommandObjectExpression::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table)/sizeof(OptionDefinition);
+}
+
+Error
+CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ //case 'l':
+ //if (language.SetLanguageFromCString (option_arg) == false)
+ //{
+ // error.SetErrorStringWithFormat("invalid language option argument '%s'", option_arg);
+ //}
+ //break;
+
+ case 'a':
+ {
+ bool success;
+ bool result;
+ result = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg);
+ else
+ try_all_threads = result;
+ }
+ break;
+
+ case 'i':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ ignore_breakpoints = tmp_value;
+ else
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
+ break;
+ }
+ case 't':
+ {
+ bool success;
+ uint32_t result;
+ result = Args::StringToUInt32(option_arg, 0, 0, &success);
+ if (success)
+ timeout = result;
+ else
+ error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg);
+ }
+ break;
+
+ case 'u':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ unwind_on_error = tmp_value;
+ else
+ error.SetErrorStringWithFormat("could not convert \"%s\" to a boolean value.", option_arg);
+ break;
+ }
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ Process *process = interpreter.GetExecutionContext().GetProcessPtr();
+ if (process != NULL)
+ {
+ ignore_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+ unwind_on_error = process->GetUnwindOnErrorInExpressions();
+ }
+ else
+ {
+ ignore_breakpoints = false;
+ unwind_on_error = true;
+ }
+
+ show_summary = true;
+ try_all_threads = true;
+ timeout = 0;
+}
+
+const OptionDefinition*
+CommandObjectExpression::CommandOptions::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "expression",
+ "Evaluate a C/ObjC/C++ expression in the current program context, using user defined variables and variables currently in scope.",
+ NULL,
+ eFlagProcessMustBePaused | eFlagTryTargetAPILock),
+ m_option_group (interpreter),
+ m_format_options (eFormatDefault),
+ m_command_options (),
+ m_expr_line_count (0),
+ m_expr_lines ()
+{
+ SetHelpLong(
+"Timeouts:\n\
+ If the expression can be evaluated statically (without runnning code) then it will be.\n\
+ Otherwise, by default the expression will run on the current thread with a short timeout:\n\
+ currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\
+ and resumed with all threads running. You can use the -a option to disable retrying on all\n\
+ threads. You can use the -t option to set a shorter timeout.\n\
+\n\
+User defined variables:\n\
+ You can define your own variables for convenience or to be used in subsequent expressions.\n\
+ You define them the same way you would define variables in C. If the first character of \n\
+ your user defined variable is a $, then the variable's value will be available in future\n\
+ expressions, otherwise it will just be available in the current expression.\n\
+\n\
+Examples: \n\
+\n\
+ expr my_struct->a = my_array[3] \n\
+ expr -f bin -- (index * 8) + 5 \n\
+ expr unsigned int $foo = 5\n\
+ expr char c[] = \"foo\"; c[0]\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the first (and only) variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Add the "--format" and "--gdb-format"
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+}
+
+CommandObjectExpression::~CommandObjectExpression ()
+{
+}
+
+Options *
+CommandObjectExpression::GetOptions ()
+{
+ return &m_option_group;
+}
+
+size_t
+CommandObjectExpression::MultiLineExpressionCallback
+(
+ void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ CommandObjectExpression *cmd_object_expr = (CommandObjectExpression *) baton;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ StreamSP async_strm_sp(reader.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ async_strm_sp->PutCString("Enter expressions, then terminate with an empty line to evaluate:\n");
+ async_strm_sp->Flush();
+ }
+ }
+ // Fall through
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ ++cmd_object_expr->m_expr_line_count;
+ if (bytes && bytes_len)
+ {
+ cmd_object_expr->m_expr_lines.append (bytes, bytes_len + 1);
+ }
+
+ if (bytes_len == 0)
+ reader.SetIsDone(true);
+ break;
+
+ case eInputReaderInterrupt:
+ cmd_object_expr->m_expr_lines.clear();
+ reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ StreamSP async_strm_sp (reader.GetDebugger().GetAsyncOutputStream());
+ if (async_strm_sp)
+ {
+ async_strm_sp->PutCString("Expression evaluation cancelled.\n");
+ async_strm_sp->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ if (cmd_object_expr->m_expr_lines.size() > 0)
+ {
+ StreamSP output_stream = reader.GetDebugger().GetAsyncOutputStream();
+ StreamSP error_stream = reader.GetDebugger().GetAsyncErrorStream();
+ cmd_object_expr->EvaluateExpression (cmd_object_expr->m_expr_lines.c_str(),
+ output_stream.get(),
+ error_stream.get());
+ output_stream->Flush();
+ error_stream->Flush();
+ }
+ break;
+ }
+
+ return bytes_len;
+}
+
+bool
+CommandObjectExpression::EvaluateExpression
+(
+ const char *expr,
+ Stream *output_stream,
+ Stream *error_stream,
+ CommandReturnObject *result
+)
+{
+ // Don't use m_exe_ctx as this might be called asynchronously
+ // after the command object DoExecute has finished when doing
+ // multi-line expression that use an input reader...
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ target = Host::GetDummyTarget(m_interpreter.GetDebugger()).get();
+
+ if (target)
+ {
+ lldb::ValueObjectSP result_valobj_sp;
+
+ ExecutionResults exe_results;
+
+ bool keep_in_memory = true;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(m_varobj_options.use_objc)
+ .SetUnwindOnError(m_command_options.unwind_on_error)
+ .SetIgnoreBreakpoints (m_command_options.ignore_breakpoints)
+ .SetKeepInMemory(keep_in_memory)
+ .SetUseDynamic(m_varobj_options.use_dynamic)
+ .SetRunOthers(m_command_options.try_all_threads)
+ .SetTimeoutUsec(m_command_options.timeout);
+
+ exe_results = target->EvaluateExpression (expr,
+ exe_ctx.GetFramePtr(),
+ result_valobj_sp,
+ options);
+
+ if (result_valobj_sp)
+ {
+ Format format = m_format_options.GetFormat();
+
+ if (result_valobj_sp->GetError().Success())
+ {
+ if (format != eFormatVoid)
+ {
+ if (format != eFormatDefault)
+ result_valobj_sp->SetFormat (format);
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(true,format));
+
+ ValueObject::DumpValueObject (*(output_stream),
+ result_valobj_sp.get(), // Variable object to dump
+ options);
+ if (result)
+ result->SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ if (result_valobj_sp->GetError().GetError() == ClangUserExpression::kNoResult)
+ {
+ if (format != eFormatVoid && m_interpreter.GetDebugger().GetNotifyVoid())
+ {
+ error_stream->PutCString("(void)\n");
+ }
+
+ if (result)
+ result->SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ const char *error_cstr = result_valobj_sp->GetError().AsCString();
+ if (error_cstr && error_cstr[0])
+ {
+ const size_t error_cstr_len = strlen (error_cstr);
+ const bool ends_with_newline = error_cstr[error_cstr_len - 1] == '\n';
+ if (strstr(error_cstr, "error:") != error_cstr)
+ error_stream->PutCString ("error: ");
+ error_stream->Write(error_cstr, error_cstr_len);
+ if (!ends_with_newline)
+ error_stream->EOL();
+ }
+ else
+ {
+ error_stream->PutCString ("error: unknown error\n");
+ }
+
+ if (result)
+ result->SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ error_stream->Printf ("error: invalid execution context for expression\n");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+CommandObjectExpression::DoExecute
+(
+ const char *command,
+ CommandReturnObject &result
+)
+{
+ m_option_group.NotifyOptionParsingStarting();
+
+ const char * expr = NULL;
+
+ if (command[0] == '\0')
+ {
+ m_expr_lines.clear();
+ m_expr_line_count = 0;
+
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (reader_sp)
+ {
+ Error err (reader_sp->Initialize (CommandObjectExpression::MultiLineExpressionCallback,
+ this, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ NULL, // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ if (command[0] == '-')
+ {
+ // We have some options and these options MUST end with --.
+ const char *end_options = NULL;
+ const char *s = command;
+ while (s && s[0])
+ {
+ end_options = ::strstr (s, "--");
+ if (end_options)
+ {
+ end_options += 2; // Get past the "--"
+ if (::isspace (end_options[0]))
+ {
+ expr = end_options;
+ while (::isspace (*expr))
+ ++expr;
+ break;
+ }
+ }
+ s = end_options;
+ }
+
+ if (end_options)
+ {
+ Args args (command, end_options - command);
+ if (!ParseOptions (args, result))
+ return false;
+
+ Error error (m_option_group.NotifyOptionParsingFinished());
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (expr == NULL)
+ expr = command;
+
+ if (EvaluateExpression (expr, &(result.GetOutputStream()), &(result.GetErrorStream()), &result))
+ return true;
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+}
+
diff --git a/source/Commands/CommandObjectExpression.h b/source/Commands/CommandObjectExpression.h
new file mode 100644
index 000000000000..3964f2d423eb
--- /dev/null
+++ b/source/Commands/CommandObjectExpression.h
@@ -0,0 +1,99 @@
+//===-- CommandObjectExpression.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_CommandObjectExpression_h_
+#define liblldb_CommandObjectExpression_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Target/ExecutionContext.h"
+
+namespace lldb_private {
+
+class CommandObjectExpression : public CommandObjectRaw
+{
+public:
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+
+ CommandOptions ();
+
+ virtual
+ ~CommandOptions ();
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ();
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value);
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter);
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ bool unwind_on_error;
+ bool ignore_breakpoints;
+ bool show_types;
+ bool show_summary;
+ uint32_t timeout;
+ bool try_all_threads;
+ };
+
+ CommandObjectExpression (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectExpression ();
+
+ virtual
+ Options *
+ GetOptions ();
+
+protected:
+ virtual bool
+ DoExecute (const char *command,
+ CommandReturnObject &result);
+
+ static size_t
+ MultiLineExpressionCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ bool
+ EvaluateExpression (const char *expr,
+ Stream *output_stream,
+ Stream *error_stream,
+ CommandReturnObject *result = NULL);
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupValueObjectDisplay m_varobj_options;
+ CommandOptions m_command_options;
+ uint32_t m_expr_line_count;
+ std::string m_expr_lines; // Multi-line expression support
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectExpression_h_
diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp
new file mode 100644
index 000000000000..aace3a649602
--- /dev/null
+++ b/source/Commands/CommandObjectFrame.cpp
@@ -0,0 +1,624 @@
+//===-- CommandObjectFrame.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 "CommandObjectFrame.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Interpreter/OptionGroupVariable.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark CommandObjectFrameInfo
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameInfo : public CommandObjectParsed
+{
+public:
+
+ CommandObjectFrameInfo (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame info",
+ "List information about the currently selected frame in the current thread.",
+ "frame info",
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectFrameInfo ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat (&result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectFrameSelect
+
+//-------------------------------------------------------------------------
+// CommandObjectFrameSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectFrameSelect : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ bool success = false;
+ const int short_option = m_getopt_table[option_idx].val;
+ switch (short_option)
+ {
+ case 'r':
+ relative_frame_offset = Args::StringToSInt32 (option_arg, INT32_MIN, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid frame offset argument '%s'", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("invalid short option character '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ relative_frame_offset = INT32_MIN;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ int32_t relative_frame_offset;
+ };
+
+ CommandObjectFrameSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame select",
+ "Select a frame by index from within the current thread and make it the current frame.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData index_arg;
+
+ // Define the first (and only) variant of this arg.
+ index_arg.arg_type = eArgTypeFrameIndex;
+ index_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (index_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectFrameSelect ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "thread" for validity as eFlagRequiresThread ensures it is valid
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+
+ uint32_t frame_idx = UINT32_MAX;
+ if (m_options.relative_frame_offset != INT32_MIN)
+ {
+ // The one and only argument is a signed relative frame index
+ frame_idx = thread->GetSelectedFrameIndex ();
+ if (frame_idx == UINT32_MAX)
+ frame_idx = 0;
+
+ if (m_options.relative_frame_offset < 0)
+ {
+ if (frame_idx >= -m_options.relative_frame_offset)
+ frame_idx += m_options.relative_frame_offset;
+ else
+ {
+ if (frame_idx == 0)
+ {
+ //If you are already at the bottom of the stack, then just warn and don't reset the frame.
+ result.AppendError("Already at the bottom of the stack");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ frame_idx = 0;
+ }
+ }
+ else if (m_options.relative_frame_offset > 0)
+ {
+ // I don't want "up 20" where "20" takes you past the top of the stack to produce
+ // an error, but rather to just go to the top. So I have to count the stack here...
+ const uint32_t num_frames = thread->GetStackFrameCount();
+ if (num_frames - frame_idx > m_options.relative_frame_offset)
+ frame_idx += m_options.relative_frame_offset;
+ else
+ {
+ if (frame_idx == num_frames - 1)
+ {
+ //If we are already at the top of the stack, just warn and don't reset the frame.
+ result.AppendError("Already at the top of the stack");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ frame_idx = num_frames - 1;
+ }
+ }
+ }
+ else
+ {
+ if (command.GetArgumentCount() == 1)
+ {
+ const char *frame_idx_cstr = command.GetArgumentAtIndex(0);
+ frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0);
+ }
+ else if (command.GetArgumentCount() == 0)
+ {
+ frame_idx = thread->GetSelectedFrameIndex ();
+ if (frame_idx == UINT32_MAX)
+ {
+ frame_idx = 0;
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid arguments.\n");
+ m_options.GenerateOptionUsage (result.GetErrorStream(), this);
+ }
+ }
+
+ bool success = thread->SetSelectedFrameByIndexNoisily (frame_idx, result.GetOutputStream());
+ if (success)
+ {
+ m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx);
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+protected:
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectFrameSelect::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "relative", 'r', required_argument, NULL, 0, eArgTypeOffset, "A relative frame index offset from the current frame index."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectFrameVariable
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectFrameVariable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectFrameVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "frame variable",
+ "Show frame variables. All argument and local variables "
+ "that are in scope will be shown when no arguments are given. "
+ "If any arguments are specified, they can be names of "
+ "argument, local, file static and file global variables. "
+ "Children of aggregate variables can be specified such as "
+ "'var->child.x'.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused |
+ eFlagRequiresProcess),
+ m_option_group (interpreter),
+ m_option_variable(true), // Include the frame specific options by passing "true"
+ m_option_format (eFormatDefault),
+ m_varobj_options()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectFrameVariable ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard source file completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eVariablePathCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "frame" for validity as eFlagRequiresFrame ensures it is valid
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ Stream &s = result.GetOutputStream();
+
+ bool get_file_globals = true;
+
+ // Be careful about the stack frame, if any summary formatter runs code, it might clear the StackFrameList
+ // for the thread. So hold onto a shared pointer to the frame so it stays alive.
+
+ VariableList *variable_list = frame->GetVariableList (get_file_globals);
+
+ VariableSP var_sp;
+ ValueObjectSP valobj_sp;
+
+ const char *name_cstr = NULL;
+ size_t idx;
+
+ TypeSummaryImplSP summary_format_sp;
+ if (!m_option_variable.summary.IsCurrentValueEmpty())
+ DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(m_option_variable.summary.GetCurrentValue()), summary_format_sp);
+ else if (!m_option_variable.summary_string.IsCurrentValueEmpty())
+ summary_format_sp.reset(new StringSummaryFormat(TypeSummaryImpl::Flags(),m_option_variable.summary_string.GetCurrentValue()));
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,eFormatDefault,summary_format_sp));
+
+ if (variable_list)
+ {
+ const Format format = m_option_format.GetFormat();
+ options.SetFormat(format);
+
+ if (command.GetArgumentCount() > 0)
+ {
+ VariableList regex_var_list;
+
+ // If we have any args to the variable command, we will make
+ // variable objects from them...
+ for (idx = 0; (name_cstr = command.GetArgumentAtIndex(idx)) != NULL; ++idx)
+ {
+ if (m_option_variable.use_regex)
+ {
+ const size_t regex_start_index = regex_var_list.GetSize();
+ RegularExpression regex (name_cstr);
+ if (regex.Compile(name_cstr))
+ {
+ size_t num_matches = 0;
+ const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
+ regex_var_list,
+ num_matches);
+ if (num_new_regex_vars > 0)
+ {
+ for (size_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
+ regex_idx < end_index;
+ ++regex_idx)
+ {
+ var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
+ if (var_sp)
+ {
+ valobj_sp = frame->GetValueObjectForFrameVariable (var_sp, m_varobj_options.use_dynamic);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+
+ if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
+ {
+ bool show_fullpaths = false;
+ bool show_module = true;
+ if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
+ s.PutCString (": ");
+ }
+ ValueObject::DumpValueObject (result.GetOutputStream(),
+ valobj_sp.get(),
+ options);
+ }
+ }
+ }
+ }
+ else if (num_matches == 0)
+ {
+ result.GetErrorStream().Printf ("error: no variables matched the regular expression '%s'.\n", name_cstr);
+ }
+ }
+ else
+ {
+ char regex_error[1024];
+ if (regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
+ result.GetErrorStream().Printf ("error: %s\n", regex_error);
+ else
+ result.GetErrorStream().Printf ("error: unkown regex error when compiling '%s'\n", name_cstr);
+ }
+ }
+ else // No regex, either exact variable names or variable expressions.
+ {
+ Error error;
+ uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
+ lldb::VariableSP var_sp;
+ valobj_sp = frame->GetValueForVariableExpressionPath (name_cstr,
+ m_varobj_options.use_dynamic,
+ expr_path_options,
+ var_sp,
+ error);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+ if (m_option_variable.show_decl && var_sp && var_sp->GetDeclaration ().GetFile())
+ {
+ var_sp->GetDeclaration ().DumpStopContext (&s, false);
+ s.PutCString (": ");
+ }
+
+ options.SetFormat(format);
+
+ Stream &output_stream = result.GetOutputStream();
+ options.SetRootValueObjectName(valobj_sp->GetParent() ? name_cstr : NULL);
+ ValueObject::DumpValueObject (output_stream,
+ valobj_sp.get(),
+ options);
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString(NULL);
+ if (error_cstr)
+ result.GetErrorStream().Printf("error: %s\n", error_cstr);
+ else
+ result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n", name_cstr);
+ }
+ }
+ }
+ }
+ else // No command arg specified. Use variable_list, instead.
+ {
+ const size_t num_variables = variable_list->GetSize();
+ if (num_variables > 0)
+ {
+ for (size_t i=0; i<num_variables; i++)
+ {
+ var_sp = variable_list->GetVariableAtIndex(i);
+ bool dump_variable = true;
+ switch (var_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ dump_variable = m_option_variable.show_globals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString("GLOBAL: ");
+ break;
+
+ case eValueTypeVariableStatic:
+ dump_variable = m_option_variable.show_globals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString("STATIC: ");
+ break;
+
+ case eValueTypeVariableArgument:
+ dump_variable = m_option_variable.show_args;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString(" ARG: ");
+ break;
+
+ case eValueTypeVariableLocal:
+ dump_variable = m_option_variable.show_locals;
+ if (dump_variable && m_option_variable.show_scope)
+ s.PutCString(" LOCAL: ");
+ break;
+
+ default:
+ break;
+ }
+
+ if (dump_variable)
+ {
+ // Use the variable object code to make sure we are
+ // using the same APIs as the the public API will be
+ // using...
+ valobj_sp = frame->GetValueObjectForFrameVariable (var_sp,
+ m_varobj_options.use_dynamic);
+ if (valobj_sp)
+ {
+// if (format != eFormatDefault)
+// valobj_sp->SetFormat (format);
+
+ // When dumping all variables, don't print any variables
+ // that are not in scope to avoid extra unneeded output
+ if (valobj_sp->IsInScope ())
+ {
+ if (m_option_variable.show_decl && var_sp->GetDeclaration ().GetFile())
+ {
+ var_sp->GetDeclaration ().DumpStopContext (&s, false);
+ s.PutCString (": ");
+ }
+
+ options.SetFormat(format);
+ options.SetRootValueObjectName(name_cstr);
+ ValueObject::DumpValueObject (result.GetOutputStream(),
+ valobj_sp.get(),
+ options);
+ }
+ }
+ }
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ if (m_interpreter.TruncationWarningNecessary())
+ {
+ result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
+ m_cmd_name.c_str());
+ m_interpreter.TruncationWarningGiven();
+ }
+
+ return result.Succeeded();
+ }
+protected:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupVariable m_option_variable;
+ OptionGroupFormat m_option_format;
+ OptionGroupValueObjectDisplay m_varobj_options;
+};
+
+
+#pragma mark CommandObjectMultiwordFrame
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordFrame
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordFrame::CommandObjectMultiwordFrame (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "frame",
+ "A set of commands for operating on the current thread's frames.",
+ "frame <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("info", CommandObjectSP (new CommandObjectFrameInfo (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectFrameSelect (interpreter)));
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectFrameVariable (interpreter)));
+}
+
+CommandObjectMultiwordFrame::~CommandObjectMultiwordFrame ()
+{
+}
+
diff --git a/source/Commands/CommandObjectFrame.h b/source/Commands/CommandObjectFrame.h
new file mode 100644
index 000000000000..ea7c808e84b1
--- /dev/null
+++ b/source/Commands/CommandObjectFrame.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectFrame.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_CommandObjectFrame_h_
+#define liblldb_CommandObjectFrame_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordFrame
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordFrame : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordFrame (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordFrame ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectFrame_h_
diff --git a/source/Commands/CommandObjectHelp.cpp b/source/Commands/CommandObjectHelp.cpp
new file mode 100644
index 000000000000..d2c97f91260b
--- /dev/null
+++ b/source/Commands/CommandObjectHelp.cpp
@@ -0,0 +1,249 @@
+//===-- CommandObjectHelp.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 "CommandObjectHelp.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+CommandObjectHelp::CommandObjectHelp (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "help",
+ "Show a list of all debugger commands, or give details about specific commands.",
+ "help [<cmd-name>]"), m_options (interpreter)
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData command_arg;
+
+ // Define the first (and only) variant of this arg.
+ command_arg.arg_type = eArgTypeCommandName;
+ command_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (command_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectHelp::~CommandObjectHelp()
+{
+}
+
+OptionDefinition
+CommandObjectHelp::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "show-aliases", 'a', no_argument, NULL, 0, eArgTypeNone, "Show aliases in the command list."},
+ { LLDB_OPT_SET_ALL, false, "hide-user-commands", 'u', no_argument, NULL, 0, eArgTypeNone, "Hide user-defined commands from the list."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+bool
+CommandObjectHelp::DoExecute (Args& command, CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const size_t argc = command.GetArgumentCount ();
+
+ // 'help' doesn't take any arguments, other than command names. If argc is 0, we show the user
+ // all commands (aliases and user commands if asked for). Otherwise every argument must be the name of a command or a sub-command.
+ if (argc == 0)
+ {
+ uint32_t cmd_types = CommandInterpreter::eCommandTypesBuiltin;
+ if (m_options.m_show_aliases)
+ cmd_types |= CommandInterpreter::eCommandTypesAliases;
+ if (m_options.m_show_user_defined)
+ cmd_types |= CommandInterpreter::eCommandTypesUserDef;
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ m_interpreter.GetHelp (result, cmd_types); // General help
+ }
+ else
+ {
+ // Get command object for the first command argument. Only search built-in command dictionary.
+ StringList matches;
+ cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex (0), &matches);
+ bool is_alias_command = m_interpreter.AliasExists (command.GetArgumentAtIndex (0));
+ std::string alias_name = command.GetArgumentAtIndex(0);
+
+ if (cmd_obj != NULL)
+ {
+ StringList matches;
+ bool all_okay = true;
+ CommandObject *sub_cmd_obj = cmd_obj;
+ // Loop down through sub_command dictionaries until we find the command object that corresponds
+ // to the help command entered.
+ for (size_t i = 1; i < argc && all_okay; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex(i);
+ matches.Clear();
+ if (! sub_cmd_obj->IsMultiwordObject ())
+ {
+ all_okay = false;
+ }
+ else
+ {
+ CommandObject *found_cmd;
+ found_cmd = sub_cmd_obj->GetSubcommandObject(sub_command.c_str(), &matches);
+ if (found_cmd == NULL)
+ all_okay = false;
+ else if (matches.GetSize() > 1)
+ all_okay = false;
+ else
+ sub_cmd_obj = found_cmd;
+ }
+ }
+
+ if (!all_okay || (sub_cmd_obj == NULL))
+ {
+ std::string cmd_string;
+ command.GetCommandString (cmd_string);
+ if (matches.GetSize() >= 2)
+ {
+ StreamString s;
+ s.Printf ("ambiguous command %s", cmd_string.c_str());
+ size_t num_matches = matches.GetSize();
+ for (size_t match_idx = 0; match_idx < num_matches; match_idx++)
+ {
+ s.Printf ("\n\t%s", matches.GetStringAtIndex(match_idx));
+ }
+ s.Printf ("\n");
+ result.AppendError(s.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (!sub_cmd_obj)
+ {
+ result.AppendErrorWithFormat("'%s' is not a known command.\n"
+ "Try 'help' to see a current list of commands.\n",
+ cmd_string.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.GetOutputStream().Printf("'%s' is not a known command.\n"
+ "Try 'help' to see a current list of commands.\n"
+ "The closest match is '%s'. Help on it follows.\n\n",
+ cmd_string.c_str(),
+ sub_cmd_obj->GetCommandName());
+ }
+ }
+
+ sub_cmd_obj->GenerateHelpText(result);
+
+ if (is_alias_command)
+ {
+ StreamString sstr;
+ m_interpreter.GetAliasHelp (alias_name.c_str(), cmd_obj->GetCommandName(), sstr);
+ result.GetOutputStream().Printf ("\n'%s' is an abbreviation for %s\n", alias_name.c_str(), sstr.GetData());
+ }
+ }
+ else if (matches.GetSize() > 0)
+ {
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf("Help requested with ambiguous command name, possible completions:\n");
+ const size_t match_count = matches.GetSize();
+ for (size_t i = 0; i < match_count; i++)
+ {
+ output_strm.Printf("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ }
+ else
+ {
+ // Maybe the user is asking for help about a command argument rather than a command.
+ const CommandArgumentType arg_type = CommandObject::LookupArgumentName (command.GetArgumentAtIndex (0));
+ if (arg_type != eArgTypeLastArg)
+ {
+ Stream &output_strm = result.GetOutputStream ();
+ CommandObject::GetArgumentHelp (output_strm, arg_type, m_interpreter);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat
+ ("'%s' is not a known command.\nTry 'help' to see a current list of commands.\n",
+ command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+int
+CommandObjectHelp::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ // Return the completions of the commands in the help system:
+ if (cursor_index == 0)
+ {
+ return m_interpreter.HandleCompletionMatches (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ CommandObject *cmd_obj = m_interpreter.GetCommandObject (input.GetArgumentAtIndex(0));
+
+ // The command that they are getting help on might be ambiguous, in which case we should complete that,
+ // otherwise complete with the command the user is getting help on...
+
+ if (cmd_obj)
+ {
+ input.Shift();
+ cursor_index--;
+ return cmd_obj->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ return m_interpreter.HandleCompletionMatches (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ }
+}
diff --git a/source/Commands/CommandObjectHelp.h b/source/Commands/CommandObjectHelp.h
new file mode 100644
index 000000000000..6e8f9d4cbc7b
--- /dev/null
+++ b/source/Commands/CommandObjectHelp.h
@@ -0,0 +1,119 @@
+//===-- CommandObjectHelp.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_CommandObjectHelp_h_
+#define liblldb_CommandObjectHelp_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectHelp
+//-------------------------------------------------------------------------
+
+class CommandObjectHelp : public CommandObjectParsed
+{
+public:
+
+ CommandObjectHelp (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectHelp ();
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches);
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_show_aliases = true;
+ break;
+ case 'u':
+ m_show_user_defined = false;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_show_aliases = false;
+ m_show_user_defined = true;
+ }
+
+ 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_show_aliases;
+ bool m_show_user_defined;
+ };
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+private:
+ CommandOptions m_options;
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectHelp_h_
diff --git a/source/Commands/CommandObjectLog.cpp b/source/Commands/CommandObjectLog.cpp
new file mode 100644
index 000000000000..5fb79154c4ef
--- /dev/null
+++ b/source/Commands/CommandObjectLog.cpp
@@ -0,0 +1,503 @@
+//===-- CommandObjectLog.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 "CommandObjectLog.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+class CommandObjectLogEnable : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogEnable(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log enable",
+ "Enable logging for a single log channel.",
+ NULL),
+ m_options (interpreter)
+ {
+
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData channel_arg;
+ CommandArgumentData category_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (channel_arg);
+
+ category_arg.arg_type = eArgTypeLogCategory;
+ category_arg.arg_repetition = eArgRepeatPlus;
+
+ arg2.push_back (category_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectLogEnable()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+// int
+// HandleArgumentCompletion (Args &input,
+// int &cursor_index,
+// int &cursor_char_position,
+// OptionElementVector &opt_element_vector,
+// int match_start_point,
+// int max_return_elements,
+// bool &word_complete,
+// StringList &matches)
+// {
+// std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+// completion_str.erase (cursor_char_position);
+//
+// if (cursor_index == 1)
+// {
+// //
+// Log::AutoCompleteChannelName (completion_str.c_str(), matches);
+// }
+// return matches.GetSize();
+// }
+//
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ log_file (),
+ log_options (0)
+ {
+ }
+
+
+ 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': log_file.SetFile(option_arg, true); break;
+ case 't': log_options |= LLDB_LOG_OPTION_THREADSAFE; break;
+ case 'v': log_options |= LLDB_LOG_OPTION_VERBOSE; break;
+ case 'g': log_options |= LLDB_LOG_OPTION_DEBUG; break;
+ case 's': log_options |= LLDB_LOG_OPTION_PREPEND_SEQUENCE; break;
+ case 'T': log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP; break;
+ case 'p': log_options |= LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD;break;
+ case 'n': log_options |= LLDB_LOG_OPTION_PREPEND_THREAD_NAME; break;
+ case 'S': log_options |= LLDB_LOG_OPTION_BACKTRACE; break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ log_file.Clear();
+ log_options = 0;
+ }
+
+ 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.
+
+ FileSpec log_file;
+ uint32_t log_options;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() < 2)
+ {
+ result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
+ }
+ else
+ {
+ std::string channel(args.GetArgumentAtIndex(0));
+ args.Shift (); // Shift off the channel
+ char log_file[PATH_MAX];
+ if (m_options.log_file)
+ m_options.log_file.GetPath(log_file, sizeof(log_file));
+ else
+ log_file[0] = '\0';
+ bool success = m_interpreter.GetDebugger().EnableLog (channel.c_str(),
+ args.GetConstArgumentVector(),
+ log_file,
+ m_options.log_options,
+ result.GetErrorStream());
+ if (success)
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectLogEnable::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Set the destination file to log to."},
+{ LLDB_OPT_SET_1, false, "threadsafe", 't', no_argument, NULL, 0, eArgTypeNone, "Enable thread safe logging to avoid interweaved log lines." },
+{ LLDB_OPT_SET_1, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose logging." },
+{ LLDB_OPT_SET_1, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable debug logging." },
+{ LLDB_OPT_SET_1, false, "sequence", 's', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with an increasing integer sequence id." },
+{ LLDB_OPT_SET_1, false, "timestamp", 'T', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with a timestamp." },
+{ LLDB_OPT_SET_1, false, "pid-tid", 'p', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the process and thread ID that generates the log line." },
+{ LLDB_OPT_SET_1, false, "thread-name",'n', no_argument, NULL, 0, eArgTypeNone, "Prepend all log lines with the thread name for the thread that generates the log line." },
+{ LLDB_OPT_SET_1, false, "stack", 'S', no_argument, NULL, 0, eArgTypeNone, "Append a stack backtrace to each log line." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectLogDisable : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogDisable(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log disable",
+ "Disable one or more log channel categories.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData channel_arg;
+ CommandArgumentData category_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (channel_arg);
+
+ category_arg.arg_type = eArgTypeLogCategory;
+ category_arg.arg_repetition = eArgRepeatPlus;
+
+ arg2.push_back (category_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectLogDisable()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat("%s takes a log channel and one or more log types.\n", m_cmd_name.c_str());
+ }
+ else
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(0));
+ args.Shift (); // Shift off the channel
+ if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
+ {
+ log_callbacks.disable (args.GetConstArgumentVector(), &result.GetErrorStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else if (channel == "all")
+ {
+ Log::DisableAllLogChannels(&result.GetErrorStream());
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
+ if (log_channel_sp)
+ {
+ log_channel_sp->Disable(args.GetConstArgumentVector(), &result.GetErrorStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectLogList : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log list",
+ "List the log categories for one or more log channels. If none specified, lists them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData channel_arg;
+
+ // Define the first (and only) variant of this arg.
+ channel_arg.arg_type = eArgTypeLogChannel;
+ channel_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (channel_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectLogList()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ Log::ListAllLogChannels (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ Log::Callbacks log_callbacks;
+
+ std::string channel(args.GetArgumentAtIndex(i));
+ if (Log::GetLogChannelCallbacks (ConstString(channel.c_str()), log_callbacks))
+ {
+ log_callbacks.list_categories (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (channel == "all")
+ {
+ Log::ListAllLogChannels (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin(channel.c_str()));
+ if (log_channel_sp)
+ {
+ log_channel_sp->ListCategories(&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendErrorWithFormat("Invalid log channel '%s'.\n", args.GetArgumentAtIndex(0));
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+class CommandObjectLogTimer : public CommandObjectParsed
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLogTimer(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "log timers",
+ "Enable, disable, dump, and reset LLDB internal performance timers.",
+ "log timers < enable <depth> | disable | dump | increment <bool> | reset >")
+ {
+ }
+
+ virtual
+ ~CommandObjectLogTimer()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ result.SetStatus(eReturnStatusFailed);
+
+ if (argc == 1)
+ {
+ const char *sub_command = args.GetArgumentAtIndex(0);
+
+ if (strcasecmp(sub_command, "enable") == 0)
+ {
+ Timer::SetDisplayDepth (UINT32_MAX);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else if (strcasecmp(sub_command, "disable") == 0)
+ {
+ Timer::DumpCategoryTimes (&result.GetOutputStream());
+ Timer::SetDisplayDepth (0);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (strcasecmp(sub_command, "dump") == 0)
+ {
+ Timer::DumpCategoryTimes (&result.GetOutputStream());
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (strcasecmp(sub_command, "reset") == 0)
+ {
+ Timer::ResetCategoryTimes ();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+ }
+ else if (argc == 2)
+ {
+ const char *sub_command = args.GetArgumentAtIndex(0);
+
+ if (strcasecmp(sub_command, "enable") == 0)
+ {
+ bool success;
+ uint32_t depth = Args::StringToUInt32(args.GetArgumentAtIndex(1), 0, 0, &success);
+ if (success)
+ {
+ Timer::SetDisplayDepth (depth);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendError("Could not convert enable depth to an unsigned integer.");
+ }
+ if (strcasecmp(sub_command, "increment") == 0)
+ {
+ bool success;
+ bool increment = Args::StringToBoolean(args.GetArgumentAtIndex(1), false, &success);
+ if (success)
+ {
+ Timer::SetQuiet (!increment);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ result.AppendError("Could not convert increment value to boolean.");
+ }
+ }
+
+ if (!result.Succeeded())
+ {
+ result.AppendError("Missing subcommand");
+ result.AppendErrorWithFormat("Usage: %s\n", m_cmd_syntax.c_str());
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// CommandObjectLog constructor
+//----------------------------------------------------------------------
+CommandObjectLog::CommandObjectLog(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "log",
+ "A set of commands for operating on logs.",
+ "log <command> [<command-options>]")
+{
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectLogEnable (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectLogDisable (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectLogList (interpreter)));
+ LoadSubCommand ("timers", CommandObjectSP (new CommandObjectLogTimer (interpreter)));
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectLog::~CommandObjectLog()
+{
+}
+
+
+
+
diff --git a/source/Commands/CommandObjectLog.h b/source/Commands/CommandObjectLog.h
new file mode 100644
index 000000000000..3e731fa1d186
--- /dev/null
+++ b/source/Commands/CommandObjectLog.h
@@ -0,0 +1,48 @@
+//===-- CommandObjectLog.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_CommandObjectLog_h_
+#define liblldb_CommandObjectLog_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectLog
+//-------------------------------------------------------------------------
+
+class CommandObjectLog : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectLog(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectLog();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectLog only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectLog);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectLog_h_
diff --git a/source/Commands/CommandObjectMemory.cpp b/source/Commands/CommandObjectMemory.cpp
new file mode 100644
index 000000000000..4725a4da6578
--- /dev/null
+++ b/source/Commands/CommandObjectMemory.cpp
@@ -0,0 +1,1370 @@
+//===-- CommandObjectMemory.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 "CommandObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupOutputFile.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
+ { LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
+ { LLDB_OPT_SET_3, true , "type" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
+ { LLDB_OPT_SET_1|
+ LLDB_OPT_SET_2|
+ LLDB_OPT_SET_3, false, "force" ,'r', no_argument, NULL, 0, eArgTypeNone ,"Necessary if reading over target.max-memory-read-size bytes."},
+};
+
+
+
+class OptionGroupReadMemory : public OptionGroup
+{
+public:
+
+ OptionGroupReadMemory () :
+ m_num_per_line (1,1),
+ m_output_as_binary (false),
+ m_view_as_type()
+ {
+ }
+
+ virtual
+ ~OptionGroupReadMemory ()
+ {
+ }
+
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_option_table) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'l':
+ error = m_num_per_line.SetValueFromCString (option_arg);
+ if (m_num_per_line.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
+ break;
+
+ case 'b':
+ m_output_as_binary = true;
+ break;
+
+ case 't':
+ error = m_view_as_type.SetValueFromCString (option_arg);
+ break;
+
+ case 'r':
+ m_force = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_num_per_line.Clear();
+ m_output_as_binary = false;
+ m_view_as_type.Clear();
+ m_force = false;
+ }
+
+ Error
+ FinalizeSettings (Target *target, OptionGroupFormat& format_options)
+ {
+ Error error;
+ OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
+ OptionValueUInt64 &count_value = format_options.GetCountValue();
+ const bool byte_size_option_set = byte_size_value.OptionWasSet();
+ const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
+ const bool count_option_set = format_options.GetCountValue().OptionWasSet();
+
+ switch (format_options.GetFormat())
+ {
+ default:
+ break;
+
+ case eFormatBoolean:
+ if (!byte_size_option_set)
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatCString:
+ break;
+
+ case eFormatInstruction:
+ if (count_option_set)
+ byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
+ m_num_per_line = 1;
+ break;
+
+ case eFormatAddressInfo:
+ if (!byte_size_option_set)
+ byte_size_value = target->GetArchitecture().GetAddressByteSize();
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatPointer:
+ byte_size_value = target->GetArchitecture().GetAddressByteSize();
+ if (!num_per_line_option_set)
+ m_num_per_line = 4;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatBinary:
+ case eFormatFloat:
+ case eFormatOctal:
+ case eFormatDecimal:
+ case eFormatEnum:
+ case eFormatUnicode16:
+ case eFormatUnicode32:
+ case eFormatUnsigned:
+ case eFormatHexFloat:
+ if (!byte_size_option_set)
+ byte_size_value = 4;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ if (byte_size_option_set)
+ {
+ if (byte_size_value > 1)
+ error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
+ "\tconsider using a different display format or don't specify the byte size",
+ byte_size_value.GetCurrentValue());
+ }
+ else
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 16;
+ if (!count_option_set)
+ format_options.GetCountValue() = 32;
+ break;
+ case eFormatCharArray:
+ case eFormatChar:
+ case eFormatCharPrintable:
+ if (!byte_size_option_set)
+ byte_size_value = 1;
+ if (!num_per_line_option_set)
+ m_num_per_line = 32;
+ if (!count_option_set)
+ format_options.GetCountValue() = 64;
+ break;
+ case eFormatComplex:
+ if (!byte_size_option_set)
+ byte_size_value = 8;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+ case eFormatComplexInteger:
+ if (!byte_size_option_set)
+ byte_size_value = 8;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ format_options.GetCountValue() = 8;
+ break;
+ case eFormatHex:
+ if (!byte_size_option_set)
+ byte_size_value = 4;
+ if (!num_per_line_option_set)
+ {
+ switch (byte_size_value)
+ {
+ case 1:
+ case 2:
+ m_num_per_line = 8;
+ break;
+ case 4:
+ m_num_per_line = 4;
+ break;
+ case 8:
+ m_num_per_line = 2;
+ break;
+ default:
+ m_num_per_line = 1;
+ break;
+ }
+ }
+ if (!count_option_set)
+ count_value = 8;
+ break;
+
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ if (!byte_size_option_set)
+ byte_size_value = 128;
+ if (!num_per_line_option_set)
+ m_num_per_line = 1;
+ if (!count_option_set)
+ count_value = 4;
+ break;
+ }
+ return error;
+ }
+
+ bool
+ AnyOptionWasSet () const
+ {
+ return m_num_per_line.OptionWasSet() ||
+ m_output_as_binary ||
+ m_view_as_type.OptionWasSet();
+ }
+
+ OptionValueUInt64 m_num_per_line;
+ bool m_output_as_binary;
+ OptionValueString m_view_as_type;
+ bool m_force;
+};
+
+
+
+//----------------------------------------------------------------------
+// Read memory from the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryRead : public CommandObjectParsed
+{
+public:
+
+ CommandObjectMemoryRead (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory read",
+ "Read from the memory of the process being debugged.",
+ NULL,
+ eFlagRequiresTarget | eFlagProcessMustBePaused),
+ m_option_group (interpreter),
+ m_format_options (eFormatBytesWithASCII, 1, 8),
+ m_memory_options (),
+ m_outfile_options (),
+ m_varobj_options(),
+ m_next_addr(LLDB_INVALID_ADDRESS),
+ m_prev_byte_size(0),
+ m_prev_format_options (eFormatBytesWithASCII, 1, 8),
+ m_prev_memory_options (),
+ m_prev_outfile_options (),
+ m_prev_varobj_options()
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData start_addr_arg;
+ CommandArgumentData end_addr_arg;
+
+ // Define the first (and only) variant of this arg.
+ start_addr_arg.arg_type = eArgTypeAddressOrExpression;
+ start_addr_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (start_addr_arg);
+
+ // Define the first (and only) variant of this arg.
+ end_addr_arg.arg_type = eArgTypeAddressOrExpression;
+ end_addr_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (end_addr_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ // Add the "--format" and "--count" options to group 1 and 3
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_GDB_FMT,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
+ // Add the "--size" option to group 1 and 2
+ m_option_group.Append (&m_format_options,
+ OptionGroupFormat::OPTION_GROUP_SIZE,
+ LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
+ m_option_group.Append (&m_memory_options);
+ m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectMemoryRead ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ 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)
+ {
+ // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
+ {
+ result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
+ result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ ClangASTType clang_ast_type;
+ Error error;
+
+ const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
+ if (view_as_type_cstr && view_as_type_cstr[0])
+ {
+ // We are viewing memory as a type
+
+ SymbolContext sc;
+ const bool exact_match = false;
+ TypeList type_list;
+ uint32_t reference_count = 0;
+ uint32_t pointer_count = 0;
+ size_t idx;
+
+#define ALL_KEYWORDS \
+ KEYWORD("const") \
+ KEYWORD("volatile") \
+ KEYWORD("restrict") \
+ KEYWORD("struct") \
+ KEYWORD("class") \
+ KEYWORD("union")
+
+#define KEYWORD(s) s,
+ static const char *g_keywords[] =
+ {
+ ALL_KEYWORDS
+ };
+#undef KEYWORD
+
+#define KEYWORD(s) (sizeof(s) - 1),
+ static const int g_keyword_lengths[] =
+ {
+ ALL_KEYWORDS
+ };
+#undef KEYWORD
+
+#undef ALL_KEYWORDS
+
+ static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
+ std::string type_str(view_as_type_cstr);
+
+ // Remove all instances of g_keywords that are followed by spaces
+ for (size_t i = 0; i < g_num_keywords; ++i)
+ {
+ const char *keyword = g_keywords[i];
+ int keyword_len = g_keyword_lengths[i];
+
+ idx = 0;
+ while ((idx = type_str.find (keyword, idx)) != std::string::npos)
+ {
+ if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
+ {
+ type_str.erase(idx, keyword_len+1);
+ idx = 0;
+ }
+ else
+ {
+ idx += keyword_len;
+ }
+ }
+ }
+ bool done = type_str.empty();
+ //
+ idx = type_str.find_first_not_of (" \t");
+ if (idx > 0 && idx != std::string::npos)
+ type_str.erase (0, idx);
+ while (!done)
+ {
+ // Strip trailing spaces
+ if (type_str.empty())
+ done = true;
+ else
+ {
+ switch (type_str[type_str.size()-1])
+ {
+ case '*':
+ ++pointer_count;
+ // fall through...
+ case ' ':
+ case '\t':
+ type_str.erase(type_str.size()-1);
+ break;
+
+ case '&':
+ if (reference_count == 0)
+ {
+ reference_count = 1;
+ type_str.erase(type_str.size()-1);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ break;
+
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+
+ ConstString lookup_type_name(type_str.c_str());
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ sc = frame->GetSymbolContext (eSymbolContextModule);
+ if (sc.module_sp)
+ {
+ sc.module_sp->FindTypes (sc,
+ lookup_type_name,
+ exact_match,
+ 1,
+ type_list);
+ }
+ }
+ if (type_list.GetSize() == 0)
+ {
+ target->GetImages().FindTypes (sc,
+ lookup_type_name,
+ exact_match,
+ 1,
+ type_list);
+ }
+
+ if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$')
+ {
+ clang::TypeDecl *tdecl = target->GetPersistentVariables().GetPersistentType(ConstString(lookup_type_name));
+ if (tdecl)
+ {
+ clang_ast_type.SetClangType(&tdecl->getASTContext(),(lldb::clang_type_t)tdecl->getTypeForDecl());
+ }
+ }
+
+ if (clang_ast_type.IsValid() == false)
+ {
+ if (type_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
+ lookup_type_name.GetCString(),
+ view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(0));
+ clang_ast_type = type_sp->GetClangFullType();
+ }
+ }
+
+ while (pointer_count > 0)
+ {
+ ClangASTType pointer_type = clang_ast_type.GetPointerType();
+ if (pointer_type.IsValid())
+ clang_ast_type = pointer_type;
+ else
+ {
+ result.AppendError ("unable make a pointer type\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ --pointer_count;
+ }
+
+ m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize();
+
+ if (m_format_options.GetByteSizeValue() == 0)
+ {
+ result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
+ view_as_type_cstr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (!m_format_options.GetCountValue().OptionWasSet())
+ m_format_options.GetCountValue() = 1;
+ }
+ else
+ {
+ error = m_memory_options.FinalizeSettings (target, m_format_options);
+ }
+
+ // Look for invalid combinations of settings
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ lldb::addr_t addr;
+ size_t total_byte_size = 0;
+ if (argc == 0)
+ {
+ // Use the last address and byte size and all options as they were
+ // if no options have been set
+ addr = m_next_addr;
+ total_byte_size = m_prev_byte_size;
+ clang_ast_type = m_prev_clang_ast_type;
+ if (!m_format_options.AnyOptionWasSet() &&
+ !m_memory_options.AnyOptionWasSet() &&
+ !m_outfile_options.AnyOptionWasSet() &&
+ !m_varobj_options.AnyOptionWasSet())
+ {
+ m_format_options = m_prev_format_options;
+ m_memory_options = m_prev_memory_options;
+ m_outfile_options = m_prev_outfile_options;
+ m_varobj_options = m_prev_varobj_options;
+ }
+ }
+
+ size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
+ size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
+ const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
+
+ if (total_byte_size == 0)
+ {
+ total_byte_size = item_count * item_byte_size;
+ if (total_byte_size == 0)
+ total_byte_size = 32;
+ }
+
+ if (argc > 0)
+ addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid start address expression.");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (argc == 2)
+ {
+ lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
+ if (end_addr == LLDB_INVALID_ADDRESS)
+ {
+ result.AppendError("invalid end address expression.");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (end_addr <= addr)
+ {
+ result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (m_format_options.GetCountValue().OptionWasSet())
+ {
+ result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %lu), not both.\n", end_addr, item_count);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ 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)
+ {
+ result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size);
+ result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n");
+ result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n");
+ return false;
+ }
+
+ DataBufferSP data_sp;
+ size_t bytes_read = 0;
+ if (clang_ast_type.GetOpaqueQualType())
+ {
+ // Make sure we don't display our type as ASCII bytes like the default memory read
+ if (m_format_options.GetFormatValue().OptionWasSet() == false)
+ m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
+
+ bytes_read = clang_ast_type.GetByteSize() * m_format_options.GetCountValue().GetCurrentValue();
+ }
+ else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
+ {
+ data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
+ if (data_sp->GetBytes() == NULL)
+ {
+ result.AppendErrorWithFormat ("can't allocate 0x%zx bytes for the memory read buffer, specify a smaller size to read", total_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Address address(addr, NULL);
+ bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
+ if (bytes_read == 0)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr && error_cstr[0])
+ {
+ result.AppendError(error_cstr);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
+ }
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (bytes_read < total_byte_size)
+ result.AppendWarningWithFormat("Not all bytes (%lu/%lu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
+ }
+ else
+ {
+ // we treat c-strings as a special case because they do not have a fixed size
+ if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
+ item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
+ else
+ item_byte_size = target->GetMaximumSizeOfStringSummary();
+ if (!m_format_options.GetCountValue().OptionWasSet())
+ item_count = 1;
+ data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
+ if (data_sp->GetBytes() == NULL)
+ {
+ result.AppendErrorWithFormat ("can't allocate 0x%" PRIx64 " bytes for the memory read buffer, specify a smaller size to read", (uint64_t)((item_byte_size+1) * item_count));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ uint8_t *data_ptr = data_sp->GetBytes();
+ auto data_addr = addr;
+ auto count = item_count;
+ item_count = 0;
+ while (item_count < count)
+ {
+ std::string buffer;
+ buffer.resize(item_byte_size+1,0);
+ Error error;
+ size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
+ if (error.Fail())
+ {
+ result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ if (item_byte_size == read)
+ {
+ result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
+ break;
+ }
+ read+=1; // account for final NULL byte
+ memcpy(data_ptr, &buffer[0], read);
+ data_ptr += read;
+ data_addr += read;
+ bytes_read += read;
+ item_count++; // if we break early we know we only read item_count strings
+ }
+ data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
+ }
+
+ m_next_addr = addr + bytes_read;
+ m_prev_byte_size = bytes_read;
+ m_prev_format_options = m_format_options;
+ m_prev_memory_options = m_memory_options;
+ m_prev_outfile_options = m_outfile_options;
+ m_prev_varobj_options = m_varobj_options;
+ m_prev_clang_ast_type = clang_ast_type;
+
+ StreamFile outfile_stream;
+ Stream *output_stream = NULL;
+ const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
+ if (outfile_spec)
+ {
+ char path[PATH_MAX];
+ outfile_spec.GetPath (path, sizeof(path));
+
+ uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
+ const bool append = m_outfile_options.GetAppend().GetCurrentValue();
+ if (append)
+ open_options |= File::eOpenOptionAppend;
+
+ if (outfile_stream.GetFile ().Open (path, open_options).Success())
+ {
+ if (m_memory_options.m_output_as_binary)
+ {
+ const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
+ if (bytes_written > 0)
+ {
+ result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
+ bytes_written,
+ append ? "appended" : "written",
+ path);
+ return true;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // We are going to write ASCII to the file just point the
+ // output_stream to our outfile_stream...
+ output_stream = &outfile_stream;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ output_stream = &result.GetOutputStream();
+ }
+
+
+ ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
+ if (clang_ast_type.GetOpaqueQualType())
+ {
+ for (uint32_t i = 0; i<item_count; ++i)
+ {
+ addr_t item_addr = addr + (i * item_byte_size);
+ Address address (item_addr);
+ StreamString name_strm;
+ name_strm.Printf ("0x%" PRIx64, item_addr);
+ ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
+ name_strm.GetString().c_str(),
+ address,
+ clang_ast_type));
+ if (valobj_sp)
+ {
+ Format format = m_format_options.GetFormat();
+ if (format != eFormatDefault)
+ valobj_sp->SetFormat (format);
+
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(false,format));
+
+ ValueObject::DumpValueObject (*output_stream,
+ valobj_sp.get(),
+ options);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
+ view_as_type_cstr,
+ name_strm.GetString().c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ DataExtractor data (data_sp,
+ target->GetArchitecture().GetByteOrder(),
+ target->GetArchitecture().GetAddressByteSize());
+
+ Format format = m_format_options.GetFormat();
+ if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) )
+ && (item_byte_size != 1)
+ && (item_count == 1))
+ {
+ // this turns requests such as
+ // memory read -fc -s10 -c1 *charPtrPtr
+ // which make no sense (what is a char of size 10?)
+ // into a request for fetching 10 chars of size 1 from the same memory location
+ format = eFormatCharArray;
+ item_count = item_byte_size;
+ item_byte_size = 1;
+ }
+
+ assert (output_stream);
+ size_t bytes_dumped = data.Dump (output_stream,
+ 0,
+ format,
+ item_byte_size,
+ item_count,
+ num_per_line,
+ addr,
+ 0,
+ 0,
+ exe_scope);
+ m_next_addr = addr + bytes_dumped;
+ output_stream->EOL();
+ return true;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupReadMemory m_memory_options;
+ OptionGroupOutputFile m_outfile_options;
+ OptionGroupValueObjectDisplay m_varobj_options;
+ lldb::addr_t m_next_addr;
+ lldb::addr_t m_prev_byte_size;
+ OptionGroupFormat m_prev_format_options;
+ OptionGroupReadMemory m_prev_memory_options;
+ OptionGroupOutputFile m_prev_outfile_options;
+ OptionGroupValueObjectDisplay m_prev_varobj_options;
+ ClangASTType m_prev_clang_ast_type;
+};
+
+
+OptionDefinition
+g_memory_write_option_table[] =
+{
+{ LLDB_OPT_SET_1, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
+{ LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
+};
+
+
+//----------------------------------------------------------------------
+// Write memory to the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryWrite : public CommandObjectParsed
+{
+public:
+
+ class OptionGroupWriteMemory : public OptionGroup
+ {
+ public:
+ OptionGroupWriteMemory () :
+ OptionGroup()
+ {
+ }
+
+ virtual
+ ~OptionGroupWriteMemory ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ()
+ {
+ return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
+ }
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_memory_write_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_memory_write_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'i':
+ m_infile.SetFile (option_arg, true);
+ if (!m_infile.Exists())
+ {
+ m_infile.Clear();
+ error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
+ }
+ break;
+
+ case 'o':
+ {
+ bool success;
+ m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_infile.Clear();
+ m_infile_offset = 0;
+ }
+
+ FileSpec m_infile;
+ off_t m_infile_offset;
+ };
+
+ CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "memory write",
+ "Write to the memory of the process being debugged.",
+ NULL,
+ eFlagRequiresProcess | eFlagProcessMustBeLaunched),
+ m_option_group (interpreter),
+ m_format_options (eFormatBytes, 1, UINT64_MAX),
+ m_memory_options ()
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData addr_arg;
+ CommandArgumentData value_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);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
+ m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+
+ }
+
+ virtual
+ ~CommandObjectMemoryWrite ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ bool
+ UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
+ return uval64 <= max;
+ }
+
+ bool
+ SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
+ {
+ if (total_byte_size > 8)
+ return false;
+
+ if (total_byte_size == 8)
+ return true;
+
+ const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
+ const int64_t min = ~(max);
+ return min <= sval64 && sval64 <= max;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ if (m_memory_options.m_infile)
+ {
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else if (argc < 2)
+ {
+ result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ StreamString buffer (Stream::eBinary,
+ process->GetTarget().GetArchitecture().GetAddressByteSize(),
+ process->GetTarget().GetArchitecture().GetByteOrder());
+
+ OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
+ size_t item_byte_size = byte_size_value.GetCurrentValue();
+
+ 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\n");
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_memory_options.m_infile)
+ {
+ size_t length = SIZE_MAX;
+ if (item_byte_size > 0)
+ length = item_byte_size;
+ lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
+ if (data_sp)
+ {
+ length = data_sp->GetByteSize();
+ if (length > 0)
+ {
+ Error error;
+ size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
+
+ if (bytes_written == length)
+ {
+ // All bytes written
+ result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else if (bytes_written > 0)
+ {
+ // Some byte written
+ result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to read contents of file.\n");
+ result.SetStatus(eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+ else if (item_byte_size == 0)
+ {
+ if (m_format_options.GetFormat() == eFormatPointer)
+ item_byte_size = buffer.GetAddressByteSize();
+ else
+ item_byte_size = 1;
+ }
+
+ command.Shift(); // shift off the address argument
+ uint64_t uval64;
+ int64_t sval64;
+ bool success = false;
+ const size_t num_value_args = command.GetArgumentCount();
+ for (size_t i=0; i<num_value_args; ++i)
+ {
+ const char *value_str = command.GetArgumentAtIndex(i);
+
+ switch (m_format_options.GetFormat())
+ {
+ case kNumFormats:
+ case eFormatFloat: // TODO: add support for floats soon
+ case eFormatCharPrintable:
+ case eFormatBytesWithASCII:
+ case eFormatComplex:
+ case eFormatEnum:
+ case eFormatUnicode16:
+ case eFormatUnicode32:
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ case eFormatOSType:
+ case eFormatComplexInteger:
+ case eFormatAddressInfo:
+ case eFormatHexFloat:
+ case eFormatInstruction:
+ case eFormatVoid:
+ result.AppendError("unsupported format for writing memory");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+
+ case eFormatDefault:
+ case eFormatBytes:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ case eFormatPointer:
+
+ // Decode hex bytes
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatBoolean:
+ uval64 = Args::StringToBoolean(value_str, false, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatBinary:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatCharArray:
+ case eFormatChar:
+ case eFormatCString:
+ if (value_str[0])
+ {
+ size_t len = strlen (value_str);
+ // Include the NULL for C strings...
+ if (m_format_options.GetFormat() == eFormatCString)
+ ++len;
+ Error error;
+ if (process->WriteMemory (addr, value_str, len, error) == len)
+ {
+ addr += len;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ break;
+
+ case eFormatDecimal:
+ sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!SIntValueIsValidForSize (sval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (sval64, item_byte_size);
+ break;
+
+ case eFormatUnsigned:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+
+ case eFormatOctal:
+ uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+ {
+ result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ buffer.PutMaxHex64 (uval64, item_byte_size);
+ break;
+ }
+ }
+
+ if (!buffer.GetString().empty())
+ {
+ Error error;
+ if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
+ return true;
+ else
+ {
+ result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ OptionGroupWriteMemory m_memory_options;
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectMemory
+//-------------------------------------------------------------------------
+
+CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "memory",
+ "A set of commands for operating on memory.",
+ "memory <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
+ LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
+}
+
+CommandObjectMemory::~CommandObjectMemory ()
+{
+}
diff --git a/source/Commands/CommandObjectMemory.h b/source/Commands/CommandObjectMemory.h
new file mode 100644
index 000000000000..b044921ae077
--- /dev/null
+++ b/source/Commands/CommandObjectMemory.h
@@ -0,0 +1,33 @@
+//===-- CommandObjectMemory.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_CommandObjectMemory_h_
+#define liblldb_CommandObjectMemory_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+class CommandObjectMemory : public CommandObjectMultiword
+{
+public:
+ CommandObjectMemory (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMemory ();
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectMemory_h_
diff --git a/source/Commands/CommandObjectMultiword.cpp b/source/Commands/CommandObjectMultiword.cpp
new file mode 100644
index 000000000000..f84b401f3aa6
--- /dev/null
+++ b/source/Commands/CommandObjectMultiword.cpp
@@ -0,0 +1,520 @@
+//===-- CommandObjectMultiword.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/Interpreter/CommandObjectMultiword.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiword
+//-------------------------------------------------------------------------
+
+CommandObjectMultiword::CommandObjectMultiword
+(
+ CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags
+) :
+ CommandObject (interpreter, name, help, syntax, flags),
+ m_can_be_removed(false)
+{
+}
+
+CommandObjectMultiword::~CommandObjectMultiword ()
+{
+}
+
+CommandObjectSP
+CommandObjectMultiword::GetSubcommandSP (const char *sub_cmd, StringList *matches)
+{
+ CommandObjectSP return_cmd_sp;
+ CommandObject::CommandMap::iterator pos;
+
+ if (!m_subcommand_dict.empty())
+ {
+ pos = m_subcommand_dict.find (sub_cmd);
+ if (pos != m_subcommand_dict.end()) {
+ // An exact match; append the sub_cmd to the 'matches' string list.
+ if (matches)
+ matches->AppendString(sub_cmd);
+ return_cmd_sp = pos->second;
+ }
+ else
+ {
+
+ StringList local_matches;
+ if (matches == NULL)
+ matches = &local_matches;
+ int num_matches = CommandObject::AddNamesMatchingPartialString (m_subcommand_dict, sub_cmd, *matches);
+
+ if (num_matches == 1)
+ {
+ // Cleaner, but slightly less efficient would be to call back into this function, since I now
+ // know I have an exact match...
+
+ sub_cmd = matches->GetStringAtIndex(0);
+ pos = m_subcommand_dict.find(sub_cmd);
+ if (pos != m_subcommand_dict.end())
+ return_cmd_sp = pos->second;
+ }
+ }
+ }
+ return return_cmd_sp;
+}
+
+CommandObject *
+CommandObjectMultiword::GetSubcommandObject (const char *sub_cmd, StringList *matches)
+{
+ return GetSubcommandSP(sub_cmd, matches).get();
+}
+
+bool
+CommandObjectMultiword::LoadSubCommand
+(
+ const char *name,
+ const CommandObjectSP& cmd_obj
+)
+{
+ CommandMap::iterator pos;
+ bool success = true;
+
+ pos = m_subcommand_dict.find(name);
+ if (pos == m_subcommand_dict.end())
+ {
+ m_subcommand_dict[name] = cmd_obj;
+ }
+ else
+ success = false;
+
+ return success;
+}
+
+bool
+CommandObjectMultiword::Execute(const char *args_string, CommandReturnObject &result)
+{
+ Args args (args_string);
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ this->CommandObject::GenerateHelpText (result);
+ }
+ else
+ {
+ const char *sub_command = args.GetArgumentAtIndex (0);
+
+ if (sub_command)
+ {
+ if (::strcasecmp (sub_command, "help") == 0)
+ {
+ this->CommandObject::GenerateHelpText (result);
+ }
+ else if (!m_subcommand_dict.empty())
+ {
+ StringList matches;
+ CommandObject *sub_cmd_obj = GetSubcommandObject(sub_command, &matches);
+ if (sub_cmd_obj != NULL)
+ {
+ // Now call CommandObject::Execute to process and options in 'rest_of_line'. From there
+ // the command-specific version of Execute will be called, with the processed arguments.
+
+ args.Shift();
+
+ sub_cmd_obj->Execute (args_string, result);
+ }
+ else
+ {
+ std::string error_msg;
+ const size_t num_subcmd_matches = matches.GetSize();
+ if (num_subcmd_matches > 0)
+ error_msg.assign ("ambiguous command ");
+ else
+ error_msg.assign ("invalid command ");
+
+ error_msg.append ("'");
+ error_msg.append (GetCommandName());
+ error_msg.append (" ");
+ error_msg.append (sub_command);
+ error_msg.append ("'");
+
+ if (num_subcmd_matches > 0)
+ {
+ error_msg.append (" Possible completions:");
+ for (size_t i = 0; i < num_subcmd_matches; i++)
+ {
+ error_msg.append ("\n\t");
+ error_msg.append (matches.GetStringAtIndex (i));
+ }
+ }
+ error_msg.append ("\n");
+ result.AppendRawError (error_msg.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' does not have any subcommands.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+}
+
+void
+CommandObjectMultiword::GenerateHelpText (Stream &output_stream)
+{
+ // First time through here, generate the help text for the object and
+ // push it to the return result object as well
+
+ output_stream.PutCString ("The following subcommands are supported:\n\n");
+
+ CommandMap::iterator pos;
+ uint32_t max_len = m_interpreter.FindLongestCommandWord (m_subcommand_dict);
+
+ if (max_len)
+ max_len += 4; // Indent the output by 4 spaces.
+
+ for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
+ {
+ std::string indented_command (" ");
+ indented_command.append (pos->first);
+ if (pos->second->WantsRawCommandString ())
+ {
+ std::string help_text (pos->second->GetHelp());
+ help_text.append (" This command takes 'raw' input (no need to quote stuff).");
+ m_interpreter.OutputFormattedHelpText (output_stream,
+ indented_command.c_str(),
+ "--",
+ help_text.c_str(),
+ max_len);
+ }
+ else
+ m_interpreter.OutputFormattedHelpText (output_stream,
+ indented_command.c_str(),
+ "--",
+ pos->second->GetHelp(),
+ max_len);
+ }
+
+ output_stream.PutCString ("\nFor more help on any particular subcommand, type 'help <command> <subcommand>'.\n");
+}
+
+int
+CommandObjectMultiword::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ // Any of the command matches will provide a complete word, otherwise the individual
+ // completers will override this.
+ word_complete = true;
+
+ if (cursor_index == 0)
+ {
+ CommandObject::AddNamesMatchingPartialString (m_subcommand_dict,
+ input.GetArgumentAtIndex(0),
+ matches);
+
+ if (matches.GetSize() == 1
+ && matches.GetStringAtIndex(0) != NULL
+ && strcmp (input.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
+ {
+ StringList temp_matches;
+ CommandObject *cmd_obj = GetSubcommandObject (input.GetArgumentAtIndex(0),
+ &temp_matches);
+ if (cmd_obj != NULL)
+ {
+ matches.DeleteStringAtIndex (0);
+ input.Shift();
+ cursor_char_position = 0;
+ input.AppendArgument ("");
+ return cmd_obj->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ else
+ return matches.GetSize();
+ }
+ else
+ return matches.GetSize();
+ }
+ else
+ {
+ CommandObject *sub_command_object = GetSubcommandObject (input.GetArgumentAtIndex(0),
+ &matches);
+ if (sub_command_object == NULL)
+ {
+ return matches.GetSize();
+ }
+ else
+ {
+ // Remove the one match that we got from calling GetSubcommandObject.
+ matches.DeleteStringAtIndex(0);
+ input.Shift();
+ cursor_index--;
+ return sub_command_object->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+
+ }
+}
+
+const char *
+CommandObjectMultiword::GetRepeatCommand (Args &current_command_args, uint32_t index)
+{
+ index++;
+ if (current_command_args.GetArgumentCount() <= index)
+ return NULL;
+ CommandObject *sub_command_object = GetSubcommandObject (current_command_args.GetArgumentAtIndex(index));
+ if (sub_command_object == NULL)
+ return NULL;
+ return sub_command_object->GetRepeatCommand(current_command_args, index);
+}
+
+
+void
+CommandObjectMultiword::AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject::CommandMap::const_iterator pos;
+
+ for (pos = m_subcommand_dict.begin(); pos != m_subcommand_dict.end(); ++pos)
+ {
+ const char * command_name = pos->first.c_str();
+ CommandObject *sub_cmd_obj = pos->second.get();
+ StreamString complete_command_name;
+
+ complete_command_name.Printf ("%s %s", prefix, command_name);
+
+ if (sub_cmd_obj->HelpTextContainsWord (search_word))
+ {
+ commands_found.AppendString (complete_command_name.GetData());
+ commands_help.AppendString (sub_cmd_obj->GetHelp());
+ }
+
+ if (sub_cmd_obj->IsMultiwordObject())
+ sub_cmd_obj->AproposAllSubCommands (complete_command_name.GetData(),
+ search_word,
+ commands_found,
+ commands_help);
+ }
+}
+
+
+
+CommandObjectProxy::CommandObjectProxy (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObject (interpreter, name, help, syntax, flags)
+{
+}
+
+CommandObjectProxy::~CommandObjectProxy ()
+{
+}
+
+const char *
+CommandObjectProxy::GetHelpLong ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetHelpLong();
+ return NULL;
+}
+
+bool
+CommandObjectProxy::IsRemovable() const
+{
+ const CommandObject *proxy_command = const_cast<CommandObjectProxy *>(this)->GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->IsRemovable();
+ return false;
+}
+
+bool
+CommandObjectProxy::IsMultiwordObject ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->IsMultiwordObject();
+ return false;
+}
+
+lldb::CommandObjectSP
+CommandObjectProxy::GetSubcommandSP (const char *sub_cmd, StringList *matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetSubcommandSP(sub_cmd, matches);
+ return lldb::CommandObjectSP();
+}
+
+CommandObject *
+CommandObjectProxy::GetSubcommandObject (const char *sub_cmd, StringList *matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetSubcommandObject(sub_cmd, matches);
+ return NULL;
+}
+
+void
+CommandObjectProxy::AproposAllSubCommands (const char *prefix,
+ const char *search_word,
+ StringList &commands_found,
+ StringList &commands_help)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->AproposAllSubCommands (prefix,
+ search_word,
+ commands_found,
+ commands_help);
+}
+
+bool
+CommandObjectProxy::LoadSubCommand (const char *cmd_name,
+ const lldb::CommandObjectSP& command_sp)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->LoadSubCommand (cmd_name, command_sp);
+ return false;
+}
+
+bool
+CommandObjectProxy::WantsRawCommandString()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->WantsRawCommandString();
+ return false;
+}
+
+bool
+CommandObjectProxy::WantsCompletion()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->WantsCompletion();
+ return false;
+}
+
+
+Options *
+CommandObjectProxy::GetOptions ()
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetOptions ();
+ return NULL;
+}
+
+
+int
+CommandObjectProxy::HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->HandleCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ matches.Clear();
+ return 0;
+}
+int
+CommandObjectProxy::HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->HandleArgumentCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ opt_element_vector,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ matches.Clear();
+ return 0;
+}
+
+const char *
+CommandObjectProxy::GetRepeatCommand (Args &current_command_args,
+ uint32_t index)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->GetRepeatCommand (current_command_args, index);
+ return NULL;
+}
+
+bool
+CommandObjectProxy::Execute (const char *args_string,
+ CommandReturnObject &result)
+{
+ CommandObject *proxy_command = GetProxyCommandObject();
+ if (proxy_command)
+ return proxy_command->Execute (args_string, result);
+ result.AppendError ("command is not implemented");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+}
+
+
diff --git a/source/Commands/CommandObjectPlatform.cpp b/source/Commands/CommandObjectPlatform.cpp
new file mode 100644
index 000000000000..c2185e598ad4
--- /dev/null
+++ b/source/Commands/CommandObjectPlatform.cpp
@@ -0,0 +1,987 @@
+//===-- CommandObjectPlatform.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 "CommandObjectPlatform.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// "platform select <platform-name>"
+//----------------------------------------------------------------------
+class CommandObjectPlatformSelect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform select",
+ "Create a platform if needed and select it as the current platform.",
+ "platform select <platform-name>",
+ 0),
+ m_option_group (interpreter),
+ m_platform_options (false) // Don't include the "--platform" option by passing false
+ {
+ m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, 1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectPlatformSelect ()
+ {
+ }
+
+ virtual int
+ HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::PlatformPluginNames (m_interpreter,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ const char *platform_name = args.GetArgumentAtIndex (0);
+ if (platform_name && platform_name[0])
+ {
+ const bool select = true;
+ m_platform_options.SetPlatformName (platform_name);
+ Error error;
+ ArchSpec platform_arch;
+ PlatformSP platform_sp (m_platform_options.CreatePlatformWithOptions (m_interpreter, ArchSpec(), select, error, platform_arch));
+ if (platform_sp)
+ {
+ platform_sp->GetStatus (result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid platform name");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("platform create takes a platform name as an argument\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupPlatform m_platform_options;
+};
+
+//----------------------------------------------------------------------
+// "platform list"
+//----------------------------------------------------------------------
+class CommandObjectPlatformList : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform list",
+ "List all platforms that are available.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformList ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+ ostrm.Printf("Available platforms:\n");
+
+ PlatformSP host_platform_sp (Platform::GetDefaultPlatform());
+ ostrm.Printf ("%s: %s\n",
+ host_platform_sp->GetPluginName().GetCString(),
+ host_platform_sp->GetDescription());
+
+ uint32_t idx;
+ for (idx = 0; 1; ++idx)
+ {
+ const char *plugin_name = PluginManager::GetPlatformPluginNameAtIndex (idx);
+ if (plugin_name == NULL)
+ break;
+ const char *plugin_desc = PluginManager::GetPlatformPluginDescriptionAtIndex (idx);
+ if (plugin_desc == NULL)
+ break;
+ ostrm.Printf("%s: %s\n", plugin_name, plugin_desc);
+ }
+
+ if (idx == 0)
+ {
+ result.AppendError ("no platforms are available\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform status"
+//----------------------------------------------------------------------
+class CommandObjectPlatformStatus : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformStatus (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform status",
+ "Display status for the currently selected platform.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformStatus ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+ if (platform_sp)
+ {
+ platform_sp->GetStatus (ostrm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("no platform us currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform connect <connect-url>"
+//----------------------------------------------------------------------
+class CommandObjectPlatformConnect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformConnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform connect",
+ "Connect a platform by name to be the currently selected platform.",
+ "platform connect <connect-url>",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformConnect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ Error error (platform_sp->ConnectRemote (args));
+ if (error.Success())
+ {
+ platform_sp->GetStatus (ostrm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("%s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform us currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// "platform disconnect"
+//----------------------------------------------------------------------
+class CommandObjectPlatformDisconnect : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformDisconnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform disconnect",
+ "Disconnect a platform by name to be the currently selected platform.",
+ "platform disconnect",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformDisconnect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ PlatformSP platform_sp (m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform());
+ if (platform_sp)
+ {
+ if (args.GetArgumentCount() == 0)
+ {
+ Error error;
+
+ if (platform_sp->IsConnected())
+ {
+ // Cache the instance name if there is one since we are
+ // about to disconnect and the name might go with it.
+ const char *hostname_cstr = platform_sp->GetHostname();
+ std::string hostname;
+ if (hostname_cstr)
+ hostname.assign (hostname_cstr);
+
+ error = platform_sp->DisconnectRemote ();
+ if (error.Success())
+ {
+ Stream &ostrm = result.GetOutputStream();
+ if (hostname.empty())
+ ostrm.Printf ("Disconnected from \"%s\"\n", platform_sp->GetPluginName().GetCString());
+ else
+ ostrm.Printf ("Disconnected from \"%s\"\n", hostname.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("%s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Not connected...
+ result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Bad args
+ result.AppendError ("\"platform disconnect\" doesn't take any arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+//----------------------------------------------------------------------
+// "platform process launch"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessLaunch : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessLaunch (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process launch",
+ "Launch a new process on a remote platform.",
+ "platform process launch program",
+ eFlagRequiresTarget | eFlagTryTargetAPILock),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessLaunch ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ Error error;
+ const size_t argc = args.GetArgumentCount();
+ Target *target = m_exe_ctx.GetTargetPtr();
+ Module *exe_module = target->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ m_options.launch_info.GetExecutableFile () = exe_module->GetFileSpec();
+ char exe_path[PATH_MAX];
+ if (m_options.launch_info.GetExecutableFile ().GetPath (exe_path, sizeof(exe_path)))
+ m_options.launch_info.GetArguments().AppendArgument (exe_path);
+ m_options.launch_info.GetArchitecture() = exe_module->GetArchitecture();
+ }
+
+ if (argc > 0)
+ {
+ if (m_options.launch_info.GetExecutableFile ())
+ {
+ // We already have an executable file, so we will use this
+ // and all arguments to this function are extra arguments
+ m_options.launch_info.GetArguments().AppendArguments (args);
+ }
+ else
+ {
+ // We don't have any file yet, so the first argument is our
+ // executable, and the rest are program arguments
+ const bool first_arg_is_executable = true;
+ m_options.launch_info.SetArguments (args, first_arg_is_executable);
+ }
+ }
+
+ if (m_options.launch_info.GetExecutableFile ())
+ {
+ Debugger &debugger = m_interpreter.GetDebugger();
+
+ if (argc == 0)
+ target->GetRunArguments(m_options.launch_info.GetArguments());
+
+ ProcessSP process_sp (platform_sp->DebugProcess (m_options.launch_info,
+ debugger,
+ target,
+ debugger.GetListener(),
+ error));
+ if (process_sp && process_sp->IsAlive())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ if (error.Success())
+ result.AppendError ("process launch failed");
+ else
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendError ("'platform process launch' uses the current target file and arguments, or the executable and its arguments can be specified in this command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is selected\n");
+ }
+ return result.Succeeded();
+ }
+
+protected:
+ ProcessLaunchCommandOptions m_options;
+};
+
+
+
+//----------------------------------------------------------------------
+// "platform process list"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessList : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process list",
+ "List processes on a remote platform by name, pid, or many other matching attributes.",
+ "platform process list",
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessList ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ Error error;
+ if (args.GetArgumentCount() == 0)
+ {
+
+ if (platform_sp)
+ {
+ Stream &ostrm = result.GetOutputStream();
+
+ lldb::pid_t pid = m_options.match_info.GetProcessInfo().GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (platform_sp->GetProcessInfo (pid, proc_info))
+ {
+ ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ proc_info.DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no process found with pid = %" PRIu64 "\n", pid);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ ProcessInstanceInfoList proc_infos;
+ const uint32_t matches = platform_sp->FindProcesses (m_options.match_info, proc_infos);
+ const char *match_desc = NULL;
+ const char *match_name = m_options.match_info.GetProcessInfo().GetName();
+ if (match_name && match_name[0])
+ {
+ switch (m_options.match_info.GetNameMatchType())
+ {
+ case eNameMatchIgnore: break;
+ case eNameMatchEquals: match_desc = "matched"; break;
+ case eNameMatchContains: match_desc = "contained"; break;
+ case eNameMatchStartsWith: match_desc = "started with"; break;
+ case eNameMatchEndsWith: match_desc = "ended with"; break;
+ case eNameMatchRegularExpression: match_desc = "matched the regular expression"; break;
+ }
+ }
+
+ if (matches == 0)
+ {
+ if (match_desc)
+ result.AppendErrorWithFormat ("no processes were found that %s \"%s\" on the \"%s\" platform\n",
+ match_desc,
+ match_name,
+ platform_sp->GetPluginName().GetCString());
+ else
+ result.AppendErrorWithFormat ("no processes were found on the \"%s\" platform\n", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("%u matching process%s found on \"%s\"",
+ matches,
+ matches > 1 ? "es were" : " was",
+ platform_sp->GetName().GetCString());
+ if (match_desc)
+ result.AppendMessageWithFormat (" whose name %s \"%s\"",
+ match_desc,
+ match_name);
+ result.AppendMessageWithFormat ("\n");
+ ProcessInstanceInfo::DumpTableHeader (ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ for (uint32_t i=0; i<matches; ++i)
+ {
+ proc_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(ostrm, platform_sp.get(), m_options.show_args, m_options.verbose);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid args: process list takes only options\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ match_info ()
+ {
+ }
+
+ 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;
+ bool success = false;
+
+ switch (short_option)
+ {
+ case 'p':
+ match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid process ID string: '%s'", option_arg);
+ break;
+
+ case 'P':
+ match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid parent process ID string: '%s'", option_arg);
+ break;
+
+ case 'u':
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid user ID string: '%s'", option_arg);
+ break;
+
+ case 'U':
+ match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid effective user ID string: '%s'", option_arg);
+ break;
+
+ case 'g':
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid group ID string: '%s'", option_arg);
+ break;
+
+ case 'G':
+ match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid effective group ID string: '%s'", option_arg);
+ break;
+
+ case 'a':
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (option_arg, m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform().get());
+ break;
+
+ case 'n':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchEquals);
+ break;
+
+ case 'e':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ break;
+
+ case 's':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ break;
+
+ case 'c':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchContains);
+ break;
+
+ case 'r':
+ match_info.GetProcessInfo().GetExecutableFile().SetFile (option_arg, false);
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ break;
+
+ case 'A':
+ show_args = true;
+ break;
+
+ case 'v':
+ verbose = true;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ match_info.Clear();
+ show_args = false;
+ verbose = 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.
+
+ ProcessInstanceInfoMatch match_info;
+ bool show_args;
+ bool verbose;
+ };
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectPlatformProcessList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1 , false, "pid" , 'p', required_argument, NULL, 0, eArgTypePid , "List the process info for a specific process ID." },
+{ LLDB_OPT_SET_2 , true , "name" , 'n', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that match a string." },
+{ LLDB_OPT_SET_3 , true , "ends-with" , 'e', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that end with a string." },
+{ LLDB_OPT_SET_4 , true , "starts-with", 's', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that start with a string." },
+{ LLDB_OPT_SET_5 , true , "contains" , 'c', required_argument, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." },
+{ LLDB_OPT_SET_6 , true , "regex" , 'r', required_argument, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', required_argument, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', required_argument, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." },
+{ LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', no_argument , NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." },
+{ LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', no_argument , NULL, 0, eArgTypeNone , "Enable verbose output." },
+{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone , NULL }
+};
+
+//----------------------------------------------------------------------
+// "platform process info"
+//----------------------------------------------------------------------
+class CommandObjectPlatformProcessInfo : public CommandObjectParsed
+{
+public:
+ CommandObjectPlatformProcessInfo (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "platform process info",
+ "Get detailed information for one or more process by process ID.",
+ "platform process info <pid> [<pid> <pid> ...]",
+ 0)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData pid_args;
+
+ // Define the first (and only) variant of this arg.
+ pid_args.arg_type = eArgTypePid;
+ pid_args.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (pid_args);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectPlatformProcessInfo ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ PlatformSP platform_sp;
+ if (target)
+ {
+ platform_sp = target->GetPlatform();
+ }
+ if (!platform_sp)
+ {
+ platform_sp = m_interpreter.GetDebugger().GetPlatformList().GetSelectedPlatform();
+ }
+
+ if (platform_sp)
+ {
+ const size_t argc = args.GetArgumentCount();
+ if (argc > 0)
+ {
+ Error error;
+
+ if (platform_sp->IsConnected())
+ {
+ Stream &ostrm = result.GetOutputStream();
+ bool success;
+ for (size_t i=0; i<argc; ++ i)
+ {
+ const char *arg = args.GetArgumentAtIndex(i);
+ lldb::pid_t pid = Args::StringToUInt32 (arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (success)
+ {
+ ProcessInstanceInfo proc_info;
+ if (platform_sp->GetProcessInfo (pid, proc_info))
+ {
+ ostrm.Printf ("Process information for process %" PRIu64 ":\n", pid);
+ proc_info.Dump (ostrm, platform_sp.get());
+ }
+ else
+ {
+ ostrm.Printf ("error: no process information is available for process %" PRIu64 "\n", pid);
+ }
+ ostrm.EOL();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid process ID argument '%s'", arg);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Not connected...
+ result.AppendErrorWithFormat ("not connected to '%s'", platform_sp->GetPluginName().GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // No args
+ result.AppendError ("one or more process id(s) must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("no platform is currently selected");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+
+
+class CommandObjectPlatformProcess : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectPlatformProcess (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "platform process",
+ "A set of commands to query, launch and attach to platform processes",
+ "platform process [attach|launch|list] ...")
+ {
+// LoadSubCommand ("attach", CommandObjectSP (new CommandObjectPlatformProcessAttach (interpreter)));
+ LoadSubCommand ("launch", CommandObjectSP (new CommandObjectPlatformProcessLaunch (interpreter)));
+ LoadSubCommand ("info" , CommandObjectSP (new CommandObjectPlatformProcessInfo (interpreter)));
+ LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformProcessList (interpreter)));
+
+ }
+
+ virtual
+ ~CommandObjectPlatformProcess ()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectPlatform only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatformProcess);
+};
+
+
+class CommandObjectPlatformShell : public CommandObjectRaw
+{
+public:
+ CommandObjectPlatformShell (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "platform shell",
+ "Run a shell command on a the selected platform.",
+ "platform shell <shell-command>",
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectPlatformShell ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command_line, CommandReturnObject &result)
+ {
+ // TODO: Implement "Platform::RunShellCommand()" and switch over to using
+ // the current platform when it is in the interface.
+ const char *working_dir = NULL;
+ std::string output;
+ int status = -1;
+ int signo = -1;
+ Error error (Host::RunShellCommand (raw_command_line, working_dir, &status, &signo, &output, 10));
+ if (!output.empty())
+ result.GetOutputStream().PutCString(output.c_str());
+ if (status > 0)
+ {
+ if (signo > 0)
+ {
+ const char *signo_cstr = Host::GetSignalAsCString(signo);
+ if (signo_cstr)
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %s\n", status, signo_cstr);
+ else
+ result.GetOutputStream().Printf("error: command returned with status %i and signal %i\n", status, signo);
+ }
+ else
+ result.GetOutputStream().Printf("error: command returned with status %i\n", status);
+ }
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ return true;
+ }
+};
+
+//----------------------------------------------------------------------
+// CommandObjectPlatform constructor
+//----------------------------------------------------------------------
+CommandObjectPlatform::CommandObjectPlatform(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "platform",
+ "A set of commands to manage and create platforms.",
+ "platform [connect|disconnect|info|list|status|select] ...")
+{
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectPlatformSelect (interpreter)));
+ LoadSubCommand ("list" , CommandObjectSP (new CommandObjectPlatformList (interpreter)));
+ LoadSubCommand ("status", CommandObjectSP (new CommandObjectPlatformStatus (interpreter)));
+ LoadSubCommand ("connect", CommandObjectSP (new CommandObjectPlatformConnect (interpreter)));
+ LoadSubCommand ("disconnect", CommandObjectSP (new CommandObjectPlatformDisconnect (interpreter)));
+ LoadSubCommand ("process", CommandObjectSP (new CommandObjectPlatformProcess (interpreter)));
+ LoadSubCommand ("shell", CommandObjectSP (new CommandObjectPlatformShell (interpreter)));
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectPlatform::~CommandObjectPlatform()
+{
+}
diff --git a/source/Commands/CommandObjectPlatform.h b/source/Commands/CommandObjectPlatform.h
new file mode 100644
index 000000000000..f3bd75848649
--- /dev/null
+++ b/source/Commands/CommandObjectPlatform.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectPlatform.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_CommandObjectPlatform_h_
+#define liblldb_CommandObjectPlatform_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectPlatform
+//-------------------------------------------------------------------------
+
+class CommandObjectPlatform : public CommandObjectMultiword
+{
+public:
+ CommandObjectPlatform(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectPlatform();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectPlatform);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectPlatform_h_
diff --git a/source/Commands/CommandObjectPlugin.cpp b/source/Commands/CommandObjectPlugin.cpp
new file mode 100644
index 000000000000..1bc7632e2985
--- /dev/null
+++ b/source/Commands/CommandObjectPlugin.cpp
@@ -0,0 +1,122 @@
+//===-- CommandObjectPlugin.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 "CommandObjectPlugin.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CommandObjectPluginLoad : public CommandObjectParsed
+{
+private:
+public:
+ CommandObjectPluginLoad (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "plugin load",
+ "Import a dylib that implements an LLDB plugin.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData cmd_arg;
+
+ // Define the first (and only) variant of this arg.
+ cmd_arg.arg_type = eArgTypeFilename;
+ cmd_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (cmd_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ ~CommandObjectPluginLoad ()
+ {
+ }
+
+ int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ typedef void (*LLDBCommandPluginInit) (lldb::SBDebugger debugger);
+
+ size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'plugin load' requires one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char* path = command.GetArgumentAtIndex(0);
+
+ Error error;
+
+ FileSpec dylib_fspec(path,true);
+
+ if (m_interpreter.GetDebugger().LoadPlugin(dylib_fspec, error))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+CommandObjectPlugin::CommandObjectPlugin (CommandInterpreter &interpreter) :
+CommandObjectMultiword (interpreter,
+ "plugin",
+ "A set of commands for managing or customizing plugin commands.",
+ "plugin <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectPluginLoad (interpreter)));
+}
+
+CommandObjectPlugin::~CommandObjectPlugin ()
+{
+}
diff --git a/source/Commands/CommandObjectPlugin.h b/source/Commands/CommandObjectPlugin.h
new file mode 100644
index 000000000000..9d0f0fcc1ed3
--- /dev/null
+++ b/source/Commands/CommandObjectPlugin.h
@@ -0,0 +1,36 @@
+//===-- CommandObjectPlugin.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_CommandObjectPlugin_h_
+#define liblldb_CommandObjectPlugin_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+ class CommandObjectPlugin : public CommandObjectMultiword
+ {
+ public:
+ CommandObjectPlugin (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectPlugin ();
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectPlugin_h_
diff --git a/source/Commands/CommandObjectProcess.cpp b/source/Commands/CommandObjectProcess.cpp
new file mode 100644
index 000000000000..4c406a4f2aae
--- /dev/null
+++ b/source/Commands/CommandObjectProcess.cpp
@@ -0,0 +1,1945 @@
+//===-- CommandObjectProcess.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 "CommandObjectProcess.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed
+{
+public:
+ CommandObjectProcessLaunchOrAttach (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags,
+ const char *new_process_action) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags),
+ m_new_process_action (new_process_action) {}
+
+ virtual ~CommandObjectProcessLaunchOrAttach () {}
+protected:
+ bool
+ StopProcessIfNecessary (Process *&process, StateType &state, CommandReturnObject &result)
+ {
+ state = eStateInvalid;
+ if (process)
+ {
+ state = process->GetState();
+
+ if (process->IsAlive() && state != eStateConnected)
+ {
+ char message[1024];
+ if (process->GetState() == eStateAttaching)
+ ::snprintf (message, sizeof(message), "There is a pending attach, abort it and %s?", m_new_process_action.c_str());
+ else if (process->GetShouldDetach())
+ ::snprintf (message, sizeof(message), "There is a running process, detach from it and %s?", m_new_process_action.c_str());
+ else
+ ::snprintf (message, sizeof(message), "There is a running process, kill it and %s?", m_new_process_action.c_str());
+
+ if (!m_interpreter.Confirm (message, true))
+ {
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (process->GetShouldDetach())
+ {
+ bool keep_stopped = false;
+ Error detach_error (process->Detach(keep_stopped));
+ if (detach_error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ process = NULL;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to detach from process: %s\n", detach_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ Error destroy_error (process->Destroy());
+ if (destroy_error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ process = NULL;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to kill process: %s\n", destroy_error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+ std::string m_new_process_action;
+};
+//-------------------------------------------------------------------------
+// CommandObjectProcessLaunch
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessLaunch
+class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach
+{
+public:
+
+ CommandObjectProcessLaunch (CommandInterpreter &interpreter) :
+ CommandObjectProcessLaunchOrAttach (interpreter,
+ "process launch",
+ "Launch the executable in the debugger.",
+ NULL,
+ eFlagRequiresTarget,
+ "restart"),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData run_args_arg;
+
+ // Define the first (and only) variant of this arg.
+ run_args_arg.arg_type = eArgTypeRunArgs;
+ run_args_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (run_args_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ ~CommandObjectProcessLaunch ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ // No repeat for "process launch"...
+ return "";
+ }
+
+protected:
+ bool
+ DoExecute (Args& launch_args, CommandReturnObject &result)
+ {
+ Debugger &debugger = m_interpreter.GetDebugger();
+ Target *target = debugger.GetSelectedTarget().get();
+ Error error;
+ // If our listener is NULL, users aren't allows to launch
+ char filename[PATH_MAX];
+ const Module *exe_module = target->GetExecutableModulePointer();
+
+ if (exe_module == NULL)
+ {
+ result.AppendError ("no file in target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ StateType state = eStateInvalid;
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (!StopProcessIfNecessary(process, state, result))
+ return false;
+
+ const char *target_settings_argv0 = target->GetArg0();
+
+ exe_module->GetFileSpec().GetPath (filename, sizeof(filename));
+
+ if (target_settings_argv0)
+ {
+ m_options.launch_info.GetArguments().AppendArgument (target_settings_argv0);
+ m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), false);
+ }
+ else
+ {
+ m_options.launch_info.SetExecutableFile(exe_module->GetPlatformFileSpec(), true);
+ }
+
+ if (launch_args.GetArgumentCount() == 0)
+ {
+ Args target_setting_args;
+ if (target->GetRunArguments(target_setting_args))
+ m_options.launch_info.GetArguments().AppendArguments (target_setting_args);
+ }
+ else
+ {
+ m_options.launch_info.GetArguments().AppendArguments (launch_args);
+
+ // Save the arguments for subsequent runs in the current target.
+ target->SetRunArguments (launch_args);
+ }
+
+ if (target->GetDisableASLR())
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+
+ if (target->GetDisableSTDIO())
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDisableSTDIO);
+
+ m_options.launch_info.GetFlags().Set (eLaunchFlagDebug);
+
+ Args environment;
+ target->GetEnvironmentAsArgs (environment);
+ if (environment.GetArgumentCount() > 0)
+ m_options.launch_info.GetEnvironmentEntries ().AppendArguments (environment);
+
+ // Get the value of synchronous execution here. If you wait till after you have started to
+ // run, then you could have hit a breakpoint, whose command might switch the value, and
+ // then you'll pick up that incorrect value.
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ // Finalize the file actions, and if none were given, default to opening
+ // up a pseudo terminal
+ const bool default_to_use_pty = true;
+ m_options.launch_info.FinalizeFileActions (target, default_to_use_pty);
+
+ if (state == eStateConnected)
+ {
+ if (m_options.launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY))
+ {
+ result.AppendWarning("can't launch in tty when launching through a remote connection");
+ m_options.launch_info.GetFlags().Clear (eLaunchFlagLaunchInTTY);
+ }
+ }
+
+ if (!m_options.launch_info.GetArchitecture().IsValid())
+ m_options.launch_info.GetArchitecture() = target->GetArchitecture();
+
+ PlatformSP platform_sp (target->GetPlatform());
+
+ if (platform_sp && platform_sp->CanDebugProcess ())
+ {
+ process = target->GetPlatform()->DebugProcess (m_options.launch_info,
+ debugger,
+ target,
+ debugger.GetListener(),
+ error).get();
+ }
+ else
+ {
+ const char *plugin_name = m_options.launch_info.GetProcessPluginName();
+ process = target->CreateProcess (debugger.GetListener(), plugin_name, NULL).get();
+ if (process)
+ error = process->Launch (m_options.launch_info);
+ }
+
+ if (process == NULL)
+ {
+ result.SetError (error, "failed to launch or debug process");
+ return false;
+ }
+
+
+ if (error.Success())
+ {
+ const char *archname = exe_module->GetArchitecture().GetArchitectureName();
+
+ result.AppendMessageWithFormat ("Process %" PRIu64 " launched: '%s' (%s)\n", process->GetID(), filename, archname);
+ result.SetDidChangeProcessState (true);
+ if (m_options.launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ if (state == eStateStopped)
+ {
+ error = process->Resume();
+ if (error.Success())
+ {
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+ const bool must_be_alive = true;
+ if (!StateIsStoppedState(state, must_be_alive))
+ {
+ result.AppendErrorWithFormat ("process isn't stopped: %s", StateAsCString(state));
+ }
+ result.SetDidChangeProcessState (true);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process resume at entry point failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process launch failed: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+protected:
+ ProcessLaunchCommandOptions m_options;
+};
+
+
+//#define SET1 LLDB_OPT_SET_1
+//#define SET2 LLDB_OPT_SET_2
+//#define SET3 LLDB_OPT_SET_3
+//
+//OptionDefinition
+//CommandObjectProcessLaunch::CommandOptions::g_option_table[] =
+//{
+//{ SET1 | SET2 | SET3, false, "stop-at-entry", 's', no_argument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
+//{ SET1 , false, "stdin", 'i', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stdin for the process to <path>."},
+//{ SET1 , false, "stdout", 'o', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stdout for the process to <path>."},
+//{ SET1 , false, "stderr", 'e', required_argument, NULL, 0, eArgTypeDirectoryName, "Redirect stderr for the process to <path>."},
+//{ SET1 | SET2 | SET3, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+//{ SET2 , false, "tty", 't', optional_argument, NULL, 0, eArgTypeDirectoryName, "Start the process in a terminal. If <path> is specified, look for a terminal whose name contains <path>, else start the process in a new terminal."},
+//{ SET3, false, "no-stdio", 'n', no_argument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
+//{ SET1 | SET2 | SET3, false, "working-dir", 'w', required_argument, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
+//{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+//};
+//
+//#undef SET1
+//#undef SET2
+//#undef SET3
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessAttach
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessAttach
+class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'c':
+ attach_info.SetContinueOnceAttached(true);
+ break;
+
+ case 'p':
+ {
+ lldb::pid_t pid = Args::StringToUInt32 (option_arg, LLDB_INVALID_PROCESS_ID, 0, &success);
+ if (!success || pid == LLDB_INVALID_PROCESS_ID)
+ {
+ error.SetErrorStringWithFormat("invalid process ID '%s'", option_arg);
+ }
+ else
+ {
+ attach_info.SetProcessID (pid);
+ }
+ }
+ break;
+
+ case 'P':
+ attach_info.SetProcessPluginName (option_arg);
+ break;
+
+ case 'n':
+ attach_info.GetExecutableFile().SetFile(option_arg, false);
+ break;
+
+ case 'w':
+ attach_info.SetWaitForLaunch(true);
+ break;
+
+ case 'i':
+ attach_info.SetIgnoreExisting(false);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ attach_info.Clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual bool
+ HandleOptionArgumentCompletion (Args &input,
+ int cursor_index,
+ int char_pos,
+ OptionElementVector &opt_element_vector,
+ int opt_element_index,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+
+ // We are only completing the name option for now...
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+ if (opt_defs[opt_defs_index].short_option == 'n')
+ {
+ // Are we in the name?
+
+ // Look to see if there is a -P argument provided, and if so use that plugin, otherwise
+ // use the default plugin.
+
+ const char *partial_name = NULL;
+ partial_name = input.GetArgumentAtIndex(opt_arg_pos);
+
+ PlatformSP platform_sp (m_interpreter.GetPlatform (true));
+ if (platform_sp)
+ {
+ ProcessInstanceInfoList process_infos;
+ ProcessInstanceInfoMatch match_info;
+ if (partial_name)
+ {
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(partial_name, false);
+ match_info.SetNameMatchType(eNameMatchStartsWith);
+ }
+ platform_sp->FindProcesses (match_info, process_infos);
+ const size_t num_matches = process_infos.GetSize();
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ matches.AppendString (process_infos.GetProcessNameAtIndex(i),
+ process_infos.GetProcessNameLengthAtIndex(i));
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ ProcessAttachInfo attach_info;
+ };
+
+ CommandObjectProcessAttach (CommandInterpreter &interpreter) :
+ CommandObjectProcessLaunchOrAttach (interpreter,
+ "process attach",
+ "Attach to a process.",
+ "process attach <cmd-options>",
+ 0,
+ "attach"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectProcessAttach ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ // N.B. The attach should be synchronous. It doesn't help much to get the prompt back between initiating the attach
+ // and the target actually stopping. So even if the interpreter is set to be asynchronous, we wait for the stop
+ // ourselves here.
+
+ StateType state = eStateInvalid;
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (!StopProcessIfNecessary (process, state, result))
+ return false;
+
+ if (target == NULL)
+ {
+ // If there isn't a current target create one.
+ TargetSP new_target_sp;
+ Error error;
+
+ error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
+ NULL,
+ NULL,
+ false,
+ NULL, // No platform options
+ new_target_sp);
+ target = new_target_sp.get();
+ if (target == NULL || error.Fail())
+ {
+ result.AppendError(error.AsCString("Error creating target"));
+ return false;
+ }
+ m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target);
+ }
+
+ // Record the old executable module, we want to issue a warning if the process of attaching changed the
+ // current executable (like somebody said "file foo" then attached to a PID whose executable was bar.)
+
+ ModuleSP old_exec_module_sp = target->GetExecutableModule();
+ ArchSpec old_arch_spec = target->GetArchitecture();
+
+ if (command.GetArgumentCount())
+ {
+ result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ if (state != eStateConnected)
+ {
+ const char *plugin_name = m_options.attach_info.GetProcessPluginName();
+ process = target->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get();
+ }
+
+ if (process)
+ {
+ Error error;
+ // If no process info was specified, then use the target executable
+ // name as the process to attach to by default
+ if (!m_options.attach_info.ProcessInfoSpecified ())
+ {
+ if (old_exec_module_sp)
+ m_options.attach_info.GetExecutableFile().GetFilename() = old_exec_module_sp->GetPlatformFileSpec().GetFilename();
+
+ if (!m_options.attach_info.ProcessInfoSpecified ())
+ {
+ error.SetErrorString ("no process specified, create a target with a file, or specify the --pid or --name command option");
+ }
+ }
+
+ if (error.Success())
+ {
+ error = process->Attach (m_options.attach_info);
+
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("attach failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // If we're synchronous, wait for the stopped event and report that.
+ // Otherwise just return.
+ // FIXME: in the async case it will now be possible to get to the command
+ // interpreter with a state eStateAttaching. Make sure we handle that correctly.
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+
+ if (state == eStateStopped)
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("attach failed: process did not stop (no such process or permission problem?)");
+ process->Destroy();
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ }
+
+ if (result.Succeeded())
+ {
+ // Okay, we're done. Last step is to warn if the executable module has changed:
+ char new_path[PATH_MAX];
+ ModuleSP new_exec_module_sp (target->GetExecutableModule());
+ if (!old_exec_module_sp)
+ {
+ // We might not have a module if we attached to a raw pid...
+ if (new_exec_module_sp)
+ {
+ new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
+ result.AppendMessageWithFormat("Executable module set to \"%s\".\n", new_path);
+ }
+ }
+ else if (old_exec_module_sp->GetFileSpec() != new_exec_module_sp->GetFileSpec())
+ {
+ char old_path[PATH_MAX];
+
+ old_exec_module_sp->GetFileSpec().GetPath (old_path, PATH_MAX);
+ new_exec_module_sp->GetFileSpec().GetPath (new_path, PATH_MAX);
+
+ result.AppendWarningWithFormat("Executable module changed from \"%s\" to \"%s\".\n",
+ old_path, new_path);
+ }
+
+ if (!old_arch_spec.IsValid())
+ {
+ result.AppendMessageWithFormat ("Architecture set to: %s.\n", target->GetArchitecture().GetTriple().getTriple().c_str());
+ }
+ else if (!old_arch_spec.IsExactMatch(target->GetArchitecture()))
+ {
+ result.AppendWarningWithFormat("Architecture changed from %s to %s.\n",
+ old_arch_spec.GetTriple().getTriple().c_str(),
+ target->GetArchitecture().GetTriple().getTriple().c_str());
+ }
+
+ // This supports the use-case scenario of immediately continuing the process once attached.
+ if (m_options.attach_info.GetContinueOnceAttached())
+ m_interpreter.HandleCommand("process continue", eLazyBoolNo, result);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+
+OptionDefinition
+CommandObjectProcessAttach::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "continue",'c', no_argument, NULL, 0, eArgTypeNone, "Immediately continue the process once attached."},
+{ LLDB_OPT_SET_ALL, false, "plugin", 'P', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+{ LLDB_OPT_SET_1, false, "pid", 'p', required_argument, NULL, 0, eArgTypePid, "The process ID of an existing process to attach to."},
+{ LLDB_OPT_SET_2, false, "name", 'n', required_argument, NULL, 0, eArgTypeProcessName, "The name of the process to attach to."},
+{ LLDB_OPT_SET_2, false, "include-existing", 'i', no_argument, NULL, 0, eArgTypeNone, "Include existing processes when doing attach -w."},
+{ LLDB_OPT_SET_2, false, "waitfor", 'w', no_argument, NULL, 0, eArgTypeNone, "Wait for the process with <process-name> to launch."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessContinue
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessContinue
+
+class CommandObjectProcessContinue : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessContinue (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process continue",
+ "Continue execution of all threads in the current process.",
+ "process continue",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options(interpreter)
+ {
+ }
+
+
+ ~CommandObjectProcessContinue ()
+ {
+ }
+
+protected:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success = false;
+ switch (short_option)
+ {
+ case 'i':
+ m_ignore = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("invalid value for ignore option: \"%s\", should be a number.", option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ uint32_t m_ignore;
+ };
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+ StateType state = process->GetState();
+ if (state == eStateStopped)
+ {
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendErrorWithFormat ("The '%s' command does not take any arguments.\n", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_ignore > 0)
+ {
+ ThreadSP sel_thread_sp(process->GetThreadList().GetSelectedThread());
+ if (sel_thread_sp)
+ {
+ StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo();
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
+ {
+ lldb::break_id_t bp_site_id = (lldb::break_id_t)stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp(process->GetBreakpointSiteList().FindByID(bp_site_id));
+ if (bp_site_sp)
+ {
+ const size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t i = 0; i < num_owners; i++)
+ {
+ Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+ if (!bp_ref.IsInternal())
+ {
+ bp_ref.SetIgnoreCount(m_options.m_ignore);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ { // Scope for thread list mutex:
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+
+ // Set the actions that the threads should each take when resuming
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState (eStateRunning);
+ }
+ }
+
+ Error error(process->Resume());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
+ StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectProcessContinue::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "ignore-count",'i', required_argument, NULL, 0, eArgTypeUnsignedInteger,
+ "Ignore <N> crossings of the breakpoint (if it exists) for the currently selected thread."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessDetach
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessDetach
+
+class CommandObjectProcessDetach : public CommandObjectParsed
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ bool tmp_result;
+ bool success;
+ tmp_result = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean option: \"%s\"", option_arg);
+ else
+ {
+ if (tmp_result)
+ m_keep_stopped = eLazyBoolYes;
+ else
+ m_keep_stopped = eLazyBoolNo;
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_keep_stopped = eLazyBoolCalculate;
+ }
+
+ 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.
+ LazyBool m_keep_stopped;
+ };
+
+ CommandObjectProcessDetach (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process detach",
+ "Detach from the current process being debugged.",
+ "process detach",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectProcessDetach ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ result.AppendMessageWithFormat ("Detaching from process %" PRIu64 "\n", process->GetID());
+ // FIXME: This will be a Command Option:
+ bool keep_stopped;
+ if (m_options.m_keep_stopped == eLazyBoolCalculate)
+ {
+ // Check the process default:
+ if (process->GetDetachKeepsStopped())
+ keep_stopped = true;
+ else
+ keep_stopped = false;
+ }
+ else if (m_options.m_keep_stopped == eLazyBoolYes)
+ keep_stopped = true;
+ else
+ keep_stopped = false;
+
+ Error error (process->Detach(keep_stopped));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Detach failed: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessDetach::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "keep-stopped", 's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be kept stopped on detach (if possible)." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessConnect
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessConnect
+
+class CommandObjectProcessConnect : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ // Keep default values of all options in one place: OptionParsingStarting ()
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ 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 'p':
+ plugin_name.assign (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ plugin_name.clear();
+ }
+
+ 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.
+
+ std::string plugin_name;
+ };
+
+ CommandObjectProcessConnect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process connect",
+ "Connect to a remote debug service.",
+ "process connect <remote-url>",
+ 0),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectProcessConnect ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+
+ TargetSP target_sp (m_interpreter.GetDebugger().GetSelectedTarget());
+ Error error;
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ result.AppendErrorWithFormat ("Process %" PRIu64 " is currently being debugged, kill the process before connecting.\n",
+ process->GetID());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (!target_sp)
+ {
+ // If there isn't a current target create one.
+
+ error = m_interpreter.GetDebugger().GetTargetList().CreateTarget (m_interpreter.GetDebugger(),
+ NULL,
+ NULL,
+ false,
+ NULL, // No platform options
+ target_sp);
+ if (!target_sp || error.Fail())
+ {
+ result.AppendError(error.AsCString("Error creating target"));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ m_interpreter.GetDebugger().GetTargetList().SetSelectedTarget(target_sp.get());
+ }
+
+ if (command.GetArgumentCount() == 1)
+ {
+ const char *plugin_name = NULL;
+ if (!m_options.plugin_name.empty())
+ plugin_name = m_options.plugin_name.c_str();
+
+ const char *remote_url = command.GetArgumentAtIndex(0);
+ process = target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), plugin_name, NULL).get();
+
+ if (process)
+ {
+ error = process->ConnectRemote (&process->GetTarget().GetDebugger().GetOutputStream(), remote_url);
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString("Remote connect failed"));
+ result.SetStatus (eReturnStatusFailed);
+ target_sp->DeleteCurrentProcess();
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find process plug-in for remote URL '%s'.\nPlease specify a process plug-in name with the --plugin option, or specify an object file using the \"file\" command.\n",
+ remote_url);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes exactly one argument:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessConnect::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+ { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessPlugin
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessPlugin
+
+class CommandObjectProcessPlugin : public CommandObjectProxy
+{
+public:
+
+ CommandObjectProcessPlugin (CommandInterpreter &interpreter) :
+ CommandObjectProxy (interpreter,
+ "process plugin",
+ "Send a custom command to the current process plug-in.",
+ "process plugin <args>",
+ 0)
+ {
+ }
+
+ ~CommandObjectProcessPlugin ()
+ {
+ }
+
+ virtual CommandObject *
+ GetProxyCommandObject()
+ {
+ Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ return process->GetPluginCommandObject();
+ return NULL;
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessLoad
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessLoad
+
+class CommandObjectProcessLoad : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessLoad (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process load",
+ "Load a shared library into the current process.",
+ "process load <filename> [<filename> ...]",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectProcessLoad ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ Error error;
+ const char *image_path = command.GetArgumentAtIndex(i);
+ FileSpec image_spec (image_path, false);
+ process->GetTarget().GetPlatform()->ResolveRemotePath(image_spec, image_spec);
+ uint32_t image_token = process->LoadImage(image_spec, error);
+ if (image_token != LLDB_INVALID_IMAGE_TOKEN)
+ {
+ result.AppendMessageWithFormat ("Loading \"%s\"...ok\nImage %u loaded.\n", image_path, image_token);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to load '%s': %s", image_path, error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessUnload
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessUnload
+
+class CommandObjectProcessUnload : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessUnload (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process unload",
+ "Unload a shared library from the current process using the index returned by a previous call to \"process load\".",
+ "process unload <index>",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectProcessUnload ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ const char *image_token_cstr = command.GetArgumentAtIndex(i);
+ uint32_t image_token = Args::StringToUInt32(image_token_cstr, LLDB_INVALID_IMAGE_TOKEN, 0);
+ if (image_token == LLDB_INVALID_IMAGE_TOKEN)
+ {
+ result.AppendErrorWithFormat ("invalid image index argument '%s'", image_token_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else
+ {
+ Error error (process->UnloadImage(image_token));
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Unloading shared library with index %u...ok\n", image_token);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("failed to unload image: %s", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessSignal
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessSignal
+
+class CommandObjectProcessSignal : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessSignal (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process signal",
+ "Send a UNIX signal to the current process being debugged.",
+ NULL,
+ eFlagRequiresProcess | eFlagTryTargetAPILock)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData signal_arg;
+
+ // Define the first (and only) variant of this arg.
+ signal_arg.arg_type = eArgTypeUnixSignal;
+ signal_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (signal_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectProcessSignal ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+
+ if (command.GetArgumentCount() == 1)
+ {
+ int signo = LLDB_INVALID_SIGNAL_NUMBER;
+
+ const char *signal_name = command.GetArgumentAtIndex(0);
+ if (::isxdigit (signal_name[0]))
+ signo = Args::StringToSInt32(signal_name, LLDB_INVALID_SIGNAL_NUMBER, 0);
+ else
+ signo = process->GetUnixSignals().GetSignalNumberFromName (signal_name);
+
+ if (signo == LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ result.AppendErrorWithFormat ("Invalid signal argument '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ Error error (process->Signal (signo));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to send signal %i: %s\n", signo, error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one signal number argument:\nUsage: %s\n", m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessInterrupt
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessInterrupt
+
+class CommandObjectProcessInterrupt : public CommandObjectParsed
+{
+public:
+
+
+ CommandObjectProcessInterrupt (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process interrupt",
+ "Interrupt the current process being debugged.",
+ "process interrupt",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessInterrupt ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process to halt");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ bool clear_thread_plans = true;
+ Error error(process->Halt (clear_thread_plans));
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to halt process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessKill
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessKill
+
+class CommandObjectProcessKill : public CommandObjectParsed
+{
+public:
+
+ CommandObjectProcessKill (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process kill",
+ "Terminate the current process being debugged.",
+ "process kill",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched)
+ {
+ }
+
+ ~CommandObjectProcessKill ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process to kill");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ Error error (process->Destroy());
+ if (error.Success())
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to kill process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
+ m_cmd_name.c_str(),
+ m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessStatus
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessStatus
+
+class CommandObjectProcessStatus : public CommandObjectParsed
+{
+public:
+ CommandObjectProcessStatus (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process status",
+ "Show the current status and location of executing process.",
+ "process status",
+ eFlagRequiresProcess | eFlagTryTargetAPILock)
+ {
+ }
+
+ ~CommandObjectProcessStatus()
+ {
+ }
+
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
+ Process *process = m_exe_ctx.GetProcessPtr();
+ 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->GetStatus(strm);
+ process->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectProcessHandle
+//-------------------------------------------------------------------------
+#pragma mark CommandObjectProcessHandle
+
+class CommandObjectProcessHandle : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ OptionParsingStarting ();
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ stop = option_arg;
+ break;
+ case 'n':
+ notify = option_arg;
+ break;
+ case 'p':
+ pass = option_arg;
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ stop.clear();
+ notify.clear();
+ pass.clear();
+ }
+
+ 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.
+
+ std::string stop;
+ std::string notify;
+ std::string pass;
+ };
+
+
+ CommandObjectProcessHandle (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process handle",
+ "Show or update what the process and debugger should do with various signals received from the OS.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong ("If no signals are specified, update them all. If no update option is specified, list the current values.\n");
+ CommandArgumentEntry arg;
+ CommandArgumentData signal_arg;
+
+ signal_arg.arg_type = eArgTypeUnixSignal;
+ signal_arg.arg_repetition = eArgRepeatStar;
+
+ arg.push_back (signal_arg);
+
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectProcessHandle ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ bool
+ VerifyCommandOptionValue (const std::string &option, int &real_value)
+ {
+ bool okay = true;
+
+ bool success = false;
+ bool tmp_value = Args::StringToBoolean (option.c_str(), false, &success);
+
+ if (success && tmp_value)
+ real_value = 1;
+ else if (success && !tmp_value)
+ real_value = 0;
+ else
+ {
+ // If the value isn't 'true' or 'false', it had better be 0 or 1.
+ real_value = Args::StringToUInt32 (option.c_str(), 3);
+ if (real_value != 0 && real_value != 1)
+ okay = false;
+ }
+
+ return okay;
+ }
+
+ void
+ PrintSignalHeader (Stream &str)
+ {
+ str.Printf ("NAME PASS STOP NOTIFY\n");
+ str.Printf ("========== ===== ===== ======\n");
+ }
+
+ void
+ PrintSignal (Stream &str, int32_t signo, const char *sig_name, UnixSignals &signals)
+ {
+ bool stop;
+ bool suppress;
+ bool notify;
+
+ str.Printf ("%-10s ", sig_name);
+ if (signals.GetSignalInfo (signo, suppress, stop, notify))
+ {
+ bool pass = !suppress;
+ str.Printf ("%s %s %s",
+ (pass ? "true " : "false"),
+ (stop ? "true " : "false"),
+ (notify ? "true " : "false"));
+ }
+ str.Printf ("\n");
+ }
+
+ void
+ PrintSignalInformation (Stream &str, Args &signal_args, int num_valid_signals, UnixSignals &signals)
+ {
+ PrintSignalHeader (str);
+
+ if (num_valid_signals > 0)
+ {
+ size_t num_args = signal_args.GetArgumentCount();
+ for (size_t i = 0; i < num_args; ++i)
+ {
+ int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ PrintSignal (str, signo, signal_args.GetArgumentAtIndex (i), signals);
+ }
+ }
+ else // Print info for ALL signals
+ {
+ int32_t signo = signals.GetFirstSignalNumber();
+ while (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ PrintSignal (str, signo, signals.GetSignalAsCString (signo), signals);
+ signo = signals.GetNextSignalNumber (signo);
+ }
+ }
+ }
+
+protected:
+ bool
+ DoExecute (Args &signal_args, CommandReturnObject &result)
+ {
+ TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
+
+ if (!target_sp)
+ {
+ result.AppendError ("No current target;"
+ " cannot handle signals until you have a valid target and process.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessSP process_sp = target_sp->GetProcessSP();
+
+ if (!process_sp)
+ {
+ result.AppendError ("No current process; cannot handle signals until you have a valid process.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ int stop_action = -1; // -1 means leave the current setting alone
+ int pass_action = -1; // -1 means leave the current setting alone
+ int notify_action = -1; // -1 means leave the current setting alone
+
+ if (! m_options.stop.empty()
+ && ! VerifyCommandOptionValue (m_options.stop, stop_action))
+ {
+ result.AppendError ("Invalid argument for command option --stop; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (! m_options.notify.empty()
+ && ! VerifyCommandOptionValue (m_options.notify, notify_action))
+ {
+ result.AppendError ("Invalid argument for command option --notify; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (! m_options.pass.empty()
+ && ! VerifyCommandOptionValue (m_options.pass, pass_action))
+ {
+ result.AppendError ("Invalid argument for command option --pass; must be true or false.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ size_t num_args = signal_args.GetArgumentCount();
+ UnixSignals &signals = process_sp->GetUnixSignals();
+ int num_signals_set = 0;
+
+ if (num_args > 0)
+ {
+ for (size_t i = 0; i < num_args; ++i)
+ {
+ int32_t signo = signals.GetSignalNumberFromName (signal_args.GetArgumentAtIndex (i));
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ // Casting the actions as bools here should be okay, because VerifyCommandOptionValue guarantees
+ // the value is either 0 or 1.
+ if (stop_action != -1)
+ signals.SetShouldStop (signo, (bool) stop_action);
+ if (pass_action != -1)
+ {
+ bool suppress = ! ((bool) pass_action);
+ signals.SetShouldSuppress (signo, suppress);
+ }
+ if (notify_action != -1)
+ signals.SetShouldNotify (signo, (bool) notify_action);
+ ++num_signals_set;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid signal name '%s'\n", signal_args.GetArgumentAtIndex (i));
+ }
+ }
+ }
+ else
+ {
+ // No signal specified, if any command options were specified, update ALL signals.
+ if ((notify_action != -1) || (stop_action != -1) || (pass_action != -1))
+ {
+ if (m_interpreter.Confirm ("Do you really want to update all the signals?", false))
+ {
+ int32_t signo = signals.GetFirstSignalNumber();
+ while (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ {
+ if (notify_action != -1)
+ signals.SetShouldNotify (signo, (bool) notify_action);
+ if (stop_action != -1)
+ signals.SetShouldStop (signo, (bool) stop_action);
+ if (pass_action != -1)
+ {
+ bool suppress = ! ((bool) pass_action);
+ signals.SetShouldSuppress (signo, suppress);
+ }
+ signo = signals.GetNextSignalNumber (signo);
+ }
+ }
+ }
+ }
+
+ PrintSignalInformation (result.GetOutputStream(), signal_args, num_signals_set, signals);
+
+ if (num_signals_set > 0)
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectProcessHandle::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "stop", 's', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the process should be stopped if the signal is received." },
+{ LLDB_OPT_SET_1, false, "notify", 'n', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the debugger should notify the user if the signal is received." },
+{ LLDB_OPT_SET_1, false, "pass", 'p', required_argument, NULL, 0, eArgTypeBoolean, "Whether or not the signal should be passed to the process." },
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordProcess
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordProcess::CommandObjectMultiwordProcess (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process",
+ "A set of commands for operating on a process.",
+ "process <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("attach", CommandObjectSP (new CommandObjectProcessAttach (interpreter)));
+ LoadSubCommand ("launch", CommandObjectSP (new CommandObjectProcessLaunch (interpreter)));
+ LoadSubCommand ("continue", CommandObjectSP (new CommandObjectProcessContinue (interpreter)));
+ LoadSubCommand ("connect", CommandObjectSP (new CommandObjectProcessConnect (interpreter)));
+ LoadSubCommand ("detach", CommandObjectSP (new CommandObjectProcessDetach (interpreter)));
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectProcessLoad (interpreter)));
+ LoadSubCommand ("unload", CommandObjectSP (new CommandObjectProcessUnload (interpreter)));
+ LoadSubCommand ("signal", CommandObjectSP (new CommandObjectProcessSignal (interpreter)));
+ LoadSubCommand ("handle", CommandObjectSP (new CommandObjectProcessHandle (interpreter)));
+ LoadSubCommand ("status", CommandObjectSP (new CommandObjectProcessStatus (interpreter)));
+ LoadSubCommand ("interrupt", CommandObjectSP (new CommandObjectProcessInterrupt (interpreter)));
+ LoadSubCommand ("kill", CommandObjectSP (new CommandObjectProcessKill (interpreter)));
+ LoadSubCommand ("plugin", CommandObjectSP (new CommandObjectProcessPlugin (interpreter)));
+}
+
+CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess ()
+{
+}
+
diff --git a/source/Commands/CommandObjectProcess.h b/source/Commands/CommandObjectProcess.h
new file mode 100644
index 000000000000..0aaa74d28a07
--- /dev/null
+++ b/source/Commands/CommandObjectProcess.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectProcess.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_CommandObjectProcess_h_
+#define liblldb_CommandObjectProcess_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordProcess
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordProcess : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcess (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordProcess ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectProcess_h_
diff --git a/source/Commands/CommandObjectQuit.cpp b/source/Commands/CommandObjectQuit.cpp
new file mode 100644
index 000000000000..d04ecdd9885c
--- /dev/null
+++ b/source/Commands/CommandObjectQuit.cpp
@@ -0,0 +1,99 @@
+//===-- CommandObjectQuit.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 "CommandObjectQuit.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectQuit
+//-------------------------------------------------------------------------
+
+CommandObjectQuit::CommandObjectQuit (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter, "quit", "Quit out of the LLDB debugger.", "quit")
+{
+}
+
+CommandObjectQuit::~CommandObjectQuit ()
+{
+}
+
+// returns true if there is at least one alive process
+// is_a_detach will be true if all alive processes will be detached when you quit
+// and false if at least one process will be killed instead
+bool
+CommandObjectQuit::ShouldAskForConfirmation (bool& is_a_detach)
+{
+ if (m_interpreter.GetPromptOnQuit() == false)
+ return false;
+ bool should_prompt = false;
+ is_a_detach = true;
+ for (uint32_t debugger_idx = 0;
+ debugger_idx < Debugger::GetNumDebuggers();
+ debugger_idx++)
+ {
+ DebuggerSP debugger_sp(Debugger::GetDebuggerAtIndex(debugger_idx));
+ if (!debugger_sp)
+ continue;
+ const TargetList& target_list(debugger_sp->GetTargetList());
+ for (uint32_t target_idx = 0;
+ target_idx < target_list.GetNumTargets();
+ target_idx++)
+ {
+ TargetSP target_sp(target_list.GetTargetAtIndex(target_idx));
+ if (!target_sp)
+ continue;
+ ProcessSP process_sp(target_sp->GetProcessSP());
+ if (process_sp
+ && process_sp->IsValid()
+ && process_sp->IsAlive()
+ && process_sp->WarnBeforeDetach())
+ {
+ should_prompt = true;
+ if (process_sp->GetShouldDetach() == false)
+ {
+ // if we need to kill at least one process, just say so and return
+ is_a_detach = false;
+ return should_prompt;
+ }
+ }
+ }
+ }
+ return should_prompt;
+}
+
+bool
+CommandObjectQuit::DoExecute (Args& command, CommandReturnObject &result)
+{
+ bool is_a_detach = true;
+ if (ShouldAskForConfirmation (is_a_detach))
+ {
+ StreamString message;
+ message.Printf("Quitting LLDB will %s one or more processes. Do you really want to proceed", (is_a_detach ? "detach from" : "kill"));
+ if (!m_interpreter.Confirm(message.GetData(), true))
+ {
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ m_interpreter.BroadcastEvent (CommandInterpreter::eBroadcastBitQuitCommandReceived);
+ result.SetStatus (eReturnStatusQuit);
+ return true;
+}
+
diff --git a/source/Commands/CommandObjectQuit.h b/source/Commands/CommandObjectQuit.h
new file mode 100644
index 000000000000..aab0e26cce59
--- /dev/null
+++ b/source/Commands/CommandObjectQuit.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectQuit.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_CommandObjectQuit_h_
+#define liblldb_CommandObjectQuit_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectQuit
+//-------------------------------------------------------------------------
+
+class CommandObjectQuit : public CommandObjectParsed
+{
+public:
+
+ CommandObjectQuit (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectQuit ();
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result);
+
+ bool
+ ShouldAskForConfirmation (bool& is_a_detach);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectQuit_h_
diff --git a/source/Commands/CommandObjectRegister.cpp b/source/Commands/CommandObjectRegister.cpp
new file mode 100644
index 000000000000..ba43f23f34ac
--- /dev/null
+++ b/source/Commands/CommandObjectRegister.cpp
@@ -0,0 +1,499 @@
+//===-- CommandObjectRegister.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 "CommandObjectRegister.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// "register read"
+//----------------------------------------------------------------------
+class CommandObjectRegisterRead : public CommandObjectParsed
+{
+public:
+ CommandObjectRegisterRead (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "register read",
+ "Dump the contents of one or more register values from the current frame. If no register is specified, dumps them all.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagRequiresRegContext |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_format_options (eFormatDefault),
+ m_command_options ()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData register_arg;
+
+ // Define the first (and only) variant of this arg.
+ register_arg.arg_type = eArgTypeRegisterName;
+ register_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (register_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Add the "--format"
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_ALL);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Finalize();
+
+ }
+
+ virtual
+ ~CommandObjectRegisterRead ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ bool
+ DumpRegister (const ExecutionContext &exe_ctx,
+ Stream &strm,
+ RegisterContext *reg_ctx,
+ const RegisterInfo *reg_info)
+ {
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ strm.Indent ();
+
+ bool prefix_with_altname = m_command_options.alternate_name;
+ bool prefix_with_name = !prefix_with_altname;
+ reg_value.Dump(&strm, reg_info, prefix_with_name, prefix_with_altname, m_format_options.GetFormat(), 8);
+ if ((reg_info->encoding == eEncodingUint) || (reg_info->encoding == eEncodingSint))
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && reg_info->byte_size == process->GetAddressByteSize())
+ {
+ addr_t reg_addr = reg_value.GetAsUInt64(LLDB_INVALID_ADDRESS);
+ if (reg_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address so_reg_addr;
+ if (exe_ctx.GetTargetRef().GetSectionLoadList().ResolveLoadAddress(reg_addr, so_reg_addr))
+ {
+ strm.PutCString (" ");
+ so_reg_addr.Dump(&strm, exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
+ }
+ }
+ }
+ }
+ strm.EOL();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool
+ DumpRegisterSet (const ExecutionContext &exe_ctx,
+ Stream &strm,
+ RegisterContext *reg_ctx,
+ size_t set_idx,
+ bool primitive_only=false)
+ {
+ uint32_t unavailable_count = 0;
+ uint32_t available_count = 0;
+
+ if (!reg_ctx)
+ return false; // thread has no registers (i.e. core files are corrupt, incomplete crash logs...)
+
+ const RegisterSet * const reg_set = reg_ctx->GetRegisterSet(set_idx);
+ if (reg_set)
+ {
+ strm.Printf ("%s:\n", reg_set->name);
+ strm.IndentMore ();
+ const size_t num_registers = reg_set->num_registers;
+ for (size_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
+ {
+ const uint32_t reg = reg_set->registers[reg_idx];
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg);
+ // Skip the dumping of derived register if primitive_only is true.
+ if (primitive_only && reg_info && reg_info->value_regs)
+ continue;
+
+ if (DumpRegister (exe_ctx, strm, reg_ctx, reg_info))
+ ++available_count;
+ else
+ ++unavailable_count;
+ }
+ strm.IndentLess ();
+ if (unavailable_count)
+ {
+ strm.Indent ();
+ strm.Printf("%u registers were unavailable.\n", unavailable_count);
+ }
+ strm.EOL();
+ }
+ return available_count > 0;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext ();
+
+ const RegisterInfo *reg_info = NULL;
+ if (command.GetArgumentCount() == 0)
+ {
+ size_t set_idx;
+
+ size_t num_register_sets = 1;
+ const size_t set_array_size = m_command_options.set_indexes.GetSize();
+ if (set_array_size > 0)
+ {
+ for (size_t i=0; i<set_array_size; ++i)
+ {
+ set_idx = m_command_options.set_indexes[i]->GetUInt64Value (UINT32_MAX, NULL);
+ if (set_idx < reg_ctx->GetRegisterSetCount())
+ {
+ if (!DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx))
+ {
+ if (errno)
+ result.AppendErrorWithFormat ("register read failed with errno: %d\n", errno);
+ else
+ result.AppendError ("unknown error while reading registers.\n");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid register set index: %zu\n", set_idx);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (m_command_options.dump_all_sets)
+ num_register_sets = reg_ctx->GetRegisterSetCount();
+
+ for (set_idx = 0; set_idx < num_register_sets; ++set_idx)
+ {
+ // When dump_all_sets option is set, dump primitive as well as derived registers.
+ DumpRegisterSet (m_exe_ctx, strm, reg_ctx, set_idx, !m_command_options.dump_all_sets.GetCurrentValue());
+ }
+ }
+ }
+ else
+ {
+ if (m_command_options.dump_all_sets)
+ {
+ result.AppendError ("the --all option can't be used when registers names are supplied as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else if (m_command_options.set_indexes.GetSize() > 0)
+ {
+ result.AppendError ("the --set <set> option can't be used when registers names are supplied as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ // in most LLDB commands we accept $rbx as the name for register RBX - and here we would
+ // reject it and non-existant. we should be more consistent towards the user and allow them
+ // to say reg read $rbx - internally, however, we should be strict and not allow ourselves
+ // to call our registers $rbx in our own API
+ if (*arg_cstr == '$')
+ arg_cstr = arg_cstr+1;
+ reg_info = reg_ctx->GetRegisterInfoByName(arg_cstr);
+
+ if (reg_info)
+ {
+ if (!DumpRegister (m_exe_ctx, strm, reg_ctx, reg_info))
+ strm.Printf("%-12s = error: unavailable\n", reg_info->name);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid register name '%s'.\n", arg_cstr);
+ }
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+ CommandOptions () :
+ OptionGroup(),
+ set_indexes (OptionValue::ConvertTypeToMask (OptionValue::eTypeUInt64)),
+ dump_all_sets (false, false), // Initial and default values are false
+ alternate_name (false, false)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ set_indexes.Clear();
+ dump_all_sets.Clear();
+ alternate_name.Clear();
+ }
+
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 's':
+ {
+ OptionValueSP value_sp (OptionValueUInt64::Create (option_value, error));
+ if (value_sp)
+ set_indexes.AppendValue (value_sp);
+ }
+ break;
+
+ case 'a':
+ // When we don't use OptionValue::SetValueFromCString(const char *) to
+ // set an option value, it won't be marked as being set in the options
+ // so we make a call to let users know the value was set via option
+ dump_all_sets.SetCurrentValue (true);
+ dump_all_sets.SetOptionWasSet ();
+ break;
+
+ case 'A':
+ // When we don't use OptionValue::SetValueFromCString(const char *) to
+ // set an option value, it won't be marked as being set in the options
+ // so we make a call to let users know the value was set via option
+ alternate_name.SetCurrentValue (true);
+ dump_all_sets.SetOptionWasSet ();
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+ return error;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static const OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ OptionValueArray set_indexes;
+ OptionValueBoolean dump_all_sets;
+ OptionValueBoolean alternate_name;
+ };
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ CommandOptions m_command_options;
+};
+
+const OptionDefinition
+CommandObjectRegisterRead::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "alternate", 'A', no_argument , NULL, 0, eArgTypeNone , "Display register names using the alternate register name if there is one."},
+ { LLDB_OPT_SET_1 , false, "set" , 's', required_argument, NULL, 0, eArgTypeIndex , "Specify which register sets to dump by index."},
+ { LLDB_OPT_SET_2 , false, "all" , 'a', no_argument , NULL, 0, eArgTypeNone , "Show all register sets."},
+};
+
+uint32_t
+CommandObjectRegisterRead::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table)/sizeof(OptionDefinition);
+}
+
+
+//----------------------------------------------------------------------
+// "register write"
+//----------------------------------------------------------------------
+class CommandObjectRegisterWrite : public CommandObjectParsed
+{
+public:
+ CommandObjectRegisterWrite (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "register write",
+ "Modify a single register value.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagRequiresRegContext |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData register_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ register_arg.arg_type = eArgTypeRegisterName;
+ register_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (register_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectRegisterWrite ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute(Args& command, CommandReturnObject &result)
+ {
+ DataExtractor reg_data;
+ RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext ();
+
+ if (command.GetArgumentCount() != 2)
+ {
+ result.AppendError ("register write takes exactly 2 arguments: <reg-name> <value>");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ const char *reg_name = command.GetArgumentAtIndex(0);
+ const char *value_str = command.GetArgumentAtIndex(1);
+
+
+ // in most LLDB commands we accept $rbx as the name for register RBX - and here we would
+ // reject it and non-existant. we should be more consistent towards the user and allow them
+ // to say reg write $rbx - internally, however, we should be strict and not allow ourselves
+ // to call our registers $rbx in our own API
+ if (reg_name && *reg_name == '$')
+ reg_name = reg_name+1;
+
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
+
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+
+ Error error (reg_value.SetValueFromCString (reg_info, value_str));
+ if (error.Success())
+ {
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ // Toss all frames and anything else in the thread
+ // after a register has been written.
+ m_exe_ctx.GetThreadRef().Flush();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ if (error.AsCString())
+ {
+ result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s': %s\n",
+ reg_name,
+ value_str,
+ error.AsCString());
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Failed to write register '%s' with value '%s'",
+ reg_name,
+ value_str);
+ }
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Register not found for '%s'.\n", reg_name);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// CommandObjectRegister constructor
+//----------------------------------------------------------------------
+CommandObjectRegister::CommandObjectRegister(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "register",
+ "A set of commands to access thread registers.",
+ "register [read|write] ...")
+{
+ LoadSubCommand ("read", CommandObjectSP (new CommandObjectRegisterRead (interpreter)));
+ LoadSubCommand ("write", CommandObjectSP (new CommandObjectRegisterWrite (interpreter)));
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectRegister::~CommandObjectRegister()
+{
+}
diff --git a/source/Commands/CommandObjectRegister.h b/source/Commands/CommandObjectRegister.h
new file mode 100644
index 000000000000..7f856c2de529
--- /dev/null
+++ b/source/Commands/CommandObjectRegister.h
@@ -0,0 +1,45 @@
+//===-- CommandObjectRegister.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_CommandObjectRegister_h_
+#define liblldb_CommandObjectRegister_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectRegister
+//-------------------------------------------------------------------------
+
+class CommandObjectRegister : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectRegister(CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectRegister();
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectRegister only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectRegister);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectRegister_h_
diff --git a/source/Commands/CommandObjectSettings.cpp b/source/Commands/CommandObjectSettings.cpp
new file mode 100644
index 000000000000..95cc9b68a8f7
--- /dev/null
+++ b/source/Commands/CommandObjectSettings.cpp
@@ -0,0 +1,1208 @@
+//===-- CommandObjectSettings.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 "CommandObjectSettings.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+#include "llvm/ADT/StringRef.h"
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsSet
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsSet : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsSet (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings set",
+ "Set or change the value of a single debugger setting variable.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+
+ SetHelpLong (
+"When setting a dictionary or array variable, you can set multiple entries \n\
+at once by giving the values to the set command. For example: \n\
+\n\
+(lldb) settings set target.run-args value1 value2 value3 \n\
+(lldb) settings set target.env-vars MYPATH=~/.:/usr/bin SOME_ENV_VAR=12345 \n\
+\n\
+(lldb) settings show target.run-args \n\
+ [0]: 'value1' \n\
+ [1]: 'value2' \n\
+ [3]: 'value3' \n\
+(lldb) settings show target.env-vars \n\
+ 'MYPATH=~/.:/usr/bin'\n\
+ 'SOME_ENV_VAR=12345' \n\
+\n\
+Warning: The 'set' command re-sets the entire array or dictionary. If you \n\
+just want to add, remove or update individual values (or add something to \n\
+the end), use one of the other settings sub-commands: append, replace, \n\
+insert-before or insert-after.\n");
+
+ }
+
+
+ virtual
+ ~CommandObjectSettingsSet () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_global (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 'g':
+ m_global = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized options '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_global = 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_global;
+ };
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ const size_t argc = input.GetArgumentCount();
+ const char *arg = NULL;
+ int setting_var_idx;
+ for (setting_var_idx = 1; setting_var_idx < argc; ++setting_var_idx)
+ {
+ arg = input.GetArgumentAtIndex(setting_var_idx);
+ if (arg && arg[0] != '-')
+ break; // We found our setting variable name index
+ }
+ if (cursor_index == setting_var_idx)
+ {
+ // Attempting to complete setting variable name
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ }
+ else
+ {
+ arg = input.GetArgumentAtIndex(cursor_index);
+
+ if (arg)
+ {
+ if (arg[0] == '-')
+ {
+ // Complete option name
+ }
+ else
+ {
+ // Complete setting value
+ const char *setting_var_name = input.GetArgumentAtIndex(setting_var_idx);
+ Error error;
+ lldb::OptionValueSP value_sp (m_interpreter.GetDebugger().GetPropertyValue(&m_exe_ctx, setting_var_name, false, error));
+ if (value_sp)
+ {
+ value_sp->AutoComplete (m_interpreter,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ }
+ }
+ }
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ Args cmd_args(command);
+
+ // Process possible options.
+ if (!ParseOptions (cmd_args, result))
+ return false;
+
+ const size_t argc = cmd_args.GetArgumentCount ();
+ if ((argc < 2) && (!m_options.m_global))
+ {
+ result.AppendError ("'settings set' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings set' command requires a valid variable name");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error;
+ if (m_options.m_global)
+ {
+ error = m_interpreter.GetDebugger().SetPropertyValue (NULL,
+ eVarSetOperationAssign,
+ var_name,
+ var_value_cstr);
+ }
+
+ if (error.Success())
+ {
+ // FIXME this is the same issue as the one in commands script import
+ // we could be setting target.load-script-from-symbol-file which would cause
+ // Python scripts to be loaded, which could run LLDB commands
+ // (e.g. settings set target.process.python-os-plugin-path) and cause a crash
+ // if we did not clear the command's exe_ctx first
+ ExecutionContext exe_ctx(m_exe_ctx);
+ m_exe_ctx.Clear();
+ error = m_interpreter.GetDebugger().SetPropertyValue (&exe_ctx,
+ eVarSetOperationAssign,
+ var_name,
+ var_value_cstr);
+ }
+
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ return result.Succeeded();
+ }
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectSettingsSet::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_2, false, "global", 'g', no_argument, NULL, 0, eArgTypeNone, "Apply the new value to the global default value." },
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsShow -- Show current values
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsShow : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsShow (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings show",
+ "Show the specified internal debugger setting variable and its value, or show all the currently set variables and their values, if nothing is specified.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ }
+
+ virtual
+ ~CommandObjectSettingsShow () {}
+
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ const size_t argc = args.GetArgumentCount ();
+ if (argc > 0)
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *property_path = args.GetArgumentAtIndex (i);
+
+ Error error(m_interpreter.GetDebugger().DumpPropertyValue (&m_exe_ctx, result.GetOutputStream(), property_path, OptionValue::eDumpGroupValue));
+ if (error.Success())
+ {
+ result.GetOutputStream().EOL();
+ }
+ else
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ m_interpreter.GetDebugger().DumpAllPropertyValues (&m_exe_ctx, result.GetOutputStream(), OptionValue::eDumpGroupValue);
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsList -- List settable variables
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsList : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings list",
+ "List and describe all the internal debugger settings variables that are available to the user to 'set' or 'show', or describe a particular variable or set of variables (by specifying the variable name or a common prefix).",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData prefix_name_arg;
+
+ // Define the first variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatOptional;
+
+ // Define the second variant of this arg.
+ prefix_name_arg.arg_type = eArgTypeSettingPrefix;
+ prefix_name_arg.arg_repetition = eArgRepeatOptional;
+
+ arg.push_back (var_name_arg);
+ arg.push_back (prefix_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectSettingsList () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+
+ const bool will_modify = false;
+ const size_t argc = args.GetArgumentCount ();
+ if (argc > 0)
+ {
+ const bool dump_qualified_name = true;
+
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *property_path = args.GetArgumentAtIndex (i);
+
+ const Property *property = m_interpreter.GetDebugger().GetValueProperties()->GetPropertyAtPath (&m_exe_ctx, will_modify, property_path);
+
+ if (property)
+ {
+ property->DumpDescription (m_interpreter, result.GetOutputStream(), 0, dump_qualified_name);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid property path '%s'", property_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ else
+ {
+ m_interpreter.GetDebugger().DumpAllDescriptions (m_interpreter, result.GetOutputStream());
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsRemove
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsRemove : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsRemove (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings remove",
+ "Remove the specified element from an array or dictionary settings variable.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData key_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Define the second variant of this arg.
+ key_arg.arg_type = eArgTypeSettingKey;
+ key_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push both variants into this arg
+ arg2.push_back (index_arg);
+ arg2.push_back (key_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectSettingsRemove () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+
+ // Process possible options.
+ if (!ParseOptions (cmd_args, result))
+ return false;
+
+ const size_t argc = cmd_args.GetArgumentCount ();
+ if (argc == 0)
+ {
+ result.AppendError ("'settings set' takes an array or dictionary item, or an array followed by one or more indexes, or a dictionary followed by one or more key names to remove");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings set' command requires a valid variable name");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error (m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationRemove,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsReplace
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsReplace : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsReplace (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings replace",
+ "Replace the specified element from an internal debugger settings array or dictionary variable with the specified new value.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData key_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Define the second (variant of this arg.
+ key_arg.arg_type = eArgTypeSettingKey;
+ key_arg.arg_repetition = eArgRepeatPlain;
+
+ // Put both variants into this arg
+ arg2.push_back (index_arg);
+ arg2.push_back (key_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+
+ virtual
+ ~CommandObjectSettingsReplace () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings replace' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationReplace,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsInsertBefore
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsInsertBefore : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsInsertBefore (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings insert-before",
+ "Insert value(s) into an internal debugger settings array variable, immediately before the specified element.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (index_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ virtual
+ ~CommandObjectSettingsInsertBefore () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 3)
+ {
+ result.AppendError ("'settings insert-before' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings insert-before' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationInsertBefore,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingInsertAfter
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsInsertAfter : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsInsertAfter (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings insert-after",
+ "Insert value(s) into an internal debugger settings array variable, immediately after the specified element.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentEntry arg3;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData index_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (variant of this arg.
+ index_arg.arg_type = eArgTypeSettingIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (index_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg3.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ m_arguments.push_back (arg3);
+ }
+
+ virtual
+ ~CommandObjectSettingsInsertAfter () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 3)
+ {
+ result.AppendError ("'settings insert-after' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings insert-after' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Split the raw command into var_name, index_value, and value triple.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationInsertAfter,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsAppend
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsAppend : public CommandObjectRaw
+{
+public:
+ CommandObjectSettingsAppend (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "settings append",
+ "Append a new value to the end of an internal debugger settings array, dictionary or string variable.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData var_name_arg;
+ CommandArgumentData value_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg1.push_back (var_name_arg);
+
+ // Define the first (and only) variant of this arg.
+ value_arg.arg_type = eArgTypeValue;
+ value_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg2.push_back (value_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ virtual
+ ~CommandObjectSettingsAppend () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ Args cmd_args(command);
+ const size_t argc = cmd_args.GetArgumentCount ();
+
+ if (argc < 2)
+ {
+ result.AppendError ("'settings append' takes more arguments");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = cmd_args.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings append' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // Do not perform cmd_args.Shift() since StringRef is manipulating the
+ // raw character string later on.
+
+ // Split the raw command into var_name and value pair.
+ llvm::StringRef raw_str(command);
+ std::string var_value_string = raw_str.split(var_name).second.str();
+ const char *var_value_cstr = Args::StripSpaces(var_value_string, true, true, false);
+
+ Error error(m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationAppend,
+ var_name,
+ var_value_cstr));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectSettingsClear
+//-------------------------------------------------------------------------
+
+class CommandObjectSettingsClear : public CommandObjectParsed
+{
+public:
+ CommandObjectSettingsClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "settings clear",
+ "Erase all the contents of an internal debugger settings variables; this is only valid for variables with clearable types, i.e. strings, arrays or dictionaries.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeSettingVariableName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectSettingsClear () {}
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+
+ // Attempting to complete variable name
+ if (cursor_index < 2)
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSettingsNameCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+
+ return matches.GetSize();
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ const size_t argc = command.GetArgumentCount ();
+
+ if (argc != 1)
+ {
+ result.AppendError ("'setttings clear' takes exactly one argument");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const char *var_name = command.GetArgumentAtIndex (0);
+ if ((var_name == NULL) || (var_name[0] == '\0'))
+ {
+ result.AppendError ("'settings clear' command requires a valid variable name; No value supplied");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Error error (m_interpreter.GetDebugger().SetPropertyValue (&m_exe_ctx,
+ eVarSetOperationClear,
+ var_name,
+ NULL));
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSettings
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordSettings::CommandObjectMultiwordSettings (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "settings",
+ "A set of commands for manipulating internal settable debugger variables.",
+ "settings <command> [<command-options>]")
+{
+ LoadSubCommand ("set", CommandObjectSP (new CommandObjectSettingsSet (interpreter)));
+ LoadSubCommand ("show", CommandObjectSP (new CommandObjectSettingsShow (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectSettingsList (interpreter)));
+ LoadSubCommand ("remove", CommandObjectSP (new CommandObjectSettingsRemove (interpreter)));
+ LoadSubCommand ("replace", CommandObjectSP (new CommandObjectSettingsReplace (interpreter)));
+ LoadSubCommand ("insert-before", CommandObjectSP (new CommandObjectSettingsInsertBefore (interpreter)));
+ LoadSubCommand ("insert-after", CommandObjectSP (new CommandObjectSettingsInsertAfter (interpreter)));
+ LoadSubCommand ("append", CommandObjectSP (new CommandObjectSettingsAppend (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectSettingsClear (interpreter)));
+}
+
+CommandObjectMultiwordSettings::~CommandObjectMultiwordSettings ()
+{
+}
diff --git a/source/Commands/CommandObjectSettings.h b/source/Commands/CommandObjectSettings.h
new file mode 100644
index 000000000000..eca7adeea76f
--- /dev/null
+++ b/source/Commands/CommandObjectSettings.h
@@ -0,0 +1,41 @@
+//===-- CommandObjectSettings.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_CommandObjectSettings_h_
+#define liblldb_CommandObjectSettings_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSettings
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordSettings : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordSettings (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordSettings ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSettings_h_
diff --git a/source/Commands/CommandObjectSource.cpp b/source/Commands/CommandObjectSource.cpp
new file mode 100644
index 000000000000..a08e39352b3d
--- /dev/null
+++ b/source/Commands/CommandObjectSource.cpp
@@ -0,0 +1,925 @@
+//===-- CommandObjectSource.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 "CommandObjectSource.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/FileLineResolver.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/Options.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectSourceInfo
+//-------------------------------------------------------------------------
+
+class CommandObjectSourceInfo : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'l':
+ start_line = Args::StringToUInt32 (option_arg, 0);
+ if (start_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ file_spec.Clear();
+ file_name.clear();
+ start_line = 0;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ FileSpec file_spec;
+ std::string file_name;
+ uint32_t start_line;
+
+ };
+
+public:
+ CommandObjectSourceInfo(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "source info",
+ "Display information about the source lines from the current executable's debug info.",
+ "source info [<cmd-options>]"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectSourceInfo ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.AppendError ("Not yet implemented");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectSourceInfo::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectSourceList
+//-------------------------------------------------------------------------
+// CommandObjectSourceList
+//-------------------------------------------------------------------------
+
+class CommandObjectSourceList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ }
+
+ ~CommandOptions ()
+ {
+ }
+
+ Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'l':
+ start_line = Args::StringToUInt32 (option_arg, 0);
+ if (start_line == 0)
+ error.SetErrorStringWithFormat("invalid line number: '%s'", option_arg);
+ break;
+
+ case 'c':
+ num_lines = Args::StringToUInt32 (option_arg, 0);
+ if (num_lines == 0)
+ error.SetErrorStringWithFormat("invalid line count: '%s'", option_arg);
+ break;
+
+ case 'f':
+ file_name = option_arg;
+ break;
+
+ case 'n':
+ symbol_name = option_arg;
+ break;
+
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ address = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+ case 's':
+ modules.push_back (std::string (option_arg));
+ break;
+
+ case 'b':
+ show_bp_locs = true;
+ break;
+ case 'r':
+ reverse = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ file_spec.Clear();
+ file_name.clear();
+ symbol_name.clear();
+ address = LLDB_INVALID_ADDRESS;
+ start_line = 0;
+ num_lines = 0;
+ show_bp_locs = false;
+ reverse = false;
+ modules.clear();
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ FileSpec file_spec;
+ std::string file_name;
+ std::string symbol_name;
+ lldb::addr_t address;
+ uint32_t start_line;
+ uint32_t num_lines;
+ STLStringArray modules;
+ bool show_bp_locs;
+ bool reverse;
+ };
+
+public:
+ CommandObjectSourceList(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "source list",
+ "Display source code (as specified) based on the current executable's debug info.",
+ NULL,
+ eFlagRequiresTarget),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectSourceList ()
+ {
+ }
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ virtual const char *
+ GetRepeatCommand (Args &current_command_args, uint32_t index)
+ {
+ // This is kind of gross, but the command hasn't been parsed yet so we can't look at the option
+ // values for this invocation... I have to scan the arguments directly.
+ size_t num_args = current_command_args.GetArgumentCount();
+ bool is_reverse = false;
+ for (size_t i = 0 ; i < num_args; i++)
+ {
+ const char *arg = current_command_args.GetArgumentAtIndex(i);
+ if (arg && (strcmp(arg, "-r") == 0 || strcmp(arg, "--reverse") == 0))
+ {
+ is_reverse = true;
+ }
+ }
+ if (is_reverse)
+ {
+ if (m_reverse_name.empty())
+ {
+ m_reverse_name = m_cmd_name;
+ m_reverse_name.append (" -r");
+ }
+ return m_reverse_name.c_str();
+ }
+ else
+ return m_cmd_name.c_str();
+ }
+
+protected:
+
+ struct SourceInfo
+ {
+ ConstString function;
+ LineEntry line_entry;
+
+ SourceInfo (const ConstString &name, const LineEntry &line_entry) :
+ function(name),
+ line_entry(line_entry)
+ {
+ }
+
+ SourceInfo () :
+ function(),
+ line_entry()
+ {
+ }
+
+ bool
+ IsValid () const
+ {
+ return (bool)function && line_entry.IsValid();
+ }
+
+ bool
+ operator == (const SourceInfo &rhs) const
+ {
+ return function == rhs.function &&
+ line_entry.file == rhs.line_entry.file &&
+ line_entry.line == rhs.line_entry.line;
+ }
+
+ bool
+ operator != (const SourceInfo &rhs) const
+ {
+ return function != rhs.function ||
+ line_entry.file != rhs.line_entry.file ||
+ line_entry.line != rhs.line_entry.line;
+ }
+
+ bool
+ operator < (const SourceInfo &rhs) const
+ {
+ if (function.GetCString() < rhs.function.GetCString())
+ return true;
+ if (line_entry.file.GetDirectory().GetCString() < rhs.line_entry.file.GetDirectory().GetCString())
+ return true;
+ if (line_entry.file.GetFilename().GetCString() < rhs.line_entry.file.GetFilename().GetCString())
+ return true;
+ if (line_entry.line < rhs.line_entry.line)
+ return true;
+ return false;
+ }
+ };
+
+ size_t
+ DisplayFunctionSource (const SymbolContext &sc,
+ SourceInfo &source_info,
+ CommandReturnObject &result)
+ {
+ if (!source_info.IsValid())
+ {
+ source_info.function = sc.GetFunctionName();
+ source_info.line_entry = sc.GetFunctionStartLineEntry();
+ }
+
+ if (sc.function)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ FileSpec start_file;
+ uint32_t start_line;
+ uint32_t end_line;
+ FileSpec end_file;
+
+ if (sc.block == NULL)
+ {
+ // Not an inlined function
+ sc.function->GetStartLineSourceInfo (start_file, start_line);
+ if (start_line == 0)
+ {
+ result.AppendErrorWithFormat("Could not find line information for start of function: \"%s\".\n", source_info.function.GetCString());
+ result.SetStatus (eReturnStatusFailed);
+ return 0;
+ }
+ sc.function->GetEndLineSourceInfo (end_file, end_line);
+ }
+ else
+ {
+ // We have an inlined function
+ start_file = source_info.line_entry.file;
+ start_line = source_info.line_entry.line;
+ end_line = start_line + m_options.num_lines;
+ }
+
+ // This is a little hacky, but the first line table entry for a function points to the "{" that
+ // starts the function block. It would be nice to actually get the function
+ // declaration in there too. So back up a bit, but not further than what you're going to display.
+ uint32_t extra_lines;
+ if (m_options.num_lines >= 10)
+ extra_lines = 5;
+ else
+ extra_lines = m_options.num_lines/2;
+ uint32_t line_no;
+ if (start_line <= extra_lines)
+ line_no = 1;
+ else
+ line_no = start_line - extra_lines;
+
+ // For fun, if the function is shorter than the number of lines we're supposed to display,
+ // only display the function...
+ if (end_line != 0)
+ {
+ if (m_options.num_lines > end_line - line_no)
+ m_options.num_lines = end_line - line_no + extra_lines;
+ }
+
+ m_breakpoint_locations.Clear();
+
+ if (m_options.show_bp_locs)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (start_file, 0, show_inlines);
+ SearchFilter target_search_filter (m_exe_ctx.GetTargetSP());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+
+ result.AppendMessageWithFormat("File: %s\n", start_file.GetPath().c_str());
+ return target->GetSourceManager().DisplaySourceLinesWithLineNumbers (start_file,
+ line_no,
+ 0,
+ m_options.num_lines,
+ "",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Could not find function info for: \"%s\".\n", m_options.symbol_name.c_str());
+ }
+ return 0;
+ }
+
+ // From Jim: The FindMatchingFunctions / FindMatchingFunctionSymbols functions
+ // "take a possibly empty vector of strings which are names of modules, and
+ // run the two search functions on the subset of the full module list that
+ // matches the strings in the input vector". If we wanted to put these somewhere,
+ // there should probably be a module-filter-list that can be passed to the
+ // various ModuleList::Find* calls, which would either be a vector of string
+ // names or a ModuleSpecList.
+ size_t FindMatchingFunctions (Target *target, const ConstString &name, SymbolContextList& sc_list)
+ {
+ // Displaying the source for a symbol:
+ bool include_inlines = true;
+ bool append = true;
+ bool include_symbols = false;
+ size_t num_matches = 0;
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ const size_t num_modules = m_options.modules.size();
+ if (num_modules > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().FindFunctions (name, eFunctionNameTypeAuto, include_symbols, include_inlines, append, sc_list);
+ }
+ return num_matches;
+ }
+
+ size_t FindMatchingFunctionSymbols (Target *target, const ConstString &name, SymbolContextList& sc_list)
+ {
+ size_t num_matches = 0;
+ const size_t num_modules = m_options.modules.size();
+ if (num_modules > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0; i < num_modules; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().FindFunctionSymbols (name, eFunctionNameTypeAuto, sc_list);
+ }
+ return num_matches;
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 0)
+ {
+ result.AppendErrorWithFormat("'%s' takes no arguments, only flags.\n", GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ if (!m_options.symbol_name.empty())
+ {
+ SymbolContextList sc_list;
+ ConstString name(m_options.symbol_name.c_str());
+
+ // Displaying the source for a symbol. Search for function named name.
+ size_t num_matches = FindMatchingFunctions (target, name, sc_list);
+ if (!num_matches)
+ {
+ // If we didn't find any functions with that name, try searching for symbols
+ // that line up exactly with function addresses.
+ SymbolContextList sc_list_symbols;
+ size_t num_symbol_matches = FindMatchingFunctionSymbols (target, name, sc_list_symbols);
+ for (size_t i = 0; i < num_symbol_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list_symbols.GetContextAtIndex (i, sc);
+ if (sc.symbol)
+ {
+ const Address &base_address = sc.symbol->GetAddress();
+ Function *function = base_address.CalculateSymbolContextFunction();
+ if (function)
+ {
+ sc_list.Append (SymbolContext(function));
+ num_matches++;
+ break;
+ }
+ }
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ result.AppendErrorWithFormat("Could not find function named: \"%s\".\n", m_options.symbol_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (num_matches > 1)
+ {
+ std::set<SourceInfo> source_match_set;
+
+ bool displayed_something = false;
+ for (size_t i = 0; i < num_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (i, sc);
+ SourceInfo source_info (sc.GetFunctionName(),
+ sc.GetFunctionStartLineEntry());
+
+ if (source_info.IsValid())
+ {
+ if (source_match_set.find(source_info) == source_match_set.end())
+ {
+ source_match_set.insert(source_info);
+ if (DisplayFunctionSource (sc, source_info, result))
+ displayed_something = true;
+ }
+ }
+ }
+
+ if (displayed_something)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ SourceInfo source_info;
+
+ if (DisplayFunctionSource (sc, source_info, result))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+ else if (m_options.address != LLDB_INVALID_ADDRESS)
+ {
+ Address so_addr;
+ StreamString error_strm;
+ SymbolContextList sc_list;
+
+ if (target->GetSectionLoadList().IsEmpty())
+ {
+ // The target isn't loaded yet, we need to lookup the file address
+ // in all modules
+ const ModuleList &module_list = target->GetImages();
+ const size_t num_modules = module_list.GetSize();
+ for (size_t i=0; i<num_modules; ++i)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndex(i));
+ if (module_sp && module_sp->ResolveFileAddress(m_options.address, so_addr))
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
+ sc_list.Append(sc);
+ }
+ }
+
+ if (sc_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat("no modules have source information for file address 0x%" PRIx64 ".\n",
+ m_options.address);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // The target has some things loaded, resolve this address to a
+ // compile unit + file + line and display
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.address, so_addr))
+ {
+ ModuleSP module_sp (so_addr.GetModule());
+ if (module_sp)
+ {
+ SymbolContext sc;
+ sc.Clear(true);
+ if (module_sp->ResolveSymbolContextForAddress (so_addr, eSymbolContextEverything, sc) & eSymbolContextLineEntry)
+ {
+ sc_list.Append(sc);
+ }
+ else
+ {
+ so_addr.Dump(&error_strm, NULL, Address::DumpStyleModuleWithFileAddress);
+ result.AppendErrorWithFormat("address resolves to %s, but there is no line table information available for this address.\n",
+ error_strm.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (sc_list.GetSize() == 0)
+ {
+ result.AppendErrorWithFormat("no modules contain load address 0x%" PRIx64 ".\n", m_options.address);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ uint32_t num_matches = sc_list.GetSize();
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (m_options.show_bp_locs)
+ {
+ 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());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+
+ bool show_fullpaths = true;
+ bool show_module = true;
+ bool show_inlined_frames = true;
+ sc.DumpStopContext(&result.GetOutputStream(),
+ m_exe_ctx.GetBestExecutionContextScope(),
+ sc.line_entry.range.GetBaseAddress(),
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+ result.GetOutputStream().EOL();
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ size_t lines_to_back_up = m_options.num_lines >= 10 ? 5 : m_options.num_lines/2;
+
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
+ sc.line_entry.line,
+ lines_to_back_up,
+ m_options.num_lines - lines_to_back_up,
+ "->",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ }
+ else if (m_options.file_name.empty())
+ {
+ // Last valid source manager context, or the current frame if no
+ // valid last context in source manager.
+ // One little trick here, if you type the exact same list command twice in a row, it is
+ // more likely because you typed it once, then typed it again
+ if (m_options.start_line == 0)
+ {
+ if (target->GetSourceManager().DisplayMoreWithLineNumbers (&result.GetOutputStream(),
+ m_options.num_lines,
+ m_options.reverse,
+ GetBreakpointLocations ()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else
+ {
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ if (m_options.show_bp_locs)
+ {
+ SourceManager::FileSP last_file_sp (target->GetSourceManager().GetLastFile ());
+ if (last_file_sp)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (last_file_sp->GetFileSpec(), 0, show_inlines);
+ SearchFilter target_search_filter (target->shared_from_this());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+ }
+ else
+ m_breakpoint_locations.Clear();
+
+ if (target->GetSourceManager().DisplaySourceLinesWithLineNumbersUsingLastFile(
+ m_options.start_line, // Line to display
+ m_options.num_lines, // Lines after line to
+ UINT32_MAX, // Don't mark "line"
+ "", // Don't mark "line"
+ &result.GetOutputStream(),
+ GetBreakpointLocations ()))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+
+ }
+ }
+ else
+ {
+ const char *filename = m_options.file_name.c_str();
+
+ bool check_inlines = false;
+ SymbolContextList sc_list;
+ size_t num_matches = 0;
+
+ if (m_options.modules.size() > 0)
+ {
+ ModuleList matching_modules;
+ for (size_t i = 0, e = m_options.modules.size(); i < e; ++i)
+ {
+ FileSpec module_file_spec(m_options.modules[i].c_str(), false);
+ if (module_file_spec)
+ {
+ ModuleSpec module_spec (module_file_spec);
+ matching_modules.Clear();
+ target->GetImages().FindModules (module_spec, matching_modules);
+ num_matches += matching_modules.ResolveSymbolContextForFilePath (filename,
+ 0,
+ check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit,
+ sc_list);
+ }
+ }
+ }
+ else
+ {
+ num_matches = target->GetImages().ResolveSymbolContextForFilePath (filename,
+ 0,
+ check_inlines,
+ eSymbolContextModule | eSymbolContextCompUnit,
+ sc_list);
+ }
+
+ if (num_matches == 0)
+ {
+ result.AppendErrorWithFormat("Could not find source file \"%s\".\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (num_matches > 1)
+ {
+ bool got_multiple = false;
+ FileSpec *test_cu_spec = NULL;
+
+ for (unsigned i = 0; i < num_matches; i++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (test_cu_spec)
+ {
+ if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
+ got_multiple = true;
+ break;
+ }
+ else
+ test_cu_spec = sc.comp_unit;
+ }
+ }
+ if (got_multiple)
+ {
+ result.AppendErrorWithFormat("Multiple source files found matching: \"%s.\"\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ if (sc.comp_unit)
+ {
+ if (m_options.show_bp_locs)
+ {
+ const bool show_inlines = true;
+ m_breakpoint_locations.Reset (*sc.comp_unit, 0, show_inlines);
+ SearchFilter target_search_filter (target->shared_from_this());
+ target_search_filter.Search (m_breakpoint_locations);
+ }
+ else
+ m_breakpoint_locations.Clear();
+
+ if (m_options.num_lines == 0)
+ m_options.num_lines = 10;
+
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers (sc.comp_unit,
+ m_options.start_line,
+ 0,
+ m_options.num_lines,
+ "",
+ &result.GetOutputStream(),
+ GetBreakpointLocations ());
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("No comp unit found for: \"%s.\"\n",
+ m_options.file_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ return result.Succeeded();
+ }
+
+ const SymbolContextList *
+ GetBreakpointLocations ()
+ {
+ if (m_breakpoint_locations.GetFileLineMatches().GetSize() > 0)
+ return &m_breakpoint_locations.GetFileLineMatches();
+ return NULL;
+ }
+ CommandOptions m_options;
+ FileLineResolver m_breakpoint_locations;
+ std::string m_reverse_name;
+
+};
+
+OptionDefinition
+CommandObjectSourceList::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of source lines to display."},
+{ LLDB_OPT_SET_1 |
+ LLDB_OPT_SET_2 , false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Look up the source file in the given shared library."},
+{ LLDB_OPT_SET_ALL, false, "show-breakpoints", 'b', no_argument, NULL, 0, eArgTypeNone, "Show the line table locations from the debug information that indicate valid places to set source level breakpoints."},
+{ LLDB_OPT_SET_1 , false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "The file from which to display source."},
+{ LLDB_OPT_SET_1 , false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "The line number at which to start the display source."},
+{ LLDB_OPT_SET_2 , false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeSymbol, "The name of a function whose source to display."},
+{ LLDB_OPT_SET_3 , false, "address",'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Lookup the address and display the source information for the corresponding file and line."},
+{ LLDB_OPT_SET_4, false, "reverse", 'r', no_argument, NULL, 0, eArgTypeNone, "Reverse the listing to look backwards from the last displayed block of source."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectMultiwordSource
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSource
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordSource::CommandObjectMultiwordSource (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "source",
+ "A set of commands for accessing source file information",
+ "source <subcommand> [<subcommand-options>]")
+{
+ // "source info" isn't implemented yet...
+ //LoadSubCommand ("info", CommandObjectSP (new CommandObjectSourceInfo (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectSourceList (interpreter)));
+}
+
+CommandObjectMultiwordSource::~CommandObjectMultiwordSource ()
+{
+}
+
diff --git a/source/Commands/CommandObjectSource.h b/source/Commands/CommandObjectSource.h
new file mode 100644
index 000000000000..0daef1385860
--- /dev/null
+++ b/source/Commands/CommandObjectSource.h
@@ -0,0 +1,40 @@
+//===-- CommandObjectSource.h.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_CommandObjectSource_h_
+#define liblldb_CommandObjectSource_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Core/STLUtils.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordSource
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordSource : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordSource (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordSource ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSource.h_h_
diff --git a/source/Commands/CommandObjectSyntax.cpp b/source/Commands/CommandObjectSyntax.cpp
new file mode 100644
index 000000000000..d2021ea3eb19
--- /dev/null
+++ b/source/Commands/CommandObjectSyntax.cpp
@@ -0,0 +1,113 @@
+//===-- CommandObjectSyntax.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 "CommandObjectSyntax.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/Options.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectSyntax
+//-------------------------------------------------------------------------
+
+CommandObjectSyntax::CommandObjectSyntax (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "syntax",
+ "Shows the correct syntax for a given debugger command.",
+ "syntax <command>")
+{
+ CommandArgumentEntry arg;
+ CommandArgumentData command_arg;
+
+ // Define the first (and only) variant of this arg.
+ command_arg.arg_type = eArgTypeCommandName;
+ command_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (command_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+}
+
+CommandObjectSyntax::~CommandObjectSyntax()
+{
+}
+
+
+bool
+CommandObjectSyntax::DoExecute (Args& command, CommandReturnObject &result)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObject *cmd_obj;
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc > 0)
+ {
+ cmd_obj = m_interpreter.GetCommandObject (command.GetArgumentAtIndex(0));
+ bool all_okay = true;
+ for (size_t i = 1; i < argc; ++i)
+ {
+ std::string sub_command = command.GetArgumentAtIndex (i);
+ if (!cmd_obj->IsMultiwordObject())
+ all_okay = false;
+ else
+ {
+ cmd_obj = cmd_obj->GetSubcommandObject(sub_command.c_str());
+ if (!cmd_obj)
+ all_okay = false;
+ }
+ }
+
+ if (all_okay && (cmd_obj != NULL))
+ {
+ Stream &output_strm = result.GetOutputStream();
+ if (cmd_obj->GetOptions() != NULL)
+ {
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ output_strm.Printf ("(Try 'help %s' for more information on command options syntax.)\n",
+ cmd_obj->GetCommandName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ output_strm.Printf ("\nSyntax: %s\n", cmd_obj->GetSyntax());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ std::string cmd_string;
+ command.GetCommandString (cmd_string);
+ result.AppendErrorWithFormat ("'%s' is not a known command.\n", cmd_string.c_str());
+ result.AppendError ("Try 'help' to see a current list of commands.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("Must call 'syntax' with a valid command.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+}
diff --git a/source/Commands/CommandObjectSyntax.h b/source/Commands/CommandObjectSyntax.h
new file mode 100644
index 000000000000..47bf85f8549e
--- /dev/null
+++ b/source/Commands/CommandObjectSyntax.h
@@ -0,0 +1,44 @@
+//===-- CommandObjectSyntax.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_CommandObjectSyntax_h_
+#define liblldb_CommandObjectSyntax_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectSyntax
+//-------------------------------------------------------------------------
+
+class CommandObjectSyntax : public CommandObjectParsed
+{
+public:
+
+ CommandObjectSyntax (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectSyntax ();
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result);
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectSyntax_h_
diff --git a/source/Commands/CommandObjectTarget.cpp b/source/Commands/CommandObjectTarget.cpp
new file mode 100644
index 000000000000..dd0e2a0011b0
--- /dev/null
+++ b/source/Commands/CommandObjectTarget.cpp
@@ -0,0 +1,5354 @@
+//===-- CommandObjectTarget.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 "CommandObjectTarget.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupArchitecture.h"
+#include "lldb/Interpreter/OptionGroupBoolean.h"
+#include "lldb/Interpreter/OptionGroupFile.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+#include "lldb/Interpreter/OptionGroupVariable.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Interpreter/OptionGroupUInt64.h"
+#include "lldb/Interpreter/OptionGroupUUID.h"
+#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+static void
+DumpTargetInfo (uint32_t target_idx, Target *target, const char *prefix_cstr, bool show_stopped_process_status, Stream &strm)
+{
+ const ArchSpec &target_arch = target->GetArchitecture();
+
+ Module *exe_module = target->GetExecutableModulePointer();
+ char exe_path[PATH_MAX];
+ bool exe_valid = false;
+ if (exe_module)
+ exe_valid = exe_module->GetFileSpec().GetPath (exe_path, sizeof(exe_path));
+
+ if (!exe_valid)
+ ::strcpy (exe_path, "<none>");
+
+ strm.Printf ("%starget #%u: %s", prefix_cstr ? prefix_cstr : "", target_idx, exe_path);
+
+ uint32_t properties = 0;
+ if (target_arch.IsValid())
+ {
+ strm.Printf ("%sarch=%s", properties++ > 0 ? ", " : " ( ", target_arch.GetTriple().str().c_str());
+ properties++;
+ }
+ PlatformSP platform_sp (target->GetPlatform());
+ if (platform_sp)
+ strm.Printf ("%splatform=%s", properties++ > 0 ? ", " : " ( ", platform_sp->GetName().GetCString());
+
+ ProcessSP process_sp (target->GetProcessSP());
+ bool show_process_status = false;
+ if (process_sp)
+ {
+ lldb::pid_t pid = process_sp->GetID();
+ StateType state = process_sp->GetState();
+ if (show_stopped_process_status)
+ show_process_status = StateIsStoppedState(state, true);
+ const char *state_cstr = StateAsCString (state);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ strm.Printf ("%spid=%" PRIu64, properties++ > 0 ? ", " : " ( ", pid);
+ strm.Printf ("%sstate=%s", properties++ > 0 ? ", " : " ( ", state_cstr);
+ }
+ if (properties > 0)
+ strm.PutCString (" )\n");
+ else
+ strm.EOL();
+ if (show_process_status)
+ {
+ 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 (strm);
+ process_sp->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+
+ }
+}
+
+static uint32_t
+DumpTargetList (TargetList &target_list, bool show_stopped_process_status, Stream &strm)
+{
+ const uint32_t num_targets = target_list.GetNumTargets();
+ if (num_targets)
+ {
+ TargetSP selected_target_sp (target_list.GetSelectedTarget());
+ strm.PutCString ("Current targets:\n");
+ for (uint32_t i=0; i<num_targets; ++i)
+ {
+ TargetSP target_sp (target_list.GetTargetAtIndex (i));
+ if (target_sp)
+ {
+ bool is_selected = target_sp.get() == selected_target_sp.get();
+ DumpTargetInfo (i,
+ target_sp.get(),
+ is_selected ? "* " : " ",
+ show_stopped_process_status,
+ strm);
+ }
+ }
+ }
+ return num_targets;
+}
+#pragma mark CommandObjectTargetCreate
+
+//-------------------------------------------------------------------------
+// "target create"
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetCreate : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetCreate(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target create",
+ "Create a target using the argument as the main executable.",
+ NULL),
+ m_option_group (interpreter),
+ m_arch_option (),
+ m_platform_options(true), // Do include the "--platform" option in the platform settings by passing true
+ m_core_file (LLDB_OPT_SET_1, false, "core", 'c', 0, eArgTypeFilename, "Fullpath to a core file to use for this target."),
+ m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable."),
+ m_remote_file (LLDB_OPT_SET_1, false, "remote-file", 'r', 0, eArgTypeFilename, "Fullpath to the file on the remote host if debugging remotely."),
+ m_add_dependents (LLDB_OPT_SET_1, false, "no-dependents", 'd', "Don't load dependent files when creating the target, just add the specified executable.", true, true)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_arch_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_platform_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_core_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_remote_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_add_dependents, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ ~CommandObjectTargetCreate ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ FileSpec core_file (m_core_file.GetOptionValue().GetCurrentValue());
+ FileSpec remote_file (m_remote_file.GetOptionValue().GetCurrentValue());
+
+ if (argc == 1 || core_file)
+ {
+ FileSpec symfile (m_symbol_file.GetOptionValue().GetCurrentValue());
+ if (symfile)
+ {
+ if (!symfile.Exists())
+ {
+ char symfile_path[PATH_MAX];
+ symfile.GetPath(symfile_path, sizeof(symfile_path));
+ result.AppendErrorWithFormat("invalid symbol file path '%s'", symfile_path);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ const char *file_path = command.GetArgumentAtIndex(0);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "(lldb) target create '%s'", file_path);
+ TargetSP target_sp;
+ Debugger &debugger = m_interpreter.GetDebugger();
+ const char *arch_cstr = m_arch_option.GetArchitectureName();
+ const bool get_dependent_files = m_add_dependents.GetOptionValue().GetCurrentValue();
+ Error error (debugger.GetTargetList().CreateTarget (debugger,
+ file_path,
+ arch_cstr,
+ get_dependent_files,
+ &m_platform_options,
+ target_sp));
+
+ if (target_sp)
+ {
+ if (symfile || remote_file)
+ {
+ ModuleSP module_sp (target_sp->GetExecutableModule());
+ if (module_sp)
+ {
+ if (symfile)
+ module_sp->SetSymbolFileFileSpec(symfile);
+ if (remote_file)
+ {
+ std::string remote_path = remote_file.GetPath();
+ target_sp->SetArg0(remote_path.c_str());
+ module_sp->SetPlatformFileSpec(remote_file);
+ }
+ }
+ }
+
+ debugger.GetTargetList().SetSelectedTarget(target_sp.get());
+ if (core_file)
+ {
+ char core_path[PATH_MAX];
+ core_file.GetPath(core_path, sizeof(core_path));
+ if (core_file.Exists())
+ {
+ FileSpec core_file_dir;
+ core_file_dir.GetDirectory() = core_file.GetDirectory();
+ target_sp->GetExecutableSearchPaths ().Append (core_file_dir);
+
+ ProcessSP process_sp (target_sp->CreateProcess (m_interpreter.GetDebugger().GetListener(), NULL, &core_file));
+
+ if (process_sp)
+ {
+ // Seems wierd that we Launch a core file, but that is
+ // what we do!
+ error = process_sp->LoadCore();
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString("can't find plug-in for core file"));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Core file '%s' (%s) was loaded.\n", core_path, target_sp->GetArchitecture().GetArchitectureName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to find process plug-in for core file '%s'\n", core_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Core file '%s' does not exist\n", core_path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Current executable set to '%s' (%s).\n", file_path, target_sp->GetArchitecture().GetArchitectureName());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ }
+ else
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one executable path argument, or use the --core-file option.\n", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupArchitecture m_arch_option;
+ OptionGroupPlatform m_platform_options;
+ OptionGroupFile m_core_file;
+ OptionGroupFile m_symbol_file;
+ OptionGroupFile m_remote_file;
+ OptionGroupBoolean m_add_dependents;
+};
+
+#pragma mark CommandObjectTargetList
+
+//----------------------------------------------------------------------
+// "target list"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetList : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target list",
+ "List all current targets in the current debug session.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetList ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 0)
+ {
+ Stream &strm = result.GetOutputStream();
+
+ bool show_stopped_process_status = false;
+ if (DumpTargetList (m_interpreter.GetDebugger().GetTargetList(), show_stopped_process_status, strm) == 0)
+ {
+ strm.PutCString ("No targets.\n");
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("the 'target list' command takes no arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetSelect
+
+//----------------------------------------------------------------------
+// "target select"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetSelect : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target select",
+ "Select a target as the current target by target index.",
+ NULL,
+ 0)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetSelect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ bool success = false;
+ const char *target_idx_arg = args.GetArgumentAtIndex(0);
+ uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success);
+ if (success)
+ {
+ TargetList &target_list = m_interpreter.GetDebugger().GetTargetList();
+ const uint32_t num_targets = target_list.GetNumTargets();
+ if (target_idx < num_targets)
+ {
+ TargetSP target_sp (target_list.GetTargetAtIndex (target_idx));
+ if (target_sp)
+ {
+ Stream &strm = result.GetOutputStream();
+ target_list.SetSelectedTarget (target_sp.get());
+ bool show_stopped_process_status = false;
+ DumpTargetList (target_list, show_stopped_process_status, strm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("target #%u is NULL in target list\n", target_idx);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid index string value '%s'\n", target_idx_arg);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("'target select' takes a single argument: a target index\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetSelect
+
+//----------------------------------------------------------------------
+// "target delete"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target delete",
+ "Delete one or more targets by target index.",
+ NULL,
+ 0),
+ m_option_group (interpreter),
+ m_cleanup_option (LLDB_OPT_SET_1, false, "clean", 'c', "Perform extra cleanup to minimize memory consumption after deleting the target.", false, false)
+ {
+ m_option_group.Append (&m_cleanup_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetDelete ()
+ {
+ }
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ const size_t argc = args.GetArgumentCount();
+ std::vector<TargetSP> delete_target_list;
+ TargetList &target_list = m_interpreter.GetDebugger().GetTargetList();
+ bool success = true;
+ TargetSP target_sp;
+ if (argc > 0)
+ {
+ const uint32_t num_targets = target_list.GetNumTargets();
+ // Bail out if don't have any targets.
+ if (num_targets == 0) {
+ result.AppendError("no targets to delete");
+ result.SetStatus(eReturnStatusFailed);
+ success = false;
+ }
+
+ for (uint32_t arg_idx = 0; success && arg_idx < argc; ++arg_idx)
+ {
+ const char *target_idx_arg = args.GetArgumentAtIndex(arg_idx);
+ uint32_t target_idx = Args::StringToUInt32 (target_idx_arg, UINT32_MAX, 0, &success);
+ if (success)
+ {
+ if (target_idx < num_targets)
+ {
+ target_sp = target_list.GetTargetAtIndex (target_idx);
+ if (target_sp)
+ {
+ delete_target_list.push_back (target_sp);
+ continue;
+ }
+ }
+ if (num_targets > 1)
+ result.AppendErrorWithFormat ("target index %u is out of range, valid target indexes are 0 - %u\n",
+ target_idx,
+ num_targets - 1);
+ else
+ result.AppendErrorWithFormat("target index %u is out of range, the only valid index is 0\n",
+ target_idx);
+
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid target index '%s'\n", target_idx_arg);
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ }
+
+ }
+ else
+ {
+ target_sp = target_list.GetSelectedTarget();
+ if (target_sp)
+ {
+ delete_target_list.push_back (target_sp);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("no target is currently selected\n");
+ result.SetStatus (eReturnStatusFailed);
+ success = false;
+ }
+ }
+ if (success)
+ {
+ const size_t num_targets_to_delete = delete_target_list.size();
+ for (size_t idx = 0; idx < num_targets_to_delete; ++idx)
+ {
+ target_sp = delete_target_list[idx];
+ target_list.DeleteTarget(target_sp);
+ target_sp->Destroy();
+ }
+ // If "--clean" was specified, prune any orphaned shared modules from
+ // the global shared module list
+ if (m_cleanup_option.GetOptionValue ())
+ {
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+ }
+ result.GetOutputStream().Printf("%u targets deleted.\n", (uint32_t)num_targets_to_delete);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupBoolean m_cleanup_option;
+};
+
+
+#pragma mark CommandObjectTargetVariable
+
+//----------------------------------------------------------------------
+// "target variable"
+//----------------------------------------------------------------------
+
+class CommandObjectTargetVariable : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target variable",
+ "Read global variable(s) prior to, or while running your binary.",
+ NULL,
+ eFlagRequiresTarget),
+ m_option_group (interpreter),
+ m_option_variable (false), // Don't include frame options
+ m_option_format (eFormatDefault),
+ m_option_compile_units (LLDB_OPT_SET_1, false, "file", 'file', 0, eArgTypeFilename, "A basename or fullpath to a file that contains global variables. This option can be specified multiple times."),
+ m_option_shared_libraries (LLDB_OPT_SET_1, false, "shlib",'shlb', 0, eArgTypeFilename, "A basename or fullpath to a shared library to use in the search for global variables. This option can be specified multiple times."),
+ m_varobj_options()
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the first (and only) variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_variable, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_format, OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_GDB_FMT, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_compile_units, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_option_shared_libraries, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetVariable ()
+ {
+ }
+
+ void
+ DumpValueObject (Stream &s, VariableSP &var_sp, ValueObjectSP &valobj_sp, const char *root_name)
+ {
+ ValueObject::DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions());
+
+ switch (var_sp->GetScope())
+ {
+ case eValueTypeVariableGlobal:
+ if (m_option_variable.show_scope)
+ s.PutCString("GLOBAL: ");
+ break;
+
+ case eValueTypeVariableStatic:
+ if (m_option_variable.show_scope)
+ s.PutCString("STATIC: ");
+ break;
+
+ case eValueTypeVariableArgument:
+ if (m_option_variable.show_scope)
+ s.PutCString(" ARG: ");
+ break;
+
+ case eValueTypeVariableLocal:
+ if (m_option_variable.show_scope)
+ s.PutCString(" LOCAL: ");
+ break;
+
+ default:
+ break;
+ }
+
+ if (m_option_variable.show_decl)
+ {
+ bool show_fullpaths = false;
+ bool show_module = true;
+ if (var_sp->DumpDeclaration(&s, show_fullpaths, show_module))
+ s.PutCString (": ");
+ }
+
+ const Format format = m_option_format.GetFormat();
+ if (format != eFormatDefault)
+ options.SetFormat(format);
+
+ options.SetRootValueObjectName(root_name);
+
+ ValueObject::DumpValueObject (s,
+ valobj_sp.get(),
+ options);
+
+ }
+
+
+ static size_t GetVariableCallback (void *baton,
+ const char *name,
+ VariableList &variable_list)
+ {
+ Target *target = static_cast<Target *>(baton);
+ if (target)
+ {
+ return target->GetImages().FindGlobalVariables (ConstString(name),
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ return 0;
+ }
+
+
+
+ Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+
+ void
+ DumpGlobalVariableList(const ExecutionContext &exe_ctx, const SymbolContext &sc, const VariableList &variable_list, Stream &s)
+ {
+ size_t count = variable_list.GetSize();
+ if (count > 0)
+ {
+ if (sc.module_sp)
+ {
+ if (sc.comp_unit)
+ {
+ s.Printf ("Global variables for %s in %s:\n",
+ sc.comp_unit->GetPath().c_str(),
+ sc.module_sp->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ s.Printf ("Global variables for %s\n",
+ sc.module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ else if (sc.comp_unit)
+ {
+ s.Printf ("Global variables for %s\n",
+ sc.comp_unit->GetPath().c_str());
+ }
+
+ for (uint32_t i=0; i<count; ++i)
+ {
+ VariableSP var_sp (variable_list.GetVariableAtIndex(i));
+ if (var_sp)
+ {
+ ValueObjectSP valobj_sp (ValueObjectVariable::Create (exe_ctx.GetBestExecutionContextScope(), var_sp));
+
+ if (valobj_sp)
+ DumpValueObject (s, var_sp, valobj_sp, var_sp->GetName().GetCString());
+ }
+ }
+ }
+
+ }
+ virtual bool
+ DoExecute (Args& args, CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ const size_t argc = args.GetArgumentCount();
+ Stream &s = result.GetOutputStream();
+
+ if (argc > 0)
+ {
+
+ for (size_t idx = 0; idx < argc; ++idx)
+ {
+ VariableList variable_list;
+ ValueObjectList valobj_list;
+
+ const char *arg = args.GetArgumentAtIndex(idx);
+ size_t matches = 0;
+ bool use_var_name = false;
+ if (m_option_variable.use_regex)
+ {
+ RegularExpression regex(arg);
+ if (!regex.IsValid ())
+ {
+ result.GetErrorStream().Printf ("error: invalid regular expression: '%s'\n", arg);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ use_var_name = true;
+ matches = target->GetImages().FindGlobalVariables (regex,
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ else
+ {
+ Error error (Variable::GetValuesForVariableExpressionPath (arg,
+ m_exe_ctx.GetBestExecutionContextScope(),
+ GetVariableCallback,
+ target,
+ variable_list,
+ valobj_list));
+ matches = variable_list.GetSize();
+ }
+
+ if (matches == 0)
+ {
+ result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", arg);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ for (uint32_t global_idx=0; global_idx<matches; ++global_idx)
+ {
+ VariableSP var_sp (variable_list.GetVariableAtIndex(global_idx));
+ if (var_sp)
+ {
+ ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(global_idx));
+ if (!valobj_sp)
+ valobj_sp = ValueObjectVariable::Create (m_exe_ctx.GetBestExecutionContextScope(), var_sp);
+
+ if (valobj_sp)
+ DumpValueObject (s, var_sp, valobj_sp, use_var_name ? var_sp->GetName().GetCString() : arg);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ const FileSpecList &compile_units = m_option_compile_units.GetOptionValue().GetCurrentValue();
+ const FileSpecList &shlibs = m_option_shared_libraries.GetOptionValue().GetCurrentValue();
+ SymbolContextList sc_list;
+ const size_t num_compile_units = compile_units.GetSize();
+ const size_t num_shlibs = shlibs.GetSize();
+ if (num_compile_units == 0 && num_shlibs == 0)
+ {
+ bool success = false;
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ CompileUnit *comp_unit = NULL;
+ if (frame)
+ {
+ SymbolContext sc = frame->GetSymbolContext (eSymbolContextCompUnit);
+ if (sc.comp_unit)
+ {
+ const bool can_create = true;
+ VariableListSP comp_unit_varlist_sp (sc.comp_unit->GetVariableList(can_create));
+ if (comp_unit_varlist_sp)
+ {
+ size_t count = comp_unit_varlist_sp->GetSize();
+ if (count > 0)
+ {
+ DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
+ success = true;
+ }
+ }
+ }
+ }
+ if (!success)
+ {
+ if (frame)
+ {
+ if (comp_unit)
+ result.AppendErrorWithFormat ("no global variables in current compile unit: %s\n",
+ comp_unit->GetPath().c_str());
+ else
+ result.AppendErrorWithFormat ("no debug information for frame %u\n", frame->GetFrameIndex());
+ }
+ else
+ result.AppendError ("'target variable' takes one or more global variable names as arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ SymbolContextList sc_list;
+ const bool append = true;
+ // We have one or more compile unit or shlib
+ if (num_shlibs > 0)
+ {
+ for (size_t shlib_idx=0; shlib_idx<num_shlibs; ++shlib_idx)
+ {
+ const FileSpec module_file(shlibs.GetFileSpecAtIndex(shlib_idx));
+ ModuleSpec module_spec (module_file);
+
+ ModuleSP module_sp (target->GetImages().FindFirstModule(module_spec));
+ if (module_sp)
+ {
+ if (num_compile_units > 0)
+ {
+ for (size_t cu_idx=0; cu_idx<num_compile_units; ++cu_idx)
+ module_sp->FindCompileUnits(compile_units.GetFileSpecAtIndex(cu_idx), append, sc_list);
+ }
+ else
+ {
+ SymbolContext sc;
+ sc.module_sp = module_sp;
+ sc_list.Append(sc);
+ }
+ }
+ else
+ {
+ // Didn't find matching shlib/module in target...
+ result.AppendErrorWithFormat ("target doesn't contain the specified shared library: %s\n",
+ module_file.GetPath().c_str());
+ }
+ }
+ }
+ else
+ {
+ // No shared libraries, we just want to find globals for the compile units files that were specified
+ for (size_t cu_idx=0; cu_idx<num_compile_units; ++cu_idx)
+ target->GetImages().FindCompileUnits(compile_units.GetFileSpecAtIndex(cu_idx), append, sc_list);
+ }
+
+ const uint32_t num_scs = sc_list.GetSize();
+ if (num_scs > 0)
+ {
+ SymbolContext sc;
+ for (uint32_t sc_idx=0; sc_idx<num_scs; ++sc_idx)
+ {
+ if (sc_list.GetContextAtIndex(sc_idx, sc))
+ {
+ if (sc.comp_unit)
+ {
+ const bool can_create = true;
+ VariableListSP comp_unit_varlist_sp (sc.comp_unit->GetVariableList(can_create));
+ if (comp_unit_varlist_sp)
+ DumpGlobalVariableList(m_exe_ctx, sc, *comp_unit_varlist_sp, s);
+ }
+ else if (sc.module_sp)
+ {
+ // Get all global variables for this module
+ lldb_private::RegularExpression all_globals_regex("."); // Any global with at least one character
+ VariableList variable_list;
+ sc.module_sp->FindGlobalVariables(all_globals_regex, append, UINT32_MAX, variable_list);
+ DumpGlobalVariableList(m_exe_ctx, sc, variable_list, s);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (m_interpreter.TruncationWarningNecessary())
+ {
+ result.GetOutputStream().Printf(m_interpreter.TruncationWarningText(),
+ m_cmd_name.c_str());
+ m_interpreter.TruncationWarningGiven();
+ }
+
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupVariable m_option_variable;
+ OptionGroupFormat m_option_format;
+ OptionGroupFileList m_option_compile_units;
+ OptionGroupFileList m_option_shared_libraries;
+ OptionGroupValueObjectDisplay m_varobj_options;
+
+};
+
+
+#pragma mark CommandObjectTargetModulesSearchPathsAdd
+
+class CommandObjectTargetModulesSearchPathsAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths add",
+ "Add new image search paths substitution pairs to the current target.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData old_prefix_arg;
+ CommandArgumentData new_prefix_arg;
+
+ // Define the first variant of this arg pair.
+ old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
+ old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // Define the first variant of this arg pair.
+ new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
+ new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // There are two required arguments that must always occur together, i.e. an argument "pair". Because they
+ // must always occur together, they are treated as two variants of one argument rather than two independent
+ // arguments. Push them both into the first argument position for m_arguments...
+
+ arg.push_back (old_prefix_arg);
+ arg.push_back (new_prefix_arg);
+
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc & 1)
+ {
+ result.AppendError ("add requires an even number of arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ for (size_t i=0; i<argc; i+=2)
+ {
+ const char *from = command.GetArgumentAtIndex(i);
+ const char *to = command.GetArgumentAtIndex(i+1);
+
+ if (from[0] && to[0])
+ {
+ bool last_pair = ((argc - i) == 2);
+ target->GetImageSearchPathList().Append (ConstString(from),
+ ConstString(to),
+ last_pair); // Notify if this is the last pair
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty\n");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsClear
+
+class CommandObjectTargetModulesSearchPathsClear : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths clear",
+ "Clear all current image search path substitution pairs from the current target.",
+ "target modules search-paths clear")
+ {
+ }
+
+ ~CommandObjectTargetModulesSearchPathsClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ bool notify = true;
+ target->GetImageSearchPathList().Clear(notify);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsInsert
+
+class CommandObjectTargetModulesSearchPathsInsert : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsInsert (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths insert",
+ "Insert a new image search path substitution pair into the current target at the specified index.",
+ NULL)
+ {
+ CommandArgumentEntry arg1;
+ CommandArgumentEntry arg2;
+ CommandArgumentData index_arg;
+ CommandArgumentData old_prefix_arg;
+ CommandArgumentData new_prefix_arg;
+
+ // Define the first and only variant of this arg.
+ index_arg.arg_type = eArgTypeIndex;
+ index_arg.arg_repetition = eArgRepeatPlain;
+
+ // Put the one and only variant into the first arg for m_arguments:
+ arg1.push_back (index_arg);
+
+ // Define the first variant of this arg pair.
+ old_prefix_arg.arg_type = eArgTypeOldPathPrefix;
+ old_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // Define the first variant of this arg pair.
+ new_prefix_arg.arg_type = eArgTypeNewPathPrefix;
+ new_prefix_arg.arg_repetition = eArgRepeatPairPlus;
+
+ // There are two required arguments that must always occur together, i.e. an argument "pair". Because they
+ // must always occur together, they are treated as two variants of one argument rather than two independent
+ // arguments. Push them both into the same argument position for m_arguments...
+
+ arg2.push_back (old_prefix_arg);
+ arg2.push_back (new_prefix_arg);
+
+ // Add arguments to m_arguments.
+ m_arguments.push_back (arg1);
+ m_arguments.push_back (arg2);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsInsert ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ size_t argc = command.GetArgumentCount();
+ // check for at least 3 arguments and an odd nubmer of parameters
+ if (argc >= 3 && argc & 1)
+ {
+ bool success = false;
+
+ uint32_t insert_idx = Args::StringToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success);
+
+ if (!success)
+ {
+ result.AppendErrorWithFormat("<index> parameter is not an integer: '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ // shift off the index
+ command.Shift();
+ argc = command.GetArgumentCount();
+
+ for (uint32_t i=0; i<argc; i+=2, ++insert_idx)
+ {
+ const char *from = command.GetArgumentAtIndex(i);
+ const char *to = command.GetArgumentAtIndex(i+1);
+
+ if (from[0] && to[0])
+ {
+ bool last_pair = ((argc - i) == 2);
+ target->GetImageSearchPathList().Insert (ConstString(from),
+ ConstString(to),
+ insert_idx,
+ last_pair);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ if (from[0])
+ result.AppendError ("<path-prefix> can't be empty\n");
+ else
+ result.AppendError ("<new-path-prefix> can't be empty\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("insert requires at least three arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesSearchPathsList
+
+
+class CommandObjectTargetModulesSearchPathsList : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths list",
+ "List all current image search path substitution pairs in the current target.",
+ "target modules search-paths list")
+ {
+ }
+
+ ~CommandObjectTargetModulesSearchPathsList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 0)
+ {
+ result.AppendError ("list takes no arguments\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ target->GetImageSearchPathList().Dump(&result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSearchPathsQuery
+
+class CommandObjectTargetModulesSearchPathsQuery : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSearchPathsQuery (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules search-paths query",
+ "Transform a path using the first applicable image search path.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData path_arg;
+
+ // Define the first (and only) variant of this arg.
+ path_arg.arg_type = eArgTypeDirectoryName;
+ path_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (path_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ ~CommandObjectTargetModulesSearchPathsQuery ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ if (command.GetArgumentCount() != 1)
+ {
+ result.AppendError ("query requires one argument\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ ConstString orig(command.GetArgumentAtIndex(0));
+ ConstString transformed;
+ if (target->GetImageSearchPathList().RemapPath(orig, transformed))
+ result.GetOutputStream().Printf("%s\n", transformed.GetCString());
+ else
+ result.GetOutputStream().Printf("%s\n", orig.GetCString());
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+//----------------------------------------------------------------------
+// Static Helper functions
+//----------------------------------------------------------------------
+static void
+DumpModuleArchitecture (Stream &strm, Module *module, bool full_triple, uint32_t width)
+{
+ if (module)
+ {
+ const char *arch_cstr;
+ if (full_triple)
+ arch_cstr = module->GetArchitecture().GetTriple().str().c_str();
+ else
+ arch_cstr = module->GetArchitecture().GetArchitectureName();
+ if (width)
+ strm.Printf("%-*s", width, arch_cstr);
+ else
+ strm.PutCString(arch_cstr);
+ }
+}
+
+static void
+DumpModuleUUID (Stream &strm, Module *module)
+{
+ if (module && module->GetUUID().IsValid())
+ module->GetUUID().Dump (&strm);
+ else
+ strm.PutCString(" ");
+}
+
+static uint32_t
+DumpCompileUnitLineTable (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const FileSpec &file_spec,
+ bool load_addresses)
+{
+ uint32_t num_matches = 0;
+ if (module)
+ {
+ SymbolContextList sc_list;
+ num_matches = module->ResolveSymbolContextsForFileSpec (file_spec,
+ 0,
+ false,
+ eSymbolContextCompUnit,
+ sc_list);
+
+ for (uint32_t i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ if (i > 0)
+ strm << "\n\n";
+
+ strm << "Line table for " << *static_cast<FileSpec*> (sc.comp_unit) << " in `"
+ << module->GetFileSpec().GetFilename() << "\n";
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table)
+ line_table->GetDescription (&strm,
+ interpreter.GetExecutionContext().GetTargetPtr(),
+ lldb::eDescriptionLevelBrief);
+ else
+ strm << "No line table";
+ }
+ }
+ }
+ return num_matches;
+}
+
+static void
+DumpFullpath (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ {
+ std::string fullpath = file_spec_ptr->GetPath();
+ strm.Printf("%-*s", width, fullpath.c_str());
+ return;
+ }
+ else
+ {
+ file_spec_ptr->Dump(&strm);
+ return;
+ }
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+static void
+DumpDirectory (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ strm.Printf("%-*s", width, file_spec_ptr->GetDirectory().AsCString(""));
+ else
+ file_spec_ptr->GetDirectory().Dump(&strm);
+ return;
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+static void
+DumpBasename (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
+{
+ if (file_spec_ptr)
+ {
+ if (width > 0)
+ strm.Printf("%-*s", width, file_spec_ptr->GetFilename().AsCString(""));
+ else
+ file_spec_ptr->GetFilename().Dump(&strm);
+ return;
+ }
+ // Keep the width spacing correct if things go wrong...
+ if (width > 0)
+ strm.Printf("%-*s", width, "");
+}
+
+
+static void
+DumpModuleSymtab (CommandInterpreter &interpreter, Stream &strm, Module *module, SortOrder sort_order)
+{
+ if (module)
+ {
+ SymbolVendor *sym_vendor = module->GetSymbolVendor ();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ symtab->Dump(&strm, interpreter.GetExecutionContext().GetTargetPtr(), sort_order);
+ }
+ }
+}
+
+static void
+DumpModuleSections (CommandInterpreter &interpreter, Stream &strm, Module *module)
+{
+ if (module)
+ {
+ SectionList *section_list = module->GetSectionList();
+ if (section_list)
+ {
+ strm.Printf ("Sections for '%s' (%s):\n",
+ module->GetSpecificationDescription().c_str(),
+ module->GetArchitecture().GetArchitectureName());
+ strm.IndentMore();
+ section_list->Dump(&strm, interpreter.GetExecutionContext().GetTargetPtr(), true, UINT32_MAX);
+ strm.IndentLess();
+ }
+ }
+}
+
+static bool
+DumpModuleSymbolVendor (Stream &strm, Module *module)
+{
+ if (module)
+ {
+ SymbolVendor *symbol_vendor = module->GetSymbolVendor(true);
+ if (symbol_vendor)
+ {
+ symbol_vendor->Dump(&strm);
+ return true;
+ }
+ }
+ return false;
+}
+
+static void
+DumpAddress (ExecutionContextScope *exe_scope, const Address &so_addr, bool verbose, Stream &strm)
+{
+ strm.IndentMore();
+ strm.Indent (" Address: ");
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
+ strm.PutCString (" (");
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset);
+ strm.PutCString (")\n");
+ strm.Indent (" Summary: ");
+ const uint32_t save_indent = strm.GetIndentLevel ();
+ strm.SetIndentLevel (save_indent + 13);
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription);
+ strm.SetIndentLevel (save_indent);
+ // Print out detailed address information when verbose is enabled
+ if (verbose)
+ {
+ strm.EOL();
+ so_addr.Dump (&strm, exe_scope, Address::DumpStyleDetailedSymbolContext);
+ }
+ strm.IndentLess();
+}
+
+static bool
+LookupAddressInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ uint32_t resolve_mask,
+ lldb::addr_t raw_addr,
+ lldb::addr_t offset,
+ bool verbose)
+{
+ if (module)
+ {
+ lldb::addr_t addr = raw_addr - offset;
+ Address so_addr;
+ SymbolContext sc;
+ Target *target = interpreter.GetExecutionContext().GetTargetPtr();
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (!target->GetSectionLoadList().ResolveLoadAddress (addr, so_addr))
+ return false;
+ else if (so_addr.GetModule().get() != module)
+ return false;
+ }
+ else
+ {
+ if (!module->ResolveFileAddress (addr, so_addr))
+ return false;
+ }
+
+ ExecutionContextScope *exe_scope = interpreter.GetExecutionContext().GetBestExecutionContextScope();
+ DumpAddress (exe_scope, so_addr, verbose, strm);
+// strm.IndentMore();
+// strm.Indent (" Address: ");
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
+// strm.PutCString (" (");
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleSectionNameOffset);
+// strm.PutCString (")\n");
+// strm.Indent (" Summary: ");
+// const uint32_t save_indent = strm.GetIndentLevel ();
+// strm.SetIndentLevel (save_indent + 13);
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleResolvedDescription);
+// strm.SetIndentLevel (save_indent);
+// // Print out detailed address information when verbose is enabled
+// if (verbose)
+// {
+// strm.EOL();
+// so_addr.Dump (&strm, exe_scope, Address::DumpStyleDetailedSymbolContext);
+// }
+// strm.IndentLess();
+ return true;
+ }
+
+ return false;
+}
+
+static uint32_t
+LookupSymbolInModule (CommandInterpreter &interpreter, Stream &strm, Module *module, const char *name, bool name_is_regex, bool verbose)
+{
+ if (module)
+ {
+ SymbolContext sc;
+
+ SymbolVendor *sym_vendor = module->GetSymbolVendor ();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ uint32_t i;
+ std::vector<uint32_t> match_indexes;
+ ConstString symbol_name (name);
+ uint32_t num_matches = 0;
+ if (name_is_regex)
+ {
+ RegularExpression name_regexp(name);
+ num_matches = symtab->AppendSymbolIndexesMatchingRegExAndType (name_regexp,
+ eSymbolTypeAny,
+ match_indexes);
+ }
+ else
+ {
+ num_matches = symtab->AppendSymbolIndexesWithName (symbol_name, match_indexes);
+ }
+
+
+ if (num_matches > 0)
+ {
+ strm.Indent ();
+ strm.Printf("%u symbols match %s'%s' in ", num_matches,
+ name_is_regex ? "the regular expression " : "", name);
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ strm.IndentMore ();
+ //Symtab::DumpSymbolHeader (&strm);
+ for (i=0; i < num_matches; ++i)
+ {
+ Symbol *symbol = symtab->SymbolAtIndex(match_indexes[i]);
+ DumpAddress (interpreter.GetExecutionContext().GetBestExecutionContextScope(),
+ symbol->GetAddress(),
+ verbose,
+ strm);
+
+// strm.Indent ();
+// symbol->Dump (&strm, interpreter.GetExecutionContext().GetTargetPtr(), i);
+ }
+ strm.IndentLess ();
+ return num_matches;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+static void
+DumpSymbolContextList (ExecutionContextScope *exe_scope, Stream &strm, SymbolContextList &sc_list, bool verbose)
+{
+ strm.IndentMore ();
+ uint32_t i;
+ const uint32_t num_matches = sc_list.GetSize();
+
+ for (i=0; i<num_matches; ++i)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ AddressRange range;
+
+ sc.GetAddressRange(eSymbolContextEverything,
+ 0,
+ true,
+ range);
+
+ DumpAddress (exe_scope, range.GetBaseAddress(), verbose, strm);
+ }
+ }
+ strm.IndentLess ();
+}
+
+static size_t
+LookupFunctionInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const char *name,
+ bool name_is_regex,
+ bool include_inlines,
+ bool include_symbols,
+ bool verbose)
+{
+ if (module && name && name[0])
+ {
+ SymbolContextList sc_list;
+ const bool append = true;
+ size_t num_matches = 0;
+ if (name_is_regex)
+ {
+ RegularExpression function_name_regex (name);
+ num_matches = module->FindFunctions (function_name_regex,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+ else
+ {
+ ConstString function_name (name);
+ num_matches = module->FindFunctions (function_name,
+ NULL,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ DumpSymbolContextList (interpreter.GetExecutionContext().GetBestExecutionContextScope(), strm, sc_list, verbose);
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+static size_t
+LookupTypeInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const char *name_cstr,
+ bool name_is_regex)
+{
+ if (module && name_cstr && name_cstr[0])
+ {
+ TypeList type_list;
+ const uint32_t max_num_matches = UINT32_MAX;
+ size_t num_matches = 0;
+ bool name_is_fully_qualified = false;
+ SymbolContext sc;
+
+ ConstString name(name_cstr);
+ num_matches = module->FindTypes(sc, name, name_is_fully_qualified, max_num_matches, type_list);
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.Printf("%zu match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ const uint32_t num_types = type_list.GetSize();
+ for (uint32_t i=0; i<num_types; ++i)
+ {
+ TypeSP type_sp (type_list.GetTypeAtIndex(i));
+ if (type_sp)
+ {
+ // Resolve the clang type so that any forward references
+ // to types that haven't yet been parsed will get parsed.
+ type_sp->GetClangFullType ();
+ type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ // Print all typedef chains
+ TypeSP typedef_type_sp (type_sp);
+ TypeSP typedefed_type_sp (typedef_type_sp->GetTypedefType());
+ while (typedefed_type_sp)
+ {
+ strm.EOL();
+ strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString());
+ typedefed_type_sp->GetClangFullType ();
+ typedefed_type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ typedef_type_sp = typedefed_type_sp;
+ typedefed_type_sp = typedef_type_sp->GetTypedefType();
+ }
+ }
+ strm.EOL();
+ }
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+static size_t
+LookupTypeHere (CommandInterpreter &interpreter,
+ Stream &strm,
+ const SymbolContext &sym_ctx,
+ const char *name_cstr,
+ bool name_is_regex)
+{
+ if (!sym_ctx.module_sp)
+ return 0;
+
+ TypeList type_list;
+ const uint32_t max_num_matches = UINT32_MAX;
+ size_t num_matches = 1;
+ bool name_is_fully_qualified = false;
+
+ ConstString name(name_cstr);
+ num_matches = sym_ctx.module_sp->FindTypes(sym_ctx, name, name_is_fully_qualified, max_num_matches, type_list);
+
+ if (num_matches)
+ {
+ strm.Indent ();
+ strm.PutCString("Best match found in ");
+ DumpFullpath (strm, &sym_ctx.module_sp->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+
+ TypeSP type_sp (type_list.GetTypeAtIndex(0));
+ if (type_sp)
+ {
+ // Resolve the clang type so that any forward references
+ // to types that haven't yet been parsed will get parsed.
+ type_sp->GetClangFullType ();
+ type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ // Print all typedef chains
+ TypeSP typedef_type_sp (type_sp);
+ TypeSP typedefed_type_sp (typedef_type_sp->GetTypedefType());
+ while (typedefed_type_sp)
+ {
+ strm.EOL();
+ strm.Printf(" typedef '%s': ", typedef_type_sp->GetName().GetCString());
+ typedefed_type_sp->GetClangFullType ();
+ typedefed_type_sp->GetDescription (&strm, eDescriptionLevelFull, true);
+ typedef_type_sp = typedefed_type_sp;
+ typedefed_type_sp = typedef_type_sp->GetTypedefType();
+ }
+ }
+ strm.EOL();
+ }
+ return num_matches;
+}
+
+static uint32_t
+LookupFileAndLineInModule (CommandInterpreter &interpreter,
+ Stream &strm,
+ Module *module,
+ const FileSpec &file_spec,
+ uint32_t line,
+ bool check_inlines,
+ bool verbose)
+{
+ if (module && file_spec)
+ {
+ SymbolContextList sc_list;
+ const uint32_t num_matches = module->ResolveSymbolContextsForFileSpec(file_spec, line, check_inlines,
+ eSymbolContextEverything, sc_list);
+ if (num_matches > 0)
+ {
+ strm.Indent ();
+ strm.Printf("%u match%s found in ", num_matches, num_matches > 1 ? "es" : "");
+ strm << file_spec;
+ if (line > 0)
+ strm.Printf (":%u", line);
+ strm << " in ";
+ DumpFullpath (strm, &module->GetFileSpec(), 0);
+ strm.PutCString(":\n");
+ DumpSymbolContextList (interpreter.GetExecutionContext().GetBestExecutionContextScope(), strm, sc_list, verbose);
+ return num_matches;
+ }
+ }
+ return 0;
+
+}
+
+
+static size_t
+FindModulesByName (Target *target,
+ const char *module_name,
+ ModuleList &module_list,
+ bool check_global_list)
+{
+// Dump specified images (by basename or fullpath)
+ FileSpec module_file_spec(module_name, false);
+ ModuleSpec module_spec (module_file_spec);
+
+ const size_t initial_size = module_list.GetSize ();
+
+ if (check_global_list)
+ {
+ // Check the global list
+ Mutex::Locker locker(Module::GetAllocationModuleCollectionMutex());
+ const size_t num_modules = Module::GetNumberAllocatedModules();
+ ModuleSP module_sp;
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ Module *module = Module::GetAllocatedModuleAtIndex(image_idx);
+
+ if (module)
+ {
+ if (module->MatchesModuleSpec (module_spec))
+ {
+ module_sp = module->shared_from_this();
+ module_list.AppendIfNeeded(module_sp);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (target)
+ {
+ const size_t num_matches = target->GetImages().FindModules (module_spec, module_list);
+
+ // Not found in our module list for our target, check the main
+ // shared module list in case it is a extra file used somewhere
+ // else
+ if (num_matches == 0)
+ {
+ module_spec.GetArchitecture() = target->GetArchitecture();
+ ModuleList::FindSharedModules (module_spec, module_list);
+ }
+ }
+ else
+ {
+ ModuleList::FindSharedModules (module_spec,module_list);
+ }
+ }
+
+ return module_list.GetSize () - initial_size;
+}
+
+#pragma mark CommandObjectTargetModulesModuleAutoComplete
+
+//----------------------------------------------------------------------
+// A base command object class that can auto complete with module file
+// paths
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesModuleAutoComplete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesModuleAutoComplete (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax) :
+ CommandObjectParsed (interpreter, name, help, syntax)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesModuleAutoComplete ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard module completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eModuleCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+#pragma mark CommandObjectTargetModulesSourceFileAutoComplete
+
+//----------------------------------------------------------------------
+// A base command object class that can auto complete with module source
+// file paths
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesSourceFileAutoComplete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetModulesSourceFileAutoComplete (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags) :
+ CommandObjectParsed (interpreter, name, help, syntax, flags)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData source_file_arg;
+
+ // Define the first (and only) variant of this arg.
+ source_file_arg.arg_type = eArgTypeSourceFile;
+ source_file_arg.arg_repetition = eArgRepeatPlus;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (source_file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesSourceFileAutoComplete ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ // Arguments are the standard source file completer.
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eSourceFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpSymtab
+
+
+class CommandObjectTargetModulesDumpSymtab : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSymtab (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump symtab",
+ "Dump the symbol table from one or more target modules.",
+ NULL),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSymtab ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_sort_order (eSortOrderNone)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's':
+ m_sort_order = (SortOrder) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eSortOrderNone,
+ error);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_sort_order = eSortOrderNone;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+ static OptionDefinition g_option_table[];
+
+ SortOrder m_sort_order;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ Mutex::Locker modules_locker(target->GetImages().GetMutex());
+ const size_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping symbol table for %zu modules.\n", num_modules);
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ if (num_dumped > 0)
+ {
+ result.GetOutputStream().EOL();
+ result.GetOutputStream().EOL();
+ }
+ num_dumped++;
+ DumpModuleSymtab (m_interpreter,
+ result.GetOutputStream(),
+ target->GetImages().GetModulePointerAtIndexUnlocked(image_idx),
+ m_options.m_sort_order);
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ if (num_dumped > 0)
+ {
+ result.GetOutputStream().EOL();
+ result.GetOutputStream().EOL();
+ }
+ num_dumped++;
+ DumpModuleSymtab (m_interpreter, result.GetOutputStream(), module, m_options.m_sort_order);
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+
+
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement
+g_sort_option_enumeration[4] =
+{
+ { eSortOrderNone, "none", "No sorting, use the original symbol table order."},
+ { eSortOrderByAddress, "address", "Sort output by symbol address."},
+ { eSortOrderByName, "name", "Sort output by symbol name."},
+ { 0, NULL, NULL }
+};
+
+
+OptionDefinition
+CommandObjectTargetModulesDumpSymtab::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "sort", 's', required_argument, g_sort_option_enumeration, 0, eArgTypeSortOrder, "Supply a sort order when dumping the symbol table."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetModulesDumpSections
+
+//----------------------------------------------------------------------
+// Image section dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpSections : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSections (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump sections",
+ "Dump the sections from one or more target modules.",
+ //"target modules dump sections [<file1> ...]")
+ NULL)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSections ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ const size_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping sections for %zu modules.\n", num_modules);
+ for (size_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ num_dumped++;
+ DumpModuleSections (m_interpreter, result.GetOutputStream(), target->GetImages().GetModulePointerAtIndex(image_idx));
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ num_dumped++;
+ DumpModuleSections (m_interpreter, result.GetOutputStream(), module);
+ }
+ }
+ }
+ else
+ {
+ // Check the global list
+ Mutex::Locker locker(Module::GetAllocationModuleCollectionMutex());
+
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpSymfile
+
+//----------------------------------------------------------------------
+// Image debug symbol dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpSymfile : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpSymfile (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules dump symfile",
+ "Dump the debug symbol file for one or more target modules.",
+ //"target modules dump symfile [<file1> ...]")
+ NULL)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpSymfile ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ uint32_t num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // Dump all sections for all modules images
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker (target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ result.GetOutputStream().Printf("Dumping debug symbols for %zu modules.\n", num_modules);
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), target_modules.GetModulePointerAtIndexUnlocked(image_idx)))
+ num_dumped++;
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, true);
+ if (num_matches > 0)
+ {
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(i);
+ if (module)
+ {
+ if (DumpModuleSymbolVendor (result.GetOutputStream(), module))
+ num_dumped++;
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no matching executable images found");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDumpLineTable
+
+//----------------------------------------------------------------------
+// Image debug line table dumping command
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDumpLineTable : public CommandObjectTargetModulesSourceFileAutoComplete
+{
+public:
+ CommandObjectTargetModulesDumpLineTable (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesSourceFileAutoComplete (interpreter,
+ "target modules dump line-table",
+ "Dump the line table for one or more compilation units.",
+ NULL,
+ eFlagRequiresTarget)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDumpLineTable ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ uint32_t total_num_dumped = 0;
+
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+ {
+ FileSpec file_spec(arg_cstr, false);
+
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ uint32_t num_dumped = 0;
+ for (uint32_t i = 0; i<num_modules; ++i)
+ {
+ if (DumpCompileUnitLineTable (m_interpreter,
+ result.GetOutputStream(),
+ target_modules.GetModulePointerAtIndexUnlocked(i),
+ file_spec,
+ m_exe_ctx.GetProcessPtr() && m_exe_ctx.GetProcessRef().IsAlive()))
+ num_dumped++;
+ }
+ if (num_dumped == 0)
+ result.AppendWarningWithFormat ("No source filenames matched '%s'.\n", arg_cstr);
+ else
+ total_num_dumped += num_dumped;
+ }
+ }
+ }
+
+ if (total_num_dumped > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ {
+ result.AppendError ("no source filenames matched any command arguments");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+};
+
+
+#pragma mark CommandObjectTargetModulesDump
+
+//----------------------------------------------------------------------
+// Dump multi-word command for target modules
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesDump : public CommandObjectMultiword
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetModulesDump(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules dump",
+ "A set of commands for dumping information about one or more target modules.",
+ "target modules dump [symtab|sections|symfile|line-table] [<file1> <file2> ...]")
+ {
+ LoadSubCommand ("symtab", CommandObjectSP (new CommandObjectTargetModulesDumpSymtab (interpreter)));
+ LoadSubCommand ("sections", CommandObjectSP (new CommandObjectTargetModulesDumpSections (interpreter)));
+ LoadSubCommand ("symfile", CommandObjectSP (new CommandObjectTargetModulesDumpSymfile (interpreter)));
+ LoadSubCommand ("line-table", CommandObjectSP (new CommandObjectTargetModulesDumpLineTable (interpreter)));
+ }
+
+ virtual
+ ~CommandObjectTargetModulesDump()
+ {
+ }
+};
+
+class CommandObjectTargetModulesAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetModulesAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules add",
+ "Add a new module to the current target's modules.",
+ "target modules add [<module>]"),
+ m_option_group (interpreter),
+ m_symbol_file (LLDB_OPT_SET_1, false, "symfile", 's', 0, eArgTypeFilename, "Fullpath to a stand alone debug symbols file for when debug symbols are not in the executable.")
+ {
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_symbol_file, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetModulesAdd ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+protected:
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_symbol_file;
+
+
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ bool flush = false;
+
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (m_uuid_option_group.GetOptionValue ().OptionWasSet())
+ {
+ // We are given a UUID only, go locate the file
+ ModuleSpec module_spec;
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue ().GetCurrentValue();
+ if (m_symbol_file.GetOptionValue().OptionWasSet())
+ module_spec.GetSymbolFileSpec() = m_symbol_file.GetOptionValue().GetCurrentValue();
+ if (Symbols::DownloadObjectAndSymbolFile (module_spec))
+ {
+ ModuleSP module_sp (target->GetSharedModule (module_spec));
+ if (module_sp)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ else
+ {
+ flush = true;
+
+ StreamString strm;
+ module_spec.GetUUID().Dump (&strm);
+ if (module_spec.GetFileSpec())
+ {
+ if (module_spec.GetSymbolFileSpec())
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s with path %s and symbol file %s",
+ strm.GetString().c_str(),
+ module_spec.GetFileSpec().GetPath().c_str(),
+ module_spec.GetSymbolFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s with path %s",
+ strm.GetString().c_str(),
+ module_spec.GetFileSpec().GetPath().c_str());
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Unable to create the executable or symbol file with UUID %s",
+ strm.GetString().c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ StreamString strm;
+ module_spec.GetUUID().Dump (&strm);
+ result.AppendErrorWithFormat ("Unable to locate the executable or symbol file with UUID %s", strm.GetString().c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more executable image paths must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *path = args.GetArgumentAtIndex(i);
+ if (path)
+ {
+ FileSpec file_spec(path, true);
+ if (file_spec.Exists())
+ {
+ ModuleSpec module_spec (file_spec);
+ if (m_uuid_option_group.GetOptionValue ().OptionWasSet())
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue ().GetCurrentValue();
+ if (m_symbol_file.GetOptionValue().OptionWasSet())
+ module_spec.GetSymbolFileSpec() = m_symbol_file.GetOptionValue().GetCurrentValue();
+ Error error;
+ ModuleSP module_sp (target->GetSharedModule (module_spec, &error));
+ if (!module_sp)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ result.AppendError (error_cstr);
+ else
+ result.AppendErrorWithFormat ("unsupported module: %s", path);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ flush = true;
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ char resolved_path[PATH_MAX];
+ result.SetStatus (eReturnStatusFailed);
+ if (file_spec.GetPath (resolved_path, sizeof(resolved_path)))
+ {
+ if (strcmp (resolved_path, path) != 0)
+ {
+ result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", path, resolved_path);
+ break;
+ }
+ }
+ result.AppendErrorWithFormat ("invalid module path '%s'\n", path);
+ break;
+ }
+ }
+ }
+ }
+
+ if (flush)
+ {
+ ProcessSP process = target->GetProcessSP();
+ if (process)
+ process->Flush();
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+class CommandObjectTargetModulesLoad : public CommandObjectTargetModulesModuleAutoComplete
+{
+public:
+ CommandObjectTargetModulesLoad (CommandInterpreter &interpreter) :
+ CommandObjectTargetModulesModuleAutoComplete (interpreter,
+ "target modules load",
+ "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_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);
+ m_option_group.Append (&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_slide_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetModulesLoad ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ const size_t argc = args.GetArgumentCount();
+ ModuleSpec module_spec;
+ bool search_using_module_spec = false;
+ if (m_file_option.GetOptionValue().OptionWasSet())
+ {
+ search_using_module_spec = true;
+ module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+ }
+
+ if (m_uuid_option_group.GetOptionValue().OptionWasSet())
+ {
+ search_using_module_spec = true;
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue().GetCurrentValue();
+ }
+
+ if (search_using_module_spec)
+ {
+
+ ModuleList matching_modules;
+ const size_t num_matches = target->GetImages().FindModules (module_spec, matching_modules);
+
+ char path[PATH_MAX];
+ if (num_matches == 1)
+ {
+ Module *module = matching_modules.GetModulePointerAtIndex(0);
+ if (module)
+ {
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile)
+ {
+ SectionList *section_list = module->GetSectionList();
+ if (section_list)
+ {
+ bool changed = false;
+ if (argc == 0)
+ {
+ if (m_slide_option.GetOptionValue().OptionWasSet())
+ {
+ const addr_t slide = m_slide_option.GetOptionValue().GetCurrentValue();
+ module->SetLoadAddress (*target, slide, changed);
+ }
+ else
+ {
+ result.AppendError ("one or more section name + load address pair must be specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ if (m_slide_option.GetOptionValue().OptionWasSet())
+ {
+ result.AppendError ("The \"--slide <offset>\" option can't be used in conjunction with setting section load addresses.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ for (size_t i=0; i<argc; i += 2)
+ {
+ const char *sect_name = args.GetArgumentAtIndex(i);
+ const char *load_addr_cstr = args.GetArgumentAtIndex(i+1);
+ if (sect_name && load_addr_cstr)
+ {
+ ConstString const_sect_name(sect_name);
+ bool success = false;
+ addr_t load_addr = Args::StringToUInt64(load_addr_cstr, LLDB_INVALID_ADDRESS, 0, &success);
+ if (success)
+ {
+ SectionSP section_sp (section_list->FindSectionByName(const_sect_name));
+ if (section_sp)
+ {
+ if (section_sp->IsThreadSpecific())
+ {
+ result.AppendErrorWithFormat ("thread specific sections are not yet supported (section '%s')\n", sect_name);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ else
+ {
+ if (target->GetSectionLoadList().SetSectionLoadAddress (section_sp, load_addr))
+ changed = true;
+ result.AppendMessageWithFormat("section '%s' loaded at 0x%" PRIx64 "\n", sect_name, load_addr);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no section found that matches the section name '%s'\n", sect_name);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid load address string '%s'\n", load_addr_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ if (sect_name)
+ result.AppendError ("section names must be followed by a load address.\n");
+ else
+ result.AppendError ("one or more section name + load address pair must be specified.\n");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ }
+
+ if (changed)
+ {
+ target->ModulesDidLoad (matching_modules);
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ process->Flush();
+ }
+ }
+ else
+ {
+ module->GetFileSpec().GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("no sections in object file '%s'\n", path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ module->GetFileSpec().GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("no object file for module '%s'\n", path);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ FileSpec *module_spec_file = module_spec.GetFileSpecPtr();
+ if (module_spec_file)
+ {
+ module_spec_file->GetPath (path, sizeof(path));
+ result.AppendErrorWithFormat ("invalid module '%s'.\n", path);
+ }
+ else
+ result.AppendError ("no module spec");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ std::string uuid_str;
+
+ if (module_spec.GetFileSpec())
+ module_spec.GetFileSpec().GetPath (path, sizeof(path));
+ else
+ path[0] = '\0';
+
+ if (module_spec.GetUUIDPtr())
+ uuid_str = module_spec.GetUUID().GetAsString();
+ if (num_matches > 1)
+ {
+ result.AppendErrorWithFormat ("multiple modules match%s%s%s%s:\n",
+ path[0] ? " file=" : "",
+ path,
+ !uuid_str.empty() ? " uuid=" : "",
+ uuid_str.c_str());
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ if (matching_modules.GetModulePointerAtIndex(i)->GetFileSpec().GetPath (path, sizeof(path)))
+ result.AppendMessageWithFormat("%s\n", path);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no modules were found that match%s%s%s%s.\n",
+ path[0] ? " file=" : "",
+ path,
+ !uuid_str.empty() ? " uuid=" : "",
+ uuid_str.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("either the \"--file <module>\" or the \"--uuid <uuid>\" option must be specified.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_file_option;
+ OptionGroupUInt64 m_slide_option;
+};
+
+//----------------------------------------------------------------------
+// List images with associated information
+//----------------------------------------------------------------------
+class CommandObjectTargetModulesList : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_format_array(),
+ m_use_global_module_list (false),
+ m_module_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ 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;
+ if (short_option == 'g')
+ {
+ m_use_global_module_list = true;
+ }
+ else if (short_option == 'a')
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_module_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ else
+ {
+ unsigned long width = 0;
+ if (option_arg)
+ width = strtoul (option_arg, NULL, 0);
+ m_format_array.push_back(std::make_pair(short_option, width));
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_format_array.clear();
+ m_use_global_module_list = false;
+ m_module_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ typedef std::vector< std::pair<char, uint32_t> > FormatWidthCollection;
+ FormatWidthCollection m_format_array;
+ bool m_use_global_module_list;
+ lldb::addr_t m_module_addr;
+ };
+
+ CommandObjectTargetModulesList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules list",
+ "List current executable and dependent shared library images.",
+ "target modules list [<cmd-options>]"),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesList ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ const bool use_global_module_list = m_options.m_use_global_module_list;
+ // Define a local module list here to ensure it lives longer than any "locker"
+ // object which might lock its contents below (through the "module_list_ptr"
+ // variable).
+ ModuleList module_list;
+ if (target == NULL && use_global_module_list == false)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (target)
+ {
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+ }
+ // Dump all sections for all modules images
+ Stream &strm = result.GetOutputStream();
+
+ if (m_options.m_module_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (target)
+ {
+ Address module_address;
+ if (module_address.SetLoadAddress(m_options.m_module_addr, target))
+ {
+ ModuleSP module_sp (module_address.GetModule());
+ if (module_sp)
+ {
+ PrintModule (target, module_sp.get(), 0, strm);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Couldn't find module matching address: 0x%" PRIx64 ".", m_options.m_module_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Couldn't find module containing address: 0x%" PRIx64 ".", m_options.m_module_addr);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError ("Can only look up modules by address with a valid target.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ size_t num_modules = 0;
+ Mutex::Locker locker; // This locker will be locked on the mutex in module_list_ptr if it is non-NULL.
+ // Otherwise it will lock the AllocationModuleCollectionMutex when accessing
+ // the global module list directly.
+ const ModuleList *module_list_ptr = NULL;
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (use_global_module_list)
+ {
+ locker.Lock (Module::GetAllocationModuleCollectionMutex());
+ num_modules = Module::GetNumberAllocatedModules();
+ }
+ else
+ {
+ module_list_ptr = &target->GetImages();
+ }
+ }
+ else
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr = command.GetArgumentAtIndex(i);
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, use_global_module_list);
+ if (num_matches == 0)
+ {
+ if (argc == 1)
+ {
+ result.AppendErrorWithFormat ("no modules found that match '%s'", arg_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ module_list_ptr = &module_list;
+ }
+
+ if (module_list_ptr != NULL)
+ {
+ locker.Lock(module_list_ptr->GetMutex());
+ num_modules = module_list_ptr->GetSize();
+ }
+
+ if (num_modules > 0)
+ {
+ for (uint32_t image_idx = 0; image_idx<num_modules; ++image_idx)
+ {
+ ModuleSP module_sp;
+ Module *module;
+ if (module_list_ptr)
+ {
+ module_sp = module_list_ptr->GetModuleAtIndexUnlocked(image_idx);
+ module = module_sp.get();
+ }
+ else
+ {
+ module = Module::GetAllocatedModuleAtIndex(image_idx);
+ module_sp = module->shared_from_this();
+ }
+
+ const size_t indent = strm.Printf("[%3u] ", image_idx);
+ PrintModule (target, module, indent, strm);
+
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ if (argc)
+ {
+ if (use_global_module_list)
+ result.AppendError ("the global module list has no matching modules");
+ else
+ result.AppendError ("the target has no matching modules");
+ }
+ else
+ {
+ if (use_global_module_list)
+ result.AppendError ("the global module list is empty");
+ else
+ result.AppendError ("the target has no associated executable images");
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+
+ void
+ PrintModule (Target *target, Module *module, int indent, Stream &strm)
+ {
+
+ if (module == NULL)
+ {
+ strm.PutCString("Null module");
+ return;
+ }
+
+ bool dump_object_name = false;
+ if (m_options.m_format_array.empty())
+ {
+ m_options.m_format_array.push_back(std::make_pair('u', 0));
+ m_options.m_format_array.push_back(std::make_pair('h', 0));
+ m_options.m_format_array.push_back(std::make_pair('f', 0));
+ m_options.m_format_array.push_back(std::make_pair('S', 0));
+ }
+ const size_t num_entries = m_options.m_format_array.size();
+ bool print_space = false;
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ if (print_space)
+ strm.PutChar(' ');
+ print_space = true;
+ const char format_char = m_options.m_format_array[i].first;
+ uint32_t width = m_options.m_format_array[i].second;
+ switch (format_char)
+ {
+ case 'A':
+ DumpModuleArchitecture (strm, module, false, width);
+ break;
+
+ case 't':
+ DumpModuleArchitecture (strm, module, true, width);
+ break;
+
+ case 'f':
+ DumpFullpath (strm, &module->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+
+ case 'd':
+ DumpDirectory (strm, &module->GetFileSpec(), width);
+ break;
+
+ case 'b':
+ DumpBasename (strm, &module->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+
+ case 'h':
+ case 'o':
+ // Image header address
+ {
+ uint32_t addr_nibble_width = target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16;
+
+ ObjectFile *objfile = module->GetObjectFile ();
+ if (objfile)
+ {
+ Address header_addr(objfile->GetHeaderAddress());
+ if (header_addr.IsValid())
+ {
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ lldb::addr_t header_load_addr = header_addr.GetLoadAddress (target);
+ if (header_load_addr == LLDB_INVALID_ADDRESS)
+ {
+ header_addr.Dump (&strm, target, Address::DumpStyleModuleWithFileAddress, Address::DumpStyleFileAddress);
+ }
+ else
+ {
+ if (format_char == 'o')
+ {
+ // Show the offset of slide for the image
+ strm.Printf ("0x%*.*" PRIx64, addr_nibble_width, addr_nibble_width, header_load_addr - header_addr.GetFileAddress());
+ }
+ else
+ {
+ // Show the load address of the image
+ strm.Printf ("0x%*.*" PRIx64, addr_nibble_width, addr_nibble_width, header_load_addr);
+ }
+ }
+ break;
+ }
+ // The address was valid, but the image isn't loaded, output the address in an appropriate format
+ header_addr.Dump (&strm, target, Address::DumpStyleFileAddress);
+ break;
+ }
+ }
+ strm.Printf ("%*s", addr_nibble_width + 2, "");
+ }
+ break;
+ case 'r':
+ {
+ size_t ref_count = 0;
+ ModuleSP module_sp (module->shared_from_this());
+ if (module_sp)
+ {
+ // Take one away to make sure we don't count our local "module_sp"
+ ref_count = module_sp.use_count() - 1;
+ }
+ if (width)
+ strm.Printf("{%*zu}", width, ref_count);
+ else
+ strm.Printf("{%zu}", ref_count);
+ }
+ break;
+
+ case 's':
+ case 'S':
+ {
+ SymbolVendor *symbol_vendor = module->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
+ if (symbol_file)
+ {
+ if (format_char == 'S')
+ {
+ FileSpec &symfile_spec = symbol_file->GetObjectFile()->GetFileSpec();
+ // Dump symbol file only if different from module file
+ if (!symfile_spec || symfile_spec == module->GetFileSpec())
+ {
+ print_space = false;
+ break;
+ }
+ // Add a newline and indent past the index
+ strm.Printf ("\n%*s", indent, "");
+ }
+ DumpFullpath (strm, &symbol_file->GetObjectFile()->GetFileSpec(), width);
+ dump_object_name = true;
+ break;
+ }
+ }
+ strm.Printf("%.*s", width, "<NONE>");
+ }
+ break;
+
+ case 'm':
+ module->GetModificationTime().Dump(&strm, width);
+ break;
+
+ case 'p':
+ strm.Printf("%p", module);
+ break;
+
+ case 'u':
+ DumpModuleUUID(strm, module);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ if (dump_object_name)
+ {
+ const char *object_name = module->GetObjectName().GetCString();
+ if (object_name)
+ strm.Printf ("(%s)", object_name);
+ }
+ strm.EOL();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Display the image at this address."},
+ { LLDB_OPT_SET_1, false, "arch", 'A', optional_argument, NULL, 0, eArgTypeWidth, "Display the architecture when listing images."},
+ { LLDB_OPT_SET_1, false, "triple", 't', optional_argument, NULL, 0, eArgTypeWidth, "Display the triple when listing images."},
+ { LLDB_OPT_SET_1, false, "header", 'h', no_argument, NULL, 0, eArgTypeNone, "Display the image header address as a load address if debugging, a file address otherwise."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', no_argument, NULL, 0, eArgTypeNone, "Display the image header address offset from the header file address (the slide amount)."},
+ { LLDB_OPT_SET_1, false, "uuid", 'u', no_argument, NULL, 0, eArgTypeNone, "Display the UUID when listing images."},
+ { LLDB_OPT_SET_1, false, "fullpath", 'f', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image object file."},
+ { LLDB_OPT_SET_1, false, "directory", 'd', optional_argument, NULL, 0, eArgTypeWidth, "Display the directory with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "basename", 'b', optional_argument, NULL, 0, eArgTypeWidth, "Display the basename with optional width for the image object file."},
+ { LLDB_OPT_SET_1, false, "symfile", 's', optional_argument, NULL, 0, eArgTypeWidth, "Display the fullpath to the image symbol file with optional width."},
+ { LLDB_OPT_SET_1, false, "symfile-unique", 'S', optional_argument, NULL, 0, eArgTypeWidth, "Display the symbol file with optional width only if it is different from the executable object file."},
+ { LLDB_OPT_SET_1, false, "mod-time", 'm', optional_argument, NULL, 0, eArgTypeWidth, "Display the modification time with optional width of the module."},
+ { LLDB_OPT_SET_1, false, "ref-count", 'r', optional_argument, NULL, 0, eArgTypeWidth, "Display the reference count if the module is still in the shared module cache."},
+ { LLDB_OPT_SET_1, false, "pointer", 'p', optional_argument, NULL, 0, eArgTypeNone, "Display the module pointer."},
+ { LLDB_OPT_SET_1, false, "global", 'g', no_argument, NULL, 0, eArgTypeNone, "Display the modules from the global module list, not just the current target."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetModulesShowUnwind
+
+//----------------------------------------------------------------------
+// Lookup unwind information in images
+//----------------------------------------------------------------------
+
+class CommandObjectTargetModulesShowUnwind : public CommandObjectParsed
+{
+public:
+
+ enum
+ {
+ eLookupTypeInvalid = -1,
+ eLookupTypeAddress = 0,
+ eLookupTypeSymbol,
+ eLookupTypeFunction,
+ eLookupTypeFunctionOrSymbol,
+ kNumLookupTypes
+ };
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_type(eLookupTypeInvalid),
+ m_str(),
+ m_addr(LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_type = eLookupTypeAddress;
+ m_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ if (m_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("invalid address string '%s'", option_arg);
+ break;
+ }
+
+ case 'n':
+ {
+ m_str = option_arg;
+ m_type = eLookupTypeFunctionOrSymbol;
+ break;
+ }
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_type = eLookupTypeInvalid;
+ m_str.clear();
+ m_addr = LLDB_INVALID_ADDRESS;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ int m_type; // Should be a eLookupTypeXXX enum after parsing options
+ std::string m_str; // Holds name lookup
+ lldb::addr_t m_addr; // Holds the address to lookup
+ };
+
+ CommandObjectTargetModulesShowUnwind (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules show-unwind",
+ "Show synthesized unwind instructions for a function.",
+ NULL,
+ eFlagRequiresTarget |
+ eFlagRequiresProcess |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandObjectTargetModulesShowUnwind ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ ABI *abi = NULL;
+ if (process)
+ abi = process->GetABI().get();
+
+ if (process == NULL)
+ {
+ result.AppendError ("You must have a process running to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadList threads(process->GetThreadList());
+ if (threads.GetSize() == 0)
+ {
+ result.AppendError ("The process must be paused to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadSP thread(threads.GetThreadAtIndex(0));
+ if (thread.get() == NULL)
+ {
+ result.AppendError ("The process must be paused to use this command.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ SymbolContextList sc_list;
+
+ if (m_options.m_type == eLookupTypeFunctionOrSymbol)
+ {
+ ConstString function_name (m_options.m_str.c_str());
+ target->GetImages().FindFunctions (function_name, eFunctionNameTypeAuto, true, false, true, sc_list);
+ }
+ else if (m_options.m_type == eLookupTypeAddress && target)
+ {
+ Address addr;
+ if (target->GetSectionLoadList().ResolveLoadAddress (m_options.m_addr, addr))
+ {
+ SymbolContext sc;
+ ModuleSP module_sp (addr.GetModule());
+ module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ sc_list.Append(sc);
+ }
+ }
+ }
+
+ size_t num_matches = sc_list.GetSize();
+ for (uint32_t idx = 0; idx < num_matches; idx++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(idx, sc);
+ if (sc.symbol == NULL && sc.function == NULL)
+ continue;
+ if (sc.module_sp.get() == NULL || sc.module_sp->GetObjectFile() == NULL)
+ continue;
+ AddressRange range;
+ if (!sc.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, range))
+ continue;
+ if (!range.GetBaseAddress().IsValid())
+ continue;
+ ConstString funcname(sc.GetFunctionName());
+ if (funcname.IsEmpty())
+ continue;
+ addr_t start_addr = range.GetBaseAddress().GetLoadAddress(target);
+ if (abi)
+ start_addr = abi->FixCodeAddress(start_addr);
+
+ FuncUnwindersSP func_unwinders_sp (sc.module_sp->GetObjectFile()->GetUnwindTable().GetUncachedFuncUnwindersContainingAddress(start_addr, sc));
+ 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");
+ }
+
+ UnwindPlanSP non_callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtNonCallSite(*thread.get());
+ 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");
+ }
+
+ UnwindPlanSP callsite_unwind_plan = func_unwinders_sp->GetUnwindPlanAtCallSite(-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");
+ }
+
+ UnwindPlanSP arch_default_unwind_plan = func_unwinders_sp->GetUnwindPlanArchitectureDefault(*thread.get());
+ if (arch_default_unwind_plan.get())
+ {
+ 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");
+ }
+
+ UnwindPlanSP fast_unwind_plan = func_unwinders_sp->GetUnwindPlanFastUnwind(*thread.get());
+ if (fast_unwind_plan.get())
+ {
+ result.GetOutputStream().Printf("Fast UnwindPlan for %s`%s (start addr 0x%" PRIx64 "):\n", sc.module_sp->GetPlatformFileSpec().GetFilename().AsCString(), funcname.AsCString(), start_addr);
+ fast_unwind_plan->Dump(result.GetOutputStream(), thread.get(), LLDB_INVALID_ADDRESS);
+ result.GetOutputStream().Printf ("\n");
+ }
+
+
+ result.GetOutputStream().Printf ("\n");
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesShowUnwind::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "name", 'n', required_argument, NULL, 0, eArgTypeFunctionName, "Show unwind instructions for a function or symbol name."},
+ { LLDB_OPT_SET_2, false, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Show unwind instructions for a function or symbol containing an address"},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//----------------------------------------------------------------------
+// Lookup information in images
+//----------------------------------------------------------------------
+class CommandObjectTargetModulesLookup : public CommandObjectParsed
+{
+public:
+
+ enum
+ {
+ eLookupTypeInvalid = -1,
+ eLookupTypeAddress = 0,
+ eLookupTypeSymbol,
+ eLookupTypeFileLine, // Line is optional
+ eLookupTypeFunction,
+ eLookupTypeFunctionOrSymbol,
+ eLookupTypeType,
+ kNumLookupTypes
+ };
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter)
+ {
+ OptionParsingStarting();
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ {
+ m_type = eLookupTypeAddress;
+ ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
+ m_addr = Args::StringToAddress(&exe_ctx, option_arg, LLDB_INVALID_ADDRESS, &error);
+ }
+ break;
+
+ case 'o':
+ m_offset = Args::StringToUInt64(option_arg, LLDB_INVALID_ADDRESS);
+ if (m_offset == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat ("invalid offset string '%s'", option_arg);
+ break;
+
+ case 's':
+ m_str = option_arg;
+ m_type = eLookupTypeSymbol;
+ break;
+
+ case 'f':
+ m_file.SetFile (option_arg, false);
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'i':
+ m_include_inlines = false;
+ break;
+
+ case 'l':
+ m_line_number = Args::StringToUInt32(option_arg, UINT32_MAX);
+ if (m_line_number == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid line number string '%s'", option_arg);
+ else if (m_line_number == 0)
+ error.SetErrorString ("zero is an invalid line number");
+ m_type = eLookupTypeFileLine;
+ break;
+
+ case 'F':
+ m_str = option_arg;
+ m_type = eLookupTypeFunction;
+ break;
+
+ case 'n':
+ m_str = option_arg;
+ m_type = eLookupTypeFunctionOrSymbol;
+ break;
+
+ case 't':
+ m_str = option_arg;
+ m_type = eLookupTypeType;
+ break;
+
+ case 'v':
+ m_verbose = 1;
+ break;
+
+ case 'A':
+ m_print_all = true;
+ break;
+
+ case 'r':
+ m_use_regex = true;
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_type = eLookupTypeInvalid;
+ m_str.clear();
+ m_file.Clear();
+ m_addr = LLDB_INVALID_ADDRESS;
+ m_offset = 0;
+ m_line_number = 0;
+ m_use_regex = false;
+ m_include_inlines = true;
+ m_verbose = false;
+ m_print_all = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+ int m_type; // Should be a eLookupTypeXXX enum after parsing options
+ std::string m_str; // Holds name lookup
+ FileSpec m_file; // Files for file lookups
+ lldb::addr_t m_addr; // Holds the address to lookup
+ lldb::addr_t m_offset; // Subtract this offset from m_addr before doing lookups.
+ uint32_t m_line_number; // Line number for file+line lookups
+ bool m_use_regex; // Name lookups in m_str are regular expressions.
+ bool m_include_inlines;// Check for inline entries when looking up by file/line.
+ bool m_verbose; // Enable verbose lookup info
+ bool m_print_all; // Print all matches, even in cases where there's a best match.
+
+ };
+
+ CommandObjectTargetModulesLookup (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target modules lookup",
+ "Look up information within executable and dependent shared library images.",
+ NULL,
+ eFlagRequiresTarget),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData file_arg;
+
+ // Define the first (and only) variant of this arg.
+ file_arg.arg_type = eArgTypeFilename;
+ file_arg.arg_repetition = eArgRepeatStar;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (file_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectTargetModulesLookup ()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ bool
+ LookupHere (CommandInterpreter &interpreter, CommandReturnObject &result, bool &syntax_error)
+ {
+ switch (m_options.m_type)
+ {
+ case eLookupTypeAddress:
+ case eLookupTypeFileLine:
+ case eLookupTypeFunction:
+ case eLookupTypeFunctionOrSymbol:
+ case eLookupTypeSymbol:
+ default:
+ return false;
+ case eLookupTypeType:
+ break;
+ }
+
+ StackFrameSP frame = m_exe_ctx.GetFrameSP();
+
+ if (!frame)
+ return false;
+
+ const SymbolContext &sym_ctx(frame->GetSymbolContext(eSymbolContextModule));
+
+ if (!sym_ctx.module_sp)
+ return false;
+
+ switch (m_options.m_type)
+ {
+ default:
+ return false;
+ case eLookupTypeType:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupTypeHere (m_interpreter,
+ result.GetOutputStream(),
+ sym_ctx,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ bool
+ LookupInModule (CommandInterpreter &interpreter, Module *module, CommandReturnObject &result, bool &syntax_error)
+ {
+ switch (m_options.m_type)
+ {
+ case eLookupTypeAddress:
+ if (m_options.m_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (LookupAddressInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ eSymbolContextEverything,
+ m_options.m_addr,
+ m_options.m_offset,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeSymbol:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupSymbolInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFileLine:
+ if (m_options.m_file)
+ {
+
+ if (LookupFileAndLineInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_file,
+ m_options.m_line_number,
+ m_options.m_include_inlines,
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ case eLookupTypeFunctionOrSymbol:
+ case eLookupTypeFunction:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupFunctionInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex,
+ m_options.m_include_inlines,
+ m_options.m_type == eLookupTypeFunctionOrSymbol, // include symbols
+ m_options.m_verbose))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+
+ case eLookupTypeType:
+ if (!m_options.m_str.empty())
+ {
+ if (LookupTypeInModule (m_interpreter,
+ result.GetOutputStream(),
+ module,
+ m_options.m_str.c_str(),
+ m_options.m_use_regex))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ break;
+
+ default:
+ m_options.GenerateOptionUsage (result.GetErrorStream(), this);
+ syntax_error = true;
+ break;
+ }
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ bool syntax_error = false;
+ uint32_t i;
+ uint32_t num_successful_lookups = 0;
+ uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+ result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+ result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+ // Dump all sections for all modules images
+
+ if (command.GetArgumentCount() == 0)
+ {
+ ModuleSP current_module;
+
+ // Where it is possible to look in the current symbol context
+ // first, try that. If this search was successful and --all
+ // was not passed, don't print anything else.
+ if (LookupHere (m_interpreter, result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ if (!m_options.m_print_all)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ }
+
+ // Dump all sections for all other modules
+
+ const ModuleList &target_modules = target->GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ const size_t num_modules = target_modules.GetSize();
+ if (num_modules > 0)
+ {
+ for (i = 0; i<num_modules && syntax_error == false; ++i)
+ {
+ Module *module_pointer = target_modules.GetModulePointerAtIndexUnlocked(i);
+
+ if (module_pointer != current_module.get() &&
+ LookupInModule (m_interpreter, target_modules.GetModulePointerAtIndexUnlocked(i), result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ }
+ }
+ }
+ else
+ {
+ result.AppendError ("the target has no associated executable images");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // Dump specified images (by basename or fullpath)
+ const char *arg_cstr;
+ for (i = 0; (arg_cstr = command.GetArgumentAtIndex(i)) != NULL && syntax_error == false; ++i)
+ {
+ ModuleList module_list;
+ const size_t num_matches = FindModulesByName (target, arg_cstr, module_list, false);
+ if (num_matches > 0)
+ {
+ for (size_t j=0; j<num_matches; ++j)
+ {
+ Module *module = module_list.GetModulePointerAtIndex(j);
+ if (module)
+ {
+ if (LookupInModule (m_interpreter, module, result, syntax_error))
+ {
+ result.GetOutputStream().EOL();
+ num_successful_lookups++;
+ }
+ }
+ }
+ }
+ else
+ result.AppendWarningWithFormat("Unable to find an image that matches '%s'.\n", arg_cstr);
+ }
+ }
+
+ if (num_successful_lookups > 0)
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ else
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetModulesLookup::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, true, "address", 'a', required_argument, NULL, 0, eArgTypeAddressOrExpression, "Lookup an address in one or more target modules."},
+ { LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "When looking up an address subtract <offset> from any addresses before doing the lookup."},
+ { LLDB_OPT_SET_2| LLDB_OPT_SET_4 | LLDB_OPT_SET_5
+ /* FIXME: re-enable this for types when the LookupTypeInModule actually uses the regex option: | LLDB_OPT_SET_6 */ ,
+ false, "regex", 'r', no_argument, NULL, 0, eArgTypeNone, "The <name> argument for name lookups are regular expressions."},
+ { LLDB_OPT_SET_2, true, "symbol", 's', required_argument, NULL, 0, eArgTypeSymbol, "Lookup a symbol by name in the symbol tables in one or more target modules."},
+ { LLDB_OPT_SET_3, true, "file", 'f', required_argument, NULL, 0, eArgTypeFilename, "Lookup a file by fullpath or basename in one or more target modules."},
+ { LLDB_OPT_SET_3, false, "line", 'l', required_argument, NULL, 0, eArgTypeLineNum, "Lookup a line number in a file (must be used in conjunction with --file)."},
+ { LLDB_OPT_SET_FROM_TO(3,5),
+ false, "no-inlines", 'i', no_argument, NULL, 0, eArgTypeNone, "Ignore inline entries (must be used in conjunction with --file or --function)."},
+ { LLDB_OPT_SET_4, true, "function", 'F', required_argument, NULL, 0, eArgTypeFunctionName, "Lookup a function by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_5, true, "name", 'n', required_argument, NULL, 0, eArgTypeFunctionOrSymbol, "Lookup a function or symbol by name in one or more target modules."},
+ { LLDB_OPT_SET_6, true, "type", 't', required_argument, NULL, 0, eArgTypeName, "Lookup a type by name in the debug symbols in one or more target modules."},
+ { LLDB_OPT_SET_ALL, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone, "Enable verbose lookup information."},
+ { LLDB_OPT_SET_ALL, false, "all", 'A', no_argument, NULL, 0, eArgTypeNone, "Print all matches, not just the best match, if a best match is available."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+#pragma mark CommandObjectMultiwordImageSearchPaths
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordImageSearchPaths
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetModulesImageSearchPaths : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectTargetModulesImageSearchPaths (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules search-paths",
+ "A set of commands for operating on debugger target image search paths.",
+ "target modules search-paths <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetModulesSearchPathsAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTargetModulesSearchPathsClear (interpreter)));
+ LoadSubCommand ("insert", CommandObjectSP (new CommandObjectTargetModulesSearchPathsInsert (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetModulesSearchPathsList (interpreter)));
+ LoadSubCommand ("query", CommandObjectSP (new CommandObjectTargetModulesSearchPathsQuery (interpreter)));
+ }
+
+ ~CommandObjectTargetModulesImageSearchPaths()
+ {
+ }
+};
+
+
+
+#pragma mark CommandObjectTargetModules
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetModules
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetModules : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetModules(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target modules",
+ "A set of commands for accessing information for one or more target modules.",
+ "target modules <sub-command> ...")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetModulesAdd (interpreter)));
+ LoadSubCommand ("load", CommandObjectSP (new CommandObjectTargetModulesLoad (interpreter)));
+ LoadSubCommand ("dump", CommandObjectSP (new CommandObjectTargetModulesDump (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetModulesList (interpreter)));
+ LoadSubCommand ("lookup", CommandObjectSP (new CommandObjectTargetModulesLookup (interpreter)));
+ LoadSubCommand ("search-paths", CommandObjectSP (new CommandObjectTargetModulesImageSearchPaths (interpreter)));
+ LoadSubCommand ("show-unwind", CommandObjectSP (new CommandObjectTargetModulesShowUnwind (interpreter)));
+
+ }
+ virtual
+ ~CommandObjectTargetModules()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectTargetModules only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectTargetModules);
+};
+
+
+
+class CommandObjectTargetSymbolsAdd : public CommandObjectParsed
+{
+public:
+ CommandObjectTargetSymbolsAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target symbols add",
+ "Add a debug symbol file to one of the target's current modules by specifying a path to a debug symbols file, or using the options to specify a module to download symbols for.",
+ "target symbols add [<symfile>]", eFlagRequiresTarget),
+ m_option_group (interpreter),
+ m_file_option (LLDB_OPT_SET_1, false, "shlib", 's', CommandCompletions::eModuleCompletion, eArgTypeShlibName, "Fullpath or basename for module to find debug symbols for."),
+ m_current_frame_option (LLDB_OPT_SET_2, false, "frame", 'F', "Locate the debug symbols the currently selected frame.", false, true)
+
+ {
+ m_option_group.Append (&m_uuid_option_group, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_file_option, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Append (&m_current_frame_option, LLDB_OPT_SET_2, LLDB_OPT_SET_2);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectTargetSymbolsAdd ()
+ {
+ }
+
+ virtual int
+ HandleArgumentCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ OptionElementVector &opt_element_vector,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+ {
+ std::string completion_str (input.GetArgumentAtIndex(cursor_index));
+ completion_str.erase (cursor_char_position);
+
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ CommandCompletions::eDiskFileCompletion,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+
+protected:
+
+ bool
+ AddModuleSymbols (Target *target,
+ ModuleSpec &module_spec,
+ bool &flush,
+ CommandReturnObject &result)
+ {
+ const FileSpec &symbol_fspec = module_spec.GetSymbolFileSpec();
+ if (symbol_fspec)
+ {
+ char symfile_path[PATH_MAX];
+ symbol_fspec.GetPath (symfile_path, sizeof(symfile_path));
+
+ if (!module_spec.GetUUID().IsValid())
+ {
+ if (!module_spec.GetFileSpec() && !module_spec.GetPlatformFileSpec())
+ module_spec.GetFileSpec().GetFilename() = symbol_fspec.GetFilename();
+ }
+ // We now have a module that represents a symbol file
+ // that can be used for a module that might exist in the
+ // current target, so we need to find that module in the
+ // target
+ ModuleList matching_module_list;
+
+ size_t num_matches = 0;
+ // First extract all module specs from the symbol file
+ lldb_private::ModuleSpecList symfile_module_specs;
+ if (ObjectFile::GetModuleSpecifications(module_spec.GetSymbolFileSpec(), 0, 0, symfile_module_specs))
+ {
+ // Now extract the module spec that matches the target architecture
+ ModuleSpec target_arch_module_spec;
+ ModuleSpec symfile_module_spec;
+ target_arch_module_spec.GetArchitecture() = target->GetArchitecture();
+ if (symfile_module_specs.FindMatchingModuleSpec(target_arch_module_spec, symfile_module_spec))
+ {
+ // See if it has a UUID?
+ if (symfile_module_spec.GetUUID().IsValid())
+ {
+ // It has a UUID, look for this UUID in the target modules
+ ModuleSpec symfile_uuid_module_spec;
+ symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID();
+ num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
+ }
+ }
+
+ if (num_matches == 0)
+ {
+ // No matches yet, iterate through the module specs to find a UUID value that
+ // we can match up to an image in our target
+ const size_t num_symfile_module_specs = symfile_module_specs.GetSize();
+ for (size_t i=0; i<num_symfile_module_specs && num_matches == 0; ++i)
+ {
+ if (symfile_module_specs.GetModuleSpecAtIndex(i, symfile_module_spec))
+ {
+ if (symfile_module_spec.GetUUID().IsValid())
+ {
+ // It has a UUID, look for this UUID in the target modules
+ ModuleSpec symfile_uuid_module_spec;
+ symfile_uuid_module_spec.GetUUID() = symfile_module_spec.GetUUID();
+ num_matches = target->GetImages().FindModules (symfile_uuid_module_spec, matching_module_list);
+ }
+ }
+ }
+ }
+ }
+
+ // Just try to match up the file by basename if we have no matches at this point
+ if (num_matches == 0)
+ num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
+
+ while (num_matches == 0)
+ {
+ ConstString filename_no_extension(module_spec.GetFileSpec().GetFileNameStrippingExtension());
+ // Empty string returned, lets bail
+ if (!filename_no_extension)
+ break;
+
+ // Check if there was no extension to strip and the basename is the same
+ if (filename_no_extension == module_spec.GetFileSpec().GetFilename())
+ break;
+
+ // Replace basename with one less extension
+ module_spec.GetFileSpec().GetFilename() = filename_no_extension;
+
+ num_matches = target->GetImages().FindModules (module_spec, matching_module_list);
+
+ }
+
+ if (num_matches > 1)
+ {
+ result.AppendErrorWithFormat ("multiple modules match symbol file '%s', use the --uuid option to resolve the ambiguity.\n", symfile_path);
+ }
+ else if (num_matches == 1)
+ {
+ ModuleSP module_sp (matching_module_list.GetModuleAtIndex(0));
+
+ // The module has not yet created its symbol vendor, we can just
+ // give the existing target module the symfile path to use for
+ // when it decides to create it!
+ module_sp->SetSymbolFileFileSpec (symbol_fspec);
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor(true, &result.GetErrorStream());
+ if (symbol_vendor)
+ {
+ SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
+
+ if (symbol_file)
+ {
+ ObjectFile *object_file = symbol_file->GetObjectFile();
+
+ if (object_file && object_file->GetFileSpec() == symbol_fspec)
+ {
+ // Provide feedback that the symfile has been successfully added.
+ const FileSpec &module_fs = module_sp->GetFileSpec();
+ result.AppendMessageWithFormat("symbol file '%s' has been added to '%s'\n",
+ symfile_path,
+ module_fs.GetPath().c_str());
+
+ // Let clients know something changed in the module
+ // if it is currently loaded
+ ModuleList module_list;
+ module_list.Append (module_sp);
+ target->SymbolsDidLoad (module_list);
+
+ // Make sure we load any scripting resources that may be embedded
+ // in the debug info files in case the platform supports that.
+ Error error;
+ StreamString feedback_stream;
+ module_sp->LoadScriptingResourceInTarget (target, error,&feedback_stream);
+ if (error.Fail() && error.AsCString())
+ result.AppendWarningWithFormat("unable to load scripting data for module %s - error reported was %s",
+ module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ error.AsCString());
+ else if (feedback_stream.GetSize())
+ result.AppendWarningWithFormat("%s",feedback_stream.GetData());
+
+ flush = true;
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ }
+ // Clear the symbol file spec if anything went wrong
+ module_sp->SetSymbolFileFileSpec (FileSpec());
+ }
+
+ if (module_spec.GetUUID().IsValid())
+ {
+ StreamString ss_symfile_uuid;
+ module_spec.GetUUID().Dump(&ss_symfile_uuid);
+ result.AppendErrorWithFormat ("symbol file '%s' (%s) does not match any existing module%s\n",
+ symfile_path,
+ ss_symfile_uuid.GetData(),
+ (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ ? "\n please specify the full path to the symbol file"
+ : "");
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("symbol file '%s' does not match any existing module%s\n",
+ symfile_path,
+ (symbol_fspec.GetFileType() != FileSpec::eFileTypeRegular)
+ ? "\n please specify the full path to the symbol file"
+ : "");
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more executable image paths must be specified");
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ result.SetStatus (eReturnStatusFailed);
+ bool flush = false;
+ ModuleSpec module_spec;
+ const bool uuid_option_set = m_uuid_option_group.GetOptionValue().OptionWasSet();
+ const bool file_option_set = m_file_option.GetOptionValue().OptionWasSet();
+ const bool frame_option_set = m_current_frame_option.GetOptionValue().OptionWasSet();
+
+ const size_t argc = args.GetArgumentCount();
+ if (argc == 0)
+ {
+ if (uuid_option_set || file_option_set || frame_option_set)
+ {
+ bool success = false;
+ bool error_set = false;
+ if (frame_option_set)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ const StateType process_state = process->GetState();
+ if (StateIsStoppedState (process_state, true))
+ {
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ ModuleSP frame_module_sp (frame->GetSymbolContext(eSymbolContextModule).module_sp);
+ if (frame_module_sp)
+ {
+ if (frame_module_sp->GetPlatformFileSpec().Exists())
+ {
+ module_spec.GetArchitecture() = frame_module_sp->GetArchitecture();
+ module_spec.GetFileSpec() = frame_module_sp->GetPlatformFileSpec();
+ }
+ module_spec.GetUUID() = frame_module_sp->GetUUID();
+ success = module_spec.GetUUID().IsValid() || module_spec.GetFileSpec();
+ }
+ else
+ {
+ result.AppendError ("frame has no module");
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendError ("invalid current frame");
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("process is not stopped: %s", StateAsCString(process_state));
+ error_set = true;
+ }
+ }
+ else
+ {
+ result.AppendError ("a process must exist in order to use the --frame option");
+ error_set = true;
+ }
+ }
+ else
+ {
+ if (uuid_option_set)
+ {
+ module_spec.GetUUID() = m_uuid_option_group.GetOptionValue().GetCurrentValue();
+ success |= module_spec.GetUUID().IsValid();
+ }
+ else if (file_option_set)
+ {
+ module_spec.GetFileSpec() = m_file_option.GetOptionValue().GetCurrentValue();
+ ModuleSP module_sp (target->GetImages().FindFirstModule(module_spec));
+ if (module_sp)
+ {
+ module_spec.GetFileSpec() = module_sp->GetFileSpec();
+ module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
+ module_spec.GetUUID() = module_sp->GetUUID();
+ module_spec.GetArchitecture() = module_sp->GetArchitecture();
+ }
+ else
+ {
+ module_spec.GetArchitecture() = target->GetArchitecture();
+ }
+ success |= module_spec.GetFileSpec().Exists();
+ }
+ }
+
+ if (success)
+ {
+ if (Symbols::DownloadObjectAndSymbolFile (module_spec))
+ {
+ if (module_spec.GetSymbolFileSpec())
+ success = AddModuleSymbols (target, module_spec, flush, result);
+ }
+ }
+
+ if (!success && !error_set)
+ {
+ StreamString error_strm;
+ if (uuid_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for UUID ");
+ module_spec.GetUUID().Dump (&error_strm);
+ }
+ else if (file_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for the executable file ");
+ error_strm << module_spec.GetFileSpec();
+ }
+ else if (frame_option_set)
+ {
+ error_strm.PutCString("unable to find debug symbols for the current frame");
+ }
+ result.AppendError (error_strm.GetData());
+ }
+ }
+ else
+ {
+ result.AppendError ("one or more symbol file paths must be specified, or options must be specified");
+ }
+ }
+ else
+ {
+ if (uuid_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --uuid option without arguments");
+ }
+ else if (file_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --file option without arguments");
+ }
+ else if (frame_option_set)
+ {
+ result.AppendError ("specify either one or more paths to symbol files or use the --frame option without arguments");
+ }
+ else
+ {
+ PlatformSP platform_sp (target->GetPlatform());
+
+ for (size_t i=0; i<argc; ++i)
+ {
+ const char *symfile_path = args.GetArgumentAtIndex(i);
+ if (symfile_path)
+ {
+ module_spec.GetSymbolFileSpec().SetFile(symfile_path, true);
+ if (platform_sp)
+ {
+ FileSpec symfile_spec;
+ if (platform_sp->ResolveSymbolFile(*target, module_spec, symfile_spec).Success())
+ module_spec.GetSymbolFileSpec() = symfile_spec;
+ }
+
+ ArchSpec arch;
+ bool symfile_exists = module_spec.GetSymbolFileSpec().Exists();
+
+ if (symfile_exists)
+ {
+ if (!AddModuleSymbols (target, module_spec, flush, result))
+ break;
+ }
+ else
+ {
+ char resolved_symfile_path[PATH_MAX];
+ if (module_spec.GetSymbolFileSpec().GetPath (resolved_symfile_path, sizeof(resolved_symfile_path)))
+ {
+ if (strcmp (resolved_symfile_path, symfile_path) != 0)
+ {
+ result.AppendErrorWithFormat ("invalid module path '%s' with resolved path '%s'\n", symfile_path, resolved_symfile_path);
+ break;
+ }
+ }
+ result.AppendErrorWithFormat ("invalid module path '%s'\n", symfile_path);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (flush)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process)
+ process->Flush();
+ }
+ return result.Succeeded();
+ }
+
+ OptionGroupOptions m_option_group;
+ OptionGroupUUID m_uuid_option_group;
+ OptionGroupFile m_file_option;
+ OptionGroupBoolean m_current_frame_option;
+
+
+};
+
+
+#pragma mark CommandObjectTargetSymbols
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetSymbols
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetSymbols : public CommandObjectMultiword
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ CommandObjectTargetSymbols(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target symbols",
+ "A set of commands for adding and managing debug symbol files.",
+ "target symbols <sub-command> ...")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetSymbolsAdd (interpreter)));
+
+ }
+ virtual
+ ~CommandObjectTargetSymbols()
+ {
+ }
+
+private:
+ //------------------------------------------------------------------
+ // For CommandObjectTargetModules only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (CommandObjectTargetSymbols);
+};
+
+
+#pragma mark CommandObjectTargetStopHookAdd
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookAdd : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_line_start(0),
+ m_line_end (UINT_MAX),
+ m_func_name_type_mask (eFunctionNameTypeAuto),
+ m_sym_ctx_specified (false),
+ m_thread_specified (false),
+ m_use_one_liner (false),
+ m_one_liner()
+ {
+ }
+
+ ~CommandOptions () {}
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'c':
+ m_class_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'e':
+ m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat ("invalid end line number: \"%s\"", option_arg);
+ break;
+ }
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'l':
+ m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ {
+ error.SetErrorStringWithFormat ("invalid start line number: \"%s\"", option_arg);
+ break;
+ }
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'i':
+ m_no_inlines = true;
+ break;
+
+ case 'n':
+ m_function_name = option_arg;
+ m_func_name_type_mask |= eFunctionNameTypeAuto;
+ m_sym_ctx_specified = true;
+ break;
+
+ case 'f':
+ m_file_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+ case 's':
+ m_module_name = option_arg;
+ m_sym_ctx_specified = true;
+ break;
+ case 't' :
+ {
+ m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0);
+ if (m_thread_id == LLDB_INVALID_THREAD_ID)
+ error.SetErrorStringWithFormat ("invalid thread id string '%s'", option_arg);
+ m_thread_specified = true;
+ }
+ break;
+ case 'T':
+ m_thread_name = option_arg;
+ m_thread_specified = true;
+ break;
+ case 'q':
+ m_queue_name = option_arg;
+ m_thread_specified = true;
+ break;
+ case 'x':
+ {
+ m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_thread_id == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid thread index string '%s'", option_arg);
+ m_thread_specified = true;
+ }
+ break;
+ case 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option %c.", short_option);
+ break;
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_class_name.clear();
+ m_function_name.clear();
+ m_line_start = 0;
+ m_line_end = UINT_MAX;
+ m_file_name.clear();
+ m_module_name.clear();
+ m_func_name_type_mask = eFunctionNameTypeAuto;
+ m_thread_id = LLDB_INVALID_THREAD_ID;
+ m_thread_index = UINT32_MAX;
+ m_thread_name.clear();
+ m_queue_name.clear();
+
+ m_no_inlines = false;
+ m_sym_ctx_specified = false;
+ m_thread_specified = false;
+
+ m_use_one_liner = false;
+ m_one_liner.clear();
+ }
+
+
+ static OptionDefinition g_option_table[];
+
+ std::string m_class_name;
+ std::string m_function_name;
+ uint32_t m_line_start;
+ uint32_t m_line_end;
+ std::string m_file_name;
+ std::string m_module_name;
+ uint32_t m_func_name_type_mask; // A pick from lldb::FunctionNameType.
+ lldb::tid_t m_thread_id;
+ uint32_t m_thread_index;
+ std::string m_thread_name;
+ std::string m_queue_name;
+ bool m_sym_ctx_specified;
+ bool m_no_inlines;
+ bool m_thread_specified;
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ };
+
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandObjectTargetStopHookAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook add ",
+ "Add a hook to be executed when the target stops.",
+ "target stop-hook add"),
+ m_options (interpreter)
+ {
+ }
+
+ ~CommandObjectTargetStopHookAdd ()
+ {
+ }
+
+ static size_t
+ ReadCommandsCallbackFunction (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ Target::StopHook *new_stop_hook = ((Target::StopHook *) baton);
+ static bool got_interrupted;
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", "Enter your stop hook command(s). Type 'DONE' to end.");
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ got_interrupted = false;
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ got_interrupted = false;
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && baton)
+ {
+ StringList *commands = new_stop_hook->GetCommandPointer();
+ if (commands)
+ {
+ commands->AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the stop hook.
+ new_stop_hook->GetTarget()->RemoveStopHookByID(new_stop_hook->GetID());
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Stop hook cancelled.\n");
+ out_stream->Flush();
+ }
+
+ reader.SetIsDone (true);
+ }
+ got_interrupted = true;
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ if (!got_interrupted && !batch_mode)
+ {
+ out_stream->Printf ("Stop hook #%" PRIu64 " added.\n", new_stop_hook->GetID());
+ out_stream->Flush();
+ }
+ break;
+ }
+
+ return bytes_len;
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ Target::StopHookSP new_hook_sp;
+ target->AddStopHook (new_hook_sp);
+
+ // First step, make the specifier.
+ std::unique_ptr<SymbolContextSpecifier> specifier_ap;
+ if (m_options.m_sym_ctx_specified)
+ {
+ specifier_ap.reset(new SymbolContextSpecifier(m_interpreter.GetDebugger().GetSelectedTarget()));
+
+ if (!m_options.m_module_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_module_name.c_str(), SymbolContextSpecifier::eModuleSpecified);
+ }
+
+ if (!m_options.m_class_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_class_name.c_str(), SymbolContextSpecifier::eClassOrNamespaceSpecified);
+ }
+
+ if (!m_options.m_file_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_file_name.c_str(), SymbolContextSpecifier::eFileSpecified);
+ }
+
+ if (m_options.m_line_start != 0)
+ {
+ specifier_ap->AddLineSpecification (m_options.m_line_start, SymbolContextSpecifier::eLineStartSpecified);
+ }
+
+ if (m_options.m_line_end != UINT_MAX)
+ {
+ specifier_ap->AddLineSpecification (m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified);
+ }
+
+ if (!m_options.m_function_name.empty())
+ {
+ specifier_ap->AddSpecification (m_options.m_function_name.c_str(), SymbolContextSpecifier::eFunctionSpecified);
+ }
+ }
+
+ if (specifier_ap.get())
+ new_hook_sp->SetSpecifier (specifier_ap.release());
+
+ // Next see if any of the thread options have been entered:
+
+ if (m_options.m_thread_specified)
+ {
+ ThreadSpec *thread_spec = new ThreadSpec();
+
+ if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID)
+ {
+ thread_spec->SetTID (m_options.m_thread_id);
+ }
+
+ if (m_options.m_thread_index != UINT32_MAX)
+ thread_spec->SetIndex (m_options.m_thread_index);
+
+ if (!m_options.m_thread_name.empty())
+ thread_spec->SetName (m_options.m_thread_name.c_str());
+
+ if (!m_options.m_queue_name.empty())
+ thread_spec->SetQueueName (m_options.m_queue_name.c_str());
+
+ new_hook_sp->SetThreadSpecifier (thread_spec);
+
+ }
+ if (m_options.m_use_one_liner)
+ {
+ // Use one-liner.
+ new_hook_sp->GetCommandPointer()->AppendString (m_options.m_one_liner.c_str());
+ result.AppendMessageWithFormat("Stop hook #%" PRIu64 " added.\n", new_hook_sp->GetID());
+ }
+ else
+ {
+ // Otherwise gather up the command list, we'll push an input reader and suck the data from that directly into
+ // the new stop hook's command string.
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ if (!reader_sp)
+ {
+ result.AppendError("out of memory\n");
+ result.SetStatus (eReturnStatusFailed);
+ target->RemoveStopHookByID (new_hook_sp->GetID());
+ return false;
+ }
+
+ Error err (reader_sp->Initialize (CommandObjectTargetStopHookAdd::ReadCommandsCallbackFunction,
+ new_hook_sp.get(), // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (!err.Success())
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ target->RemoveStopHookByID (new_hook_sp->GetID());
+ return false;
+ }
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+private:
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectTargetStopHookAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
+ { LLDB_OPT_SET_ALL, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName,
+ "Set the module within which the stop-hook is to be run."},
+ { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, 0, eArgTypeThreadIndex,
+ "The stop hook is run only for the thread whose index matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, 0, eArgTypeThreadID,
+ "The stop hook is run only for the thread whose TID matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, 0, eArgTypeThreadName,
+ "The stop hook is run only for the thread whose thread name matches this argument."},
+ { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, 0, eArgTypeQueueName,
+ "The stop hook is run only for threads in the queue whose name is given by this argument."},
+ { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,
+ "Specify the source file within which the stop-hook is to be run." },
+ { LLDB_OPT_SET_1, false, "start-line", 'l', required_argument, NULL, 0, eArgTypeLineNum,
+ "Set the start of the line range for which the stop-hook is to be run."},
+ { LLDB_OPT_SET_1, false, "end-line", 'e', required_argument, NULL, 0, eArgTypeLineNum,
+ "Set the end of the line range for which the stop-hook is to be run."},
+ { LLDB_OPT_SET_2, false, "classname", 'c', required_argument, NULL, 0, eArgTypeClassName,
+ "Specify the class within which the stop-hook is to be run." },
+ { LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName,
+ "Set the function name within which the stop hook will be run." },
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#pragma mark CommandObjectTargetStopHookDelete
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookDelete : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook delete",
+ "Delete a stop-hook.",
+ "target stop-hook delete [<idx>]")
+ {
+ }
+
+ ~CommandObjectTargetStopHookDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ // FIXME: see if we can use the breakpoint id style parser?
+ size_t num_args = command.GetArgumentCount();
+ if (num_args == 0)
+ {
+ if (!m_interpreter.Confirm ("Delete all stop hooks?", true))
+ {
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ target->RemoveAllStopHooks();
+ }
+ }
+ else
+ {
+ bool success;
+ for (size_t i = 0; i < num_args; i++)
+ {
+ lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ success = target->RemoveStopHookByID (user_id);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+};
+#pragma mark CommandObjectTargetStopHookEnableDisable
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookEnableDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookEnableDisable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookEnableDisable (CommandInterpreter &interpreter, bool enable, const char *name, const char *help, const char *syntax) :
+ CommandObjectParsed (interpreter,
+ name,
+ help,
+ syntax),
+ m_enable (enable)
+ {
+ }
+
+ ~CommandObjectTargetStopHookEnableDisable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target)
+ {
+ // FIXME: see if we can use the breakpoint id style parser?
+ size_t num_args = command.GetArgumentCount();
+ bool success;
+
+ if (num_args == 0)
+ {
+ target->SetAllStopHooksActiveState (m_enable);
+ }
+ else
+ {
+ for (size_t i = 0; i < num_args; i++)
+ {
+ lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ success = target->SetStopHookActiveStateByID (user_id, m_enable);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+private:
+ bool m_enable;
+};
+
+#pragma mark CommandObjectTargetStopHookList
+
+//-------------------------------------------------------------------------
+// CommandObjectTargetStopHookList
+//-------------------------------------------------------------------------
+
+class CommandObjectTargetStopHookList : public CommandObjectParsed
+{
+public:
+
+ CommandObjectTargetStopHookList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "target stop-hook list",
+ "List all stop-hooks.",
+ "target stop-hook list [<type>]")
+ {
+ }
+
+ ~CommandObjectTargetStopHookList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!target)
+ {
+ result.AppendError ("invalid target\n");
+ result.SetStatus (eReturnStatusFailed);
+ return result.Succeeded();
+ }
+
+ size_t num_hooks = target->GetNumStopHooks ();
+ if (num_hooks == 0)
+ {
+ result.GetOutputStream().PutCString ("No stop hooks.\n");
+ }
+ else
+ {
+ for (size_t i = 0; i < num_hooks; i++)
+ {
+ Target::StopHookSP this_hook = target->GetStopHookAtIndex (i);
+ if (i > 0)
+ result.GetOutputStream().PutCString ("\n");
+ this_hook->GetDescription (&(result.GetOutputStream()), eDescriptionLevelFull);
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+};
+
+#pragma mark CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTargetStopHooks
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordTargetStopHooks (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target stop-hook",
+ "A set of commands for operating on debugger target stop-hooks.",
+ "target stop-hook <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetStopHookAdd (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetStopHookDelete (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter,
+ false,
+ "target stop-hook disable [<id>]",
+ "Disable a stop-hook.",
+ "target stop-hook disable")));
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter,
+ true,
+ "target stop-hook enable [<id>]",
+ "Enable a stop-hook.",
+ "target stop-hook enable")));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetStopHookList (interpreter)));
+ }
+
+ ~CommandObjectMultiwordTargetStopHooks()
+ {
+ }
+};
+
+
+
+#pragma mark CommandObjectMultiwordTarget
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTarget
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "target",
+ "A set of commands for operating on debugger targets.",
+ "target <subcommand> [<subcommand-options>]")
+{
+
+ LoadSubCommand ("create", CommandObjectSP (new CommandObjectTargetCreate (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetList (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectTargetSelect (interpreter)));
+ LoadSubCommand ("stop-hook", CommandObjectSP (new CommandObjectMultiwordTargetStopHooks (interpreter)));
+ LoadSubCommand ("modules", CommandObjectSP (new CommandObjectTargetModules (interpreter)));
+ LoadSubCommand ("symbols", CommandObjectSP (new CommandObjectTargetSymbols (interpreter)));
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectTargetVariable (interpreter)));
+}
+
+CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget ()
+{
+}
+
+
diff --git a/source/Commands/CommandObjectTarget.h b/source/Commands/CommandObjectTarget.h
new file mode 100644
index 000000000000..7b6637812c4c
--- /dev/null
+++ b/source/Commands/CommandObjectTarget.h
@@ -0,0 +1,41 @@
+//===-- CommandObjectTarget.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_CommandObjectTarget_h_
+#define liblldb_CommandObjectTarget_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordTarget
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordTarget : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordTarget (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordTarget ();
+
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectTarget_h_
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp
new file mode 100644
index 000000000000..b8657b4361d5
--- /dev/null
+++ b/source/Commands/CommandObjectThread.cpp
@@ -0,0 +1,1526 @@
+//===-- CommandObjectThread.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 "CommandObjectThread.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/LineEntry.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObjectParsed
+{
+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 'c':
+ {
+ bool success;
+ int32_t input_count = Args::StringToSInt32 (option_arg, -1, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option);
+ if (input_count < -1)
+ m_count = UINT32_MAX;
+ else
+ m_count = input_count;
+ }
+ break;
+ case 's':
+ {
+ bool success;
+ m_start = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid integer value for option '%c'", short_option);
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_count = UINT32_MAX;
+ m_start = 0;
+ }
+
+ 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.
+ uint32_t m_count;
+ uint32_t m_start;
+ };
+
+ CommandObjectThreadBacktrace (CommandInterpreter &interpreter) :
+ CommandObjectParsed (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,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ 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()
+ {
+ }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ 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,
+ m_options.m_start,
+ m_options.m_count,
+ num_frames_with_source))
+ {
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ }
+ else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ uint32_t num_threads = process->GetThreadList().GetSize();
+ for (uint32_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = process->GetThreadList().GetThreadAtIndex(i);
+ 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", i);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (i < num_threads - 1)
+ result.AppendMessage("");
+
+ }
+ }
+ else
+ {
+ const size_t num_args = command.GetArgumentCount();
+ Process *process = m_exe_ctx.GetProcessPtr();
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ std::vector<ThreadSP> thread_sps;
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ bool success;
+
+ uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx));
+
+ if (!thread_sps[i])
+ {
+ result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+ for (uint32_t i = 0; i < num_args; i++)
+ {
+ if (!thread_sps[i]->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 (i < num_args - 1)
+ result.AppendMessage("");
+ }
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
+OptionDefinition
+CommandObjectThreadBacktrace::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "How many frames to display (-1 for all)"},
+{ LLDB_OPT_SET_1, false, "start", 's', required_argument, NULL, 0, eArgTypeFrameIndex, "Frame in which to start the backtrace"},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+enum StepScope
+{
+ eStepScopeSource,
+ eStepScopeInstruction
+};
+
+class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed
+{
+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 'a':
+ {
+ bool success;
+ m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid boolean value for option '%c'", short_option);
+ }
+ break;
+
+ case 'm':
+ {
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
+ }
+ break;
+
+ case 'r':
+ {
+ m_avoid_regexp.clear();
+ m_avoid_regexp.assign(option_arg);
+ }
+ break;
+
+ case 't':
+ {
+ m_step_in_target.clear();
+ m_step_in_target.assign(option_arg);
+
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_avoid_no_debug = true;
+ m_run_mode = eOnlyDuringStepping;
+ m_avoid_regexp.clear();
+ m_step_in_target.clear();
+ }
+
+ 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_avoid_no_debug;
+ RunMode m_run_mode;
+ std::string m_avoid_regexp;
+ std::string m_step_in_target;
+ };
+
+ CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ StepType step_type,
+ StepScope step_scope) :
+ CommandObjectParsed (interpreter, name, help, syntax,
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_step_type (step_type),
+ m_step_scope (step_scope),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData thread_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ thread_id_arg.arg_type = eArgTypeThreadID;
+ thread_id_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (thread_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectThreadStepWithTypeAndScope ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ bool synchronous_execution = m_interpreter.GetSynchronous();
+
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ Thread *thread = NULL;
+
+ if (command.GetArgumentCount() == 0)
+ {
+ thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ {
+ result.AppendError ("no selected thread in process");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
+ uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32);
+ if (step_thread_idx == LLDB_INVALID_INDEX32)
+ {
+ result.AppendErrorWithFormat ("invalid thread index '%s'.\n", thread_idx_cstr);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
+ if (thread == NULL)
+ {
+ result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n",
+ step_thread_idx, num_threads);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ const bool abort_other_plans = false;
+ const lldb::RunMode stop_other_threads = m_options.m_run_mode;
+
+ // This is a bit unfortunate, but not all the commands in this command object support
+ // only while stepping, so I use the bool for them.
+ bool bool_stop_other_threads;
+ if (m_options.m_run_mode == eAllThreads)
+ bool_stop_other_threads = false;
+ else if (m_options.m_run_mode == eOnlyDuringStepping)
+ {
+ if (m_step_type == eStepTypeOut)
+ bool_stop_other_threads = false;
+ else
+ bool_stop_other_threads = true;
+ }
+ else
+ bool_stop_other_threads = true;
+
+ ThreadPlanSP new_plan_sp;
+
+ if (m_step_type == eStepTypeInto)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+
+ if (frame->HasDebugInformation ())
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepInRange (abort_other_plans,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ m_options.m_step_in_target.c_str(),
+ stop_other_threads,
+ m_options.m_avoid_no_debug);
+ if (new_plan_sp && !m_options.m_avoid_regexp.empty())
+ {
+ ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan_sp.get());
+ step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str());
+ }
+ }
+ else
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+
+ }
+ else if (m_step_type == eStepTypeOver)
+ {
+ StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+
+ if (frame->HasDebugInformation())
+ new_plan_sp = thread->QueueThreadPlanForStepOverRange (abort_other_plans,
+ frame->GetSymbolContext(eSymbolContextEverything).line_entry.range,
+ frame->GetSymbolContext(eSymbolContextEverything),
+ stop_other_threads);
+ else
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true,
+ abort_other_plans,
+ bool_stop_other_threads);
+
+ }
+ else if (m_step_type == eStepTypeTrace)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+ }
+ else if (m_step_type == eStepTypeTraceOver)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
+ }
+ else if (m_step_type == eStepTypeOut)
+ {
+ new_plan_sp = thread->QueueThreadPlanForStepOut (abort_other_plans,
+ NULL,
+ false,
+ bool_stop_other_threads,
+ eVoteYes,
+ eVoteNoOpinion,
+ thread->GetSelectedFrameIndex());
+ }
+ else
+ {
+ result.AppendError ("step type is not supported");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ // If we got a new plan, then set it to be a master plan (User level Plans should be master plans
+ // so that they can be interruptible). Then resume the process.
+
+ if (new_plan_sp)
+ {
+ new_plan_sp->SetIsMasterPlan (true);
+ new_plan_sp->SetOkayToDiscard (false);
+
+ process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ process->Resume ();
+
+
+ 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);
+ // }
+ process->GetThreadList().SetSelectedThreadByID (thread->GetID());
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendError ("Couldn't find thread plan to implement step type.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return result.Succeeded();
+ }
+
+protected:
+ StepType m_step_type;
+ StepScope m_step_scope;
+ CommandOptions m_options;
+};
+
+static OptionEnumValueElement
+g_tri_running_mode[] =
+{
+{ eOnlyThisThread, "this-thread", "Run only this thread"},
+{ eAllThreads, "all-threads", "Run all threads"},
+{ eOnlyDuringStepping, "while-stepping", "Run only this thread while stepping"},
+{ 0, NULL, NULL }
+};
+
+static OptionEnumValueElement
+g_duo_running_mode[] =
+{
+{ eOnlyThisThread, "this-thread", "Run only this thread"},
+{ eAllThreads, "all-threads", "Run all threads"},
+{ 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "avoid-no-debug", 'a', required_argument, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether step-in will step over functions with no debug information."},
+{ LLDB_OPT_SET_1, false, "run-mode", 'm', required_argument, 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', required_argument, 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', required_argument, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadContinue
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadContinue : public CommandObjectParsed
+{
+public:
+
+ CommandObjectThreadContinue (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread continue",
+ "Continue execution of one or more threads in an active process.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused)
+ {
+ 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 = eArgRepeatPlus;
+
+ // 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);
+ }
+
+
+ virtual
+ ~CommandObjectThreadContinue ()
+ {
+ }
+
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ if (!m_interpreter.GetDebugger().GetSelectedTarget().get())
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process exists. Cannot continue");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ StateType state = process->GetState();
+ if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended))
+ {
+ Mutex::Locker locker (process->GetThreadList().GetMutex());
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ const size_t argc = command.GetArgumentCount();
+ if (argc > 0)
+ {
+ std::vector<Thread *> resume_threads;
+ for (uint32_t i=0; i<argc; ++i)
+ {
+ bool success;
+ const int base = 0;
+ uint32_t thread_idx = Args::StringToUInt32 (command.GetArgumentAtIndex(i), LLDB_INVALID_INDEX32, base, &success);
+ if (success)
+ {
+ Thread *thread = process->GetThreadList().FindThreadByIndexID(thread_idx).get();
+
+ if (thread)
+ {
+ resume_threads.push_back(thread);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("invalid thread index %u.\n", thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("invalid thread index argument: \"%s\".\n", command.GetArgumentAtIndex(i));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (resume_threads.empty())
+ {
+ result.AppendError ("no valid thread indexes were specified");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ if (resume_threads.size() == 1)
+ result.AppendMessageWithFormat ("Resuming thread: ");
+ else
+ result.AppendMessageWithFormat ("Resuming threads: ");
+
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ std::vector<Thread *>::iterator this_thread_pos = find(resume_threads.begin(), resume_threads.end(), thread);
+
+ if (this_thread_pos != resume_threads.end())
+ {
+ resume_threads.erase(this_thread_pos);
+ if (resume_threads.size() > 0)
+ result.AppendMessageWithFormat ("%u, ", thread->GetIndexID());
+ else
+ result.AppendMessageWithFormat ("%u ", thread->GetIndexID());
+
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ result.AppendMessageWithFormat ("in process %" PRIu64 "\n", process->GetID());
+ }
+ }
+ else
+ {
+ Thread *current_thread = process->GetThreadList().GetSelectedThread().get();
+ if (current_thread == NULL)
+ {
+ result.AppendError ("the process doesn't have a current thread");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // Set the actions that the threads should each take when resuming
+ for (uint32_t idx=0; idx<num_threads; ++idx)
+ {
+ Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+ if (thread == current_thread)
+ {
+ result.AppendMessageWithFormat ("Resuming thread 0x%4.4" PRIx64 " in process %" PRIu64 "\n", thread->GetID(), process->GetID());
+ thread->SetResumeState (eStateRunning);
+ }
+ else
+ {
+ thread->SetResumeState (eStateSuspended);
+ }
+ }
+ }
+
+ Error error (process->Resume());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
+ StateAsCString(state));
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadUntil
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadUntil : public CommandObjectParsed
+{
+public:
+
+ class CommandOptions : public Options
+ {
+ public:
+ uint32_t m_thread_idx;
+ uint32_t m_frame_idx;
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_thread_idx(LLDB_INVALID_THREAD_ID),
+ m_frame_idx(LLDB_INVALID_FRAME_ID)
+ {
+ // 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 't':
+ {
+ m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
+ if (m_thread_idx == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorStringWithFormat ("invalid thread index '%s'", option_arg);
+ }
+ }
+ break;
+ case 'f':
+ {
+ m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID);
+ if (m_frame_idx == LLDB_INVALID_FRAME_ID)
+ {
+ error.SetErrorStringWithFormat ("invalid frame index '%s'", option_arg);
+ }
+ }
+ break;
+ case 'm':
+ {
+ OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values;
+ lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, error);
+
+ if (error.Success())
+ {
+ if (run_mode == eAllThreads)
+ m_stop_others = false;
+ else
+ m_stop_others = true;
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_thread_idx = LLDB_INVALID_THREAD_ID;
+ m_frame_idx = 0;
+ m_stop_others = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ uint32_t m_step_thread_idx;
+ bool m_stop_others;
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ };
+
+ CommandObjectThreadUntil (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread until",
+ "Run the current or specified thread until it reaches a given line number or leaves the current function.",
+ NULL,
+ eFlagRequiresThread |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData line_num_arg;
+
+ // Define the first (and only) variant of this arg.
+ line_num_arg.arg_type = eArgTypeLineNum;
+ line_num_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (line_num_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectThreadUntil ()
+ {
+ }
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ bool synchronous_execution = m_interpreter.GetSynchronous ();
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("invalid target, create a debug target using the 'target create' command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("need a valid process to step");
+ result.SetStatus (eReturnStatusFailed);
+
+ }
+ else
+ {
+ Thread *thread = NULL;
+ uint32_t line_number;
+
+ if (command.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX);
+ if (line_number == UINT32_MAX)
+ {
+ result.AppendErrorWithFormat ("invalid line number: '%s'.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID)
+ {
+ thread = process->GetThreadList().GetSelectedThread().get();
+ }
+ else
+ {
+ thread = process->GetThreadList().FindThreadByIndexID(m_options.m_thread_idx).get();
+ }
+
+ if (thread == NULL)
+ {
+ const uint32_t num_threads = process->GetThreadList().GetSize();
+ result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n",
+ m_options.m_thread_idx,
+ num_threads);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const bool abort_other_plans = false;
+
+ StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
+ if (frame == NULL)
+ {
+
+ result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n",
+ m_options.m_frame_idx,
+ m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ThreadPlanSP new_plan_sp;
+
+ if (frame->HasDebugInformation ())
+ {
+ // Finally we got here... Translate the given line number to a bunch of addresses:
+ SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit));
+ LineTable *line_table = NULL;
+ if (sc.comp_unit)
+ line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table == NULL)
+ {
+ result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n",
+ m_options.m_frame_idx, m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ LineEntry function_start;
+ uint32_t index_ptr = 0, end_ptr;
+ std::vector<addr_t> address_list;
+
+ // Find the beginning & end index of the
+ AddressRange fun_addr_range = sc.function->GetAddressRange();
+ Address fun_start_addr = fun_addr_range.GetBaseAddress();
+ line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr);
+
+ Address fun_end_addr(fun_start_addr.GetSection(),
+ fun_start_addr.GetOffset() + fun_addr_range.GetByteSize());
+ line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr);
+
+ bool all_in_function = true;
+
+ while (index_ptr <= end_ptr)
+ {
+ LineEntry line_entry;
+ const bool exact = false;
+ index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, exact, &line_entry);
+ if (index_ptr == UINT32_MAX)
+ break;
+
+ addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(target);
+ if (address != LLDB_INVALID_ADDRESS)
+ {
+ if (fun_addr_range.ContainsLoadAddress (address, target))
+ address_list.push_back (address);
+ else
+ all_in_function = false;
+ }
+ index_ptr++;
+ }
+
+ if (address_list.size() == 0)
+ {
+ if (all_in_function)
+ result.AppendErrorWithFormat ("No line entries matching until target.\n");
+ else
+ result.AppendErrorWithFormat ("Until target outside of the current function.\n");
+
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ new_plan_sp = thread->QueueThreadPlanForStepUntil (abort_other_plans,
+ &address_list.front(),
+ address_list.size(),
+ m_options.m_stop_others,
+ m_options.m_frame_idx);
+ // User level plans should be master plans so they can be interrupted (e.g. by hitting a breakpoint)
+ // and other plans executed by the user (stepping around the breakpoint) and then a "continue"
+ // will resume the original plan.
+ new_plan_sp->SetIsMasterPlan (true);
+ new_plan_sp->SetOkayToDiscard(false);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n",
+ m_options.m_frame_idx,
+ m_options.m_thread_idx);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+
+ process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx);
+ Error error (process->Resume ());
+ if (error.Success())
+ {
+ result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID());
+ if (synchronous_execution)
+ {
+ StateType state = process->WaitForProcessToStop (NULL);
+
+ result.SetDidChangeProcessState (true);
+ result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+
+};
+
+OptionDefinition
+CommandObjectThreadUntil::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "frame", 'f', required_argument, NULL, 0, eArgTypeFrameIndex, "Frame index for until operation - defaults to 0"},
+{ LLDB_OPT_SET_1, false, "thread", 't', required_argument, NULL, 0, eArgTypeThreadIndex, "Thread index for the thread for until operation"},
+{ LLDB_OPT_SET_1, false, "run-mode",'m', required_argument, g_duo_running_mode, 0, eArgTypeRunMode,"Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadSelect : public CommandObjectParsed
+{
+public:
+
+ CommandObjectThreadSelect (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "thread select",
+ "Select a thread as the currently active thread.",
+ NULL,
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ 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 = eArgRepeatPlain;
+
+ // 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);
+ }
+
+
+ virtual
+ ~CommandObjectThreadSelect ()
+ {
+ }
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Process *process = m_exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ {
+ result.AppendError ("no process");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ else if (command.GetArgumentCount() != 1)
+ {
+ result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: %s\n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0);
+
+ Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
+ if (new_thread == NULL)
+ {
+ result.AppendErrorWithFormat ("invalid thread #%s.\n", command.GetArgumentAtIndex(0));
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ process->GetThreadList().SetSelectedThreadByID(new_thread->GetID(), true);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+
+ return result.Succeeded();
+ }
+
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadList
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadList : public CommandObjectParsed
+{
+public:
+
+
+ CommandObjectThreadList (CommandInterpreter &interpreter):
+ CommandObjectParsed (interpreter,
+ "thread list",
+ "Show a summary of all current threads in a process.",
+ "thread list",
+ eFlagRequiresProcess |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused )
+ {
+ }
+
+ ~CommandObjectThreadList()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Stream &strm = result.GetOutputStream();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ Process *process = m_exe_ctx.GetProcessPtr();
+ const bool only_threads_with_stop_reason = false;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 0;
+ const uint32_t num_frames_with_source = 0;
+ process->GetStatus(strm);
+ process->GetThreadStatus (strm,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadReturn
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadReturn : public CommandObjectRaw
+{
+public:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_from_expression (false)
+ {
+ // 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 'x':
+ {
+ bool success;
+ bool tmp_value = Args::StringToBoolean (option_arg, false, &success);
+ if (success)
+ m_from_expression = tmp_value;
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid boolean value '%s' for 'x' option", option_arg);
+ }
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat("invalid short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_from_expression = false;
+ }
+
+ const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ bool m_from_expression;
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+ };
+
+ virtual
+ Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ CommandObjectThreadReturn (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "thread return",
+ "Return from the currently selected frame, short-circuiting execution of the frames below it, with an optional return value,"
+ " or with the -x option from the innermost function evaluation.",
+ "thread return",
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the first (and only) variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatOptional;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+
+ }
+
+ ~CommandObjectThreadReturn()
+ {
+ }
+
+protected:
+
+ bool DoExecute
+ (
+ const char *command,
+ CommandReturnObject &result
+ )
+ {
+ // I am going to handle this by hand, because I don't want you to have to say:
+ // "thread return -- -5".
+ if (command[0] == '-' && command[1] == 'x')
+ {
+ if (command && command[2] != '\0')
+ result.AppendWarning("Return values ignored when returning from user called expressions");
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ Error error;
+ error = thread->UnwindInnermostExpression();
+ if (!error.Success())
+ {
+ result.AppendErrorWithFormat ("Unwinding expression failed - %s.", error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ else
+ {
+ bool success = thread->SetSelectedFrameByIndexNoisily (0, result.GetOutputStream());
+ if (success)
+ {
+ m_exe_ctx.SetFrameSP(thread->GetSelectedFrame ());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Could not select 0th frame after unwinding expression.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ return result.Succeeded();
+ }
+
+ ValueObjectSP return_valobj_sp;
+
+ StackFrameSP frame_sp = m_exe_ctx.GetFrameSP();
+ uint32_t frame_idx = frame_sp->GetFrameIndex();
+
+ if (frame_sp->IsInlined())
+ {
+ result.AppendError("Don't know how to return from inlined frames.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command && command[0] != '\0')
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ EvaluateExpressionOptions options;
+
+ options.SetUnwindOnError(true);
+ options.SetUseDynamic(eNoDynamicValues);
+
+ ExecutionResults exe_results = eExecutionSetupError;
+ exe_results = target->EvaluateExpression (command,
+ frame_sp.get(),
+ return_valobj_sp,
+ options);
+ if (exe_results != eExecutionCompleted)
+ {
+ if (return_valobj_sp)
+ result.AppendErrorWithFormat("Error evaluating result expression: %s", return_valobj_sp->GetError().AsCString());
+ else
+ result.AppendErrorWithFormat("Unknown error evaluating result expression.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+ }
+
+ Error error;
+ ThreadSP thread_sp = m_exe_ctx.GetThreadSP();
+ const bool broadcast = true;
+ error = thread_sp->ReturnFromFrame (frame_sp, return_valobj_sp, broadcast);
+ if (!error.Success())
+ {
+ result.AppendErrorWithFormat("Error returning from frame %d of thread %d: %s.", frame_idx, thread_sp->GetIndexID(), error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+
+ CommandOptions m_options;
+
+};
+OptionDefinition
+CommandObjectThreadReturn::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "from-expression", 'x', no_argument, NULL, 0, eArgTypeNone, "Return from the innermost expression evaluation."},
+{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThread
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "thread",
+ "A set of commands for operating on one or more threads within a running process.",
+ "thread <subcommand> [<subcommand-options>]")
+{
+ LoadSubCommand ("backtrace", CommandObjectSP (new CommandObjectThreadBacktrace (interpreter)));
+ LoadSubCommand ("continue", CommandObjectSP (new CommandObjectThreadContinue (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadList (interpreter)));
+ LoadSubCommand ("return", CommandObjectSP (new CommandObjectThreadReturn (interpreter)));
+ LoadSubCommand ("select", CommandObjectSP (new CommandObjectThreadSelect (interpreter)));
+ LoadSubCommand ("until", CommandObjectSP (new CommandObjectThreadUntil (interpreter)));
+ LoadSubCommand ("step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-in",
+ "Source level single step in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeInto,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-out", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-out",
+ "Finish executing the function of the currently selected frame and return to its call site in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeOut,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-over",
+ "Source level single step in specified thread (current thread, if none specified), stepping over calls.",
+ NULL,
+ eStepTypeOver,
+ eStepScopeSource)));
+
+ LoadSubCommand ("step-inst", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-inst",
+ "Single step one instruction in specified thread (current thread, if none specified).",
+ NULL,
+ eStepTypeTrace,
+ eStepScopeInstruction)));
+
+ LoadSubCommand ("step-inst-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope (
+ interpreter,
+ "thread step-inst-over",
+ "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
+ NULL,
+ eStepTypeTraceOver,
+ eStepScopeInstruction)));
+}
+
+CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
+{
+}
+
+
diff --git a/source/Commands/CommandObjectThread.h b/source/Commands/CommandObjectThread.h
new file mode 100644
index 000000000000..52902ee36c76
--- /dev/null
+++ b/source/Commands/CommandObjectThread.h
@@ -0,0 +1,34 @@
+//===-- CommandObjectThread.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_CommandObjectThread_h_
+#define liblldb_CommandObjectThread_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+namespace lldb_private {
+
+class CommandObjectMultiwordThread : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectMultiwordThread (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordThread ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectThread_h_
diff --git a/source/Commands/CommandObjectType.cpp b/source/Commands/CommandObjectType.cpp
new file mode 100644
index 000000000000..b300f213db0f
--- /dev/null
+++ b/source/Commands/CommandObjectType.cpp
@@ -0,0 +1,4112 @@
+//===-- CommandObjectType.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 "CommandObjectType.h"
+
+// C Includes
+
+#include <ctype.h>
+
+// C++ Includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReaderEZ.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupFormat.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+class ScriptAddOptions
+{
+
+public:
+
+ TypeSummaryImpl::Flags m_flags;
+
+ StringList m_target_types;
+ StringList m_user_source;
+
+ bool m_regex;
+
+ ConstString m_name;
+
+ std::string m_category;
+
+ ScriptAddOptions(const TypeSummaryImpl::Flags& flags,
+ bool regx,
+ const ConstString& name,
+ std::string catg) :
+ m_flags(flags),
+ m_regex(regx),
+ m_name(name),
+ m_category(catg)
+ {
+ }
+
+ typedef std::shared_ptr<ScriptAddOptions> SharedPointer;
+
+};
+
+class SynthAddOptions
+{
+
+public:
+
+ bool m_skip_pointers;
+ bool m_skip_references;
+ bool m_cascade;
+ bool m_regex;
+ StringList m_user_source;
+ StringList m_target_types;
+
+ std::string m_category;
+
+ SynthAddOptions(bool sptr,
+ bool sref,
+ bool casc,
+ bool regx,
+ std::string catg) :
+ m_skip_pointers(sptr),
+ m_skip_references(sref),
+ m_cascade(casc),
+ m_regex(regx),
+ m_user_source(),
+ m_target_types(),
+ m_category(catg)
+ {
+ }
+
+ typedef std::shared_ptr<SynthAddOptions> SharedPointer;
+
+};
+
+
+
+class CommandObjectTypeSummaryAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg);
+
+ void
+ OptionParsingStarting ();
+
+ 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.
+
+ TypeSummaryImpl::Flags m_flags;
+ bool m_regex;
+ std::string m_format_string;
+ ConstString m_name;
+ std::string m_python_script;
+ std::string m_python_function;
+ bool m_is_add_script;
+ std::string m_category;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectPythonScript(ScriptAddOptions *options,
+ CommandReturnObject &result);
+
+ bool
+ Execute_ScriptSummary (Args& command, CommandReturnObject &result);
+
+ bool
+ Execute_StringSummary (Args& command, CommandReturnObject &result);
+
+public:
+
+ enum SummaryFormatType
+ {
+ eRegularSummary,
+ eRegexSummary,
+ eNamedSummary
+ };
+
+ CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter);
+
+ ~CommandObjectTypeSummaryAdd ()
+ {
+ }
+
+ static bool
+ AddSummary(ConstString type_name,
+ lldb::TypeSummaryImplSP entry,
+ SummaryFormatType type,
+ std::string category,
+ Error* error = NULL);
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result);
+
+};
+
+class CommandObjectTypeSynthAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'P':
+ handwrite_python = true;
+ break;
+ case 'l':
+ m_class_name = std::string(option_arg);
+ is_class_based = true;
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_cascade = true;
+ m_class_name = "";
+ m_skip_pointers = false;
+ m_skip_references = false;
+ m_category = "default";
+ is_class_based = false;
+ handwrite_python = false;
+ m_regex = 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_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ std::string m_class_name;
+ bool m_input_python;
+ std::string m_category;
+
+ bool is_class_based;
+
+ bool handwrite_python;
+
+ bool m_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectPythonScript (SynthAddOptions *options,
+ CommandReturnObject &result);
+ bool
+ Execute_HandwritePython (Args& command, CommandReturnObject &result);
+
+ bool
+ Execute_PythonClass (Args& command, CommandReturnObject &result);
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result);
+
+public:
+
+ enum SynthFormatType
+ {
+ eRegularSynth,
+ eRegexSynth
+ };
+
+ CommandObjectTypeSynthAdd (CommandInterpreter &interpreter);
+
+ ~CommandObjectTypeSynthAdd ()
+ {
+ }
+
+ static bool
+ AddSynth(ConstString type_name,
+ lldb::SyntheticChildrenSP entry,
+ SynthFormatType type,
+ std::string category_name,
+ Error* error);
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public OptionGroup
+ {
+ public:
+
+ CommandOptions () :
+ OptionGroup()
+ {
+ }
+
+ virtual
+ ~CommandOptions ()
+ {
+ }
+
+ virtual uint32_t
+ GetNumDefinitions ();
+
+ virtual const OptionDefinition*
+ GetDefinitions ()
+ {
+ return g_option_table;
+ }
+
+ virtual void
+ OptionParsingStarting (CommandInterpreter &interpreter)
+ {
+ m_cascade = true;
+ m_skip_pointers = false;
+ m_skip_references = false;
+ }
+ virtual Error
+ SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_value)
+ {
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_value, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_value);
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ // Options table: Required for subclasses of Options.
+
+ static OptionDefinition g_option_table[];
+
+ // Instance variables to hold the values for command options.
+
+ bool m_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ };
+
+ OptionGroupOptions m_option_group;
+ OptionGroupFormat m_format_options;
+ CommandOptions m_command_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+public:
+ CommandObjectTypeFormatAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format add",
+ "Add a new formatting style for a type.",
+ NULL),
+ m_option_group (interpreter),
+ m_format_options (eFormatInvalid),
+ m_command_options ()
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "\n"
+ "typedef int Aint;\n"
+ "typedef float Afloat;\n"
+ "typedef Aint Bint;\n"
+ "typedef Afloat Bfloat;\n"
+ "\n"
+ "Aint ix = 5;\n"
+ "Bint iy = 5;\n"
+ "\n"
+ "Afloat fx = 3.14;\n"
+ "BFloat fy = 3.14;\n"
+ "\n"
+ "Typing:\n"
+ "type format add -f hex AInt\n"
+ "frame variable iy\n"
+ "will produce an hex display of iy, because no formatter is available for Bint and the one for Aint is used instead\n"
+ "To prevent this type\n"
+ "type format add -f hex -C no AInt\n"
+ "\n"
+ "A similar reasoning applies to\n"
+ "type format add -f hex -C no float -p\n"
+ "which now prints all floats and float&s as hexadecimal, but does not format float*s\n"
+ "and does not change the default display for Afloat and Bfloat objects.\n"
+ );
+
+ // Add the "--format" to all options groups
+ m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_ALL);
+ m_option_group.Append (&m_command_options);
+ m_option_group.Finalize();
+
+ }
+
+ ~CommandObjectTypeFormatAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const Format format = m_format_options.GetFormat();
+ if (format == eFormatInvalid)
+ {
+ result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ TypeFormatImplSP entry;
+
+ entry.reset(new TypeFormatImpl(format,
+ TypeFormatImpl::Flags().SetCascades(m_command_options.m_cascade).
+ SetSkipPointers(m_command_options.m_skip_pointers).
+ SetSkipReferences(m_command_options.m_skip_references)));
+
+ // now I have a valid format, let's add it to every type
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ DataVisualization::ValueFormats::Add(typeCS, entry);
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+};
+
+OptionDefinition
+CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+};
+
+
+uint32_t
+CommandObjectTypeFormatAdd::CommandOptions::GetNumDefinitions ()
+{
+ return sizeof(g_option_table) / sizeof (OptionDefinition);
+}
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format delete",
+ "Delete an existing formatting style for a type.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeFormatDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+
+ if (DataVisualization::ValueFormats::Delete(typeCS))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom format for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFormatClear : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format clear",
+ "Delete all existing format styles.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectTypeFormatClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ DataVisualization::ValueFormats::Clear();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry);
+
+class CommandObjectTypeFormatList;
+
+struct CommandObjectTypeFormatList_LoopCallbackParam {
+ CommandObjectTypeFormatList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ CommandObjectTypeFormatList_LoopCallbackParam(CommandObjectTypeFormatList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
+};
+
+class CommandObjectTypeFormatList : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeFormatList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type format list",
+ "Show a list of current formatting styles.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeFormatList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeFormatList_LoopCallbackParam *param;
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,regex);
+ }
+ else
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result);
+ DataVisualization::ValueFormats::LoopThrough(CommandObjectTypeFormatList_LoopCallback, param);
+ delete param;
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ bool
+ LoopCallback (ConstString type,
+ const lldb::TypeFormatImplSP& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type.AsCString()))
+ {
+ result->GetOutputStream().Printf ("%s: %s\n", type.AsCString(),
+ entry->GetDescription().c_str());
+ }
+ return true;
+ }
+
+ friend bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeFormatImplSP& entry);
+
+};
+
+bool
+CommandObjectTypeFormatList_LoopCallback (
+ void* pt2self,
+ ConstString type,
+ const lldb::TypeFormatImplSP& entry)
+{
+ CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type, entry, param->regex, param->result);
+}
+
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryAdd
+//-------------------------------------------------------------------------
+
+static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "def function (valobj,internal_dict):\n"
+ " \"\"\"valobj: an SBValue which you want to provide a summary for\n"
+ " internal_dict: an LLDB support object not to be used\"\"\"";
+
+class TypeScriptAddInputReader : public InputReaderEZ
+{
+private:
+ DISALLOW_COPY_AND_ASSIGN (TypeScriptAddInputReader);
+public:
+ TypeScriptAddInputReader(Debugger& debugger) :
+ InputReaderEZ(debugger)
+ {}
+
+ virtual
+ ~TypeScriptAddInputReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_summary_addreader_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (data.bytes && data.bytes_len && data.baton)
+ {
+ ((ScriptAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.reader.GetDebugger().GetAsyncOutputStream();
+ ScriptAddOptions *options_ptr = ((ScriptAddOptions*)data.baton);
+ if (!options_ptr)
+ {
+ out_stream->Printf ("internal synchronization information missing or invalid.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ ScriptAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("no script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string funct_name_str;
+ if (!interpreter->GenerateTypeScriptFunction (options->m_user_source,
+ funct_name_str))
+ {
+ out_stream->Printf ("unable to generate a function.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (funct_name_str.empty())
+ {
+ out_stream->Printf ("unable to obtain a valid function name from the script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ // now I have a valid function name, let's add this as script for every type in the list
+
+ TypeSummaryImplSP script_format;
+ script_format.reset(new ScriptSummaryFormat(options->m_flags,
+ funct_name_str.c_str(),
+ options->m_user_source.CopyList(" ").c_str()));
+
+ Error error;
+
+ for (size_t i = 0; i < options->m_target_types.GetSize(); i++)
+ {
+ const char *type_name = options->m_target_types.GetStringAtIndex(i);
+ CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name),
+ script_format,
+ (options->m_regex ? CommandObjectTypeSummaryAdd::eRegexSummary : CommandObjectTypeSummaryAdd::eRegularSummary),
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+
+ if (options->m_name)
+ {
+ CommandObjectTypeSummaryAdd::AddSummary (options->m_name,
+ script_format,
+ CommandObjectTypeSummaryAdd::eNamedSummary,
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ CommandObjectTypeSummaryAdd::AddSummary (options->m_name,
+ script_format,
+ CommandObjectTypeSummaryAdd::eNamedSummary,
+ options->m_category,
+ &error);
+ if (error.Fail())
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ out_stream->Printf ("%s", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ if (error.AsCString())
+ {
+ out_stream->PutCString (error.AsCString());
+ out_stream->Flush();
+ }
+ return;
+ }
+ }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+Error
+CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_flags.SetCascades(Args::StringToBoolean(option_arg, true, &success));
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'e':
+ m_flags.SetDontShowChildren(false);
+ break;
+ case 'v':
+ m_flags.SetDontShowValue(true);
+ break;
+ case 'c':
+ m_flags.SetShowMembersOneLiner(true);
+ break;
+ case 's':
+ m_format_string = std::string(option_arg);
+ break;
+ case 'p':
+ m_flags.SetSkipPointers(true);
+ break;
+ case 'r':
+ m_flags.SetSkipReferences(true);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ case 'n':
+ m_name.SetCString(option_arg);
+ break;
+ case 'o':
+ m_python_script = std::string(option_arg);
+ m_is_add_script = true;
+ break;
+ case 'F':
+ m_python_function = std::string(option_arg);
+ m_is_add_script = true;
+ break;
+ case 'P':
+ m_is_add_script = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'O':
+ m_flags.SetHideItemNames(true);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+CommandObjectTypeSummaryAdd::CommandOptions::OptionParsingStarting ()
+{
+ m_flags.Clear().SetCascades().SetDontShowChildren().SetDontShowValue(false);
+ m_flags.SetShowMembersOneLiner(false).SetSkipPointers(false).SetSkipReferences(false).SetHideItemNames(false);
+
+ m_regex = false;
+ m_name.Clear();
+ m_python_script = "";
+ m_python_function = "";
+ m_format_string = "";
+ m_is_add_script = false;
+ m_category = "default";
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+void
+CommandObjectTypeSummaryAdd::CollectPythonScript (ScriptAddOptions *options,
+ CommandReturnObject &result)
+{
+ InputReaderSP reader_sp (new TypeScriptAddInputReader(m_interpreter.GetDebugger()));
+ if (reader_sp && options)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+bool
+CommandObjectTypeSummaryAdd::Execute_ScriptSummary (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1 && !m_options.m_name)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ TypeSummaryImplSP script_format;
+
+ if (!m_options.m_python_function.empty()) // we have a Python function ready to use
+ {
+ const char *funct_name = m_options.m_python_function.c_str();
+ if (!funct_name || !funct_name[0])
+ {
+ result.AppendError ("function name empty.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string code = (" " + m_options.m_python_function + "(valobj,internal_dict)");
+
+ script_format.reset(new ScriptSummaryFormat(m_options.m_flags,
+ funct_name,
+ code.c_str()));
+
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+
+ if (interpreter && interpreter->CheckObjectExists(funct_name) == false)
+ result.AppendWarningWithFormat("The provided function \"%s\" does not exist - "
+ "please define it before attempting to use this summary.\n",
+ funct_name);
+ }
+ else if (!m_options.m_python_script.empty()) // we have a quick 1-line script, just use it
+ {
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+ if (!interpreter)
+ {
+ result.AppendError ("script interpreter missing - unable to generate function wrapper.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ StringList funct_sl;
+ funct_sl << m_options.m_python_script.c_str();
+ std::string funct_name_str;
+ if (!interpreter->GenerateTypeScriptFunction (funct_sl,
+ funct_name_str))
+ {
+ result.AppendError ("unable to generate function wrapper.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ if (funct_name_str.empty())
+ {
+ result.AppendError ("script interpreter failed to generate a valid function name.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::string code = " " + m_options.m_python_script;
+
+ script_format.reset(new ScriptSummaryFormat(m_options.m_flags,
+ funct_name_str.c_str(),
+ code.c_str()));
+ }
+ else // use an InputReader to grab Python code from the user
+ {
+ ScriptAddOptions *options = new ScriptAddOptions(m_options.m_flags,
+ m_options.m_regex,
+ m_options.m_name,
+ m_options.m_category);
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (typeA && *typeA)
+ options->m_target_types << typeA;
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ CollectPythonScript(options,result);
+ return result.Succeeded();
+ }
+
+ // if I am here, script_format must point to something good, so I can add that
+ // as a script summary to all interested parties
+
+ Error error;
+
+ for (size_t i = 0; i < command.GetArgumentCount(); i++)
+ {
+ const char *type_name = command.GetArgumentAtIndex(i);
+ CommandObjectTypeSummaryAdd::AddSummary(ConstString(type_name),
+ script_format,
+ (m_options.m_regex ? eRegexSummary : eRegularSummary),
+ m_options.m_category,
+ &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (m_options.m_name)
+ {
+ AddSummary(m_options.m_name, script_format, eNamedSummary, m_options.m_category, &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.AppendError("added to types, but not given a name");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ return result.Succeeded();
+}
+
+#endif
+
+
+bool
+CommandObjectTypeSummaryAdd::Execute_StringSummary (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1 && !m_options.m_name)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (!m_options.m_flags.GetShowMembersOneLiner() && m_options.m_format_string.empty())
+ {
+ result.AppendError("empty summary strings not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* format_cstr = (m_options.m_flags.GetShowMembersOneLiner() ? "" : m_options.m_format_string.c_str());
+
+ // ${var%S} is an endless recursion, prevent it
+ if (strcmp(format_cstr, "${var%S}") == 0)
+ {
+ result.AppendError("recursive summary not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Error error;
+
+ lldb::TypeSummaryImplSP entry(new StringSummaryFormat(m_options.m_flags,
+ format_cstr));
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // now I have a valid format, let's add it to every type
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (!typeA || typeA[0] == '\0')
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ ConstString typeCS(typeA);
+
+ AddSummary(typeCS,
+ entry,
+ (m_options.m_regex ? eRegexSummary : eRegularSummary),
+ m_options.m_category,
+ &error);
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ if (m_options.m_name)
+ {
+ AddSummary(m_options.m_name, entry, eNamedSummary, m_options.m_category, &error);
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.AppendError("added to types, but not given a name");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+}
+
+CommandObjectTypeSummaryAdd::CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary add",
+ "Add a new summary style for a type.",
+ NULL),
+ m_options (interpreter)
+{
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "struct JustADemo\n"
+ "{\n"
+ "int* ptr;\n"
+ "float value;\n"
+ "JustADemo(int p = 1, float v = 0.1) : ptr(new int(p)), value(v) {}\n"
+ "};\n"
+ "JustADemo object(42,3.14);\n"
+ "struct AnotherDemo : public JustADemo\n"
+ "{\n"
+ "uint8_t byte;\n"
+ "AnotherDemo(uint8_t b = 'E', int p = 1, float v = 0.1) : JustADemo(p,v), byte(b) {}\n"
+ "};\n"
+ "AnotherDemo *another_object = new AnotherDemo('E',42,3.14);\n"
+ "\n"
+ "type summary add --summary-string \"the answer is ${*var.ptr}\" JustADemo\n"
+ "when typing frame variable object you will get \"the answer is 42\"\n"
+ "type summary add --summary-string \"the answer is ${*var.ptr}, and the question is ${var.value}\" JustADemo\n"
+ "when typing frame variable object you will get \"the answer is 42 and the question is 3.14\"\n"
+ "\n"
+ "Alternatively, you could also say\n"
+ "type summary add --summary-string \"${var%V} -> ${*var}\" \"int *\"\n"
+ "and replace the above summary string with\n"
+ "type summary add --summary-string \"the answer is ${var.ptr}, and the question is ${var.value}\" JustADemo\n"
+ "to obtain a similar result\n"
+ "\n"
+ "To add a summary valid for both JustADemo and AnotherDemo you can use the scoping operator, as in:\n"
+ "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes\n"
+ "\n"
+ "This will be used for both variables of type JustADemo and AnotherDemo. To prevent this, change the -C to read -C no\n"
+ "If you do not want pointers to be shown using that summary, you can use the -p option, as in:\n"
+ "type summary add --summary-string \"${var.ptr}, ${var.value},{${var.byte}}\" JustADemo -C yes -p\n"
+ "A similar option -r exists for references.\n"
+ "\n"
+ "If you simply want a one-line summary of the content of your variable, without typing an explicit string to that effect\n"
+ "you can use the -c option, without giving any summary string:\n"
+ "type summary add -c JustADemo\n"
+ "frame variable object\n"
+ "the output being similar to (ptr=0xsomeaddress, value=3.14)\n"
+ "\n"
+ "If you want to display some summary text, but also expand the structure of your object, you can add the -e option, as in:\n"
+ "type summary add -e --summary-string \"*ptr = ${*var.ptr}\" JustADemo\n"
+ "Here the value of the int* is displayed, followed by the standard LLDB sequence of children objects, one per line.\n"
+ "to get an output like:\n"
+ "\n"
+ "*ptr = 42 {\n"
+ " ptr = 0xsomeaddress\n"
+ " value = 3.14\n"
+ "}\n"
+ "\n"
+ "You can also add Python summaries, in which case you will use lldb public API to gather information from your variables"
+ "and elaborate them to a meaningful summary inside a script written in Python. The variable object will be passed to your"
+ "script as an SBValue object. The following example might help you when starting to use the Python summaries feature:\n"
+ "type summary add JustADemo -o \"value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();\"\n"
+ "If you prefer to type your scripts on multiple lines, you will use the -P option and then type your script, ending it with "
+ "the word DONE on a line by itself to mark you're finished editing your code:\n"
+ "(lldb)type summary add JustADemo -P\n"
+ " value = valobj.GetChildMemberWithName('value');\n"
+ " return 'My value is ' + value.GetValue();\n"
+ "DONE\n"
+ "(lldb) <-- type further LLDB commands here\n"
+ );
+}
+
+bool
+CommandObjectTypeSummaryAdd::DoExecute (Args& command, CommandReturnObject &result)
+{
+ if (m_options.m_is_add_script)
+ {
+#ifndef LLDB_DISABLE_PYTHON
+ return Execute_ScriptSummary(command, result);
+#else
+ result.AppendError ("python is disabled");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+#endif
+ }
+
+ return Execute_StringSummary(command, result);
+}
+
+bool
+CommandObjectTypeSummaryAdd::AddSummary(ConstString type_name,
+ TypeSummaryImplSP entry,
+ SummaryFormatType type,
+ std::string category_name,
+ Error* error)
+{
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularSummary)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegexSummary;
+ }
+ }
+
+ if (type == eRegexSummary)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexSummaryNavigator()->Delete(type_name);
+ category->GetRegexSummaryNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else if (type == eNamedSummary)
+ {
+ // system named summaries do not exist (yet?)
+ DataVisualization::NamedSummaryFormats::Add(type_name,entry);
+ return true;
+ }
+ else
+ {
+ category->GetSummaryNavigator()->Add(type_name, entry);
+ return true;
+ }
+}
+
+OptionDefinition
+CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeNone, "Don't show the value, just show the summary, for this type."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { LLDB_OPT_SET_1 , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeNone, "If true, inline all child values into summary string."},
+ { LLDB_OPT_SET_1 , false, "omit-names", 'O', no_argument, NULL, 0, eArgTypeNone, "If true, omit value names in the summary display."},
+ { LLDB_OPT_SET_2 , true, "summary-string", 's', required_argument, NULL, 0, eArgTypeSummaryString, "Summary string used to display text and object contents."},
+ { LLDB_OPT_SET_3, false, "python-script", 'o', required_argument, NULL, 0, eArgTypePythonScript, "Give a one-liner Python script as part of the command."},
+ { LLDB_OPT_SET_3, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction, "Give the name of a Python function to use for this type."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeNone, "Input Python code to use for this type manually."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "expand", 'e', no_argument, NULL, 0, eArgTypeNone, "Expand aggregate data types to show children on separate lines."},
+ { LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, 0, eArgTypeName, "A name for this summary string."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSummaryDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ 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_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& category_sp)
+ {
+ ConstString *name = (ConstString*)param;
+ category_sp->Delete(*name, eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ return true;
+ }
+
+public:
+ CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary delete",
+ "Delete an existing summary style for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeSummaryDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, &typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->Delete(typeCS,
+ eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ bool delete_named = DataVisualization::NamedSummaryFormats::Delete(typeCS);
+
+ if (delete_category || delete_named)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom summary for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSummaryDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectTypeSummaryClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = 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_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->GetSummaryNavigator()->Clear();
+ cate->GetRegexSummaryNavigator()->Clear();
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary clear",
+ "Delete all existing summary styles.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeSummaryClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->Clear(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+ }
+
+ DataVisualization::NamedSummaryFormats::Clear();
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSummaryClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const StringSummaryFormat::SharedPointer& entry);
+bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const StringSummaryFormat::SharedPointer& entry);
+
+class CommandObjectTypeSummaryList;
+
+struct CommandObjectTypeSummaryList_LoopCallbackParam {
+ CommandObjectTypeSummaryList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeSummaryList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ 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.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSummaryList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type summary list",
+ "Show a list of current summary styles.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSummaryList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSummaryList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (DataVisualization::NamedSummaryFormats::GetCount() > 0)
+ {
+ result.GetOutputStream().Printf("Named summaries:\n");
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex);
+ }
+ else
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result);
+ DataVisualization::NamedSummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param);
+ delete param;
+ }
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ CommandObjectTypeSummaryList_LoopCallbackParam* param =
+ (CommandObjectTypeSummaryList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ const char* cate_name = cate->GetName();
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetSummaryNavigator()->LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param_vp);
+
+ if (cate->GetRegexSummaryNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based summaries (slower):\n");
+ cate->GetRegexSummaryNavigator()->LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, param_vp);
+ }
+ return true;
+ }
+
+
+ bool
+ LoopCallback (const char* type,
+ const lldb::TypeSummaryImplSP& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || strcmp(type,regex->GetText()) == 0 || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, ConstString type, const lldb::TypeSummaryImplSP& entry);
+ friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const lldb::TypeSummaryImplSP& entry);
+};
+
+bool
+CommandObjectTypeSummaryList_LoopCallback (
+ void* pt2self,
+ ConstString type,
+ const lldb::TypeSummaryImplSP& entry)
+{
+ CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeRXSummaryList_LoopCallback (
+ void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const lldb::TypeSummaryImplSP& entry)
+{
+ CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+OptionDefinition
+CommandObjectTypeSummaryList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryEnable
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category enable",
+ "Enable a category as a source of formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryEnable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ 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);
+ }
+ else
+ {
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ DataVisualization::Categories::Enable(typeCS);
+ lldb::TypeCategoryImplSP cate;
+ if (DataVisualization::Categories::GetCategory(typeCS, cate) && cate.get())
+ {
+ if (cate->GetCount() == 0)
+ {
+ result.AppendWarning("empty category enabled (typo?)");
+ }
+ }
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category delete",
+ "Delete a category and all associated formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ bool success = true;
+
+ // the order is not relevant here
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ if (!DataVisualization::Categories::Delete(typeCS))
+ success = false; // keep deleting even if we hit an error
+ }
+ if (success)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendError("cannot delete one or more categories\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryDisable
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectTypeCategoryDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category disable",
+ "Disable a category as a source of formatters.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeCategoryDisable ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ 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);
+ }
+ }
+ else
+ {
+ // the order is not relevant here
+ for (int i = argc - 1; i >= 0; i--)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty category name not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ DataVisualization::Categories::Disable(typeCS);
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeCategoryList
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeCategoryList : public CommandObjectParsed
+{
+private:
+
+ struct CommandObjectTypeCategoryList_CallbackParam
+ {
+ CommandReturnObject* result;
+ RegularExpression* regex;
+
+ CommandObjectTypeCategoryList_CallbackParam(CommandReturnObject* res,
+ RegularExpression* rex = NULL) :
+ result(res),
+ regex(rex)
+ {
+ }
+
+ };
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ CommandObjectTypeCategoryList_CallbackParam* param =
+ (CommandObjectTypeCategoryList_CallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+ RegularExpression* regex = param->regex;
+
+ const char* cate_name = cate->GetName();
+
+ if (regex == NULL || strcmp(cate_name, regex->GetText()) == 0 || regex->Execute(cate_name))
+ result->GetOutputStream().Printf("Category %s is%s enabled\n",
+ cate_name,
+ (cate->IsEnabled() ? "" : " not"));
+ return true;
+ }
+public:
+ CommandObjectTypeCategoryList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type category list",
+ "Provide a list of all existing categories.",
+ NULL)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeCategoryList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ RegularExpression* regex = NULL;
+
+ if (argc == 0)
+ ;
+ else if (argc == 1)
+ regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ else
+ {
+ result.AppendErrorWithFormat ("%s takes 0 or one arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ CommandObjectTypeCategoryList_CallbackParam param(&result,
+ regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, &param);
+
+ if (regex)
+ delete regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+
+class CommandObjectTypeFilterList;
+
+struct CommandObjectTypeFilterList_LoopCallbackParam {
+ CommandObjectTypeFilterList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeFilterList_LoopCallbackParam(CommandObjectTypeFilterList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeFilterList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ 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.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeFilterList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter list",
+ "Show a list of current filters.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeFilterList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeFilterList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeFilterList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ const char* cate_name = cate->GetName();
+
+ CommandObjectTypeFilterList_LoopCallbackParam* param =
+ (CommandObjectTypeFilterList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetFilterNavigator()->LoopThrough(CommandObjectTypeFilterList_LoopCallback, param_vp);
+
+ if (cate->GetRegexFilterNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based filters (slower):\n");
+ cate->GetRegexFilterNavigator()->LoopThrough(CommandObjectTypeFilterRXList_LoopCallback, param_vp);
+ }
+
+ return true;
+ }
+
+ bool
+ LoopCallback (const char* type,
+ const SyntheticChildren::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeFilterList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+ friend bool CommandObjectTypeFilterRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+};
+
+bool
+CommandObjectTypeFilterList_LoopCallback (void* pt2self,
+ ConstString type,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeFilterRXList_LoopCallback (void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeFilterList_LoopCallbackParam* param = (CommandObjectTypeFilterList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+
+OptionDefinition
+CommandObjectTypeFilterList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+
+class CommandObjectTypeSynthList;
+
+struct CommandObjectTypeSynthList_LoopCallbackParam {
+ CommandObjectTypeSynthList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ RegularExpression* cate_regex;
+ CommandObjectTypeSynthList_LoopCallbackParam(CommandObjectTypeSynthList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL,
+ RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
+};
+
+class CommandObjectTypeSynthList : public CommandObjectParsed
+{
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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 'w':
+ m_category_regex = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_category_regex = "";
+ }
+
+ 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.
+
+ std::string m_category_regex;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSynthList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic list",
+ "Show a list of current synthetic providers.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatOptional;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSynthList ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSynthList_LoopCallbackParam *param;
+ RegularExpression* cate_regex =
+ m_options.m_category_regex.empty() ? NULL :
+ new RegularExpression(m_options.m_category_regex.c_str());
+
+ if (argc == 1)
+ {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,regex,cate_regex);
+ }
+ else
+ param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex);
+
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback,param);
+
+ if (cate_regex)
+ delete cate_regex;
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ static bool
+ PerCategoryCallback(void* param_vp,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+
+ CommandObjectTypeSynthList_LoopCallbackParam* param =
+ (CommandObjectTypeSynthList_LoopCallbackParam*)param_vp;
+ CommandReturnObject* result = param->result;
+
+ const char* cate_name = cate->GetName();
+
+ // if the category is disabled or empty and there is no regex, just skip it
+ if ((cate->IsEnabled() == false || cate->GetCount(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth) == 0) && param->cate_regex == NULL)
+ return true;
+
+ // if we have a regex and this category does not match it, just skip it
+ if(param->cate_regex != NULL && strcmp(cate_name,param->cate_regex->GetText()) != 0 && param->cate_regex->Execute(cate_name) == false)
+ return true;
+
+ result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
+ cate_name,
+ (cate->IsEnabled() ? "enabled" : "disabled"));
+
+ cate->GetSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp);
+
+ if (cate->GetRegexSyntheticNavigator()->GetCount() > 0)
+ {
+ result->GetOutputStream().Printf("Regex-based synthetic providers (slower):\n");
+ cate->GetRegexSyntheticNavigator()->LoopThrough(CommandObjectTypeSynthRXList_LoopCallback, param_vp);
+ }
+
+ return true;
+ }
+
+ bool
+ LoopCallback (const char* type,
+ const SyntheticChildren::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
+ return true;
+ }
+
+ friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, ConstString type, const SyntheticChildren::SharedPointer& entry);
+ friend bool CommandObjectTypeSynthRXList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SyntheticChildren::SharedPointer& entry);
+};
+
+bool
+CommandObjectTypeSynthList_LoopCallback (void* pt2self,
+ ConstString type,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type.AsCString(), entry, param->regex, param->result);
+}
+
+bool
+CommandObjectTypeSynthRXList_LoopCallback (void* pt2self,
+ lldb::RegularExpressionSP regex,
+ const SyntheticChildren::SharedPointer& entry)
+{
+ CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
+}
+
+
+OptionDefinition
+CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFilterDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ 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_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ ConstString *name = (ConstString*)param;
+ return cate->Delete(*name, eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter);
+ }
+
+public:
+ CommandObjectTypeFilterDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter delete",
+ "Delete an existing filter for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeFilterDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->GetFilterNavigator()->Delete(typeCS);
+ delete_category = category->GetRegexFilterNavigator()->Delete(typeCS) || delete_category;
+
+ if (delete_category)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeFilterDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthDelete : public CommandObjectParsed
+{
+private:
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = false;
+ m_category = "default";
+ }
+
+ 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_delete_all;
+ std::string m_category;
+
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ ConstString* name = (ConstString*)param;
+ return cate->Delete(*name, eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth);
+ }
+
+public:
+ CommandObjectTypeSynthDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic delete",
+ "Delete an existing synthetic provider for a type.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ }
+
+ ~CommandObjectTypeSynthDelete ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc != 1)
+ {
+ result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* typeA = command.GetArgumentAtIndex(0);
+ ConstString typeCS(typeA);
+
+ if (!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_delete_all)
+ {
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, (void*)&typeCS);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ bool delete_category = category->GetSyntheticNavigator()->Delete(typeCS);
+ delete_category = category->GetRegexSyntheticNavigator()->Delete(typeCS) || delete_category;
+
+ if (delete_category)
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+};
+
+OptionDefinition
+CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Delete from every category."},
+ { LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFilterClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeFilterClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = 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_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->Clear(eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter);
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeFilterClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter clear",
+ "Delete all existing filters.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeFilterClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->GetFilterNavigator()->Clear();
+ category->GetRegexFilterNavigator()->Clear();
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeFilterClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+//-------------------------------------------------------------------------
+// CommandObjectTypeSynthClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSynthClear : public CommandObjectParsed
+{
+private:
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ virtual
+ ~CommandOptions (){}
+
+ virtual Error
+ SetOptionValue (uint32_t option_idx, const char *option_arg)
+ {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_delete_all = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_delete_all = 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_delete_all;
+ bool m_delete_named;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ static bool
+ PerCategoryCallback(void* param,
+ const lldb::TypeCategoryImplSP& cate)
+ {
+ cate->Clear(eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth);
+ return true;
+
+ }
+
+public:
+ CommandObjectTypeSynthClear (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic clear",
+ "Delete all existing synthetic providers.",
+ NULL),
+ m_options(interpreter)
+ {
+ }
+
+ ~CommandObjectTypeSynthClear ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+
+ if (m_options.m_delete_all)
+ DataVisualization::Categories::LoopThrough(PerCategoryCallback, NULL);
+
+ else
+ {
+ lldb::TypeCategoryImplSP category;
+ if (command.GetArgumentCount() > 0)
+ {
+ const char* cat_name = command.GetArgumentAtIndex(0);
+ ConstString cat_nameCS(cat_name);
+ DataVisualization::Categories::GetCategory(cat_nameCS, category);
+ }
+ else
+ DataVisualization::Categories::GetCategory(ConstString(NULL), category);
+ category->GetSyntheticNavigator()->Clear();
+ category->GetRegexSyntheticNavigator()->Clear();
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSynthClear::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeNone, "Clear every category."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// TypeSynthAddInputReader
+//-------------------------------------------------------------------------
+
+static const char *g_synth_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "You must define a Python class with these methods:\n"
+ " def __init__(self, valobj, dict):\n"
+ " def num_children(self):\n"
+ " def get_child_at_index(self, index):\n"
+ " def get_child_index(self, name):\n"
+ "Optionally, you can also define a method:\n"
+ " def update(self):\n"
+ "if your synthetic provider is holding on to any per-object state variables (currently, this is not implemented because of the way LLDB handles instances of SBValue and you should not rely on object persistence and per-object state)\n"
+ "class synthProvider:";
+
+class TypeSynthAddInputReader : public InputReaderEZ
+{
+public:
+ TypeSynthAddInputReader(Debugger& debugger) :
+ InputReaderEZ(debugger)
+ {}
+
+ virtual
+ ~TypeSynthAddInputReader()
+ {
+ }
+
+ virtual void ActivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_synth_addreader_instructions);
+ if (data.reader.GetPrompt())
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+
+ virtual void ReactivateHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void GotTokenHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ if (data.bytes && data.bytes_len && data.baton)
+ {
+ ((SynthAddOptions*)data.baton)->m_user_source.AppendString(data.bytes, data.bytes_len);
+ }
+ if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", data.reader.GetPrompt());
+ out_stream->Flush();
+ }
+ }
+ virtual void InterruptHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ bool batch_mode = data.GetBatchMode();
+ data.reader.SetIsDone (true);
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ virtual void EOFHandler(HandlerData& data)
+ {
+ data.reader.SetIsDone (true);
+ }
+ virtual void DoneHandler(HandlerData& data)
+ {
+ StreamSP out_stream = data.GetOutStream();
+ SynthAddOptions *options_ptr = ((SynthAddOptions*)data.baton);
+ if (!options_ptr)
+ {
+ out_stream->Printf ("internal synchronization data missing.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ SynthAddOptions::SharedPointer options(options_ptr); // this will ensure that we get rid of the pointer when going out of scope
+
+ ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (!interpreter)
+ {
+ out_stream->Printf ("no script interpreter.\n");
+ out_stream->Flush();
+ return;
+ }
+ std::string class_name_str;
+ if (!interpreter->GenerateTypeSynthClass (options->m_user_source,
+ class_name_str))
+ {
+ out_stream->Printf ("unable to generate a class.\n");
+ out_stream->Flush();
+ return;
+ }
+ if (class_name_str.empty())
+ {
+ out_stream->Printf ("unable to obtain a proper name for the class.\n");
+ out_stream->Flush();
+ return;
+ }
+
+ // everything should be fine now, let's add the synth provider class
+
+ SyntheticChildrenSP synth_provider;
+ synth_provider.reset(new ScriptedSyntheticChildren(SyntheticChildren::Flags().SetCascades(options->m_cascade).
+ SetSkipPointers(options->m_skip_pointers).
+ SetSkipReferences(options->m_skip_references),
+ class_name_str.c_str()));
+
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(options->m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < options->m_target_types.GetSize(); i++)
+ {
+ const char *type_name = options->m_target_types.GetStringAtIndex(i);
+ ConstString typeCS(type_name);
+ if (typeCS)
+ {
+ if (!CommandObjectTypeSynthAdd::AddSynth(typeCS,
+ synth_provider,
+ options->m_regex ? CommandObjectTypeSynthAdd::eRegexSynth : CommandObjectTypeSynthAdd::eRegularSynth,
+ options->m_category,
+ &error))
+ {
+ out_stream->Printf("%s\n", error.AsCString());
+ out_stream->Flush();
+ return;
+ }
+ }
+ else
+ {
+ out_stream->Printf ("invalid type name.\n");
+ out_stream->Flush();
+ return;
+ }
+ }
+ }
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (TypeSynthAddInputReader);
+};
+
+void
+CommandObjectTypeSynthAdd::CollectPythonScript (SynthAddOptions *options,
+ CommandReturnObject &result)
+{
+ InputReaderSP reader_sp (new TypeSynthAddInputReader(m_interpreter.GetDebugger()));
+ if (reader_sp && options)
+ {
+
+ InputReaderEZ::InitializationParameters ipr;
+
+ Error err (reader_sp->Initialize (ipr.SetBaton(options).SetPrompt(" ")));
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+bool
+CommandObjectTypeSynthAdd::Execute_HandwritePython (Args& command, CommandReturnObject &result)
+{
+ SynthAddOptions *options = new SynthAddOptions ( m_options.m_skip_pointers,
+ m_options.m_skip_references,
+ m_options.m_cascade,
+ m_options.m_regex,
+ m_options.m_category);
+
+ const size_t argc = command.GetArgumentCount();
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ if (typeA && *typeA)
+ options->m_target_types << typeA;
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ CollectPythonScript(options,result);
+ return result.Succeeded();
+}
+
+bool
+CommandObjectTypeSynthAdd::Execute_PythonClass (Args& command, CommandReturnObject &result)
+{
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_class_name.empty() && !m_options.m_input_python)
+ {
+ result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ SyntheticChildrenSP entry;
+
+ ScriptedSyntheticChildren* impl = new ScriptedSyntheticChildren(SyntheticChildren::Flags().
+ SetCascades(m_options.m_cascade).
+ SetSkipPointers(m_options.m_skip_pointers).
+ SetSkipReferences(m_options.m_skip_references),
+ m_options.m_class_name.c_str());
+
+ entry.reset(impl);
+
+ ScriptInterpreter *interpreter = m_interpreter.GetScriptInterpreter();
+
+ if (interpreter && interpreter->CheckObjectExists(impl->GetPythonClassName()) == false)
+ result.AppendWarning("The provided class does not exist - please define it before attempting to use this synthetic provider");
+
+ // now I have a valid provider, let's add it to every type
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ {
+ if (!AddSynth(typeCS,
+ entry,
+ m_options.m_regex ? eRegexSynth : eRegularSynth,
+ m_options.m_category,
+ &error))
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+}
+
+CommandObjectTypeSynthAdd::CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type synthetic add",
+ "Add a new synthetic provider for a type.",
+ NULL),
+ m_options (interpreter)
+{
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+}
+
+bool
+CommandObjectTypeSynthAdd::AddSynth(ConstString type_name,
+ SyntheticChildrenSP entry,
+ SynthFormatType type,
+ std::string category_name,
+ Error* error)
+{
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularSynth)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegularSynth;
+ }
+ }
+
+ if (category->AnyMatches(type_name,
+ eFormatCategoryItemFilter | eFormatCategoryItemRegexFilter,
+ false))
+ {
+ if (error)
+ error->SetErrorStringWithFormat("cannot add synthetic for type %s when filter is defined in same category!", type_name.AsCString());
+ return false;
+ }
+
+ if (type == eRegexSynth)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexSyntheticNavigator()->Delete(type_name);
+ category->GetRegexSyntheticNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else
+ {
+ category->GetSyntheticNavigator()->Add(type_name, entry);
+ return true;
+ }
+}
+
+bool
+CommandObjectTypeSynthAdd::DoExecute (Args& command, CommandReturnObject &result)
+{
+ if (m_options.handwrite_python)
+ return Execute_HandwritePython(command, result);
+ else if (m_options.is_class_based)
+ return Execute_PythonClass(command, result);
+ else
+ {
+ result.AppendError("must either provide a children list, a Python class name, or use -P and type a Python class line-by-line");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+}
+
+OptionDefinition
+CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_2, false, "python-class", 'l', required_argument, NULL, 0, eArgTypePythonClass, "Use this Python class to produce synthetic children."},
+ { LLDB_OPT_SET_3, false, "input-python", 'P', no_argument, NULL, 0, eArgTypeNone, "Type Python code to generate a class that provides synthetic children."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeFilterAdd : public CommandObjectParsed
+{
+
+private:
+
+ class CommandOptions : public Options
+ {
+ typedef std::vector<std::string> option_vector;
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter)
+ {
+ }
+
+ 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;
+ bool success;
+
+ switch (short_option)
+ {
+ case 'C':
+ m_cascade = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for cascade: %s", option_arg);
+ break;
+ case 'c':
+ m_expr_paths.push_back(option_arg);
+ has_child_list = true;
+ break;
+ case 'p':
+ m_skip_pointers = true;
+ break;
+ case 'r':
+ m_skip_references = true;
+ break;
+ case 'w':
+ m_category = std::string(option_arg);
+ break;
+ case 'x':
+ m_regex = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_cascade = true;
+ m_skip_pointers = false;
+ m_skip_references = false;
+ m_category = "default";
+ m_expr_paths.clear();
+ has_child_list = false;
+ m_regex = 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_cascade;
+ bool m_skip_references;
+ bool m_skip_pointers;
+ bool m_input_python;
+ option_vector m_expr_paths;
+ std::string m_category;
+
+ bool has_child_list;
+
+ bool m_regex;
+
+ typedef option_vector::iterator ExpressionPathsIterator;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ enum FilterFormatType
+ {
+ eRegularFilter,
+ eRegexFilter
+ };
+
+ bool
+ AddFilter(ConstString type_name,
+ SyntheticChildrenSP entry,
+ FilterFormatType type,
+ std::string category_name,
+ Error* error)
+ {
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(category_name.c_str()), category);
+
+ if (type == eRegularFilter)
+ {
+ std::string type_name_str(type_name.GetCString());
+ if (type_name_str.compare(type_name_str.length() - 2, 2, "[]") == 0)
+ {
+ type_name_str.resize(type_name_str.length()-2);
+ if (type_name_str.back() != ' ')
+ type_name_str.append(" \\[[0-9]+\\]");
+ else
+ type_name_str.append("\\[[0-9]+\\]");
+ type_name.SetCString(type_name_str.c_str());
+ type = eRegexFilter;
+ }
+ }
+
+ if (category->AnyMatches(type_name,
+ eFormatCategoryItemSynth | eFormatCategoryItemRegexSynth,
+ false))
+ {
+ if (error)
+ error->SetErrorStringWithFormat("cannot add filter for type %s when synthetic is defined in same category!", type_name.AsCString());
+ return false;
+ }
+
+ if (type == eRegexFilter)
+ {
+ RegularExpressionSP typeRX(new RegularExpression());
+ if (!typeRX->Compile(type_name.GetCString()))
+ {
+ if (error)
+ error->SetErrorString("regex format error (maybe this is not really a regex?)");
+ return false;
+ }
+
+ category->GetRegexFilterNavigator()->Delete(type_name);
+ category->GetRegexFilterNavigator()->Add(typeRX, entry);
+
+ return true;
+ }
+ else
+ {
+ category->GetFilterNavigator()->Add(type_name, entry);
+ return true;
+ }
+ }
+
+
+public:
+
+ CommandObjectTypeFilterAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "type filter add",
+ "Add a new filter for a type.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (type_arg);
+
+ SetHelpLong(
+ "Some examples of using this command.\n"
+ "We use as reference the following snippet of code:\n"
+ "\n"
+ "class Foo {;\n"
+ " int a;\n"
+ " int b;\n"
+ " int c;\n"
+ " int d;\n"
+ " int e;\n"
+ " int f;\n"
+ " int g;\n"
+ " int h;\n"
+ " int i;\n"
+ "} \n"
+ "Typing:\n"
+ "type filter add --child a --child g Foo\n"
+ "frame variable a_foo\n"
+ "will produce an output where only a and g are displayed\n"
+ "Other children of a_foo (b,c,d,e,f,h and i) are available by asking for them, as in:\n"
+ "frame variable a_foo.b a_foo.c ... a_foo.i\n"
+ "\n"
+ "Use option --raw to frame variable prevails on the filter\n"
+ "frame variable a_foo --raw\n"
+ "shows all the children of a_foo (a thru i) as if no filter was defined\n"
+ );
+ }
+
+ ~CommandObjectTypeFilterAdd ()
+ {
+ }
+
+protected:
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ if (argc < 1)
+ {
+ result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_expr_paths.size() == 0)
+ {
+ result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ SyntheticChildrenSP entry;
+
+ TypeFilterImpl* impl = new TypeFilterImpl(SyntheticChildren::Flags().SetCascades(m_options.m_cascade).
+ SetSkipPointers(m_options.m_skip_pointers).
+ SetSkipReferences(m_options.m_skip_references));
+
+ entry.reset(impl);
+
+ // go through the expression paths
+ CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
+
+ for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
+ impl->AddExpressionPath(*begin);
+
+
+ // now I have a valid provider, let's add it to every type
+
+ lldb::TypeCategoryImplSP category;
+ DataVisualization::Categories::GetCategory(ConstString(m_options.m_category.c_str()), category);
+
+ Error error;
+
+ for (size_t i = 0; i < argc; i++)
+ {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ {
+ if (!AddFilter(typeCS,
+ entry,
+ m_options.m_regex ? eRegexFilter : eRegularFilter,
+ m_options.m_category,
+ &error))
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeFilterAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade through typedef chains."},
+ { LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for pointers-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeNone, "Don't use this format for references-to-type objects."},
+ { LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
+ { LLDB_OPT_SET_ALL, false, "child", 'c', required_argument, NULL, 0, eArgTypeExpressionPath, "Include this expression path in the synthetic view."},
+ { LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeNone, "Type names are actually regular expressions."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+class CommandObjectTypeFormat : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeFormat (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type format",
+ "A set of commands for editing variable value display options",
+ "type format [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFormatAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeFormat ()
+ {
+ }
+};
+
+#ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeSynth : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSynth (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type synthetic",
+ "A set of commands for operating on synthetic type representations",
+ "type synthetic [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSynthAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSynth ()
+ {
+ }
+};
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
+
+class CommandObjectTypeFilter : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeFilter (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type filter",
+ "A set of commands for operating on type filters",
+ "type synthetic [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFilterAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFilterClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFilterDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFilterList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeFilter ()
+ {
+ }
+};
+
+class CommandObjectTypeCategory : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeCategory (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type category",
+ "A set of commands for operating on categories",
+ "type category [<sub-command-options>] ")
+ {
+ LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTypeCategoryEnable (interpreter)));
+ LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTypeCategoryDisable (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeCategoryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeCategoryList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeCategory ()
+ {
+ }
+};
+
+class CommandObjectTypeSummary : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSummary (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type summary",
+ "A set of commands for editing variable summary display options",
+ "type summary [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSummary ()
+ {
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectType
+//-------------------------------------------------------------------------
+
+CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type",
+ "A set of commands for operating on the type system",
+ "type [<sub-command-options>]")
+{
+ LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter)));
+ LoadSubCommand ("filter", CommandObjectSP (new CommandObjectTypeFilter (interpreter)));
+ LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter)));
+ LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter)));
+#ifndef LLDB_DISABLE_PYTHON
+ LoadSubCommand ("synthetic", CommandObjectSP (new CommandObjectTypeSynth (interpreter)));
+#endif
+}
+
+
+CommandObjectType::~CommandObjectType ()
+{
+}
+
+
diff --git a/source/Commands/CommandObjectType.h b/source/Commands/CommandObjectType.h
new file mode 100644
index 000000000000..c796902cf3bd
--- /dev/null
+++ b/source/Commands/CommandObjectType.h
@@ -0,0 +1,37 @@
+//===-- CommandObjectType.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_CommandObjectType_h_
+#define liblldb_CommandObjectType_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+
+namespace lldb_private {
+
+class CommandObjectType : public CommandObjectMultiword
+{
+public:
+ CommandObjectType (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectType ();
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectType_h_
diff --git a/source/Commands/CommandObjectVersion.cpp b/source/Commands/CommandObjectVersion.cpp
new file mode 100644
index 000000000000..2d950a89c9b3
--- /dev/null
+++ b/source/Commands/CommandObjectVersion.cpp
@@ -0,0 +1,53 @@
+//===-- CommandObjectVersion.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 "CommandObjectVersion.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectVersion
+//-------------------------------------------------------------------------
+
+CommandObjectVersion::CommandObjectVersion (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter, "version", "Show version of LLDB debugger.", "version")
+{
+}
+
+CommandObjectVersion::~CommandObjectVersion ()
+{
+}
+
+bool
+CommandObjectVersion::DoExecute (Args& args, CommandReturnObject &result)
+{
+ if (args.GetArgumentCount() == 0)
+ {
+ result.AppendMessageWithFormat ("%s\n", lldb_private::GetVersion());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendError("the version command takes no arguments.");
+ result.SetStatus (eReturnStatusFailed);
+ }
+ return true;
+}
+
diff --git a/source/Commands/CommandObjectVersion.h b/source/Commands/CommandObjectVersion.h
new file mode 100644
index 000000000000..1fdbed60c65d
--- /dev/null
+++ b/source/Commands/CommandObjectVersion.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectVersion.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_CommandObjectVersion_h_
+#define liblldb_CommandObjectVersion_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectVersion
+//-------------------------------------------------------------------------
+
+class CommandObjectVersion : public CommandObjectParsed
+{
+public:
+
+ CommandObjectVersion (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectVersion ();
+
+protected:
+ virtual bool
+ DoExecute (Args& args,
+ CommandReturnObject &result);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectVersion_h_
diff --git a/source/Commands/CommandObjectWatchpoint.cpp b/source/Commands/CommandObjectWatchpoint.cpp
new file mode 100644
index 000000000000..6f70f39c1c71
--- /dev/null
+++ b/source/Commands/CommandObjectWatchpoint.cpp
@@ -0,0 +1,1394 @@
+//===-- CommandObjectWatchpoint.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 "CommandObjectWatchpoint.h"
+#include "CommandObjectWatchpointCommand.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/WatchpointList.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Target.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+AddWatchpointDescription(Stream *s, Watchpoint *wp, lldb::DescriptionLevel level)
+{
+ s->IndentMore();
+ wp->GetDescription(s, level);
+ s->IndentLess();
+ s->EOL();
+}
+
+static bool
+CheckTargetForWatchpointOperations(Target *target, CommandReturnObject &result)
+{
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No existing target or watchpoints.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ bool process_is_valid = target->GetProcessSP() && target->GetProcessSP()->IsAlive();
+ if (!process_is_valid)
+ {
+ result.AppendError ("Thre's no process or it is not alive.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ // Target passes our checks, return true.
+ return true;
+}
+
+// FIXME: This doesn't seem to be the right place for this functionality.
+#include "llvm/ADT/StringRef.h"
+static inline void StripLeadingSpaces(llvm::StringRef &Str)
+{
+ while (!Str.empty() && isspace(Str[0]))
+ Str = Str.substr(1);
+}
+
+// Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
+static const char* RSA[4] = { "-", "to", "To", "TO" };
+
+// Return the index to RSA if found; otherwise -1 is returned.
+static int32_t
+WithRSAIndex(llvm::StringRef &Arg)
+{
+
+ uint32_t i;
+ for (i = 0; i < 4; ++i)
+ if (Arg.find(RSA[i]) != llvm::StringRef::npos)
+ return i;
+ return -1;
+}
+
+// Return true if wp_ids is successfully populated with the watch ids.
+// False otherwise.
+bool
+CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(Target *target, Args &args, std::vector<uint32_t> &wp_ids)
+{
+ // Pre-condition: args.GetArgumentCount() > 0.
+ if (args.GetArgumentCount() == 0)
+ {
+ if (target == NULL)
+ return false;
+ WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
+ if (watch_sp)
+ {
+ wp_ids.push_back(watch_sp->GetID());
+ return true;
+ }
+ else
+ return false;
+ }
+
+ llvm::StringRef Minus("-");
+ std::vector<llvm::StringRef> StrRefArgs;
+ std::pair<llvm::StringRef, llvm::StringRef> Pair;
+ size_t i;
+ int32_t idx;
+ // Go through the argments and make a canonical form of arg list containing
+ // only numbers with possible "-" in between.
+ for (i = 0; i < args.GetArgumentCount(); ++i) {
+ llvm::StringRef Arg(args.GetArgumentAtIndex(i));
+ if ((idx = WithRSAIndex(Arg)) == -1) {
+ StrRefArgs.push_back(Arg);
+ continue;
+ }
+ // The Arg contains the range specifier, split it, then.
+ Pair = Arg.split(RSA[idx]);
+ if (!Pair.first.empty())
+ StrRefArgs.push_back(Pair.first);
+ StrRefArgs.push_back(Minus);
+ if (!Pair.second.empty())
+ StrRefArgs.push_back(Pair.second);
+ }
+ // Now process the canonical list and fill in the vector of uint32_t's.
+ // If there is any error, return false and the client should ignore wp_ids.
+ uint32_t beg, end, id;
+ size_t size = StrRefArgs.size();
+ bool in_range = false;
+ for (i = 0; i < size; ++i) {
+ llvm::StringRef Arg = StrRefArgs[i];
+ if (in_range) {
+ // Look for the 'end' of the range. Note StringRef::getAsInteger()
+ // returns true to signify error while parsing.
+ if (Arg.getAsInteger(0, end))
+ return false;
+ // Found a range! Now append the elements.
+ for (id = beg; id <= end; ++id)
+ wp_ids.push_back(id);
+ in_range = false;
+ continue;
+ }
+ if (i < (size - 1) && StrRefArgs[i+1] == Minus) {
+ if (Arg.getAsInteger(0, beg))
+ return false;
+ // Turn on the in_range flag, we are looking for end of range next.
+ ++i; in_range = true;
+ continue;
+ }
+ // Otherwise, we have a simple ID. Just append it.
+ if (Arg.getAsInteger(0, beg))
+ return false;
+ wp_ids.push_back(beg);
+ }
+ // It is an error if after the loop, we're still in_range.
+ if (in_range)
+ return false;
+
+ return true; // Success!
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointList
+//-------------------------------------------------------------------------
+#pragma mark List
+
+class CommandObjectWatchpointList : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint list",
+ "List all watchpoints at configurable levels of detail.",
+ NULL),
+ m_options(interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointList () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options(interpreter),
+ m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to brief descriptions
+ {
+ }
+
+ 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 'b':
+ m_level = lldb::eDescriptionLevelBrief;
+ break;
+ case 'f':
+ m_level = lldb::eDescriptionLevelFull;
+ break;
+ case 'v':
+ m_level = lldb::eDescriptionLevelVerbose;
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_level = lldb::eDescriptionLevelFull;
+ }
+
+ 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.
+
+ lldb::DescriptionLevel m_level;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (target == NULL)
+ {
+ result.AppendError ("Invalid target. No current target or watchpoints.");
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ if (target->GetProcessSP() && target->GetProcessSP()->IsAlive())
+ {
+ uint32_t num_supported_hardware_watchpoints;
+ Error error = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints);
+ if (error.Success())
+ result.AppendMessageWithFormat("Number of supported hardware watchpoints: %u\n",
+ num_supported_hardware_watchpoints);
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendMessage("No watchpoints currently set.");
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+ Stream &output_stream = result.GetOutputStream();
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; show info about all currently set watchpoints.
+ result.AppendMessage ("Current watchpoints:");
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ Watchpoint *wp = watchpoints.GetByIndex(i).get();
+ AddWatchpointDescription(&output_stream, wp, m_options.m_level);
+ }
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; enable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get();
+ if (wp)
+ AddWatchpointDescription(&output_stream, wp, m_options.m_level);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointList::Options
+//-------------------------------------------------------------------------
+#pragma mark List::CommandOptions
+OptionDefinition
+CommandObjectWatchpointList::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "brief", 'b', no_argument, NULL, 0, eArgTypeNone,
+ "Give a brief description of the watchpoint (no location info)."},
+
+ { LLDB_OPT_SET_2, false, "full", 'f', no_argument, NULL, 0, eArgTypeNone,
+ "Give a full description of the watchpoint and its locations."},
+
+ { LLDB_OPT_SET_3, false, "verbose", 'v', no_argument, NULL, 0, eArgTypeNone,
+ "Explain everything we know about the watchpoint (for debugging debugger bugs)." },
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointEnable
+//-------------------------------------------------------------------------
+#pragma mark Enable
+
+class CommandObjectWatchpointEnable : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointEnable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "enable",
+ "Enable the specified disabled watchpoint(s). If no watchpoints are specified, enable all of them.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointEnable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be enabled.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; enable all currently set watchpoints.
+ target->EnableAllWatchpoints();
+ result.AppendMessageWithFormat("All watchpoints enabled. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; enable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->EnableWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointDisable
+//-------------------------------------------------------------------------
+#pragma mark Disable
+
+class CommandObjectWatchpointDisable : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointDisable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint disable",
+ "Disable the specified watchpoint(s) without removing it/them. If no watchpoints are specified, disable them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointDisable () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be disabled.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ // No watchpoint selected; disable all currently set watchpoints.
+ if (target->DisableAllWatchpoints())
+ {
+ result.AppendMessageWithFormat("All watchpoints disabled. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError("Disable all watchpoints failed\n");
+ result.SetStatus(eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ // Particular watchpoints selected; disable them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->DisableWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointDelete
+//-------------------------------------------------------------------------
+#pragma mark Delete
+
+class CommandObjectWatchpointDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed(interpreter,
+ "watchpoint delete",
+ "Delete the specified watchpoint(s). If no watchpoints are specified, delete them all.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be deleted.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ if (!m_interpreter.Confirm("About to delete all watchpoints, do you want to do that?", true))
+ {
+ result.AppendMessage("Operation cancelled...");
+ }
+ else
+ {
+ target->RemoveAllWatchpoints();
+ result.AppendMessageWithFormat("All watchpoints removed. (%lu watchpoints)\n", num_watchpoints);
+ }
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; delete them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->RemoveWatchpointByID(wp_ids[i]))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints deleted.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointIgnore
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointIgnore : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointIgnore (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint ignore",
+ "Set ignore count on the specified watchpoint(s). If no watchpoints are specified, set them all.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back(arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointIgnore () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_ignore_count (0)
+ {
+ }
+
+ 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_ignore_count = Args::StringToUInt32(option_arg, UINT32_MAX, 0);
+ if (m_ignore_count == UINT32_MAX)
+ error.SetErrorStringWithFormat ("invalid ignore count '%s'", option_arg);
+ }
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_ignore_count = 0;
+ }
+
+ 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.
+
+ uint32_t m_ignore_count;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be ignored.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ target->IgnoreAllWatchpoints(m_options.m_ignore_count);
+ result.AppendMessageWithFormat("All watchpoints ignored. (%lu watchpoints)\n", num_watchpoints);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; ignore them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count))
+ ++count;
+ result.AppendMessageWithFormat("%d watchpoints ignored.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Ignore::CommandOptions
+OptionDefinition
+CommandObjectWatchpointIgnore::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', required_argument, NULL, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." },
+ { 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointModify
+//-------------------------------------------------------------------------
+#pragma mark Modify
+
+class CommandObjectWatchpointModify : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointModify (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint modify",
+ "Modify the options on a watchpoint or set of watchpoints in the executable. "
+ "If no watchpoint is specified, act on the last created watchpoint. "
+ "Passing an empty argument clears the modification.",
+ NULL),
+ m_options (interpreter)
+ {
+ CommandArgumentEntry arg;
+ CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID, eArgTypeWatchpointIDRange);
+ // Add the entry for the first argument for this command to the object's arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointModify () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_condition (),
+ m_condition_passed (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 'c':
+ if (option_arg != NULL)
+ m_condition.assign (option_arg);
+ else
+ m_condition.clear();
+ m_condition_passed = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_condition.clear();
+ m_condition_passed = 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.
+
+ std::string m_condition;
+ bool m_condition_passed;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ if (!CheckTargetForWatchpointOperations(target, result))
+ return false;
+
+ Mutex::Locker locker;
+ target->GetWatchpointList().GetListMutex(locker);
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError("No watchpoints exist to be modified.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ // Particular watchpoints selected; set condition on them.
+ std::vector<uint32_t> wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ int count = 0;
+ const size_t size = wp_ids.size();
+ for (size_t i = 0; i < size; ++i)
+ {
+ WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
+ if (wp_sp)
+ {
+ wp_sp->SetCondition(m_options.m_condition.c_str());
+ ++count;
+ }
+ }
+ result.AppendMessageWithFormat("%d watchpoints modified.\n",count);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+};
+
+#pragma mark Modify::CommandOptions
+OptionDefinition
+CommandObjectWatchpointModify::CommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "condition", 'c', required_argument, NULL, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true."},
+{ 0, false, NULL, 0 , 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSetVariable
+//-------------------------------------------------------------------------
+#pragma mark SetVariable
+
+class CommandObjectWatchpointSetVariable : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointSetVariable (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "watchpoint set variable",
+ "Set a watchpoint on a variable. "
+ "Use the '-w' option to specify the type of watchpoint and "
+ "the '-x' option to specify the byte size to watch for. "
+ "If no '-w' option is specified, it defaults to write. "
+ "If no '-x' option is specified, it defaults to the variable's "
+ "byte size. "
+ "Note that there are limited hardware resources for watchpoints. "
+ "If watchpoint setting fails, consider disable/delete existing ones "
+ "to free up resources.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_option_watchpoint ()
+ {
+ SetHelpLong(
+ "Examples: \n\
+ \n\
+ watchpoint set variable -w read_wriate my_global_var \n\
+ # Watch my_global_var for read/write access, with the region to watch corresponding to the byte size of the data type.\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData var_name_arg;
+
+ // Define the only variant of this arg.
+ var_name_arg.arg_type = eArgTypeVarName;
+ var_name_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push the variant into the argument entry.
+ arg.push_back (var_name_arg);
+
+ // Push the data for the only argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Absorb the '-w' and '-x' options into our option group.
+ m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+ virtual
+ ~CommandObjectWatchpointSetVariable () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ static size_t GetVariableCallback (void *baton,
+ const char *name,
+ VariableList &variable_list)
+ {
+ Target *target = static_cast<Target *>(baton);
+ if (target)
+ {
+ return target->GetImages().FindGlobalVariables (ConstString(name),
+ true,
+ UINT32_MAX,
+ variable_list);
+ }
+ return 0;
+ }
+
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ // If no argument is present, issue an error message. There's no way to set a watchpoint.
+ if (command.GetArgumentCount() <= 0)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify your program variable to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // If no '-w' is specified, default to '-w write'.
+ if (!m_option_watchpoint.watch_type_specified)
+ {
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ }
+
+ // We passed the sanity check for the command.
+ // Proceed to set the watchpoint now.
+ lldb::addr_t addr = 0;
+ size_t size = 0;
+
+ VariableSP var_sp;
+ ValueObjectSP valobj_sp;
+ Stream &output_stream = result.GetOutputStream();
+
+ // A simple watch variable gesture allows only one argument.
+ if (command.GetArgumentCount() != 1)
+ {
+ result.GetErrorStream().Printf("error: specify exactly one variable to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Things have checked out ok...
+ Error error;
+ uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember |
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
+ valobj_sp = frame->GetValueForVariableExpressionPath (command.GetArgumentAtIndex(0),
+ eNoDynamicValues,
+ expr_path_options,
+ var_sp,
+ error);
+
+ if (!valobj_sp)
+ {
+ // Not in the frame; let's check the globals.
+
+ VariableList variable_list;
+ ValueObjectList valobj_list;
+
+ Error error (Variable::GetValuesForVariableExpressionPath (command.GetArgumentAtIndex(0),
+ m_exe_ctx.GetBestExecutionContextScope(),
+ GetVariableCallback,
+ target,
+ variable_list,
+ valobj_list));
+
+ if (valobj_list.GetSize())
+ valobj_sp = valobj_list.GetValueObjectAtIndex(0);
+ }
+
+ ClangASTType clang_type;
+
+ if (valobj_sp)
+ {
+ AddressType addr_type;
+ addr = valobj_sp->GetAddressOf(false, &addr_type);
+ if (addr_type == eAddressTypeLoad)
+ {
+ // We're in business.
+ // Find out the size of this variable.
+ size = m_option_watchpoint.watch_size == 0 ? valobj_sp->GetByteSize()
+ : m_option_watchpoint.watch_size;
+ }
+ clang_type = valobj_sp->GetClangType();
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString(NULL);
+ if (error_cstr)
+ result.GetErrorStream().Printf("error: %s\n", error_cstr);
+ else
+ result.GetErrorStream().Printf ("error: unable to find any variable expression path that matches '%s'\n",
+ command.GetArgumentAtIndex(0));
+ return false;
+ }
+
+ // Now it's time to create the watchpoint.
+ uint32_t watch_type = m_option_watchpoint.watch_type;
+
+ error.Clear();
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &clang_type, watch_type, error).get();
+ if (wp)
+ {
+ wp->SetWatchSpec(command.GetArgumentAtIndex(0));
+ wp->SetWatchVariable(true);
+ if (var_sp && var_sp->GetDeclaration().GetFile())
+ {
+ StreamString ss;
+ // True to show fullpath for declaration file.
+ var_sp->GetDeclaration().DumpStopContext(&ss, true);
+ wp->SetDeclInfo(ss.GetString());
+ }
+ output_stream.Printf("Watchpoint created: ");
+ wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
+ output_stream.EOL();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%lu, variable expression='%s').\n",
+ addr, size, command.GetArgumentAtIndex(0));
+ if (error.AsCString(NULL))
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupWatchpoint m_option_watchpoint;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSetExpression
+//-------------------------------------------------------------------------
+#pragma mark Set
+
+class CommandObjectWatchpointSetExpression : public CommandObjectRaw
+{
+public:
+
+ CommandObjectWatchpointSetExpression (CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "watchpoint set expression",
+ "Set a watchpoint on an address by supplying an expression. "
+ "Use the '-w' option to specify the type of watchpoint and "
+ "the '-x' option to specify the byte size to watch for. "
+ "If no '-w' option is specified, it defaults to write. "
+ "If no '-x' option is specified, it defaults to the target's "
+ "pointer byte size. "
+ "Note that there are limited hardware resources for watchpoints. "
+ "If watchpoint setting fails, consider disable/delete existing ones "
+ "to free up resources.",
+ NULL,
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock |
+ eFlagProcessMustBeLaunched |
+ eFlagProcessMustBePaused ),
+ m_option_group (interpreter),
+ m_option_watchpoint ()
+ {
+ SetHelpLong(
+ "Examples: \n\
+ \n\
+ watchpoint set expression -w write -x 1 -- foo + 32\n\
+ # Watch write access for the 1-byte region pointed to by the address 'foo + 32'.\n");
+
+ CommandArgumentEntry arg;
+ CommandArgumentData expression_arg;
+
+ // Define the only variant of this arg.
+ expression_arg.arg_type = eArgTypeExpression;
+ expression_arg.arg_repetition = eArgRepeatPlain;
+
+ // Push the only variant into the argument entry.
+ arg.push_back (expression_arg);
+
+ // Push the data for the only argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+
+ // Absorb the '-w' and '-x' options into our option group.
+ m_option_group.Append (&m_option_watchpoint, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
+ m_option_group.Finalize();
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointSetExpression () {}
+
+ // Overrides base class's behavior where WantsCompletion = !WantsRawCommandString.
+ virtual bool
+ WantsCompletion() { return true; }
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_option_group;
+ }
+
+protected:
+ virtual bool
+ DoExecute (const char *raw_command, CommandReturnObject &result)
+ {
+ m_option_group.NotifyOptionParsingStarting(); // This is a raw command, so notify the option group
+
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+ StackFrame *frame = m_exe_ctx.GetFramePtr();
+
+ Args command(raw_command);
+ const char *expr = NULL;
+ if (raw_command[0] == '-')
+ {
+ // We have some options and these options MUST end with --.
+ const char *end_options = NULL;
+ const char *s = raw_command;
+ while (s && s[0])
+ {
+ end_options = ::strstr (s, "--");
+ if (end_options)
+ {
+ end_options += 2; // Get past the "--"
+ if (::isspace (end_options[0]))
+ {
+ expr = end_options;
+ while (::isspace (*expr))
+ ++expr;
+ break;
+ }
+ }
+ s = end_options;
+ }
+
+ if (end_options)
+ {
+ Args args (raw_command, end_options - raw_command);
+ if (!ParseOptions (args, result))
+ return false;
+
+ Error error (m_option_group.NotifyOptionParsingFinished());
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+
+ if (expr == NULL)
+ expr = raw_command;
+
+ // If no argument is present, issue an error message. There's no way to set a watchpoint.
+ if (command.GetArgumentCount() == 0)
+ {
+ result.GetErrorStream().Printf("error: required argument missing; specify an expression to evaulate into the address to watch for\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // If no '-w' is specified, default to '-w write'.
+ if (!m_option_watchpoint.watch_type_specified)
+ {
+ m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
+ }
+
+ // We passed the sanity check for the command.
+ // Proceed to set the watchpoint now.
+ lldb::addr_t addr = 0;
+ size_t size = 0;
+
+ ValueObjectSP valobj_sp;
+
+ // Use expression evaluation to arrive at the address to watch.
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(false)
+ .SetRunOthers(true)
+ .SetTimeoutUsec(0);
+
+ ExecutionResults expr_result = target->EvaluateExpression (expr,
+ frame,
+ valobj_sp,
+ options);
+ if (expr_result != eExecutionCompleted)
+ {
+ result.GetErrorStream().Printf("error: expression evaluation of address to watch failed\n");
+ result.GetErrorStream().Printf("expression evaluated: %s\n", expr);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // Get the address to watch.
+ bool success = false;
+ addr = valobj_sp->GetValueAsUnsigned(0, &success);
+ if (!success)
+ {
+ result.GetErrorStream().Printf("error: expression did not evaluate to an address\n");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_option_watchpoint.watch_size != 0)
+ size = m_option_watchpoint.watch_size;
+ else
+ size = target->GetArchitecture().GetAddressByteSize();
+
+ // Now it's time to create the watchpoint.
+ uint32_t watch_type = m_option_watchpoint.watch_type;
+
+ // Fetch the type from the value object, the type of the watched object is the pointee type
+ /// of the expression, so convert to that if we found a valid type.
+ ClangASTType clang_type(valobj_sp->GetClangType());
+
+ Error error;
+ Watchpoint *wp = target->CreateWatchpoint(addr, size, &clang_type, watch_type, error).get();
+ if (wp)
+ {
+ Stream &output_stream = result.GetOutputStream();
+ output_stream.Printf("Watchpoint created: ");
+ wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
+ output_stream.EOL();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64 ", size=%lu).\n",
+ addr, size);
+ if (error.AsCString(NULL))
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ OptionGroupOptions m_option_group;
+ OptionGroupWatchpoint m_option_watchpoint;
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointSet
+//-------------------------------------------------------------------------
+#pragma mark Set
+
+class CommandObjectWatchpointSet : public CommandObjectMultiword
+{
+public:
+
+ CommandObjectWatchpointSet (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "watchpoint set",
+ "A set of commands for setting a watchpoint.",
+ "watchpoint set <subcommand> [<subcommand-options>]")
+ {
+
+ LoadSubCommand ("variable", CommandObjectSP (new CommandObjectWatchpointSetVariable (interpreter)));
+ LoadSubCommand ("expression", CommandObjectSP (new CommandObjectWatchpointSetExpression (interpreter)));
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointSet () {}
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+#pragma mark MultiwordWatchpoint
+
+CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "watchpoint",
+ "A set of commands for operating on watchpoints.",
+ "watchpoint <command> [<command-options>]")
+{
+ CommandObjectSP list_command_object (new CommandObjectWatchpointList (interpreter));
+ CommandObjectSP enable_command_object (new CommandObjectWatchpointEnable (interpreter));
+ CommandObjectSP disable_command_object (new CommandObjectWatchpointDisable (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectWatchpointDelete (interpreter));
+ CommandObjectSP ignore_command_object (new CommandObjectWatchpointIgnore (interpreter));
+ CommandObjectSP command_command_object (new CommandObjectWatchpointCommand (interpreter));
+ CommandObjectSP modify_command_object (new CommandObjectWatchpointModify (interpreter));
+ CommandObjectSP set_command_object (new CommandObjectWatchpointSet (interpreter));
+
+ list_command_object->SetCommandName ("watchpoint list");
+ enable_command_object->SetCommandName("watchpoint enable");
+ disable_command_object->SetCommandName("watchpoint disable");
+ delete_command_object->SetCommandName("watchpoint delete");
+ ignore_command_object->SetCommandName("watchpoint ignore");
+ command_command_object->SetCommandName ("watchpoint command");
+ modify_command_object->SetCommandName("watchpoint modify");
+ set_command_object->SetCommandName("watchpoint set");
+
+ LoadSubCommand ("list", list_command_object);
+ LoadSubCommand ("enable", enable_command_object);
+ LoadSubCommand ("disable", disable_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("ignore", ignore_command_object);
+ LoadSubCommand ("command", command_command_object);
+ LoadSubCommand ("modify", modify_command_object);
+ LoadSubCommand ("set", set_command_object);
+}
+
+CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint()
+{
+}
+
diff --git a/source/Commands/CommandObjectWatchpoint.h b/source/Commands/CommandObjectWatchpoint.h
new file mode 100644
index 000000000000..1b1ebd7764a3
--- /dev/null
+++ b/source/Commands/CommandObjectWatchpoint.h
@@ -0,0 +1,43 @@
+//===-- CommandObjectWatchpoint.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_CommandObjectWatchpoint_h_
+#define liblldb_CommandObjectWatchpoint_h_
+
+// C Includes
+// C++ Includes
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/OptionGroupWatchpoint.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectMultiwordWatchpoint : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordWatchpoint (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectMultiwordWatchpoint ();
+
+ static bool
+ VerifyWatchpointIDs(Target *target, Args &args, std::vector<uint32_t> &wp_ids);
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectWatchpoint_h_
diff --git a/source/Commands/CommandObjectWatchpointCommand.cpp b/source/Commands/CommandObjectWatchpointCommand.cpp
new file mode 100644
index 000000000000..4e200465031d
--- /dev/null
+++ b/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -0,0 +1,850 @@
+//===-- CommandObjectWatchpointCommand.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"
+
+// C Includes
+// C++ Includes
+
+
+#include "CommandObjectWatchpointCommand.h"
+#include "CommandObjectWatchpoint.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Core/State.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandAdd
+//-------------------------------------------------------------------------
+
+
+class CommandObjectWatchpointCommandAdd : public CommandObjectParsed
+{
+public:
+
+ CommandObjectWatchpointCommandAdd (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "add",
+ "Add a set of commands to a watchpoint, to be executed whenever the watchpoint is hit.",
+ NULL),
+ m_options (interpreter)
+ {
+ SetHelpLong (
+"\nGeneral information about entering watchpoint commands \n\
+------------------------------------------------------ \n\
+ \n\
+This command will cause you to be prompted to enter the command or set \n\
+of commands you wish to be executed when the specified watchpoint is \n\
+hit. You will be told to enter your command(s), and will see a '> ' \n\
+prompt. Because you can enter one or many commands to be executed when \n\
+a watchpoint is hit, you will continue to be prompted after each \n\
+new-line that you enter, until you enter the word 'DONE', which will \n\
+cause the commands you have entered to be stored with the watchpoint \n\
+and executed when the watchpoint is hit. \n\
+ \n\
+Syntax checking is not necessarily done when watchpoint commands are \n\
+entered. An improperly written watchpoint command will attempt to get \n\
+executed when the watchpoint gets hit, and usually silently fail. If \n\
+your watchpoint command does not appear to be getting executed, go \n\
+back and check your syntax. \n\
+ \n\
+ \n\
+Special information about PYTHON watchpoint commands \n\
+---------------------------------------------------- \n\
+ \n\
+You may enter either one line of Python or multiple lines of Python \n\
+(including defining whole functions, if desired). If you enter a \n\
+single line of Python, that will be passed to the Python interpreter \n\
+'as is' when the watchpoint gets hit. If you enter function \n\
+definitions, they will be passed to the Python interpreter as soon as \n\
+you finish entering the watchpoint command, and they can be called \n\
+later (don't forget to add calls to them, if you want them called when \n\
+the watchpoint is hit). If you enter multiple lines of Python that \n\
+are not function definitions, they will be collected into a new, \n\
+automatically generated Python function, and a call to the newly \n\
+generated function will be attached to the watchpoint. \n\
+ \n\
+This auto-generated function is passed in two arguments: \n\
+ \n\
+ frame: an SBFrame object representing the frame which hit the watchpoint. \n\
+ From the frame you can get back to the thread and process. \n\
+ wp: the watchpoint that was hit. \n\
+ \n\
+Important Note: Because loose Python code gets collected into functions, \n\
+if you want to access global variables in the 'loose' code, you need to \n\
+specify that they are global, using the 'global' keyword. Be sure to \n\
+use correct Python syntax, including indentation, when entering Python \n\
+watchpoint commands. \n\
+ \n\
+As a third option, you can pass the name of an already existing Python function \n\
+and that function will be attached to the watchpoint. It will get passed the \n\
+frame and wp_loc arguments mentioned above. \n\
+ \n\
+Example Python one-line watchpoint command: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> print \"Hit this watchpoint!\" \n\
+> DONE \n\
+ \n\
+As a convenience, this also works for a short Python one-liner: \n\
+(lldb) watchpoint command add -s python 1 -o \"import time; print time.asctime()\" \n\
+(lldb) run \n\
+Launching '.../a.out' (x86_64) \n\
+(lldb) Fri Sep 10 12:17:45 2010 \n\
+Process 21778 Stopped \n\
+* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = watchpoint 1.1, queue = com.apple.main-thread \n\
+ 36 \n\
+ 37 int c(int val)\n\
+ 38 {\n\
+ 39 -> return val + 3;\n\
+ 40 }\n\
+ 41 \n\
+ 42 int main (int argc, char const *argv[])\n\
+(lldb) \n\
+ \n\
+Example multiple line Python watchpoint command, using function definition: \n\
+ \n\
+(lldb) watchpoint command add -s python 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> def watchpoint_output (wp_no): \n\
+> out_string = \"Hit watchpoint number \" + repr (wp_no) \n\
+> print out_string \n\
+> return True \n\
+> watchpoint_output (1) \n\
+> DONE \n\
+ \n\
+ \n\
+Example multiple line Python watchpoint command, using 'loose' Python: \n\
+ \n\
+(lldb) watchpoint command add -s p 1 \n\
+Enter your Python command(s). Type 'DONE' to end. \n\
+> global wp_count \n\
+> wp_count = wp_count + 1 \n\
+> print \"Hit this watchpoint \" + repr(wp_count) + \" times!\" \n\
+> DONE \n\
+ \n\
+In this case, since there is a reference to a global variable, \n\
+'wp_count', you will also need to make sure 'wp_count' exists and is \n\
+initialized: \n\
+ \n\
+(lldb) script \n\
+>>> wp_count = 0 \n\
+>>> quit() \n\
+ \n\
+(lldb) \n\
+ \n\
+ \n\
+Final Note: If you get a warning that no watchpoint command was generated, \n\
+but you did not get any syntax errors, you probably forgot to add a call \n\
+to your functions. \n\
+ \n\
+Special information about debugger command watchpoint commands \n\
+-------------------------------------------------------------- \n\
+ \n\
+You may enter any debugger command, exactly as you would at the \n\
+debugger prompt. You may enter as many debugger commands as you like, \n\
+but do NOT enter more than one command per line. \n" );
+
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointCommandAdd () {}
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+ void
+ CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+ CommandReturnObject &result)
+ {
+ InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+ if (reader_sp && data_ap.get())
+ {
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+ Error err (reader_sp->Initialize (CommandObjectWatchpointCommandAdd::GenerateWatchpointCommandCallback,
+ wp_options, // callback_data
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ m_interpreter.GetDebugger().PushInputReader (reader_sp);
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ }
+
+ /// Set a one-liner as the callback for the watchpoint.
+ void
+ SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+ const char *oneliner)
+ {
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in watchpoint command list)
+ // while the latter is used for Python to interpret during the actual callback.
+ data_ap->user_source.AppendString (oneliner);
+ data_ap->script_source.assign (oneliner);
+ data_ap->stop_on_error = m_options.m_stop_on_error;
+
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (WatchpointOptionsCallbackFunction, baton_sp);
+
+ return;
+ }
+
+ static size_t
+ GenerateWatchpointCommandCallback (void *callback_data,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_reader_instructions);
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes && bytes_len && callback_data)
+ {
+ WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+ if (wp_options)
+ {
+ Baton *wp_options_baton = wp_options->GetBaton();
+ if (wp_options_baton)
+ ((WatchpointOptions::CommandData *)wp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
+ }
+ }
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush();
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ // Finish, and cancel the watchpoint command.
+ reader.SetIsDone (true);
+ WatchpointOptions *wp_options = (WatchpointOptions *) callback_data;
+ if (wp_options)
+ {
+ Baton *wp_options_baton = wp_options->GetBaton ();
+ if (wp_options_baton)
+ {
+ ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->user_source.Clear();
+ ((WatchpointOptions::CommandData *) wp_options_baton->m_data)->script_source.clear();
+ }
+ }
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Warning: No command attached to watchpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+ }
+
+ static bool
+ WatchpointOptionsCallbackFunction (void *baton,
+ StoppointCallbackContext *context,
+ lldb::user_id_t watch_id)
+ {
+ bool ret_value = true;
+ if (baton == NULL)
+ return true;
+
+
+ WatchpointOptions::CommandData *data = (WatchpointOptions::CommandData *) baton;
+ StringList &commands = data->user_source;
+
+ if (commands.GetSize() > 0)
+ {
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ CommandReturnObject result;
+ Debugger &debugger = target->GetDebugger();
+ // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
+ // if the debugger is set up that way.
+
+ StreamSP output_stream (debugger.GetAsyncOutputStream());
+ StreamSP error_stream (debugger.GetAsyncErrorStream());
+ 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,
+ &exe_ctx,
+ stop_on_continue,
+ data->stop_on_error,
+ echo_commands,
+ print_results,
+ eLazyBoolNo,
+ result);
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+ }
+ }
+ return ret_value;
+ }
+
+ class CommandOptions : public Options
+ {
+ public:
+
+ CommandOptions (CommandInterpreter &interpreter) :
+ Options (interpreter),
+ m_use_commands (false),
+ m_use_script_language (false),
+ m_script_language (eScriptLanguageNone),
+ m_use_one_liner (false),
+ m_one_liner(),
+ m_function_name()
+ {
+ }
+
+ 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 'o':
+ m_use_one_liner = true;
+ m_one_liner = option_arg;
+ break;
+
+ case 's':
+ m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
+ g_option_table[option_idx].enum_values,
+ eScriptLanguageNone,
+ error);
+
+ if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
+ {
+ m_use_script_language = true;
+ }
+ else
+ {
+ m_use_script_language = false;
+ }
+ break;
+
+ case 'e':
+ {
+ bool success = false;
+ m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
+ }
+ break;
+
+ case 'F':
+ {
+ m_use_one_liner = false;
+ m_use_script_language = true;
+ m_function_name.assign(option_arg);
+ }
+ break;
+
+ default:
+ break;
+ }
+ return error;
+ }
+ void
+ OptionParsingStarting ()
+ {
+ m_use_commands = true;
+ m_use_script_language = false;
+ m_script_language = eScriptLanguageNone;
+
+ m_use_one_liner = false;
+ m_stop_on_error = true;
+ m_one_liner.clear();
+ m_function_name.clear();
+ }
+
+ 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_commands;
+ bool m_use_script_language;
+ lldb::ScriptLanguage m_script_language;
+
+ // Instance variables to hold the values for one_liner options.
+ bool m_use_one_liner;
+ std::string m_one_liner;
+ bool m_stop_on_error;
+ std::string m_function_name;
+ };
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints to which to add commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist to have commands added");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (m_options.m_use_script_language == false && m_options.m_function_name.size())
+ {
+ result.AppendError ("need to enable scripting to have a function run as a watchpoint command");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+ // Sanity check wp first.
+ if (wp == NULL) continue;
+
+ WatchpointOptions *wp_options = wp->GetOptions();
+ // Skip this watchpoint if wp_options is not good.
+ if (wp_options == NULL) continue;
+
+ // If we are using script language, get the script interpreter
+ // in order to set or collect command callback. Otherwise, call
+ // the methods associated with this object.
+ if (m_options.m_use_script_language)
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ {
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+ m_options.m_one_liner.c_str());
+ }
+ // Special handling for using a Python function by name
+ // instead of extending the watchpoint callback data structures, we just automatize
+ // what the user would do manually: make their watchpoint command be a function call
+ else if (m_options.m_function_name.size())
+ {
+ std::string oneliner(m_options.m_function_name);
+ oneliner += "(frame, wp, internal_dict)";
+ m_interpreter.GetScriptInterpreter()->SetWatchpointCommandCallback (wp_options,
+ oneliner.c_str());
+ }
+ else
+ {
+ m_interpreter.GetScriptInterpreter()->CollectDataForWatchpointCommandCallback (wp_options,
+ result);
+ }
+ }
+ else
+ {
+ // Special handling for one-liner specified inline.
+ if (m_options.m_use_one_liner)
+ SetWatchpointCommandCallback (wp_options,
+ m_options.m_one_liner.c_str());
+ else
+ CollectDataForWatchpointCommandCallback (wp_options,
+ result);
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+
+private:
+ CommandOptions m_options;
+ static const char *g_reader_instructions;
+
+};
+
+const char *
+CommandObjectWatchpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end.";
+
+// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
+// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
+
+static OptionEnumValueElement
+g_script_option_enumeration[4] =
+{
+ { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"},
+ { eScriptLanguagePython, "python", "Commands are in the Python language."},
+ { eSortOrderByName, "default-script", "Commands are in the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+OptionDefinition
+CommandObjectWatchpointCommandAdd::CommandOptions::g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
+ "Specify a one-line watchpoint command inline. Be sure to surround it with quotes." },
+
+ { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
+ "Specify whether watchpoint command execution should terminate on error." },
+
+ { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
+ "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
+
+ { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction,
+ "Give the name of a Python function to run as command for this watchpoint. Be sure to give a module name if appropriate."},
+
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandDelete : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointCommandDelete (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "delete",
+ "Delete the set of commands from a watchpoint.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+
+ virtual
+ ~CommandObjectWatchpointCommandDelete () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints from which to delete commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist to have commands deleted");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No watchpoint specified from which to delete the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+ if (wp)
+ wp->ClearCallback();
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n",
+ cur_wp_id);
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommandList
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommandList : public CommandObjectParsed
+{
+public:
+ CommandObjectWatchpointCommandList (CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "list",
+ "List the script or set of commands to be executed when the watchpoint is hit.",
+ NULL)
+ {
+ CommandArgumentEntry arg;
+ CommandArgumentData wp_id_arg;
+
+ // Define the first (and only) variant of this arg.
+ wp_id_arg.arg_type = eArgTypeWatchpointID;
+ wp_id_arg.arg_repetition = eArgRepeatPlain;
+
+ // There is only one variant this argument could be; put it into the argument entry.
+ arg.push_back (wp_id_arg);
+
+ // Push the data for the first argument into the m_arguments vector.
+ m_arguments.push_back (arg);
+ }
+
+ virtual
+ ~CommandObjectWatchpointCommandList () {}
+
+protected:
+ virtual bool
+ DoExecute (Args& command,
+ CommandReturnObject &result)
+ {
+ Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
+
+ if (target == NULL)
+ {
+ result.AppendError ("There is not a current executable; there are no watchpoints for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ const WatchpointList &watchpoints = target->GetWatchpointList();
+ size_t num_watchpoints = watchpoints.GetSize();
+
+ if (num_watchpoints == 0)
+ {
+ result.AppendError ("No watchpoints exist for which to list commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (command.GetArgumentCount() == 0)
+ {
+ result.AppendError ("No watchpoint specified for which to list the commands");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ std::vector<uint32_t> valid_wp_ids;
+ if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(target, command, valid_wp_ids))
+ {
+ result.AppendError("Invalid watchpoints specification.");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ const size_t count = valid_wp_ids.size();
+ for (size_t i = 0; i < count; ++i)
+ {
+ uint32_t cur_wp_id = valid_wp_ids.at (i);
+ if (cur_wp_id != LLDB_INVALID_WATCH_ID)
+ {
+ Watchpoint *wp = target->GetWatchpointList().FindByID (cur_wp_id).get();
+
+ if (wp)
+ {
+ const WatchpointOptions *wp_options = wp->GetOptions();
+ if (wp_options)
+ {
+ // Get the callback baton associated with the current watchpoint.
+ const Baton *baton = wp_options->GetBaton();
+ if (baton)
+ {
+ result.GetOutputStream().Printf ("Watchpoint %u:\n", cur_wp_id);
+ result.GetOutputStream().IndentMore ();
+ baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
+ result.GetOutputStream().IndentLess ();
+ }
+ else
+ {
+ result.AppendMessageWithFormat ("Watchpoint %u does not have an associated command.\n",
+ cur_wp_id);
+ }
+ }
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat("Invalid watchpoint ID: %u.\n", cur_wp_id);
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ }
+
+ return result.Succeeded();
+ }
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectWatchpointCommand
+//-------------------------------------------------------------------------
+
+CommandObjectWatchpointCommand::CommandObjectWatchpointCommand (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "command",
+ "A set of commands for adding, removing and examining bits of code to be executed when the watchpoint is hit (watchpoint 'commmands').",
+ "command <sub-command> [<sub-command-options>] <watchpoint-id>")
+{
+ CommandObjectSP add_command_object (new CommandObjectWatchpointCommandAdd (interpreter));
+ CommandObjectSP delete_command_object (new CommandObjectWatchpointCommandDelete (interpreter));
+ CommandObjectSP list_command_object (new CommandObjectWatchpointCommandList (interpreter));
+
+ add_command_object->SetCommandName ("watchpoint command add");
+ delete_command_object->SetCommandName ("watchpoint command delete");
+ list_command_object->SetCommandName ("watchpoint command list");
+
+ LoadSubCommand ("add", add_command_object);
+ LoadSubCommand ("delete", delete_command_object);
+ LoadSubCommand ("list", list_command_object);
+}
+
+CommandObjectWatchpointCommand::~CommandObjectWatchpointCommand ()
+{
+}
+
+
diff --git a/source/Commands/CommandObjectWatchpointCommand.h b/source/Commands/CommandObjectWatchpointCommand.h
new file mode 100644
index 000000000000..c2faf7187db9
--- /dev/null
+++ b/source/Commands/CommandObjectWatchpointCommand.h
@@ -0,0 +1,46 @@
+//===-- CommandObjectWatchpointCommand.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_CommandObjectWatchpointCommand_h_
+#define liblldb_CommandObjectWatchpointCommand_h_
+
+// C Includes
+// C++ Includes
+
+
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-types.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordWatchpoint
+//-------------------------------------------------------------------------
+
+class CommandObjectWatchpointCommand : public CommandObjectMultiword
+{
+public:
+ CommandObjectWatchpointCommand (CommandInterpreter &interpreter);
+
+ virtual
+ ~CommandObjectWatchpointCommand ();
+
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectWatchpointCommand_h_
diff --git a/source/Core/Address.cpp b/source/Core/Address.cpp
new file mode 100644
index 000000000000..8d599d80ad4f
--- /dev/null
+++ b/source/Core/Address.cpp
@@ -0,0 +1,1045 @@
+//===-- Address.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/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static size_t
+ReadBytes (ExecutionContextScope *exe_scope, const Address &address, void *dst, size_t dst_len)
+{
+ if (exe_scope == NULL)
+ return 0;
+
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ if (target_sp)
+ {
+ Error error;
+ bool prefer_file_cache = false;
+ return target_sp->ReadMemory (address, prefer_file_cache, dst, dst_len, error);
+ }
+ return 0;
+}
+
+static bool
+GetByteOrderAndAddressSize (ExecutionContextScope *exe_scope, const Address &address, ByteOrder& byte_order, uint32_t& addr_size)
+{
+ byte_order = eByteOrderInvalid;
+ addr_size = 0;
+ if (exe_scope == NULL)
+ return false;
+
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ if (target_sp)
+ {
+ byte_order = target_sp->GetArchitecture().GetByteOrder();
+ addr_size = target_sp->GetArchitecture().GetAddressByteSize();
+ }
+
+ if (byte_order == eByteOrderInvalid || addr_size == 0)
+ {
+ ModuleSP module_sp (address.GetModule());
+ if (module_sp)
+ {
+ byte_order = module_sp->GetArchitecture().GetByteOrder();
+ addr_size = module_sp->GetArchitecture().GetAddressByteSize();
+ }
+ }
+ return byte_order != eByteOrderInvalid && addr_size != 0;
+}
+
+static uint64_t
+ReadUIntMax64 (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, bool &success)
+{
+ uint64_t uval64 = 0;
+ if (exe_scope == NULL || byte_size > sizeof(uint64_t))
+ {
+ success = false;
+ return 0;
+ }
+ uint64_t buf = 0;
+
+ success = ReadBytes (exe_scope, address, &buf, byte_size) == byte_size;
+ if (success)
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (&buf, sizeof(buf), byte_order, addr_size);
+ lldb::offset_t offset = 0;
+ uval64 = data.GetU64(&offset);
+ }
+ else
+ success = false;
+ }
+ return uval64;
+}
+
+static bool
+ReadAddress (ExecutionContextScope *exe_scope, const Address &address, uint32_t pointer_size, Address &deref_so_addr)
+{
+ if (exe_scope == NULL)
+ return false;
+
+
+ bool success = false;
+ addr_t deref_addr = ReadUIntMax64 (exe_scope, address, pointer_size, success);
+ if (success)
+ {
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ // If we have any sections that are loaded, try and resolve using the
+ // section load list
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress (deref_addr, deref_so_addr))
+ return true;
+ }
+ else
+ {
+ // If we were not running, yet able to read an integer, we must
+ // have a module
+ ModuleSP module_sp (address.GetModule());
+
+ assert (module_sp);
+ if (module_sp->ResolveFileAddress(deref_addr, deref_so_addr))
+ return true;
+ }
+
+ // We couldn't make "deref_addr" into a section offset value, but we were
+ // able to read the address, so we return a section offset address with
+ // no section and "deref_addr" as the offset (address).
+ deref_so_addr.SetRawAddress(deref_addr);
+ return true;
+ }
+ return false;
+}
+
+static bool
+DumpUInt (ExecutionContextScope *exe_scope, const Address &address, uint32_t byte_size, Stream* strm)
+{
+ if (exe_scope == NULL || byte_size == 0)
+ return 0;
+ std::vector<uint8_t> buf(byte_size, 0);
+
+ if (ReadBytes (exe_scope, address, &buf[0], buf.size()) == buf.size())
+ {
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t addr_size = 0;
+ if (GetByteOrderAndAddressSize (exe_scope, address, byte_order, addr_size))
+ {
+ DataExtractor data (&buf.front(), buf.size(), byte_order, addr_size);
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatHex, // Print as characters
+ buf.size(), // Size of item
+ 1, // Items count
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+static size_t
+ReadCStringFromMemory (ExecutionContextScope *exe_scope, const Address &address, Stream *strm)
+{
+ if (exe_scope == NULL)
+ return 0;
+ const size_t k_buf_len = 256;
+ char buf[k_buf_len+1];
+ buf[k_buf_len] = '\0'; // NULL terminate
+
+ // Byte order and address size don't matter for C string dumping..
+ DataExtractor data (buf, sizeof(buf), lldb::endian::InlHostByteOrder(), 4);
+ size_t total_len = 0;
+ size_t bytes_read;
+ Address curr_address(address);
+ strm->PutChar ('"');
+ while ((bytes_read = ReadBytes (exe_scope, curr_address, buf, k_buf_len)) > 0)
+ {
+ size_t len = strlen(buf);
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+
+ data.Dump (strm,
+ 0, // Start offset in "data"
+ eFormatChar, // Print as characters
+ 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
+
+ total_len += bytes_read;
+
+ if (len < k_buf_len)
+ break;
+ curr_address.SetOffset (curr_address.GetOffset() + bytes_read);
+ }
+ strm->PutChar ('"');
+ return total_len;
+}
+
+Address::Address (lldb::addr_t abs_addr) :
+ m_section_wp (),
+ m_offset (abs_addr)
+{
+}
+
+Address::Address (addr_t address, const SectionList *section_list) :
+ m_section_wp (),
+ m_offset (LLDB_INVALID_ADDRESS)
+{
+ ResolveAddressUsingFileSections(address, section_list);
+}
+
+const Address&
+Address::operator= (const Address& rhs)
+{
+ if (this != &rhs)
+ {
+ m_section_wp = rhs.m_section_wp;
+ m_offset = rhs.m_offset.load();
+ }
+ return *this;
+}
+
+bool
+Address::ResolveAddressUsingFileSections (addr_t file_addr, const SectionList *section_list)
+{
+ if (section_list)
+ {
+ SectionSP section_sp (section_list->FindSectionContainingFileAddress(file_addr));
+ m_section_wp = section_sp;
+ if (section_sp)
+ {
+ assert( section_sp->ContainsFileAddress(file_addr) );
+ m_offset = file_addr - section_sp->GetFileAddress();
+ return true; // Successfully transformed addr into a section offset address
+ }
+ }
+ m_offset = file_addr;
+ return false; // Failed to resolve this address to a section offset value
+}
+
+ModuleSP
+Address::GetModule () const
+{
+ lldb::ModuleSP module_sp;
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ module_sp = section_sp->GetModule();
+ return module_sp;
+}
+
+addr_t
+Address::GetFileAddress () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ addr_t sect_file_addr = section_sp->GetFileAddress();
+ if (sect_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ // Section isn't resolved, we can't return a valid file address
+ return LLDB_INVALID_ADDRESS;
+ }
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_file_addr + m_offset;
+ }
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+}
+
+addr_t
+Address::GetLoadAddress (Target *target) const
+{
+ SectionSP section_sp (GetSection());
+ if (!section_sp)
+ {
+ // No section, we just return the offset since it is the value in this case
+ return m_offset;
+ }
+
+ if (target)
+ {
+ addr_t sect_load_addr = section_sp->GetLoadBaseAddress (target);
+
+ if (sect_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ // We have a valid file range, so we can return the file based
+ // address by adding the file base address to our offset
+ return sect_load_addr + m_offset;
+ }
+ }
+ // The section isn't resolved or no process was supplied so we can't
+ // return a valid file address.
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+Address::GetCallableLoadAddress (Target *target, bool is_indirect) const
+{
+ if (is_indirect && target) {
+ ProcessSP processSP = target->GetProcessSP();
+ Error error;
+ if (processSP.get())
+ return processSP->ResolveIndirectFunction(this, error);
+ }
+
+ addr_t code_addr = GetLoadAddress (target);
+
+ if (target)
+ return target->GetCallableLoadAddress (code_addr, GetAddressClass());
+ return code_addr;
+}
+
+bool
+Address::SetCallableLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (SetLoadAddress (load_addr, target))
+ {
+ if (target)
+ m_offset = target->GetCallableLoadAddress(m_offset, GetAddressClass());
+ return true;
+ }
+ return false;
+}
+
+addr_t
+Address::GetOpcodeLoadAddress (Target *target) const
+{
+ addr_t code_addr = GetLoadAddress (target);
+ if (code_addr != LLDB_INVALID_ADDRESS)
+ code_addr = target->GetOpcodeLoadAddress (code_addr, GetAddressClass());
+ return code_addr;
+}
+
+bool
+Address::SetOpcodeLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (SetLoadAddress (load_addr, target))
+ {
+ if (target)
+ m_offset = target->GetOpcodeLoadAddress (m_offset, GetAddressClass());
+ return true;
+ }
+ return false;
+}
+
+bool
+Address::Dump (Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, DumpStyle fallback_style, uint32_t addr_size) const
+{
+ // If the section was NULL, only load address is going to work unless we are
+ // trying to deref a pointer
+ SectionSP section_sp (GetSection());
+ if (!section_sp && style != DumpStyleResolvedPointerDescription)
+ style = DumpStyleLoadAddress;
+
+ ExecutionContext exe_ctx (exe_scope);
+ Target *target = exe_ctx.GetTargetPtr();
+ // If addr_byte_size is UINT32_MAX, then determine the correct address
+ // byte size for the process or default to the size of addr_t
+ if (addr_size == UINT32_MAX)
+ {
+ if (target)
+ addr_size = target->GetArchitecture().GetAddressByteSize ();
+ else
+ addr_size = sizeof(addr_t);
+ }
+
+ Address so_addr;
+ switch (style)
+ {
+ case DumpStyleInvalid:
+ return false;
+
+ case DumpStyleSectionNameOffset:
+ if (section_sp)
+ {
+ section_sp->DumpName(s);
+ s->Printf (" + %" PRIu64, m_offset.load());
+ }
+ else
+ {
+ s->Address(m_offset, addr_size);
+ }
+ break;
+
+ case DumpStyleSectionPointerOffset:
+ s->Printf("(Section *)%p + ", section_sp.get());
+ s->Address(m_offset, addr_size);
+ break;
+
+ case DumpStyleModuleWithFileAddress:
+ if (section_sp)
+ s->Printf("%s[", section_sp->GetModule()->GetFileSpec().GetFilename().AsCString());
+ // Fall through
+ case DumpStyleFileAddress:
+ {
+ addr_t file_addr = GetFileAddress();
+ if (file_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ s->Address (file_addr, addr_size);
+ if (style == DumpStyleModuleWithFileAddress && section_sp)
+ s->PutChar(']');
+ }
+ break;
+
+ case DumpStyleLoadAddress:
+ {
+ addr_t load_addr = GetLoadAddress (target);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ s->Address (load_addr, addr_size);
+ }
+ break;
+
+ case DumpStyleResolvedDescription:
+ case DumpStyleResolvedDescriptionNoModule:
+ if (IsSectionOffset())
+ {
+ uint32_t pointer_size = 4;
+ ModuleSP module_sp (GetModule());
+ if (target)
+ pointer_size = target->GetArchitecture().GetAddressByteSize();
+ else if (module_sp)
+ pointer_size = module_sp->GetArchitecture().GetAddressByteSize();
+
+ bool showed_info = false;
+ if (section_sp)
+ {
+ SectionType sect_type = section_sp->GetType();
+ switch (sect_type)
+ {
+ case eSectionTypeData:
+ if (module_sp)
+ {
+ SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ const addr_t file_Addr = GetFileAddress();
+ Symbol *symbol = symtab->FindSymbolContainingFileAddress (file_Addr);
+ if (symbol)
+ {
+ const char *symbol_name = symbol->GetName().AsCString();
+ if (symbol_name)
+ {
+ s->PutCString(symbol_name);
+ addr_t delta = file_Addr - symbol->GetAddress().GetFileAddress();
+ if (delta)
+ s->Printf(" + %" PRIu64, delta);
+ showed_info = true;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case eSectionTypeDataCString:
+ // Read the C string from memory and display it
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, *this, s);
+ break;
+
+ case eSectionTypeDataCStringPointers:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(": ");
+#endif
+ showed_info = true;
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCMessageRefs:
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ if (target && so_addr.IsSectionOffset())
+ {
+ SymbolContext func_sc;
+ target->GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ func_sc);
+ if (func_sc.function || func_sc.symbol)
+ {
+ showed_info = true;
+#if VERBOSE_OUTPUT
+ s->PutCString ("(objc_msgref *) -> { (func*)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+#else
+ s->PutCString ("{ ");
+#endif
+ Address cstr_addr(*this);
+ cstr_addr.SetOffset(cstr_addr.GetOffset() + pointer_size);
+ func_sc.DumpStopContext(s, exe_scope, so_addr, true, true, false);
+ if (ReadAddress (exe_scope, cstr_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("), (char *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" (");
+#else
+ s->PutCString(", ");
+#endif
+ ReadCStringFromMemory (exe_scope, so_addr, s);
+ }
+#if VERBOSE_OUTPUT
+ s->PutCString(") }");
+#else
+ s->PutCString(" }");
+#endif
+ }
+ }
+ }
+ }
+ break;
+
+ case eSectionTypeDataObjCCFStrings:
+ {
+ Address cfstring_data_addr(*this);
+ cfstring_data_addr.SetOffset(cfstring_data_addr.GetOffset() + (2 * pointer_size));
+ if (ReadAddress (exe_scope, cfstring_data_addr, pointer_size, so_addr))
+ {
+#if VERBOSE_OUTPUT
+ s->PutCString("(CFString *) ");
+ cfstring_data_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+ s->PutCString(" -> @");
+#else
+ s->PutChar('@');
+#endif
+ if (so_addr.Dump(s, exe_scope, DumpStyleResolvedDescription))
+ showed_info = true;
+ }
+ }
+ break;
+
+ case eSectionTypeData4:
+ // Read the 4 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint32_t) ");
+ DumpUInt (exe_scope, *this, 4, s);
+ break;
+
+ case eSectionTypeData8:
+ // Read the 8 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint64_t) ");
+ DumpUInt (exe_scope, *this, 8, s);
+ break;
+
+ case eSectionTypeData16:
+ // Read the 16 byte data and display it
+ showed_info = true;
+ s->PutCString("(uint128_t) ");
+ DumpUInt (exe_scope, *this, 16, s);
+ break;
+
+ case eSectionTypeDataPointers:
+ // Read the pointer data and display it
+ {
+ if (ReadAddress (exe_scope, *this, pointer_size, so_addr))
+ {
+ s->PutCString ("(void *)");
+ so_addr.Dump(s, exe_scope, DumpStyleLoadAddress, DumpStyleFileAddress);
+
+ showed_info = true;
+ if (so_addr.IsSectionOffset())
+ {
+ SymbolContext pointer_sc;
+ if (target)
+ {
+ target->GetImages().ResolveSymbolContextForAddress (so_addr,
+ eSymbolContextEverything,
+ pointer_sc);
+ if (pointer_sc.function || pointer_sc.symbol)
+ {
+ s->PutCString(": ");
+ pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false, false);
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!showed_info)
+ {
+ if (module_sp)
+ {
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.function || sc.symbol)
+ {
+ bool show_stop_context = true;
+ const bool show_module = (style == DumpStyleResolvedDescription);
+ const bool show_fullpaths = false;
+ const bool show_inlined_frames = true;
+ if (sc.function == NULL && sc.symbol != NULL)
+ {
+ // If we have just a symbol make sure it is in the right section
+ if (sc.symbol->ValueIsAddress())
+ {
+ if (sc.symbol->GetAddress().GetSection() != GetSection())
+ {
+ // don't show the module if the symbol is a trampoline symbol
+ show_stop_context = false;
+ }
+ }
+ }
+ if (show_stop_context)
+ {
+ // We have a function or a symbol from the same
+ // sections as this address.
+ sc.DumpStopContext (s,
+ exe_scope,
+ *this,
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+ }
+ else
+ {
+ // We found a symbol but it was in a different
+ // section so it isn't the symbol we should be
+ // showing, just show the section name + offset
+ Dump (s, exe_scope, DumpStyleSectionNameOffset);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+
+ case DumpStyleDetailedSymbolContext:
+ if (IsSectionOffset())
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ SymbolContext sc;
+ module_sp->ResolveSymbolContextForAddress(*this, eSymbolContextEverything, sc);
+ if (sc.symbol)
+ {
+ // If we have just a symbol make sure it is in the same section
+ // as our address. If it isn't, then we might have just found
+ // the last symbol that came before the address that we are
+ // looking up that has nothing to do with our address lookup.
+ if (sc.symbol->ValueIsAddress() && sc.symbol->GetAddress().GetSection() != GetSection())
+ sc.symbol = NULL;
+ }
+ sc.GetDescription(s, eDescriptionLevelBrief, target);
+
+ if (sc.block)
+ {
+ bool can_create = true;
+ bool get_parent_variables = true;
+ bool stop_if_block_is_inlined_function = false;
+ VariableList variable_list;
+ sc.block->AppendVariables (can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ &variable_list);
+
+ const size_t num_variables = variable_list.GetSize();
+ for (size_t var_idx = 0; var_idx < num_variables; ++var_idx)
+ {
+ Variable *var = variable_list.GetVariableAtIndex (var_idx).get();
+ if (var && var->LocationIsValidForAddress (*this))
+ {
+ s->Indent();
+ s->Printf (" Variable: id = {0x%8.8" PRIx64 "}, name = \"%s\", type= \"%s\", location =",
+ var->GetID(),
+ var->GetName().GetCString(),
+ var->GetType()->GetName().GetCString());
+ var->DumpLocationForAddress(s, *this);
+ s->PutCString(", decl = ");
+ var->GetDeclaration().DumpStopContext(s, false);
+ s->EOL();
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+ case DumpStyleResolvedPointerDescription:
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t load_addr = GetLoadAddress (target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ Error memory_error;
+ addr_t dereferenced_load_addr = process->ReadPointerFromMemory(load_addr, memory_error);
+ if (dereferenced_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ Address dereferenced_addr;
+ if (dereferenced_addr.SetLoadAddress(dereferenced_load_addr, target))
+ {
+ StreamString strm;
+ if (dereferenced_addr.Dump (&strm, exe_scope, DumpStyleResolvedDescription, DumpStyleInvalid, addr_size))
+ {
+ s->Address (dereferenced_load_addr, addr_size, " -> ", " ");
+ s->Write(strm.GetData(), strm.GetSize());
+ return true;
+ }
+ }
+ }
+ }
+ }
+ if (fallback_style != DumpStyleInvalid)
+ return Dump (s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+uint32_t
+Address::CalculateSymbolContext (SymbolContext *sc, uint32_t resolve_scope) const
+{
+ sc->Clear(false);
+ // Absolute addresses don't have enough information to reconstruct even their target.
+
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ ModuleSP module_sp (section_sp->GetModule());
+ if (module_sp)
+ {
+ sc->module_sp = module_sp;
+ if (sc->module_sp)
+ return sc->module_sp->ResolveSymbolContextForAddress (*this, resolve_scope, *sc);
+ }
+ }
+ return 0;
+}
+
+ModuleSP
+Address::CalculateSymbolContextModule () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ return section_sp->GetModule();
+ return ModuleSP();
+}
+
+CompileUnit *
+Address::CalculateSymbolContextCompileUnit () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextCompUnit, sc);
+ return sc.comp_unit;
+ }
+ }
+ return NULL;
+}
+
+Function *
+Address::CalculateSymbolContextFunction () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextFunction, sc);
+ return sc.function;
+ }
+ }
+ return NULL;
+}
+
+Block *
+Address::CalculateSymbolContextBlock () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextBlock, sc);
+ return sc.block;
+ }
+ }
+ return NULL;
+}
+
+Symbol *
+Address::CalculateSymbolContextSymbol () const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextSymbol, sc);
+ return sc.symbol;
+ }
+ }
+ return NULL;
+}
+
+bool
+Address::CalculateSymbolContextLineEntry (LineEntry &line_entry) const
+{
+ SectionSP section_sp (GetSection());
+ if (section_sp)
+ {
+ SymbolContext sc;
+ sc.module_sp = section_sp->GetModule();
+ if (sc.module_sp)
+ {
+ sc.module_sp->ResolveSymbolContextForAddress (*this, eSymbolContextLineEntry, sc);
+ if (sc.line_entry.IsValid())
+ {
+ line_entry = sc.line_entry;
+ return true;
+ }
+ }
+ }
+ line_entry.Clear();
+ return false;
+}
+
+int
+Address::CompareFileAddress (const Address& a, const Address& b)
+{
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+int
+Address::CompareLoadAddress (const Address& a, const Address& b, Target *target)
+{
+ assert (target != NULL);
+ addr_t a_load_addr = a.GetLoadAddress (target);
+ addr_t b_load_addr = b.GetLoadAddress (target);
+ if (a_load_addr < b_load_addr)
+ return -1;
+ if (a_load_addr > b_load_addr)
+ return +1;
+ return 0;
+}
+
+int
+Address::CompareModulePointerAndOffset (const Address& a, const Address& b)
+{
+ ModuleSP a_module_sp (a.GetModule());
+ ModuleSP b_module_sp (b.GetModule());
+ Module *a_module = a_module_sp.get();
+ Module *b_module = b_module_sp.get();
+ if (a_module < b_module)
+ return -1;
+ if (a_module > b_module)
+ return +1;
+ // Modules are the same, just compare the file address since they should
+ // be unique
+ addr_t a_file_addr = a.GetFileAddress();
+ addr_t b_file_addr = b.GetFileAddress();
+ if (a_file_addr < b_file_addr)
+ return -1;
+ if (a_file_addr > b_file_addr)
+ return +1;
+ return 0;
+}
+
+
+size_t
+Address::MemorySize () const
+{
+ // Noting special for the memory size of a single Address object,
+ // it is just the size of itself.
+ return sizeof(Address);
+}
+
+
+//----------------------------------------------------------------------
+// NOTE: Be careful using this operator. It can correctly compare two
+// addresses from the same Module correctly. It can't compare two
+// addresses from different modules in any meaningful way, but it will
+// compare the module pointers.
+//
+// To sum things up:
+// - works great for addresses within the same module
+// - it works for addresses across multiple modules, but don't expect the
+// address results to make much sense
+//
+// This basically lets Address objects be used in ordered collection
+// classes.
+//----------------------------------------------------------------------
+
+bool
+lldb_private::operator< (const Address& lhs, const Address& rhs)
+{
+ ModuleSP lhs_module_sp (lhs.GetModule());
+ ModuleSP rhs_module_sp (rhs.GetModule());
+ Module *lhs_module = lhs_module_sp.get();
+ Module *rhs_module = rhs_module_sp.get();
+ if (lhs_module == rhs_module)
+ {
+ // Addresses are in the same module, just compare the file addresses
+ return lhs.GetFileAddress() < rhs.GetFileAddress();
+ }
+ else
+ {
+ // The addresses are from different modules, just use the module
+ // pointer value to get consistent ordering
+ return lhs_module < rhs_module;
+ }
+}
+
+bool
+lldb_private::operator> (const Address& lhs, const Address& rhs)
+{
+ ModuleSP lhs_module_sp (lhs.GetModule());
+ ModuleSP rhs_module_sp (rhs.GetModule());
+ Module *lhs_module = lhs_module_sp.get();
+ Module *rhs_module = rhs_module_sp.get();
+ if (lhs_module == rhs_module)
+ {
+ // Addresses are in the same module, just compare the file addresses
+ return lhs.GetFileAddress() > rhs.GetFileAddress();
+ }
+ else
+ {
+ // The addresses are from different modules, just use the module
+ // pointer value to get consistent ordering
+ return lhs_module > rhs_module;
+ }
+}
+
+
+// The operator == checks for exact equality only (same section, same offset)
+bool
+lldb_private::operator== (const Address& a, const Address& rhs)
+{
+ return a.GetOffset() == rhs.GetOffset() &&
+ a.GetSection() == rhs.GetSection();
+}
+// The operator != checks for exact inequality only (differing section, or
+// different offset)
+bool
+lldb_private::operator!= (const Address& a, const Address& rhs)
+{
+ return a.GetOffset() != rhs.GetOffset() ||
+ a.GetSection() != rhs.GetSection();
+}
+
+AddressClass
+Address::GetAddressClass () const
+{
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ ObjectFile *obj_file = module_sp->GetObjectFile();
+ if (obj_file)
+ {
+ // Give the symbol vendor a chance to add to the unified section list.
+ module_sp->GetSymbolVendor();
+ return obj_file->GetAddressClass (GetFileAddress());
+ }
+ }
+ return eAddressClassUnknown;
+}
+
+bool
+Address::SetLoadAddress (lldb::addr_t load_addr, Target *target)
+{
+ if (target && target->GetSectionLoadList().ResolveLoadAddress(load_addr, *this))
+ return true;
+ m_section_wp.reset();
+ m_offset = load_addr;
+ return false;
+}
+
diff --git a/source/Core/AddressRange.cpp b/source/Core/AddressRange.cpp
new file mode 100644
index 000000000000..835a01d82aa4
--- /dev/null
+++ b/source/Core/AddressRange.cpp
@@ -0,0 +1,208 @@
+//===-- AddressRange.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/AddressRange.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+AddressRange::AddressRange () :
+ m_base_addr(),
+ m_byte_size(0)
+{
+}
+
+AddressRange::AddressRange (addr_t file_addr, addr_t byte_size, const SectionList *section_list) :
+ m_base_addr(file_addr, section_list),
+ m_byte_size(byte_size)
+{
+}
+
+AddressRange::AddressRange (const lldb::SectionSP &section, addr_t offset, addr_t byte_size) :
+ m_base_addr(section, offset),
+ m_byte_size(byte_size)
+{
+}
+
+AddressRange::AddressRange (const Address& so_addr, addr_t byte_size) :
+ m_base_addr(so_addr),
+ m_byte_size(byte_size)
+{
+}
+
+AddressRange::~AddressRange ()
+{
+}
+
+//bool
+//AddressRange::Contains (const Address &addr) const
+//{
+// const addr_t byte_size = GetByteSize();
+// if (byte_size)
+// return addr.GetSection() == m_base_addr.GetSection() && (addr.GetOffset() - m_base_addr.GetOffset()) < byte_size;
+//}
+//
+//bool
+//AddressRange::Contains (const Address *addr) const
+//{
+// if (addr)
+// return Contains (*addr);
+// return false;
+//}
+
+bool
+AddressRange::ContainsFileAddress (const Address &addr) const
+{
+ if (addr.GetSection() == m_base_addr.GetSection())
+ return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
+ addr_t file_base_addr = GetBaseAddress().GetFileAddress();
+ if (file_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t file_addr = addr.GetFileAddress();
+ if (file_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (file_base_addr <= file_addr)
+ return (file_addr - file_base_addr) < GetByteSize();
+
+ return false;
+}
+
+bool
+AddressRange::ContainsFileAddress (addr_t file_addr) const
+{
+ if (file_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t file_base_addr = GetBaseAddress().GetFileAddress();
+ if (file_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (file_base_addr <= file_addr)
+ return (file_addr - file_base_addr) < GetByteSize();
+
+ return false;
+}
+
+
+bool
+AddressRange::ContainsLoadAddress (const Address &addr, Target *target) const
+{
+ if (addr.GetSection() == m_base_addr.GetSection())
+ return (addr.GetOffset() - m_base_addr.GetOffset()) < GetByteSize();
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target);
+ if (load_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_addr = addr.GetLoadAddress(target);
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (load_base_addr <= load_addr)
+ return (load_addr - load_base_addr) < GetByteSize();
+
+ return false;
+}
+
+bool
+AddressRange::ContainsLoadAddress (addr_t load_addr, Target *target) const
+{
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t load_base_addr = GetBaseAddress().GetLoadAddress(target);
+ if (load_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (load_base_addr <= load_addr)
+ return (load_addr - load_base_addr) < GetByteSize();
+
+ return false;
+}
+
+void
+AddressRange::Clear()
+{
+ m_base_addr.Clear();
+ m_byte_size = 0;
+}
+
+bool
+AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style) const
+{
+ addr_t vmaddr = LLDB_INVALID_ADDRESS;
+ int addr_size = sizeof (addr_t);
+ if (target)
+ addr_size = target->GetArchitecture().GetAddressByteSize ();
+
+ bool show_module = false;
+ switch (style)
+ {
+ default:
+ break;
+ case Address::DumpStyleSectionNameOffset:
+ case Address::DumpStyleSectionPointerOffset:
+ s->PutChar ('[');
+ m_base_addr.Dump(s, target, style, fallback_style);
+ s->PutChar ('-');
+ s->Address (m_base_addr.GetOffset() + GetByteSize(), addr_size);
+ s->PutChar (')');
+ return true;
+ break;
+
+ case Address::DumpStyleModuleWithFileAddress:
+ show_module = true;
+ // fall through
+ case Address::DumpStyleFileAddress:
+ vmaddr = m_base_addr.GetFileAddress();
+ break;
+
+ case Address::DumpStyleLoadAddress:
+ vmaddr = m_base_addr.GetLoadAddress(target);
+ break;
+ }
+
+ if (vmaddr != LLDB_INVALID_ADDRESS)
+ {
+ if (show_module)
+ {
+ ModuleSP module_sp (GetBaseAddress().GetModule());
+ if (module_sp)
+ s->Printf("%s", module_sp->GetFileSpec().GetFilename().AsCString());
+ }
+ s->AddressRange(vmaddr, vmaddr + GetByteSize(), addr_size);
+ return true;
+ }
+ else if (fallback_style != Address::DumpStyleInvalid)
+ {
+ return Dump(s, target, fallback_style, Address::DumpStyleInvalid);
+ }
+
+ return false;
+}
+
+
+void
+AddressRange::DumpDebug (Stream *s) const
+{
+ s->Printf("%p: AddressRange section = %p, offset = 0x%16.16" PRIx64 ", byte_size = 0x%16.16" PRIx64 "\n", this, m_base_addr.GetSection().get(), m_base_addr.GetOffset(), GetByteSize());
+}
+//
+//bool
+//lldb::operator== (const AddressRange& lhs, const AddressRange& rhs)
+//{
+// if (lhs.GetBaseAddress() == rhs.GetBaseAddress())
+// return lhs.GetByteSize() == rhs.GetByteSize();
+// return false;
+//}
diff --git a/source/Core/AddressResolver.cpp b/source/Core/AddressResolver.cpp
new file mode 100644
index 000000000000..5369d960f251
--- /dev/null
+++ b/source/Core/AddressResolver.cpp
@@ -0,0 +1,67 @@
+//===-- AddressResolver.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/AddressResolver.h"
+
+
+// Project includes
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// AddressResolver:
+//----------------------------------------------------------------------
+AddressResolver::AddressResolver ()
+{
+}
+
+AddressResolver::~AddressResolver ()
+{
+
+}
+
+void
+AddressResolver::ResolveAddressInModules (SearchFilter &filter, ModuleList &modules)
+{
+ filter.SearchInModuleList(*this, modules);
+}
+
+void
+AddressResolver::ResolveAddress (SearchFilter &filter)
+{
+ filter.Search (*this);
+}
+
+std::vector<AddressRange> &
+AddressResolver::GetAddressRanges ()
+{
+ return m_address_ranges;
+}
+
+size_t
+AddressResolver::GetNumberOfAddresses ()
+{
+ return m_address_ranges.size();
+}
+
+AddressRange &
+AddressResolver::GetAddressRangeAtIndex (size_t idx)
+{
+ return m_address_ranges[idx];
+}
diff --git a/source/Core/AddressResolverFileLine.cpp b/source/Core/AddressResolverFileLine.cpp
new file mode 100644
index 000000000000..f7004c8bb089
--- /dev/null
+++ b/source/Core/AddressResolverFileLine.cpp
@@ -0,0 +1,102 @@
+//===-- AddressResolverFileLine.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/AddressResolverFileLine.h"
+
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// AddressResolverFileLine:
+//----------------------------------------------------------------------
+AddressResolverFileLine::AddressResolverFileLine
+(
+ const FileSpec &file_spec,
+ uint32_t line_no,
+ bool check_inlines
+) :
+ AddressResolver (),
+ m_file_spec (file_spec),
+ m_line_number (line_no),
+ m_inlines (check_inlines)
+{
+}
+
+AddressResolverFileLine::~AddressResolverFileLine ()
+{
+}
+
+Searcher::CallbackReturn
+AddressResolverFileLine::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList sc_list;
+ uint32_t sc_list_size;
+ CompileUnit *cu = context.comp_unit;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ sc_list_size = cu->ResolveSymbolContext (m_file_spec, m_line_number, m_inlines, false, eSymbolContextEverything,
+ sc_list);
+ for (uint32_t i = 0; i < sc_list_size; i++)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ Address line_start = sc.line_entry.range.GetBaseAddress();
+ addr_t byte_size = sc.line_entry.range.GetByteSize();
+ if (line_start.IsValid())
+ {
+ AddressRange new_range (line_start, byte_size);
+ m_address_ranges.push_back (new_range);
+ if (log)
+ {
+ StreamString s;
+ //new_bp_loc->GetDescription (&s, lldb::eDescriptionLevelVerbose);
+ //log->Printf ("Added address: %s\n", s.GetData());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: Unable to resolve address at file address 0x%" PRIx64 " for %s:%d\n",
+ line_start.GetFileAddress(),
+ m_file_spec.GetFilename().AsCString("<Unknown>"),
+ m_line_number);
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+AddressResolverFileLine::GetDepth()
+{
+ return Searcher::eDepthCompUnit;
+}
+
+void
+AddressResolverFileLine::GetDescription (Stream *s)
+{
+ s->Printf ("File and line address - file: \"%s\" line: %u", m_file_spec.GetFilename().AsCString(), m_line_number);
+}
+
+
diff --git a/source/Core/AddressResolverName.cpp b/source/Core/AddressResolverName.cpp
new file mode 100644
index 000000000000..dd22e17402ba
--- /dev/null
+++ b/source/Core/AddressResolverName.cpp
@@ -0,0 +1,255 @@
+//===-- AddressResolverName.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/AddressResolverName.h"
+
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+AddressResolverName::AddressResolverName
+(
+ const char *func_name,
+ AddressResolver::MatchType type
+) :
+ AddressResolver (),
+ m_func_name (func_name),
+ m_class_name (NULL),
+ m_regex (),
+ m_match_type (type)
+{
+ if (m_match_type == AddressResolver::Regexp)
+ {
+ if (!m_regex.Compile (m_func_name.AsCString()))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (log)
+ log->Warning ("function name regexp: \"%s\" did not compile.", m_func_name.AsCString());
+ }
+ }
+}
+
+AddressResolverName::AddressResolverName
+(
+ RegularExpression &func_regex
+) :
+ AddressResolver (),
+ m_func_name (NULL),
+ m_class_name (NULL),
+ m_regex (func_regex),
+ m_match_type (AddressResolver::Regexp)
+{
+
+}
+
+AddressResolverName::AddressResolverName
+(
+ const char *class_name,
+ const char *method,
+ AddressResolver::MatchType type
+) :
+ AddressResolver (),
+ m_func_name (method),
+ m_class_name (class_name),
+ m_regex (),
+ m_match_type (type)
+{
+
+}
+
+AddressResolverName::~AddressResolverName ()
+{
+}
+
+// FIXME: Right now we look at the module level, and call the module's "FindFunctions".
+// Greg says he will add function tables, maybe at the CompileUnit level to accelerate function
+// lookup. At that point, we should switch the depth to CompileUnit, and look in these tables.
+
+Searcher::CallbackReturn
+AddressResolverName::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ SymbolContextList func_list;
+ SymbolContextList sym_list;
+
+ bool skip_prologue = true;
+ uint32_t i;
+ SymbolContext sc;
+ Address func_addr;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+
+ if (m_class_name)
+ {
+ if (log)
+ log->Warning ("Class/method function specification not supported yet.\n");
+ return Searcher::eCallbackReturnStop;
+ }
+
+ const bool include_symbols = false;
+ const bool include_inlines = true;
+ const bool append = false;
+ switch (m_match_type)
+ {
+ case AddressResolver::Exact:
+ if (context.module_sp)
+ {
+ context.module_sp->FindSymbolsWithNameAndType (m_func_name,
+ eSymbolTypeCode,
+ sym_list);
+ context.module_sp->FindFunctions (m_func_name,
+ NULL,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ append,
+ func_list);
+ }
+ break;
+
+ case AddressResolver::Regexp:
+ if (context.module_sp)
+ {
+ context.module_sp->FindSymbolsMatchingRegExAndType (m_regex,
+ eSymbolTypeCode,
+ sym_list);
+ context.module_sp->FindFunctions (m_regex,
+ include_symbols,
+ include_inlines,
+ append,
+ func_list);
+ }
+ break;
+
+ case AddressResolver::Glob:
+ if (log)
+ log->Warning ("glob is not supported yet.");
+ break;
+ }
+
+ // Remove any duplicates between the funcion list and the symbol list
+ if (func_list.GetSize())
+ {
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc) == false)
+ continue;
+
+ if (sc.function == NULL)
+ continue;
+ uint32_t j = 0;
+ while (j < sym_list.GetSize())
+ {
+ SymbolContext symbol_sc;
+ if (sym_list.GetContextAtIndex(j, symbol_sc))
+ {
+ if (symbol_sc.symbol && symbol_sc.symbol->ValueIsAddress())
+ {
+ if (sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
+ {
+ sym_list.RemoveContextAtIndex(j);
+ continue; // Don't increment j
+ }
+ }
+ }
+
+ j++;
+ }
+ }
+
+ for (i = 0; i < func_list.GetSize(); i++)
+ {
+ if (func_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.function)
+ {
+ func_addr = sc.function->GetAddressRange().GetBaseAddress();
+ addr_t byte_size = sc.function->GetAddressRange().GetByteSize();
+ if (skip_prologue)
+ {
+ const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
+ if (prologue_byte_size)
+ {
+ func_addr.SetOffset (func_addr.GetOffset() + prologue_byte_size);
+ byte_size -= prologue_byte_size;
+ }
+ }
+
+ if (filter.AddressPasses (func_addr))
+ {
+ AddressRange new_range (func_addr, byte_size);
+ m_address_ranges.push_back (new_range);
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < sym_list.GetSize(); i++)
+ {
+ if (sym_list.GetContextAtIndex(i, sc))
+ {
+ if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ func_addr = sc.symbol->GetAddress();
+ addr_t byte_size = sc.symbol->GetByteSize();
+
+ if (skip_prologue)
+ {
+ const uint32_t prologue_byte_size = sc.symbol->GetPrologueByteSize();
+ if (prologue_byte_size)
+ {
+ func_addr.SetOffset (func_addr.GetOffset() + prologue_byte_size);
+ byte_size -= prologue_byte_size;
+ }
+ }
+
+ if (filter.AddressPasses (func_addr))
+ {
+ AddressRange new_range (func_addr, byte_size);
+ m_address_ranges.push_back (new_range);
+ }
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+AddressResolverName::GetDepth()
+{
+ return Searcher::eDepthModule;
+}
+
+void
+AddressResolverName::GetDescription (Stream *s)
+{
+ s->PutCString("Address by function name: ");
+
+ if (m_match_type == AddressResolver::Regexp)
+ s->Printf("'%s' (regular expression)", m_regex.GetText());
+ else
+ s->Printf("'%s'", m_func_name.AsCString());
+}
+
diff --git a/source/Core/ArchSpec.cpp b/source/Core/ArchSpec.cpp
new file mode 100644
index 000000000000..27d62c358bbf
--- /dev/null
+++ b/source/Core/ArchSpec.cpp
@@ -0,0 +1,893 @@
+//===-- ArchSpec.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/ArchSpec.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <string>
+
+#include "llvm/Support/ELF.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ARCH_SPEC_SEPARATOR_CHAR '-'
+
+
+static bool cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match);
+
+namespace lldb_private {
+
+ struct CoreDefinition
+ {
+ ByteOrder default_byte_order;
+ uint32_t addr_byte_size;
+ uint32_t min_opcode_byte_size;
+ uint32_t max_opcode_byte_size;
+ llvm::Triple::ArchType machine;
+ ArchSpec::Core core;
+ const char *name;
+ };
+
+}
+
+// This core information can be looked using the ArchSpec::Core as the index
+static const CoreDefinition g_core_definitions[ArchSpec::kNumCores] =
+{
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_generic , "arm" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4 , "armv4" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv4t , "armv4t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5 , "armv5" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5e , "armv5e" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv5t , "armv5t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv6 , "armv6" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7 , "armv7" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7f , "armv7f" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7s , "armv7s" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7k , "armv7k" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7m , "armv7m" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_armv7em , "armv7em" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::arm , ArchSpec::eCore_arm_xscale , "xscale" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumb , "thumb" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv4t , "thumbv4t" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5 , "thumbv5" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv5e , "thumbv5e" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv6 , "thumbv6" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7 , "thumbv7" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7f , "thumbv7f" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7s , "thumbv7s" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7k , "thumbv7k" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7m , "thumbv7m" },
+ { eByteOrderLittle, 4, 2, 4, llvm::Triple::thumb , ArchSpec::eCore_thumbv7em , "thumbv7em" },
+
+
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_generic , "ppc" },
+ { 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" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603e , "ppc603e" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc603ev , "ppc603ev" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604 , "ppc604" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc604e , "ppc604e" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc620 , "ppc620" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc750 , "ppc750" },
+ { eByteOrderBig , 4, 4, 4, llvm::Triple::ppc , ArchSpec::eCore_ppc_ppc7400 , "ppc7400" },
+ { 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_ppc970_64 , "ppc970-64" },
+
+ { eByteOrderLittle, 4, 4, 4, llvm::Triple::sparc , ArchSpec::eCore_sparc_generic , "sparc" },
+ { eByteOrderLittle, 8, 4, 4, llvm::Triple::sparcv9, ArchSpec::eCore_sparc9_generic , "sparcv9" },
+
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i386 , "i386" },
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486 , "i486" },
+ { eByteOrderLittle, 4, 1, 15, llvm::Triple::x86 , ArchSpec::eCore_x86_32_i486sx , "i486sx" },
+
+ { eByteOrderLittle, 8, 1, 15, llvm::Triple::x86_64 , ArchSpec::eCore_x86_64_x86_64 , "x86_64" },
+ { 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" }
+};
+
+struct ArchDefinitionEntry
+{
+ ArchSpec::Core core;
+ uint32_t cpu;
+ uint32_t sub;
+ uint32_t cpu_mask;
+ uint32_t sub_mask;
+};
+
+struct ArchDefinition
+{
+ ArchitectureType type;
+ size_t num_entries;
+ const ArchDefinitionEntry *entries;
+ const char *name;
+};
+
+
+size_t
+ArchSpec::AutoComplete (const char *name, StringList &matches)
+{
+ uint32_t i;
+ if (name && name[0])
+ {
+ for (i = 0; i < ArchSpec::kNumCores; ++i)
+ {
+ if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name))
+ matches.AppendString (g_core_definitions[i].name);
+ }
+ }
+ else
+ {
+ for (i = 0; i < ArchSpec::kNumCores; ++i)
+ matches.AppendString (g_core_definitions[i].name);
+ }
+ return matches.GetSize();
+}
+
+
+
+#define CPU_ANY (UINT32_MAX)
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+#define SUBTYPE_MASK 0x00FFFFFFu
+static const ArchDefinitionEntry g_macho_arch_entries[] =
+{
+ { ArchSpec::eCore_arm_generic , llvm::MachO::CPUTypeARM , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_arm_generic , llvm::MachO::CPUTypeARM , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv4 , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv4t , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv6 , llvm::MachO::CPUTypeARM , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5 , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5e , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv5t , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_xscale , llvm::MachO::CPUTypeARM , 8 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7 , llvm::MachO::CPUTypeARM , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7f , llvm::MachO::CPUTypeARM , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7s , llvm::MachO::CPUTypeARM , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7k , llvm::MachO::CPUTypeARM , 12 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7m , llvm::MachO::CPUTypeARM , 15 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_arm_armv7em , llvm::MachO::CPUTypeARM , 16 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumb , llvm::MachO::CPUTypeARM , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv4t , llvm::MachO::CPUTypeARM , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv5 , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv5e , llvm::MachO::CPUTypeARM , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv6 , llvm::MachO::CPUTypeARM , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7 , llvm::MachO::CPUTypeARM , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7f , llvm::MachO::CPUTypeARM , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7s , llvm::MachO::CPUTypeARM , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7k , llvm::MachO::CPUTypeARM , 12 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7m , llvm::MachO::CPUTypeARM , 15 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_thumbv7em , llvm::MachO::CPUTypeARM , 16 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_generic , llvm::MachO::CPUTypePowerPC , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_ppc_generic , llvm::MachO::CPUTypePowerPC , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc601 , llvm::MachO::CPUTypePowerPC , 1 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc602 , llvm::MachO::CPUTypePowerPC , 2 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603 , llvm::MachO::CPUTypePowerPC , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603e , llvm::MachO::CPUTypePowerPC , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc603ev , llvm::MachO::CPUTypePowerPC , 5 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc604 , llvm::MachO::CPUTypePowerPC , 6 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc604e , llvm::MachO::CPUTypePowerPC , 7 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc620 , llvm::MachO::CPUTypePowerPC , 8 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc750 , llvm::MachO::CPUTypePowerPC , 9 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc7400 , llvm::MachO::CPUTypePowerPC , 10 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc7450 , llvm::MachO::CPUTypePowerPC , 11 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc_ppc970 , llvm::MachO::CPUTypePowerPC , 100 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc64_generic , llvm::MachO::CPUTypePowerPC64 , 0 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_ppc64_ppc970_64 , llvm::MachO::CPUTypePowerPC64 , 100 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPUTypeI386 , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i486 , llvm::MachO::CPUTypeI386 , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i486sx , llvm::MachO::CPUTypeI386 , 0x84 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_32_i386 , llvm::MachO::CPUTypeI386 , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , 3 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , 4 , UINT32_MAX , SUBTYPE_MASK },
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::MachO::CPUTypeX86_64 , CPU_ANY, UINT32_MAX , UINT32_MAX },
+ // Catch any unknown mach architectures so we can always use the object and symbol mach-o files
+ { ArchSpec::eCore_uknownMach32 , 0 , 0 , 0xFF000000u, 0x00000000u },
+ { ArchSpec::eCore_uknownMach64 , llvm::MachO::CPUArchABI64 , 0 , 0xFF000000u, 0x00000000u }
+};
+static const ArchDefinition g_macho_arch_def = {
+ eArchTypeMachO,
+ sizeof(g_macho_arch_entries)/sizeof(g_macho_arch_entries[0]),
+ g_macho_arch_entries,
+ "mach-o"
+};
+
+//===----------------------------------------------------------------------===//
+// A table that gets searched linearly for matches. This table is used to
+// convert cpu type and subtypes to architecture names, and to convert
+// architecture names to cpu types and subtypes. The ordering is important and
+// allows the precedence to be set when the table is built.
+static const ArchDefinitionEntry g_elf_arch_entries[] =
+{
+ { ArchSpec::eCore_sparc_generic , llvm::ELF::EM_SPARC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Sparc
+ { ArchSpec::eCore_x86_32_i386 , llvm::ELF::EM_386 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 80386
+ { ArchSpec::eCore_x86_32_i486 , llvm::ELF::EM_486 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // Intel 486 (deprecated)
+ { ArchSpec::eCore_ppc_generic , llvm::ELF::EM_PPC , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC
+ { ArchSpec::eCore_ppc64_generic , llvm::ELF::EM_PPC64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // PowerPC64
+ { ArchSpec::eCore_arm_generic , llvm::ELF::EM_ARM , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // ARM
+ { ArchSpec::eCore_sparc9_generic , llvm::ELF::EM_SPARCV9, LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu }, // SPARC V9
+ { ArchSpec::eCore_x86_64_x86_64 , llvm::ELF::EM_X86_64 , LLDB_INVALID_CPUTYPE, 0xFFFFFFFFu, 0xFFFFFFFFu } // AMD64
+};
+
+static const ArchDefinition g_elf_arch_def = {
+ eArchTypeELF,
+ sizeof(g_elf_arch_entries)/sizeof(g_elf_arch_entries[0]),
+ g_elf_arch_entries,
+ "elf",
+};
+
+//===----------------------------------------------------------------------===//
+// Table of all ArchDefinitions
+static const ArchDefinition *g_arch_definitions[] = {
+ &g_macho_arch_def,
+ &g_elf_arch_def
+};
+
+static const size_t k_num_arch_definitions =
+ sizeof(g_arch_definitions) / sizeof(g_arch_definitions[0]);
+
+//===----------------------------------------------------------------------===//
+// Static helper functions.
+
+
+// Get the architecture definition for a given object type.
+static const ArchDefinition *
+FindArchDefinition (ArchitectureType arch_type)
+{
+ for (unsigned int i = 0; i < k_num_arch_definitions; ++i)
+ {
+ const ArchDefinition *def = g_arch_definitions[i];
+ if (def->type == arch_type)
+ return def;
+ }
+ return NULL;
+}
+
+// Get an architecture definition by name.
+static const CoreDefinition *
+FindCoreDefinition (llvm::StringRef name)
+{
+ for (unsigned int i = 0; i < ArchSpec::kNumCores; ++i)
+ {
+ if (name.equals_lower(g_core_definitions[i].name))
+ return &g_core_definitions[i];
+ }
+ return NULL;
+}
+
+static inline const CoreDefinition *
+FindCoreDefinition (ArchSpec::Core core)
+{
+ if (core >= 0 && core < ArchSpec::kNumCores)
+ return &g_core_definitions[core];
+ return NULL;
+}
+
+// Get a definition entry by cpu type and subtype.
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry (const ArchDefinition *def, uint32_t cpu, uint32_t sub)
+{
+ if (def == NULL)
+ return NULL;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i)
+ {
+ if (entries[i].cpu == (cpu & entries[i].cpu_mask))
+ if (entries[i].sub == (sub & entries[i].sub_mask))
+ return &entries[i];
+ }
+ return NULL;
+}
+
+static const ArchDefinitionEntry *
+FindArchDefinitionEntry (const ArchDefinition *def, ArchSpec::Core core)
+{
+ if (def == NULL)
+ return NULL;
+
+ const ArchDefinitionEntry *entries = def->entries;
+ for (size_t i = 0; i < def->num_entries; ++i)
+ {
+ if (entries[i].core == core)
+ return &entries[i];
+ }
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// Constructors and destructors.
+
+ArchSpec::ArchSpec() :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+}
+
+ArchSpec::ArchSpec (const char *triple_cstr, Platform *platform) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ if (triple_cstr)
+ SetTriple(triple_cstr, platform);
+}
+
+
+ArchSpec::ArchSpec (const char *triple_cstr) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ if (triple_cstr)
+ SetTriple(triple_cstr);
+}
+
+ArchSpec::ArchSpec(const llvm::Triple &triple) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ SetTriple(triple);
+}
+
+ArchSpec::ArchSpec (ArchitectureType arch_type, uint32_t cpu, uint32_t subtype) :
+ m_triple (),
+ m_core (kCore_invalid),
+ m_byte_order (eByteOrderInvalid)
+{
+ SetArchitecture (arch_type, cpu, subtype);
+}
+
+ArchSpec::~ArchSpec()
+{
+}
+
+//===----------------------------------------------------------------------===//
+// Assignment and initialization.
+
+const ArchSpec&
+ArchSpec::operator= (const ArchSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_triple = rhs.m_triple;
+ m_core = rhs.m_core;
+ m_byte_order = rhs.m_byte_order;
+ }
+ return *this;
+}
+
+void
+ArchSpec::Clear()
+{
+ m_triple = llvm::Triple();
+ m_core = kCore_invalid;
+ m_byte_order = eByteOrderInvalid;
+}
+
+//===----------------------------------------------------------------------===//
+// Predicates.
+
+
+const char *
+ArchSpec::GetArchitectureName () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->name;
+ return "unknown";
+}
+
+uint32_t
+ArchSpec::GetMachOCPUType () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core);
+ if (arch_def)
+ {
+ return arch_def->cpu;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+uint32_t
+ArchSpec::GetMachOCPUSubType () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ const ArchDefinitionEntry *arch_def = FindArchDefinitionEntry (&g_macho_arch_def, core_def->core);
+ if (arch_def)
+ {
+ return arch_def->sub;
+ }
+ }
+ return LLDB_INVALID_CPUTYPE;
+}
+
+llvm::Triple::ArchType
+ArchSpec::GetMachine () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->machine;
+
+ return llvm::Triple::UnknownArch;
+}
+
+uint32_t
+ArchSpec::GetAddressByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->addr_byte_size;
+ return 0;
+}
+
+ByteOrder
+ArchSpec::GetDefaultEndian () const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->default_byte_order;
+ return eByteOrderInvalid;
+}
+
+lldb::ByteOrder
+ArchSpec::GetByteOrder () const
+{
+ if (m_byte_order == eByteOrderInvalid)
+ return GetDefaultEndian();
+ return m_byte_order;
+}
+
+//===----------------------------------------------------------------------===//
+// Mutators.
+
+bool
+ArchSpec::SetTriple (const llvm::Triple &triple)
+{
+ m_triple = triple;
+
+ llvm::StringRef arch_name (m_triple.getArchName());
+ const CoreDefinition *core_def = FindCoreDefinition (arch_name);
+ if (core_def)
+ {
+ m_core = core_def->core;
+ // Set the byte order to the default byte order for an architecture.
+ // This can be modified if needed for cases when cores handle both
+ // big and little endian
+ m_byte_order = core_def->default_byte_order;
+ }
+ else
+ {
+ Clear();
+ }
+
+
+ return IsValid();
+}
+
+static bool
+ParseMachCPUDashSubtypeTriple (const char *triple_cstr, ArchSpec &arch)
+{
+ // Accept "12-10" or "12.10" as cpu type/subtype
+ if (isdigit(triple_cstr[0]))
+ {
+ char *end = NULL;
+ errno = 0;
+ uint32_t cpu = (uint32_t)::strtoul (triple_cstr, &end, 0);
+ if (errno == 0 && cpu != 0 && end && ((*end == '-') || (*end == '.')))
+ {
+ errno = 0;
+ uint32_t sub = (uint32_t)::strtoul (end + 1, &end, 0);
+ if (errno == 0 && end && ((*end == '-') || (*end == '.') || (*end == '\0')))
+ {
+ if (arch.SetArchitecture (eArchTypeMachO, cpu, sub))
+ {
+ if (*end == '-')
+ {
+ llvm::StringRef vendor_os (end + 1);
+ size_t dash_pos = vendor_os.find('-');
+ if (dash_pos != llvm::StringRef::npos)
+ {
+ llvm::StringRef vendor_str(vendor_os.substr(0, dash_pos));
+ arch.GetTriple().setVendorName(vendor_str);
+ const size_t vendor_start_pos = dash_pos+1;
+ dash_pos = vendor_os.find('-', vendor_start_pos);
+ if (dash_pos == llvm::StringRef::npos)
+ {
+ if (vendor_start_pos < vendor_os.size())
+ arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos));
+ }
+ else
+ {
+ arch.GetTriple().setOSName(vendor_os.substr(vendor_start_pos, dash_pos - vendor_start_pos));
+ }
+ }
+ }
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+bool
+ArchSpec::SetTriple (const char *triple_cstr)
+{
+ if (triple_cstr && triple_cstr[0])
+ {
+ if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this))
+ return true;
+
+ llvm::StringRef triple_stref (triple_cstr);
+ if (triple_stref.startswith (LLDB_ARCH_DEFAULT))
+ {
+ // Special case for the current host default architectures...
+ if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ }
+ else
+ {
+ std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref));
+ triple_stref = normalized_triple_sstr;
+ SetTriple (llvm::Triple (triple_stref));
+ }
+ }
+ else
+ Clear();
+ return IsValid();
+}
+
+bool
+ArchSpec::SetTriple (const char *triple_cstr, Platform *platform)
+{
+ if (triple_cstr && triple_cstr[0])
+ {
+ if (ParseMachCPUDashSubtypeTriple (triple_cstr, *this))
+ return true;
+
+ llvm::StringRef triple_stref (triple_cstr);
+ if (triple_stref.startswith (LLDB_ARCH_DEFAULT))
+ {
+ // Special case for the current host default architectures...
+ if (triple_stref.equals (LLDB_ARCH_DEFAULT_32BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT_64BIT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture64);
+ else if (triple_stref.equals (LLDB_ARCH_DEFAULT))
+ *this = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ }
+ else
+ {
+ ArchSpec raw_arch (triple_cstr);
+
+ std::string normalized_triple_sstr (llvm::Triple::normalize(triple_stref));
+ triple_stref = normalized_triple_sstr;
+ llvm::Triple normalized_triple (triple_stref);
+
+ const bool os_specified = normalized_triple.getOSName().size() > 0;
+ const bool vendor_specified = normalized_triple.getVendorName().size() > 0;
+ const bool env_specified = normalized_triple.getEnvironmentName().size() > 0;
+
+ // If we got an arch only, then default the vendor, os, environment
+ // to match the platform if one is supplied
+ if (!(os_specified || vendor_specified || env_specified))
+ {
+ if (platform)
+ {
+ // If we were given a platform, use the platform's system
+ // architecture. If this is not available (might not be
+ // connected) use the first supported architecture.
+ ArchSpec compatible_arch;
+ if (platform->IsCompatibleArchitecture (raw_arch, false, &compatible_arch))
+ {
+ if (compatible_arch.IsValid())
+ {
+ const llvm::Triple &compatible_triple = compatible_arch.GetTriple();
+ if (!vendor_specified)
+ normalized_triple.setVendor(compatible_triple.getVendor());
+ if (!os_specified)
+ normalized_triple.setOS(compatible_triple.getOS());
+ if (!env_specified && compatible_triple.getEnvironmentName().size())
+ normalized_triple.setEnvironment(compatible_triple.getEnvironment());
+ }
+ }
+ else
+ {
+ *this = raw_arch;
+ return IsValid();
+ }
+ }
+ else
+ {
+ // No platform specified, fall back to the host system for
+ // the default vendor, os, and environment.
+ llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
+ if (!vendor_specified)
+ normalized_triple.setVendor(host_triple.getVendor());
+ if (!vendor_specified)
+ normalized_triple.setOS(host_triple.getOS());
+ if (!env_specified && host_triple.getEnvironmentName().size())
+ normalized_triple.setEnvironment(host_triple.getEnvironment());
+ }
+ }
+ SetTriple (normalized_triple);
+ }
+ }
+ else
+ Clear();
+ return IsValid();
+}
+
+bool
+ArchSpec::SetArchitecture (ArchitectureType arch_type, uint32_t cpu, uint32_t sub)
+{
+ m_core = kCore_invalid;
+ bool update_triple = true;
+ const ArchDefinition *arch_def = FindArchDefinition(arch_type);
+ if (arch_def)
+ {
+ const ArchDefinitionEntry *arch_def_entry = FindArchDefinitionEntry (arch_def, cpu, sub);
+ if (arch_def_entry)
+ {
+ const CoreDefinition *core_def = FindCoreDefinition (arch_def_entry->core);
+ if (core_def)
+ {
+ m_core = core_def->core;
+ update_triple = false;
+ // Always use the architecture name because it might be more descriptive
+ // than the architecture enum ("armv7" -> llvm::Triple::arm).
+ m_triple.setArchName(llvm::StringRef(core_def->name));
+ if (arch_type == eArchTypeMachO)
+ {
+ m_triple.setVendor (llvm::Triple::Apple);
+
+ switch (core_def->machine)
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ m_triple.setOS (llvm::Triple::IOS);
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ default:
+ m_triple.setOS (llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ else
+ {
+ m_triple.setVendor (llvm::Triple::UnknownVendor);
+ m_triple.setOS (llvm::Triple::UnknownOS);
+ }
+ // Fall back onto setting the machine type if the arch by name failed...
+ if (m_triple.getArch () == llvm::Triple::UnknownArch)
+ m_triple.setArch (core_def->machine);
+ }
+ }
+ }
+ CoreUpdated(update_triple);
+ return IsValid();
+}
+
+uint32_t
+ArchSpec::GetMinimumOpcodeByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->min_opcode_byte_size;
+ return 0;
+}
+
+uint32_t
+ArchSpec::GetMaximumOpcodeByteSize() const
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ return core_def->max_opcode_byte_size;
+ return 0;
+}
+
+bool
+ArchSpec::IsExactMatch (const ArchSpec& rhs) const
+{
+ return IsEqualTo (rhs, true);
+}
+
+bool
+ArchSpec::IsCompatibleMatch (const ArchSpec& rhs) const
+{
+ return IsEqualTo (rhs, false);
+}
+
+bool
+ArchSpec::IsEqualTo (const ArchSpec& rhs, bool exact_match) const
+{
+ if (GetByteOrder() != rhs.GetByteOrder())
+ return false;
+
+ const ArchSpec::Core lhs_core = GetCore ();
+ const ArchSpec::Core rhs_core = rhs.GetCore ();
+
+ const bool core_match = cores_match (lhs_core, rhs_core, true, exact_match);
+
+ if (core_match)
+ {
+ const llvm::Triple &lhs_triple = GetTriple();
+ const llvm::Triple &rhs_triple = rhs.GetTriple();
+
+ const llvm::Triple::VendorType lhs_triple_vendor = lhs_triple.getVendor();
+ const llvm::Triple::VendorType rhs_triple_vendor = rhs_triple.getVendor();
+ if (lhs_triple_vendor != rhs_triple_vendor)
+ {
+ if (exact_match)
+ {
+ const bool rhs_vendor_specified = rhs.TripleVendorWasSpecified();
+ const bool lhs_vendor_specified = TripleVendorWasSpecified();
+ // Both architectures had the vendor specified, so if they aren't
+ // equal then we return false
+ if (rhs_vendor_specified && lhs_vendor_specified)
+ return false;
+ }
+
+ // Only fail if both vendor types are not unknown
+ if (lhs_triple_vendor != llvm::Triple::UnknownVendor &&
+ rhs_triple_vendor != llvm::Triple::UnknownVendor)
+ return false;
+ }
+
+ const llvm::Triple::OSType lhs_triple_os = lhs_triple.getOS();
+ const llvm::Triple::OSType rhs_triple_os = rhs_triple.getOS();
+ if (lhs_triple_os != rhs_triple_os)
+ {
+ if (exact_match)
+ {
+ const bool rhs_os_specified = rhs.TripleOSWasSpecified();
+ const bool lhs_os_specified = TripleOSWasSpecified();
+ // Both architectures had the OS specified, so if they aren't
+ // equal then we return false
+ if (rhs_os_specified && lhs_os_specified)
+ return false;
+ }
+ // Only fail if both os types are not unknown
+ if (lhs_triple_os != llvm::Triple::UnknownOS &&
+ rhs_triple_os != llvm::Triple::UnknownOS)
+ return false;
+ }
+
+ const llvm::Triple::EnvironmentType lhs_triple_env = lhs_triple.getEnvironment();
+ const llvm::Triple::EnvironmentType rhs_triple_env = rhs_triple.getEnvironment();
+
+ if (lhs_triple_env != rhs_triple_env)
+ {
+ // Only fail if both environment types are not unknown
+ if (lhs_triple_env != llvm::Triple::UnknownEnvironment &&
+ rhs_triple_env != llvm::Triple::UnknownEnvironment)
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Helper methods.
+
+void
+ArchSpec::CoreUpdated (bool update_triple)
+{
+ const CoreDefinition *core_def = FindCoreDefinition (m_core);
+ if (core_def)
+ {
+ if (update_triple)
+ m_triple = llvm::Triple(core_def->name, "unknown", "unknown");
+ m_byte_order = core_def->default_byte_order;
+ }
+ else
+ {
+ if (update_triple)
+ m_triple = llvm::Triple();
+ m_byte_order = eByteOrderInvalid;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+// Operators.
+
+static bool
+cores_match (const ArchSpec::Core core1, const ArchSpec::Core core2, bool try_inverse, bool enforce_exact_match)
+{
+ if (core1 == core2)
+ return true;
+
+ switch (core1)
+ {
+ case ArchSpec::kCore_any:
+ return true;
+
+ case ArchSpec::kCore_arm_any:
+ if (core2 >= ArchSpec::kCore_arm_first && core2 <= ArchSpec::kCore_arm_last)
+ return true;
+ if (core2 >= ArchSpec::kCore_thumb_first && core2 <= ArchSpec::kCore_thumb_last)
+ return true;
+ if (core2 == ArchSpec::kCore_arm_any)
+ return true;
+ break;
+
+ case ArchSpec::kCore_x86_32_any:
+ if ((core2 >= ArchSpec::kCore_x86_32_first && core2 <= ArchSpec::kCore_x86_32_last) || (core2 == ArchSpec::kCore_x86_32_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc_any:
+ if ((core2 >= ArchSpec::kCore_ppc_first && core2 <= ArchSpec::kCore_ppc_last) || (core2 == ArchSpec::kCore_ppc_any))
+ return true;
+ break;
+
+ case ArchSpec::kCore_ppc64_any:
+ if ((core2 >= ArchSpec::kCore_ppc64_first && core2 <= ArchSpec::kCore_ppc64_last) || (core2 == ArchSpec::kCore_ppc64_any))
+ return true;
+ break;
+
+ case ArchSpec::eCore_arm_armv7m:
+ case ArchSpec::eCore_arm_armv7em:
+ case ArchSpec::eCore_arm_armv7f:
+ case ArchSpec::eCore_arm_armv7k:
+ case ArchSpec::eCore_arm_armv7s:
+ if (!enforce_exact_match)
+ {
+ try_inverse = false;
+ if (core2 == ArchSpec::eCore_arm_armv7)
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (try_inverse)
+ return cores_match (core2, core1, false, enforce_exact_match);
+ return false;
+}
+
+bool
+lldb_private::operator<(const ArchSpec& lhs, const ArchSpec& rhs)
+{
+ const ArchSpec::Core lhs_core = lhs.GetCore ();
+ const ArchSpec::Core rhs_core = rhs.GetCore ();
+ return lhs_core < rhs_core;
+}
diff --git a/source/Core/Baton.cpp b/source/Core/Baton.cpp
new file mode 100644
index 000000000000..8bed01be8839
--- /dev/null
+++ b/source/Core/Baton.cpp
@@ -0,0 +1,24 @@
+//===-- Baton.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/Baton.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+Baton::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+}
diff --git a/source/Core/Broadcaster.cpp b/source/Core/Broadcaster.cpp
new file mode 100644
index 000000000000..5af7497c8da9
--- /dev/null
+++ b/source/Core/Broadcaster.cpp
@@ -0,0 +1,499 @@
+//===-- Broadcaster.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/Broadcaster.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Broadcaster::Broadcaster (BroadcasterManager *manager, const char *name) :
+ m_broadcaster_name (name),
+ m_listeners (),
+ m_listeners_mutex (Mutex::eMutexTypeRecursive),
+ m_hijacking_listeners(),
+ m_hijacking_masks(),
+ m_manager (manager)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Broadcaster::Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
+
+}
+
+Broadcaster::~Broadcaster()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Broadcaster::~Broadcaster(\"%s\")", this, m_broadcaster_name.AsCString());
+
+ Clear();
+}
+
+void
+Broadcaster::CheckInWithManager ()
+{
+ if (m_manager != NULL)
+ {
+ m_manager->SignUpListenersForBroadcaster(*this);
+ }
+}
+
+void
+Broadcaster::Clear()
+{
+ Mutex::Locker listeners_locker(m_listeners_mutex);
+
+ // Make sure the listener forgets about this broadcaster. We do
+ // this in the broadcaster in case the broadcaster object initiates
+ // the removal.
+
+ collection::iterator pos, end = m_listeners.end();
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ pos->first->BroadcasterWillDestruct (this);
+
+ m_listeners.clear();
+}
+const ConstString &
+Broadcaster::GetBroadcasterName ()
+{
+ return m_broadcaster_name;
+}
+
+bool
+Broadcaster::GetEventNames (Stream &s, uint32_t event_mask, bool prefix_with_broadcaster_name) const
+{
+ uint32_t num_names_added = 0;
+ if (event_mask && !m_event_names.empty())
+ {
+ event_names_map::const_iterator end = m_event_names.end();
+ for (uint32_t bit=1u, mask=event_mask; mask != 0 && bit != 0; bit <<= 1, mask >>= 1)
+ {
+ if (mask & 1)
+ {
+ event_names_map::const_iterator pos = m_event_names.find(bit);
+ if (pos != end)
+ {
+ if (num_names_added > 0)
+ s.PutCString(", ");
+
+ if (prefix_with_broadcaster_name)
+ {
+ s.PutCString (m_broadcaster_name.GetCString());
+ s.PutChar('.');
+ }
+ s.PutCString(pos->second.c_str());
+ ++num_names_added;
+ }
+ }
+ }
+ }
+ return num_names_added > 0;
+}
+
+void
+Broadcaster::AddInitialEventsToListener (Listener *listener, uint32_t requested_events)
+{
+
+}
+
+uint32_t
+Broadcaster::AddListener (Listener* listener, uint32_t event_mask)
+{
+ if (listener == NULL)
+ return 0;
+
+ Mutex::Locker locker(m_listeners_mutex);
+ collection::iterator pos, end = m_listeners.end();
+
+ collection::iterator existing_pos = end;
+ // See if we already have this listener, and if so, update its mask
+ uint32_t taken_event_types = 0;
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->first == listener)
+ existing_pos = pos;
+ // For now don't descriminate on who gets what
+ // FIXME: Implement "unique listener for this bit" mask
+ // taken_event_types |= pos->second;
+ }
+
+ // Each event bit in a Broadcaster object can only be used
+ // by one listener
+ uint32_t available_event_types = ~taken_event_types & event_mask;
+
+ if (available_event_types)
+ {
+ // If we didn't find our listener, add it
+ if (existing_pos == end)
+ {
+ // Grant a new listener the available event bits
+ m_listeners.push_back(std::make_pair(listener, available_event_types));
+ }
+ else
+ {
+ // Grant the existing listener the available event bits
+ existing_pos->second |= available_event_types;
+ }
+
+ // Individual broadcasters decide whether they have outstanding data when a
+ // listener attaches, and insert it into the listener with this method.
+
+ AddInitialEventsToListener (listener, available_event_types);
+ }
+
+ // Return the event bits that were granted to the listener
+ return available_event_types;
+}
+
+bool
+Broadcaster::EventTypeHasListeners (uint32_t event_type)
+{
+ Mutex::Locker locker (m_listeners_mutex);
+
+ if (m_hijacking_listeners.size() > 0 && event_type & m_hijacking_masks.back())
+ return true;
+
+ if (m_listeners.empty())
+ return false;
+
+ collection::iterator pos, end = m_listeners.end();
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->second & event_type)
+ return true;
+ }
+ return false;
+}
+
+bool
+Broadcaster::RemoveListener (Listener* listener, uint32_t event_mask)
+{
+ Mutex::Locker locker(m_listeners_mutex);
+ collection::iterator pos, end = m_listeners.end();
+ // See if we already have this listener, and if so, update its mask
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ if (pos->first == listener)
+ {
+ // Relinquish all event bits in "event_mask"
+ pos->second &= ~event_mask;
+ // If all bits have been relinquished then remove this listener
+ if (pos->second == 0)
+ m_listeners.erase (pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Broadcaster::BroadcastEvent (EventSP &event_sp)
+{
+ return PrivateBroadcastEvent (event_sp, false);
+}
+
+void
+Broadcaster::BroadcastEventIfUnique (EventSP &event_sp)
+{
+ return PrivateBroadcastEvent (event_sp, true);
+}
+
+void
+Broadcaster::PrivateBroadcastEvent (EventSP &event_sp, bool unique)
+{
+ // Can't add a NULL event...
+ if (event_sp.get() == NULL)
+ return;
+
+ // Update the broadcaster on this event
+ event_sp->SetBroadcaster (this);
+
+ const uint32_t event_type = event_sp->GetType();
+
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Listener *hijacking_listener = NULL;
+ if (!m_hijacking_listeners.empty())
+ {
+ assert (!m_hijacking_masks.empty());
+ hijacking_listener = m_hijacking_listeners.back();
+ if ((event_type & m_hijacking_masks.back()) == 0)
+ hijacking_listener = NULL;
+ }
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ {
+ StreamString event_description;
+ event_sp->Dump (&event_description);
+ log->Printf ("%p Broadcaster(\"%s\")::BroadcastEvent (event_sp = {%s}, unique =%i) hijack = %p",
+ this,
+ m_broadcaster_name.AsCString(""),
+ event_description.GetData(),
+ unique,
+ hijacking_listener);
+ }
+
+ if (hijacking_listener)
+ {
+ if (unique && hijacking_listener->PeekAtNextEventForBroadcasterWithType (this, event_type))
+ return;
+ hijacking_listener->AddEvent (event_sp);
+ }
+ else
+ {
+ collection::iterator pos, end = m_listeners.end();
+
+
+ // Iterate through all listener/mask pairs
+ for (pos = m_listeners.begin(); pos != end; ++pos)
+ {
+ // If the listener's mask matches any bits that we just set, then
+ // put the new event on its event queue.
+ if (event_type & pos->second)
+ {
+ if (unique && pos->first->PeekAtNextEventForBroadcasterWithType (this, event_type))
+ continue;
+ pos->first->AddEvent (event_sp);
+ }
+ }
+ }
+}
+
+void
+Broadcaster::BroadcastEvent (uint32_t event_type, EventData *event_data)
+{
+ EventSP event_sp (new Event (event_type, event_data));
+ PrivateBroadcastEvent (event_sp, false);
+}
+
+void
+Broadcaster::BroadcastEventIfUnique (uint32_t event_type, EventData *event_data)
+{
+ EventSP event_sp (new Event (event_type, event_data));
+ PrivateBroadcastEvent (event_sp, true);
+}
+
+bool
+Broadcaster::HijackBroadcaster (Listener *listener, uint32_t event_mask)
+{
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ {
+ log->Printf ("%p Broadcaster(\"%s\")::HijackBroadcaster (listener(\"%s\")=%p)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ listener->m_name.c_str(),
+ listener);
+ }
+ m_hijacking_listeners.push_back(listener);
+ m_hijacking_masks.push_back(event_mask);
+ return true;
+}
+
+void
+Broadcaster::RestoreBroadcaster ()
+{
+ Mutex::Locker event_types_locker(m_listeners_mutex);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ {
+ Listener *listener = m_hijacking_listeners.back();
+ log->Printf ("%p Broadcaster(\"%s\")::RestoreBroadcaster (about to pop listener(\"%s\")=%p)",
+ this,
+ m_broadcaster_name.AsCString(""),
+ listener->m_name.c_str(),
+ listener);
+ }
+ m_hijacking_listeners.pop_back();
+ m_hijacking_masks.pop_back();
+}
+
+ConstString &
+Broadcaster::GetBroadcasterClass() const
+{
+ static ConstString class_name ("lldb.anonymous");
+ return class_name;
+}
+
+BroadcastEventSpec::BroadcastEventSpec (const BroadcastEventSpec &rhs) :
+ m_broadcaster_class (rhs.m_broadcaster_class),
+ m_event_bits (rhs.m_event_bits)
+{
+}
+
+bool
+BroadcastEventSpec::operator< (const BroadcastEventSpec &rhs) const
+{
+ if (GetBroadcasterClass() == rhs.GetBroadcasterClass())
+ {
+ return GetEventBits() < rhs.GetEventBits();
+ }
+ else
+ {
+ return GetBroadcasterClass() < rhs.GetBroadcasterClass();
+ }
+}
+
+const BroadcastEventSpec &
+BroadcastEventSpec::operator= (const BroadcastEventSpec &rhs)
+{
+ m_broadcaster_class = rhs.m_broadcaster_class;
+ m_event_bits = rhs.m_event_bits;
+ return *this;
+}
+
+BroadcasterManager::BroadcasterManager() :
+ m_manager_mutex(Mutex::eMutexTypeRecursive)
+{
+
+}
+
+uint32_t
+BroadcasterManager::RegisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec)
+{
+ Mutex::Locker locker(m_manager_mutex);
+
+ collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
+ uint32_t available_bits = event_spec.GetEventBits();
+
+ while (iter != end_iter
+ && (iter = find_if (iter, end_iter, BroadcasterClassMatches(event_spec.GetBroadcasterClass()))) != end_iter)
+ {
+ available_bits &= ~((*iter).first.GetEventBits());
+ iter++;
+ }
+
+ if (available_bits != 0)
+ {
+ m_event_map.insert (event_listener_key (BroadcastEventSpec (event_spec.GetBroadcasterClass(), available_bits), &listener));
+ m_listeners.insert(&listener);
+ }
+
+ return available_bits;
+}
+
+bool
+BroadcasterManager::UnregisterListenerForEvents (Listener &listener, BroadcastEventSpec event_spec)
+{
+ Mutex::Locker locker(m_manager_mutex);
+ bool removed_some = false;
+
+ if (m_listeners.erase(&listener) == 0)
+ return false;
+
+ ListenerMatchesAndSharedBits predicate (event_spec, listener);
+ std::vector<BroadcastEventSpec> to_be_readded;
+ uint32_t event_bits_to_remove = event_spec.GetEventBits();
+
+ // Go through the map and delete the exact matches, and build a list of matches that weren't exact to re-add:
+ while (1)
+ {
+ collection::iterator iter, end_iter = m_event_map.end();
+ iter = find_if (m_event_map.begin(), end_iter, predicate);
+ if (iter == end_iter)
+ {
+ break;
+ }
+ else
+ {
+ uint32_t iter_event_bits = (*iter).first.GetEventBits();
+ removed_some = true;
+
+ if (event_bits_to_remove != iter_event_bits)
+ {
+ uint32_t new_event_bits = iter_event_bits & ~event_bits_to_remove;
+ to_be_readded.push_back(BroadcastEventSpec (event_spec.GetBroadcasterClass(), new_event_bits));
+ }
+ m_event_map.erase (iter);
+ }
+ }
+
+ // Okay now add back the bits that weren't completely removed:
+ for (size_t i = 0; i < to_be_readded.size(); i++)
+ {
+ m_event_map.insert (event_listener_key (to_be_readded[i], &listener));
+ }
+
+ return removed_some;
+}
+
+Listener *
+BroadcasterManager::GetListenerForEventSpec (BroadcastEventSpec event_spec) const
+{
+ Mutex::Locker locker(*(const_cast<Mutex *> (&m_manager_mutex)));
+
+ collection::const_iterator iter, end_iter = m_event_map.end();
+ iter = find_if (m_event_map.begin(), end_iter, BroadcastEventSpecMatches (event_spec));
+ if (iter != end_iter)
+ return (*iter).second;
+ else
+ return NULL;
+}
+
+void
+BroadcasterManager::RemoveListener (Listener &listener)
+{
+ Mutex::Locker locker(m_manager_mutex);
+ ListenerMatches predicate (listener);
+
+
+ if (m_listeners.erase (&listener) == 0)
+ return;
+
+ while (1)
+ {
+ collection::iterator iter, end_iter = m_event_map.end();
+ iter = find_if (m_event_map.begin(), end_iter, predicate);
+ if (iter == end_iter)
+ break;
+ else
+ m_event_map.erase(iter);
+ }
+}
+
+void
+BroadcasterManager::SignUpListenersForBroadcaster (Broadcaster &broadcaster)
+{
+ Mutex::Locker locker(m_manager_mutex);
+
+ collection::iterator iter = m_event_map.begin(), end_iter = m_event_map.end();
+
+ while (iter != end_iter
+ && (iter = find_if (iter, end_iter, BroadcasterClassMatches(broadcaster.GetBroadcasterClass()))) != end_iter)
+ {
+ (*iter).second->StartListeningForEvents (&broadcaster, (*iter).first.GetEventBits());
+ iter++;
+ }
+}
+
+void
+BroadcasterManager::Clear ()
+{
+ Mutex::Locker locker(m_manager_mutex);
+ listener_collection::iterator end_iter = m_listeners.end();
+
+ for (listener_collection::iterator iter = m_listeners.begin(); iter != end_iter; iter++)
+ (*iter)->BroadcasterManagerWillDestruct(this);
+ m_listeners.clear();
+ m_event_map.clear();
+
+}
diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp
new file mode 100644
index 000000000000..7f40e6520204
--- /dev/null
+++ b/source/Core/Communication.cpp
@@ -0,0 +1,431 @@
+//===-- Communication.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/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Connection.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Host/Host.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConstString &
+Communication::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.communication");
+ return class_name;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+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),
+ m_write_mutex (Mutex::eMutexTypeNormal),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_close_on_eof (true)
+
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Communication (name = %s)",
+ this, name);
+
+ SetEventName (eBroadcastBitDisconnected, "disconnected");
+ SetEventName (eBroadcastBitReadThreadGotBytes, "got bytes");
+ SetEventName (eBroadcastBitReadThreadDidExit, "read thread did exit");
+ SetEventName (eBroadcastBitReadThreadShouldExit, "read thread should exit");
+ SetEventName (eBroadcastBitPacketAvailable, "packet available");
+
+ CheckInWithManager();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Communication::~Communication()
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT | LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::~Communication (name = %s)",
+ this, m_broadcaster_name.AsCString(""));
+ Clear();
+}
+
+void
+Communication::Clear()
+{
+ SetReadThreadBytesReceivedCallback (NULL, NULL);
+ Disconnect (NULL);
+ StopReadThread (NULL);
+}
+
+ConnectionStatus
+Communication::Connect (const char *url, Error *error_ptr)
+{
+ Clear();
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Connect (url = %s)", this, url);
+
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ return connection_sp->Connect (url, error_ptr);
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ return eConnectionStatusNoConnection;
+}
+
+ConnectionStatus
+Communication::Disconnect (Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION, "%p Communication::Disconnect ()", this);
+
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ {
+ ConnectionStatus status = connection_sp->Disconnect (error_ptr);
+ // We currently don't protect connection_sp with any mutex for
+ // multi-threaded environments. So lets not nuke our connection class
+ // without putting some multi-threaded protections in. We also probably
+ // don't want to pay for the overhead it might cause if every time we
+ // access the connection we have to take a lock.
+ //
+ // This unique pointer will cleanup after itself when this object goes away,
+ // so there is no need to currently have it destroy itself immediately
+ // upon disconnnect.
+ //connection_sp.reset();
+ return status;
+ }
+ return eConnectionStatusNoConnection;
+}
+
+bool
+Communication::IsConnected () const
+{
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ return connection_sp->IsConnected ();
+ return false;
+}
+
+bool
+Communication::HasConnection () const
+{
+ return m_connection_sp.get() != NULL;
+}
+
+size_t
+Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, ConnectionStatus &status, Error *error_ptr)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Read (dst = %p, dst_len = %" PRIu64 ", timeout = %u usec) connection = %p",
+ this,
+ dst,
+ (uint64_t)dst_len,
+ timeout_usec,
+ m_connection_sp.get());
+
+ if (m_read_thread_enabled)
+ {
+ // We have a dedicated read thread that is getting data for us
+ size_t cached_bytes = GetCachedBytes (dst, dst_len);
+ if (cached_bytes > 0 || timeout_usec == 0)
+ {
+ status = eConnectionStatusSuccess;
+ return cached_bytes;
+ }
+
+ if (m_connection_sp.get() == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+ // Set the timeout appropriately
+ TimeValue timeout_time;
+ if (timeout_usec != UINT32_MAX)
+ {
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithMicroSeconds (timeout_usec);
+ }
+
+ Listener listener ("Communication::Read");
+ listener.StartListeningForEvents (this, eBroadcastBitReadThreadGotBytes | eBroadcastBitReadThreadDidExit);
+ EventSP event_sp;
+ while (listener.WaitForEvent (timeout_time.IsValid() ? &timeout_time : NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_type & eBroadcastBitReadThreadGotBytes)
+ {
+ return GetCachedBytes (dst, dst_len);
+ }
+
+ if (event_type & eBroadcastBitReadThreadDidExit)
+ {
+ Disconnect (NULL);
+ break;
+ }
+ }
+ return 0;
+ }
+
+ // We aren't using a read thread, just read the data synchronously in this
+ // thread.
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ {
+ return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+}
+
+
+size_t
+Communication::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+
+ Mutex::Locker locker(m_write_mutex);
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::Write (src = %p, src_len = %" PRIu64 ") connection = %p",
+ this,
+ src,
+ (uint64_t)src_len,
+ connection_sp.get());
+
+ if (connection_sp.get())
+ return connection_sp->Write (src, src_len, status, error_ptr);
+
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid connection.");
+ status = eConnectionStatusNoConnection;
+ return 0;
+}
+
+
+bool
+Communication::StartReadThread (Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ return true;
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::StartReadThread ()", this);
+
+
+ char thread_name[1024];
+ 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_enabled = false;
+ return m_read_thread_enabled;
+}
+
+bool
+Communication::StopReadThread (Error *error_ptr)
+{
+ if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ return true;
+
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::StopReadThread ()", this);
+
+ m_read_thread_enabled = false;
+
+ BroadcastEvent (eBroadcastBitReadThreadShouldExit, NULL);
+
+ //Host::ThreadCancel (m_read_thread, error_ptr);
+
+ bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr);
+ m_read_thread = LLDB_INVALID_HOST_THREAD;
+ return status;
+}
+
+
+size_t
+Communication::GetCachedBytes (void *dst, size_t dst_len)
+{
+ Mutex::Locker locker(m_bytes_mutex);
+ if (m_bytes.size() > 0)
+ {
+ // If DST is NULL and we have a thread, then return the number
+ // of bytes that are available so the caller can call again
+ if (dst == NULL)
+ return m_bytes.size();
+
+ const size_t len = std::min<size_t>(dst_len, m_bytes.size());
+
+ ::memcpy (dst, m_bytes.c_str(), len);
+ m_bytes.erase(m_bytes.begin(), m_bytes.begin() + len);
+
+ return len;
+ }
+ return 0;
+}
+
+void
+Communication::AppendBytesToCache (const uint8_t * bytes, size_t len, bool broadcast, ConnectionStatus status)
+{
+ lldb_private::LogIfAnyCategoriesSet (LIBLLDB_LOG_COMMUNICATION,
+ "%p Communication::AppendBytesToCache (src = %p, src_len = %" PRIu64 ", broadcast = %i)",
+ this, bytes, (uint64_t)len, broadcast);
+ if ((bytes == NULL || len == 0)
+ && (status != lldb::eConnectionStatusEndOfFile))
+ return;
+ if (m_callback)
+ {
+ // If the user registered a callback, then call it and do not broadcast
+ m_callback (m_callback_baton, bytes, len);
+ }
+ else if (bytes != NULL && len > 0)
+ {
+ Mutex::Locker locker(m_bytes_mutex);
+ m_bytes.append ((const char *)bytes, len);
+ if (broadcast)
+ BroadcastEventIfUnique (eBroadcastBitReadThreadGotBytes);
+ }
+}
+
+size_t
+Communication::ReadFromConnection (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ lldb::ConnectionSP connection_sp (m_connection_sp);
+ if (connection_sp.get())
+ return connection_sp->Read (dst, dst_len, timeout_usec, status, error_ptr);
+ return 0;
+}
+
+bool
+Communication::ReadThreadIsRunning ()
+{
+ return m_read_thread_enabled;
+}
+
+void *
+Communication::ReadThread (void *p)
+{
+ Communication *comm = (Communication *)p;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION));
+
+ if (log)
+ log->Printf ("%p Communication::ReadThread () thread starting...", p);
+
+ uint8_t buf[1024];
+
+ Error error;
+ ConnectionStatus status = eConnectionStatusSuccess;
+ bool done = false;
+ while (!done && comm->m_read_thread_enabled)
+ {
+ size_t bytes_read = comm->ReadFromConnection (buf, sizeof(buf), 5 * TimeValue::MicroSecPerSec, status, &error);
+ if (bytes_read > 0)
+ comm->AppendBytesToCache (buf, bytes_read, true, status);
+ else if ((bytes_read == 0)
+ && status == eConnectionStatusEndOfFile)
+ {
+ if (comm->GetCloseOnEOF ())
+ comm->Disconnect ();
+ comm->AppendBytesToCache (buf, bytes_read, true, status);
+ }
+
+ switch (status)
+ {
+ case eConnectionStatusSuccess:
+ break;
+
+ case eConnectionStatusEndOfFile:
+ if (comm->GetCloseOnEOF())
+ done = true;
+ break;
+ case eConnectionStatusNoConnection: // No connection
+ case eConnectionStatusLostConnection: // Lost connection while connected to a valid connection
+ done = true;
+ // Fall through...
+ case eConnectionStatusError: // Check GetError() for details
+ case eConnectionStatusTimedOut: // Request timed out
+ if (log)
+ error.LogIfError (log,
+ "%p Communication::ReadFromConnection () => status = %s",
+ p,
+ Communication::ConnectionStatusAsCString (status));
+ break;
+ }
+ }
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMUNICATION);
+ if (log)
+ log->Printf ("%p Communication::ReadThread () thread exiting...", p);
+
+ // Let clients know that this thread is exiting
+ comm->BroadcastEvent (eBroadcastBitReadThreadDidExit);
+ return NULL;
+}
+
+void
+Communication::SetReadThreadBytesReceivedCallback
+(
+ ReadThreadBytesReceived callback,
+ void *callback_baton
+)
+{
+ m_callback = callback;
+ m_callback_baton = callback_baton;
+}
+
+void
+Communication::SetConnection (Connection *connection)
+{
+ Disconnect (NULL);
+ StopReadThread(NULL);
+ m_connection_sp.reset(connection);
+}
+
+const char *
+Communication::ConnectionStatusAsCString (lldb::ConnectionStatus status)
+{
+ switch (status)
+ {
+ case eConnectionStatusSuccess: return "success";
+ case eConnectionStatusError: return "error";
+ case eConnectionStatusTimedOut: return "timed out";
+ case eConnectionStatusNoConnection: return "no connection";
+ case eConnectionStatusLostConnection: return "lost connection";
+ case eConnectionStatusEndOfFile: return "end of file";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "ConnectionStatus = %i", status);
+ return unknown_state_string;
+}
diff --git a/source/Core/Connection.cpp b/source/Core/Connection.cpp
new file mode 100644
index 000000000000..3c9bb8b1b7ed
--- /dev/null
+++ b/source/Core/Connection.cpp
@@ -0,0 +1,24 @@
+//===-- Connection.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/Core/Connection.h"
+
+using namespace lldb_private;
+
+Connection::Connection ()
+{
+}
+
+Connection::~Connection ()
+{
+}
diff --git a/source/Core/ConnectionFileDescriptor.cpp b/source/Core/ConnectionFileDescriptor.cpp
new file mode 100644
index 000000000000..e320bda2fcdc
--- /dev/null
+++ b/source/Core/ConnectionFileDescriptor.cpp
@@ -0,0 +1,1528 @@
+//===-- ConnectionFileDescriptor.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+// Enable this special support for Apple builds where we can have unlimited
+// select bounds. We tried switching to poll() and kqueue and we were panicing
+// the kernel, so we have to stick with select for now.
+#define _DARWIN_UNLIMITED_SELECT
+#endif
+
+#include "lldb/Core/ConnectionFileDescriptor.h"
+
+// C Includes
+#include <errno.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#if defined(__APPLE__)
+#include "llvm/ADT/SmallVector.h"
+#endif
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+DecodeHostAndPort (const char *host_and_port,
+ std::string &host_str,
+ std::string &port_str,
+ int32_t& port,
+ Error *error_ptr)
+{
+ static RegularExpression g_regex ("([^:]+):([0-9]+)");
+ RegularExpression::Match regex_match(2);
+ if (g_regex.Execute (host_and_port, &regex_match))
+ {
+ if (regex_match.GetMatchAtIndex (host_and_port, 1, host_str) &&
+ regex_match.GetMatchAtIndex (host_and_port, 2, port_str))
+ {
+ port = Args::StringToSInt32 (port_str.c_str(), INT32_MIN);
+ if (port != INT32_MIN)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ }
+ }
+ host_str.clear();
+ port_str.clear();
+ port = INT32_MIN;
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("invalid host:port specification: '%s'", host_and_port);
+ return false;
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor () :
+ Connection(),
+ m_fd_send (-1),
+ m_fd_recv (-1),
+ m_fd_send_type (eFDTypeFile),
+ m_fd_recv_type (eFDTypeFile),
+ m_udp_send_sockaddr (),
+ m_should_close_fd (false),
+ m_socket_timeout_usec(0),
+ m_pipe_read(-1),
+ m_pipe_write(-1),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_shutting_down (false)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor ()", this);
+}
+
+ConnectionFileDescriptor::ConnectionFileDescriptor (int fd, bool owns_fd) :
+ Connection(),
+ m_fd_send (fd),
+ m_fd_recv (fd),
+ m_fd_send_type (eFDTypeFile),
+ m_fd_recv_type (eFDTypeFile),
+ m_udp_send_sockaddr (),
+ m_should_close_fd (owns_fd),
+ m_socket_timeout_usec(0),
+ m_pipe_read(-1),
+ m_pipe_write(-1),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_shutting_down (false)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor (fd = %i, owns_fd = %i)", this, fd, owns_fd);
+ OpenCommandPipe ();
+}
+
+
+ConnectionFileDescriptor::~ConnectionFileDescriptor ()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION | LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::~ConnectionFileDescriptor ()", this);
+ Disconnect (NULL);
+ CloseCommandPipe ();
+}
+
+void
+ConnectionFileDescriptor::OpenCommandPipe ()
+{
+ CloseCommandPipe();
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ // Make the command file descriptor here:
+ int filedes[2];
+ int result = pipe (filedes);
+ if (result != 0)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectionFileDescriptor () - could not make pipe: %s",
+ this,
+ strerror(errno));
+ }
+ else
+ {
+ m_pipe_read = filedes[0];
+ m_pipe_write = filedes[1];
+ }
+}
+
+void
+ConnectionFileDescriptor::CloseCommandPipe ()
+{
+ if (m_pipe_read != -1)
+ {
+ close (m_pipe_read);
+ m_pipe_read = -1;
+ }
+
+ if (m_pipe_write != -1)
+ {
+ close (m_pipe_write);
+ m_pipe_write = -1;
+ }
+}
+
+bool
+ConnectionFileDescriptor::IsConnected () const
+{
+ return m_fd_send >= 0 || m_fd_recv >= 0;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Connect (const char *s, Error *error_ptr)
+{
+ Mutex::Locker locker (m_mutex);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Connect (url = '%s')", this, s);
+
+ OpenCommandPipe();
+
+ if (s && s[0])
+ {
+ char *end = NULL;
+ if (strstr(s, "listen://"))
+ {
+ // listen://HOST:PORT
+ unsigned long listen_port = ::strtoul(s + strlen("listen://"), &end, 0);
+ return SocketListen (listen_port, error_ptr);
+ }
+ else if (strstr(s, "unix-accept://"))
+ {
+ // unix://SOCKNAME
+ return NamedSocketAccept (s + strlen("unix-accept://"), error_ptr);
+ }
+ else if (strstr(s, "connect://"))
+ {
+ return ConnectTCP (s + strlen("connect://"), error_ptr);
+ }
+ else if (strstr(s, "tcp-connect://"))
+ {
+ return ConnectTCP (s + strlen("tcp-connect://"), error_ptr);
+ }
+ else if (strstr(s, "udp://"))
+ {
+ return ConnectUDP (s + strlen("udp://"), error_ptr);
+ }
+ else if (strstr(s, "fd://"))
+ {
+ // Just passing a native file descriptor within this current process
+ // that is already opened (possibly from a service or other source).
+ s += strlen ("fd://");
+ bool success = false;
+ m_fd_send = m_fd_recv = Args::StringToSInt32 (s, -1, 0, &success);
+
+ if (success)
+ {
+ // 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
+ // isn't a bad fd.
+ errno = 0;
+ int flags = ::fcntl (m_fd_send, F_GETFL, 0);
+ if (flags == -1 || errno == EBADF)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("stale file descriptor: %s", s);
+ m_fd_send = m_fd_recv = -1;
+ return eConnectionStatusError;
+ }
+ else
+ {
+ // Try and get a socket option from this file descriptor to
+ // see if this is a socket and set m_is_socket accordingly.
+ int resuse;
+ bool is_socket = GetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, resuse) == 0;
+ if (is_socket)
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ // Don't take ownership of a file descriptor that gets passed
+ // to us since someone else opened the file descriptor and
+ // handed it to us.
+ // 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
+ // assume we don't own it.
+ m_should_close_fd = false;
+ return eConnectionStatusSuccess;
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("invalid file descriptor: \"fd://%s\"", s);
+ m_fd_send = m_fd_recv = -1;
+ return eConnectionStatusError;
+ }
+ else if (strstr(s, "file://"))
+ {
+ // file:///PATH
+ const char *path = s + strlen("file://");
+ do
+ {
+ m_fd_send = m_fd_recv = ::open (path, O_RDWR);
+ } while (m_fd_send == -1 && errno == EINTR);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ if (::isatty(m_fd_send))
+ {
+ // Set up serial terminal emulation
+ struct termios options;
+ ::tcgetattr (m_fd_send, &options);
+
+ // Set port speed to maximum
+ ::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[VTIME] = 0;
+
+ ::tcsetattr (m_fd_send, TCSANOW, &options);
+ }
+
+ int flags = ::fcntl (m_fd_send, F_GETFL, 0);
+ if (flags >= 0)
+ {
+ if ((flags & O_NONBLOCK) == 0)
+ {
+ flags |= O_NONBLOCK;
+ ::fcntl (m_fd_send, F_SETFL, flags);
+ }
+ }
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("invalid connect arguments");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::Disconnect (Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect ()", this);
+
+ ConnectionStatus status = eConnectionStatusSuccess;
+
+ if (m_fd_send < 0 && m_fd_recv < 0)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Disconnect(): Nothing to disconnect", this);
+ return eConnectionStatusSuccess;
+ }
+
+ // Try to get the ConnectionFileDescriptor's mutex. If we fail, that is quite likely
+ // because somebody is doing a blocking read on our file descriptor. If that's the case,
+ // then send the "q" char to the command file channel so the read will wake up and the connection
+ // will then know to shut down.
+
+ m_shutting_down = true;
+
+ Mutex::Locker locker;
+ bool got_lock= locker.TryLock (m_mutex);
+
+ if (!got_lock)
+ {
+ if (m_pipe_write != -1 )
+ {
+ write (m_pipe_write, "q", 1);
+ close (m_pipe_write);
+ m_pipe_write = -1;
+ }
+ locker.Lock (m_mutex);
+ }
+
+ if (m_should_close_fd == true)
+ {
+ if (m_fd_send == m_fd_recv)
+ {
+ status = Close (m_fd_send, error_ptr);
+ }
+ else
+ {
+ // File descriptors are the different, close both if needed
+ if (m_fd_send >= 0)
+ status = Close (m_fd_send, error_ptr);
+ if (m_fd_recv >= 0)
+ {
+ ConnectionStatus recv_status = Close (m_fd_recv, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ status = recv_status;
+ }
+ }
+ }
+
+ // Now set all our descriptors to invalid values.
+
+ m_fd_send = m_fd_recv = -1;
+
+ if (status != eConnectionStatusSuccess)
+ {
+
+ return status;
+ }
+
+ m_shutting_down = false;
+ return eConnectionStatusSuccess;
+}
+
+size_t
+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));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ")...",
+ this, m_fd_recv, dst, (uint64_t)dst_len);
+
+ Mutex::Locker locker;
+ bool got_lock = locker.TryLock (m_mutex);
+ if (!got_lock)
+ {
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () failed to get the connection lock.",
+ this);
+ if (error_ptr)
+ error_ptr->SetErrorString ("failed to get the connection lock for read.");
+
+ status = eConnectionStatusTimedOut;
+ return 0;
+ }
+ else if (m_shutting_down)
+ return eConnectionStatusError;
+
+ ssize_t bytes_read = 0;
+
+ status = BytesAvailable (timeout_usec, error_ptr);
+ if (status == eConnectionStatusSuccess)
+ {
+ do
+ {
+ bytes_read = ::read (m_fd_recv, dst, dst_len);
+ } while (bytes_read < 0 && errno == EINTR);
+ }
+
+ if (status != eConnectionStatusSuccess)
+ return 0;
+
+ Error error;
+ if (bytes_read == 0)
+ {
+ error.Clear(); // End-of-file. Do not automatically close; pass along for the end-of-file handlers.
+ status = eConnectionStatusEndOfFile;
+ }
+ else if (bytes_read < 0)
+ {
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.Clear();
+ }
+
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Read () ::read (fd = %i, dst = %p, dst_len = %" PRIu64 ") => %" PRIi64 ", error = %s",
+ this,
+ m_fd_recv,
+ dst,
+ (uint64_t)dst_len,
+ (int64_t)bytes_read,
+ error.AsCString());
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ 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_fd_recv_type == eFDTypeSocket || m_fd_recv_type == eFDTypeSocketUDP)
+ 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;
+ }
+
+ return 0;
+ }
+ return bytes_read;
+}
+
+size_t
+ConnectionFileDescriptor::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Write (src = %p, src_len = %" PRIu64 ")", this, src, (uint64_t)src_len);
+
+ if (!IsConnected ())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ status = eConnectionStatusNoConnection;
+ return 0;
+ }
+
+
+ Error error;
+
+ ssize_t bytes_sent = 0;
+
+ switch (m_fd_send_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ do
+ {
+ bytes_sent = ::write (m_fd_send, src, src_len);
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ do
+ {
+ bytes_sent = ::send (m_fd_send, src, src_len, 0);
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ assert (m_udp_send_sockaddr.GetFamily() != 0);
+ do
+ {
+ bytes_sent = ::sendto (m_fd_send,
+ src,
+ src_len,
+ 0,
+ m_udp_send_sockaddr,
+ m_udp_send_sockaddr.GetLength());
+ } while (bytes_sent < 0 && errno == EINTR);
+ break;
+ }
+
+ if (bytes_sent < 0)
+ error.SetErrorToErrno ();
+ else
+ error.Clear ();
+
+ if (log)
+ {
+ switch (m_fd_send_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::write (fd = %i, src = %p, src_len = %" PRIu64 ") => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::send (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ log->Printf ("%p ConnectionFileDescriptor::Write() ::sendto (socket = %i, src = %p, src_len = %" PRIu64 ", flags = 0) => %" PRIi64 " (error = %s)",
+ this,
+ m_fd_send,
+ src,
+ (uint64_t)src_len,
+ (int64_t)bytes_sent,
+ error.AsCString());
+ break;
+ }
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ 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....
+ }
+
+ return 0;
+ }
+
+ status = eConnectionStatusSuccess;
+ return bytes_sent;
+}
+
+
+
+#if defined(__APPLE__)
+
+// This ConnectionFileDescriptor::BytesAvailable() uses select().
+//
+// PROS:
+// - select is consistent across most unix platforms
+// - this Apple specific version allows for unlimited fds in the fd_sets by
+// setting the _DARWIN_UNLIMITED_SELECT define prior to including the
+// required header files.
+
+// CONS:
+// - Darwin only
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ struct timeval *tv_ptr;
+ struct timeval tv;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ tv_ptr = NULL;
+ }
+ else
+ {
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds (timeout_usec);
+ tv = time_value.GetAsTimeVal();
+ tv_ptr = &tv;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ if (data_fd >= 0)
+ {
+ const bool have_pipe_fd = pipe_fd >= 0;
+
+ while (data_fd == m_fd_recv)
+ {
+ const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+ 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
+ FD_SET (data_fd, read_fds.data());
+ if (have_pipe_fd)
+ FD_SET (pipe_fd, read_fds.data());
+
+ Error error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, pipe_fd, tv_ptr);
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, tv_ptr);
+ }
+
+ const int num_set_fds = ::select (nfds, read_fds.data(), NULL, NULL, tv_ptr);
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ // FD_ISSET is happy to deal with a something larger than
+ // a single fd_set.
+ if (FD_ISSET(data_fd, read_fds.data()))
+ return eConnectionStatusSuccess;
+ if (have_pipe_fd && FD_ISSET(pipe_fd, read_fds.data()))
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#else
+
+// This ConnectionFileDescriptor::BytesAvailable() uses select().
+//
+// PROS:
+// - select is consistent across most unix platforms
+// CONS:
+// - only supports file descriptors up to FD_SETSIZE. This implementation
+// will assert if it runs into that hard limit to let users know that
+// another ConnectionFileDescriptor::BytesAvailable() should be used
+// or a new version of ConnectionFileDescriptor::BytesAvailable() should
+// be written for the system that is running into the limitations. MacOSX
+// uses kqueues, and there is a poll() based implementation below.
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ struct timeval *tv_ptr;
+ struct timeval tv;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ tv_ptr = NULL;
+ }
+ else
+ {
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds (timeout_usec);
+ tv = time_value.GetAsTimeVal();
+ tv_ptr = &tv;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ if (data_fd >= 0)
+ {
+ // If this assert fires off on MacOSX, we will need to switch to using
+ // libdispatch to read from file descriptors because poll() is causing
+ // kernel panics and if we exceed FD_SETSIZE we will have no choice...
+ assert (data_fd < FD_SETSIZE);
+
+ const bool have_pipe_fd = pipe_fd >= 0;
+
+ if (have_pipe_fd)
+ {
+ assert (pipe_fd < FD_SETSIZE);
+ }
+
+ while (data_fd == m_fd_recv)
+ {
+ fd_set read_fds;
+ FD_ZERO (&read_fds);
+ FD_SET (data_fd, &read_fds);
+ if (have_pipe_fd)
+ FD_SET (pipe_fd, &read_fds);
+
+ const int nfds = std::max<int>(data_fd, pipe_fd) + 1;
+
+ Error error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, pipe_fd, tv_ptr);
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p)...",
+ this, nfds, data_fd, tv_ptr);
+ }
+
+ const int num_set_fds = ::select (nfds, &read_fds, NULL, NULL, tv_ptr);
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i, %i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, pipe_fd, tv_ptr, num_set_fds, error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::select (nfds=%i, fds={%i}, NULL, NULL, timeout=%p) => %d, error = %s",
+ this, nfds, data_fd, tv_ptr, num_set_fds, error.AsCString());
+ }
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ if (FD_ISSET(data_fd, &read_fds))
+ return eConnectionStatusSuccess;
+ if (have_pipe_fd && FD_ISSET(pipe_fd, &read_fds))
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#endif
+
+#if 0
+#include <poll.h>
+
+// This ConnectionFileDescriptor::BytesAvailable() uses poll(). poll() should NOT
+// be used on MacOSX as it has all sorts of restrictions on the types of file descriptors
+// that it doesn't support.
+//
+// There may be some systems that properly support poll() that could use this
+// implementation. I will let each system opt into this on their own.
+//
+// PROS:
+// - no restrictions on the fd value that is used
+// CONS:
+// - varies wildly from platform to platform in its implementation restrictions
+
+ConnectionStatus
+ConnectionFileDescriptor::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ // Don't need to take the mutex here separately since we are only called from Read. If we
+ // ever get used more generally we will need to lock here as well.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable (timeout_usec = %u)", this, timeout_usec);
+ int timeout_msec = 0;
+ if (timeout_usec == UINT32_MAX)
+ {
+ // Infinite wait...
+ timeout_msec = -1;
+ }
+ else if (timeout_usec == 0)
+ {
+ // Return immediately, don't wait
+ timeout_msec = 0;
+ }
+ else
+ {
+ // Convert usec to msec
+ timeout_msec = (timeout_usec + 999) / 1000;
+ }
+
+ // Make a copy of the file descriptors to make sure we don't
+ // have another thread change these values out from under us
+ // and cause problems in the loop below where like in FS_SET()
+ const int data_fd = m_fd_recv;
+ const int pipe_fd = m_pipe_read;
+
+ // Make sure the file descriptor can be used with select as it
+ // must be in range
+ if (data_fd >= 0)
+ {
+ const bool have_pipe_fd = pipe_fd >= 0;
+ struct pollfd fds[2] =
+ {
+ { data_fd, POLLIN, 0 },
+ { pipe_fd, POLLIN, 0 }
+ };
+ const int nfds = have_pipe_fd ? 2 : 1;
+ Error error;
+ while (data_fd == m_fd_recv)
+ {
+ const int num_set_fds = ::poll (fds, nfds, timeout_msec);
+
+ if (num_set_fds < 0)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+
+ if (error_ptr)
+ *error_ptr = error;
+
+ if (log)
+ {
+ if (have_pipe_fd)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN},{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
+ this,
+ data_fd,
+ pipe_fd,
+ nfds,
+ timeout_msec,
+ num_set_fds,
+ error.AsCString());
+ else
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() ::poll (fds={{%i,POLLIN}}, nfds=%i, timeout_ms=%i) => %d, error = %s\n",
+ this,
+ data_fd,
+ nfds,
+ timeout_msec,
+ num_set_fds,
+ error.AsCString());
+ }
+
+ if (error.Fail())
+ {
+ switch (error.GetError())
+ {
+ case EBADF: // One of the descriptor sets specified an invalid descriptor.
+ return eConnectionStatusLostConnection;
+
+ case EINVAL: // The specified time limit is invalid. One of its components is negative or too large.
+ default: // Other unknown error
+ return eConnectionStatusError;
+
+ case EAGAIN: // The kernel was (perhaps temporarily) unable to
+ // allocate the requested number of file descriptors,
+ // or we have non-blocking IO
+ case EINTR: // A signal was delivered before the time limit
+ // expired and before any of the selected events
+ // occurred.
+ break; // Lets keep reading to until we timeout
+ }
+ }
+ else if (num_set_fds == 0)
+ {
+ return eConnectionStatusTimedOut;
+ }
+ else if (num_set_fds > 0)
+ {
+ if (fds[0].revents & POLLIN)
+ return eConnectionStatusSuccess;
+ if (fds[1].revents & POLLIN)
+ {
+ // We got a command to exit. Read the data from that pipe:
+ char buffer[16];
+ ssize_t bytes_read;
+
+ do
+ {
+ bytes_read = ::read (pipe_fd, buffer, sizeof(buffer));
+ } while (bytes_read < 0 && errno == EINTR);
+ assert (bytes_read == 1 && buffer[0] == 'q');
+
+ if (log)
+ log->Printf("%p ConnectionFileDescriptor::BytesAvailable() got data: %*s from the command channel.",
+ this, (int) bytes_read, buffer);
+
+ return eConnectionStatusEndOfFile;
+ }
+ }
+ }
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString("not connected");
+ return eConnectionStatusLostConnection;
+}
+
+#endif
+
+ConnectionStatus
+ConnectionFileDescriptor::Close (int& fd, Error *error_ptr)
+{
+ if (error_ptr)
+ error_ptr->Clear();
+ bool success = true;
+ // Avoid taking a lock if we can
+ if (fd >= 0)
+ {
+ Mutex::Locker locker (m_mutex);
+ // Check the FD after the lock is taken to ensure only one thread
+ // can get into the close scope below
+ if (fd >= 0)
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::Close (fd = %i)", this,fd);
+
+ success = ::close (fd) == 0;
+ // A reference to a FD was passed in, set it to an invalid value
+ fd = -1;
+ if (!success && error_ptr)
+ {
+ // Only set the error if we have been asked to since something else
+ // might have caused us to try and shut down the connection and may
+ // have already set the error.
+ error_ptr->SetErrorToErrno();
+ }
+ }
+ }
+ if (success)
+ return eConnectionStatusSuccess;
+ else
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketAccept (const char *socket_name, Error *error_ptr)
+{
+ ConnectionStatus result = eConnectionStatusError;
+ struct sockaddr_un saddr_un;
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+
+ int listen_socket = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (listen_socket == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::bind (listen_socket, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) == 0)
+ {
+ if (::listen (listen_socket, 5) == 0)
+ {
+ m_fd_send = m_fd_recv = ::accept (listen_socket, NULL, 0);
+ if (m_fd_send > 0)
+ {
+ m_should_close_fd = true;
+
+ if (error_ptr)
+ error_ptr->Clear();
+ result = eConnectionStatusSuccess;
+ }
+ }
+ }
+
+ if (result != eConnectionStatusSuccess)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ }
+ // We are done with the listen port
+ Close (listen_socket, NULL);
+ return result;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::NamedSocketConnect (const char *socket_name, Error *error_ptr)
+{
+ Disconnect (NULL);
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+
+ // Open the socket that was passed in as an option
+ struct sockaddr_un saddr_un;
+ m_fd_send = m_fd_recv = ::socket (AF_UNIX, SOCK_STREAM, 0);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ saddr_un.sun_family = AF_UNIX;
+ ::strncpy(saddr_un.sun_path, socket_name, sizeof(saddr_un.sun_path) - 1);
+ saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0';
+#if defined(__APPLE__) || defined(__FreeBSD__)
+ saddr_un.sun_len = SUN_LEN (&saddr_un);
+#endif
+
+ if (::connect (m_fd_send, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::SocketListen (uint16_t listen_port_num, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::SocketListen (port = %i)", this, listen_port_num);
+
+ Disconnect (NULL);
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ int listen_port = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (listen_port == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ // enable local address reuse
+ SetSocketOption (listen_port, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ SocketAddress localhost;
+ if (localhost.SetToLocalhost (AF_INET, listen_port_num))
+ {
+ int err = ::bind (listen_port, localhost, localhost.GetLength());
+ if (err == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+
+ err = ::listen (listen_port, 1);
+ if (err == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+
+ m_fd_send = m_fd_recv = ::accept (listen_port, NULL, 0);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Close (listen_port, NULL);
+ return eConnectionStatusError;
+ }
+ }
+
+ // We are done with the listen port
+ Close (listen_port, NULL);
+
+ m_should_close_fd = true;
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectTCP (const char *host_and_port, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectTCP (host/port = %s)", this, host_and_port);
+ Disconnect (NULL);
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocket;
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
+ return eConnectionStatusError;
+
+ // Create the socket
+ m_fd_send = m_fd_recv = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (m_fd_send == -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ return eConnectionStatusError;
+ }
+
+ m_should_close_fd = true;
+
+ // Enable local address reuse
+ SetSocketOption (m_fd_send, SOL_SOCKET, SO_REUSEADDR, 1);
+
+ struct sockaddr_in sa;
+ ::memset (&sa, 0, sizeof (sa));
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons (port);
+
+ int inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+
+ if (inet_pton_result <= 0)
+ {
+ struct hostent *host_entry = gethostbyname (host_str.c_str());
+ if (host_entry)
+ host_str = ::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
+ inet_pton_result = ::inet_pton (AF_INET, host_str.c_str(), &sa.sin_addr);
+ if (inet_pton_result <= 0)
+ {
+
+ if (error_ptr)
+ {
+ if (inet_pton_result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->SetErrorStringWithFormat("invalid host string: '%s'", host_str.c_str());
+ }
+ Disconnect (NULL);
+
+ return eConnectionStatusError;
+ }
+ }
+
+ if (-1 == ::connect (m_fd_send, (const struct sockaddr *)&sa, sizeof(sa)))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+
+ return eConnectionStatusError;
+ }
+
+ // Keep our TCP packets coming without any delays.
+ SetSocketOption (m_fd_send, IPPROTO_TCP, TCP_NODELAY, 1);
+ if (error_ptr)
+ error_ptr->Clear();
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionFileDescriptor::ConnectUDP (const char *host_and_port, Error *error_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_CONNECTION));
+ if (log)
+ log->Printf ("%p ConnectionFileDescriptor::ConnectUDP (host/port = %s)", this, host_and_port);
+ Disconnect (NULL);
+
+ m_fd_send_type = m_fd_recv_type = eFDTypeSocketUDP;
+
+ std::string host_str;
+ std::string port_str;
+ int32_t port = INT32_MIN;
+ if (!DecodeHostAndPort (host_and_port, host_str, port_str, port, error_ptr))
+ return eConnectionStatusError;
+
+ // Setup the receiving end of the UDP connection on this localhost
+ // on port zero. After we bind to port zero we can read the port.
+ m_fd_recv = ::socket (AF_INET, SOCK_DGRAM, 0);
+ if (m_fd_recv == -1)
+ {
+ // Socket creation failed...
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ }
+ else
+ {
+ // Socket was created, now lets bind to the requested port
+ SocketAddress addr;
+ addr.SetToLocalhost (AF_INET, 0);
+
+ if (::bind (m_fd_recv, addr, addr.GetLength()) == -1)
+ {
+ // Bind failed...
+ if (error_ptr)
+ error_ptr->SetErrorToErrno();
+ Disconnect (NULL);
+ }
+ }
+
+ if (m_fd_recv == -1)
+ return eConnectionStatusError;
+
+ // At this point we have setup the recieve port, now we need to
+ // setup the UDP send socket
+
+ struct addrinfo hints;
+ struct addrinfo *service_info_list = NULL;
+
+ ::memset (&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_DGRAM;
+ int err = ::getaddrinfo (host_str.c_str(), port_str.c_str(), &hints, &service_info_list);
+ if (err != 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("getaddrinfo(%s, %s, &hints, &info) returned error %i (%s)",
+ host_str.c_str(),
+ port_str.c_str(),
+ err,
+ gai_strerror(err));
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+
+ for (struct addrinfo *service_info_ptr = service_info_list;
+ service_info_ptr != NULL;
+ service_info_ptr = service_info_ptr->ai_next)
+ {
+ m_fd_send = ::socket (service_info_ptr->ai_family,
+ service_info_ptr->ai_socktype,
+ service_info_ptr->ai_protocol);
+
+ if (m_fd_send != -1)
+ {
+ m_udp_send_sockaddr = service_info_ptr;
+ break;
+ }
+ else
+ continue;
+ }
+
+ :: freeaddrinfo (service_info_list);
+
+ if (m_fd_send == -1)
+ {
+ Disconnect (NULL);
+ return eConnectionStatusError;
+ }
+
+ if (error_ptr)
+ error_ptr->Clear();
+
+ m_should_close_fd = true;
+ return eConnectionStatusSuccess;
+}
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+typedef const char * set_socket_option_arg_type;
+typedef char * get_socket_option_arg_type;
+#else // #if defined(__MINGW32__) || defined(__MINGW64__)
+typedef const void * set_socket_option_arg_type;
+typedef void * get_socket_option_arg_type;
+#endif // #if defined(__MINGW32__) || defined(__MINGW64__)
+
+int
+ConnectionFileDescriptor::GetSocketOption(int fd, int level, int option_name, int &option_value)
+{
+ get_socket_option_arg_type option_value_p = static_cast<get_socket_option_arg_type>(&option_value);
+ socklen_t option_value_size = sizeof(int);
+ return ::getsockopt(fd, level, option_name, option_value_p, &option_value_size);
+}
+
+int
+ConnectionFileDescriptor::SetSocketOption(int fd, int level, int option_name, int option_value)
+{
+ set_socket_option_arg_type option_value_p = static_cast<get_socket_option_arg_type>(&option_value);
+ return ::setsockopt(fd, level, option_name, option_value_p, sizeof(option_value));
+}
+
+bool
+ConnectionFileDescriptor::SetSocketReceiveTimeout (uint32_t timeout_usec)
+{
+ switch (m_fd_recv_type)
+ {
+ case eFDTypeFile: // Other FD requireing read/write
+ break;
+
+ case eFDTypeSocket: // Socket requiring send/recv
+ case eFDTypeSocketUDP: // Unconnected UDP socket requiring sendto/recvfrom
+ {
+ // Check in case timeout for m_fd has already been set to this value
+ if (timeout_usec == m_socket_timeout_usec)
+ return true;
+ //printf ("ConnectionFileDescriptor::SetSocketReceiveTimeout (timeout_usec = %u)\n", timeout_usec);
+
+ struct timeval timeout;
+ if (timeout_usec == UINT32_MAX)
+ {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+ else if (timeout_usec == 0)
+ {
+ // Sending in zero does an infinite timeout, so set this as low
+ // as we can go to get an effective zero timeout...
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 1;
+ }
+ else
+ {
+ timeout.tv_sec = timeout_usec / TimeValue::MicroSecPerSec;
+ timeout.tv_usec = timeout_usec % TimeValue::MicroSecPerSec;
+ }
+ if (::setsockopt (m_fd_recv, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == 0)
+ {
+ m_socket_timeout_usec = timeout_usec;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+in_port_t
+ConnectionFileDescriptor::GetSocketPort (int fd)
+{
+ // We bound to port zero, so we need to figure out which port we actually bound to
+ SocketAddress sock_addr;
+ socklen_t sock_addr_len = sock_addr.GetMaxLength ();
+ if (::getsockname (fd, sock_addr, &sock_addr_len) == 0)
+ return sock_addr.GetPort ();
+
+ return 0;
+}
+
+// If the read file descriptor is a socket, then return
+// the port number that is being used by the socket.
+in_port_t
+ConnectionFileDescriptor::GetReadPort () const
+{
+ return ConnectionFileDescriptor::GetSocketPort (m_fd_recv);
+}
+
+// If the write file descriptor is a socket, then return
+// the port number that is being used by the socket.
+in_port_t
+ConnectionFileDescriptor::GetWritePort () const
+{
+ return ConnectionFileDescriptor::GetSocketPort (m_fd_send);
+}
+
+
diff --git a/source/Core/ConnectionMachPort.cpp b/source/Core/ConnectionMachPort.cpp
new file mode 100644
index 000000000000..ca818d405a20
--- /dev/null
+++ b/source/Core/ConnectionMachPort.cpp
@@ -0,0 +1,323 @@
+//===-- ConnectionMachPort.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#if defined(__APPLE__)
+
+#include "lldb/Core/ConnectionMachPort.h"
+
+// C Includes
+#include <servers/bootstrap.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+struct MessageType
+{
+ mach_msg_header_t head;
+ ConnectionMachPort::PayloadType payload;
+};
+
+
+
+ConnectionMachPort::ConnectionMachPort () :
+ Connection(),
+ m_task(mach_task_self()),
+ m_port(MACH_PORT_TYPE_NONE)
+{
+}
+
+ConnectionMachPort::~ConnectionMachPort ()
+{
+ Disconnect (NULL);
+}
+
+bool
+ConnectionMachPort::IsConnected () const
+{
+ return m_port != MACH_PORT_TYPE_NONE;
+}
+
+ConnectionStatus
+ConnectionMachPort::Connect (const char *s, Error *error_ptr)
+{
+ if (IsConnected())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("already connected");
+ return eConnectionStatusError;
+ }
+
+ if (s == NULL || s[0] == '\0')
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("empty connect URL");
+ return eConnectionStatusError;
+ }
+
+ ConnectionStatus status = eConnectionStatusError;
+
+ if (strncmp (s, "bootstrap-checkin://", strlen("bootstrap-checkin://")))
+ {
+ s += strlen("bootstrap-checkin://");
+
+ if (*s)
+ {
+ status = BootstrapCheckIn (s, error_ptr);
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap port name is empty");
+ }
+ }
+ else if (strncmp (s, "bootstrap-lookup://", strlen("bootstrap-lookup://")))
+ {
+ s += strlen("bootstrap-lookup://");
+ if (*s)
+ {
+ status = BootstrapLookup (s, error_ptr);
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap port name is empty");
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+ }
+
+
+ if (status == eConnectionStatusSuccess)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ }
+ else
+ {
+ Disconnect(NULL);
+ }
+
+ return status;
+}
+
+ConnectionStatus
+ConnectionMachPort::BootstrapCheckIn (const char *port, Error *error_ptr)
+{
+ mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
+
+ /* Getting bootstrap server port */
+ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (kret == KERN_SUCCESS)
+ {
+ name_t port_name;
+ int len = snprintf(port_name, sizeof(port_name), "%s", port);
+ if (len < sizeof(port_name))
+ {
+ kret = ::bootstrap_check_in (bootstrap_port,
+ port_name,
+ &m_port);
+ }
+ else
+ {
+ Disconnect(NULL);
+ if (error_ptr)
+ error_ptr->SetErrorString ("bootstrap is too long");
+ return eConnectionStatusError;
+ }
+ }
+
+ if (kret != KERN_SUCCESS)
+ {
+ Disconnect(NULL);
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ return eConnectionStatusError;
+ }
+ return eConnectionStatusSuccess;
+}
+
+lldb::ConnectionStatus
+ConnectionMachPort::BootstrapLookup (const char *port,
+ Error *error_ptr)
+{
+ name_t port_name;
+
+ if (port && port[0])
+ {
+ if (::snprintf (port_name, sizeof (port_name), "%s", port) >= sizeof (port_name))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("port netname is too long");
+ return eConnectionStatusError;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("empty port netname");
+ return eConnectionStatusError;
+ }
+
+ mach_port_t bootstrap_port = MACH_PORT_TYPE_NONE;
+
+ /* Getting bootstrap server port */
+ kern_return_t kret = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (kret == KERN_SUCCESS)
+ {
+ kret = ::bootstrap_look_up (bootstrap_port,
+ port_name,
+ &m_port);
+ }
+
+ if (kret != KERN_SUCCESS)
+ {
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ return eConnectionStatusError;
+ }
+
+ return eConnectionStatusSuccess;
+}
+
+ConnectionStatus
+ConnectionMachPort::Disconnect (Error *error_ptr)
+{
+ kern_return_t kret;
+
+ // TODO: verify if we need to netname_check_out for
+ // either or both
+ if (m_port != MACH_PORT_TYPE_NONE)
+ {
+ kret = ::mach_port_deallocate (m_task, m_port);
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ m_port = MACH_PORT_TYPE_NONE;
+ }
+
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionMachPort::Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ PayloadType payload;
+
+ kern_return_t kret = Receive (payload);
+ if (kret == KERN_SUCCESS)
+ {
+ memcpy (dst, payload.data, payload.data_length);
+ status = eConnectionStatusSuccess;
+ return payload.data_length;
+ }
+
+ if (error_ptr)
+ error_ptr->SetError (kret, eErrorTypeMachKernel);
+ status = eConnectionStatusError;
+ return 0;
+}
+
+size_t
+ConnectionMachPort::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ PayloadType payload;
+ payload.command = 0;
+ payload.data_length = src_len;
+ const size_t max_payload_size = sizeof(payload.data);
+ if (src_len > max_payload_size)
+ payload.data_length = max_payload_size;
+ memcpy (payload.data, src, payload.data_length);
+
+ if (Send (payload) == KERN_SUCCESS)
+ {
+ status = eConnectionStatusSuccess;
+ return payload.data_length;
+ }
+ status = eConnectionStatusError;
+ return 0;
+}
+
+ConnectionStatus
+ConnectionMachPort::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ return eConnectionStatusLostConnection;
+}
+
+kern_return_t
+ConnectionMachPort::Send (const PayloadType &payload)
+{
+ struct MessageType message;
+
+ /* (i) Form the message : */
+
+ /* (i.a) Fill the header fields : */
+ message.head.msgh_bits = MACH_MSGH_BITS_REMOTE (MACH_MSG_TYPE_MAKE_SEND) |
+ MACH_MSGH_BITS_OTHER (MACH_MSGH_BITS_COMPLEX);
+ message.head.msgh_size = sizeof(MessageType);
+ message.head.msgh_local_port = MACH_PORT_NULL;
+ message.head.msgh_remote_port = m_port;
+
+ /* (i.b) Explain the message type ( an integer ) */
+ // message.type.msgt_name = MACH_MSG_TYPE_INTEGER_32;
+ // message.type.msgt_size = 32;
+ // message.type.msgt_number = 1;
+ // message.type.msgt_inline = TRUE;
+ // message.type.msgt_longform = FALSE;
+ // message.type.msgt_deallocate = FALSE;
+ /* message.type.msgt_unused = 0; */ /* not needed, I think */
+
+ /* (i.c) Fill the message with the given integer : */
+ message.payload = payload;
+
+ /* (ii) Send the message : */
+ kern_return_t kret = ::mach_msg (&message.head,
+ MACH_SEND_MSG,
+ message.head.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ return kret;
+}
+
+kern_return_t
+ConnectionMachPort::Receive (PayloadType &payload)
+{
+ MessageType message;
+ message.head.msgh_size = sizeof(MessageType);
+
+ kern_return_t kret = ::mach_msg (&message.head,
+ MACH_RCV_MSG,
+ 0,
+ sizeof(MessageType),
+ m_port,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ if (kret == KERN_SUCCESS)
+ payload = message.payload;
+
+ return kret;
+}
+
+
+#endif // #if defined(__APPLE__)
diff --git a/source/Core/ConnectionSharedMemory.cpp b/source/Core/ConnectionSharedMemory.cpp
new file mode 100644
index 000000000000..625f17a0985b
--- /dev/null
+++ b/source/Core/ConnectionSharedMemory.cpp
@@ -0,0 +1,131 @@
+//===-- ConnectionSharedMemory.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/ConnectionSharedMemory.h"
+
+// C Includes
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConnectionSharedMemory::ConnectionSharedMemory () :
+ Connection(),
+ m_name(),
+ m_fd (-1),
+ m_mmap()
+{
+}
+
+ConnectionSharedMemory::~ConnectionSharedMemory ()
+{
+ Disconnect (NULL);
+}
+
+bool
+ConnectionSharedMemory::IsConnected () const
+{
+ return m_fd >= 0;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Connect (const char *s, Error *error_ptr)
+{
+// if (s && s[0])
+// {
+// if (strstr(s, "shm-create://"))
+// {
+// }
+// else if (strstr(s, "shm-connect://"))
+// {
+// }
+// if (error_ptr)
+// error_ptr->SetErrorStringWithFormat ("unsupported connection URL: '%s'", s);
+// return eConnectionStatusError;
+// }
+ if (error_ptr)
+ error_ptr->SetErrorString("invalid connect arguments");
+ return eConnectionStatusError;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Disconnect (Error *error_ptr)
+{
+ m_mmap.Clear();
+ if (!m_name.empty())
+ {
+ shm_unlink (m_name.c_str());
+ m_name.clear();
+ }
+ return eConnectionStatusSuccess;
+}
+
+size_t
+ConnectionSharedMemory::Read (void *dst,
+ size_t dst_len,
+ uint32_t timeout_usec,
+ ConnectionStatus &status,
+ Error *error_ptr)
+{
+ status = eConnectionStatusSuccess;
+ return 0;
+}
+
+size_t
+ConnectionSharedMemory::Write (const void *src, size_t src_len, ConnectionStatus &status, Error *error_ptr)
+{
+ status = eConnectionStatusSuccess;
+ return 0;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::BytesAvailable (uint32_t timeout_usec, Error *error_ptr)
+{
+ return eConnectionStatusLostConnection;
+}
+
+ConnectionStatus
+ConnectionSharedMemory::Open (bool create, const char *name, size_t size, Error *error_ptr)
+{
+ if (m_fd != -1)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("already open");
+ return eConnectionStatusError;
+ }
+
+ m_name.assign (name);
+ int oflag = O_RDWR;
+ if (create)
+ oflag |= O_CREAT;
+ m_fd = ::shm_open (m_name.c_str(), oflag, S_IRUSR|S_IWUSR);
+
+ if (create)
+ ::ftruncate (m_fd, size);
+
+ if (m_mmap.MemoryMapFromFileDescriptor(m_fd, 0, size, true, false) == size)
+ return eConnectionStatusSuccess;
+
+ Disconnect(NULL);
+ return eConnectionStatusError;
+}
+
diff --git a/source/Core/ConstString.cpp b/source/Core/ConstString.cpp
new file mode 100644
index 000000000000..875169428d2a
--- /dev/null
+++ b/source/Core/ConstString.cpp
@@ -0,0 +1,342 @@
+//===-- ConstString.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/ConstString.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+#include "llvm/ADT/StringMap.h"
+
+using namespace lldb_private;
+
+
+class Pool
+{
+public:
+ typedef const char * StringPoolValueType;
+ typedef llvm::StringMap<StringPoolValueType, llvm::BumpPtrAllocator> StringPool;
+ typedef llvm::StringMapEntry<StringPoolValueType> StringPoolEntryType;
+
+ //------------------------------------------------------------------
+ // Default constructor
+ //
+ // Initialize the member variables and create the empty string.
+ //------------------------------------------------------------------
+ Pool () :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_string_map ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ // Destructor
+ //------------------------------------------------------------------
+ ~Pool ()
+ {
+ }
+
+
+ static StringPoolEntryType &
+ GetStringMapEntryFromKeyData (const char *keyData)
+ {
+ char *ptr = const_cast<char*>(keyData) - sizeof (StringPoolEntryType);
+ return *reinterpret_cast<StringPoolEntryType*>(ptr);
+ }
+
+ size_t
+ GetConstCStringLength (const char *ccstr) const
+ {
+ if (ccstr)
+ {
+ const StringPoolEntryType&entry = GetStringMapEntryFromKeyData (ccstr);
+ return entry.getKey().size();
+ }
+ return 0;
+ }
+
+ StringPoolValueType
+ GetMangledCounterpart (const char *ccstr) const
+ {
+ if (ccstr)
+ return GetStringMapEntryFromKeyData (ccstr).getValue();
+ return 0;
+ }
+
+ bool
+ SetMangledCounterparts (const char *key_ccstr, const char *value_ccstr)
+ {
+ if (key_ccstr && value_ccstr)
+ {
+ GetStringMapEntryFromKeyData (key_ccstr).setValue(value_ccstr);
+ GetStringMapEntryFromKeyData (value_ccstr).setValue(key_ccstr);
+ return true;
+ }
+ return false;
+ }
+
+ const char *
+ GetConstCString (const char *cstr)
+ {
+ if (cstr)
+ return GetConstCStringWithLength (cstr, strlen (cstr));
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithLength (const char *cstr, size_t cstr_len)
+ {
+ if (cstr)
+ {
+ Mutex::Locker locker (m_mutex);
+ llvm::StringRef string_ref (cstr, cstr_len);
+ StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ return entry.getKeyData();
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringWithStringRef (const llvm::StringRef &string_ref)
+ {
+ if (string_ref.data())
+ {
+ Mutex::Locker locker (m_mutex);
+ StringPoolEntryType& entry = m_string_map.GetOrCreateValue (string_ref, (StringPoolValueType)NULL);
+ return entry.getKeyData();
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstCStringAndSetMangledCounterPart (const char *demangled_cstr, const char *mangled_ccstr)
+ {
+ if (demangled_cstr)
+ {
+ 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);
+
+ // Extract the const version of the demangled_cstr
+ const char *demangled_ccstr = entry.getKeyData();
+ // Now assign the demangled const string as the counterpart of the
+ // mangled const string...
+ GetStringMapEntryFromKeyData (mangled_ccstr).setValue(demangled_ccstr);
+ // Return the constant demangled C string
+ return demangled_ccstr;
+ }
+ return NULL;
+ }
+
+ const char *
+ GetConstTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
+ {
+ if (cstr)
+ {
+ const size_t trimmed_len = std::min<size_t> (strlen (cstr), cstr_len);
+ return GetConstCStringWithLength (cstr, trimmed_len);
+ }
+ return NULL;
+ }
+
+ //------------------------------------------------------------------
+ // Return the size in bytes that this object and any items in its
+ // collection of uniqued strings + data count values takes in
+ // memory.
+ //------------------------------------------------------------------
+ size_t
+ MemorySize() const
+ {
+ Mutex::Locker locker (m_mutex);
+ size_t mem_size = sizeof(Pool);
+ const_iterator end = m_string_map.end();
+ for (const_iterator pos = m_string_map.begin(); pos != end; ++pos)
+ {
+ mem_size += sizeof(StringPoolEntryType) + pos->getKey().size();
+ }
+ return mem_size;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Typedefs
+ //------------------------------------------------------------------
+ typedef StringPool::iterator iterator;
+ typedef StringPool::const_iterator const_iterator;
+
+ //------------------------------------------------------------------
+ // Member variables
+ //------------------------------------------------------------------
+ mutable Mutex m_mutex;
+ StringPool m_string_map;
+};
+
+//----------------------------------------------------------------------
+// Frameworks and dylibs aren't supposed to have global C++
+// initializers so we hide the string pool in a static function so
+// that it will get initialized on the first call to this static
+// function.
+//
+// Note, for now we make the string pool a pointer to the pool, because
+// 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 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();
+ }
+ }
+
+ return *g_string_pool;
+}
+
+ConstString::ConstString (const char *cstr) :
+ m_string (StringPool().GetConstCString (cstr))
+{
+}
+
+ConstString::ConstString (const char *cstr, size_t cstr_len) :
+ m_string (StringPool().GetConstCStringWithLength (cstr, cstr_len))
+{
+}
+
+ConstString::ConstString (const llvm::StringRef &s) :
+ m_string (StringPool().GetConstCStringWithLength (s.data(), s.size()))
+{
+}
+
+bool
+ConstString::operator < (const ConstString& rhs) const
+{
+ if (m_string == rhs.m_string)
+ return false;
+
+ llvm::StringRef lhs_string_ref (m_string, StringPool().GetConstCStringLength (m_string));
+ llvm::StringRef rhs_string_ref (rhs.m_string, StringPool().GetConstCStringLength (rhs.m_string));
+
+ // If both have valid C strings, then return the comparison
+ if (lhs_string_ref.data() && rhs_string_ref.data())
+ return lhs_string_ref < rhs_string_ref;
+
+ // Else one of them was NULL, so if LHS is NULL then it is less than
+ return lhs_string_ref.data() == NULL;
+}
+
+Stream&
+lldb_private::operator << (Stream& s, const ConstString& str)
+{
+ const char *cstr = str.GetCString();
+ if (cstr)
+ s << cstr;
+
+ return s;
+}
+
+size_t
+ConstString::GetLength () const
+{
+ return StringPool().GetConstCStringLength (m_string);
+}
+
+int
+ConstString::Compare (const ConstString& lhs, const ConstString& rhs)
+{
+ // If the iterators are the same, this is the same string
+ register const char *lhs_cstr = lhs.m_string;
+ register const char *rhs_cstr = rhs.m_string;
+ if (lhs_cstr == rhs_cstr)
+ return 0;
+ if (lhs_cstr && rhs_cstr)
+ {
+ llvm::StringRef lhs_string_ref (lhs_cstr, StringPool().GetConstCStringLength (lhs_cstr));
+ llvm::StringRef rhs_string_ref (rhs_cstr, StringPool().GetConstCStringLength (rhs_cstr));
+ return lhs_string_ref.compare(rhs_string_ref);
+ }
+
+ if (lhs_cstr)
+ return +1; // LHS isn't NULL but RHS is
+ else
+ return -1; // LHS is NULL but RHS isn't
+}
+
+void
+ConstString::Dump(Stream *s, const char *fail_value) const
+{
+ if (s)
+ {
+ const char *cstr = AsCString (fail_value);
+ if (cstr)
+ s->PutCString (cstr);
+ }
+}
+
+void
+ConstString::DumpDebug(Stream *s) const
+{
+ const char *cstr = GetCString ();
+ size_t cstr_len = GetLength();
+ // Only print the parens if we have a non-NULL string
+ const char *parens = cstr ? "\"" : "";
+ s->Printf("%*p: ConstString, string = %s%s%s, length = %" PRIu64, (int)sizeof(void*) * 2, this, parens, cstr, parens, (uint64_t)cstr_len);
+}
+
+void
+ConstString::SetCString (const char *cstr)
+{
+ m_string = StringPool().GetConstCString (cstr);
+}
+
+void
+ConstString::SetString (const llvm::StringRef &s)
+{
+ m_string = StringPool().GetConstCStringWithLength (s.data(), s.size());
+}
+
+void
+ConstString::SetCStringWithMangledCounterpart (const char *demangled, const ConstString &mangled)
+{
+ m_string = StringPool().GetConstCStringAndSetMangledCounterPart (demangled, mangled.m_string);
+}
+
+bool
+ConstString::GetMangledCounterpart (ConstString &counterpart) const
+{
+ counterpart.m_string = StringPool().GetMangledCounterpart(m_string);
+ return counterpart;
+}
+
+void
+ConstString::SetCStringWithLength (const char *cstr, size_t cstr_len)
+{
+ m_string = StringPool().GetConstCStringWithLength(cstr, cstr_len);
+}
+
+void
+ConstString::SetTrimmedCStringWithLength (const char *cstr, size_t cstr_len)
+{
+ m_string = StringPool().GetConstTrimmedCStringWithLength (cstr, cstr_len);
+}
+
+size_t
+ConstString::StaticMemorySize()
+{
+ // Get the size of the static string pool
+ return StringPool().MemorySize();
+}
diff --git a/source/Core/DataBufferHeap.cpp b/source/Core/DataBufferHeap.cpp
new file mode 100644
index 000000000000..2c8a865b966c
--- /dev/null
+++ b/source/Core/DataBufferHeap.cpp
@@ -0,0 +1,111 @@
+//===-- DataBufferHeap.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap () :
+ m_data()
+{
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with "n" characters and fill the buffer
+// with "ch".
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (lldb::offset_t n, uint8_t ch) :
+ m_data()
+{
+ if (n < m_data.max_size())
+ m_data.assign (n, ch);
+}
+
+//----------------------------------------------------------------------
+// Initialize this class with a copy of the "n" bytes from the "bytes"
+// buffer.
+//----------------------------------------------------------------------
+DataBufferHeap::DataBufferHeap (const void *src, lldb::offset_t src_len) :
+ m_data()
+{
+ CopyData (src, src_len);
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor since this class inherits from a pure virtual
+// base class.
+//----------------------------------------------------------------------
+DataBufferHeap::~DataBufferHeap ()
+{
+}
+
+//----------------------------------------------------------------------
+// Return a pointer to the bytes owned by this object, or NULL if
+// the object contains no bytes.
+//----------------------------------------------------------------------
+uint8_t *
+DataBufferHeap::GetBytes ()
+{
+ if (m_data.empty())
+ return NULL;
+ return &m_data[0];
+}
+
+//----------------------------------------------------------------------
+// Return a const pointer to the bytes owned by this object, or NULL
+// if the object contains no bytes.
+//----------------------------------------------------------------------
+const uint8_t *
+DataBufferHeap::GetBytes () const
+{
+ if (m_data.empty())
+ return NULL;
+ return &m_data[0];
+}
+
+//----------------------------------------------------------------------
+// Return the number of bytes this object currently contains.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferHeap::GetByteSize () const
+{
+ return m_data.size();
+}
+
+
+//----------------------------------------------------------------------
+// Sets the number of bytes that this object should be able to
+// contain. This can be used prior to copying data into the buffer.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferHeap::SetByteSize (uint64_t new_size)
+{
+ m_data.resize(new_size);
+ return m_data.size();
+}
+
+void
+DataBufferHeap::CopyData (const void *src, uint64_t src_len)
+{
+ const uint8_t *src_u8 = (const uint8_t *)src;
+ if (src && src_len > 0)
+ m_data.assign (src_u8, src_u8 + src_len);
+ else
+ m_data.clear();
+}
+
+void
+DataBufferHeap::Clear()
+{
+ buffer_t empty;
+ m_data.swap(empty);
+}
diff --git a/source/Core/DataBufferMemoryMap.cpp b/source/Core/DataBufferMemoryMap.cpp
new file mode 100644
index 000000000000..a4382a0c67e1
--- /dev/null
+++ b/source/Core/DataBufferMemoryMap.cpp
@@ -0,0 +1,258 @@
+//===-- DataBufferMemoryMap.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/Log.h"
+#include "lldb/lldb-private-log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default Constructor
+//----------------------------------------------------------------------
+DataBufferMemoryMap::DataBufferMemoryMap() :
+ m_mmap_addr(NULL),
+ m_mmap_size(0),
+ m_data(NULL),
+ m_size(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Virtual destructor since this class inherits from a pure virtual
+// base class.
+//----------------------------------------------------------------------
+DataBufferMemoryMap::~DataBufferMemoryMap()
+{
+ Clear();
+}
+
+//----------------------------------------------------------------------
+// Return a pointer to the bytes owned by this object, or NULL if
+// the object contains no bytes.
+//----------------------------------------------------------------------
+uint8_t *
+DataBufferMemoryMap::GetBytes()
+{
+ return m_data;
+}
+
+//----------------------------------------------------------------------
+// Return a const pointer to the bytes owned by this object, or NULL
+// if the object contains no bytes.
+//----------------------------------------------------------------------
+const uint8_t *
+DataBufferMemoryMap::GetBytes() const
+{
+ return m_data;
+}
+
+//----------------------------------------------------------------------
+// Return the number of bytes this object currently contains.
+//----------------------------------------------------------------------
+uint64_t
+DataBufferMemoryMap::GetByteSize() const
+{
+ return m_size;
+}
+
+//----------------------------------------------------------------------
+// Reverts this object to an empty state by unmapping any memory
+// that is currently owned.
+//----------------------------------------------------------------------
+void
+DataBufferMemoryMap::Clear()
+{
+ if (m_mmap_addr != NULL)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
+ if (log)
+ log->Printf("DataBufferMemoryMap::Clear() m_mmap_addr = %p, m_mmap_size = %zu", m_mmap_addr, m_mmap_size);
+ ::munmap((void *)m_mmap_addr, m_mmap_size);
+ m_mmap_addr = NULL;
+ m_mmap_size = 0;
+ m_data = NULL;
+ m_size = 0;
+ }
+}
+
+//----------------------------------------------------------------------
+// Memory map "length" bytes from "file" starting "offset"
+// bytes into the file. If "length" is set to SIZE_MAX, then
+// map as many bytes as possible.
+//
+// Returns the number of bytes mapped starting from the requested
+// offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileSpec (const FileSpec* filespec,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ bool writeable)
+{
+ if (filespec != NULL)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP));
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(file=\"%s\", offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i",
+ filespec->GetPath().c_str(),
+ offset,
+ length,
+ writeable);
+ }
+ char path[PATH_MAX];
+ if (filespec->GetPath(path, sizeof(path)))
+ {
+ uint32_t options = File::eOpenOptionRead;
+ if (writeable)
+ options |= File::eOpenOptionWrite;
+
+ File file;
+ Error error (file.Open(path, options));
+ if (error.Success())
+ {
+ const bool fd_is_file = true;
+ return MemoryMapFromFileDescriptor (file.GetDescriptor(), offset, length, writeable, fd_is_file);
+ }
+ }
+ }
+ // We should only get here if there was an error
+ Clear();
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// The file descriptor FD is assumed to already be opened as read only
+// and the STAT structure is assumed to a valid pointer and already
+// containing valid data from a call to stat().
+//
+// Memory map FILE_LENGTH bytes in FILE starting FILE_OFFSET bytes into
+// the file. If FILE_LENGTH is set to SIZE_MAX, then map as many bytes
+// as possible.
+//
+// RETURNS
+// Number of bytes mapped starting from the requested offset.
+//----------------------------------------------------------------------
+size_t
+DataBufferMemoryMap::MemoryMapFromFileDescriptor (int fd,
+ lldb::offset_t offset,
+ lldb::offset_t length,
+ bool writeable,
+ bool fd_is_file)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_MMAP|LIBLLDB_LOG_VERBOSE));
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec(fd=%i, offset=0x%" PRIx64 ", length=0x%" PRIx64 ", writeable=%i, fd_is_file=%i)",
+ fd,
+ offset,
+ length,
+ writeable,
+ fd_is_file);
+ }
+ struct stat stat;
+ if (::fstat(fd, &stat) == 0)
+ {
+ if (S_ISREG(stat.st_mode) && (stat.st_size > offset))
+ {
+ const size_t max_bytes_available = stat.st_size - offset;
+ if (length == SIZE_MAX)
+ {
+ length = max_bytes_available;
+ }
+ else if (length > max_bytes_available)
+ {
+ // Cap the length if too much data was requested
+ length = max_bytes_available;
+ }
+
+ if (length > 0)
+ {
+ int prot = PROT_READ;
+ if (writeable)
+ prot |= PROT_WRITE;
+
+ int flags = MAP_PRIVATE;
+ if (fd_is_file)
+ flags |= MAP_FILE;
+
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length, prot, flags, fd, offset);
+ Error error;
+
+ if (m_mmap_addr == (void*)-1)
+ {
+ error.SetErrorToErrno ();
+ if (error.GetError() == EINVAL)
+ {
+ // We may still have a shot at memory mapping if we align things correctly
+ size_t page_offset = offset % Host::GetPageSize();
+ if (page_offset != 0)
+ {
+ m_mmap_addr = (uint8_t *)::mmap(NULL, length + page_offset, prot, flags, fd, offset - page_offset);
+ if (m_mmap_addr == (void*)-1)
+ {
+ // Failed to map file
+ m_mmap_addr = NULL;
+ }
+ else if (m_mmap_addr != NULL)
+ {
+ // We recovered and were able to memory map
+ // after we aligned things to page boundaries
+
+ // Save the actual mmap'ed size
+ m_mmap_size = length + page_offset;
+ // Our data is at an offset into the the mapped data
+ m_data = m_mmap_addr + page_offset;
+ // Our pretend size is the size that was requestd
+ m_size = length;
+ }
+ }
+ }
+ if (error.GetError() == ENOMEM)
+ {
+ error.SetErrorStringWithFormat("could not allocate %" PRId64 " bytes of memory to mmap in file", (uint64_t) length);
+ }
+ }
+ else
+ {
+ // We were able to map the requested data in one chunk
+ // where our mmap and actual data are the same.
+ m_mmap_size = length;
+ m_data = m_mmap_addr;
+ m_size = length;
+ }
+
+ if (log)
+ {
+ log->Printf("DataBufferMemoryMap::MemoryMapFromFileSpec() m_mmap_addr = %p, m_mmap_size = %zu, error = %s",
+ m_mmap_addr, m_mmap_size, error.AsCString());
+ }
+ }
+ }
+ }
+ }
+ return GetByteSize ();
+}
diff --git a/source/Core/DataEncoder.cpp b/source/Core/DataEncoder.cpp
new file mode 100644
index 000000000000..92a9104acc3a
--- /dev/null
+++ b/source/Core/DataEncoder.cpp
@@ -0,0 +1,335 @@
+//===-- DataEncoder.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/DataEncoder.h"
+
+#include <assert.h>
+#include <stddef.h>
+
+#include "llvm/Support/MathExtras.h"
+
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Host/Endian.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline void
+WriteInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+{
+ *(uint16_t *)(ptr + offset) = value;
+}
+static inline void
+WriteInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+{
+ *(uint32_t *)(ptr + offset) = value;
+}
+
+static inline void
+WriteInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+{
+ *(uint64_t *)(ptr + offset) = value;
+}
+
+static inline void
+WriteSwappedInt16(const unsigned char* ptr, unsigned offset, uint16_t value)
+{
+ *(uint16_t *)(ptr + offset) = llvm::ByteSwap_16(value);
+}
+
+static inline void
+WriteSwappedInt32 (const unsigned char* ptr, unsigned offset, uint32_t value)
+{
+ *(uint32_t *)(ptr + offset) = llvm::ByteSwap_32(value);
+}
+
+static inline void
+WriteSwappedInt64(const unsigned char* ptr, unsigned offset, uint64_t value)
+{
+ *(uint64_t *)(ptr + offset) = llvm::ByteSwap_64(value);
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_addr_size (sizeof(void*)),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// 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.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder (void* data, uint32_t length, ByteOrder endian, uint8_t addr_size) :
+ m_start ((uint8_t*)data),
+ m_end ((uint8_t*)data + length),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// Make a shared pointer reference to the shared data in "data_sp" and
+// set the endian swapping setting to "swap", and the address size to
+// "addr_size". The shared data reference will ensure the data lives
+// as long as any DataEncoder objects exist that have a reference to
+// this data.
+//----------------------------------------------------------------------
+DataEncoder::DataEncoder (const DataBufferSP& data_sp, ByteOrder endian, uint8_t addr_size) :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+ SetData (data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DataEncoder::~DataEncoder ()
+{
+}
+
+//------------------------------------------------------------------
+// Clears the object contents back to a default invalid state, and
+// release any references to shared data that this object may
+// contain.
+//------------------------------------------------------------------
+void
+DataEncoder::Clear ()
+{
+ m_start = NULL;
+ m_end = NULL;
+ m_byte_order = lldb::endian::InlHostByteOrder();
+ m_addr_size = sizeof(void*);
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// If this object contains shared data, this function returns the
+// offset into that shared data. Else zero is returned.
+//------------------------------------------------------------------
+size_t
+DataEncoder::GetSharedDataOffset () const
+{
+ if (m_start != NULL)
+ {
+ const DataBuffer * data = m_data_sp.get();
+ if (data != NULL)
+ {
+ const uint8_t * data_bytes = data->GetBytes();
+ if (data_bytes != NULL)
+ {
+ assert(m_start >= data_bytes);
+ return m_start - data_bytes;
+ }
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Set the data with which this object will extract from to data
+// starting at BYTES and set the length of the data to LENGTH bytes
+// long. The data is externally owned must be around at least as
+// long as this object points to the data. No copy of the data is
+// made, this object just refers to this data and can extract from
+// it. If this object refers to any shared data upon entry, the
+// reference to that data will be released. Is SWAP is set to true,
+// any data extracted will be endian swapped.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::SetData (const void *bytes, uint32_t length, ByteOrder endian)
+{
+ m_byte_order = endian;
+ m_data_sp.reset();
+ if (bytes == NULL || length == 0)
+ {
+ m_start = NULL;
+ m_end = NULL;
+ }
+ else
+ {
+ m_start = (uint8_t *)bytes;
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange of the shared
+// data in "data_sp" starting "data_offset" bytes into "data_sp"
+// and ending "data_length" bytes later. If "data_offset" is not
+// a valid offset into "data_sp", then this object will contain no
+// bytes. If "data_offset" is within "data_sp" yet "data_length" is
+// too large, the length will be capped at the number of bytes
+// remaining in "data_sp". A ref counted pointer to the data in
+// "data_sp" will be made in this object IF the number of bytes this
+// object refers to in greater than zero (if at least one byte was
+// available starting at "data_offset") to ensure the data stays
+// around as long as it is needed. The address size and endian swap
+// settings will remain unchanged from their current settings.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::SetData (const DataBufferSP& data_sp, uint32_t data_offset, uint32_t data_length)
+{
+ m_start = m_end = NULL;
+
+ if (data_length > 0)
+ {
+ m_data_sp = data_sp;
+ if (data_sp.get())
+ {
+ const size_t data_size = data_sp->GetByteSize();
+ if (data_offset < data_size)
+ {
+ m_start = data_sp->GetBytes() + data_offset;
+ const size_t bytes_left = data_size - data_offset;
+ // Cap the length of we asked for too many
+ if (data_length <= bytes_left)
+ m_end = m_start + data_length; // We got all the bytes we wanted
+ else
+ m_end = m_start + bytes_left; // Not all the bytes requested were available in the shared data
+ }
+ }
+ }
+
+ uint32_t new_size = GetByteSize();
+
+ // Don't hold a shared pointer to the data buffer if we don't share
+ // any valid bytes in the shared buffer.
+ if (new_size == 0)
+ m_data_sp.reset();
+
+ return new_size;
+}
+
+//----------------------------------------------------------------------
+// Extract a single unsigned char from the binary data and update
+// the offset pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::PutU8 (uint32_t offset, uint8_t value)
+{
+ if (ValidOffset(offset))
+ {
+ m_start[offset] = value;
+ return offset + 1;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU16 (uint32_t offset, uint16_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt16 (m_start, offset, value);
+ else
+ WriteInt16 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU32 (uint32_t offset, uint32_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt32 (m_start, offset, value);
+ else
+ WriteInt32 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutU64 (uint32_t offset, uint64_t value)
+{
+ if (ValidOffsetForDataOfSize(offset, sizeof(value)))
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ WriteSwappedInt64 (m_start, offset, value);
+ else
+ WriteInt64 (m_start, offset, value);
+
+ return offset + sizeof (value);
+ }
+ return UINT32_MAX;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataEncoder::PutMaxU64 (uint32_t offset, uint32_t byte_size, uint64_t value)
+{
+ switch (byte_size)
+ {
+ case 1: return PutU8 (offset, value);
+ case 2: return PutU16(offset, value);
+ case 4: return PutU32(offset, value);
+ case 8: return PutU64(offset, value);
+ default:
+ assert(!"GetMax64 unhandled case!");
+ break;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutData (uint32_t offset, const void *src, uint32_t src_len)
+{
+ if (src == NULL || src_len == 0)
+ return offset;
+
+ if (ValidOffsetForDataOfSize(offset, src_len))
+ {
+ memcpy (m_start + offset, src, src_len);
+ return offset + src_len;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+DataEncoder::PutAddress (uint32_t offset, lldb::addr_t addr)
+{
+ return PutMaxU64 (offset, GetAddressByteSize(), addr);
+}
+
+uint32_t
+DataEncoder::PutCString (uint32_t offset, const char *cstr)
+{
+ if (cstr)
+ return PutData (offset, cstr, strlen(cstr) + 1);
+ return UINT32_MAX;
+}
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp
new file mode 100644
index 000000000000..518faeb71ea7
--- /dev/null
+++ b/source/Core/DataExtractor.cpp
@@ -0,0 +1,2179 @@
+//===-- DataExtractor.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+#include <stddef.h>
+
+#include <bitset>
+#include <limits>
+#include <sstream>
+#include <string>
+
+#include "clang/AST/ASTContext.h"
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/MathExtras.h"
+
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static inline uint16_t
+ReadInt16(const unsigned char* ptr, offset_t offset)
+{
+ return *(uint16_t *)(ptr + offset);
+}
+static inline uint32_t
+ReadInt32 (const unsigned char* ptr, offset_t offset)
+{
+ return *(uint32_t *)(ptr + offset);
+}
+
+static inline uint64_t
+ReadInt64(const unsigned char* ptr, offset_t offset)
+{
+ return *(uint64_t *)(ptr + offset);
+}
+
+static inline uint16_t
+ReadInt16(const void* ptr)
+{
+ return *(uint16_t *)(ptr);
+}
+static inline uint32_t
+ReadInt32 (const void* ptr)
+{
+ return *(uint32_t *)(ptr);
+}
+
+static inline uint64_t
+ReadInt64(const void* ptr)
+{
+ return *(uint64_t *)(ptr);
+}
+
+static inline uint16_t
+ReadSwapInt16(const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_16(*(uint16_t *)(ptr + offset));
+}
+
+static inline uint32_t
+ReadSwapInt32 (const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_32(*(uint32_t *)(ptr + offset));
+}
+static inline uint64_t
+ReadSwapInt64(const unsigned char* ptr, offset_t offset)
+{
+ return llvm::ByteSwap_64(*(uint64_t *)(ptr + offset));
+}
+
+static inline uint16_t
+ReadSwapInt16(const void* ptr)
+{
+ return llvm::ByteSwap_16(*(uint16_t *)(ptr));
+}
+
+static inline uint32_t
+ReadSwapInt32 (const void* ptr)
+{
+ return llvm::ByteSwap_32(*(uint32_t *)(ptr));
+}
+static inline uint64_t
+ReadSwapInt64(const void* ptr)
+{
+ return llvm::ByteSwap_64(*(uint64_t *)(ptr));
+}
+
+#define NON_PRINTABLE_CHAR '.'
+//----------------------------------------------------------------------
+// Default constructor.
+//----------------------------------------------------------------------
+DataExtractor::DataExtractor () :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_addr_size (4),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// 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) :
+ m_start ((uint8_t*)data),
+ m_end ((uint8_t*)data + length),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+}
+
+//----------------------------------------------------------------------
+// Make a shared pointer reference to the shared data in "data_sp" and
+// set the endian swapping setting to "swap", and the address size to
+// "addr_size". The shared data reference will ensure the data lives
+// 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) :
+ m_start (NULL),
+ m_end (NULL),
+ m_byte_order(endian),
+ m_addr_size (addr_size),
+ m_data_sp ()
+{
+ SetData (data_sp);
+}
+
+//----------------------------------------------------------------------
+// Initialize this object with a subset of the data bytes in "data".
+// If "data" contains shared data, then a reference to this shared
+// data will added and the shared data will stay around as long
+// 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) :
+ m_start(NULL),
+ m_end(NULL),
+ m_byte_order(data.m_byte_order),
+ m_addr_size(data.m_addr_size),
+ m_data_sp()
+{
+ if (data.ValidOffset(offset))
+ {
+ offset_t bytes_available = data.GetByteSize() - offset;
+ if (length > bytes_available)
+ length = bytes_available;
+ SetData(data, offset, length);
+ }
+}
+
+DataExtractor::DataExtractor (const DataExtractor& rhs) :
+ m_start (rhs.m_start),
+ 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)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const DataExtractor&
+DataExtractor::operator= (const DataExtractor& rhs)
+{
+ if (this != &rhs)
+ {
+ m_start = rhs.m_start;
+ 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;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DataExtractor::~DataExtractor ()
+{
+}
+
+//------------------------------------------------------------------
+// Clears the object contents back to a default invalid state, and
+// release any references to shared data that this object may
+// contain.
+//------------------------------------------------------------------
+void
+DataExtractor::Clear ()
+{
+ m_start = NULL;
+ m_end = NULL;
+ m_byte_order = lldb::endian::InlHostByteOrder();
+ m_addr_size = 4;
+ m_data_sp.reset();
+}
+
+//------------------------------------------------------------------
+// If this object contains shared data, this function returns the
+// offset into that shared data. Else zero is returned.
+//------------------------------------------------------------------
+size_t
+DataExtractor::GetSharedDataOffset () const
+{
+ if (m_start != NULL)
+ {
+ const DataBuffer * data = m_data_sp.get();
+ if (data != NULL)
+ {
+ const uint8_t * data_bytes = data->GetBytes();
+ if (data_bytes != NULL)
+ {
+ assert(m_start >= data_bytes);
+ return m_start - data_bytes;
+ }
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Set the data with which this object will extract from to data
+// starting at BYTES and set the length of the data to LENGTH bytes
+// long. The data is externally owned must be around at least as
+// long as this object points to the data. No copy of the data is
+// made, this object just refers to this data and can extract from
+// it. If this object refers to any shared data upon entry, the
+// reference to that data will be released. Is SWAP is set to true,
+// any data extracted will be endian swapped.
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const void *bytes, offset_t length, ByteOrder endian)
+{
+ m_byte_order = endian;
+ m_data_sp.reset();
+ if (bytes == NULL || length == 0)
+ {
+ m_start = NULL;
+ m_end = NULL;
+ }
+ else
+ {
+ m_start = (uint8_t *)bytes;
+ m_end = m_start + length;
+ }
+ return GetByteSize();
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange in "data"
+// starting "data_offset" bytes into "data" and ending "data_length"
+// bytes later. If "data_offset" is not a valid offset into "data",
+// then this object will contain no bytes. If "data_offset" is
+// within "data" yet "data_length" is too large, the length will be
+// capped at the number of bytes remaining in "data". If "data"
+// contains a shared pointer to other data, then a ref counted
+// pointer to that data will be made in this object. If "data"
+// doesn't contain a shared pointer to data, then the bytes referred
+// to in "data" will need to exist at least as long as this object
+// refers to those bytes. The address size and endian swap settings
+// are copied from the current values in "data".
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const DataExtractor& data, offset_t data_offset, offset_t data_length)
+{
+ m_addr_size = data.m_addr_size;
+ // If "data" contains shared pointer to data, then we can use that
+ if (data.m_data_sp.get())
+ {
+ m_byte_order = data.m_byte_order;
+ return SetData(data.m_data_sp, data.GetSharedDataOffset() + data_offset, data_length);
+ }
+
+ // We have a DataExtractor object that just has a pointer to bytes
+ if (data.ValidOffset(data_offset))
+ {
+ if (data_length > data.GetByteSize() - data_offset)
+ data_length = data.GetByteSize() - data_offset;
+ return SetData (data.GetDataStart() + data_offset, data_length, data.GetByteOrder());
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Assign the data for this object to be a subrange of the shared
+// data in "data_sp" starting "data_offset" bytes into "data_sp"
+// and ending "data_length" bytes later. If "data_offset" is not
+// a valid offset into "data_sp", then this object will contain no
+// bytes. If "data_offset" is within "data_sp" yet "data_length" is
+// too large, the length will be capped at the number of bytes
+// remaining in "data_sp". A ref counted pointer to the data in
+// "data_sp" will be made in this object IF the number of bytes this
+// object refers to in greater than zero (if at least one byte was
+// available starting at "data_offset") to ensure the data stays
+// around as long as it is needed. The address size and endian swap
+// settings will remain unchanged from their current settings.
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::SetData (const DataBufferSP& data_sp, offset_t data_offset, offset_t data_length)
+{
+ m_start = m_end = NULL;
+
+ if (data_length > 0)
+ {
+ m_data_sp = data_sp;
+ if (data_sp.get())
+ {
+ const size_t data_size = data_sp->GetByteSize();
+ if (data_offset < data_size)
+ {
+ m_start = data_sp->GetBytes() + data_offset;
+ const size_t bytes_left = data_size - data_offset;
+ // Cap the length of we asked for too many
+ if (data_length <= bytes_left)
+ m_end = m_start + data_length; // We got all the bytes we wanted
+ else
+ m_end = m_start + bytes_left; // Not all the bytes requested were available in the shared data
+ }
+ }
+ }
+
+ size_t new_size = GetByteSize();
+
+ // Don't hold a shared pointer to the data buffer if we don't share
+ // any valid bytes in the shared buffer.
+ if (new_size == 0)
+ m_data_sp.reset();
+
+ return new_size;
+}
+
+//----------------------------------------------------------------------
+// Extract a single unsigned char from the binary data and update
+// the offset pointed to by "offset_ptr".
+//
+// RETURNS the byte that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint8_t
+DataExtractor::GetU8 (offset_t *offset_ptr) const
+{
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, 1);
+ if (data)
+ return *data;
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extract "count" unsigned chars from the binary data and update the
+// offset pointed to by "offset_ptr". The extracted data is copied into
+// "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available in
+// the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU8 (offset_t *offset_ptr, void *dst, uint32_t count) const
+{
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, count);
+ if (data)
+ {
+ // Copy the data into the buffer
+ memcpy (dst, data, count);
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint16_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint16_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint16_t
+DataExtractor::GetU16 (offset_t *offset_ptr) const
+{
+ uint16_t val = 0;
+ const uint8_t *data = (const uint8_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt16(data);
+ else
+ val = ReadInt16 (data);
+ }
+ return val;
+}
+
+uint16_t
+DataExtractor::GetU16_unchecked (offset_t *offset_ptr) const
+{
+ uint16_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt16 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt16(m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint32_t
+DataExtractor::GetU32_unchecked (offset_t *offset_ptr) const
+{
+ uint32_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt32 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt32 (m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+uint64_t
+DataExtractor::GetU64_unchecked (offset_t *offset_ptr) const
+{
+ uint64_t val;
+ if (m_byte_order == lldb::endian::InlHostByteOrder())
+ val = ReadInt64 (m_start, *offset_ptr);
+ else
+ val = ReadSwapInt64 (m_start, *offset_ptr);
+ *offset_ptr += sizeof(val);
+ return val;
+}
+
+
+//----------------------------------------------------------------------
+// Extract "count" uint16_t values from the binary data and update
+// the offset pointed to by "offset_ptr". The extracted data is
+// copied into "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available
+// in the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU16 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint16_t) * count;
+ const uint16_t *src = (const uint16_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint16_t *dst_pos = (uint16_t *)void_dst;
+ uint16_t *dst_end = dst_pos + count;
+ const uint16_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt16 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint32_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint32_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::GetU32 (offset_t *offset_ptr) const
+{
+ uint32_t val = 0;
+ const uint32_t *data = (const uint32_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt32 (data);
+ else
+ val = *data;
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// Extract "count" uint32_t values from the binary data and update
+// the offset pointed to by "offset_ptr". The extracted data is
+// copied into "dst".
+//
+// RETURNS the non-NULL buffer pointer upon successful extraction of
+// all the requested bytes, or NULL when the data is not available
+// in the buffer due to being out of bounds, or unsufficient data.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU32 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint32_t) * count;
+ const uint32_t *src = (const uint32_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint32_t *dst_pos = (uint32_t *)void_dst;
+ uint32_t *dst_end = dst_pos + count;
+ const uint32_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt32 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single uint64_t from the data and update the offset
+// pointed to by "offset_ptr".
+//
+// RETURNS the uint64_t that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetU64 (offset_t *offset_ptr) const
+{
+ uint64_t val = 0;
+ const uint64_t *data = (const uint64_t *)GetData (offset_ptr, sizeof(val));
+ if (data)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ val = ReadSwapInt64 (data);
+ else
+ val = *data;
+ }
+ return val;
+}
+
+//----------------------------------------------------------------------
+// GetU64
+//
+// Get multiple consecutive 64 bit values. Return true if the entire
+// read succeeds and increment the offset pointed to by offset_ptr, else
+// return false and leave the offset pointed to by offset_ptr unchanged.
+//----------------------------------------------------------------------
+void *
+DataExtractor::GetU64 (offset_t *offset_ptr, void *void_dst, uint32_t count) const
+{
+ const size_t src_size = sizeof(uint64_t) * count;
+ const uint64_t *src = (const uint64_t *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ uint64_t *dst_pos = (uint64_t *)void_dst;
+ uint64_t *dst_end = dst_pos + count;
+ const uint64_t *src_pos = src;
+ while (dst_pos < dst_end)
+ {
+ *dst_pos = ReadSwapInt64 (src_pos);
+ ++dst_pos;
+ ++src_pos;
+ }
+ }
+ else
+ {
+ memcpy (void_dst, src, src_size);
+ }
+ // Return a non-NULL pointer to the converted data as an indicator of success
+ return void_dst;
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value between 1 and 4 since the return value is only 32 bits
+// wide. Any "byte_size" values less than 1 or greater than 4 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::GetMaxU32 (offset_t *offset_ptr, size_t byte_size) const
+{
+ switch (byte_size)
+ {
+ case 1: return GetU8 (offset_ptr); break;
+ case 2: return GetU16(offset_ptr); break;
+ case 4: return GetU32(offset_ptr); break;
+ default:
+ assert("GetMaxU32 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extract a single integer value from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted integer
+// is specified by the "byte_size" argument. "byte_size" should have
+// a value >= 1 and <= 8 since the return value is only 64 bits
+// wide. Any "byte_size" values less than 1 or greater than 8 will
+// result in nothing being extracted, and zero being returned.
+//
+// RETURNS the integer value that was extracted, or zero on failure.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetMaxU64 (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return GetU8 (offset_ptr); break;
+ case 2: return GetU16(offset_ptr); break;
+ case 4: return GetU32(offset_ptr); break;
+ case 8: return GetU64(offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64_unchecked (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return GetU8_unchecked (offset_ptr); break;
+ case 2: return GetU16_unchecked (offset_ptr); break;
+ case 4: return GetU32_unchecked (offset_ptr); break;
+ case 8: return GetU64_unchecked (offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+int64_t
+DataExtractor::GetMaxS64 (offset_t *offset_ptr, size_t size) const
+{
+ switch (size)
+ {
+ case 1: return (int8_t)GetU8 (offset_ptr); break;
+ case 2: return (int16_t)GetU16(offset_ptr); break;
+ case 4: return (int32_t)GetU32(offset_ptr); break;
+ case 8: return (int64_t)GetU64(offset_ptr); break;
+ default:
+ assert("GetMax64 unhandled case!" == NULL);
+ break;
+ }
+ return 0;
+}
+
+uint64_t
+DataExtractor::GetMaxU64Bitfield (offset_t *offset_ptr, size_t size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset) const
+{
+ uint64_t uval64 = GetMaxU64 (offset_ptr, size);
+ if (bitfield_bit_size > 0)
+ {
+ if (bitfield_bit_offset > 0)
+ uval64 >>= bitfield_bit_offset;
+ uint64_t bitfield_mask = ((1ul << bitfield_bit_size) - 1);
+ if (!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64)
+ return uval64;
+ uval64 &= bitfield_mask;
+ }
+ return uval64;
+}
+
+int64_t
+DataExtractor::GetMaxS64Bitfield (offset_t *offset_ptr, size_t size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset) const
+{
+ int64_t sval64 = GetMaxS64 (offset_ptr, size);
+ if (bitfield_bit_size > 0)
+ {
+ if (bitfield_bit_offset > 0)
+ sval64 >>= bitfield_bit_offset;
+ uint64_t bitfield_mask = (((uint64_t)1) << bitfield_bit_size) - 1;
+ sval64 &= bitfield_mask;
+ // sign extend if needed
+ if (sval64 & (((uint64_t)1) << (bitfield_bit_size - 1)))
+ sval64 |= ~bitfield_mask;
+ }
+ return sval64;
+}
+
+
+float
+DataExtractor::GetFloat (offset_t *offset_ptr) const
+{
+ typedef float float_type;
+ float_type val = 0.0;
+ const size_t src_size = sizeof(float_type);
+ const float_type *src = (const float_type *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (uint8_t *)&val;
+ for (size_t i=0; i<sizeof(float_type); ++i)
+ dst_data[sizeof(float_type) - 1 - i] = src_data[i];
+ }
+ else
+ {
+ val = *src;
+ }
+ }
+ return val;
+}
+
+double
+DataExtractor::GetDouble (offset_t *offset_ptr) const
+{
+ typedef double float_type;
+ float_type val = 0.0;
+ const size_t src_size = sizeof(float_type);
+ const float_type *src = (const float_type *)GetData (offset_ptr, src_size);
+ if (src)
+ {
+ if (m_byte_order != lldb::endian::InlHostByteOrder())
+ {
+ const uint8_t *src_data = (const uint8_t *)src;
+ uint8_t *dst_data = (uint8_t *)&val;
+ for (size_t i=0; i<sizeof(float_type); ++i)
+ dst_data[sizeof(float_type) - 1 - i] = src_data[i];
+ }
+ else
+ {
+ val = *src;
+ }
+ }
+ return val;
+}
+
+
+long double
+DataExtractor::GetLongDouble (offset_t *offset_ptr) const
+{
+ long double val = 0.0;
+#if defined (__i386__) || defined (__amd64__) || defined (__x86_64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_X64)
+ *offset_ptr += CopyByteOrderedData (*offset_ptr, 10, &val, sizeof(val), lldb::endian::InlHostByteOrder());
+#else
+ *offset_ptr += CopyByteOrderedData (*offset_ptr, sizeof(val), &val, sizeof(val), lldb::endian::InlHostByteOrder());
+#endif
+ return val;
+}
+
+
+//------------------------------------------------------------------
+// Extract a single address from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted address
+// comes from the "this->m_addr_size" member variable and should be
+// set correctly prior to extracting any address values.
+//
+// RETURNS the address that was extracted, or zero on failure.
+//------------------------------------------------------------------
+uint64_t
+DataExtractor::GetAddress (offset_t *offset_ptr) const
+{
+ return GetMaxU64 (offset_ptr, m_addr_size);
+}
+
+uint64_t
+DataExtractor::GetAddress_unchecked (offset_t *offset_ptr) const
+{
+ return GetMaxU64_unchecked (offset_ptr, m_addr_size);
+}
+
+//------------------------------------------------------------------
+// Extract a single pointer from the data and update the offset
+// pointed to by "offset_ptr". The size of the extracted pointer
+// comes from the "this->m_addr_size" member variable and should be
+// set correctly prior to extracting any pointer values.
+//
+// RETURNS the pointer that was extracted, or zero on failure.
+//------------------------------------------------------------------
+uint64_t
+DataExtractor::GetPointer (offset_t *offset_ptr) const
+{
+ return GetMaxU64 (offset_ptr, m_addr_size);
+}
+
+//----------------------------------------------------------------------
+// GetDwarfEHPtr
+//
+// Used for calls when the value type is specified by a DWARF EH Frame
+// pointer encoding.
+//----------------------------------------------------------------------
+
+uint64_t
+DataExtractor::GetGNUEHPointer (offset_t *offset_ptr, uint32_t eh_ptr_enc, lldb::addr_t pc_rel_addr, lldb::addr_t text_addr, lldb::addr_t data_addr)//, BSDRelocs *data_relocs) const
+{
+ if (eh_ptr_enc == DW_EH_PE_omit)
+ return ULLONG_MAX; // Value isn't in the buffer...
+
+ uint64_t baseAddress = 0;
+ uint64_t addressValue = 0;
+ const uint32_t addr_size = GetAddressByteSize();
+
+ bool signExtendValue = false;
+ // Decode the base part or adjust our offset
+ switch (eh_ptr_enc & 0x70)
+ {
+ case DW_EH_PE_pcrel:
+ signExtendValue = true;
+ baseAddress = *offset_ptr;
+ if (pc_rel_addr != LLDB_INVALID_ADDRESS)
+ baseAddress += pc_rel_addr;
+// else
+// Log::GlobalWarning ("PC relative pointer encoding found with invalid pc relative address.");
+ break;
+
+ case DW_EH_PE_textrel:
+ signExtendValue = true;
+ if (text_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = text_addr;
+// else
+// Log::GlobalWarning ("text relative pointer encoding being decoded with invalid text section address, setting base address to zero.");
+ break;
+
+ case DW_EH_PE_datarel:
+ signExtendValue = true;
+ if (data_addr != LLDB_INVALID_ADDRESS)
+ baseAddress = data_addr;
+// else
+// Log::GlobalWarning ("data relative pointer encoding being decoded with invalid data section address, setting base address to zero.");
+ break;
+
+ case DW_EH_PE_funcrel:
+ signExtendValue = true;
+ break;
+
+ case DW_EH_PE_aligned:
+ {
+ // SetPointerSize should be called prior to extracting these so the
+ // pointer size is cached
+ assert(addr_size != 0);
+ if (addr_size)
+ {
+ // Align to a address size boundary first
+ uint32_t alignOffset = *offset_ptr % addr_size;
+ if (alignOffset)
+ offset_ptr += addr_size - alignOffset;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Decode the value part
+ switch (eh_ptr_enc & DW_EH_PE_MASK_ENCODING)
+ {
+ case DW_EH_PE_absptr :
+ {
+ addressValue = GetAddress (offset_ptr);
+// if (data_relocs)
+// addressValue = data_relocs->Relocate(*offset_ptr - addr_size, *this, addressValue);
+ }
+ break;
+ case DW_EH_PE_uleb128 : addressValue = GetULEB128(offset_ptr); break;
+ case DW_EH_PE_udata2 : addressValue = GetU16(offset_ptr); break;
+ case DW_EH_PE_udata4 : addressValue = GetU32(offset_ptr); break;
+ case DW_EH_PE_udata8 : addressValue = GetU64(offset_ptr); break;
+ case DW_EH_PE_sleb128 : addressValue = GetSLEB128(offset_ptr); break;
+ case DW_EH_PE_sdata2 : addressValue = (int16_t)GetU16(offset_ptr); break;
+ case DW_EH_PE_sdata4 : addressValue = (int32_t)GetU32(offset_ptr); break;
+ case DW_EH_PE_sdata8 : addressValue = (int64_t)GetU64(offset_ptr); break;
+ default:
+ // Unhandled encoding type
+ assert(eh_ptr_enc);
+ break;
+ }
+
+ // Since we promote everything to 64 bit, we may need to sign extend
+ if (signExtendValue && addr_size < sizeof(baseAddress))
+ {
+ uint64_t sign_bit = 1ull << ((addr_size * 8ull) - 1ull);
+ if (sign_bit & addressValue)
+ {
+ uint64_t mask = ~sign_bit + 1;
+ addressValue |= mask;
+ }
+ }
+ return baseAddress + addressValue;
+}
+
+size_t
+DataExtractor::ExtractBytes (offset_t offset, offset_t length, ByteOrder dst_byte_order, void *dst) const
+{
+ const uint8_t *src = PeekData (offset, length);
+ if (src)
+ {
+ if (dst_byte_order != GetByteOrder())
+ {
+ for (uint32_t i=0; i<length; ++i)
+ ((uint8_t*)dst)[i] = src[length - i - 1];
+ }
+ else
+ ::memcpy (dst, src, length);
+ return length;
+ }
+ return 0;
+}
+
+// Extract data and swap if needed when doing the copy
+lldb::offset_t
+DataExtractor::CopyByteOrderedData (offset_t src_offset,
+ offset_t src_len,
+ void *dst_void_ptr,
+ offset_t dst_len,
+ ByteOrder dst_byte_order) const
+{
+ // Validate the source info
+ if (!ValidOffsetForDataOfSize(src_offset, src_len))
+ assert (ValidOffsetForDataOfSize(src_offset, src_len));
+ assert (src_len > 0);
+ assert (m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle);
+
+ // Validate the destination info
+ assert (dst_void_ptr != NULL);
+ assert (dst_len > 0);
+ assert (dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle);
+
+ // Must have valid byte orders set in this object and for destination
+ if (!(dst_byte_order == eByteOrderBig || dst_byte_order == eByteOrderLittle) ||
+ !(m_byte_order == eByteOrderBig || m_byte_order == eByteOrderLittle))
+ return 0;
+
+ uint32_t i;
+ uint8_t* dst = (uint8_t*)dst_void_ptr;
+ const uint8_t* src = (const uint8_t *)PeekData (src_offset, src_len);
+ if (src)
+ {
+ if (dst_len >= src_len)
+ {
+ // We are copying the entire value from src into dst.
+ // Calculate how many, if any, zeroes we need for the most
+ // significant bytes if "dst_len" is greater than "src_len"...
+ const size_t num_zeroes = dst_len - src_len;
+ if (dst_byte_order == eByteOrderBig)
+ {
+ // Big endian, so we lead with zeroes...
+ if (num_zeroes > 0)
+ ::memset (dst, 0, num_zeroes);
+ // Then either copy or swap the rest
+ if (m_byte_order == eByteOrderBig)
+ {
+ ::memcpy (dst + num_zeroes, src, src_len);
+ }
+ else
+ {
+ for (i=0; i<src_len; ++i)
+ dst[i+num_zeroes] = src[src_len - 1 - i];
+ }
+ }
+ else
+ {
+ // Little endian destination, so we lead the value bytes
+ if (m_byte_order == eByteOrderBig)
+ {
+ for (i=0; i<src_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ }
+ else
+ {
+ ::memcpy (dst, src, src_len);
+ }
+ // And zero the rest...
+ if (num_zeroes > 0)
+ ::memset (dst + src_len, 0, num_zeroes);
+ }
+ return src_len;
+ }
+ else
+ {
+ // We are only copying some of the value from src into dst..
+
+ if (dst_byte_order == eByteOrderBig)
+ {
+ // Big endian dst
+ if (m_byte_order == eByteOrderBig)
+ {
+ // Big endian dst, with big endian src
+ ::memcpy (dst, src + (src_len - dst_len), dst_len);
+ }
+ else
+ {
+ // Big endian dst, with little endian src
+ for (i=0; i<dst_len; ++i)
+ dst[i] = src[dst_len - 1 - i];
+ }
+ }
+ else
+ {
+ // Little endian dst
+ if (m_byte_order == eByteOrderBig)
+ {
+ // Little endian dst, with big endian src
+ for (i=0; i<dst_len; ++i)
+ dst[i] = src[src_len - 1 - i];
+ }
+ else
+ {
+ // Little endian dst, with big endian src
+ ::memcpy (dst, src, dst_len);
+ }
+ }
+ return dst_len;
+ }
+
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Extracts a variable length NULL terminated C string from
+// the data at the offset pointed to by "offset_ptr". The
+// "offset_ptr" will be updated with the offset of the byte that
+// follows the NULL terminator byte.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if
+// "length" is non-zero and there aren't enough avaialable
+// bytes, NULL will be returned and "offset_ptr" will not be
+// updated.
+//----------------------------------------------------------------------
+const char*
+DataExtractor::GetCStr (offset_t *offset_ptr) const
+{
+ const char *cstr = (const char *)PeekData (*offset_ptr, 1);
+ if (cstr)
+ {
+ const char *cstr_end = cstr;
+ const char *end = (const char *)m_end;
+ while (cstr_end < end && *cstr_end)
+ ++cstr_end;
+
+ // Now we are either at the end of the data or we point to the
+ // NULL C string terminator with cstr_end...
+ if (*cstr_end == '\0')
+ {
+ // Advance the offset with one extra byte for the NULL terminator
+ *offset_ptr += (cstr_end - cstr + 1);
+ return cstr;
+ }
+
+ // We reached the end of the data without finding a NULL C string
+ // terminator. Fall through and return NULL otherwise anyone that
+ // would have used the result as a C string can wonder into
+ // unknown memory...
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Extracts a NULL terminated C string from the fixed length field of
+// length "len" at the offset pointed to by "offset_ptr".
+// The "offset_ptr" will be updated with the offset of the byte that
+// follows the fixed length field.
+//
+// If the offset pointed to by "offset_ptr" is out of bounds, or if
+// the offset plus the length of the field is out of bounds, or if the
+// field does not contain a NULL terminator byte, NULL will be returned
+// and "offset_ptr" will not be updated.
+//----------------------------------------------------------------------
+const char*
+DataExtractor::GetCStr (offset_t *offset_ptr, offset_t len) const
+{
+ const char *cstr = (const char *)PeekData (*offset_ptr, len);
+ if (cstr)
+ {
+ if (memchr (cstr, '\0', len) == NULL)
+ {
+ return NULL;
+ }
+ *offset_ptr += len;
+ return cstr;
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// Peeks at a string in the contained data. No verification is done
+// to make sure the entire string lies within the bounds of this
+// object's data, only "offset" is verified to be a valid offset.
+//
+// Returns a valid C string pointer if "offset" is a valid offset in
+// this object's data, else NULL is returned.
+//------------------------------------------------------------------
+const char *
+DataExtractor::PeekCStr (offset_t offset) const
+{
+ return (const char *)PeekData (offset, 1);
+}
+
+//----------------------------------------------------------------------
+// Extracts an unsigned LEB128 number from this object's data
+// starting at the offset pointed to by "offset_ptr". The offset
+// pointed to by "offset_ptr" will be updated with the offset of the
+// byte following the last extracted byte.
+//
+// Returned the extracted integer value.
+//----------------------------------------------------------------------
+uint64_t
+DataExtractor::GetULEB128 (offset_t *offset_ptr) const
+{
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ uint64_t result = *src++;
+ if (result >= 0x80)
+ {
+ result &= 0x7f;
+ int shift = 7;
+ while (src < end)
+ {
+ uint8_t byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ }
+ *offset_ptr = src - m_start;
+ return result;
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Extracts an signed LEB128 number from this object's data
+// starting at the offset pointed to by "offset_ptr". The offset
+// pointed to by "offset_ptr" will be updated with the offset of the
+// byte following the last extracted byte.
+//
+// Returned the extracted integer value.
+//----------------------------------------------------------------------
+int64_t
+DataExtractor::GetSLEB128 (offset_t *offset_ptr) const
+{
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ int64_t result = 0;
+ int shift = 0;
+ int size = sizeof (int64_t) * 8;
+
+ uint8_t byte = 0;
+ int bytecount = 0;
+
+ while (src < end)
+ {
+ bytecount++;
+ byte = *src++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ if ((byte & 0x80) == 0)
+ break;
+ }
+
+ // Sign bit of byte is 2nd high order bit (0x40)
+ if (shift < size && (byte & 0x40))
+ result |= - (1 << shift);
+
+ *offset_ptr += bytecount;
+ return result;
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Skips a ULEB128 number (signed or unsigned) from this object's
+// data starting at the offset pointed to by "offset_ptr". The
+// offset pointed to by "offset_ptr" will be updated with the offset
+// of the byte following the last extracted byte.
+//
+// Returns the number of bytes consumed during the extraction.
+//----------------------------------------------------------------------
+uint32_t
+DataExtractor::Skip_LEB128 (offset_t *offset_ptr) const
+{
+ uint32_t bytes_consumed = 0;
+ const uint8_t *src = (const uint8_t *)PeekData (*offset_ptr, 1);
+ if (src == NULL)
+ return 0;
+
+ const uint8_t *end = m_end;
+
+ if (src < end)
+ {
+ const uint8_t *src_pos = src;
+ while ((src_pos < end) && (*src_pos++ & 0x80))
+ ++bytes_consumed;
+ *offset_ptr += src_pos - src;
+ }
+ return bytes_consumed;
+}
+
+static bool
+GetAPInt (const DataExtractor &data, lldb::offset_t *offset_ptr, lldb::offset_t byte_size, llvm::APInt &result)
+{
+ llvm::SmallVector<uint64_t, 2> uint64_array;
+ lldb::offset_t bytes_left = byte_size;
+ uint64_t u64;
+ const lldb::ByteOrder byte_order = data.GetByteOrder();
+ if (byte_order == lldb::eByteOrderLittle)
+ {
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 8)
+ {
+ u64 = data.GetU64(offset_ptr);
+ bytes_left -= 8;
+ }
+ else
+ {
+ u64 = data.GetMaxU64(offset_ptr, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ }
+ else if (byte_order == lldb::eByteOrderBig)
+ {
+ lldb::offset_t be_offset = *offset_ptr + byte_size;
+ lldb::offset_t temp_offset;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 8)
+ {
+ be_offset -= 8;
+ temp_offset = be_offset;
+ u64 = data.GetU64(&temp_offset);
+ bytes_left -= 8;
+ }
+ else
+ {
+ be_offset -= bytes_left;
+ temp_offset = be_offset;
+ u64 = data.GetMaxU64(&temp_offset, (uint32_t)bytes_left);
+ bytes_left = 0;
+ }
+ uint64_array.push_back(u64);
+ }
+ *offset_ptr += byte_size;
+ result = llvm::APInt(byte_size * 8, llvm::ArrayRef<uint64_t>(uint64_array));
+ return true;
+ }
+ return false;
+}
+
+static lldb::offset_t
+DumpAPInt (Stream *s, const DataExtractor &data, lldb::offset_t offset, lldb::offset_t byte_size, bool is_signed, unsigned radix)
+{
+ llvm::APInt apint;
+ if (GetAPInt (data, &offset, byte_size, apint))
+ {
+ std::string apint_str(apint.toString(radix, is_signed));
+ switch (radix)
+ {
+ case 2:
+ s->Write ("0b", 2);
+ break;
+ case 8:
+ s->Write ("0", 1);
+ break;
+ case 10:
+ break;
+ }
+ s->Write(apint_str.c_str(), apint_str.size());
+ }
+ return offset;
+}
+
+static float half2float (uint16_t half)
+{
+ union{ float f; uint32_t u;}u;
+ int32_t v = (int16_t) half;
+
+ if( 0 == (v & 0x7c00))
+ {
+ u.u = v & 0x80007FFFU;
+ return u.f * 0x1.0p125f;
+ }
+
+ v <<= 13;
+ u.u = v | 0x70000000U;
+ return u.f * 0x1.0p-112f;
+}
+
+lldb::offset_t
+DataExtractor::Dump (Stream *s,
+ offset_t start_offset,
+ lldb::Format item_format,
+ size_t item_byte_size,
+ size_t item_count,
+ size_t num_per_line,
+ uint64_t base_addr,
+ uint32_t item_bit_size, // If zero, this is not a bitfield value, if non-zero, the value is a bitfield
+ uint32_t item_bit_offset, // If "item_bit_size" is non-zero, this is the shift amount to apply to a bitfield
+ ExecutionContextScope *exe_scope) const
+{
+ if (s == NULL)
+ return start_offset;
+
+ if (item_format == eFormatPointer)
+ {
+ if (item_byte_size != 4 && item_byte_size != 8)
+ item_byte_size = s->GetAddressByteSize();
+ }
+
+ offset_t offset = start_offset;
+
+ if (item_format == eFormatInstruction)
+ {
+ TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp)
+ {
+ DisassemblerSP disassembler_sp (Disassembler::FindPlugin(target_sp->GetArchitecture(), NULL, NULL));
+ if (disassembler_sp)
+ {
+ lldb::addr_t addr = base_addr + start_offset;
+ lldb_private::Address so_addr;
+ bool data_from_file = true;
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
+ {
+ data_from_file = false;
+ }
+ else
+ {
+ if (target_sp->GetSectionLoadList().IsEmpty() || !target_sp->GetImages().ResolveFileAddress(addr, so_addr))
+ so_addr.SetRawAddress(addr);
+ }
+
+ size_t bytes_consumed = disassembler_sp->DecodeInstructions (so_addr, *this, start_offset, item_count, false, data_from_file);
+
+ if (bytes_consumed)
+ {
+ offset += bytes_consumed;
+ const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
+ const bool show_bytes = true;
+ ExecutionContext exe_ctx;
+ exe_scope->CalculateExecutionContext(exe_ctx);
+ disassembler_sp->GetInstructionList().Dump (s, show_address, show_bytes, &exe_ctx);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disassembler_sp->GetInstructionList().Clear();
+ }
+ }
+ }
+ else
+ s->Printf ("invalid target");
+
+ return offset;
+ }
+
+ if ((item_format == eFormatOSType || item_format == eFormatAddressInfo) && item_byte_size > 8)
+ item_format = eFormatHex;
+
+ lldb::offset_t line_start_offset = start_offset;
+ for (uint32_t count = 0; ValidOffset(offset) && count < item_count; ++count)
+ {
+ if ((count % num_per_line) == 0)
+ {
+ if (count > 0)
+ {
+ if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
+ {
+ s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ s->EOL();
+ }
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s->Printf ("0x%8.8" PRIx64 ": ", (uint64_t)(base_addr + (offset - start_offset)));
+ line_start_offset = offset;
+ }
+ else
+ if (item_format != eFormatChar &&
+ item_format != eFormatCharPrintable &&
+ item_format != eFormatCharArray &&
+ count > 0)
+ {
+ s->PutChar(' ');
+ }
+
+ uint32_t i;
+ switch (item_format)
+ {
+ case eFormatBoolean:
+ if (item_byte_size <= 8)
+ s->Printf ("%s", GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset) ? "true" : "false");
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for boolean format", item_byte_size);
+ return offset;
+ }
+ break;
+
+ case eFormatBinary:
+ if (item_byte_size <= 8)
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ // Avoid std::bitset<64>::to_string() since it is missing in
+ // earlier C++ libraries
+ std::string binary_value(64, '0');
+ std::bitset<64> bits(uval64);
+ for (i = 0; i < 64; ++i)
+ if (bits[i])
+ binary_value[64 - 1 - i] = '1';
+ if (item_bit_size > 0)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_bit_size);
+ else if (item_byte_size > 0 && item_byte_size <= 8)
+ s->Printf("0b%s", binary_value.c_str() + 64 - item_byte_size * 8);
+ }
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 2;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ for (i=0; i<item_byte_size; ++i)
+ {
+ 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)
+ s->PutChar(' ');
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray:
+ {
+ // If we are only printing one character surround it with single
+ // quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+
+ const uint64_t ch = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ if (isprint(ch))
+ s->Printf ("%c", (char)ch);
+ else if (item_format != eFormatCharPrintable)
+ {
+ switch (ch)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ case '\0': s->Printf ("\\0"); break;
+ default:
+ if (item_byte_size == 1)
+ s->Printf ("\\x%2.2x", (uint8_t)ch);
+ else
+ s->Printf ("%" PRIu64, ch);
+ break;
+ }
+ }
+ else
+ {
+ s->PutChar(NON_PRINTABLE_CHAR);
+ }
+
+ // If we are only printing one character surround it with single quotes
+ if (item_count == 1 && item_format == eFormatChar)
+ s->PutChar('\'');
+ }
+ break;
+
+ case eFormatEnum: // Print enum value as a signed integer when we don't get the enum type
+ case eFormatDecimal:
+ if (item_byte_size <= 8)
+ s->Printf ("%" PRId64, GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = true;
+ const unsigned radix = 10;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatUnsigned:
+ if (item_byte_size <= 8)
+ s->Printf ("%" PRIu64, GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 10;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOctal:
+ if (item_byte_size <= 8)
+ s->Printf ("0%" PRIo64, GetMaxS64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ else
+ {
+ const bool is_signed = false;
+ const unsigned radix = 8;
+ offset = DumpAPInt (s, *this, offset, item_byte_size, is_signed, radix);
+ }
+ break;
+
+ case eFormatOSType:
+ {
+ uint64_t uval64 = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ s->PutChar('\'');
+ for (i=0; i<item_byte_size; ++i)
+ {
+ uint8_t ch = (uint8_t)(uval64 >> ((item_byte_size - i - 1) * 8));
+ if (isprint(ch))
+ s->Printf ("%c", ch);
+ else
+ {
+ switch (ch)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ case '\0': s->Printf ("\\0"); break;
+ default: s->Printf ("\\x%2.2x", ch); break;
+ }
+ }
+ }
+ s->PutChar('\'');
+ }
+ break;
+
+ case eFormatCString:
+ {
+ const char *cstr = GetCStr(&offset);
+
+ if (!cstr)
+ {
+ s->Printf("NULL");
+ offset = LLDB_INVALID_OFFSET;
+ }
+ else
+ {
+ s->PutChar('\"');
+
+ while (const char c = *cstr)
+ {
+ if (isprint(c))
+ {
+ s->PutChar(c);
+ }
+ else
+ {
+ switch (c)
+ {
+ case '\033': s->Printf ("\\e"); break;
+ case '\a': s->Printf ("\\a"); break;
+ case '\b': s->Printf ("\\b"); break;
+ case '\f': s->Printf ("\\f"); break;
+ case '\n': s->Printf ("\\n"); break;
+ case '\r': s->Printf ("\\r"); break;
+ case '\t': s->Printf ("\\t"); break;
+ case '\v': s->Printf ("\\v"); break;
+ default: s->Printf ("\\x%2.2x", c); break;
+ }
+ }
+
+ ++cstr;
+ }
+
+ s->PutChar('\"');
+ }
+ }
+ break;
+
+
+ case eFormatPointer:
+ s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset), sizeof (addr_t));
+ break;
+
+
+ case eFormatComplexInteger:
+ {
+ size_t complex_int_byte_size = item_byte_size / 2;
+
+ if (complex_int_byte_size <= 8)
+ {
+ s->Printf("%" PRIu64, GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ s->Printf(" + %" PRIu64 "i", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0));
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for complex integer format", item_byte_size);
+ return offset;
+ }
+ }
+ break;
+
+ case eFormatComplex:
+ if (sizeof(float) * 2 == item_byte_size)
+ {
+ float f32_1 = GetFloat (&offset);
+ float f32_2 = GetFloat (&offset);
+
+ s->Printf ("%g + %gi", f32_1, f32_2);
+ break;
+ }
+ else if (sizeof(double) * 2 == item_byte_size)
+ {
+ double d64_1 = GetDouble (&offset);
+ double d64_2 = GetDouble (&offset);
+
+ s->Printf ("%lg + %lgi", d64_1, d64_2);
+ break;
+ }
+ else if (sizeof(long double) * 2 == item_byte_size)
+ {
+ long double ld64_1 = GetLongDouble (&offset);
+ long double ld64_2 = GetLongDouble (&offset);
+ s->Printf ("%Lg + %Lgi", ld64_1, ld64_2);
+ break;
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for complex float format", item_byte_size);
+ return offset;
+ }
+ break;
+
+ default:
+ case eFormatDefault:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ {
+ bool wantsuppercase = (item_format == eFormatHexUppercase);
+ if (item_byte_size <= 8)
+ {
+ s->Printf(wantsuppercase ? "0x%*.*" PRIX64 : "0x%*.*" PRIx64, (int)(2 * item_byte_size), (int)(2 * item_byte_size), GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset));
+ }
+ else
+ {
+ assert (item_bit_size == 0 && item_bit_offset == 0);
+ s->PutCString("0x");
+ const uint8_t *bytes = (const uint8_t* )GetData(&offset, item_byte_size);
+ if (bytes)
+ {
+ uint32_t idx;
+ if (m_byte_order == eByteOrderBig)
+ {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[idx]);
+ }
+ else
+ {
+ for (idx = 0; idx < item_byte_size; ++idx)
+ s->Printf(wantsuppercase ? "%2.2X" : "%2.2x", bytes[item_byte_size - 1 - idx]);
+ }
+ }
+ }
+ }
+ break;
+
+ case eFormatFloat:
+ {
+ TargetSP target_sp;
+ bool used_apfloat = false;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+ if (target_sp)
+ {
+ ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
+ if (clang_ast)
+ {
+ clang::ASTContext *ast = clang_ast->getASTContext();
+ if (ast)
+ {
+ llvm::SmallVector<char, 256> sv;
+ // Show full precision when printing float values
+ const unsigned format_precision = 0;
+ const unsigned format_max_padding = 100;
+ size_t item_bit_size = item_byte_size * 8;
+
+ if (item_bit_size == ast->getTypeSize(ast->FloatTy))
+ {
+ llvm::APInt apint(item_bit_size, this->GetMaxU64(&offset, item_byte_size));
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->FloatTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->DoubleTy))
+ {
+ llvm::APInt apint;
+ if (GetAPInt (*this, &offset, item_byte_size, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->DoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->LongDoubleTy))
+ {
+ llvm::APInt apint;
+ switch (target_sp->GetArchitecture().GetCore())
+ {
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ // clang will assert when contructing the apfloat if we use a 16 byte integer value
+ if (GetAPInt (*this, &offset, 10, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ break;
+
+ default:
+ if (GetAPInt (*this, &offset, item_byte_size, apint))
+ {
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->LongDoubleTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+ break;
+ }
+ }
+ else if (item_bit_size == ast->getTypeSize(ast->HalfTy))
+ {
+ llvm::APInt apint(item_bit_size, this->GetU16(&offset));
+ llvm::APFloat apfloat (ast->getFloatTypeSemantics(ast->HalfTy), apint);
+ apfloat.toString(sv, format_precision, format_max_padding);
+ }
+
+ if (!sv.empty())
+ {
+ s->Printf("%*.*s", (int)sv.size(), (int)sv.size(), sv.data());
+ used_apfloat = true;
+ }
+ }
+ }
+ }
+
+ if (!used_apfloat)
+ {
+ std::ostringstream ss;
+ if (item_byte_size == sizeof(float) || item_byte_size == 2)
+ {
+ float f;
+ if (item_byte_size == 2)
+ {
+ uint16_t half = this->GetU16(&offset);
+ f = half2float(half);
+ }
+ else
+ {
+ f = GetFloat (&offset);
+ }
+ ss.precision(std::numeric_limits<float>::digits10);
+ ss << f;
+ }
+ else if (item_byte_size == sizeof(double))
+ {
+ ss.precision(std::numeric_limits<double>::digits10);
+ ss << GetDouble(&offset);
+ }
+ else if (item_byte_size == sizeof(long double) || item_byte_size == 10)
+ {
+ ss.precision(std::numeric_limits<long double>::digits10);
+ ss << GetLongDouble(&offset);
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for float format", item_byte_size);
+ return offset;
+ }
+ ss.flush();
+ s->Printf("%s", ss.str().c_str());
+ }
+ }
+ break;
+
+ case eFormatUnicode16:
+ s->Printf("U+%4.4x", GetU16 (&offset));
+ break;
+
+ case eFormatUnicode32:
+ s->Printf("U+0x%8.8x", GetU32 (&offset));
+ break;
+
+ case eFormatAddressInfo:
+ {
+ addr_t addr = GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset);
+ s->Printf("0x%*.*" PRIx64, (int)(2 * item_byte_size), (int)(2 * item_byte_size), addr);
+ if (exe_scope)
+ {
+ TargetSP target_sp (exe_scope->CalculateTarget());
+ lldb_private::Address so_addr;
+ if (target_sp)
+ {
+ if (target_sp->GetSectionLoadList().ResolveLoadAddress(addr, so_addr))
+ {
+ s->PutChar(' ');
+ so_addr.Dump (s,
+ exe_scope,
+ Address::DumpStyleResolvedDescription,
+ Address::DumpStyleModuleWithFileAddress);
+ }
+ else
+ {
+ so_addr.SetOffset(addr);
+ so_addr.Dump (s, exe_scope, Address::DumpStyleResolvedPointerDescription);
+ }
+ }
+ }
+ }
+ break;
+
+ case eFormatHexFloat:
+ if (sizeof(float) == item_byte_size)
+ {
+ char float_cstr[256];
+ llvm::APFloat ap_float (GetFloat (&offset));
+ ap_float.convertToHexString (float_cstr, 0, false, llvm::APFloat::rmNearestTiesToEven);
+ s->Printf ("%s", float_cstr);
+ break;
+ }
+ else if (sizeof(double) == item_byte_size)
+ {
+ char float_cstr[256];
+ llvm::APFloat ap_float (GetDouble (&offset));
+ ap_float.convertToHexString (float_cstr, 0, false, llvm::APFloat::rmNearestTiesToEven);
+ s->Printf ("%s", float_cstr);
+ break;
+ }
+ else
+ {
+ s->Printf("error: unsupported byte size (%zu) for hex float format", item_byte_size);
+ return offset;
+ }
+ break;
+
+// please keep the single-item formats below in sync with FormatManager::GetSingleItemFormat
+// if you fail to do so, users will start getting different outputs depending on internal
+// implementation details they should not care about ||
+ case eFormatVectorOfChar: // ||
+ s->PutChar('{'); // \/
+ offset = Dump (s, offset, eFormatCharArray, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt8:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt8:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt16:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint16_t), item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt16:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint16_t), item_byte_size / sizeof(uint16_t), item_byte_size / sizeof(uint16_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint32_t), item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint32_t), item_byte_size / sizeof(uint32_t), item_byte_size / sizeof(uint32_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfSInt64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatDecimal, sizeof(uint64_t), item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, sizeof(uint64_t), item_byte_size / sizeof(uint64_t), item_byte_size / sizeof(uint64_t), LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat32:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatFloat, 4, item_byte_size / 4, item_byte_size / 4, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfFloat64:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatFloat, 8, item_byte_size / 8, item_byte_size / 8, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+
+ case eFormatVectorOfUInt128:
+ s->PutChar('{');
+ offset = Dump (s, offset, eFormatHex, 16, item_byte_size / 16, item_byte_size / 16, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('}');
+ break;
+ }
+ }
+
+ if (item_format == eFormatBytesWithASCII && offset > line_start_offset)
+ {
+ s->Printf("%*s", static_cast<int>((num_per_line - (offset - line_start_offset)) * 3 + 2), "");
+ Dump(s, line_start_offset, eFormatCharPrintable, 1, offset - line_start_offset, LLDB_INVALID_OFFSET, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+ return offset; // Return the offset at which we ended up
+}
+
+//----------------------------------------------------------------------
+// Dumps bytes from this object's data to the stream "s" starting
+// "start_offset" bytes into this data, and ending with the byte
+// before "end_offset". "base_addr" will be added to the offset
+// into the dumped data when showing the offset into the data in the
+// output information. "num_per_line" objects of type "type" will
+// be dumped with the option to override the format for each object
+// with "type_format". "type_format" is a printf style formatting
+// string. If "type_format" is NULL, then an appropriate format
+// string will be used for the supplied "type". If the stream "s"
+// is NULL, then the output will be send to Log().
+//----------------------------------------------------------------------
+lldb::offset_t
+DataExtractor::PutToLog
+(
+ Log *log,
+ offset_t start_offset,
+ offset_t length,
+ uint64_t base_addr,
+ uint32_t num_per_line,
+ DataExtractor::Type type,
+ const char *format
+) const
+{
+ if (log == NULL)
+ return start_offset;
+
+ offset_t offset;
+ offset_t end_offset;
+ uint32_t count;
+ StreamString sstr;
+ for (offset = start_offset, end_offset = offset + length, count = 0; ValidOffset(offset) && offset < end_offset; ++count)
+ {
+ if ((count % num_per_line) == 0)
+ {
+ // Print out any previous string
+ if (sstr.GetSize() > 0)
+ {
+ log->Printf("%s", sstr.GetData());
+ sstr.Clear();
+ }
+ // Reset string offset and fill the current line string with address:
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ sstr.Printf("0x%8.8" PRIx64 ":", (uint64_t)(base_addr + (offset - start_offset)));
+ }
+
+ switch (type)
+ {
+ case TypeUInt8: sstr.Printf (format ? format : " %2.2x", GetU8(&offset)); break;
+ case TypeChar:
+ {
+ char ch = GetU8(&offset);
+ sstr.Printf (format ? format : " %c", isprint(ch) ? ch : ' ');
+ }
+ break;
+ case TypeUInt16: sstr.Printf (format ? format : " %4.4x", GetU16(&offset)); break;
+ case TypeUInt32: sstr.Printf (format ? format : " %8.8x", GetU32(&offset)); break;
+ case TypeUInt64: sstr.Printf (format ? format : " %16.16" PRIx64, GetU64(&offset)); break;
+ case TypePointer: sstr.Printf (format ? format : " 0x%" PRIx64, GetAddress(&offset)); break;
+ case TypeULEB128: sstr.Printf (format ? format : " 0x%" PRIx64, GetULEB128(&offset)); break;
+ case TypeSLEB128: sstr.Printf (format ? format : " %" PRId64, GetSLEB128(&offset)); break;
+ }
+ }
+
+ if (sstr.GetSize() > 0)
+ log->Printf("%s", sstr.GetData());
+
+ return offset; // Return the offset at which we ended up
+}
+
+//----------------------------------------------------------------------
+// DumpUUID
+//
+// Dump out a UUID starting at 'offset' bytes into the buffer
+//----------------------------------------------------------------------
+void
+DataExtractor::DumpUUID (Stream *s, offset_t offset) const
+{
+ if (s)
+ {
+ const uint8_t *uuid_data = PeekData(offset, 16);
+ if ( uuid_data )
+ {
+ lldb_private::UUID uuid(uuid_data, 16);
+ uuid.Dump(s);
+ }
+ else
+ {
+ s->Printf("<not enough data for UUID at offset 0x%8.8" PRIx64 ">", offset);
+ }
+ }
+}
+
+void
+DataExtractor::DumpHexBytes (Stream *s,
+ const void *src,
+ size_t src_len,
+ uint32_t bytes_per_line,
+ addr_t base_addr)
+{
+ DataExtractor data (src, src_len, eByteOrderLittle, 4);
+ data.Dump (s,
+ 0, // Offset into "src"
+ eFormatBytes, // Dump as hex bytes
+ 1, // Size of each item is 1 for single bytes
+ src_len, // Number of bytes
+ bytes_per_line, // Num bytes per line
+ base_addr, // Base address
+ 0, 0); // Bitfield info
+}
+
+size_t
+DataExtractor::Copy (DataExtractor &dest_data) const
+{
+ if (m_data_sp.get())
+ {
+ // we can pass along the SP to the data
+ dest_data.SetData(m_data_sp);
+ }
+ else
+ {
+ const uint8_t *base_ptr = m_start;
+ size_t data_size = GetByteSize();
+ dest_data.SetData(DataBufferSP(new DataBufferHeap(base_ptr, data_size)));
+ }
+ return GetByteSize();
+}
+
+bool
+DataExtractor::Append(DataExtractor& rhs)
+{
+ if (rhs.GetByteOrder() != GetByteOrder())
+ return false;
+
+ if (rhs.GetByteSize() == 0)
+ return true;
+
+ if (GetByteSize() == 0)
+ return (rhs.Copy(*this) > 0);
+
+ size_t bytes = GetByteSize() + rhs.GetByteSize();
+
+ DataBufferHeap *buffer_heap_ptr = NULL;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (buffer_sp.get() == NULL || buffer_heap_ptr == NULL)
+ return false;
+
+ uint8_t* bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+ memcpy(bytes_ptr + GetByteSize(), rhs.GetDataStart(), rhs.GetByteSize());
+
+ SetData(buffer_sp);
+
+ return true;
+}
+
+bool
+DataExtractor::Append(void* buf, offset_t length)
+{
+ if (buf == NULL)
+ return false;
+
+ if (length == 0)
+ return true;
+
+ size_t bytes = GetByteSize() + length;
+
+ DataBufferHeap *buffer_heap_ptr = NULL;
+ DataBufferSP buffer_sp(buffer_heap_ptr = new DataBufferHeap(bytes, 0));
+
+ if (buffer_sp.get() == NULL || buffer_heap_ptr == NULL)
+ return false;
+
+ uint8_t* bytes_ptr = buffer_heap_ptr->GetBytes();
+
+ if (GetByteSize() > 0)
+ memcpy(bytes_ptr, GetDataStart(), GetByteSize());
+
+ memcpy(bytes_ptr + GetByteSize(), buf, length);
+
+ SetData(buffer_sp);
+
+ return true;
+}
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
new file mode 100644
index 000000000000..d1d2ebb0550b
--- /dev/null
+++ b/source/Core/Debugger.cpp
@@ -0,0 +1,2695 @@
+//===-- Debugger.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/SBDebugger.h"
+
+#include "lldb/Core/Debugger.h"
+
+#include <map>
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
+#include "lldb/Core/StreamCallback.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Host/DynamicLibrary.h"
+#include "lldb/Host/Terminal.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueSInt64.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Utility/AnsiTerminal.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static uint32_t g_shared_debugger_refcount = 0;
+static lldb::user_id_t g_unique_id = 1;
+
+#pragma mark Static Functions
+
+static Mutex &
+GetDebuggerListMutex ()
+{
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ return g_mutex;
+}
+
+typedef std::vector<DebuggerSP> DebuggerList;
+
+static DebuggerList &
+GetDebuggerList()
+{
+ // hide the static debugger list inside a singleton accessor to avoid
+ // global init contructors
+ static DebuggerList g_list;
+ return g_list;
+}
+
+OptionEnumValueElement
+g_show_disassembly_enum_values[] =
+{
+ { Debugger::eStopDisassemblyTypeNever, "never", "Never show disassembly when displaying a stop context."},
+ { Debugger::eStopDisassemblyTypeNoSource, "no-source", "Show disassembly when there is no source information, or the source file is missing when displaying a stop context."},
+ { Debugger::eStopDisassemblyTypeAlways, "always", "Always show disassembly when displaying a stop context."},
+ { 0, NULL, NULL }
+};
+
+OptionEnumValueElement
+g_language_enumerators[] =
+{
+ { eScriptLanguageNone, "none", "Disable scripting languages."},
+ { eScriptLanguagePython, "python", "Select python as the default scripting language."},
+ { eScriptLanguageDefault, "default", "Select the lldb default as the default scripting language."},
+ { 0, NULL, NULL }
+};
+
+#define MODULE_WITH_FUNC "{ ${module.file.basename}{`${function.name-with-args}${function.pc-offset}}}"
+#define FILE_AND_LINE "{ at ${line.file.basename}:${line.number}}"
+
+#define DEFAULT_THREAD_FORMAT "thread #${thread.index}: tid = ${thread.id%tid}"\
+ "{, ${frame.pc}}"\
+ MODULE_WITH_FUNC\
+ FILE_AND_LINE\
+ "{, name = '${thread.name}'}"\
+ "{, queue = '${thread.queue}'}"\
+ "{, stop reason = ${thread.stop-reason}}"\
+ "{\\nReturn value: ${thread.return-value}}"\
+ "\\n"
+
+#define DEFAULT_FRAME_FORMAT "frame #${frame.index}: ${frame.pc}"\
+ MODULE_WITH_FUNC\
+ FILE_AND_LINE\
+ "\\n"
+
+
+
+static PropertyDefinition
+g_properties[] =
+{
+{ "auto-confirm", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true all confirmation prompts will receive their default reply." },
+{ "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." },
+{ "script-lang", OptionValue::eTypeEnum , true, eScriptLanguagePython, NULL, g_language_enumerators, "The script language to be used for evaluating user-written scripts." },
+{ "stop-disassembly-count", OptionValue::eTypeSInt64 , true, 4 , NULL, NULL, "The number of disassembly lines to show when displaying a stopped context." },
+{ "stop-disassembly-display", OptionValue::eTypeEnum , true, Debugger::eStopDisassemblyTypeNoSource, NULL, g_show_disassembly_enum_values, "Control when to display disassembly when displaying a stopped context." },
+{ "stop-line-count-after", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come after the current source line when displaying a stopped context." },
+{ "stop-line-count-before", OptionValue::eTypeSInt64 , true, 3 , NULL, NULL, "The number of sources lines to display that come before the current source line when displaying a stopped context." },
+{ "term-width", OptionValue::eTypeSInt64 , true, 80 , NULL, NULL, "The maximum number of columns to use for displaying text." },
+{ "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." },
+
+ { NULL, OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
+};
+
+enum
+{
+ ePropertyAutoConfirm = 0,
+ ePropertyFrameFormat,
+ ePropertyNotiftVoid,
+ ePropertyPrompt,
+ ePropertyScriptLanguage,
+ ePropertyStopDisassemblyCount,
+ ePropertyStopDisassemblyDisplay,
+ ePropertyStopLineCountAfter,
+ ePropertyStopLineCountBefore,
+ ePropertyTerminalWidth,
+ ePropertyThreadFormat,
+ ePropertyUseExternalEditor,
+ ePropertyUseColor,
+};
+
+//
+//const char *
+//Debugger::GetFrameFormat() const
+//{
+// return m_properties_sp->GetFrameFormat();
+//}
+//const char *
+//Debugger::GetThreadFormat() const
+//{
+// return m_properties_sp->GetThreadFormat();
+//}
+//
+
+
+Error
+Debugger::SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *property_path,
+ const char *value)
+{
+ bool is_load_script = strcmp(property_path,"target.load-script-from-symbol-file") == 0;
+ TargetSP target_sp;
+ LoadScriptFromSymFile load_script_old_value;
+ if (is_load_script && exe_ctx->GetTargetSP())
+ {
+ target_sp = exe_ctx->GetTargetSP();
+ load_script_old_value = target_sp->TargetProperties::GetLoadScriptFromSymbolFile();
+ }
+ Error error (Properties::SetPropertyValue (exe_ctx, op, property_path, value));
+ if (error.Success())
+ {
+ // FIXME it would be nice to have "on-change" callbacks for properties
+ if (strcmp(property_path, g_properties[ePropertyPrompt].name) == 0)
+ {
+ const char *new_prompt = GetPrompt();
+ std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor());
+ if (str.length())
+ new_prompt = str.c_str();
+ EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));
+ GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp);
+ }
+ else if (strcmp(property_path, g_properties[ePropertyUseColor].name) == 0)
+ {
+ // use-color changed. Ping the prompt so it can reset the ansi terminal codes.
+ SetPrompt (GetPrompt());
+ }
+ else if (is_load_script && target_sp && load_script_old_value == eLoadScriptFromSymFileWarn)
+ {
+ if (target_sp->TargetProperties::GetLoadScriptFromSymbolFile() == eLoadScriptFromSymFileTrue)
+ {
+ std::list<Error> errors;
+ StreamString feedback_stream;
+ if (!target_sp->LoadScriptingResources(errors,&feedback_stream))
+ {
+ for (auto error : errors)
+ {
+ GetErrorStream().Printf("%s\n",error.AsCString());
+ }
+ if (feedback_stream.GetSize())
+ GetErrorStream().Printf("%s",feedback_stream.GetData());
+ }
+ }
+ }
+ }
+ return error;
+}
+
+bool
+Debugger::GetAutoConfirm () const
+{
+ const uint32_t idx = ePropertyAutoConfirm;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+const char *
+Debugger::GetFrameFormat() const
+{
+ const uint32_t idx = ePropertyFrameFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+bool
+Debugger::GetNotifyVoid () const
+{
+ const uint32_t idx = ePropertyNotiftVoid;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+const char *
+Debugger::GetPrompt() const
+{
+ const uint32_t idx = ePropertyPrompt;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+void
+Debugger::SetPrompt(const char *p)
+{
+ const uint32_t idx = ePropertyPrompt;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p);
+ const char *new_prompt = GetPrompt();
+ std::string str = lldb_utility::ansi::FormatAnsiTerminalCodes (new_prompt, GetUseColor());
+ if (str.length())
+ new_prompt = str.c_str();
+ EventSP prompt_change_event_sp (new Event(CommandInterpreter::eBroadcastBitResetPrompt, new EventDataBytes (new_prompt)));;
+ GetCommandInterpreter().BroadcastEvent (prompt_change_event_sp);
+}
+
+const char *
+Debugger::GetThreadFormat() const
+{
+ const uint32_t idx = ePropertyThreadFormat;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, g_properties[idx].default_cstr_value);
+}
+
+lldb::ScriptLanguage
+Debugger::GetScriptLanguage() const
+{
+ const uint32_t idx = ePropertyScriptLanguage;
+ return (lldb::ScriptLanguage)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+Debugger::SetScriptLanguage (lldb::ScriptLanguage script_lang)
+{
+ const uint32_t idx = ePropertyScriptLanguage;
+ return m_collection_sp->SetPropertyAtIndexAsEnumeration (NULL, idx, script_lang);
+}
+
+uint32_t
+Debugger::GetTerminalWidth () const
+{
+ const uint32_t idx = ePropertyTerminalWidth;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+Debugger::SetTerminalWidth (uint32_t term_width)
+{
+ const uint32_t idx = ePropertyTerminalWidth;
+ return m_collection_sp->SetPropertyAtIndexAsSInt64 (NULL, idx, term_width);
+}
+
+bool
+Debugger::GetUseExternalEditor () const
+{
+ const uint32_t idx = ePropertyUseExternalEditor;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+Debugger::SetUseExternalEditor (bool b)
+{
+ const uint32_t idx = ePropertyUseExternalEditor;
+ return m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
+Debugger::GetUseColor () const
+{
+ const uint32_t idx = ePropertyUseColor;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+Debugger::SetUseColor (bool b)
+{
+ const uint32_t idx = ePropertyUseColor;
+ bool ret = m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+ SetPrompt (GetPrompt());
+ return ret;
+}
+
+uint32_t
+Debugger::GetStopSourceLineCount (bool before) const
+{
+ const uint32_t idx = before ? ePropertyStopLineCountBefore : ePropertyStopLineCountAfter;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+Debugger::StopDisassemblyType
+Debugger::GetStopDisassemblyDisplay () const
+{
+ const uint32_t idx = ePropertyStopDisassemblyDisplay;
+ return (Debugger::StopDisassemblyType)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+uint32_t
+Debugger::GetDisassemblyLineCount () const
+{
+ const uint32_t idx = ePropertyStopDisassemblyCount;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+#pragma mark Debugger
+
+//const DebuggerPropertiesSP &
+//Debugger::GetSettings() const
+//{
+// return m_properties_sp;
+//}
+//
+
+int
+Debugger::TestDebuggerRefCount ()
+{
+ return g_shared_debugger_refcount;
+}
+
+void
+Debugger::Initialize ()
+{
+ if (g_shared_debugger_refcount++ == 0)
+ lldb_private::Initialize();
+}
+
+void
+Debugger::Terminate ()
+{
+ if (g_shared_debugger_refcount > 0)
+ {
+ g_shared_debugger_refcount--;
+ if (g_shared_debugger_refcount == 0)
+ {
+ lldb_private::WillTerminate();
+ lldb_private::Terminate();
+
+ // Clear our master list of debugger objects
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().clear();
+ }
+ }
+}
+
+void
+Debugger::SettingsInitialize ()
+{
+ Target::SettingsInitialize ();
+}
+
+void
+Debugger::SettingsTerminate ()
+{
+ Target::SettingsTerminate ();
+}
+
+bool
+Debugger::LoadPlugin (const FileSpec& spec, Error& error)
+{
+ lldb::DynamicLibrarySP dynlib_sp(new lldb_private::DynamicLibrary(spec));
+ if (!dynlib_sp || dynlib_sp->IsValid() == false)
+ {
+ if (spec.Exists())
+ error.SetErrorString("this file does not represent a loadable dylib");
+ else
+ error.SetErrorString("no such file");
+ return false;
+ }
+ lldb::DebuggerSP debugger_sp(shared_from_this());
+ lldb::SBDebugger debugger_sb(debugger_sp);
+ // This calls the bool lldb::PluginInitialize(lldb::SBDebugger debugger) function.
+ // TODO: mangle this differently for your system - on OSX, the first underscore needs to be removed and the second one stays
+ LLDBCommandPluginInit init_func = dynlib_sp->GetSymbol<LLDBCommandPluginInit>("_ZN4lldb16PluginInitializeENS_10SBDebuggerE");
+ if (!init_func)
+ {
+ error.SetErrorString("cannot find the initialization function lldb::PluginInitialize(lldb::SBDebugger)");
+ return false;
+ }
+ if (init_func(debugger_sb))
+ {
+ m_loaded_plugins.push_back(dynlib_sp);
+ return true;
+ }
+ error.SetErrorString("dylib refused to be loaded");
+ return false;
+}
+
+static FileSpec::EnumerateDirectoryResult
+LoadPluginCallback
+(
+ void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec
+ )
+{
+ Error error;
+
+ static ConstString g_dylibext("dylib");
+ static ConstString g_solibext("so");
+
+ if (!baton)
+ return FileSpec::eEnumerateDirectoryResultQuit;
+
+ Debugger *debugger = (Debugger*)baton;
+
+ // If we have a regular file, a symbolic link or unknown file type, try
+ // and process the file. We must handle unknown as sometimes the directory
+ // enumeration might be enumerating a file system that doesn't have correct
+ // file type information.
+ if (file_type == FileSpec::eFileTypeRegular ||
+ file_type == FileSpec::eFileTypeSymbolicLink ||
+ file_type == FileSpec::eFileTypeUnknown )
+ {
+ FileSpec plugin_file_spec (file_spec);
+ plugin_file_spec.ResolvePath ();
+
+ if (plugin_file_spec.GetFileNameExtension() != g_dylibext &&
+ plugin_file_spec.GetFileNameExtension() != g_solibext)
+ {
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+
+ Error plugin_load_error;
+ debugger->LoadPlugin (plugin_file_spec, plugin_load_error);
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+
+ else if (file_type == FileSpec::eFileTypeUnknown ||
+ file_type == FileSpec::eFileTypeDirectory ||
+ file_type == FileSpec::eFileTypeSymbolicLink )
+ {
+ // Try and recurse into anything that a directory or symbolic link.
+ // We must also do this for unknown as sometimes the directory enumeration
+ // might be enurating a file system that doesn't have correct file type
+ // information.
+ return FileSpec::eEnumerateDirectoryResultEnter;
+ }
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+void
+Debugger::InstanceInitialize ()
+{
+ FileSpec dir_spec;
+ const bool find_directories = true;
+ const bool find_files = true;
+ const bool find_other = true;
+ char dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ this);
+ }
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ this);
+ }
+ }
+
+ PluginManager::DebuggerInitialize (*this);
+}
+
+DebuggerSP
+Debugger::CreateInstance (lldb::LogOutputCallback log_callback, void *baton)
+{
+ DebuggerSP debugger_sp (new Debugger(log_callback, baton));
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ GetDebuggerList().push_back(debugger_sp);
+ }
+ debugger_sp->InstanceInitialize ();
+ return debugger_sp;
+}
+
+void
+Debugger::Destroy (DebuggerSP &debugger_sp)
+{
+ if (debugger_sp.get() == NULL)
+ return;
+
+ debugger_sp->Clear();
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList ();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin (); pos != end; ++pos)
+ {
+ if ((*pos).get() == debugger_sp.get())
+ {
+ debugger_list.erase (pos);
+ return;
+ }
+ }
+ }
+}
+
+DebuggerSP
+Debugger::FindDebuggerWithInstanceName (const ConstString &instance_name)
+{
+ DebuggerSP debugger_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get()->m_instance_name == instance_name)
+ {
+ debugger_sp = *pos;
+ break;
+ }
+ }
+ }
+ return debugger_sp;
+}
+
+TargetSP
+Debugger::FindTargetWithProcessID (lldb::pid_t pid)
+{
+ TargetSP target_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ target_sp = (*pos)->GetTargetList().FindTargetWithProcessID (pid);
+ if (target_sp)
+ break;
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+Debugger::FindTargetWithProcess (Process *process)
+{
+ TargetSP target_sp;
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ target_sp = (*pos)->GetTargetList().FindTargetWithProcess (process);
+ if (target_sp)
+ break;
+ }
+ }
+ return target_sp;
+}
+
+Debugger::Debugger (lldb::LogOutputCallback log_callback, void *baton) :
+ UserID (g_unique_id++),
+ Properties(OptionValuePropertiesSP(new OptionValueProperties())),
+ m_input_comm("debugger.input"),
+ m_input_file (),
+ m_output_file (),
+ m_error_file (),
+ 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_input_reader_data (),
+ m_instance_name()
+{
+ char instance_cstr[256];
+ snprintf(instance_cstr, sizeof(instance_cstr), "debugger_%d", (int)GetID());
+ m_instance_name.SetCString(instance_cstr);
+ if (log_callback)
+ 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());
+ assert (default_platform_sp.get());
+ m_platform_list.Append (default_platform_sp, true);
+
+ m_collection_sp->Initialize (g_properties);
+ m_collection_sp->AppendProperty (ConstString("target"),
+ ConstString("Settings specify to debugging targets."),
+ true,
+ Target::GetGlobalProperties()->GetValueProperties());
+ if (m_command_interpreter_ap.get())
+ {
+ m_collection_sp->AppendProperty (ConstString("interpreter"),
+ ConstString("Settings specify to the debugger's command interpreter."),
+ true,
+ m_command_interpreter_ap->GetValueProperties());
+ }
+ OptionValueSInt64 *term_width = m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64 (NULL, ePropertyTerminalWidth);
+ term_width->SetMinimumValue(10);
+ term_width->SetMaximumValue(1024);
+
+ // Turn off use-color if this is a dumb terminal.
+ const char *term = getenv ("TERM");
+ if (term && !strcmp (term, "dumb"))
+ SetUseColor (false);
+}
+
+Debugger::~Debugger ()
+{
+ Clear();
+}
+
+void
+Debugger::Clear()
+{
+ CleanUpInputReaders();
+ m_listener.Clear();
+ int num_targets = m_target_list.GetNumTargets();
+ for (int i = 0; i < num_targets; i++)
+ {
+ TargetSP target_sp (m_target_list.GetTargetAtIndex (i));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ process_sp->Finalize();
+ target_sp->Destroy();
+ }
+ }
+ BroadcasterManager::Clear ();
+
+ // Close the input file _before_ we close the input read communications class
+ // as it does NOT own the input file, our m_input_file does.
+ m_terminal_state.Clear();
+ GetInputFile().Close ();
+ // Now that we have closed m_input_file, we can now tell our input communication
+ // class to close down. Its read thread should quickly exit after we close
+ // the input file handle above.
+ m_input_comm.Clear ();
+}
+
+bool
+Debugger::GetCloseInputOnEOF () const
+{
+ return m_input_comm.GetCloseOnEOF();
+}
+
+void
+Debugger::SetCloseInputOnEOF (bool b)
+{
+ m_input_comm.SetCloseOnEOF(b);
+}
+
+bool
+Debugger::GetAsyncExecution ()
+{
+ return !m_command_interpreter_ap->GetSynchronous();
+}
+
+void
+Debugger::SetAsyncExecution (bool async_execution)
+{
+ m_command_interpreter_ap->SetSynchronous (!async_execution);
+}
+
+
+void
+Debugger::SetInputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &in_file = GetInputFile();
+ in_file.SetStream (fh, tranfer_ownership);
+ if (in_file.IsValid() == false)
+ in_file.SetStream (stdin, true);
+
+ // Disconnect from any old connection if we had one
+ m_input_comm.Disconnect ();
+ // Pass false as the second argument to ConnectionFileDescriptor below because
+ // our "in_file" above will already take ownership if requested and we don't
+ // want to objects trying to own and close a file descriptor.
+ m_input_comm.SetConnection (new ConnectionFileDescriptor (in_file.GetDescriptor(), false));
+ m_input_comm.SetReadThreadBytesReceivedCallback (Debugger::DispatchInputCallback, this);
+
+ // Save away the terminal state if that is relevant, so that we can restore it in RestoreInputState.
+ SaveInputTerminalState ();
+
+ Error error;
+ if (m_input_comm.StartReadThread (&error) == false)
+ {
+ File &err_file = GetErrorFile();
+
+ err_file.Printf ("error: failed to main input read thread: %s", error.AsCString() ? error.AsCString() : "unkown error");
+ exit(1);
+ }
+}
+
+void
+Debugger::SetOutputFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &out_file = GetOutputFile();
+ out_file.SetStream (fh, tranfer_ownership);
+ if (out_file.IsValid() == false)
+ out_file.SetStream (stdout, false);
+
+ // do not create the ScriptInterpreter just for setting the output file handle
+ // as the constructor will know how to do the right thing on its own
+ const bool can_create = false;
+ ScriptInterpreter* script_interpreter = GetCommandInterpreter().GetScriptInterpreter(can_create);
+ if (script_interpreter)
+ script_interpreter->ResetOutputFileHandle (fh);
+}
+
+void
+Debugger::SetErrorFileHandle (FILE *fh, bool tranfer_ownership)
+{
+ File &err_file = GetErrorFile();
+ err_file.SetStream (fh, tranfer_ownership);
+ if (err_file.IsValid() == false)
+ err_file.SetStream (stderr, false);
+}
+
+void
+Debugger::SaveInputTerminalState ()
+{
+ File &in_file = GetInputFile();
+ if (in_file.GetDescriptor() != File::kInvalidDescriptor)
+ m_terminal_state.Save(in_file.GetDescriptor(), true);
+}
+
+void
+Debugger::RestoreInputTerminalState ()
+{
+ m_terminal_state.Restore();
+}
+
+ExecutionContext
+Debugger::GetSelectedExecutionContext ()
+{
+ ExecutionContext exe_ctx;
+ TargetSP target_sp(GetSelectedTarget());
+ exe_ctx.SetTargetSP (target_sp);
+
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ exe_ctx.SetProcessSP (process_sp);
+ if (process_sp && process_sp->IsRunning() == false)
+ {
+ ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread());
+ if (thread_sp)
+ {
+ exe_ctx.SetThreadSP (thread_sp);
+ exe_ctx.SetFrameSP (thread_sp->GetSelectedFrame());
+ if (exe_ctx.GetFramePtr() == NULL)
+ exe_ctx.SetFrameSP (thread_sp->GetStackFrameAtIndex (0));
+ }
+ }
+ }
+ return exe_ctx;
+
+}
+
+InputReaderSP
+Debugger::GetCurrentInputReader ()
+{
+ InputReaderSP reader_sp;
+
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Clear any finished readers from the stack
+ while (CheckIfTopInputReaderIsDone()) ;
+
+ if (!m_input_reader_stack.IsEmpty())
+ reader_sp = m_input_reader_stack.Top();
+ }
+
+ return reader_sp;
+}
+
+void
+Debugger::DispatchInputCallback (void *baton, const void *bytes, size_t bytes_len)
+{
+ if (bytes_len > 0)
+ ((Debugger *)baton)->DispatchInput ((char *)bytes, bytes_len);
+ else
+ ((Debugger *)baton)->DispatchInputEndOfFile ();
+}
+
+
+void
+Debugger::DispatchInput (const char *bytes, size_t bytes_len)
+{
+ if (bytes == NULL || bytes_len == 0)
+ return;
+
+ WriteToDefaultReader (bytes, bytes_len);
+}
+
+void
+Debugger::DispatchInputInterrupt ()
+{
+ m_input_reader_data.clear();
+
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderInterrupt);
+
+ // If notifying the reader of the interrupt finished the reader, we should pop it off the stack.
+ while (CheckIfTopInputReaderIsDone ()) ;
+ }
+}
+
+void
+Debugger::DispatchInputEndOfFile ()
+{
+ m_input_reader_data.clear();
+
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderEndOfFile);
+
+ // If notifying the reader of the end-of-file finished the reader, we should pop it off the stack.
+ while (CheckIfTopInputReaderIsDone ()) ;
+ }
+}
+
+void
+Debugger::CleanUpInputReaders ()
+{
+ m_input_reader_data.clear();
+
+ // The bottom input reader should be the main debugger input reader. We do not want to close that one here.
+ while (m_input_reader_stack.GetSize() > 1)
+ {
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (reader_sp)
+ {
+ reader_sp->Notify (eInputReaderEndOfFile);
+ reader_sp->SetIsDone (true);
+ }
+ }
+}
+
+void
+Debugger::NotifyTopInputReader (InputReaderAction notification)
+{
+ InputReaderSP reader_sp (GetCurrentInputReader());
+ if (reader_sp)
+ {
+ reader_sp->Notify (notification);
+
+ // Flush out any input readers that are done.
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+ }
+}
+
+bool
+Debugger::InputReaderIsTopReader (const InputReaderSP& reader_sp)
+{
+ InputReaderSP top_reader_sp (GetCurrentInputReader());
+
+ return (reader_sp.get() == top_reader_sp.get());
+}
+
+
+void
+Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len)
+{
+ if (bytes && bytes_len)
+ m_input_reader_data.append (bytes, bytes_len);
+
+ if (m_input_reader_data.empty())
+ return;
+
+ while (!m_input_reader_stack.IsEmpty() && !m_input_reader_data.empty())
+ {
+ // Get the input reader from the top of the stack
+ InputReaderSP reader_sp (GetCurrentInputReader ());
+ if (!reader_sp)
+ break;
+
+ size_t bytes_handled = reader_sp->HandleRawBytes (m_input_reader_data.c_str(),
+ m_input_reader_data.size());
+ if (bytes_handled)
+ {
+ m_input_reader_data.erase (0, bytes_handled);
+ }
+ else
+ {
+ // No bytes were handled, we might not have reached our
+ // granularity, just return and wait for more data
+ break;
+ }
+ }
+
+ // Flush out any input readers that are done.
+ while (CheckIfTopInputReaderIsDone ())
+ /* Do nothing. */;
+
+}
+
+void
+Debugger::PushInputReader (const InputReaderSP& reader_sp)
+{
+ if (!reader_sp)
+ return;
+
+ // Deactivate the old top reader
+ InputReaderSP top_reader_sp (GetCurrentInputReader ());
+
+ if (top_reader_sp)
+ top_reader_sp->Notify (eInputReaderDeactivate);
+
+ m_input_reader_stack.Push (reader_sp);
+ reader_sp->Notify (eInputReaderActivate);
+ ActivateInputReader (reader_sp);
+}
+
+bool
+Debugger::PopInputReader (const InputReaderSP& pop_reader_sp)
+{
+ bool result = false;
+
+ // The reader on the stop of the stack is done, so let the next
+ // read on the stack referesh its prompt and if there is one...
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Cannot call GetCurrentInputReader here, as that would cause an infinite loop.
+ InputReaderSP reader_sp(m_input_reader_stack.Top());
+
+ if (!pop_reader_sp || pop_reader_sp.get() == reader_sp.get())
+ {
+ m_input_reader_stack.Pop ();
+ reader_sp->Notify (eInputReaderDeactivate);
+ reader_sp->Notify (eInputReaderDone);
+ result = true;
+
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ reader_sp = m_input_reader_stack.Top();
+ if (reader_sp)
+ {
+ ActivateInputReader (reader_sp);
+ reader_sp->Notify (eInputReaderReactivate);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+bool
+Debugger::CheckIfTopInputReaderIsDone ()
+{
+ bool result = false;
+ if (!m_input_reader_stack.IsEmpty())
+ {
+ // Cannot call GetCurrentInputReader here, as that would cause an infinite loop.
+ InputReaderSP reader_sp(m_input_reader_stack.Top());
+
+ if (reader_sp && reader_sp->IsDone())
+ {
+ result = true;
+ PopInputReader (reader_sp);
+ }
+ }
+ return result;
+}
+
+void
+Debugger::ActivateInputReader (const InputReaderSP &reader_sp)
+{
+ int input_fd = m_input_file.GetFile().GetDescriptor();
+
+ if (input_fd >= 0)
+ {
+ Terminal tty(input_fd);
+
+ tty.SetEcho(reader_sp->GetEcho());
+
+ switch (reader_sp->GetGranularity())
+ {
+ case eInputReaderGranularityByte:
+ case eInputReaderGranularityWord:
+ tty.SetCanonical (false);
+ break;
+
+ case eInputReaderGranularityLine:
+ case eInputReaderGranularityAll:
+ tty.SetCanonical (true);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+StreamSP
+Debugger::GetAsyncOutputStream ()
+{
+ return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousOutputData));
+}
+
+StreamSP
+Debugger::GetAsyncErrorStream ()
+{
+ return StreamSP (new StreamAsynchronousIO (GetCommandInterpreter(),
+ CommandInterpreter::eBroadcastBitAsynchronousErrorData));
+}
+
+size_t
+Debugger::GetNumDebuggers()
+{
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ return GetDebuggerList().size();
+ }
+ return 0;
+}
+
+lldb::DebuggerSP
+Debugger::GetDebuggerAtIndex (size_t index)
+{
+ DebuggerSP debugger_sp;
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+
+ if (index < debugger_list.size())
+ debugger_sp = debugger_list[index];
+ }
+
+ return debugger_sp;
+}
+
+DebuggerSP
+Debugger::FindDebuggerWithID (lldb::user_id_t id)
+{
+ DebuggerSP debugger_sp;
+
+ if (g_shared_debugger_refcount > 0)
+ {
+ Mutex::Locker locker (GetDebuggerListMutex ());
+ DebuggerList &debugger_list = GetDebuggerList();
+ DebuggerList::iterator pos, end = debugger_list.end();
+ for (pos = debugger_list.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get()->GetID() == id)
+ {
+ debugger_sp = *pos;
+ break;
+ }
+ }
+ }
+ return debugger_sp;
+}
+
+static void
+TestPromptFormats (StackFrame *frame)
+{
+ if (frame == NULL)
+ return;
+
+ StreamString s;
+ const char *prompt_format =
+ "{addr = '${addr}'\n}"
+ "{process.id = '${process.id}'\n}"
+ "{process.name = '${process.name}'\n}"
+ "{process.file.basename = '${process.file.basename}'\n}"
+ "{process.file.fullpath = '${process.file.fullpath}'\n}"
+ "{thread.id = '${thread.id}'\n}"
+ "{thread.index = '${thread.index}'\n}"
+ "{thread.name = '${thread.name}'\n}"
+ "{thread.queue = '${thread.queue}'\n}"
+ "{thread.stop-reason = '${thread.stop-reason}'\n}"
+ "{target.arch = '${target.arch}'\n}"
+ "{module.file.basename = '${module.file.basename}'\n}"
+ "{module.file.fullpath = '${module.file.fullpath}'\n}"
+ "{file.basename = '${file.basename}'\n}"
+ "{file.fullpath = '${file.fullpath}'\n}"
+ "{frame.index = '${frame.index}'\n}"
+ "{frame.pc = '${frame.pc}'\n}"
+ "{frame.sp = '${frame.sp}'\n}"
+ "{frame.fp = '${frame.fp}'\n}"
+ "{frame.flags = '${frame.flags}'\n}"
+ "{frame.reg.rdi = '${frame.reg.rdi}'\n}"
+ "{frame.reg.rip = '${frame.reg.rip}'\n}"
+ "{frame.reg.rsp = '${frame.reg.rsp}'\n}"
+ "{frame.reg.rbp = '${frame.reg.rbp}'\n}"
+ "{frame.reg.rflags = '${frame.reg.rflags}'\n}"
+ "{frame.reg.xmm0 = '${frame.reg.xmm0}'\n}"
+ "{frame.reg.carp = '${frame.reg.carp}'\n}"
+ "{function.id = '${function.id}'\n}"
+ "{function.name = '${function.name}'\n}"
+ "{function.name-with-args = '${function.name-with-args}'\n}"
+ "{function.addr-offset = '${function.addr-offset}'\n}"
+ "{function.line-offset = '${function.line-offset}'\n}"
+ "{function.pc-offset = '${function.pc-offset}'\n}"
+ "{line.file.basename = '${line.file.basename}'\n}"
+ "{line.file.fullpath = '${line.file.fullpath}'\n}"
+ "{line.number = '${line.number}'\n}"
+ "{line.start-addr = '${line.start-addr}'\n}"
+ "{line.end-addr = '${line.end-addr}'\n}"
+;
+
+ SymbolContext sc (frame->GetSymbolContext(eSymbolContextEverything));
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext(exe_ctx);
+ if (Debugger::FormatPrompt (prompt_format, &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s))
+ {
+ printf("%s\n", s.GetData());
+ }
+ else
+ {
+ printf ("what we got: %s\n", s.GetData());
+ }
+}
+
+static bool
+ScanFormatDescriptor (const char* var_name_begin,
+ const char* var_name_end,
+ const char** var_name_final,
+ const char** percent_position,
+ Format* custom_format,
+ ValueObject::ValueObjectRepresentationStyle* val_obj_display)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ *percent_position = ::strchr(var_name_begin,'%');
+ if (!*percent_position || *percent_position > var_name_end)
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] no format descriptor in string, skipping");
+ *var_name_final = var_name_end;
+ }
+ else
+ {
+ *var_name_final = *percent_position;
+ std::string format_name(*var_name_final+1, var_name_end-*var_name_final-1);
+ if (log)
+ log->Printf("[ScanFormatDescriptor] parsing %s as a format descriptor", format_name.c_str());
+ if ( !FormatManager::GetFormatFromCString(format_name.c_str(),
+ true,
+ *custom_format) )
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] %s is an unknown format", format_name.c_str());
+
+ switch (format_name.front())
+ {
+ case '@': // if this is an @ sign, print ObjC description
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleLanguageSpecific;
+ break;
+ case 'V': // if this is a V, print the value using the default format
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ break;
+ case 'L': // if this is an L, print the location of the value
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleLocation;
+ break;
+ case 'S': // if this is an S, print the summary after all
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary;
+ break;
+ case '#': // if this is a '#', print the number of children
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleChildrenCount;
+ break;
+ case 'T': // if this is a 'T', print the type
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleType;
+ break;
+ case 'N': // if this is a 'N', print the name
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleName;
+ break;
+ case '>': // if this is a '>', print the name
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleExpressionPath;
+ break;
+ default:
+ if (log)
+ log->Printf("ScanFormatDescriptor] %s is an error, leaving the previous value alone", format_name.c_str());
+ break;
+ }
+ }
+ // a good custom format tells us to print the value using it
+ else
+ {
+ if (log)
+ log->Printf("[ScanFormatDescriptor] will display value for this VO");
+ *val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+ }
+ if (log)
+ log->Printf("[ScanFormatDescriptor] final format description outcome: custom_format = %d, val_obj_display = %d",
+ *custom_format,
+ *val_obj_display);
+ return true;
+}
+
+static bool
+ScanBracketedRange (const char* var_name_begin,
+ const char* var_name_end,
+ const char* var_name_final,
+ const char** open_bracket_position,
+ const char** separator_position,
+ const char** close_bracket_position,
+ const char** var_name_final_if_array_range,
+ int64_t* index_lower,
+ int64_t* index_higher)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ *open_bracket_position = ::strchr(var_name_begin,'[');
+ if (*open_bracket_position && *open_bracket_position < var_name_final)
+ {
+ *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
+ *close_bracket_position = ::strchr(*open_bracket_position,']');
+ // as usual, we assume that [] will come before %
+ //printf("trying to expand a []\n");
+ *var_name_final_if_array_range = *open_bracket_position;
+ if (*close_bracket_position - *open_bracket_position == 1)
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] '[]' detected.. going from 0 to end of data");
+ *index_lower = 0;
+ }
+ else if (*separator_position == NULL || *separator_position > var_name_end)
+ {
+ char *end = NULL;
+ *index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
+ *index_higher = *index_lower;
+ if (log)
+ log->Printf("[ScanBracketedRange] [%" PRId64 "] detected, high index is same", *index_lower);
+ }
+ else if (*close_bracket_position && *close_bracket_position < var_name_end)
+ {
+ char *end = NULL;
+ *index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
+ *index_higher = ::strtoul (*separator_position+1, &end, 0);
+ if (log)
+ log->Printf("[ScanBracketedRange] [%" PRId64 "-%" PRId64 "] detected", *index_lower, *index_higher);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] expression is erroneous, cannot extract indices out of it");
+ return false;
+ }
+ if (*index_lower > *index_higher && *index_higher > 0)
+ {
+ if (log)
+ log->Printf("[ScanBracketedRange] swapping indices");
+ int64_t temp = *index_lower;
+ *index_lower = *index_higher;
+ *index_higher = temp;
+ }
+ }
+ else if (log)
+ log->Printf("[ScanBracketedRange] no bracketed range, skipping entirely");
+ return true;
+}
+
+template <typename T>
+static bool RunScriptFormatKeyword(Stream &s, ScriptInterpreter *script_interpreter, T t, const std::string& script_name)
+{
+ if (script_interpreter)
+ {
+ Error script_error;
+ std::string script_output;
+
+ if (script_interpreter->RunScriptFormatKeyword(script_name.c_str(), t, script_output, script_error) && script_error.Success())
+ {
+ s.Printf("%s", script_output.c_str());
+ return true;
+ }
+ else
+ {
+ s.Printf("<error: %s>",script_error.AsCString());
+ }
+ }
+ return false;
+}
+
+static ValueObjectSP
+ExpandIndexedExpression (ValueObject* valobj,
+ size_t index,
+ StackFrame* frame,
+ bool deref_pointer)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ const char* ptr_deref_format = "[%d]";
+ std::string ptr_deref_buffer(10,0);
+ ::sprintf(&ptr_deref_buffer[0], ptr_deref_format, index);
+ if (log)
+ log->Printf("[ExpandIndexedExpression] name to deref: %s",ptr_deref_buffer.c_str());
+ const char* first_unparsed;
+ ValueObject::GetValueForExpressionPathOptions options;
+ ValueObject::ExpressionPathEndResultType final_value_type;
+ ValueObject::ExpressionPathScanEndReason reason_to_stop;
+ ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
+ ValueObjectSP item = valobj->GetValueForExpressionPath (ptr_deref_buffer.c_str(),
+ &first_unparsed,
+ &reason_to_stop,
+ &final_value_type,
+ options,
+ &what_next);
+ if (!item)
+ {
+ if (log)
+ log->Printf("[ExpandIndexedExpression] ERROR: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[ExpandIndexedExpression] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ return item;
+}
+
+static inline bool
+IsToken(const char *var_name_begin, const char *var)
+{
+ return (::strncmp (var_name_begin, var, strlen(var)) == 0);
+}
+
+static bool
+IsTokenWithFormat(const char *var_name_begin, const char *var, std::string &format, const char *default_format,
+ const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr)
+{
+ int var_len = strlen(var);
+ if (::strncmp (var_name_begin, var, var_len) == 0)
+ {
+ var_name_begin += var_len;
+ if (*var_name_begin == '}')
+ {
+ format = default_format;
+ return true;
+ }
+ else if (*var_name_begin == '%')
+ {
+ // Allow format specifiers: x|X|u with optional width specifiers.
+ // ${thread.id%x} ; hex
+ // ${thread.id%X} ; uppercase hex
+ // ${thread.id%u} ; unsigned decimal
+ // ${thread.id%8.8X} ; width.precision + specifier
+ // ${thread.id%tid} ; unsigned on FreeBSD/Linux, otherwise default_format (0x%4.4x for thread.id)
+ int dot_count = 0;
+ const char *specifier = NULL;
+ int width_precision_length = 0;
+ const char *width_precision = ++var_name_begin;
+ while (isdigit(*var_name_begin) || *var_name_begin == '.')
+ {
+ dot_count += (*var_name_begin == '.');
+ if (dot_count > 1)
+ break;
+ var_name_begin++;
+ width_precision_length++;
+ }
+
+ if (IsToken (var_name_begin, "tid}"))
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx_ptr, sc_ptr);
+ if (target)
+ {
+ ArchSpec arch (target->GetArchitecture ());
+ llvm::Triple::OSType ostype = arch.IsValid() ? arch.GetTriple().getOS() : llvm::Triple::UnknownOS;
+ if ((ostype == llvm::Triple::FreeBSD) || (ostype == llvm::Triple::Linux))
+ specifier = PRIu64;
+ }
+ if (!specifier)
+ {
+ format = default_format;
+ return true;
+ }
+ }
+ else if (IsToken (var_name_begin, "x}"))
+ specifier = PRIx64;
+ else if (IsToken (var_name_begin, "X}"))
+ specifier = PRIX64;
+ else if (IsToken (var_name_begin, "u}"))
+ specifier = PRIu64;
+
+ if (specifier)
+ {
+ format = "%";
+ if (width_precision_length)
+ format += std::string(width_precision, width_precision_length);
+ format += specifier;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+FormatPromptRecurse
+(
+ const char *format,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s,
+ const char **end,
+ ValueObject* valobj
+)
+{
+ ValueObject* realvalobj = NULL; // makes it super-easy to parse pointers
+ bool success = true;
+ const char *p;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ for (p = format; *p != '\0'; ++p)
+ {
+ if (realvalobj)
+ {
+ valobj = realvalobj;
+ realvalobj = NULL;
+ }
+ size_t non_special_chars = ::strcspn (p, "${}\\");
+ if (non_special_chars > 0)
+ {
+ if (success)
+ s.Write (p, non_special_chars);
+ p += non_special_chars;
+ }
+
+ if (*p == '\0')
+ {
+ break;
+ }
+ else if (*p == '{')
+ {
+ // Start a new scope that must have everything it needs if it is to
+ // to make it into the final output stream "s". If you want to make
+ // a format that only prints out the function or symbol name if there
+ // is one in the symbol context you can use:
+ // "{function =${function.name}}"
+ // The first '{' starts a new scope that end with the matching '}' at
+ // the end of the string. The contents "function =${function.name}"
+ // will then be evaluated and only be output if there is a function
+ // or symbol with a valid name.
+ StreamString sub_strm;
+
+ ++p; // Skip the '{'
+
+ if (FormatPromptRecurse (p, sc, exe_ctx, addr, sub_strm, &p, valobj))
+ {
+ // The stream had all it needed
+ s.Write(sub_strm.GetData(), sub_strm.GetSize());
+ }
+ if (*p != '}')
+ {
+ success = false;
+ break;
+ }
+ }
+ else if (*p == '}')
+ {
+ // End of a enclosing scope
+ break;
+ }
+ else if (*p == '$')
+ {
+ // We have a prompt variable to print
+ ++p;
+ if (*p == '{')
+ {
+ ++p;
+ const char *var_name_begin = p;
+ const char *var_name_end = ::strchr (p, '}');
+
+ if (var_name_end && var_name_begin < var_name_end)
+ {
+ // if we have already failed to parse, skip this variable
+ if (success)
+ {
+ const char *cstr = NULL;
+ std::string token_format;
+ Address format_addr;
+ bool calculate_format_addr_function_offset = false;
+ // Set reg_kind and reg_num to invalid values
+ RegisterKind reg_kind = kNumRegisterKinds;
+ uint32_t reg_num = LLDB_INVALID_REGNUM;
+ FileSpec format_file_spec;
+ const RegisterInfo *reg_info = NULL;
+ RegisterContext *reg_ctx = NULL;
+ bool do_deref_pointer = false;
+ ValueObject::ExpressionPathScanEndReason reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ ValueObject::ExpressionPathEndResultType final_value_type = ValueObject::eExpressionPathEndResultTypePlain;
+
+ // Each variable must set success to true below...
+ bool var_success = false;
+ switch (var_name_begin[0])
+ {
+ case '*':
+ case 'v':
+ case 's':
+ {
+ if (!valobj)
+ break;
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] initial string: %s",var_name_begin);
+
+ // check for *var and *svar
+ if (*var_name_begin == '*')
+ {
+ do_deref_pointer = true;
+ var_name_begin++;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] found a deref, new string is: %s",var_name_begin);
+ }
+
+ if (*var_name_begin == 's')
+ {
+ if (!valobj->IsSynthetic())
+ valobj = valobj->GetSyntheticValue().get();
+ if (!valobj)
+ break;
+ var_name_begin++;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] found a synthetic, new string is: %s",var_name_begin);
+ }
+
+ // should be a 'v' by now
+ if (*var_name_begin != 'v')
+ break;
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] string I am working with: %s",var_name_begin);
+
+ ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ?
+ ValueObject::eExpressionPathAftermathDereference : ValueObject::eExpressionPathAftermathNothing);
+ ValueObject::GetValueForExpressionPathOptions options;
+ options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar().DoAllowSyntheticChildren();
+ ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eValueObjectRepresentationStyleSummary;
+ ValueObject* target = NULL;
+ Format custom_format = eFormatInvalid;
+ const char* var_name_final = NULL;
+ const char* var_name_final_if_array_range = NULL;
+ const char* close_bracket_position = NULL;
+ int64_t index_lower = -1;
+ int64_t index_higher = -1;
+ bool is_array_range = false;
+ const char* first_unparsed;
+ bool was_plain_var = false;
+ bool was_var_format = false;
+ bool was_var_indexed = false;
+
+ if (!valobj) break;
+ // simplest case ${var}, just print valobj's value
+ if (IsToken (var_name_begin, "var}"))
+ {
+ was_plain_var = true;
+ target = valobj;
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+ else if (IsToken (var_name_begin,"var%"))
+ {
+ was_var_format = true;
+ // this is a variable with some custom format applied to it
+ const char* percent_position;
+ target = valobj;
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ ScanFormatDescriptor (var_name_begin,
+ var_name_end,
+ &var_name_final,
+ &percent_position,
+ &custom_format,
+ &val_obj_display);
+ }
+ // this is ${var.something} or multiple .something nested
+ else if (IsToken (var_name_begin, "var"))
+ {
+ if (IsToken (var_name_begin, "var["))
+ was_var_indexed = true;
+ const char* percent_position;
+ ScanFormatDescriptor (var_name_begin,
+ var_name_end,
+ &var_name_final,
+ &percent_position,
+ &custom_format,
+ &val_obj_display);
+
+ const char* open_bracket_position;
+ const char* separator_position;
+ ScanBracketedRange (var_name_begin,
+ var_name_end,
+ var_name_final,
+ &open_bracket_position,
+ &separator_position,
+ &close_bracket_position,
+ &var_name_final_if_array_range,
+ &index_lower,
+ &index_higher);
+
+ Error error;
+
+ std::string expr_path(var_name_final-var_name_begin-1,0);
+ memcpy(&expr_path[0], var_name_begin+3,var_name_final-var_name_begin-3);
+
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] symbol to expand: %s",expr_path.c_str());
+
+ target = valobj->GetValueForExpressionPath(expr_path.c_str(),
+ &first_unparsed,
+ &reason_to_stop,
+ &final_value_type,
+ options,
+ &what_next).get();
+
+ if (!target)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ break;
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ALL RIGHT: unparsed portion = %s, why stopping = %d,"
+ " final_value_type %d",
+ first_unparsed, reason_to_stop, final_value_type);
+ }
+ }
+ else
+ break;
+
+ is_array_range = (final_value_type == ValueObject::eExpressionPathEndResultTypeBoundedRange ||
+ final_value_type == ValueObject::eExpressionPathEndResultTypeUnboundedRange);
+
+ do_deref_pointer = (what_next == ValueObject::eExpressionPathAftermathDereference);
+
+ if (do_deref_pointer && !is_array_range)
+ {
+ // I have not deref-ed yet, let's do it
+ // this happens when we are not going through GetValueForVariableExpressionPath
+ // to get to the target ValueObject
+ Error error;
+ target = target->Dereference(error).get();
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR: %s\n", error.AsCString("unknown")); \
+ break;
+ }
+ do_deref_pointer = false;
+ }
+
+ // <rdar://problem/11338654>
+ // we do not want to use the summary for a bitfield of type T:n
+ // if we were originally dealing with just a T - that would get
+ // us into an endless recursion
+ if (target->IsBitfield() && was_var_indexed)
+ {
+ // TODO: check for a (T:n)-specific summary - we should still obey that
+ StreamString bitfield_name;
+ bitfield_name.Printf("%s:%d", target->GetTypeName().AsCString(), target->GetBitfieldBitSize());
+ lldb::TypeNameSpecifierImplSP type_sp(new TypeNameSpecifierImpl(bitfield_name.GetData(),false));
+ if (!DataVisualization::GetSummaryForType(type_sp))
+ val_obj_display = ValueObject::eValueObjectRepresentationStyleValue;
+ }
+
+ // 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_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
+ {
+ StreamString str_temp;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] I am into array || pointer && !range");
+
+ if (target->HasSpecialPrintableRepresentation(val_obj_display, custom_format))
+ {
+ // try to use the special cases
+ var_success = target->DumpPrintableRepresentation(str_temp,
+ val_obj_display,
+ custom_format);
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] special cases did%s match", var_success ? "" : "n't");
+
+ // should not happen
+ if (var_success)
+ s << str_temp.GetData();
+ var_success = true;
+ break;
+ }
+ else
+ {
+ if (was_plain_var) // if ${var}
+ {
+ s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
+ }
+ else if (is_pointer) // if pointer, value is the address stored
+ {
+ target->DumpPrintableRepresentation (s,
+ val_obj_display,
+ custom_format,
+ ValueObject::ePrintableRepresentationSpecialCasesDisable);
+ }
+ var_success = true;
+ break;
+ }
+ }
+
+ // if directly trying to print ${var}, and this is an aggregate, display a nice
+ // type @ location message
+ if (is_aggregate && was_plain_var)
+ {
+ s << target->GetTypeName() << " @ " << target->GetLocationAsCString();
+ var_success = true;
+ break;
+ }
+
+ // if directly trying to print ${var%V}, and this is an aggregate, do not let the user do it
+ if (is_aggregate && ((was_var_format && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)))
+ {
+ s << "<invalid use of aggregate type>";
+ var_success = true;
+ break;
+ }
+
+ if (!is_array_range)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] dumping ordinary printable output");
+ var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] checking if I can handle as array");
+ if (!is_array && !is_pointer)
+ break;
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] handle as array");
+ const char* special_directions = NULL;
+ StreamString special_directions_writer;
+ if (close_bracket_position && (var_name_end-close_bracket_position > 1))
+ {
+ ConstString additional_data;
+ additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1);
+ special_directions_writer.Printf("${%svar%s}",
+ do_deref_pointer ? "*" : "",
+ additional_data.GetCString());
+ special_directions = special_directions_writer.GetData();
+ }
+
+ // let us display items index_lower thru index_higher of this array
+ s.PutChar('[');
+ var_success = true;
+
+ if (index_higher < 0)
+ index_higher = valobj->GetNumChildren() - 1;
+
+ uint32_t max_num_children = target->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+
+ for (;index_lower<=index_higher;index_lower++)
+ {
+ ValueObject* item = ExpandIndexedExpression (target,
+ index_lower,
+ exe_ctx->GetFramePtr(),
+ false).get();
+
+ if (!item)
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] ERROR in getting child item at index %" PRId64, index_lower);
+ }
+ else
+ {
+ if (log)
+ log->Printf("[Debugger::FormatPrompt] special_directions for child item: %s",special_directions);
+ }
+
+ 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);
+
+ if (--max_num_children == 0)
+ {
+ s.PutCString(", ...");
+ break;
+ }
+
+ if (index_lower < index_higher)
+ s.PutChar(',');
+ }
+ s.PutChar(']');
+ }
+ }
+ break;
+ case 'a':
+ if (IsToken (var_name_begin, "addr}"))
+ {
+ if (addr && addr->IsValid())
+ {
+ var_success = true;
+ format_addr = *addr;
+ }
+ }
+ break;
+
+ case 'p':
+ if (IsToken (var_name_begin, "process."))
+ {
+ if (exe_ctx)
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ var_name_begin += ::strlen ("process.");
+ if (IsTokenWithFormat (var_name_begin, "id", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), process->GetID());
+ var_success = true;
+ }
+ else if ((IsToken (var_name_begin, "name}")) ||
+ (IsToken (var_name_begin, "file.basename}")) ||
+ (IsToken (var_name_begin, "file.fullpath}")))
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ if (var_name_begin[0] == 'n' || var_name_begin[5] == 'f')
+ {
+ format_file_spec.GetFilename() = exe_module->GetFileSpec().GetFilename();
+ var_success = format_file_spec;
+ }
+ else
+ {
+ format_file_spec = exe_module->GetFileSpec();
+ var_success = format_file_spec;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = process->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, process, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case 't':
+ if (IsToken (var_name_begin, "thread."))
+ {
+ if (exe_ctx)
+ {
+ Thread *thread = exe_ctx->GetThreadPtr();
+ if (thread)
+ {
+ var_name_begin += ::strlen ("thread.");
+ if (IsTokenWithFormat (var_name_begin, "id", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), thread->GetID());
+ var_success = true;
+ }
+ else if (IsTokenWithFormat (var_name_begin, "protocol_id", token_format, "0x%4.4" PRIx64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), thread->GetProtocolID());
+ var_success = true;
+ }
+ else if (IsTokenWithFormat (var_name_begin, "index", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ s.Printf(token_format.c_str(), (uint64_t)thread->GetIndexID());
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "name}"))
+ {
+ cstr = thread->GetName();
+ var_success = cstr && cstr[0];
+ if (var_success)
+ s.PutCString(cstr);
+ }
+ else if (IsToken (var_name_begin, "queue}"))
+ {
+ cstr = thread->GetQueueName();
+ var_success = cstr && cstr[0];
+ if (var_success)
+ s.PutCString(cstr);
+ }
+ else if (IsToken (var_name_begin, "stop-reason}"))
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ cstr = stop_info_sp->GetDescription();
+ if (cstr && cstr[0])
+ {
+ s.PutCString(cstr);
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "return-value}"))
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ ValueObjectSP return_valobj_sp = StopInfo::GetReturnValueObject (stop_info_sp);
+ if (return_valobj_sp)
+ {
+ ValueObject::DumpValueObject (s, return_valobj_sp.get());
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = thread->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, thread, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "target."))
+ {
+ // TODO: hookup properties
+// if (!target_properties_sp)
+// {
+// Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+// if (target)
+// target_properties_sp = target->GetProperties();
+// }
+//
+// if (target_properties_sp)
+// {
+// var_name_begin += ::strlen ("target.");
+// const char *end_property = strchr(var_name_begin, '}');
+// if (end_property)
+// {
+// ConstString property_name(var_name_begin, end_property - var_name_begin);
+// std::string property_value (target_properties_sp->GetPropertyValue(property_name));
+// if (!property_value.empty())
+// {
+// s.PutCString (property_value.c_str());
+// var_success = true;
+// }
+// }
+// }
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ if (target)
+ {
+ var_name_begin += ::strlen ("target.");
+ if (IsToken (var_name_begin, "arch}"))
+ {
+ ArchSpec arch (target->GetArchitecture ());
+ if (arch.IsValid())
+ {
+ s.PutCString (arch.GetArchitectureName());
+ var_success = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = target->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, target, script_name))
+ var_success = true;
+ }
+ }
+ }
+ break;
+
+
+ case 'm':
+ if (IsToken (var_name_begin, "module."))
+ {
+ if (sc && sc->module_sp.get())
+ {
+ Module *module = sc->module_sp.get();
+ var_name_begin += ::strlen ("module.");
+
+ if (IsToken (var_name_begin, "file."))
+ {
+ if (module->GetFileSpec())
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = module->GetFileSpec().GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = module->GetFileSpec();
+ var_success = format_file_spec;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+
+ case 'f':
+ if (IsToken (var_name_begin, "file."))
+ {
+ if (sc && sc->comp_unit != NULL)
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = sc->comp_unit->GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = *sc->comp_unit;
+ var_success = format_file_spec;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "frame."))
+ {
+ if (exe_ctx)
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ if (frame)
+ {
+ var_name_begin += ::strlen ("frame.");
+ if (IsToken (var_name_begin, "index}"))
+ {
+ s.Printf("%u", frame->GetFrameIndex());
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "pc}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_PC;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "sp}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "fp}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FP;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "flags}"))
+ {
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_FLAGS;
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "reg."))
+ {
+ reg_ctx = frame->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ var_name_begin += ::strlen ("reg.");
+ if (var_name_begin < var_name_end)
+ {
+ std::string reg_name (var_name_begin, var_name_end);
+ reg_info = reg_ctx->GetRegisterInfoByName (reg_name.c_str());
+ if (reg_info)
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "script:"))
+ {
+ var_name_begin += ::strlen("script:");
+ std::string script_name(var_name_begin,var_name_end);
+ ScriptInterpreter* script_interpreter = frame->GetThread()->GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (RunScriptFormatKeyword (s, script_interpreter, frame, script_name))
+ var_success = true;
+ }
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "function."))
+ {
+ if (sc && (sc->function != NULL || sc->symbol != NULL))
+ {
+ var_name_begin += ::strlen ("function.");
+ if (IsToken (var_name_begin, "id}"))
+ {
+ if (sc->function)
+ s.Printf("function{0x%8.8" PRIx64 "}", sc->function->GetID());
+ else
+ s.Printf("symbol[%u]", sc->symbol->GetID());
+
+ var_success = true;
+ }
+ else if (IsToken (var_name_begin, "name}"))
+ {
+ if (sc->function)
+ cstr = sc->function->GetName().AsCString (NULL);
+ else if (sc->symbol)
+ cstr = sc->symbol->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ s.PutCString(cstr);
+
+ if (sc->block)
+ {
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+ if (inline_block)
+ {
+ const InlineFunctionInfo *inline_info = sc->block->GetInlinedFunctionInfo();
+ if (inline_info)
+ {
+ s.PutCString(" [inlined] ");
+ inline_info->GetName().Dump(&s);
+ }
+ }
+ }
+ var_success = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "name-with-args}"))
+ {
+ // Print the function name with arguments in it
+
+ if (sc->function)
+ {
+ var_success = true;
+ ExecutionContextScope *exe_scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL;
+ cstr = sc->function->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ const InlineFunctionInfo *inline_info = NULL;
+ VariableListSP variable_list_sp;
+ bool get_function_vars = true;
+ if (sc->block)
+ {
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+
+ if (inline_block)
+ {
+ get_function_vars = false;
+ inline_info = sc->block->GetInlinedFunctionInfo();
+ if (inline_info)
+ variable_list_sp = inline_block->GetBlockVariableList (true);
+ }
+ }
+
+ if (get_function_vars)
+ {
+ variable_list_sp = sc->function->GetBlock(true).GetBlockVariableList (true);
+ }
+
+ if (inline_info)
+ {
+ s.PutCString (cstr);
+ s.PutCString (" [inlined] ");
+ cstr = inline_info->GetName().GetCString();
+ }
+
+ VariableList args;
+ if (variable_list_sp)
+ variable_list_sp->AppendVariablesWithScope(eValueTypeVariableArgument, args);
+ if (args.GetSize() > 0)
+ {
+ const char *open_paren = strchr (cstr, '(');
+ const char *close_paren = NULL;
+ if (open_paren)
+ {
+ if (IsToken (open_paren, "(anonymous namespace)"))
+ {
+ open_paren = strchr (open_paren + strlen("(anonymous namespace)"), '(');
+ if (open_paren)
+ close_paren = strchr (open_paren, ')');
+ }
+ else
+ close_paren = strchr (open_paren, ')');
+ }
+
+ if (open_paren)
+ s.Write(cstr, open_paren - cstr + 1);
+ else
+ {
+ s.PutCString (cstr);
+ s.PutChar ('(');
+ }
+ const size_t num_args = args.GetSize();
+ for (size_t arg_idx = 0; arg_idx < num_args; ++arg_idx)
+ {
+ VariableSP var_sp (args.GetVariableAtIndex (arg_idx));
+ ValueObjectSP var_value_sp (ValueObjectVariable::Create (exe_scope, var_sp));
+ const char *var_name = var_value_sp->GetName().GetCString();
+ const char *var_value = var_value_sp->GetValueAsCString();
+ if (arg_idx > 0)
+ s.PutCString (", ");
+ if (var_value_sp->GetError().Success())
+ {
+ if (var_value)
+ s.Printf ("%s=%s", var_name, var_value);
+ else
+ s.Printf ("%s=%s at %s", var_name, var_value_sp->GetTypeName().GetCString(), var_value_sp->GetLocationAsCString());
+ }
+ else
+ s.Printf ("%s=<unavailable>", var_name);
+ }
+
+ if (close_paren)
+ s.PutCString (close_paren);
+ else
+ s.PutChar(')');
+
+ }
+ else
+ {
+ s.PutCString(cstr);
+ }
+ }
+ }
+ else if (sc->symbol)
+ {
+ cstr = sc->symbol->GetName().AsCString (NULL);
+ if (cstr)
+ {
+ s.PutCString(cstr);
+ var_success = true;
+ }
+ }
+ }
+ else if (IsToken (var_name_begin, "addr-offset}"))
+ {
+ var_success = addr != NULL;
+ if (var_success)
+ {
+ format_addr = *addr;
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "line-offset}"))
+ {
+ var_success = sc->line_entry.range.GetBaseAddress().IsValid();
+ if (var_success)
+ {
+ format_addr = sc->line_entry.range.GetBaseAddress();
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ else if (IsToken (var_name_begin, "pc-offset}"))
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ var_success = frame != NULL;
+ if (var_success)
+ {
+ format_addr = frame->GetFrameCodeAddress();
+ calculate_format_addr_function_offset = true;
+ }
+ }
+ }
+ }
+ break;
+
+ case 'l':
+ if (IsToken (var_name_begin, "line."))
+ {
+ if (sc && sc->line_entry.IsValid())
+ {
+ var_name_begin += ::strlen ("line.");
+ if (IsToken (var_name_begin, "file."))
+ {
+ var_name_begin += ::strlen ("file.");
+
+ if (IsToken (var_name_begin, "basename}"))
+ {
+ format_file_spec.GetFilename() = sc->line_entry.file.GetFilename();
+ var_success = format_file_spec;
+ }
+ else if (IsToken (var_name_begin, "fullpath}"))
+ {
+ format_file_spec = sc->line_entry.file;
+ var_success = format_file_spec;
+ }
+ }
+ else if (IsTokenWithFormat (var_name_begin, "number", token_format, "%" PRIu64, exe_ctx, sc))
+ {
+ var_success = true;
+ s.Printf(token_format.c_str(), (uint64_t)sc->line_entry.line);
+ }
+ else if ((IsToken (var_name_begin, "start-addr}")) ||
+ (IsToken (var_name_begin, "end-addr}")))
+ {
+ var_success = sc && sc->line_entry.range.GetBaseAddress().IsValid();
+ if (var_success)
+ {
+ format_addr = sc->line_entry.range.GetBaseAddress();
+ if (var_name_begin[0] == 'e')
+ format_addr.Slide (sc->line_entry.range.GetByteSize());
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (var_success)
+ {
+ // If format addr is valid, then we need to print an address
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ // We have a register value to display...
+ if (reg_num == LLDB_REGNUM_GENERIC_PC && reg_kind == eRegisterKindGeneric)
+ {
+ format_addr = frame->GetFrameCodeAddress();
+ }
+ else
+ {
+ if (reg_ctx == NULL)
+ reg_ctx = frame->GetRegisterContext().get();
+
+ if (reg_ctx)
+ {
+ if (reg_kind != kNumRegisterKinds)
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
+ reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+ var_success = reg_info != NULL;
+ }
+ }
+ }
+
+ if (reg_info != NULL)
+ {
+ RegisterValue reg_value;
+ var_success = reg_ctx->ReadRegister (reg_info, reg_value);
+ if (var_success)
+ {
+ reg_value.Dump(&s, reg_info, false, false, eFormatDefault);
+ }
+ }
+
+ if (format_file_spec)
+ {
+ s << format_file_spec;
+ }
+
+ // If format addr is valid, then we need to print an address
+ if (format_addr.IsValid())
+ {
+ var_success = false;
+
+ if (calculate_format_addr_function_offset)
+ {
+ Address func_addr;
+
+ if (sc)
+ {
+ if (sc->function)
+ {
+ func_addr = sc->function->GetAddressRange().GetBaseAddress();
+ if (sc->block)
+ {
+ // Check to make sure we aren't in an inline
+ // function. If we are, use the inline block
+ // range that contains "format_addr" since
+ // blocks can be discontiguous.
+ Block *inline_block = sc->block->GetContainingInlinedBlock ();
+ AddressRange inline_range;
+ if (inline_block && inline_block->GetRangeContainingAddress (format_addr, inline_range))
+ func_addr = inline_range.GetBaseAddress();
+ }
+ }
+ else if (sc->symbol && sc->symbol->ValueIsAddress())
+ func_addr = sc->symbol->GetAddress();
+ }
+
+ if (func_addr.IsValid())
+ {
+ 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);
+ else if (addr_file_addr < func_file_addr)
+ s.Printf(" - %" PRIu64, func_file_addr - addr_file_addr);
+ var_success = true;
+ }
+ else
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ if (target)
+ {
+ 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);
+ else if (addr_load_addr < func_load_addr)
+ s.Printf(" - %" PRIu64, func_load_addr - addr_load_addr);
+ var_success = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ Target *target = Target::GetTargetFromContexts (exe_ctx, sc);
+ addr_t vaddr = LLDB_INVALID_ADDRESS;
+ if (exe_ctx && !target->GetSectionLoadList().IsEmpty())
+ vaddr = format_addr.GetLoadAddress (target);
+ if (vaddr == LLDB_INVALID_ADDRESS)
+ vaddr = format_addr.GetFileAddress ();
+
+ if (vaddr != LLDB_INVALID_ADDRESS)
+ {
+ int addr_width = target->GetArchitecture().GetAddressByteSize() * 2;
+ if (addr_width == 0)
+ addr_width = 16;
+ s.Printf("0x%*.*" PRIx64, addr_width, addr_width, vaddr);
+ var_success = true;
+ }
+ }
+ }
+ }
+
+ if (var_success == false)
+ success = false;
+ }
+ p = var_name_end;
+ }
+ else
+ break;
+ }
+ else
+ {
+ // We got a dollar sign with no '{' after it, it must just be a dollar sign
+ s.PutChar(*p);
+ }
+ }
+ else if (*p == '\\')
+ {
+ ++p; // skip the slash
+ switch (*p)
+ {
+ case 'a': s.PutChar ('\a'); break;
+ case 'b': s.PutChar ('\b'); break;
+ case 'f': s.PutChar ('\f'); break;
+ case 'n': s.PutChar ('\n'); break;
+ case 'r': s.PutChar ('\r'); break;
+ case 't': s.PutChar ('\t'); break;
+ case 'v': s.PutChar ('\v'); break;
+ case '\'': s.PutChar ('\''); break;
+ case '\\': s.PutChar ('\\'); break;
+ case '0':
+ // 1 to 3 octal chars
+ {
+ // Make a string that can hold onto the initial zero char,
+ // up to 3 octal digits, and a terminating NULL.
+ char oct_str[5] = { 0, 0, 0, 0, 0 };
+
+ int i;
+ for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
+ oct_str[i] = p[i];
+
+ // We don't want to consume the last octal character since
+ // the main for loop will do this for us, so we advance p by
+ // one less than i (even if i is zero)
+ p += i - 1;
+ unsigned long octal_value = ::strtoul (oct_str, NULL, 8);
+ if (octal_value <= UINT8_MAX)
+ {
+ s.PutChar((char)octal_value);
+ }
+ }
+ break;
+
+ case 'x':
+ // hex number in the format
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the 'x'
+
+ // Make a string that can hold onto two hex chars plus a
+ // NULL terminator
+ char hex_str[3] = { 0,0,0 };
+ hex_str[0] = *p;
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the first of the two hex chars
+ hex_str[1] = *p;
+ }
+
+ unsigned long hex_value = strtoul (hex_str, NULL, 16);
+ if (hex_value <= UINT8_MAX)
+ s.PutChar ((char)hex_value);
+ }
+ else
+ {
+ s.PutChar('x');
+ }
+ break;
+
+ default:
+ // Just desensitize any other character by just printing what
+ // came after the '\'
+ s << *p;
+ break;
+
+ }
+
+ }
+ }
+ if (end)
+ *end = p;
+ return success;
+}
+
+bool
+Debugger::FormatPrompt
+(
+ const char *format,
+ const SymbolContext *sc,
+ const ExecutionContext *exe_ctx,
+ const Address *addr,
+ Stream &s,
+ ValueObject* valobj
+)
+{
+ bool use_color = exe_ctx ? exe_ctx->GetTargetRef().GetDebugger().GetUseColor() : true;
+ 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);
+}
+
+void
+Debugger::SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton)
+{
+ // For simplicity's sake, I am not going to deal with how to close down any
+ // open logging streams, I just redirect everything from here on out to the
+ // callback.
+ m_log_callback_stream_sp.reset (new StreamCallback (log_callback, baton));
+}
+
+bool
+Debugger::EnableLog (const char *channel, const char **categories, const char *log_file, uint32_t log_options, Stream &error_stream)
+{
+ Log::Callbacks log_callbacks;
+
+ StreamSP log_stream_sp;
+ if (m_log_callback_stream_sp)
+ {
+ log_stream_sp = m_log_callback_stream_sp;
+ // For now when using the callback mode you always get thread & timestamp.
+ log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
+ }
+ else if (log_file == NULL || *log_file == '\0')
+ {
+ log_stream_sp.reset(new StreamFile(GetOutputFile().GetDescriptor(), false));
+ }
+ else
+ {
+ LogStreamMap::iterator pos = m_log_streams.find(log_file);
+ if (pos != m_log_streams.end())
+ log_stream_sp = pos->second.lock();
+ if (!log_stream_sp)
+ {
+ log_stream_sp.reset (new StreamFile (log_file));
+ m_log_streams[log_file] = log_stream_sp;
+ }
+ }
+ assert (log_stream_sp.get());
+
+ if (log_options == 0)
+ log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE;
+
+ if (Log::GetLogChannelCallbacks (ConstString(channel), log_callbacks))
+ {
+ log_callbacks.enable (log_stream_sp, log_options, categories, &error_stream);
+ return true;
+ }
+ else
+ {
+ LogChannelSP log_channel_sp (LogChannel::FindPlugin (channel));
+ if (log_channel_sp)
+ {
+ if (log_channel_sp->Enable (log_stream_sp, log_options, &error_stream, categories))
+ {
+ return true;
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ else
+ {
+ error_stream.Printf ("Invalid log channel '%s'.\n", channel);
+ return false;
+ }
+ }
+ return false;
+}
+
+SourceManager &
+Debugger::GetSourceManager ()
+{
+ if (m_source_manager_ap.get() == NULL)
+ m_source_manager_ap.reset (new SourceManager (shared_from_this()));
+ return *m_source_manager_ap;
+}
+
+
diff --git a/source/Core/Disassembler.cpp b/source/Core/Disassembler.cpp
new file mode 100644
index 000000000000..e80e92c91b51
--- /dev/null
+++ b/source/Core/Disassembler.cpp
@@ -0,0 +1,1269 @@
+//===-- Disassembler.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/Disassembler.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Interpreter/OptionValue.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Interpreter/OptionValueString.h"
+#include "lldb/Interpreter/OptionValueUInt64.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#define DEFAULT_DISASM_BYTE_SIZE 32
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+DisassemblerSP
+Disassembler::FindPlugin (const ArchSpec &arch, const char *flavor, const char *plugin_name)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Disassembler::FindPlugin (arch = %s, plugin_name = %s)",
+ arch.GetArchitectureName(),
+ plugin_name);
+
+ DisassemblerCreateInstance create_callback = NULL;
+
+ if (plugin_name)
+ {
+ ConstString const_plugin_name (plugin_name);
+ create_callback = PluginManager::GetDisassemblerCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp.get())
+ return disassembler_sp;
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDisassemblerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ DisassemblerSP disassembler_sp(create_callback(arch, flavor));
+
+ if (disassembler_sp.get())
+ return disassembler_sp;
+ }
+ }
+ return DisassemblerSP();
+}
+
+DisassemblerSP
+Disassembler::FindPluginForTarget(const TargetSP target_sp, const ArchSpec &arch, const char *flavor, const char *plugin_name)
+{
+ if (target_sp && flavor == NULL)
+ {
+ // FIXME - we don't have the mechanism in place to do per-architecture settings. But since we know that for now
+ // we only support flavors on x86 & x86_64,
+ if (arch.GetTriple().getArch() == llvm::Triple::x86
+ || arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ flavor = target_sp->GetDisassemblyFlavor();
+ }
+ return FindPlugin(arch, flavor, plugin_name);
+}
+
+
+static void
+ResolveAddress (const ExecutionContext &exe_ctx,
+ const Address &addr,
+ Address &resolved_addr)
+{
+ if (!addr.IsSectionOffset())
+ {
+ // If we weren't passed in a section offset address range,
+ // try and resolve it to something
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ if (target->GetSectionLoadList().IsEmpty())
+ {
+ target->GetImages().ResolveFileAddress (addr.GetOffset(), resolved_addr);
+ }
+ else
+ {
+ target->GetSectionLoadList().ResolveLoadAddress (addr.GetOffset(), resolved_addr);
+ }
+ // We weren't able to resolve the address, just treat it as a
+ // raw address
+ if (resolved_addr.IsValid())
+ return;
+ }
+ }
+ resolved_addr = addr;
+}
+
+size_t
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ SymbolContextList &sc_list,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ size_t success_count = 0;
+ const size_t count = sc_list.GetSize();
+ SymbolContext sc;
+ AddressRange range;
+ const uint32_t scope = eSymbolContextBlock | eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = true;
+ for (size_t i=0; i<count; ++i)
+ {
+ if (sc_list.GetContextAtIndex(i, sc) == false)
+ break;
+ for (uint32_t range_idx = 0; sc.GetAddressRange(scope, range_idx, use_inline_block_range, range); ++range_idx)
+ {
+ if (Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ range,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm))
+ {
+ ++success_count;
+ strm.EOL();
+ }
+ }
+ }
+ return success_count;
+}
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const ConstString &name,
+ Module *module,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ SymbolContextList sc_list;
+ if (name)
+ {
+ const bool include_symbols = true;
+ const bool include_inlines = true;
+ if (module)
+ {
+ module->FindFunctions (name,
+ NULL,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ true,
+ sc_list);
+ }
+ else if (exe_ctx.GetTargetPtr())
+ {
+ exe_ctx.GetTargetPtr()->GetImages().FindFunctions (name,
+ eFunctionNameTypeAuto,
+ include_symbols,
+ include_inlines,
+ false,
+ sc_list);
+ }
+ }
+
+ if (sc_list.GetSize ())
+ {
+ return Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ sc_list,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+ }
+ return false;
+}
+
+
+lldb::DisassemblerSP
+Disassembler::DisassembleRange
+(
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &range
+)
+{
+ lldb::DisassemblerSP disasm_sp;
+ if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid())
+ {
+ disasm_sp = Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name);
+
+ if (disasm_sp)
+ {
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ disasm_sp.reset();
+ }
+ }
+ return disasm_sp;
+}
+
+lldb::DisassemblerSP
+Disassembler::DisassembleBytes (const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const Address &start,
+ const void *src,
+ size_t src_len,
+ uint32_t num_instructions,
+ bool data_from_file)
+{
+ lldb::DisassemblerSP disasm_sp;
+
+ if (src)
+ {
+ disasm_sp = Disassembler::FindPlugin(arch, flavor, plugin_name);
+
+ if (disasm_sp)
+ {
+ DataExtractor data(src, src_len, arch.GetByteOrder(), arch.GetAddressByteSize());
+
+ (void)disasm_sp->DecodeInstructions (start,
+ data,
+ 0,
+ num_instructions,
+ false,
+ data_from_file);
+ }
+ }
+
+ return disasm_sp;
+}
+
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const AddressRange &disasm_range,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ if (disasm_range.GetByteSize())
+ {
+ lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(), arch, flavor, plugin_name));
+
+ if (disasm_sp.get())
+ {
+ AddressRange range;
+ ResolveAddress (exe_ctx, disasm_range.GetBaseAddress(), range.GetBaseAddress());
+ range.SetByteSize (disasm_range.GetByteSize());
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, &strm, prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ return false;
+}
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ const Address &start_address,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ if (num_instructions > 0)
+ {
+ lldb::DisassemblerSP disasm_sp (Disassembler::FindPluginForTarget(exe_ctx.GetTargetSP(),
+ arch,
+ flavor,
+ plugin_name));
+ if (disasm_sp.get())
+ {
+ Address addr;
+ ResolveAddress (exe_ctx, start_address, addr);
+ const bool prefer_file_cache = false;
+ size_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx,
+ addr,
+ num_instructions,
+ prefer_file_cache);
+ if (bytes_disassembled == 0)
+ return false;
+ bool result = PrintInstructions (disasm_sp.get(),
+ debugger,
+ arch,
+ exe_ctx,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ return result;
+ }
+ }
+ return false;
+}
+
+bool
+Disassembler::PrintInstructions
+(
+ Disassembler *disasm_ptr,
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ // We got some things disassembled...
+ size_t num_instructions_found = disasm_ptr->GetInstructionList().GetSize();
+
+ if (num_instructions > 0 && num_instructions < num_instructions_found)
+ num_instructions_found = num_instructions;
+
+ const uint32_t max_opcode_byte_size = disasm_ptr->GetInstructionList().GetMaxOpcocdeByteSize ();
+ uint32_t offset = 0;
+ SymbolContext sc;
+ 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)
+ {
+ Instruction *inst = disasm_ptr->GetInstructionList().GetInstructionAtIndex (i).get();
+ if (inst)
+ {
+ const Address &addr = inst->GetAddress();
+ const bool inst_is_at_pc = pc_addr_ptr && addr == *pc_addr_ptr;
+
+ prev_sc = sc;
+
+ ModuleSP module_sp (addr.GetModule());
+ if (module_sp)
+ {
+ uint32_t resolved_mask = module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, sc);
+ if (resolved_mask)
+ {
+ if (num_mixed_context_lines)
+ {
+ if (!sc_range.ContainsFileAddress (addr))
+ {
+ sc.GetAddressRange (scope, 0, use_inline_block_range, sc_range);
+
+ if (sc != prev_sc)
+ {
+ if (offset != 0)
+ strm.EOL();
+
+ sc.DumpStopContext(&strm, exe_ctx.GetProcessPtr(), addr, false, true, false);
+ strm.EOL();
+
+ if (sc.comp_unit && sc.line_entry.IsValid())
+ {
+ source_manager.DisplaySourceLinesWithLineNumbers (sc.line_entry.file,
+ sc.line_entry.line,
+ num_mixed_context_lines,
+ num_mixed_context_lines,
+ ((inst_is_at_pc && (options & eOptionMarkPCSourceLine)) ? "->" : ""),
+ &strm);
+ }
+ }
+ }
+ }
+ 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
+ {
+ sc.Clear(true);
+ }
+ }
+
+ if ((options & eOptionMarkPCAddress) && pc_addr_ptr)
+ {
+ strm.PutCString(inst_is_at_pc ? "-> " : " ");
+ }
+ const bool show_bytes = (options & eOptionShowBytes) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx);
+ strm.EOL();
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ return true;
+}
+
+
+bool
+Disassembler::Disassemble
+(
+ Debugger &debugger,
+ const ArchSpec &arch,
+ const char *plugin_name,
+ const char *flavor,
+ const ExecutionContext &exe_ctx,
+ uint32_t num_instructions,
+ uint32_t num_mixed_context_lines,
+ uint32_t options,
+ Stream &strm
+)
+{
+ AddressRange range;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ SymbolContext sc(frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextSymbol));
+ if (sc.function)
+ {
+ range = sc.function->GetAddressRange();
+ }
+ else if (sc.symbol && sc.symbol->ValueIsAddress())
+ {
+ range.GetBaseAddress() = sc.symbol->GetAddress();
+ range.SetByteSize (sc.symbol->GetByteSize());
+ }
+ else
+ {
+ range.GetBaseAddress() = frame->GetFrameCodeAddress();
+ }
+
+ if (range.GetBaseAddress().IsValid() && range.GetByteSize() == 0)
+ range.SetByteSize (DEFAULT_DISASM_BYTE_SIZE);
+ }
+
+ return Disassemble (debugger,
+ arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ range,
+ num_instructions,
+ num_mixed_context_lines,
+ options,
+ strm);
+}
+
+Instruction::Instruction(const Address &address, AddressClass addr_class) :
+ m_address (address),
+ m_address_class (addr_class),
+ m_opcode(),
+ m_calculated_strings(false)
+{
+}
+
+Instruction::~Instruction()
+{
+}
+
+AddressClass
+Instruction::GetAddressClass ()
+{
+ if (m_address_class == eAddressClassInvalid)
+ m_address_class = m_address.GetAddressClass();
+ return m_address_class;
+}
+
+void
+Instruction::Dump (lldb_private::Stream *s,
+ uint32_t max_opcode_byte_size,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx)
+{
+ size_t opcode_column_width = 7;
+ const size_t operand_column_width = 25;
+
+ CalculateMnemonicOperandsAndCommentIfNeeded (exe_ctx);
+
+ StreamString ss;
+
+ if (show_address)
+ {
+ m_address.Dump(&ss,
+ exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL,
+ Address::DumpStyleLoadAddress,
+ Address::DumpStyleModuleWithFileAddress,
+ 0);
+
+ ss.PutCString(": ");
+ }
+
+ if (show_bytes)
+ {
+ if (m_opcode.GetType() == Opcode::eTypeBytes)
+ {
+ // x86_64 and i386 are the only ones that use bytes right now so
+ // pad out the byte dump to be able to always show 15 bytes (3 chars each)
+ // plus a space
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump (&ss, 15 * 3 + 1);
+ }
+ else
+ {
+ // Else, we have ARM which can show up to a uint32_t 0x00000000 (10 spaces)
+ // plus two for padding...
+ if (max_opcode_byte_size > 0)
+ m_opcode.Dump (&ss, max_opcode_byte_size * 3 + 1);
+ else
+ m_opcode.Dump (&ss, 12);
+ }
+ }
+
+ const size_t opcode_pos = ss.GetSize();
+
+ // 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
+ // consistent column spacing in these cases, unfortunately.
+ if (m_opcode_name.length() >= opcode_column_width)
+ {
+ opcode_column_width = m_opcode_name.length() + 1;
+ }
+
+ ss.PutCString (m_opcode_name.c_str());
+ ss.FillLastLineToColumn (opcode_pos + opcode_column_width, ' ');
+ ss.PutCString (m_mnemonics.c_str());
+
+ if (!m_comment.empty())
+ {
+ ss.FillLastLineToColumn (opcode_pos + opcode_column_width + operand_column_width, ' ');
+ ss.PutCString (" ; ");
+ ss.PutCString (m_comment.c_str());
+ }
+ s->Write (ss.GetData(), ss.GetSize());
+}
+
+bool
+Instruction::DumpEmulation (const ArchSpec &arch)
+{
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ {
+ insn_emulator_ap->SetInstruction (GetOpcode(), GetAddress(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (0);
+ }
+
+ return false;
+}
+
+OptionValueSP
+Instruction::ReadArray (FILE *in_file, Stream *out_stream, OptionValue::Type data_type)
+{
+ bool done = false;
+ char buffer[1024];
+
+ OptionValueSP option_value_sp (new OptionValueArray (1u << data_type));
+
+ int idx = 0;
+ while (!done)
+ {
+ if (!fgets (buffer, 1023, in_file))
+ {
+ out_stream->Printf ("Instruction::ReadArray: Error reading file (fgets).\n");
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+
+ std::string line (buffer);
+
+ size_t len = line.size();
+ if (line[len-1] == '\n')
+ {
+ line[len-1] = '\0';
+ line.resize (len-1);
+ }
+
+ if ((line.size() == 1) && line[0] == ']')
+ {
+ done = true;
+ line.clear();
+ }
+
+ if (line.size() > 0)
+ {
+ std::string value;
+ static RegularExpression g_reg_exp ("^[ \t]*([^ \t]+)[ \t]*$");
+ RegularExpression::Match regex_match(1);
+ bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
+ if (reg_exp_success)
+ regex_match.GetMatchAtIndex (line.c_str(), 1, value);
+ else
+ value = line;
+
+ OptionValueSP data_value_sp;
+ switch (data_type)
+ {
+ case OptionValue::eTypeUInt64:
+ data_value_sp.reset (new OptionValueUInt64 (0, 0));
+ data_value_sp->SetValueFromCString (value.c_str());
+ break;
+ // Other types can be added later as needed.
+ default:
+ data_value_sp.reset (new OptionValueString (value.c_str(), ""));
+ break;
+ }
+
+ option_value_sp->GetAsArray()->InsertValue (idx, data_value_sp);
+ ++idx;
+ }
+ }
+
+ return option_value_sp;
+}
+
+OptionValueSP
+Instruction::ReadDictionary (FILE *in_file, Stream *out_stream)
+{
+ bool done = false;
+ char buffer[1024];
+
+ OptionValueSP option_value_sp (new OptionValueDictionary());
+ static ConstString encoding_key ("data_encoding");
+ OptionValue::Type data_type = OptionValue::eTypeInvalid;
+
+
+ while (!done)
+ {
+ // Read the next line in the file
+ if (!fgets (buffer, 1023, in_file))
+ {
+ out_stream->Printf ("Instruction::ReadDictionary: Error reading file (fgets).\n");
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+
+ // Check to see if the line contains the end-of-dictionary marker ("}")
+ std::string line (buffer);
+
+ size_t len = line.size();
+ if (line[len-1] == '\n')
+ {
+ line[len-1] = '\0';
+ line.resize (len-1);
+ }
+
+ if ((line.size() == 1) && (line[0] == '}'))
+ {
+ done = true;
+ line.clear();
+ }
+
+ // Try to find a key-value pair in the current line and add it to the dictionary.
+ if (line.size() > 0)
+ {
+ static RegularExpression g_reg_exp ("^[ \t]*([a-zA-Z_][a-zA-Z0-9_]*)[ \t]*=[ \t]*(.*)[ \t]*$");
+ RegularExpression::Match regex_match(2);
+
+ bool reg_exp_success = g_reg_exp.Execute (line.c_str(), &regex_match);
+ std::string key;
+ std::string value;
+ if (reg_exp_success)
+ {
+ regex_match.GetMatchAtIndex (line.c_str(), 1, key);
+ regex_match.GetMatchAtIndex (line.c_str(), 2, value);
+ }
+ else
+ {
+ out_stream->Printf ("Instruction::ReadDictionary: Failure executing regular expression.\n");
+ option_value_sp.reset();
+ return option_value_sp;
+ }
+
+ ConstString const_key (key.c_str());
+ // Check value to see if it's the start of an array or dictionary.
+
+ lldb::OptionValueSP value_sp;
+ assert (value.empty() == false);
+ assert (key.empty() == false);
+
+ if (value[0] == '{')
+ {
+ assert (value.size() == 1);
+ // value is a dictionary
+ value_sp = ReadDictionary (in_file, out_stream);
+ if (value_sp.get() == NULL)
+ {
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+ }
+ else if (value[0] == '[')
+ {
+ assert (value.size() == 1);
+ // value is an array
+ value_sp = ReadArray (in_file, out_stream, data_type);
+ if (value_sp.get() == NULL)
+ {
+ option_value_sp.reset ();
+ return option_value_sp;
+ }
+ // We've used the data_type to read an array; re-set the type to Invalid
+ data_type = OptionValue::eTypeInvalid;
+ }
+ else if ((value[0] == '0') && (value[1] == 'x'))
+ {
+ value_sp.reset (new OptionValueUInt64 (0, 0));
+ value_sp->SetValueFromCString (value.c_str());
+ }
+ else
+ {
+ size_t len = value.size();
+ if ((value[0] == '"') && (value[len-1] == '"'))
+ value = value.substr (1, len-2);
+ value_sp.reset (new OptionValueString (value.c_str(), ""));
+ }
+
+
+
+ if (const_key == encoding_key)
+ {
+ // A 'data_encoding=..." is NOT a normal key-value pair; it is meta-data indicating the
+ // data type of an upcoming array (usually the next bit of data to be read in).
+ if (strcmp (value.c_str(), "uint32_t") == 0)
+ data_type = OptionValue::eTypeUInt64;
+ }
+ else
+ option_value_sp->GetAsDictionary()->SetValueForKey (const_key, value_sp, false);
+ }
+ }
+
+ return option_value_sp;
+}
+
+bool
+Instruction::TestEmulation (Stream *out_stream, const char *file_name)
+{
+ if (!out_stream)
+ return false;
+
+ if (!file_name)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Missing file_name.");
+ return false;
+ }
+
+ FILE *test_file = fopen (file_name, "r");
+ if (!test_file)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Attempt to open test file failed.");
+ return false;
+ }
+
+ char buffer[256];
+ if (!fgets (buffer, 255, test_file))
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Error reading first line of test file.\n");
+ fclose (test_file);
+ return false;
+ }
+
+ if (strncmp (buffer, "InstructionEmulationState={", 27) != 0)
+ {
+ out_stream->Printf ("Instructin::TestEmulation: Test file does not contain emulation state dictionary\n");
+ fclose (test_file);
+ return false;
+ }
+
+ // Read all the test information from the test file into an OptionValueDictionary.
+
+ OptionValueSP data_dictionary_sp (ReadDictionary (test_file, out_stream));
+ if (data_dictionary_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Error reading Dictionary Object.\n");
+ fclose (test_file);
+ return false;
+ }
+
+ fclose (test_file);
+
+ OptionValueDictionary *data_dictionary = data_dictionary_sp->GetAsDictionary();
+ static ConstString description_key ("assembly_string");
+ static ConstString triple_key ("triple");
+
+ OptionValueSP value_sp = data_dictionary->GetValueForKey (description_key);
+
+ if (value_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Test file does not contain description string.\n");
+ return false;
+ }
+
+ SetDescription (value_sp->GetStringValue());
+
+
+ value_sp = data_dictionary->GetValueForKey (triple_key);
+ if (value_sp.get() == NULL)
+ {
+ out_stream->Printf ("Instruction::TestEmulation: Test file does not contain triple.\n");
+ return false;
+ }
+
+ ArchSpec arch;
+ arch.SetTriple (llvm::Triple (value_sp->GetStringValue()));
+
+ bool success = false;
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ success = insn_emulator_ap->TestEmulation (out_stream, arch, data_dictionary);
+
+ if (success)
+ out_stream->Printf ("Emulation test succeeded.");
+ else
+ out_stream->Printf ("Emulation test failed.");
+
+ return success;
+}
+
+bool
+Instruction::Emulate (const ArchSpec &arch,
+ uint32_t evaluate_options,
+ void *baton,
+ EmulateInstruction::ReadMemoryCallback read_mem_callback,
+ EmulateInstruction::WriteMemoryCallback write_mem_callback,
+ EmulateInstruction::ReadRegisterCallback read_reg_callback,
+ EmulateInstruction::WriteRegisterCallback write_reg_callback)
+{
+ std::unique_ptr<EmulateInstruction> insn_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypeAny, NULL));
+ if (insn_emulator_ap.get())
+ {
+ insn_emulator_ap->SetBaton (baton);
+ insn_emulator_ap->SetCallbacks (read_mem_callback, write_mem_callback, read_reg_callback, write_reg_callback);
+ insn_emulator_ap->SetInstruction (GetOpcode(), GetAddress(), NULL);
+ return insn_emulator_ap->EvaluateInstruction (evaluate_options);
+ }
+
+ return false;
+}
+
+
+uint32_t
+Instruction::GetData (DataExtractor &data)
+{
+ return m_opcode.GetData(data);
+}
+
+InstructionList::InstructionList() :
+ m_instructions()
+{
+}
+
+InstructionList::~InstructionList()
+{
+}
+
+size_t
+InstructionList::GetSize() const
+{
+ return m_instructions.size();
+}
+
+uint32_t
+InstructionList::GetMaxOpcocdeByteSize () const
+{
+ uint32_t max_inst_size = 0;
+ collection::const_iterator pos, end;
+ for (pos = m_instructions.begin(), end = m_instructions.end();
+ pos != end;
+ ++pos)
+ {
+ uint32_t inst_size = (*pos)->GetOpcode().GetByteSize();
+ if (max_inst_size < inst_size)
+ max_inst_size = inst_size;
+ }
+ return max_inst_size;
+}
+
+
+
+InstructionSP
+InstructionList::GetInstructionAtIndex (size_t idx) const
+{
+ InstructionSP inst_sp;
+ if (idx < m_instructions.size())
+ inst_sp = m_instructions[idx];
+ return inst_sp;
+}
+
+void
+InstructionList::Dump (Stream *s,
+ bool show_address,
+ bool show_bytes,
+ const ExecutionContext* exe_ctx)
+{
+ const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
+ collection::const_iterator pos, begin, end;
+ 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);
+ }
+}
+
+
+void
+InstructionList::Clear()
+{
+ m_instructions.clear();
+}
+
+void
+InstructionList::Append (lldb::InstructionSP &inst_sp)
+{
+ if (inst_sp)
+ m_instructions.push_back(inst_sp);
+}
+
+uint32_t
+InstructionList::GetIndexOfNextBranchInstruction(uint32_t start) const
+{
+ size_t num_instructions = m_instructions.size();
+
+ uint32_t next_branch = UINT32_MAX;
+ for (size_t i = start; i < num_instructions; i++)
+ {
+ if (m_instructions[i]->DoesBranch())
+ {
+ next_branch = i;
+ break;
+ }
+ }
+ return next_branch;
+}
+
+uint32_t
+InstructionList::GetIndexOfInstructionAtLoadAddress (lldb::addr_t load_addr, Target &target)
+{
+ Address address;
+ address.SetLoadAddress(load_addr, &target);
+ size_t num_instructions = m_instructions.size();
+ uint32_t index = UINT32_MAX;
+ for (size_t i = 0; i < num_instructions; i++)
+ {
+ if (m_instructions[i]->GetAddress() == address)
+ {
+ index = i;
+ break;
+ }
+ }
+ return index;
+}
+
+size_t
+Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
+ const AddressRange &range,
+ Stream *error_strm_ptr,
+ bool prefer_file_cache)
+{
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ const addr_t byte_size = range.GetByteSize();
+ if (target == NULL || byte_size == 0 || !range.GetBaseAddress().IsValid())
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
+ DataBufferSP data_sp(heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target->ReadMemory (range.GetBaseAddress(),
+ prefer_file_cache,
+ heap_buffer->GetBytes(),
+ heap_buffer->GetByteSize(),
+ error,
+ &load_addr);
+
+ if (bytes_read > 0)
+ {
+ if (bytes_read != heap_buffer->GetByteSize())
+ heap_buffer->SetByteSize (bytes_read);
+ DataExtractor data (data_sp,
+ m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+ return DecodeInstructions (range.GetBaseAddress(), data, 0, UINT32_MAX, false, data_from_file);
+ }
+ else if (error_strm_ptr)
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ {
+ error_strm_ptr->Printf("error: %s\n", error_cstr);
+ }
+ }
+ }
+ else if (error_strm_ptr)
+ {
+ error_strm_ptr->PutCString("error: invalid execution context\n");
+ }
+ return 0;
+}
+
+size_t
+Disassembler::ParseInstructions (const ExecutionContext *exe_ctx,
+ const Address &start,
+ uint32_t num_instructions,
+ bool prefer_file_cache)
+{
+ m_instruction_list.Clear();
+
+ if (exe_ctx == NULL || num_instructions == 0 || !start.IsValid())
+ return 0;
+
+ Target *target = exe_ctx->GetTargetPtr();
+ // Calculate the max buffer size we will need in order to disassemble
+ const addr_t byte_size = num_instructions * m_arch.GetMaximumOpcodeByteSize();
+
+ if (target == NULL || byte_size == 0)
+ return 0;
+
+ DataBufferHeap *heap_buffer = new DataBufferHeap (byte_size, '\0');
+ DataBufferSP data_sp (heap_buffer);
+
+ Error error;
+ lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+ const size_t bytes_read = target->ReadMemory (start,
+ prefer_file_cache,
+ heap_buffer->GetBytes(),
+ byte_size,
+ error,
+ &load_addr);
+
+ const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
+
+ if (bytes_read == 0)
+ return 0;
+ DataExtractor data (data_sp,
+ m_arch.GetByteOrder(),
+ m_arch.GetAddressByteSize());
+
+ const bool append_instructions = true;
+ DecodeInstructions (start,
+ data,
+ 0,
+ num_instructions,
+ append_instructions,
+ data_from_file);
+
+ return m_instruction_list.GetSize();
+}
+
+//----------------------------------------------------------------------
+// Disassembler copy constructor
+//----------------------------------------------------------------------
+Disassembler::Disassembler(const ArchSpec& arch, const char *flavor) :
+ m_arch (arch),
+ m_instruction_list(),
+ m_base_addr(LLDB_INVALID_ADDRESS),
+ m_flavor ()
+{
+ if (flavor == NULL)
+ m_flavor.assign("default");
+ else
+ m_flavor.assign(flavor);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Disassembler::~Disassembler()
+{
+}
+
+InstructionList &
+Disassembler::GetInstructionList ()
+{
+ return m_instruction_list;
+}
+
+const InstructionList &
+Disassembler::GetInstructionList () const
+{
+ return m_instruction_list;
+}
+
+//----------------------------------------------------------------------
+// Class PseudoInstruction
+//----------------------------------------------------------------------
+PseudoInstruction::PseudoInstruction () :
+ Instruction (Address(), eAddressClassUnknown),
+ m_description ()
+{
+}
+
+PseudoInstruction::~PseudoInstruction ()
+{
+}
+
+bool
+PseudoInstruction::DoesBranch ()
+{
+ // This is NOT a valid question for a pseudo instruction.
+ return false;
+}
+
+size_t
+PseudoInstruction::Decode (const lldb_private::Disassembler &disassembler,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_offset)
+{
+ return m_opcode.GetByteSize();
+}
+
+
+void
+PseudoInstruction::SetOpcode (size_t opcode_size, void *opcode_data)
+{
+ if (!opcode_data)
+ return;
+
+ switch (opcode_size)
+ {
+ case 8:
+ {
+ uint8_t value8 = *((uint8_t *) opcode_data);
+ m_opcode.SetOpcode8 (value8);
+ break;
+ }
+ case 16:
+ {
+ uint16_t value16 = *((uint16_t *) opcode_data);
+ m_opcode.SetOpcode16 (value16);
+ break;
+ }
+ case 32:
+ {
+ uint32_t value32 = *((uint32_t *) opcode_data);
+ m_opcode.SetOpcode32 (value32);
+ break;
+ }
+ case 64:
+ {
+ uint64_t value64 = *((uint64_t *) opcode_data);
+ m_opcode.SetOpcode64 (value64);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void
+PseudoInstruction::SetDescription (const char *description)
+{
+ if (description && strlen (description) > 0)
+ m_description = description;
+}
diff --git a/source/Core/DynamicLoader.cpp b/source/Core/DynamicLoader.cpp
new file mode 100644
index 000000000000..82f84048b32a
--- /dev/null
+++ b/source/Core/DynamicLoader.cpp
@@ -0,0 +1,76 @@
+//===-- DynamicLoader.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/DynamicLoader.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicLoader*
+DynamicLoader::FindPlugin (Process *process, const char *plugin_name)
+{
+ DynamicLoaderCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ ConstString const_plugin_name(plugin_name);
+ create_callback = PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ std::unique_ptr<DynamicLoader> instance_ap(create_callback(process, true));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetDynamicLoaderCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<DynamicLoader> instance_ap(create_callback(process, false));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// DynamicLoader constructor
+//----------------------------------------------------------------------
+DynamicLoader::DynamicLoader(Process *process) :
+ m_process (process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoader::~DynamicLoader()
+{
+}
+
+//----------------------------------------------------------------------
+// Accessosors to the global setting as to whether to stop at image
+// (shared library) loading/unloading.
+//----------------------------------------------------------------------
+bool
+DynamicLoader::GetStopWhenImagesChange () const
+{
+ return m_process->GetStopOnSharedLibraryEvents();
+}
+
+void
+DynamicLoader::SetStopWhenImagesChange (bool stop)
+{
+ m_process->SetStopOnSharedLibraryEvents (stop);
+}
+
diff --git a/source/Core/EmulateInstruction.cpp b/source/Core/EmulateInstruction.cpp
new file mode 100644
index 000000000000..bf6c6d88b563
--- /dev/null
+++ b/source/Core/EmulateInstruction.cpp
@@ -0,0 +1,670 @@
+//===-- EmulateInstruction.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/Core/EmulateInstruction.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+EmulateInstruction*
+EmulateInstruction::FindPlugin (const ArchSpec &arch, InstructionType supported_inst_type, const char *plugin_name)
+{
+ EmulateInstructionCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ ConstString const_plugin_name (plugin_name);
+ create_callback = PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
+ if (emulate_insn_ptr)
+ return emulate_insn_ptr;
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetEmulateInstructionCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ EmulateInstruction *emulate_insn_ptr = create_callback(arch, supported_inst_type);
+ if (emulate_insn_ptr)
+ return emulate_insn_ptr;
+ }
+ }
+ return NULL;
+}
+
+EmulateInstruction::EmulateInstruction (const ArchSpec &arch) :
+ m_arch (arch),
+ m_baton (NULL),
+ m_read_mem_callback (&ReadMemoryDefault),
+ m_write_mem_callback (&WriteMemoryDefault),
+ m_read_reg_callback (&ReadRegisterDefault),
+ m_write_reg_callback (&WriteRegisterDefault),
+ m_addr (LLDB_INVALID_ADDRESS)
+{
+ ::memset (&m_opcode, 0, sizeof (m_opcode));
+}
+
+
+bool
+EmulateInstruction::ReadRegister (const RegisterInfo *reg_info, RegisterValue& reg_value)
+{
+ if (m_read_reg_callback)
+ return m_read_reg_callback (this, m_baton, reg_info, reg_value);
+ return false;
+}
+
+bool
+EmulateInstruction::ReadRegister (uint32_t reg_kind, uint32_t reg_num, RegisterValue& reg_value)
+{
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ return ReadRegister (&reg_info, reg_value);
+ return false;
+}
+
+uint64_t
+EmulateInstruction::ReadRegisterUnsigned (uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t fail_value,
+ bool *success_ptr)
+{
+ RegisterValue reg_value;
+ if (ReadRegister (reg_kind, reg_num, reg_value))
+ return reg_value.GetAsUInt64(fail_value, success_ptr);
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+EmulateInstruction::ReadRegisterUnsigned (const RegisterInfo *reg_info,
+ uint64_t fail_value,
+ bool *success_ptr)
+{
+ RegisterValue reg_value;
+ if (ReadRegister (reg_info, reg_value))
+ return reg_value.GetAsUInt64(fail_value, success_ptr);
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+bool
+EmulateInstruction::WriteRegister (const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue& reg_value)
+{
+ if (m_write_reg_callback)
+ return m_write_reg_callback (this, m_baton, context, reg_info, reg_value);
+ return false;
+}
+
+bool
+EmulateInstruction::WriteRegister (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ const RegisterValue& reg_value)
+{
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ return WriteRegister (context, &reg_info, reg_value);
+ return false;
+}
+
+
+bool
+EmulateInstruction::WriteRegisterUnsigned (const Context &context,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ uint64_t uint_value)
+{
+
+ RegisterInfo reg_info;
+ if (GetRegisterInfo(reg_kind, reg_num, reg_info))
+ {
+ RegisterValue reg_value;
+ if (reg_value.SetUInt(uint_value, reg_info.byte_size))
+ return WriteRegister (context, &reg_info, reg_value);
+ }
+ return false;
+}
+
+bool
+EmulateInstruction::WriteRegisterUnsigned (const Context &context,
+ const RegisterInfo *reg_info,
+ uint64_t uint_value)
+{
+
+ if (reg_info)
+ {
+ RegisterValue reg_value;
+ if (reg_value.SetUInt(uint_value, reg_info->byte_size))
+ return WriteRegister (context, reg_info, reg_value);
+ }
+ return false;
+}
+
+size_t
+EmulateInstruction::ReadMemory (const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ if (m_read_mem_callback)
+ return m_read_mem_callback (this, m_baton, context, addr, dst, dst_len) == dst_len;
+ return false;
+}
+
+uint64_t
+EmulateInstruction::ReadMemoryUnsigned (const Context &context, lldb::addr_t addr, size_t byte_size, uint64_t fail_value, bool *success_ptr)
+{
+ uint64_t uval64 = 0;
+ bool success = false;
+ if (byte_size <= 8)
+ {
+ uint8_t buf[sizeof(uint64_t)];
+ size_t bytes_read = m_read_mem_callback (this, m_baton, context, addr, buf, byte_size);
+ if (bytes_read == byte_size)
+ {
+ lldb::offset_t offset = 0;
+ DataExtractor data (buf, byte_size, GetByteOrder(), GetAddressByteSize());
+ uval64 = data.GetMaxU64 (&offset, byte_size);
+ success = true;
+ }
+ }
+
+ if (success_ptr)
+ *success_ptr = success;
+
+ if (!success)
+ uval64 = fail_value;
+ return uval64;
+}
+
+
+bool
+EmulateInstruction::WriteMemoryUnsigned (const Context &context,
+ lldb::addr_t addr,
+ uint64_t uval,
+ size_t uval_byte_size)
+{
+ StreamString strm(Stream::eBinary, GetAddressByteSize(), GetByteOrder());
+ strm.PutMaxHex64 (uval, uval_byte_size);
+
+ size_t bytes_written = m_write_mem_callback (this, m_baton, context, addr, strm.GetData(), uval_byte_size);
+ if (bytes_written == uval_byte_size)
+ return true;
+ return false;
+}
+
+bool
+EmulateInstruction::WriteMemory (const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len)
+{
+ if (m_write_mem_callback)
+ return m_write_mem_callback (this, m_baton, context, addr, src, src_len) == src_len;
+ return false;
+}
+
+
+void
+EmulateInstruction::SetBaton (void *baton)
+{
+ m_baton = baton;
+}
+
+void
+EmulateInstruction::SetCallbacks (ReadMemoryCallback read_mem_callback,
+ WriteMemoryCallback write_mem_callback,
+ ReadRegisterCallback read_reg_callback,
+ WriteRegisterCallback write_reg_callback)
+{
+ m_read_mem_callback = read_mem_callback;
+ m_write_mem_callback = write_mem_callback;
+ m_read_reg_callback = read_reg_callback;
+ m_write_reg_callback = write_reg_callback;
+}
+
+void
+EmulateInstruction::SetReadMemCallback (ReadMemoryCallback read_mem_callback)
+{
+ m_read_mem_callback = read_mem_callback;
+}
+
+
+void
+EmulateInstruction::SetWriteMemCallback (WriteMemoryCallback write_mem_callback)
+{
+ m_write_mem_callback = write_mem_callback;
+}
+
+
+void
+EmulateInstruction::SetReadRegCallback (ReadRegisterCallback read_reg_callback)
+{
+ m_read_reg_callback = read_reg_callback;
+}
+
+
+void
+EmulateInstruction::SetWriteRegCallback (WriteRegisterCallback write_reg_callback)
+{
+ m_write_reg_callback = write_reg_callback;
+}
+
+
+
+//
+// Read & Write Memory and Registers callback functions.
+//
+
+size_t
+EmulateInstruction::ReadMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ if (!baton || dst == NULL || dst_len == 0)
+ return 0;
+
+ StackFrame *frame = (StackFrame *) baton;
+
+ ProcessSP process_sp (frame->CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ return process_sp->ReadMemory (addr, dst, dst_len, error);
+ }
+ return 0;
+}
+
+size_t
+EmulateInstruction::WriteMemoryFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *src,
+ size_t src_len)
+{
+ if (!baton || src == NULL || src_len == 0)
+ return 0;
+
+ StackFrame *frame = (StackFrame *) baton;
+
+ ProcessSP process_sp (frame->CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ return process_sp->WriteMemory (addr, src, src_len, error);
+ }
+
+ return 0;
+}
+
+bool
+EmulateInstruction::ReadRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ if (!baton)
+ return false;
+
+ StackFrame *frame = (StackFrame *) baton;
+ return frame->GetRegisterContext()->ReadRegister (reg_info, reg_value);
+}
+
+bool
+EmulateInstruction::WriteRegisterFrame (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ if (!baton)
+ return false;
+
+ StackFrame *frame = (StackFrame *) baton;
+ return frame->GetRegisterContext()->WriteRegister (reg_info, reg_value);
+}
+
+size_t
+EmulateInstruction::ReadMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Read from Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length);
+ context.Dump (strm, instruction);
+ strm.EOL();
+ *((uint64_t *) dst) = 0xdeadbeef;
+ return length;
+}
+
+size_t
+EmulateInstruction::WriteMemoryDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Write to Memory (address = 0x%" PRIx64 ", length = %" PRIu64 ", context = ", addr, (uint64_t)length);
+ context.Dump (strm, instruction);
+ strm.EOL();
+ return length;
+}
+
+bool
+EmulateInstruction::ReadRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Read Register (%s)\n", reg_info->name);
+ uint32_t reg_kind, reg_num;
+ if (GetBestRegisterKindAndNumber (reg_info, reg_kind, reg_num))
+ reg_value.SetUInt64((uint64_t)reg_kind << 24 | reg_num);
+ else
+ reg_value.SetUInt64(0);
+
+ return true;
+}
+
+bool
+EmulateInstruction::WriteRegisterDefault (EmulateInstruction *instruction,
+ void *baton,
+ const Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ StreamFile strm (stdout, false);
+ strm.Printf (" Write to Register (name = %s, value = " , reg_info->name);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ strm.PutCString (", context = ");
+ context.Dump (strm, instruction);
+ strm.EOL();
+ return true;
+}
+
+void
+EmulateInstruction::Context::Dump (Stream &strm,
+ EmulateInstruction *instruction) const
+{
+ switch (type)
+ {
+ case eContextReadOpcode:
+ strm.PutCString ("reading opcode");
+ break;
+
+ case eContextImmediate:
+ strm.PutCString ("immediate");
+ break;
+
+ case eContextPushRegisterOnStack:
+ strm.PutCString ("push register");
+ break;
+
+ case eContextPopRegisterOffStack:
+ strm.PutCString ("pop register");
+ break;
+
+ case eContextAdjustStackPointer:
+ strm.PutCString ("adjust sp");
+ break;
+
+ case eContextSetFramePointer:
+ strm.PutCString ("set frame pointer");
+ break;
+
+ case eContextAdjustBaseRegister:
+ strm.PutCString ("adjusting (writing value back to) a base register");
+ break;
+
+ case eContextRegisterPlusOffset:
+ strm.PutCString ("register + offset");
+ break;
+
+ case eContextRegisterStore:
+ strm.PutCString ("store register");
+ break;
+
+ case eContextRegisterLoad:
+ strm.PutCString ("load register");
+ break;
+
+ case eContextRelativeBranchImmediate:
+ strm.PutCString ("relative branch immediate");
+ break;
+
+ case eContextAbsoluteBranchRegister:
+ strm.PutCString ("absolute branch register");
+ break;
+
+ case eContextSupervisorCall:
+ strm.PutCString ("supervisor call");
+ break;
+
+ case eContextTableBranchReadMemory:
+ strm.PutCString ("table branch read memory");
+ break;
+
+ case eContextWriteRegisterRandomBits:
+ strm.PutCString ("write random bits to a register");
+ break;
+
+ case eContextWriteMemoryRandomBits:
+ strm.PutCString ("write random bits to a memory address");
+ break;
+
+ case eContextArithmetic:
+ strm.PutCString ("arithmetic");
+ break;
+
+ case eContextReturnFromException:
+ strm.PutCString ("return from exception");
+ break;
+
+ default:
+ strm.PutCString ("unrecognized context.");
+ break;
+ }
+
+ switch (info_type)
+ {
+ case eInfoTypeRegisterPlusOffset:
+ {
+ strm.Printf (" (reg_plus_offset = %s%+" PRId64 ")",
+ info.RegisterPlusOffset.reg.name,
+ info.RegisterPlusOffset.signed_offset);
+ }
+ break;
+
+ case eInfoTypeRegisterPlusIndirectOffset:
+ {
+ strm.Printf (" (reg_plus_reg = %s + %s)",
+ info.RegisterPlusIndirectOffset.base_reg.name,
+ info.RegisterPlusIndirectOffset.offset_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterToRegisterPlusOffset:
+ {
+ strm.Printf (" (base_and_imm_offset = %s%+" PRId64 ", data_reg = %s)",
+ info.RegisterToRegisterPlusOffset.base_reg.name,
+ info.RegisterToRegisterPlusOffset.offset,
+ info.RegisterToRegisterPlusOffset.data_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterToRegisterPlusIndirectOffset:
+ {
+ strm.Printf (" (base_and_reg_offset = %s + %s, data_reg = %s)",
+ info.RegisterToRegisterPlusIndirectOffset.base_reg.name,
+ info.RegisterToRegisterPlusIndirectOffset.offset_reg.name,
+ info.RegisterToRegisterPlusIndirectOffset.data_reg.name);
+ }
+ break;
+
+ case eInfoTypeRegisterRegisterOperands:
+ {
+ strm.Printf (" (register to register binary op: %s and %s)",
+ info.RegisterRegisterOperands.operand1.name,
+ info.RegisterRegisterOperands.operand2.name);
+ }
+ break;
+
+ case eInfoTypeOffset:
+ strm.Printf (" (signed_offset = %+" PRId64 ")", info.signed_offset);
+ break;
+
+ case eInfoTypeRegister:
+ strm.Printf (" (reg = %s)", info.reg.name);
+ break;
+
+ case eInfoTypeImmediate:
+ strm.Printf (" (unsigned_immediate = %" PRIu64 " (0x%16.16" PRIx64 "))",
+ info.unsigned_immediate,
+ info.unsigned_immediate);
+ break;
+
+ case eInfoTypeImmediateSigned:
+ strm.Printf (" (signed_immediate = %+" PRId64 " (0x%16.16" PRIx64 "))",
+ info.signed_immediate,
+ info.signed_immediate);
+ break;
+
+ case eInfoTypeAddress:
+ strm.Printf (" (address = 0x%" PRIx64 ")", info.address);
+ break;
+
+ case eInfoTypeISAAndImmediate:
+ strm.Printf (" (isa = %u, unsigned_immediate = %u (0x%8.8x))",
+ info.ISAAndImmediate.isa,
+ info.ISAAndImmediate.unsigned_data32,
+ info.ISAAndImmediate.unsigned_data32);
+ break;
+
+ case eInfoTypeISAAndImmediateSigned:
+ strm.Printf (" (isa = %u, signed_immediate = %i (0x%8.8x))",
+ info.ISAAndImmediateSigned.isa,
+ info.ISAAndImmediateSigned.signed_data32,
+ info.ISAAndImmediateSigned.signed_data32);
+ break;
+
+ case eInfoTypeISA:
+ strm.Printf (" (isa = %u)", info.isa);
+ break;
+
+ case eInfoTypeNoArgs:
+ break;
+ }
+}
+
+bool
+EmulateInstruction::SetInstruction (const Opcode &opcode, const Address &inst_addr, Target *target)
+{
+ m_opcode = opcode;
+ m_addr = LLDB_INVALID_ADDRESS;
+ if (inst_addr.IsValid())
+ {
+ if (target)
+ m_addr = inst_addr.GetLoadAddress (target);
+ if (m_addr == LLDB_INVALID_ADDRESS)
+ m_addr = inst_addr.GetFileAddress ();
+ }
+ return true;
+}
+
+bool
+EmulateInstruction::GetBestRegisterKindAndNumber (const RegisterInfo *reg_info,
+ uint32_t &reg_kind,
+ uint32_t &reg_num)
+{
+ // Generic and DWARF should be the two most popular register kinds when
+ // emulating instructions since they are the most platform agnostic...
+ reg_num = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGeneric;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindDWARF];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindDWARF;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindLLDB;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindGCC];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGCC;
+ return true;
+ }
+
+ reg_num = reg_info->kinds[eRegisterKindGDB];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ reg_kind = eRegisterKindGDB;
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+EmulateInstruction::GetInternalRegisterNumber (RegisterContext *reg_ctx, const RegisterInfo &reg_info)
+{
+ uint32_t reg_kind, reg_num;
+ if (reg_ctx && GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
+ return reg_ctx->ConvertRegisterKindToRegisterNumber (reg_kind, reg_num);
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+EmulateInstruction::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ return false;
+}
+
+
diff --git a/source/Core/Error.cpp b/source/Core/Error.cpp
new file mode 100644
index 000000000000..e29f12f0b2cd
--- /dev/null
+++ b/source/Core/Error.cpp
@@ -0,0 +1,399 @@
+//===-- Error.cpp -----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "llvm/ADT/SmallVector.h"
+#include <cstdarg>
+#include <cstdlib>
+#include <cstring>
+
+#if defined (__arm__) && defined (__APPLE__)
+#include <SpringBoardServices/SpringBoardServer.h>
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+Error::Error ():
+ m_code (0),
+ m_type (eErrorTypeInvalid),
+ m_string ()
+{
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Error::Error(ValueType err, ErrorType type) :
+ m_code (err),
+ m_type (type),
+ m_string ()
+{
+}
+
+Error::Error (const Error &rhs) :
+ m_code (rhs.m_code),
+ m_type (rhs.m_type),
+ m_string (rhs.m_string)
+{
+}
+
+Error::Error (const char* err_str):
+ m_code (0),
+ m_type (eErrorTypeInvalid),
+ m_string ()
+{
+ SetErrorString(err_str);
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error&
+Error::operator = (const Error& rhs)
+{
+ if (this != &rhs)
+ {
+ m_code = rhs.m_code;
+ m_type = rhs.m_type;
+ m_string = rhs.m_string;
+ }
+ return *this;
+}
+
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const Error&
+Error::operator = (uint32_t err)
+{
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+ return *this;
+}
+
+Error::~Error()
+{
+}
+
+//----------------------------------------------------------------------
+// Get the error value as a NULL C string. The error string will be
+// fetched and cached on demand. The cached error string value will
+// remain until the error value is changed or cleared.
+//----------------------------------------------------------------------
+const char *
+Error::AsCString(const char *default_error_str) const
+{
+ if (Success())
+ return NULL;
+
+ if (m_string.empty())
+ {
+ const char *s = NULL;
+ switch (m_type)
+ {
+ case eErrorTypeMachKernel:
+#if defined (__APPLE__)
+ s = ::mach_error_string (m_code);
+#endif
+ break;
+
+ case eErrorTypePOSIX:
+ s = ::strerror (m_code);
+ break;
+
+ default:
+ break;
+ }
+ if (s)
+ m_string.assign(s);
+ }
+ if (m_string.empty())
+ {
+ if (default_error_str)
+ m_string.assign(default_error_str);
+ else
+ return NULL; // User wanted a NULL string back...
+ }
+ return m_string.c_str();
+}
+
+
+//----------------------------------------------------------------------
+// Clear the error and any cached error string that it might contain.
+//----------------------------------------------------------------------
+void
+Error::Clear ()
+{
+ m_code = 0;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Access the error value.
+//----------------------------------------------------------------------
+Error::ValueType
+Error::GetError () const
+{
+ return m_code;
+}
+
+//----------------------------------------------------------------------
+// Access the error type.
+//----------------------------------------------------------------------
+ErrorType
+Error::GetType () const
+{
+ return m_type;
+}
+
+//----------------------------------------------------------------------
+// Retuns true if this object contains an value that describes an
+// error or otherwise non-success result.
+//----------------------------------------------------------------------
+bool
+Error::Fail () const
+{
+ return m_code != 0;
+}
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging always occurs even when the error
+// code contains a non-error value.
+//----------------------------------------------------------------------
+void
+Error::PutToLog (Log *log, const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ if (Fail())
+ {
+ const char *err_str = AsCString();
+ if (err_str == NULL)
+ err_str = "???";
+
+ SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+ if (log)
+ log->Error("%s", m_string.c_str());
+ }
+ else
+ {
+ if (log)
+ log->Printf("%s err = 0x%8.8x", arg_msg, m_code);
+ }
+ ::free (arg_msg);
+ }
+}
+
+//----------------------------------------------------------------------
+// Log the error given a string with format. If the this object
+// contains an error code, update the error string to contain the
+// "error: " followed by the formatted string, followed by the error
+// value and any string that describes the current error. This
+// allows more context to be given to an error string that remains
+// cached in this object. Logging only occurs even when the error
+// code contains a error value.
+//----------------------------------------------------------------------
+void
+Error::LogIfError (Log *log, const char *format, ...)
+{
+ if (Fail())
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ const char *err_str = AsCString();
+ if (err_str == NULL)
+ err_str = "???";
+
+ SetErrorStringWithFormat("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_code);
+ if (log)
+ log->Error("%s", m_string.c_str());
+
+ ::free (arg_msg);
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value to "err" and the type to
+// "eErrorTypeMachKernel"
+//----------------------------------------------------------------------
+void
+Error::SetMachError (uint32_t err)
+{
+ m_code = err;
+ m_type = eErrorTypeMachKernel;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accesssor for the error value and type.
+//----------------------------------------------------------------------
+void
+Error::SetError (ValueType err, ErrorType type)
+{
+ m_code = err;
+ m_type = type;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be "errno" and update the type to
+// be "POSIX".
+//----------------------------------------------------------------------
+void
+Error::SetErrorToErrno()
+{
+ m_code = errno;
+ m_type = eErrorTypePOSIX;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Update the error value to be LLDB_GENERIC_ERROR and update the type
+// to be "Generic".
+//----------------------------------------------------------------------
+void
+Error::SetErrorToGenericError ()
+{
+ m_code = LLDB_GENERIC_ERROR;
+ m_type = eErrorTypeGeneric;
+ m_string.clear();
+}
+
+//----------------------------------------------------------------------
+// Set accessor for the error string value for a specific error.
+// This allows any string to be supplied as an error explanation.
+// The error string value will remain until the error value is
+// cleared or a new error value/type is assigned.
+//----------------------------------------------------------------------
+void
+Error::SetErrorString (const char *err_str)
+{
+ if (err_str && err_str[0])
+ {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+ m_string = err_str;
+ }
+ else
+ m_string.clear();
+}
+
+//------------------------------------------------------------------
+/// Set the current error string to a formatted error string.
+///
+/// @param format
+/// A printf style format string
+//------------------------------------------------------------------
+int
+Error::SetErrorStringWithFormat (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ va_list args;
+ va_start (args, format);
+ int length = SetErrorStringWithVarArg (format, args);
+ va_end (args);
+ return length;
+ }
+ else
+ {
+ m_string.clear();
+ }
+ return 0;
+}
+
+int
+Error::SetErrorStringWithVarArg (const char *format, va_list args)
+{
+ if (format && format[0])
+ {
+ // If we have an error string, we should always at least have
+ // an error set to a generic value.
+ if (Success())
+ SetErrorToGenericError();
+
+ // Try and fit our error into a 1024 byte buffer first...
+ llvm::SmallVector<char, 1024> buf;
+ buf.resize(1024);
+ // Copy in case our first call to vsnprintf doesn't fit into our
+ // allocated buffer above
+ va_list copy_args;
+ va_copy (copy_args, args);
+ unsigned length = ::vsnprintf (buf.data(), buf.size(), format, args);
+ if (length >= buf.size())
+ {
+ // The error formatted string didn't fit into our buffer, resize it
+ // to the exact needed size, and retry
+ buf.resize(length + 1);
+ length = ::vsnprintf (buf.data(), buf.size(), format, copy_args);
+ va_end (copy_args);
+ assert (length < buf.size());
+ }
+ m_string.assign(buf.data(), length);
+ va_end (args);
+ return length;
+ }
+ else
+ {
+ m_string.clear();
+ }
+ return 0;
+}
+
+
+//----------------------------------------------------------------------
+// Returns true if the error code in this object is considered a
+// successful return value.
+//----------------------------------------------------------------------
+bool
+Error::Success() const
+{
+ return m_code == 0;
+}
+
+bool
+Error::WasInterrupted() const
+{
+ if (m_type == eErrorTypePOSIX && m_code == EINTR)
+ return true;
+ else
+ return false;
+}
+
diff --git a/source/Core/Event.cpp b/source/Core/Event.cpp
new file mode 100644
index 000000000000..2d4899dd6dcb
--- /dev/null
+++ b/source/Core/Event.cpp
@@ -0,0 +1,225 @@
+//===-- Event.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/Core/Event.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Target/Process.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Event constructor
+//----------------------------------------------------------------------
+Event::Event (Broadcaster *broadcaster, uint32_t event_type, EventData *data) :
+ m_broadcaster (broadcaster),
+ m_type (event_type),
+ m_data_ap (data)
+{
+}
+
+Event::Event(uint32_t event_type, EventData *data) :
+ m_broadcaster (NULL), // Set by the broadcaster when this event gets broadcast
+ m_type (event_type),
+ m_data_ap (data)
+{
+}
+
+
+//----------------------------------------------------------------------
+// Event destructor
+//----------------------------------------------------------------------
+Event::~Event ()
+{
+}
+
+void
+Event::Dump (Stream *s) const
+{
+ if (m_broadcaster)
+ {
+ StreamString event_name;
+ if (m_broadcaster->GetEventNames (event_name, m_type, false))
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x (%s), data = ",
+ this,
+ m_broadcaster,
+ m_broadcaster->GetBroadcasterName().GetCString(),
+ m_type,
+ event_name.GetString().c_str());
+ else
+ s->Printf("%p Event: broadcaster = %p (%s), type = 0x%8.8x, data = ",
+ this,
+ m_broadcaster,
+ m_broadcaster->GetBroadcasterName().GetCString(),
+ m_type);
+ }
+ else
+ s->Printf("%p Event: broadcaster = NULL, type = 0x%8.8x, data = ", this, m_type);
+
+ if (m_data_ap.get() == NULL)
+ s->Printf ("<NULL>");
+ else
+ {
+ s->PutChar('{');
+ m_data_ap->Dump (s);
+ s->PutChar('}');
+ }
+}
+
+void
+Event::DoOnRemoval ()
+{
+ if (m_data_ap.get())
+ m_data_ap->DoOnRemoval (this);
+}
+
+EventData::EventData()
+{
+}
+
+EventData::~EventData()
+{
+}
+
+void
+EventData::Dump (Stream *s) const
+{
+ s->PutCString ("Generic Event Data");
+}
+
+EventDataBytes::EventDataBytes () :
+ m_bytes()
+{
+}
+
+EventDataBytes::EventDataBytes (const char *cstr) :
+ m_bytes()
+{
+ SetBytesFromCString (cstr);
+}
+
+EventDataBytes::EventDataBytes (const void *src, size_t src_len) :
+ m_bytes()
+{
+ SetBytes (src, src_len);
+}
+
+EventDataBytes::~EventDataBytes()
+{
+}
+
+const ConstString &
+EventDataBytes::GetFlavorString ()
+{
+ static ConstString g_flavor ("EventDataBytes");
+ return g_flavor;
+}
+
+const ConstString &
+EventDataBytes::GetFlavor () const
+{
+ return EventDataBytes::GetFlavorString ();
+}
+
+void
+EventDataBytes::Dump (Stream *s) const
+{
+ size_t num_printable_chars = std::count_if (m_bytes.begin(), m_bytes.end(), isprint);
+ if (num_printable_chars == m_bytes.size())
+ {
+ s->Printf("\"%s\"", m_bytes.c_str());
+ }
+ else if (m_bytes.size() > 0)
+ {
+ DataExtractor data;
+ data.SetData(&m_bytes[0], m_bytes.size(), lldb::endian::InlHostByteOrder());
+ data.Dump(s, 0, eFormatBytes, 1, m_bytes.size(), 32, LLDB_INVALID_ADDRESS, 0, 0);
+ }
+}
+
+const void *
+EventDataBytes::GetBytes() const
+{
+ if (m_bytes.empty())
+ return NULL;
+ return &m_bytes[0];
+}
+
+size_t
+EventDataBytes::GetByteSize() const
+{
+ return m_bytes.size ();
+}
+
+void
+EventDataBytes::SetBytes (const void *src, size_t src_len)
+{
+ if (src && src_len > 0)
+ m_bytes.assign ((const char *)src, src_len);
+ else
+ m_bytes.clear();
+}
+
+void
+EventDataBytes::SetBytesFromCString (const char *cstr)
+{
+ if (cstr && cstr[0])
+ m_bytes.assign (cstr);
+ else
+ m_bytes.clear();
+}
+
+
+const void *
+EventDataBytes::GetBytesFromEvent (const Event *event_ptr)
+{
+ const EventDataBytes *e = GetEventDataFromEvent (event_ptr);
+ if (e)
+ return e->GetBytes();
+ return NULL;
+}
+
+size_t
+EventDataBytes::GetByteSizeFromEvent (const Event *event_ptr)
+{
+ const EventDataBytes *e = GetEventDataFromEvent (event_ptr);
+ if (e)
+ return e->GetByteSize();
+ return 0;
+}
+
+const EventDataBytes *
+EventDataBytes::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == EventDataBytes::GetFlavorString())
+ return static_cast <const EventDataBytes *> (event_data);
+ }
+ return NULL;
+}
+
+void
+EventDataBytes::SwapBytes (std::string &new_bytes)
+{
+ m_bytes.swap (new_bytes);
+}
+
+
diff --git a/source/Core/FileLineResolver.cpp b/source/Core/FileLineResolver.cpp
new file mode 100644
index 000000000000..15cbbe6ff9e2
--- /dev/null
+++ b/source/Core/FileLineResolver.cpp
@@ -0,0 +1,117 @@
+//===-- FileLineResolver.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/FileLineResolver.h"
+
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// FileLineResolver:
+//----------------------------------------------------------------------
+FileLineResolver::FileLineResolver
+(
+ const FileSpec &file_spec,
+ uint32_t line_no,
+ bool check_inlines
+) :
+ Searcher (),
+ m_file_spec (file_spec),
+ m_line_number (line_no),
+ m_inlines (check_inlines)
+{
+}
+
+FileLineResolver::~FileLineResolver ()
+{
+}
+
+Searcher::CallbackReturn
+FileLineResolver::SearchCallback
+(
+ SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing
+)
+{
+ CompileUnit *cu = context.comp_unit;
+
+ if (m_inlines || m_file_spec.Compare(*cu, m_file_spec, m_file_spec.GetDirectory()))
+ {
+ uint32_t start_file_idx = 0;
+ uint32_t file_idx = cu->GetSupportFiles().FindFileIndex(start_file_idx, m_file_spec, false);
+ if (file_idx != UINT32_MAX)
+ {
+ LineTable *line_table = cu->GetLineTable();
+ if (line_table)
+ {
+ if (m_line_number == 0)
+ {
+ // Match all lines in a file...
+ const bool append = true;
+ while (file_idx != UINT32_MAX)
+ {
+ line_table->FineLineEntriesForFileIndex (file_idx, append, m_sc_list);
+ // Get the next file index in case we have multiple file
+ // entries for the same file
+ file_idx = cu->GetSupportFiles().FindFileIndex(file_idx + 1, m_file_spec, false);
+ }
+ }
+ else
+ {
+ // Match a specific line in a file...
+ }
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::Depth
+FileLineResolver::GetDepth()
+{
+ return Searcher::eDepthCompUnit;
+}
+
+void
+FileLineResolver::GetDescription (Stream *s)
+{
+ s->Printf ("File and line resolver for file: \"%s\" line: %u",
+ m_file_spec.GetPath().c_str(),
+ m_line_number);
+}
+
+void
+FileLineResolver::Clear()
+{
+ m_file_spec.Clear();
+ m_line_number = UINT32_MAX;
+ m_sc_list.Clear();
+ m_inlines = true;
+}
+
+void
+FileLineResolver::Reset (const FileSpec &file_spec,
+ uint32_t line,
+ bool check_inlines)
+{
+ m_file_spec = file_spec;
+ m_line_number = line;
+ m_sc_list.Clear();
+ m_inlines = check_inlines;
+}
+
diff --git a/source/Core/FileSpecList.cpp b/source/Core/FileSpecList.cpp
new file mode 100644
index 000000000000..0cec8faa6bc4
--- /dev/null
+++ b/source/Core/FileSpecList.cpp
@@ -0,0 +1,234 @@
+//===-- FileSpecList.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/FileSpecList.h"
+#include "lldb/Core/Stream.h"
+#include <algorithm>
+
+using namespace lldb_private;
+using namespace std;
+
+//------------------------------------------------------------------
+// Default constructor
+//------------------------------------------------------------------
+FileSpecList::FileSpecList() :
+ m_files()
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpecList::FileSpecList(const FileSpecList& rhs) :
+ m_files(rhs.m_files)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+FileSpecList::~FileSpecList()
+{
+}
+
+//------------------------------------------------------------------
+// Assignment operator
+//------------------------------------------------------------------
+const FileSpecList&
+FileSpecList::operator= (const FileSpecList& rhs)
+{
+ if (this != &rhs)
+ m_files = rhs.m_files;
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Append the "file_spec" to the end of the file spec list.
+//------------------------------------------------------------------
+void
+FileSpecList::Append(const FileSpec &file_spec)
+{
+ m_files.push_back(file_spec);
+}
+
+//------------------------------------------------------------------
+// Only append the "file_spec" if this list doesn't already contain
+// it.
+//
+// Returns true if "file_spec" was added, false if this list already
+// contained a copy of "file_spec".
+//------------------------------------------------------------------
+bool
+FileSpecList::AppendIfUnique(const FileSpec &file_spec)
+{
+ collection::iterator pos, end = m_files.end();
+ if (find(m_files.begin(), end, file_spec) == end)
+ {
+ m_files.push_back(file_spec);
+ return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------
+// Clears the file list.
+//------------------------------------------------------------------
+void
+FileSpecList::Clear()
+{
+ m_files.clear();
+}
+
+//------------------------------------------------------------------
+// Dumps the file list to the supplied stream pointer "s".
+//------------------------------------------------------------------
+void
+FileSpecList::Dump(Stream *s, const char *separator_cstr) const
+{
+ collection::const_iterator pos, end = m_files.end();
+ for (pos = m_files.begin(); pos != end; ++pos)
+ {
+ pos->Dump(s);
+ if (separator_cstr && ((pos + 1) != end))
+ s->PutCString(separator_cstr);
+ }
+}
+
+//------------------------------------------------------------------
+// Find the index of the file in the file spec list that matches
+// "file_spec" starting "start_idx" entries into the file spec list.
+//
+// Returns the valid index of the file that matches "file_spec" if
+// it is found, else UINT32_MAX is returned.
+//------------------------------------------------------------------
+size_t
+FileSpecList::FindFileIndex (size_t start_idx, const FileSpec &file_spec, bool full) const
+{
+ const size_t num_files = m_files.size();
+
+ // When looking for files, we will compare only the filename if the
+ // FILE_SPEC argument is empty
+ bool compare_filename_only = file_spec.GetDirectory().IsEmpty();
+
+ for (size_t idx = start_idx; idx < num_files; ++idx)
+ {
+ if (compare_filename_only)
+ {
+ if (m_files[idx].GetFilename() == file_spec.GetFilename())
+ return idx;
+ }
+ else
+ {
+ if (FileSpec::Equal (m_files[idx], file_spec, full))
+ return idx;
+ }
+ }
+
+ // We didn't find the file, return an invalid index
+ return UINT32_MAX;
+}
+
+//------------------------------------------------------------------
+// Returns the FileSpec object at index "idx". If "idx" is out of
+// range, then an empty FileSpec object will be returned.
+//------------------------------------------------------------------
+const FileSpec &
+FileSpecList::GetFileSpecAtIndex(size_t idx) const
+{
+
+ if (idx < m_files.size())
+ return m_files[idx];
+ static FileSpec g_empty_file_spec;
+ return g_empty_file_spec;
+}
+
+const FileSpec *
+FileSpecList::GetFileSpecPointerAtIndex(size_t idx) const
+{
+ if (idx < m_files.size())
+ return &m_files[idx];
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. This
+// returns the size in bytes of this object's member variables and
+// any FileSpec objects its member variables contain, the result
+// doesn't not include the string values for the directories any
+// filenames as those are in shared string pools.
+//------------------------------------------------------------------
+size_t
+FileSpecList::MemorySize () const
+{
+ size_t mem_size = sizeof(FileSpecList);
+ collection::const_iterator pos, end = m_files.end();
+ for (pos = m_files.begin(); pos != end; ++pos)
+ {
+ mem_size += pos->MemorySize();
+ }
+
+ return mem_size;
+}
+
+//------------------------------------------------------------------
+// Return the number of files in the file spec list.
+//------------------------------------------------------------------
+size_t
+FileSpecList::GetSize() const
+{
+ return m_files.size();
+}
+
+size_t
+FileSpecList::GetFilesMatchingPartialPath (const char *path, bool dir_okay, FileSpecList &matches)
+{
+#if 0 // FIXME: Just sketching...
+ matches.Clear();
+ FileSpec path_spec = FileSpec (path);
+ if (path_spec.Exists ())
+ {
+ FileSpec::FileType type = path_spec.GetFileType();
+ if (type == FileSpec::eFileTypeSymbolicLink)
+ // Shouldn't there be a Resolve on a file spec that real-path's it?
+ {
+ }
+
+ if (type == FileSpec::eFileTypeRegular
+ || (type == FileSpec::eFileTypeDirectory && dir_okay))
+ {
+ matches.Append (path_spec);
+ return 1;
+ }
+ else if (type == FileSpec::eFileTypeDirectory)
+ {
+ // Fill the match list with all the files in the directory:
+
+ }
+ else
+ {
+ return 0;
+ }
+
+ }
+ else
+ {
+ ConstString dir_name = path_spec.GetDirectory();
+ Constring file_name = GetFilename();
+ if (dir_name == NULL)
+ {
+ // Match files in the CWD.
+ }
+ else
+ {
+ // Match files in the given directory:
+
+ }
+ }
+#endif
+ return 0;
+}
diff --git a/source/Core/History.cpp b/source/Core/History.cpp
new file mode 100644
index 000000000000..0105dce730d2
--- /dev/null
+++ b/source/Core/History.cpp
@@ -0,0 +1,26 @@
+//===-- History.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/History.h"
+
+// C Includes
+#include <inttypes.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+HistorySourceUInt::DumpHistoryEvent (Stream &strm, HistoryEvent event)
+{
+ strm.Printf ("%s %" PRIu64, m_name.c_str(), (uint64_t)((uintptr_t)event));
+}
diff --git a/source/Core/InputReader.cpp b/source/Core/InputReader.cpp
new file mode 100644
index 000000000000..cbaa671bcba5
--- /dev/null
+++ b/source/Core/InputReader.cpp
@@ -0,0 +1,387 @@
+//===-- InputReader.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 <string>
+
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReader::InputReader (Debugger &debugger) :
+ m_debugger (debugger),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_end_token (),
+ m_granularity (eInputReaderGranularityInvalid),
+ m_done (true),
+ m_echo (true),
+ m_active (false),
+ m_reader_done (false),
+ m_user_input(),
+ m_save_user_input(false)
+{
+}
+
+InputReader::~InputReader ()
+{
+}
+
+Error
+InputReader::Initialize
+(
+ Callback callback,
+ void *baton,
+ lldb::InputReaderGranularity granularity,
+ const char *end_token,
+ const char *prompt,
+ bool echo
+)
+{
+ Error err;
+ m_callback = callback;
+ m_callback_baton = baton,
+ m_granularity = granularity;
+ if (end_token != NULL)
+ m_end_token = end_token;
+ if (prompt != NULL)
+ m_prompt = prompt;
+ m_done = true;
+ m_echo = echo;
+
+ if (m_granularity == eInputReaderGranularityInvalid)
+ {
+ err.SetErrorString ("Invalid read token size: Reader must be initialized with a token size other than 'eInputReaderGranularityInvalid'.");
+ }
+ else
+ if (end_token != NULL && granularity != eInputReaderGranularityInvalid)
+ {
+ if (granularity == eInputReaderGranularityByte)
+ {
+ // Check to see if end_token is longer than one byte.
+
+ if (strlen (end_token) > 1)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (byte).");
+ }
+ }
+ else if (granularity == eInputReaderGranularityWord)
+ {
+ // Check to see if m_end_token contains any white space (i.e. is multiple words).
+
+ const char *white_space = " \t\n";
+ size_t pos = m_end_token.find_first_of (white_space);
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot be larger than specified token size (word).");
+ }
+ }
+ else
+ {
+ // Check to see if m_end_token contains any newlines; cannot handle multi-line end tokens.
+
+ size_t pos = m_end_token.find_first_of ('\n');
+ if (pos != std::string::npos)
+ {
+ err.SetErrorString ("Invalid end token: End token cannot contain a newline.");
+ }
+ }
+ }
+
+ m_done = err.Fail();
+
+ return err;
+}
+
+size_t
+InputReader::HandleRawBytes (const char *bytes, size_t bytes_len)
+{
+ const char *end_token = NULL;
+
+ if (m_end_token.empty() == false)
+ {
+ end_token = ::strstr (bytes, m_end_token.c_str());
+ if (end_token >= bytes + bytes_len)
+ end_token = NULL;
+ }
+
+ const char *p = bytes;
+ const char *end = bytes + bytes_len;
+
+ switch (m_granularity)
+ {
+ case eInputReaderGranularityInvalid:
+ break;
+
+ case eInputReaderGranularityByte:
+ while (p < end)
+ {
+ if (end_token == p)
+ {
+ p += m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ if (m_callback (m_callback_baton, *this, eInputReaderGotToken, p, 1) == 0)
+ break;
+ ++p;
+ if (IsDone())
+ break;
+ }
+ // Return how many bytes were handled.
+ return p - bytes;
+ break;
+
+
+ case eInputReaderGranularityWord:
+ {
+ char quote = '\0';
+ const char *word_start = NULL;
+ bool send_word = false;
+ for (; p < end; ++p, send_word = false)
+ {
+ if (end_token && end_token == p)
+ {
+ m_end_token.size();
+ SetIsDone(true);
+ break;
+ }
+
+ const char ch = *p;
+ if (isspace(ch) && (!quote || (quote == ch && p[-1] != '\\')))
+ {
+ // We have a space character or the terminating quote
+ send_word = word_start != NULL;
+ quote = '\0';
+ }
+ else if (quote)
+ {
+ // We are in the middle of a quoted character
+ continue;
+ }
+ else if (ch == '"' || ch == '\'' || ch == '`')
+ quote = ch;
+ else if (word_start == NULL)
+ {
+ // We have the first character in a word
+ word_start = p;
+ }
+
+ if (send_word)
+ {
+ const size_t word_len = p - word_start;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ word_start,
+ word_len);
+
+ if (bytes_handled != word_len)
+ return word_start - bytes + bytes_handled;
+
+ if (IsDone())
+ return p - bytes;
+ }
+ }
+ }
+ break;
+
+
+ case eInputReaderGranularityLine:
+ {
+ const char *line_start = bytes;
+ const char *end_line = NULL;
+ while (p < end)
+ {
+ const char ch = *p;
+ if (ch == '\n' || ch == '\r')
+ {
+ size_t line_length = p - line_start;
+ // Now skip the newline character
+ ++p;
+ // Skip a complete DOS newline if we run into one
+ if (ch == 0xd && p < end && *p == 0xa)
+ ++p;
+
+ if (line_start <= end_token && end_token < line_start + line_length)
+ {
+ SetIsDone(true);
+ m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ end_token - line_start);
+
+ return p - bytes;
+ }
+
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ line_start,
+ line_length);
+
+ end_line = p;
+
+ if (bytes_handled != line_length)
+ {
+ // The input reader wasn't able to handle all the data
+ return line_start - bytes + bytes_handled;
+ }
+
+
+ if (IsDone())
+ return p - bytes;
+
+ line_start = p;
+ }
+ else
+ {
+ ++p;
+ }
+ }
+
+ if (end_line)
+ return end_line - bytes;
+ }
+ break;
+
+
+ case eInputReaderGranularityAll:
+ {
+ // Nothing should be handle unless we see our end token
+ if (end_token)
+ {
+ size_t length = end_token - bytes;
+ size_t bytes_handled = m_callback (m_callback_baton,
+ *this,
+ eInputReaderGotToken,
+ bytes,
+ length);
+ m_done = true;
+
+ p += bytes_handled + m_end_token.size();
+
+ // Consume any white space, such as newlines, beyond the end token
+
+ while (p < end && isspace(*p))
+ ++p;
+
+ if (bytes_handled != length)
+ return bytes_handled;
+ else
+ {
+ return p - bytes;
+ //return bytes_handled + m_end_token.size();
+ }
+ }
+ return 0;
+ }
+ break;
+ }
+ return 0;
+}
+
+const char *
+InputReader::GetPrompt () const
+{
+ if (!m_prompt.empty())
+ return m_prompt.c_str();
+ else
+ return NULL;
+}
+
+void
+InputReader::RefreshPrompt ()
+{
+ if (m_debugger.GetCommandInterpreter().GetBatchCommandMode())
+ return;
+
+ if (!m_prompt.empty())
+ {
+ File &out_file = m_debugger.GetOutputFile();
+ if (out_file.IsValid())
+ {
+ out_file.Printf ("%s", m_prompt.c_str());
+ out_file.Flush();
+ }
+ }
+}
+
+void
+InputReader::Notify (InputReaderAction notification)
+{
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ case eInputReaderReactivate:
+ m_active = true;
+ m_reader_done.SetValue(false, eBroadcastAlways);
+ break;
+
+ case eInputReaderDeactivate:
+ case eInputReaderDone:
+ m_active = false;
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderInterrupt:
+ case eInputReaderEndOfFile:
+ break;
+
+ case eInputReaderGotToken:
+ return; // We don't notify the tokens here, it is done in HandleRawBytes
+ }
+ if (m_callback)
+ m_callback (m_callback_baton, *this, notification, NULL, 0);
+ if (notification == eInputReaderDone)
+ m_reader_done.SetValue(true, eBroadcastAlways);
+}
+
+void
+InputReader::WaitOnReaderIsDone ()
+{
+ m_reader_done.WaitForValueEqualTo (true);
+}
+
+const char *
+InputReader::GranularityAsCString (lldb::InputReaderGranularity granularity)
+{
+ switch (granularity)
+ {
+ case eInputReaderGranularityInvalid: return "invalid";
+ case eInputReaderGranularityByte: return "byte";
+ case eInputReaderGranularityWord: return "word";
+ case eInputReaderGranularityLine: return "line";
+ case eInputReaderGranularityAll: return "all";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "InputReaderGranularity = %i", granularity);
+ return unknown_state_string;
+}
+
+bool
+InputReader::HandlerData::GetBatchMode()
+{
+ return reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+}
+
+lldb::StreamSP
+InputReader::HandlerData::GetOutStream()
+{
+ return reader.GetDebugger().GetAsyncOutputStream();
+}
diff --git a/source/Core/InputReaderEZ.cpp b/source/Core/InputReaderEZ.cpp
new file mode 100644
index 000000000000..7a865bdc5097
--- /dev/null
+++ b/source/Core/InputReaderEZ.cpp
@@ -0,0 +1,91 @@
+//===-- InputReaderEZ.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/InputReaderEZ.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+InputReaderEZ::Callback_Impl(void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+
+{
+ HandlerData hand_data(reader,
+ bytes,
+ bytes_len,
+ baton);
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ reader.ActivateHandler(hand_data);
+ break;
+ case eInputReaderDeactivate:
+ reader.DeactivateHandler(hand_data);
+ break;
+ case eInputReaderReactivate:
+ reader.ReactivateHandler(hand_data);
+ break;
+ case eInputReaderAsynchronousOutputWritten:
+ reader.AsynchronousOutputWrittenHandler(hand_data);
+ break;
+ case eInputReaderGotToken:
+ {
+ if (reader.GetSaveUserInput())
+ reader.GetUserInput().AppendString(bytes, bytes_len);
+ reader.GotTokenHandler(hand_data);
+ }
+ break;
+ case eInputReaderInterrupt:
+ reader.InterruptHandler(hand_data);
+ break;
+ case eInputReaderEndOfFile:
+ reader.EOFHandler(hand_data);
+ break;
+ case eInputReaderDone:
+ reader.DoneHandler(hand_data);
+ break;
+ }
+ return bytes_len;
+}
+
+Error
+InputReaderEZ::Initialize(void* baton,
+ lldb::InputReaderGranularity token_size,
+ const char* end_token,
+ const char *prompt,
+ bool echo)
+{
+ return InputReader::Initialize(Callback_Impl,
+ baton,
+ token_size,
+ end_token,
+ prompt,
+ echo);
+}
+
+Error
+InputReaderEZ::Initialize(InitializationParameters& params)
+{
+ Error ret = Initialize(params.m_baton,
+ params.m_token_size,
+ params.m_end_token,
+ params.m_prompt,
+ params.m_echo);
+ m_save_user_input = params.m_save_user_input;
+ return ret;
+}
+
+InputReaderEZ::~InputReaderEZ ()
+{
+}
diff --git a/source/Core/InputReaderStack.cpp b/source/Core/InputReaderStack.cpp
new file mode 100644
index 000000000000..764ea26550f7
--- /dev/null
+++ b/source/Core/InputReaderStack.cpp
@@ -0,0 +1,80 @@
+//===-- InputReaderStack.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/InputReaderStack.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+InputReaderStack::InputReaderStack () :
+ m_input_readers (),
+ m_input_readers_mutex (Mutex::eMutexTypeRecursive)
+{
+}
+
+InputReaderStack::~InputReaderStack ()
+{
+}
+
+size_t
+InputReaderStack::GetSize () const
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ return m_input_readers.size();
+}
+
+void
+InputReaderStack::Push (const lldb::InputReaderSP& reader_sp)
+{
+ if (reader_sp)
+ {
+ Mutex::Locker locker (m_input_readers_mutex);
+ m_input_readers.push (reader_sp);
+ }
+}
+
+bool
+InputReaderStack::IsEmpty () const
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ return m_input_readers.empty();
+}
+
+InputReaderSP
+InputReaderStack::Top ()
+{
+ InputReaderSP input_reader_sp;
+ {
+ Mutex::Locker locker (m_input_readers_mutex);
+ if (!m_input_readers.empty())
+ input_reader_sp = m_input_readers.top();
+ }
+
+ return input_reader_sp;
+}
+
+void
+InputReaderStack::Pop ()
+{
+ Mutex::Locker locker (m_input_readers_mutex);
+ if (!m_input_readers.empty())
+ m_input_readers.pop();
+}
+
+Mutex &
+InputReaderStack::GetStackMutex ()
+{
+ return m_input_readers_mutex;
+}
diff --git a/source/Core/Language.cpp b/source/Core/Language.cpp
new file mode 100644
index 000000000000..af62af37da0d
--- /dev/null
+++ b/source/Core/Language.cpp
@@ -0,0 +1,151 @@
+//===-- Language.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/Core/Language.h"
+#include "lldb/Core/Stream.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+#define ENUM_TO_DCSTREAM(x) case x: s->PutCString(#x); return
+
+struct LanguageStrings
+{
+ const char * names[3];
+};
+
+static LanguageStrings
+g_languages[] =
+{
+ { { "unknown" , NULL , NULL } },
+ { { "c89" , NULL , "ISO C:1989" } },
+ { { NULL , NULL , "K&R C" } },
+ { { "ada83" , "Ada83" , "ISO Ada:1983" } },
+ { { "c++" , "cxx" , "ISO C++:1998" } },
+ { { "cobol74" , "Cobol74" , "ISO Cobol:1974" } },
+ { { "cobol" , "Cobol85" , "ISO Cobol:1985." } },
+ { { "f77" , "Fortran77" , "ISO Fortran 77." } },
+ { { "f90" , "Fortran90" , "ISO Fortran 90" } },
+ { { "pascal" , "Pascal83" , "ISO Pascal:1983" } },
+ { { "modula2" , "Modula2" , "ISO Modula-2:1996" } },
+ { { "java" , NULL , "Java" } },
+ { { "c" , "C99" , "ISO C:1999" } },
+ { { "ada" , "Ada95" , "ISO Ada:1995" } },
+ { { "f95" , "Fortran95" , "ISO Fortran 95" } },
+ { { "PLI" , NULL , "ANSI PL/I:1976" } },
+ { { "objc" , NULL , "Objective-C" } },
+ { { "objc++" , NULL , "Objective-C++" } },
+ { { "upc" , NULL , "Unified Parallel C" } },
+ { { "d" , NULL , "D" } },
+ { { "python" , NULL , "Python" } }
+};
+
+static const size_t
+g_num_languages = sizeof(g_languages)/sizeof(LanguageStrings);
+
+Language::Language(LanguageType language) :
+ m_language (language)
+{
+}
+
+Language::~Language()
+{
+}
+
+LanguageType
+Language::GetLanguage() const
+{
+ return m_language;
+}
+
+void
+Language::Clear ()
+{
+ m_language = eLanguageTypeUnknown;
+}
+
+void
+Language::SetLanguage(LanguageType language)
+{
+ m_language = language;
+}
+
+bool
+Language::SetLanguageFromCString(const char *language_cstr)
+{
+ size_t i, desc_idx;
+ const char *name;
+
+ // First check the most common name for the languages
+ for (desc_idx=lldb::eDescriptionLevelBrief; desc_idx<kNumDescriptionLevels; ++desc_idx)
+ {
+ for (i=0; i<g_num_languages; ++i)
+ {
+ name = g_languages[i].names[desc_idx];
+ if (name == NULL)
+ continue;
+
+ if (::strcasecmp (language_cstr, name) == 0)
+ {
+ m_language = (LanguageType)i;
+ return true;
+ }
+ }
+ }
+
+ m_language = eLanguageTypeUnknown;
+ return false;
+}
+
+
+const char *
+Language::AsCString (lldb::DescriptionLevel level) const
+{
+ if (m_language < g_num_languages && level < kNumDescriptionLevels)
+ {
+ const char *name = g_languages[m_language].names[level];
+ if (name)
+ return name;
+ else if (level + 1 < kNumDescriptionLevels)
+ return AsCString ((lldb::DescriptionLevel)(level + 1));
+ else
+ return NULL;
+ }
+ return NULL;
+}
+
+void
+Language::Dump(Stream *s) const
+{
+ GetDescription(s, lldb::eDescriptionLevelVerbose);
+}
+
+void
+Language::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ const char *lang_cstr = AsCString(level);
+
+ if (lang_cstr)
+ s->PutCString(lang_cstr);
+ else
+ s->Printf("Language(language = 0x%4.4x)", m_language);
+}
+
+
+
+
+Stream&
+lldb_private::operator << (Stream& s, const Language& language)
+{
+ language.Dump(&s);
+ return s;
+}
+
diff --git a/source/Core/Listener.cpp b/source/Core/Listener.cpp
new file mode 100644
index 000000000000..aca2b374092e
--- /dev/null
+++ b/source/Core/Listener.cpp
@@ -0,0 +1,557 @@
+//===-- Listener.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/Listener.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/lldb-private-log.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Listener::Listener(const char *name) :
+ m_name (name),
+ m_broadcasters(),
+ m_broadcasters_mutex (Mutex::eMutexTypeRecursive),
+ m_events (),
+ m_events_mutex (Mutex::eMutexTypeRecursive),
+ m_cond_wait()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Listener::Listener('%s')", this, m_name.c_str());
+}
+
+Listener::~Listener()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ Mutex::Locker locker (m_broadcasters_mutex);
+
+ size_t num_managers = m_broadcaster_managers.size();
+
+ for (size_t i = 0; i < num_managers; i++)
+ m_broadcaster_managers[i]->RemoveListener(*this);
+
+ if (log)
+ log->Printf ("%p Listener::~Listener('%s')", this, m_name.c_str());
+ Clear();
+}
+
+void
+Listener::Clear()
+{
+ Mutex::Locker locker(m_broadcasters_mutex);
+ broadcaster_collection::iterator pos, end = m_broadcasters.end();
+ for (pos = m_broadcasters.begin(); pos != end; ++pos)
+ pos->first->RemoveListener (this, pos->second.event_mask);
+ m_broadcasters.clear();
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ m_broadcasters.clear();
+ Mutex::Locker event_locker(m_events_mutex);
+ m_events.clear();
+}
+
+uint32_t
+Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask)
+{
+ if (broadcaster)
+ {
+ // Scope for "locker"
+ // Tell the broadcaster to add this object as a listener
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.insert(std::make_pair(broadcaster, BroadcasterInfo(event_mask)));
+ }
+
+ uint32_t acquired_mask = broadcaster->AddListener (this, event_mask);
+
+ if (event_mask != acquired_mask)
+ {
+
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x) acquired_mask = 0x%8.8x for %s",
+ this,
+ broadcaster,
+ event_mask,
+ acquired_mask,
+ m_name.c_str());
+
+ return acquired_mask;
+
+ }
+ return 0;
+}
+
+uint32_t
+Listener::StartListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask, HandleBroadcastCallback callback, void *callback_user_data)
+{
+ if (broadcaster)
+ {
+ // Scope for "locker"
+ // Tell the broadcaster to add this object as a listener
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.insert(std::make_pair(broadcaster, BroadcasterInfo(event_mask, callback, callback_user_data)));
+ }
+
+ uint32_t acquired_mask = broadcaster->AddListener (this, event_mask);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ log->Printf ("%p Listener::StartListeningForEvents (broadcaster = %p, mask = 0x%8.8x, callback = %p, user_data = %p) acquired_mask = 0x%8.8x for %s",
+ this, broadcaster, event_mask, callback, callback_user_data, acquired_mask, m_name.c_str());
+
+ return acquired_mask;
+ }
+ return 0;
+}
+
+bool
+Listener::StopListeningForEvents (Broadcaster* broadcaster, uint32_t event_mask)
+{
+ if (broadcaster)
+ {
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_broadcasters_mutex);
+ m_broadcasters.erase (broadcaster);
+ }
+ // Remove the broadcaster from our set of broadcasters
+ return broadcaster->RemoveListener (this, event_mask);
+ }
+
+ return false;
+}
+
+// Called when a Broadcaster is in its destuctor. We need to remove all
+// knowledge of this broadcaster and any events that it may have queued up
+void
+Listener::BroadcasterWillDestruct (Broadcaster *broadcaster)
+{
+ // Scope for "broadcasters_locker"
+ {
+ Mutex::Locker broadcasters_locker(m_broadcasters_mutex);
+ m_broadcasters.erase (broadcaster);
+ }
+
+ // Scope for "event_locker"
+ {
+ Mutex::Locker event_locker(m_events_mutex);
+ // Remove all events for this broadcaster object.
+ event_collection::iterator pos = m_events.begin();
+ while (pos != m_events.end())
+ {
+ if ((*pos)->GetBroadcaster() == broadcaster)
+ pos = m_events.erase(pos);
+ else
+ ++pos;
+ }
+
+ if (m_events.empty())
+ m_cond_wait.SetValue (false, eBroadcastNever);
+
+ }
+}
+
+void
+Listener::BroadcasterManagerWillDestruct (BroadcasterManager *manager)
+{
+ // Just need to remove this broadcast manager from the list of managers:
+ broadcaster_manager_collection::iterator iter, end_iter = m_broadcaster_managers.end();
+ iter = find(m_broadcaster_managers.begin(), end_iter, manager);
+ if (iter != end_iter)
+ m_broadcaster_managers.erase (iter);
+}
+
+void
+Listener::AddEvent (EventSP &event_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ if (log)
+ log->Printf ("%p Listener('%s')::AddEvent (event_sp = {%p})", this, m_name.c_str(), event_sp.get());
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_events_mutex);
+ m_events.push_back (event_sp);
+ }
+ m_cond_wait.SetValue (true, eBroadcastAlways);
+}
+
+class EventBroadcasterMatches
+{
+public:
+ EventBroadcasterMatches (Broadcaster *broadcaster) :
+ m_broadcaster (broadcaster) {
+ }
+
+ bool operator() (const EventSP &event_sp) const
+ {
+ if (event_sp->BroadcasterIs(m_broadcaster))
+ return true;
+ else
+ return false;
+ }
+
+private:
+ Broadcaster *m_broadcaster;
+
+};
+
+class EventMatcher
+{
+public:
+ EventMatcher (Broadcaster *broadcaster, const ConstString *broadcaster_names, uint32_t num_broadcaster_names, uint32_t event_type_mask) :
+ m_broadcaster (broadcaster),
+ m_broadcaster_names (broadcaster_names),
+ m_num_broadcaster_names (num_broadcaster_names),
+ m_event_type_mask (event_type_mask)
+ {
+ }
+
+ bool operator() (const EventSP &event_sp) const
+ {
+ if (m_broadcaster && !event_sp->BroadcasterIs(m_broadcaster))
+ return false;
+
+ if (m_broadcaster_names)
+ {
+ bool found_source = false;
+ const ConstString &event_broadcaster_name = event_sp->GetBroadcaster()->GetBroadcasterName();
+ for (uint32_t i=0; i<m_num_broadcaster_names; ++i)
+ {
+ if (m_broadcaster_names[i] == event_broadcaster_name)
+ {
+ found_source = true;
+ break;
+ }
+ }
+ if (!found_source)
+ return false;
+ }
+
+ if (m_event_type_mask == 0 || m_event_type_mask & event_sp->GetType())
+ return true;
+ return false;
+ }
+
+private:
+ Broadcaster *m_broadcaster;
+ const ConstString *m_broadcaster_names;
+ const uint32_t m_num_broadcaster_names;
+ const uint32_t m_event_type_mask;
+};
+
+
+bool
+Listener::FindNextEventInternal
+(
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp,
+ bool remove)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+
+ Mutex::Locker lock(m_events_mutex);
+
+ if (m_events.empty())
+ return false;
+
+
+ Listener::event_collection::iterator pos = m_events.end();
+
+ if (broadcaster == NULL && broadcaster_names == NULL && event_type_mask == 0)
+ {
+ pos = m_events.begin();
+ }
+ else
+ {
+ pos = std::find_if (m_events.begin(), m_events.end(), EventMatcher (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask));
+ }
+
+ if (pos != m_events.end())
+ {
+ event_sp = *pos;
+
+ if (log)
+ log->Printf ("%p '%s' Listener::FindNextEventInternal(broadcaster=%p, broadcaster_names=%p[%u], event_type_mask=0x%8.8x, remove=%i) event %p",
+ this,
+ GetName(),
+ broadcaster,
+ broadcaster_names,
+ num_broadcaster_names,
+ event_type_mask,
+ remove,
+ event_sp.get());
+
+ if (remove)
+ {
+ m_events.erase(pos);
+
+ if (m_events.empty())
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ }
+
+ // Unlock the event queue here. We've removed this event and are about to return
+ // it so it should be okay to get the next event off the queue here - and it might
+ // be useful to do that in the "DoOnRemoval".
+ lock.Unlock();
+
+ // Don't call DoOnRemoval if you aren't removing the event...
+ if (remove)
+ event_sp->DoOnRemoval();
+
+ return true;
+ }
+
+ event_sp.reset();
+ return false;
+}
+
+Event *
+Listener::PeekAtNextEvent ()
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (NULL, NULL, 0, 0, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+Event *
+Listener::PeekAtNextEventForBroadcaster (Broadcaster *broadcaster)
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (broadcaster, NULL, 0, 0, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+Event *
+Listener::PeekAtNextEventForBroadcasterWithType (Broadcaster *broadcaster, uint32_t event_type_mask)
+{
+ EventSP event_sp;
+ if (FindNextEventInternal (broadcaster, NULL, 0, event_type_mask, event_sp, false))
+ return event_sp.get();
+ return NULL;
+}
+
+
+bool
+Listener::GetNextEventInternal
+(
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ return FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, true);
+}
+
+bool
+Listener::GetNextEvent (EventSP &event_sp)
+{
+ return GetNextEventInternal (NULL, NULL, 0, 0, event_sp);
+}
+
+
+bool
+Listener::GetNextEventForBroadcaster (Broadcaster *broadcaster, EventSP &event_sp)
+{
+ return GetNextEventInternal (broadcaster, NULL, 0, 0, event_sp);
+}
+
+bool
+Listener::GetNextEventForBroadcasterWithType (Broadcaster *broadcaster, uint32_t event_type_mask, EventSP &event_sp)
+{
+ return GetNextEventInternal (broadcaster, NULL, 0, event_type_mask, event_sp);
+}
+
+
+bool
+Listener::WaitForEventsInternal
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster, // NULL for any broadcaster
+ const ConstString *broadcaster_names, // NULL for any event
+ uint32_t num_broadcaster_names,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS));
+ bool timed_out = false;
+
+ if (log)
+ {
+ log->Printf ("%p Listener::WaitForEventsInternal (timeout = { %p }) for %s",
+ this, timeout, m_name.c_str());
+ }
+
+ while (1)
+ {
+ // Note, we don't want to lock the m_events_mutex in the call to GetNextEventInternal, since the DoOnRemoval
+ // code might require that new events be serviced. For instance, the Breakpoint Command's
+ if (GetNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp))
+ return true;
+
+ {
+ // Reset condition value to false, so we can wait for new events to be
+ // added that might meet our current filter
+ // But first poll for any new event that might satisfy our condition, and if so consume it,
+ // otherwise wait.
+
+ Mutex::Locker event_locker(m_events_mutex);
+ const bool remove = false;
+ if (FindNextEventInternal (broadcaster, broadcaster_names, num_broadcaster_names, event_type_mask, event_sp, remove))
+ continue;
+ else
+ m_cond_wait.SetValue (false, eBroadcastNever);
+ }
+
+ if (m_cond_wait.WaitForValueEqualTo (true, timeout, &timed_out))
+ continue;
+
+ else if (timed_out)
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ log->Printf ("%p Listener::WaitForEventsInternal() timed out for %s", this, m_name.c_str());
+ break;
+ }
+ else
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EVENTS);
+ if (log)
+ log->Printf ("%p Listener::WaitForEventsInternal() unknown error for %s", this, m_name.c_str());
+ break;
+ }
+ }
+
+ return false;
+}
+
+bool
+Listener::WaitForEventForBroadcasterWithType
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ uint32_t event_type_mask,
+ EventSP &event_sp
+)
+{
+ return WaitForEventsInternal (timeout, broadcaster, NULL, 0, event_type_mask, event_sp);
+}
+
+bool
+Listener::WaitForEventForBroadcaster
+(
+ const TimeValue *timeout,
+ Broadcaster *broadcaster,
+ EventSP &event_sp
+)
+{
+ return WaitForEventsInternal (timeout, broadcaster, NULL, 0, 0, event_sp);
+}
+
+bool
+Listener::WaitForEvent (const TimeValue *timeout, EventSP &event_sp)
+{
+ return WaitForEventsInternal (timeout, NULL, NULL, 0, 0, event_sp);
+}
+
+//Listener::broadcaster_collection::iterator
+//Listener::FindBroadcasterWithMask (Broadcaster *broadcaster, uint32_t event_mask, bool exact)
+//{
+// broadcaster_collection::iterator pos;
+// broadcaster_collection::iterator end = m_broadcasters.end();
+// for (pos = m_broadcasters.find (broadcaster);
+// pos != end && pos->first == broadcaster;
+// ++pos)
+// {
+// if (exact)
+// {
+// if ((event_mask & pos->second.event_mask) == event_mask)
+// return pos;
+// }
+// else
+// {
+// if (event_mask & pos->second.event_mask)
+// return pos;
+// }
+// }
+// return end;
+//}
+
+size_t
+Listener::HandleBroadcastEvent (EventSP &event_sp)
+{
+ size_t num_handled = 0;
+ Mutex::Locker locker(m_broadcasters_mutex);
+ Broadcaster *broadcaster = event_sp->GetBroadcaster();
+ broadcaster_collection::iterator pos;
+ broadcaster_collection::iterator end = m_broadcasters.end();
+ for (pos = m_broadcasters.find (broadcaster);
+ pos != end && pos->first == broadcaster;
+ ++pos)
+ {
+ BroadcasterInfo info = pos->second;
+ if (event_sp->GetType () & info.event_mask)
+ {
+ if (info.callback != NULL)
+ {
+ info.callback (event_sp, info.callback_user_data);
+ ++num_handled;
+ }
+ }
+ }
+ return num_handled;
+}
+
+uint32_t
+Listener::StartListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec)
+{
+ // The BroadcasterManager mutex must be locked before m_broadcasters_mutex
+ // to avoid violating the lock hierarchy (manager before broadcasters).
+ Mutex::Locker manager_locker(manager.m_manager_mutex);
+ Mutex::Locker locker(m_broadcasters_mutex);
+
+ uint32_t bits_acquired = manager.RegisterListenerForEvents(*this, event_spec);
+ if (bits_acquired)
+ m_broadcaster_managers.push_back(&manager);
+
+ return bits_acquired;
+}
+
+bool
+Listener::StopListeningForEventSpec (BroadcasterManager &manager,
+ const BroadcastEventSpec &event_spec)
+{
+ Mutex::Locker locker(m_broadcasters_mutex);
+ return manager.UnregisterListenerForEvents (*this, event_spec);
+
+}
+
+
diff --git a/source/Core/Log.cpp b/source/Core/Log.cpp
new file mode 100644
index 000000000000..d73ab15f697a
--- /dev/null
+++ b/source/Core/Log.cpp
@@ -0,0 +1,529 @@
+//===-- Log.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"
+
+// C Includes
+#include <pthread.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+// C++ Includes
+#include <map>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#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/Interpreter/Args.h"
+using namespace lldb;
+using namespace lldb_private;
+
+Log::Log () :
+ m_stream_sp(),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::Log (const StreamSP &stream_sp) :
+ m_stream_sp(stream_sp),
+ m_options(0),
+ m_mask_bits(0)
+{
+}
+
+Log::~Log ()
+{
+}
+
+Flags &
+Log::GetOptions()
+{
+ return m_options;
+}
+
+const Flags &
+Log::GetOptions() const
+{
+ return m_options;
+}
+
+Flags &
+Log::GetMask()
+{
+ return m_mask_bits;
+}
+
+const Flags &
+Log::GetMask() const
+{
+ return m_mask_bits;
+}
+
+
+//----------------------------------------------------------------------
+// All logging eventually boils down to this function call. If we have
+// a callback registered, then we call the logging callback. If we have
+// a valid file handle, we also log to the file.
+//----------------------------------------------------------------------
+void
+Log::PrintfWithFlagsVarArg (uint32_t flags, const char *format, va_list args)
+{
+ if (m_stream_sp)
+ {
+ static uint32_t g_sequence_id = 0;
+ StreamString header;
+ // Enabling the thread safe logging actually deadlocks right now.
+ // Need to fix this at some point.
+// static Mutex g_LogThreadedMutex(Mutex::eMutexTypeRecursive);
+// Mutex::Locker locker (g_LogThreadedMutex);
+
+ // Add a sequence ID if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_SEQUENCE))
+ header.Printf ("%u ", ++g_sequence_id);
+
+ // Timestamp if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_TIMESTAMP))
+ {
+ struct timeval tv = TimeValue::Now().GetAsTimeVal();
+ header.Printf ("%9ld.%6.6d ", tv.tv_sec, (int32_t)tv.tv_usec);
+ }
+
+ // Add the process and thread if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD))
+ header.Printf ("[%4.4x/%4.4" PRIx64 "]: ", getpid(), Host::GetCurrentThreadID());
+
+ // Add the process and thread if requested
+ if (m_options.Test (LLDB_LOG_OPTION_PREPEND_THREAD_NAME))
+ {
+ std::string thread_name (Host::GetThreadName (getpid(), Host::GetCurrentThreadID()));
+ if (!thread_name.empty())
+ header.Printf ("%s ", thread_name.c_str());
+ }
+
+ header.PrintfVarArg (format, args);
+ m_stream_sp->Printf("%s\n", header.GetData());
+
+ if (m_options.Test (LLDB_LOG_OPTION_BACKTRACE))
+ Host::Backtrace (*m_stream_sp, 1024);
+ m_stream_sp->Flush();
+ }
+}
+
+
+void
+Log::PutCString (const char *cstr)
+{
+ Printf ("%s", cstr);
+}
+
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::Printf(const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (0, format, args);
+ va_end (args);
+}
+
+void
+Log::VAPrintf (const char *format, va_list args)
+{
+ PrintfWithFlagsVarArg (0, format, args);
+}
+
+
+//----------------------------------------------------------------------
+// Simple variable argument logging with flags.
+//----------------------------------------------------------------------
+void
+Log::PrintfWithFlags (uint32_t flags, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (flags, format, args);
+ va_end (args);
+}
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global debug option is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+Log::Debug (const char *format, ...)
+{
+ if (GetOptions().Test(LLDB_LOG_OPTION_DEBUG))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Print debug strings if and only if the global debug option is set to
+// a non-zero value.
+//----------------------------------------------------------------------
+void
+Log::DebugVerbose (const char *format, ...)
+{
+ if (GetOptions().AllSet (LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_DEBUG | LLDB_LOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Log only if all of the bits are set
+//----------------------------------------------------------------------
+void
+Log::LogIf (uint32_t bits, const char *format, ...)
+{
+ if (m_options.AllSet (bits))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (0, format, args);
+ va_end (args);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Printing of errors that are not fatal.
+//----------------------------------------------------------------------
+void
+Log::Error (const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_ERROR, "error: %s", arg_msg);
+ free (arg_msg);
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of errors that ARE fatal. Exit with ERR exit code
+// immediately.
+//----------------------------------------------------------------------
+void
+Log::FatalError (int err, const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_ERROR | LLDB_LOG_FLAG_FATAL, "error: %s", arg_msg);
+ ::free (arg_msg);
+ }
+ ::exit (err);
+}
+
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void
+Log::Verbose (const char *format, ...)
+{
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ {
+ va_list args;
+ va_start (args, format);
+ PrintfWithFlagsVarArg (LLDB_LOG_FLAG_VERBOSE, format, args);
+ va_end (args);
+ }
+}
+
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal only if verbose mode is
+// enabled.
+//----------------------------------------------------------------------
+void
+Log::WarningVerbose (const char *format, ...)
+{
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ {
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_WARNING | LLDB_LOG_FLAG_VERBOSE, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Printing of warnings that are not fatal.
+//----------------------------------------------------------------------
+void
+Log::Warning (const char *format, ...)
+{
+ char *arg_msg = NULL;
+ va_list args;
+ va_start (args, format);
+ ::vasprintf (&arg_msg, format, args);
+ va_end (args);
+
+ if (arg_msg != NULL)
+ {
+ PrintfWithFlags (LLDB_LOG_FLAG_WARNING, "warning: %s", arg_msg);
+ free (arg_msg);
+ }
+}
+
+typedef std::map <ConstString, Log::Callbacks> CallbackMap;
+typedef CallbackMap::iterator CallbackMapIter;
+
+typedef std::map <ConstString, LogChannelSP> LogChannelMap;
+typedef LogChannelMap::iterator LogChannelMapIter;
+
+
+// Surround our callback map with a singleton function so we don't have any
+// global initializers.
+static CallbackMap &
+GetCallbackMap ()
+{
+ static CallbackMap g_callback_map;
+ return g_callback_map;
+}
+
+static LogChannelMap &
+GetChannelMap ()
+{
+ static LogChannelMap g_channel_map;
+ return g_channel_map;
+}
+
+void
+Log::RegisterLogChannel (const ConstString &channel, const Log::Callbacks &log_callbacks)
+{
+ GetCallbackMap().insert(std::make_pair(channel, log_callbacks));
+}
+
+bool
+Log::UnregisterLogChannel (const ConstString &channel)
+{
+ return GetCallbackMap().erase(channel) != 0;
+}
+
+bool
+Log::GetLogChannelCallbacks (const ConstString &channel, Log::Callbacks &log_callbacks)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos = callback_map.find(channel);
+ if (pos != callback_map.end())
+ {
+ log_callbacks = pos->second;
+ return true;
+ }
+ ::memset (&log_callbacks, 0, sizeof(log_callbacks));
+ return false;
+}
+
+void
+Log::EnableAllLogChannels
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ const char **categories,
+ Stream *feedback_strm
+)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.enable (log_stream_sp, log_options, categories, feedback_strm);
+
+ LogChannelMap &channel_map = GetChannelMap ();
+ LogChannelMapIter channel_pos, channel_end = channel_map.end();
+ for (channel_pos = channel_map.begin(); channel_pos != channel_end; ++channel_pos)
+ {
+ channel_pos->second->Enable (log_stream_sp, log_options, feedback_strm, categories);
+ }
+
+}
+
+void
+Log::AutoCompleteChannelName (const char *channel_name, StringList &matches)
+{
+ LogChannelMap &map = GetChannelMap ();
+ LogChannelMapIter pos, end = map.end();
+ for (pos = map.begin(); pos != end; ++pos)
+ {
+ const char *pos_channel_name = pos->first.GetCString();
+ if (channel_name && channel_name[0])
+ {
+ if (NameMatches (channel_name, eNameMatchStartsWith, pos_channel_name))
+ {
+ matches.AppendString(pos_channel_name);
+ }
+ }
+ else
+ matches.AppendString(pos_channel_name);
+
+ }
+}
+
+void
+Log::DisableAllLogChannels (Stream *feedback_strm)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ CallbackMapIter pos, end = callback_map.end();
+ const char *categories[1] = {NULL};
+
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.disable (categories, feedback_strm);
+
+ LogChannelMap &channel_map = GetChannelMap ();
+ LogChannelMapIter channel_pos, channel_end = channel_map.end();
+ for (channel_pos = channel_map.begin(); channel_pos != channel_end; ++channel_pos)
+ channel_pos->second->Disable (categories, feedback_strm);
+}
+
+void
+Log::Initialize()
+{
+ Log::Callbacks log_callbacks = { DisableLog, EnableLog, ListLogCategories };
+ Log::RegisterLogChannel (ConstString("lldb"), log_callbacks);
+}
+
+void
+Log::Terminate ()
+{
+ DisableAllLogChannels (NULL);
+}
+
+void
+Log::ListAllLogChannels (Stream *strm)
+{
+ CallbackMap &callback_map = GetCallbackMap ();
+ LogChannelMap &channel_map = GetChannelMap ();
+
+ if (callback_map.empty() && channel_map.empty())
+ {
+ strm->PutCString ("No logging channels are currently registered.\n");
+ return;
+ }
+
+ CallbackMapIter pos, end = callback_map.end();
+ for (pos = callback_map.begin(); pos != end; ++pos)
+ pos->second.list_categories (strm);
+
+ uint32_t idx = 0;
+ const char *name;
+ for (idx = 0; (name = PluginManager::GetLogChannelCreateNameAtIndex (idx)) != NULL; ++idx)
+ {
+ LogChannelSP log_channel_sp(LogChannel::FindPlugin (name));
+ if (log_channel_sp)
+ log_channel_sp->ListCategories (strm);
+ }
+}
+
+bool
+Log::GetVerbose() const
+{
+ // FIXME: This has to be centralized between the stream and the log...
+ if (m_options.Test(LLDB_LOG_OPTION_VERBOSE))
+ return true;
+
+ if (m_stream_sp)
+ return m_stream_sp->GetVerbose();
+ return false;
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Log::GetDebug() const
+{
+ if (m_stream_sp)
+ return m_stream_sp->GetDebug();
+ return false;
+}
+
+
+LogChannelSP
+LogChannel::FindPlugin (const char *plugin_name)
+{
+ LogChannelSP log_channel_sp;
+ LogChannelMap &channel_map = GetChannelMap ();
+ ConstString log_channel_name (plugin_name);
+ LogChannelMapIter pos = channel_map.find (log_channel_name);
+ if (pos == channel_map.end())
+ {
+ ConstString const_plugin_name (plugin_name);
+ LogChannelCreateInstance create_callback = PluginManager::GetLogChannelCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ log_channel_sp.reset(create_callback());
+ if (log_channel_sp)
+ {
+ // Cache the one and only loaded instance of each log channel
+ // plug-in after it has been loaded once.
+ channel_map[log_channel_name] = log_channel_sp;
+ }
+ }
+ }
+ else
+ {
+ // We have already loaded an instance of this log channel class,
+ // so just return the cached instance.
+ log_channel_sp = pos->second;
+ }
+ return log_channel_sp;
+}
+
+LogChannel::LogChannel () :
+ m_log_ap ()
+{
+}
+
+LogChannel::~LogChannel ()
+{
+}
+
+
diff --git a/source/Core/Mangled.cpp b/source/Core/Mangled.cpp
new file mode 100644
index 000000000000..4655eb131a6c
--- /dev/null
+++ b/source/Core/Mangled.cpp
@@ -0,0 +1,313 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// FreeBSD9-STABLE requires this to know about size_t in cxxabi.h
+#include <cstddef>
+#include <cxxabi.h>
+
+
+#include "llvm/ADT/DenseMap.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+using namespace lldb_private;
+
+static inline bool
+cstring_is_mangled (const char *s)
+{
+ if (s)
+ return s[0] == '_' && s[1] == 'Z';
+ return false;
+}
+
+#pragma mark Mangled
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+Mangled::Mangled () :
+ m_mangled(),
+ m_demangled()
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor with an optional string and a boolean indicating if it is
+// the mangled version.
+//----------------------------------------------------------------------
+Mangled::Mangled (const ConstString &s, bool mangled) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s)
+ SetValue(s, mangled);
+}
+
+Mangled::Mangled (const ConstString &s) :
+ m_mangled(),
+ m_demangled()
+{
+ if (s)
+ SetValue(s);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Mangled::~Mangled ()
+{
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any Mangled
+// objects to see if they contain anything valid using code such as:
+//
+// Mangled mangled(...);
+// if (mangled)
+// { ...
+//----------------------------------------------------------------------
+Mangled::operator void* () const
+{
+ return (m_mangled) ? const_cast<Mangled*>(this) : NULL;
+}
+
+//----------------------------------------------------------------------
+// Logical NOT operator. This allows code to check any Mangled
+// objects to see if they are invalid using code such as:
+//
+// Mangled mangled(...);
+// if (!file_spec)
+// { ...
+//----------------------------------------------------------------------
+bool
+Mangled::operator! () const
+{
+ return !m_mangled;
+}
+
+//----------------------------------------------------------------------
+// Clear the mangled and demangled values.
+//----------------------------------------------------------------------
+void
+Mangled::Clear ()
+{
+ m_mangled.Clear();
+ m_demangled.Clear();
+}
+
+
+//----------------------------------------------------------------------
+// Compare the the string values.
+//----------------------------------------------------------------------
+int
+Mangled::Compare (const Mangled& a, const Mangled& b)
+{
+ return ConstString::Compare(a.GetName(ePreferMangled), a.GetName(ePreferMangled));
+}
+
+
+
+//----------------------------------------------------------------------
+// Set the string value in this objects. If "mangled" is true, then
+// the mangled named is set with the new value in "s", else the
+// demangled name is set.
+//----------------------------------------------------------------------
+void
+Mangled::SetValue (const ConstString &s, bool mangled)
+{
+ if (s)
+ {
+ if (mangled)
+ {
+ m_demangled.Clear();
+ m_mangled = s;
+ }
+ else
+ {
+ m_demangled = s;
+ m_mangled.Clear();
+ }
+ }
+ else
+ {
+ m_demangled.Clear();
+ m_mangled.Clear();
+ }
+}
+
+void
+Mangled::SetValue (const ConstString &name)
+{
+ if (name)
+ {
+ if (cstring_is_mangled(name.GetCString()))
+ {
+ m_demangled.Clear();
+ m_mangled = name;
+ }
+ else
+ {
+ m_demangled = name;
+ m_mangled.Clear();
+ }
+ }
+ else
+ {
+ m_demangled.Clear();
+ m_mangled.Clear();
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Generate the demangled name on demand using this accessor. Code in
+// this class will need to use this accessor if it wishes to decode
+// the demangled name. The result is cached and will be kept until a
+// new string value is supplied to this object, or until the end of the
+// object's lifetime.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetDemangledName () const
+{
+ // Check to make sure we have a valid mangled name and that we
+ // haven't already decoded our mangled name.
+ if (m_mangled && !m_demangled)
+ {
+ // We need to generate and cache the demangled name.
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Mangled::GetDemangledName (m_mangled = %s)",
+ m_mangled.GetCString());
+
+ // Don't bother running anything that isn't mangled
+ const char *mangled_cstr = m_mangled.GetCString();
+ if (cstring_is_mangled(mangled_cstr))
+ {
+ if (!m_mangled.GetMangledCounterpart(m_demangled))
+ {
+ // We didn't already mangle this name, demangle it and if all goes well
+ // add it to our map.
+ char *demangled_name = abi::__cxa_demangle (mangled_cstr, NULL, NULL, NULL);
+
+ if (demangled_name)
+ {
+ m_demangled.SetCStringWithMangledCounterpart(demangled_name, m_mangled);
+ free (demangled_name);
+ }
+ }
+ }
+ if (!m_demangled)
+ {
+ // Set the demangled string to the empty string to indicate we
+ // tried to parse it once and failed.
+ m_demangled.SetCString("");
+ }
+ }
+
+ return m_demangled;
+}
+
+
+bool
+Mangled::NameMatches (const RegularExpression& regex) const
+{
+ if (m_mangled && regex.Execute (m_mangled.AsCString()))
+ return true;
+
+ if (GetDemangledName() && regex.Execute (m_demangled.AsCString()))
+ return true;
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Get the demangled name if there is one, else return the mangled name.
+//----------------------------------------------------------------------
+const ConstString&
+Mangled::GetName (Mangled::NamePreference preference) const
+{
+ if (preference == ePreferDemangled)
+ {
+ // Call the accessor to make sure we get a demangled name in case
+ // it hasn't been demangled yet...
+ if (GetDemangledName())
+ return m_demangled;
+ return m_mangled;
+ }
+ else
+ {
+ if (m_mangled)
+ return m_mangled;
+ return GetDemangledName();
+ }
+}
+
+//----------------------------------------------------------------------
+// Dump a Mangled object to stream "s". We don't force our
+// demangled name to be computed currently (we don't use the accessor).
+//----------------------------------------------------------------------
+void
+Mangled::Dump (Stream *s) const
+{
+ if (m_mangled)
+ {
+ *s << ", mangled = " << m_mangled;
+ }
+ if (m_demangled)
+ {
+ const char * demangled = m_demangled.AsCString();
+ s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
+ }
+}
+
+//----------------------------------------------------------------------
+// Dumps a debug version of this string with extra object and state
+// information to stream "s".
+//----------------------------------------------------------------------
+void
+Mangled::DumpDebug (Stream *s) const
+{
+ s->Printf("%*p: Mangled mangled = ", (int)sizeof(void*) * 2, this);
+ m_mangled.DumpDebug(s);
+ s->Printf(", demangled = ");
+ m_demangled.DumpDebug(s);
+}
+
+//----------------------------------------------------------------------
+// Return the size in byte that this object takes in memory. The size
+// includes the size of the objects it owns, and not the strings that
+// it references because they are shared strings.
+//----------------------------------------------------------------------
+size_t
+Mangled::MemorySize () const
+{
+ return m_mangled.MemorySize() + m_demangled.MemorySize();
+}
+
+//----------------------------------------------------------------------
+// Dump OBJ to the supplied stream S.
+//----------------------------------------------------------------------
+Stream&
+operator << (Stream& s, const Mangled& obj)
+{
+ if (obj.GetMangledName())
+ s << "mangled = '" << obj.GetMangledName() << "'";
+
+ const ConstString& demangled = obj.GetDemangledName();
+ if (demangled)
+ s << ", demangled = '" << demangled << '\'';
+ else
+ s << ", demangled = <error>";
+ return s;
+}
diff --git a/source/Core/Module.cpp b/source/Core/Module.cpp
new file mode 100644
index 000000000000..4252ed4cb6c6
--- /dev/null
+++ b/source/Core/Module.cpp
@@ -0,0 +1,1609 @@
+//===-- Module.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Shared pointers to modules track module lifetimes in
+// targets and in the global module, but this collection
+// will track all module objects that are still alive
+typedef std::vector<Module *> ModuleCollection;
+
+static ModuleCollection &
+GetModuleCollection()
+{
+ // This module collection needs to live past any module, so we could either make it a
+ // shared pointer in each module or just leak is. Since it is only an empty vector by
+ // the time all the modules have gone away, we just leak it for now. If we decide this
+ // is a big problem we can introduce a Finalize method that will tear everything down in
+ // a predictable order.
+
+ static ModuleCollection *g_module_collection = NULL;
+ if (g_module_collection == NULL)
+ g_module_collection = new ModuleCollection();
+
+ return *g_module_collection;
+}
+
+Mutex *
+Module::GetAllocationModuleCollectionMutex()
+{
+ // NOTE: The mutex below must be leaked since the global module list in
+ // the ModuleList class will get torn at some point, and we can't know
+ // if it will tear itself down before the "g_module_collection_mutex" below
+ // will. So we leak a Mutex object below to safeguard against that
+
+ static Mutex *g_module_collection_mutex = NULL;
+ if (g_module_collection_mutex == NULL)
+ g_module_collection_mutex = new Mutex (Mutex::eMutexTypeRecursive); // NOTE: known leak
+ return g_module_collection_mutex;
+}
+
+size_t
+Module::GetNumberAllocatedModules ()
+{
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ return GetModuleCollection().size();
+}
+
+Module *
+Module::GetAllocatedModuleAtIndex (size_t idx)
+{
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ if (idx < modules.size())
+ return modules[idx];
+ return NULL;
+}
+#if 0
+
+// These functions help us to determine if modules are still loaded, yet don't require that
+// you have a command interpreter and can easily be called from an external debugger.
+namespace lldb {
+
+ void
+ ClearModuleInfo (void)
+ {
+ const bool mandatory = true;
+ ModuleList::RemoveOrphanSharedModules(mandatory);
+ }
+
+ void
+ DumpModuleInfo (void)
+ {
+ Mutex::Locker locker (Module::GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ const size_t count = modules.size();
+ printf ("%s: %" PRIu64 " modules:\n", __PRETTY_FUNCTION__, (uint64_t)count);
+ for (size_t i=0; i<count; ++i)
+ {
+
+ StreamString strm;
+ Module *module = modules[i];
+ const bool in_shared_module_list = ModuleList::ModuleIsInCache (module);
+ module->GetDescription(&strm, eDescriptionLevelFull);
+ printf ("%p: shared = %i, ref_count = %3u, module = %s\n",
+ module,
+ in_shared_module_list,
+ (uint32_t)module->use_count(),
+ strm.GetString().c_str());
+ }
+ }
+}
+
+#endif
+
+Module::Module (const ModuleSpec &module_spec) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (module_spec.GetFileSpec().GetModificationTime()),
+ m_arch (module_spec.GetArchitecture()),
+ m_uuid (),
+ m_file (module_spec.GetFileSpec()),
+ m_platform_file(module_spec.GetPlatformFileSpec()),
+ m_symfile_spec (module_spec.GetSymbolFileSpec()),
+ m_object_name (module_spec.GetObjectName()),
+ m_object_offset (module_spec.GetObjectOffset()),
+ m_object_mod_time (module_spec.GetObjectModificationTime()),
+ m_objfile_sp (),
+ m_symfile_ap (),
+ m_ast (),
+ m_source_mappings (),
+ m_did_load_objfile (false),
+ m_did_load_symbol_vendor (false),
+ m_did_parse_uuid (false),
+ m_did_init_ast (false),
+ m_is_dynamic_loader_module (false),
+ m_file_has_changed (false),
+ m_first_file_changed_log (false)
+{
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ GetModuleCollection().push_back(this);
+ }
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+Module::Module(const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const ConstString *object_name,
+ off_t object_offset,
+ const TimeValue *object_mod_time_ptr) :
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_arch (arch),
+ m_uuid (),
+ m_file (file_spec),
+ m_platform_file(),
+ m_symfile_spec (),
+ m_object_name (),
+ m_object_offset (object_offset),
+ m_object_mod_time (),
+ m_objfile_sp (),
+ m_symfile_ap (),
+ m_ast (),
+ m_source_mappings (),
+ m_did_load_objfile (false),
+ m_did_load_symbol_vendor (false),
+ m_did_parse_uuid (false),
+ m_did_init_ast (false),
+ m_is_dynamic_loader_module (false),
+ m_file_has_changed (false),
+ m_first_file_changed_log (false)
+{
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ GetModuleCollection().push_back(this);
+ }
+
+ if (object_name)
+ m_object_name = *object_name;
+
+ if (object_mod_time_ptr)
+ m_object_mod_time = *object_mod_time_ptr;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+}
+
+Module::~Module()
+{
+ // Lock our module down while we tear everything down to make sure
+ // we don't get any access to the module while it is being destroyed
+ Mutex::Locker locker (m_mutex);
+ // Scope for locker below...
+ {
+ Mutex::Locker locker (GetAllocationModuleCollectionMutex());
+ ModuleCollection &modules = GetModuleCollection();
+ ModuleCollection::iterator end = modules.end();
+ ModuleCollection::iterator pos = std::find(modules.begin(), end, this);
+ assert (pos != end);
+ modules.erase(pos);
+ }
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_OBJECT|LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf ("%p Module::~Module((%s) '%s%s%s%s')",
+ this,
+ m_arch.GetArchitectureName(),
+ m_file.GetPath().c_str(),
+ m_object_name.IsEmpty() ? "" : "(",
+ m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
+ m_object_name.IsEmpty() ? "" : ")");
+ // Release any auto pointers before we start tearing down our member
+ // variables since the object file and symbol files might need to make
+ // function calls back into this module object. The ordering is important
+ // here because symbol files can require the module object file. So we tear
+ // down the symbol file first, then the object file.
+ m_sections_ap.reset();
+ m_symfile_ap.reset();
+ m_objfile_sp.reset();
+}
+
+ObjectFile *
+Module::GetMemoryObjectFile (const lldb::ProcessSP &process_sp, lldb::addr_t header_addr, Error &error)
+{
+ if (m_objfile_sp)
+ {
+ error.SetErrorString ("object file already exists");
+ }
+ else
+ {
+ Mutex::Locker locker (m_mutex);
+ if (process_sp)
+ {
+ m_did_load_objfile = true;
+ std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (512, 0));
+ Error readmem_error;
+ const size_t bytes_read = process_sp->ReadMemory (header_addr,
+ data_ap->GetBytes(),
+ data_ap->GetByteSize(),
+ readmem_error);
+ if (bytes_read == 512)
+ {
+ DataBufferSP data_sp(data_ap.release());
+ m_objfile_sp = ObjectFile::FindPlugin(shared_from_this(), process_sp, header_addr, data_sp);
+ if (m_objfile_sp)
+ {
+ StreamString s;
+ s.Printf("0x%16.16" PRIx64, header_addr);
+ m_object_name.SetCString (s.GetData());
+
+ // Once we get the object file, update our module with the object file's
+ // architecture since it might differ in vendor/os if some parts were
+ // unknown.
+ m_objfile_sp->GetArchitecture (m_arch);
+ }
+ else
+ {
+ error.SetErrorString ("unable to find suitable object file plug-in");
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to read header from memory: %s", readmem_error.AsCString());
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid process");
+ }
+ }
+ return m_objfile_sp.get();
+}
+
+
+const lldb_private::UUID&
+Module::GetUUID()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_parse_uuid == false)
+ {
+ ObjectFile * obj_file = GetObjectFile ();
+
+ if (obj_file != NULL)
+ {
+ obj_file->GetUUID(&m_uuid);
+ m_did_parse_uuid = true;
+ }
+ }
+ return m_uuid;
+}
+
+ClangASTContext &
+Module::GetClangASTContext ()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_init_ast == false)
+ {
+ ObjectFile * objfile = GetObjectFile();
+ ArchSpec object_arch;
+ if (objfile && objfile->GetArchitecture(object_arch))
+ {
+ m_did_init_ast = true;
+
+ // LLVM wants this to be set to iOS or MacOSX; if we're working on
+ // a bare-boards type image, change the triple for llvm's benefit.
+ if (object_arch.GetTriple().getVendor() == llvm::Triple::Apple
+ && object_arch.GetTriple().getOS() == llvm::Triple::UnknownOS)
+ {
+ if (object_arch.GetTriple().getArch() == llvm::Triple::arm ||
+ object_arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ object_arch.GetTriple().setOS(llvm::Triple::IOS);
+ }
+ else
+ {
+ object_arch.GetTriple().setOS(llvm::Triple::MacOSX);
+ }
+ }
+ m_ast.SetArchitecture (object_arch);
+ }
+ }
+ return m_ast;
+}
+
+void
+Module::ParseAllDebugSymbols()
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_comp_units = GetNumCompileUnits();
+ if (num_comp_units == 0)
+ return;
+
+ SymbolContext sc;
+ sc.module_sp = shared_from_this();
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ for (size_t cu_idx = 0; cu_idx < num_comp_units; cu_idx++)
+ {
+ sc.comp_unit = symbols->GetCompileUnitAtIndex(cu_idx).get();
+ if (sc.comp_unit)
+ {
+ sc.function = NULL;
+ symbols->ParseVariablesForContext(sc);
+
+ symbols->ParseCompileUnitFunctions(sc);
+
+ for (size_t func_idx = 0; (sc.function = sc.comp_unit->GetFunctionAtIndex(func_idx).get()) != NULL; ++func_idx)
+ {
+ symbols->ParseFunctionBlocks(sc);
+
+ // Parse the variables for this function and all its blocks
+ symbols->ParseVariablesForContext(sc);
+ }
+
+
+ // Parse all types for this compile unit
+ sc.function = NULL;
+ symbols->ParseTypes(sc);
+ }
+ }
+}
+
+void
+Module::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->module_sp = shared_from_this();
+}
+
+ModuleSP
+Module::CalculateSymbolContextModule ()
+{
+ return shared_from_this();
+}
+
+void
+Module::DumpSymbolContext(Stream *s)
+{
+ s->Printf(", Module{%p}", this);
+}
+
+size_t
+Module::GetNumCompileUnits()
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "Module::GetNumCompileUnits (module = %p)", this);
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->GetNumCompileUnits();
+ return 0;
+}
+
+CompUnitSP
+Module::GetCompileUnitAtIndex (size_t index)
+{
+ Mutex::Locker locker (m_mutex);
+ size_t num_comp_units = GetNumCompileUnits ();
+ CompUnitSP cu_sp;
+
+ if (index < num_comp_units)
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ cu_sp = symbols->GetCompileUnitAtIndex(index);
+ }
+ return cu_sp;
+}
+
+bool
+Module::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr)
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__, "Module::ResolveFileAddress (vm_addr = 0x%" PRIx64 ")", vm_addr);
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ return so_addr.ResolveAddressUsingFileSections(vm_addr, section_list);
+ return false;
+}
+
+uint32_t
+Module::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ Mutex::Locker locker (m_mutex);
+ uint32_t resolved_flags = 0;
+
+ // Clear the result symbol context in case we don't find anything, but don't clear the target
+ sc.Clear(false);
+
+ // Get the section from the section/offset address.
+ SectionSP section_sp (so_addr.GetSection());
+
+ // Make sure the section matches this module before we try and match anything
+ if (section_sp && section_sp->GetModule().get() == this)
+ {
+ // If the section offset based address resolved itself, then this
+ // is the right module.
+ sc.module_sp = shared_from_this();
+ resolved_flags |= eSymbolContextModule;
+
+ // Resolve the compile unit, function, block, line table or line
+ // entry if requested.
+ if (resolve_scope & eSymbolContextCompUnit ||
+ resolve_scope & eSymbolContextFunction ||
+ resolve_scope & eSymbolContextBlock ||
+ resolve_scope & eSymbolContextLineEntry )
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ resolved_flags |= symbols->ResolveSymbolContext (so_addr, resolve_scope, sc);
+ }
+
+ // Resolve the symbol if requested, but don't re-look it up if we've already found it.
+ if (resolve_scope & eSymbolContextSymbol && !(resolved_flags & eSymbolContextSymbol))
+ {
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ if (so_addr.IsSectionOffset())
+ {
+ sc.symbol = symtab->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+uint32_t
+Module::ResolveSymbolContextForFilePath
+(
+ const char *file_path,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list
+)
+{
+ FileSpec file_spec(file_path, false);
+ return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+}
+
+uint32_t
+Module::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ Mutex::Locker locker (m_mutex);
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::ResolveSymbolContextForFilePath (%s:%u, check_inlines = %s, resolve_scope = 0x%8.8x)",
+ file_spec.GetPath().c_str(),
+ line,
+ check_inlines ? "yes" : "no",
+ resolve_scope);
+
+ const uint32_t initial_count = sc_list.GetSize();
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ symbols->ResolveSymbolContext (file_spec, line, check_inlines, resolve_scope, sc_list);
+
+ return sc_list.GetSize() - initial_count;
+}
+
+
+size_t
+Module::FindGlobalVariables (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(name, namespace_decl, append, max_matches, variables);
+ return 0;
+}
+
+size_t
+Module::FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variables)
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindGlobalVariables(regex, append, max_matches, variables);
+ return 0;
+}
+
+size_t
+Module::FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t start_size = sc_list.GetSize();
+ const size_t num_compile_units = GetNumCompileUnits();
+ SymbolContext sc;
+ sc.module_sp = shared_from_this();
+ const bool compare_directory = path.GetDirectory();
+ for (size_t i=0; i<num_compile_units; ++i)
+ {
+ sc.comp_unit = GetCompileUnitAtIndex(i).get();
+ if (sc.comp_unit)
+ {
+ if (FileSpec::Equal (*sc.comp_unit, path, compare_directory))
+ sc_list.Append(sc);
+ }
+ }
+ return sc_list.GetSize() - start_size;
+}
+
+size_t
+Module::FindFunctions (const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t old_size = sc_list.GetSize();
+
+ // Find all the functions (not symbols, but debug information functions...
+ SymbolVendor *symbols = GetSymbolVendor ();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name,
+ name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ if (symbols)
+ {
+ symbols->FindFunctions(lookup_name,
+ namespace_decl,
+ lookup_name_type_mask,
+ include_inlines,
+ append,
+ sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ symtab->FindFunctionSymbols(lookup_name, lookup_name_type_mask, sc_list);
+ }
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ if (symbols)
+ {
+ symbols->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ symtab->FindFunctionSymbols(name, name_type_mask, sc_list);
+ }
+ }
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+Module::FindFunctions (const RegularExpression& regex,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t start_size = sc_list.GetSize();
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ {
+ symbols->FindFunctions(regex, include_inlines, append, sc_list);
+
+ // Now check our symbol table for symbols that are code symbols if requested
+ if (include_symbols)
+ {
+ Symtab *symtab = symbols->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->AppendSymbolIndexesMatchingRegExAndType (regex, eSymbolTypeAny, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+ const size_t num_matches = symbol_indexes.size();
+ if (num_matches)
+ {
+ SymbolContext sc(this);
+ const size_t end_functions_added_index = sc_list.GetSize();
+ size_t num_functions_added_to_sc_list = end_functions_added_index - start_size;
+ if (num_functions_added_to_sc_list == 0)
+ {
+ // No functions were added, just symbols, so we can just append them
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ SymbolType sym_type = sc.symbol->GetType();
+ if (sc.symbol && (sym_type == eSymbolTypeCode ||
+ sym_type == eSymbolTypeResolver))
+ sc_list.Append(sc);
+ }
+ }
+ else
+ {
+ typedef std::map<lldb::addr_t, uint32_t> FileAddrToIndexMap;
+ FileAddrToIndexMap file_addr_to_index;
+ for (size_t i=start_size; i<end_functions_added_index; ++i)
+ {
+ const SymbolContext &sc = sc_list[i];
+ if (sc.block)
+ continue;
+ file_addr_to_index[sc.function->GetAddressRange().GetBaseAddress().GetFileAddress()] = i;
+ }
+
+ FileAddrToIndexMap::const_iterator end = file_addr_to_index.end();
+ // Functions were added so we need to merge symbols into any
+ // existing function symbol contexts
+ for (size_t i=start_size; i<num_matches; ++i)
+ {
+ sc.symbol = symtab->SymbolAtIndex(symbol_indexes[i]);
+ SymbolType sym_type = sc.symbol->GetType();
+ if (sc.symbol && (sym_type == eSymbolTypeCode ||
+ sym_type == eSymbolTypeResolver))
+ {
+ FileAddrToIndexMap::const_iterator pos = file_addr_to_index.find(sc.symbol->GetAddress().GetFileAddress());
+ if (pos == end)
+ sc_list.Append(sc);
+ else
+ sc_list[pos->second].symbol = sc.symbol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return sc_list.GetSize() - start_size;
+}
+
+size_t
+Module::FindTypes_Impl (const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ size_t max_matches,
+ TypeList& types)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ if (sc.module_sp.get() == NULL || sc.module_sp.get() == this)
+ {
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return symbols->FindTypes(sc, name, namespace_decl, append, max_matches, types);
+ }
+ return 0;
+}
+
+size_t
+Module::FindTypesInNamespace (const SymbolContext& sc,
+ const ConstString &type_name,
+ const ClangNamespaceDecl *namespace_decl,
+ size_t max_matches,
+ TypeList& type_list)
+{
+ const bool append = true;
+ return FindTypes_Impl(sc, type_name, namespace_decl, append, max_matches, type_list);
+}
+
+lldb::TypeSP
+Module::FindFirstType (const SymbolContext& sc,
+ const ConstString &name,
+ bool exact_match)
+{
+ TypeList type_list;
+ const size_t num_matches = FindTypes (sc, name, exact_match, 1, type_list);
+ if (num_matches)
+ return type_list.GetTypeAtIndex(0);
+ return TypeSP();
+}
+
+
+size_t
+Module::FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ bool exact_match,
+ size_t max_matches,
+ TypeList& types)
+{
+ size_t num_matches = 0;
+ const char *type_name_cstr = name.GetCString();
+ std::string type_scope;
+ std::string type_basename;
+ const bool append = true;
+ TypeClass type_class = eTypeClassAny;
+ if (Type::GetTypeScopeAndBasename (type_name_cstr, type_scope, type_basename, type_class))
+ {
+ // Check if "name" starts with "::" which means the qualified type starts
+ // from the root namespace and implies and exact match. The typenames we
+ // get back from clang do not start with "::" so we need to strip this off
+ // in order to get the qualfied names to match
+
+ if (type_scope.size() >= 2 && type_scope[0] == ':' && type_scope[1] == ':')
+ {
+ type_scope.erase(0,2);
+ exact_match = true;
+ }
+ ConstString type_basename_const_str (type_basename.c_str());
+ if (FindTypes_Impl(sc, type_basename_const_str, NULL, append, max_matches, types))
+ {
+ types.RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match);
+ num_matches = types.GetSize();
+ }
+ }
+ else
+ {
+ // The type is not in a namespace/class scope, just search for it by basename
+ if (type_class != eTypeClassAny)
+ {
+ // The "type_name_cstr" will have been modified if we have a valid type class
+ // prefix (like "struct", "class", "union", "typedef" etc).
+ num_matches = FindTypes_Impl(sc, ConstString(type_name_cstr), NULL, append, max_matches, types);
+ types.RemoveMismatchedTypes (type_class);
+ num_matches = types.GetSize();
+ }
+ else
+ {
+ num_matches = FindTypes_Impl(sc, name, NULL, append, max_matches, types);
+ }
+ }
+
+ return num_matches;
+
+}
+
+SymbolVendor*
+Module::GetSymbolVendor (bool can_create, lldb_private::Stream *feedback_strm)
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_load_symbol_vendor == false && can_create)
+ {
+ ObjectFile *obj_file = GetObjectFile ();
+ if (obj_file != NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ m_symfile_ap.reset(SymbolVendor::FindPlugin(shared_from_this(), feedback_strm));
+ m_did_load_symbol_vendor = true;
+ }
+ }
+ return m_symfile_ap.get();
+}
+
+void
+Module::SetFileSpecAndObjectName (const FileSpec &file, const ConstString &object_name)
+{
+ // Container objects whose paths do not specify a file directly can call
+ // this function to correct the file and object names.
+ m_file = file;
+ m_mod_time = file.GetModificationTime();
+ m_object_name = object_name;
+}
+
+const ArchSpec&
+Module::GetArchitecture () const
+{
+ return m_arch;
+}
+
+std::string
+Module::GetSpecificationDescription () const
+{
+ std::string spec(GetFileSpec().GetPath());
+ if (m_object_name)
+ {
+ spec += '(';
+ spec += m_object_name.GetCString();
+ spec += ')';
+ }
+ return spec;
+}
+
+void
+Module::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (level >= eDescriptionLevelFull)
+ {
+ if (m_arch.IsValid())
+ s->Printf("(%s) ", m_arch.GetArchitectureName());
+ }
+
+ if (level == eDescriptionLevelBrief)
+ {
+ const char *filename = m_file.GetFilename().GetCString();
+ if (filename)
+ s->PutCString (filename);
+ }
+ else
+ {
+ char path[PATH_MAX];
+ if (m_file.GetPath(path, sizeof(path)))
+ s->PutCString(path);
+ }
+
+ const char *object_name = m_object_name.GetCString();
+ if (object_name)
+ s->Printf("(%s)", object_name);
+}
+
+void
+Module::ReportError (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ StreamString strm;
+ strm.PutCString("error: ");
+ GetDescription(&strm, lldb::eDescriptionLevelBrief);
+ strm.PutChar (' ');
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ Host::SystemLog (Host::eSystemLogError, "%s", strm.GetString().c_str());
+
+ }
+}
+
+bool
+Module::FileHasChanged () const
+{
+ if (m_file_has_changed == false)
+ m_file_has_changed = (m_file.GetModificationTime() != m_mod_time);
+ return m_file_has_changed;
+}
+
+void
+Module::ReportErrorIfModifyDetected (const char *format, ...)
+{
+ if (m_first_file_changed_log == false)
+ {
+ if (FileHasChanged ())
+ {
+ m_first_file_changed_log = true;
+ if (format)
+ {
+ StreamString strm;
+ strm.PutCString("error: the object file ");
+ GetDescription(&strm, lldb::eDescriptionLevelFull);
+ strm.PutCString (" has been modified\n");
+
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ strm.PutCString("The debug session should be aborted as the original debug information has been overwritten.\n");
+ Host::SystemLog (Host::eSystemLogError, "%s", strm.GetString().c_str());
+ }
+ }
+ }
+}
+
+void
+Module::ReportWarning (const char *format, ...)
+{
+ if (format && format[0])
+ {
+ StreamString strm;
+ strm.PutCString("warning: ");
+ GetDescription(&strm, lldb::eDescriptionLevelFull);
+ strm.PutChar (' ');
+
+ va_list args;
+ va_start (args, format);
+ strm.PrintfVarArg(format, args);
+ va_end (args);
+
+ const int format_len = strlen(format);
+ if (format_len > 0)
+ {
+ const char last_char = format[format_len-1];
+ if (last_char != '\n' || last_char != '\r')
+ strm.EOL();
+ }
+ Host::SystemLog (Host::eSystemLogWarning, "%s", strm.GetString().c_str());
+ }
+}
+
+void
+Module::LogMessage (Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ StreamString log_message;
+ GetDescription(&log_message, lldb::eDescriptionLevelFull);
+ log_message.PutCString (": ");
+ va_list args;
+ va_start (args, format);
+ log_message.PrintfVarArg (format, args);
+ va_end (args);
+ log->PutCString(log_message.GetString().c_str());
+ }
+}
+
+void
+Module::LogMessageVerboseBacktrace (Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ StreamString log_message;
+ GetDescription(&log_message, lldb::eDescriptionLevelFull);
+ log_message.PutCString (": ");
+ va_list args;
+ va_start (args, format);
+ log_message.PrintfVarArg (format, args);
+ va_end (args);
+ if (log->GetVerbose())
+ Host::Backtrace (log_message, 1024);
+ log->PutCString(log_message.GetString().c_str());
+ }
+}
+
+void
+Module::Dump(Stream *s)
+{
+ Mutex::Locker locker (m_mutex);
+ //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("Module %s%s%s%s\n",
+ m_file.GetPath().c_str(),
+ m_object_name ? "(" : "",
+ m_object_name ? m_object_name.GetCString() : "",
+ m_object_name ? ")" : "");
+
+ s->IndentMore();
+
+ ObjectFile *objfile = GetObjectFile ();
+ if (objfile)
+ objfile->Dump(s);
+
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ symbols->Dump(s);
+
+ s->IndentLess();
+}
+
+
+TypeList*
+Module::GetTypeList ()
+{
+ SymbolVendor *symbols = GetSymbolVendor ();
+ if (symbols)
+ return &symbols->GetTypeList();
+ return NULL;
+}
+
+const ConstString &
+Module::GetObjectName() const
+{
+ return m_object_name;
+}
+
+ObjectFile *
+Module::GetObjectFile()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_did_load_objfile == false)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString(""));
+ DataBufferSP data_sp;
+ lldb::offset_t data_offset = 0;
+ const lldb::offset_t file_size = m_file.GetByteSize();
+ if (file_size > m_object_offset)
+ {
+ m_did_load_objfile = true;
+ m_objfile_sp = ObjectFile::FindPlugin (shared_from_this(),
+ &m_file,
+ m_object_offset,
+ file_size - m_object_offset,
+ data_sp,
+ data_offset);
+ if (m_objfile_sp)
+ {
+ // Once we get the object file, update our module with the object file's
+ // architecture since it might differ in vendor/os if some parts were
+ // unknown.
+ m_objfile_sp->GetArchitecture (m_arch);
+ }
+ }
+ }
+ return m_objfile_sp.get();
+}
+
+SectionList *
+Module::GetSectionList()
+{
+ // Populate m_unified_sections_ap with sections from objfile.
+ if (m_sections_ap.get() == NULL)
+ {
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ obj_file->CreateSections(*GetUnifiedSectionList());
+ }
+ return m_sections_ap.get();
+}
+
+SectionList *
+Module::GetUnifiedSectionList()
+{
+ // Populate m_unified_sections_ap with sections from objfile.
+ if (m_sections_ap.get() == NULL)
+ m_sections_ap.reset(new SectionList());
+ return m_sections_ap.get();
+}
+
+const Symbol *
+Module::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindFirstSymbolWithNameAndType (name = %s, type = %i)",
+ name.AsCString(),
+ symbol_type);
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ return symtab->FindFirstSymbolWithNameAndType (name, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny);
+ }
+ return NULL;
+}
+void
+Module::SymbolIndicesToSymbolContextList (Symtab *symtab, std::vector<uint32_t> &symbol_indexes, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+ size_t num_indices = symbol_indexes.size();
+ if (num_indices > 0)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext (&sc);
+ for (size_t i = 0; i < num_indices; i++)
+ {
+ sc.symbol = symtab->SymbolAtIndex (symbol_indexes[i]);
+ if (sc.symbol)
+ sc_list.Append (sc);
+ }
+ }
+}
+
+size_t
+Module::FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsFunctions (name = %s, mask = 0x%8.8x)",
+ name.AsCString(),
+ name_type_mask);
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ return symtab->FindFunctionSymbols (name, name_type_mask, sc_list);
+ }
+ return 0;
+}
+
+size_t
+Module::FindSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsWithNameAndType (name = %s, type = %i)",
+ name.AsCString(),
+ symbol_type);
+ const size_t initial_size = sc_list.GetSize();
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsWithNameAndType (name, symbol_type, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+Module::FindSymbolsMatchingRegExAndType (const RegularExpression &regex, SymbolType symbol_type, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "Module::FindSymbolsMatchingRegExAndType (regex = %s, type = %i)",
+ regex.GetText(),
+ symbol_type);
+ const size_t initial_size = sc_list.GetSize();
+ SymbolVendor* sym_vendor = GetSymbolVendor();
+ if (sym_vendor)
+ {
+ Symtab *symtab = sym_vendor->GetSymtab();
+ if (symtab)
+ {
+ std::vector<uint32_t> symbol_indexes;
+ symtab->FindAllSymbolsMatchingRexExAndType (regex, symbol_type, Symtab::eDebugAny, Symtab::eVisibilityAny, symbol_indexes);
+ SymbolIndicesToSymbolContextList (symtab, symbol_indexes, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial_size;
+}
+
+void
+Module::SetSymbolFileFileSpec (const FileSpec &file)
+{
+ // Remove any sections in the unified section list that come from the current symbol vendor.
+ if (m_symfile_ap)
+ {
+ SectionList *section_list = GetSectionList();
+ SymbolFile *symbol_file = m_symfile_ap->GetSymbolFile();
+ if (section_list && symbol_file)
+ {
+ ObjectFile *obj_file = symbol_file->GetObjectFile();
+ // Make sure we have an object file and that the symbol vendor's objfile isn't
+ // the same as the module's objfile before we remove any sections for it...
+ if (obj_file && obj_file != m_objfile_sp.get())
+ {
+ size_t num_sections = section_list->GetNumSections (0);
+ for (size_t idx = num_sections; idx > 0; --idx)
+ {
+ lldb::SectionSP section_sp (section_list->GetSectionAtIndex (idx - 1));
+ if (section_sp->GetObjectFile() == obj_file)
+ {
+ section_list->DeleteSection (idx - 1);
+ }
+ }
+ }
+ }
+ }
+
+ m_symfile_spec = file;
+ m_symfile_ap.reset();
+ m_did_load_symbol_vendor = false;
+}
+
+bool
+Module::IsExecutable ()
+{
+ if (GetObjectFile() == NULL)
+ return false;
+ else
+ return GetObjectFile()->IsExecutable();
+}
+
+bool
+Module::IsLoadedInTarget (Target *target)
+{
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ {
+ SectionList *sections = GetSectionList();
+ if (sections != NULL)
+ {
+ size_t num_sections = sections->GetSize();
+ for (size_t sect_idx = 0; sect_idx < num_sections; sect_idx++)
+ {
+ SectionSP section_sp = sections->GetSectionAtIndex(sect_idx);
+ if (section_sp->GetLoadBaseAddress(target) != LLDB_INVALID_ADDRESS)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+Module::LoadScriptingResourceInTarget (Target *target, Error& error, Stream* feedback_stream)
+{
+ if (!target)
+ {
+ error.SetErrorString("invalid destination Target");
+ return false;
+ }
+
+ LoadScriptFromSymFile shoud_load = target->TargetProperties::GetLoadScriptFromSymbolFile();
+
+ Debugger &debugger = target->GetDebugger();
+ const ScriptLanguage script_language = debugger.GetScriptLanguage();
+ if (script_language != eScriptLanguageNone)
+ {
+
+ PlatformSP platform_sp(target->GetPlatform());
+
+ if (!platform_sp)
+ {
+ error.SetErrorString("invalid Platform");
+ return false;
+ }
+
+ FileSpecList file_specs = platform_sp->LocateExecutableScriptingResources (target,
+ *this);
+
+
+ const uint32_t num_specs = file_specs.GetSize();
+ if (num_specs)
+ {
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interpreter)
+ {
+ for (uint32_t i=0; i<num_specs; ++i)
+ {
+ FileSpec scripting_fspec (file_specs.GetFileSpecAtIndex(i));
+ if (scripting_fspec && scripting_fspec.Exists())
+ {
+ if (shoud_load == eLoadScriptFromSymFileFalse)
+ return false;
+ if (shoud_load == eLoadScriptFromSymFileWarn)
+ {
+ if (feedback_stream)
+ feedback_stream->Printf("warning: '%s' contains a debug script. To run this script in "
+ "this debug session:\n\n command script import \"%s\"\n\n"
+ "To run all discovered debug scripts in this session:\n\n"
+ " settings set target.load-script-from-symbol-file true\n",
+ GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ scripting_fspec.GetPath().c_str());
+ return false;
+ }
+ StreamString scripting_stream;
+ scripting_fspec.Dump(&scripting_stream);
+ const bool can_reload = true;
+ const bool init_lldb_globals = false;
+ bool did_load = script_interpreter->LoadScriptingModule(scripting_stream.GetData(),
+ can_reload,
+ init_lldb_globals,
+ error);
+ if (!did_load)
+ return false;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid ScriptInterpreter");
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+Module::SetArchitecture (const ArchSpec &new_arch)
+{
+ if (!m_arch.IsValid())
+ {
+ m_arch = new_arch;
+ return true;
+ }
+ return m_arch.IsExactMatch(new_arch);
+}
+
+bool
+Module::SetLoadAddress (Target &target, lldb::addr_t offset, bool &changed)
+{
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList ();
+ if (section_list)
+ {
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ // Only load non-thread specific sections when given a slide
+ if (section_sp && !section_sp->IsThreadSpecific())
+ {
+ if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + offset))
+ ++num_loaded_sections;
+ }
+ }
+ }
+ changed = num_loaded_sections > 0;
+ return num_loaded_sections > 0;
+}
+
+
+bool
+Module::MatchesModuleSpec (const ModuleSpec &module_ref)
+{
+ const UUID &uuid = module_ref.GetUUID();
+
+ if (uuid.IsValid())
+ {
+ // If the UUID matches, then nothing more needs to match...
+ if (uuid == GetUUID())
+ return true;
+ else
+ return false;
+ }
+
+ const FileSpec &file_spec = module_ref.GetFileSpec();
+ if (file_spec)
+ {
+ if (!FileSpec::Equal (file_spec, m_file, file_spec.GetDirectory()))
+ return false;
+ }
+
+ const FileSpec &platform_file_spec = module_ref.GetPlatformFileSpec();
+ if (platform_file_spec)
+ {
+ if (!FileSpec::Equal (platform_file_spec, GetPlatformFileSpec (), platform_file_spec.GetDirectory()))
+ return false;
+ }
+
+ const ArchSpec &arch = module_ref.GetArchitecture();
+ if (arch.IsValid())
+ {
+ if (!m_arch.IsCompatibleMatch(arch))
+ return false;
+ }
+
+ const ConstString &object_name = module_ref.GetObjectName();
+ if (object_name)
+ {
+ if (object_name != GetObjectName())
+ return false;
+ }
+ return true;
+}
+
+bool
+Module::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_source_mappings.FindFile (orig_spec, new_spec);
+}
+
+bool
+Module::RemapSourceFile (const char *path, std::string &new_path) const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_source_mappings.RemapPath(path, new_path);
+}
+
+uint32_t
+Module::GetVersion (uint32_t *versions, uint32_t num_versions)
+{
+ ObjectFile *obj_file = GetObjectFile();
+ if (obj_file)
+ return obj_file->GetVersion (versions, num_versions);
+
+ if (versions && num_versions)
+ {
+ for (uint32_t i=0; i<num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ return 0;
+}
+
+void
+Module::PrepareForFunctionNameLookup (const ConstString &name,
+ uint32_t name_type_mask,
+ ConstString &lookup_name,
+ uint32_t &lookup_name_type_mask,
+ bool &match_name_after_lookup)
+{
+ 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;
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ if (CPPLanguageRuntime::IsCPPMangledName (name_cstr))
+ lookup_name_type_mask = eFunctionNameTypeFull;
+ else if (ObjCLanguageRuntime::IsPossibleObjCMethodName (name_cstr))
+ lookup_name_type_mask = eFunctionNameTypeFull;
+ else
+ {
+ if (ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
+ lookup_name_type_mask |= eFunctionNameTypeSelector;
+
+ CPPLanguageRuntime::MethodName cpp_method (name);
+ llvm::StringRef basename (cpp_method.GetBasename());
+ if (basename.empty())
+ {
+ if (CPPLanguageRuntime::StripNamespacesFromVariableName (name_cstr, base_name_start, base_name_end))
+ lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ }
+ else
+ {
+ base_name_start = basename.data();
+ base_name_end = base_name_start + basename.size();
+ lookup_name_type_mask |= (eFunctionNameTypeMethod | eFunctionNameTypeBase);
+ }
+ }
+ }
+ else
+ {
+ lookup_name_type_mask = name_type_mask;
+ if (lookup_name_type_mask & eFunctionNameTypeMethod || name_type_mask & eFunctionNameTypeBase)
+ {
+ // If they've asked for a CPP method or function name and it can't be that, we don't
+ // even need to search for CPP methods or names.
+ 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();
+
+ if (!cpp_method.GetQualifiers().empty())
+ {
+ // There is a "const" or other qualifer following the end of the fucntion parens,
+ // this can't be a eFunctionNameTypeBase
+ lookup_name_type_mask &= ~(eFunctionNameTypeBase);
+ if (lookup_name_type_mask == eFunctionNameTypeNone)
+ return;
+ }
+ }
+ 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 (lookup_name_type_mask & eFunctionNameTypeSelector)
+ {
+ if (!ObjCLanguageRuntime::IsPossibleObjCSelector(name_cstr))
+ {
+ lookup_name_type_mask &= ~(eFunctionNameTypeSelector);
+ if (lookup_name_type_mask == eFunctionNameTypeNone)
+ return;
+ }
+ }
+ }
+
+ if (base_name_start &&
+ base_name_end &&
+ base_name_start != name_cstr &&
+ base_name_start < base_name_end)
+ {
+ // 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);
+ match_name_after_lookup = true;
+ }
+ else
+ {
+ // The name is already correct, just use the exact name as supplied, and we won't need
+ // to check if any matches contain "name"
+ lookup_name = name;
+ match_name_after_lookup = false;
+ }
+} \ No newline at end of file
diff --git a/source/Core/ModuleChild.cpp b/source/Core/ModuleChild.cpp
new file mode 100644
index 000000000000..9637fc3aedda
--- /dev/null
+++ b/source/Core/ModuleChild.cpp
@@ -0,0 +1,46 @@
+//===-- ModuleChild.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/ModuleChild.h"
+
+using namespace lldb_private;
+
+ModuleChild::ModuleChild (const lldb::ModuleSP &module_sp) :
+ m_module_wp (module_sp)
+{
+}
+
+ModuleChild::ModuleChild (const ModuleChild& rhs) :
+ m_module_wp(rhs.m_module_wp)
+{
+}
+
+ModuleChild::~ModuleChild()
+{
+}
+
+const ModuleChild&
+ModuleChild::operator= (const ModuleChild& rhs)
+{
+ if (this != &rhs)
+ m_module_wp = rhs.m_module_wp;
+ return *this;
+}
+
+lldb::ModuleSP
+ModuleChild::GetModule () const
+{
+ return m_module_wp.lock();
+}
+
+void
+ModuleChild::SetModule (const lldb::ModuleSP &module_sp)
+{
+ m_module_wp = module_sp;
+}
diff --git a/source/Core/ModuleList.cpp b/source/Core/ModuleList.cpp
new file mode 100644
index 000000000000..ebc6702d3a90
--- /dev/null
+++ b/source/Core/ModuleList.cpp
@@ -0,0 +1,1103 @@
+//===-- ModuleList.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/ModuleList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ModuleList constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList() :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive),
+ m_notifier(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Copy constructor
+//----------------------------------------------------------------------
+ModuleList::ModuleList(const ModuleList& rhs) :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive)
+{
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ m_modules = rhs.m_modules;
+}
+
+ModuleList::ModuleList (ModuleList::Notifier* notifier) :
+ m_modules(),
+ m_modules_mutex (Mutex::eMutexTypeRecursive),
+ m_notifier(notifier)
+{
+}
+
+//----------------------------------------------------------------------
+// Assignment operator
+//----------------------------------------------------------------------
+const ModuleList&
+ModuleList::operator= (const ModuleList& rhs)
+{
+ if (this != &rhs)
+ {
+ Mutex::Locker lhs_locker(m_modules_mutex);
+ Mutex::Locker rhs_locker(rhs.m_modules_mutex);
+ m_modules = rhs.m_modules;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ModuleList::~ModuleList()
+{
+}
+
+void
+ModuleList::AppendImpl (const ModuleSP &module_sp, bool use_notifier)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ m_modules.push_back(module_sp);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleAdded(*this, module_sp);
+ }
+}
+
+void
+ModuleList::Append (const ModuleSP &module_sp)
+{
+ AppendImpl (module_sp);
+}
+
+void
+ModuleList::ReplaceEquivalent (const ModuleSP &module_sp)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+
+ // First remove any equivalent modules. Equivalent modules are modules
+ // whose path, platform path and architecture match.
+ ModuleSpec equivalent_module_spec (module_sp->GetFileSpec(), module_sp->GetArchitecture());
+ equivalent_module_spec.GetPlatformFileSpec() = module_sp->GetPlatformFileSpec();
+
+ size_t idx = 0;
+ while (idx < m_modules.size())
+ {
+ ModuleSP module_sp (m_modules[idx]);
+ if (module_sp->MatchesModuleSpec (equivalent_module_spec))
+ RemoveImpl(m_modules.begin() + idx);
+ else
+ ++idx;
+ }
+ // Now add the new module to the list
+ Append(module_sp);
+ }
+}
+
+bool
+ModuleList::AppendIfNeeded (const ModuleSP &module_sp)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_sp.get())
+ return false; // Already in the list
+ }
+ // Only push module_sp on the list if it wasn't already in there.
+ Append(module_sp);
+ return true;
+ }
+ return false;
+}
+
+void
+ModuleList::Append (const ModuleList& module_list)
+{
+ for (auto pos : module_list.m_modules)
+ Append(pos);
+}
+
+bool
+ModuleList::AppendIfNeeded (const ModuleList& module_list)
+{
+ bool any_in = false;
+ for (auto pos : module_list.m_modules)
+ {
+ if (AppendIfNeeded(pos))
+ any_in = true;
+ }
+ return any_in;
+}
+
+bool
+ModuleList::RemoveImpl (const ModuleSP &module_sp, bool use_notifier)
+{
+ if (module_sp)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_sp.get())
+ {
+ m_modules.erase (pos);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleRemoved(*this, module_sp);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ModuleList::collection::iterator
+ModuleList::RemoveImpl (ModuleList::collection::iterator pos, bool use_notifier)
+{
+ ModuleSP module_sp(*pos);
+ collection::iterator retval = m_modules.erase(pos);
+ if (use_notifier && m_notifier)
+ m_notifier->ModuleRemoved(*this, module_sp);
+ return retval;
+}
+
+bool
+ModuleList::Remove (const ModuleSP &module_sp)
+{
+ return RemoveImpl (module_sp);
+}
+
+bool
+ModuleList::ReplaceModule (const lldb::ModuleSP &old_module_sp, const lldb::ModuleSP &new_module_sp)
+{
+ if (!RemoveImpl(old_module_sp, false))
+ return false;
+ AppendImpl (new_module_sp, false);
+ if (m_notifier)
+ m_notifier->ModuleUpdated(*this, old_module_sp,new_module_sp);
+ return true;
+}
+
+bool
+ModuleList::RemoveIfOrphaned (const Module *module_ptr)
+{
+ if (module_ptr)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == module_ptr)
+ {
+ if (pos->unique())
+ {
+ pos = RemoveImpl(pos);
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+ModuleList::RemoveOrphans (bool mandatory)
+{
+ Mutex::Locker locker;
+
+ if (mandatory)
+ {
+ locker.Lock (m_modules_mutex);
+ }
+ else
+ {
+ // Not mandatory, remove orphans if we can get the mutex
+ if (!locker.TryLock(m_modules_mutex))
+ return 0;
+ }
+ collection::iterator pos = m_modules.begin();
+ size_t remove_count = 0;
+ while (pos != m_modules.end())
+ {
+ if (pos->unique())
+ {
+ pos = RemoveImpl(pos);
+ ++remove_count;
+ }
+ else
+ {
+ ++pos;
+ }
+ }
+ return remove_count;
+}
+
+size_t
+ModuleList::Remove (ModuleList &module_list)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ size_t num_removed = 0;
+ collection::iterator pos, end = module_list.m_modules.end();
+ for (pos = module_list.m_modules.begin(); pos != end; ++pos)
+ {
+ if (Remove (*pos))
+ ++num_removed;
+ }
+ return num_removed;
+}
+
+
+void
+ModuleList::Clear()
+{
+ ClearImpl();
+}
+
+void
+ModuleList::Destroy()
+{
+ ClearImpl();
+}
+
+void
+ModuleList::ClearImpl (bool use_notifier)
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (use_notifier && m_notifier)
+ m_notifier->WillClearList(*this);
+ m_modules.clear();
+}
+
+Module*
+ModuleList::GetModulePointerAtIndex (size_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ return GetModulePointerAtIndexUnlocked(idx);
+}
+
+Module*
+ModuleList::GetModulePointerAtIndexUnlocked (size_t idx) const
+{
+ if (idx < m_modules.size())
+ return m_modules[idx].get();
+ return NULL;
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndex(size_t idx) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ return GetModuleAtIndexUnlocked(idx);
+}
+
+ModuleSP
+ModuleList::GetModuleAtIndexUnlocked(size_t idx) const
+{
+ ModuleSP module_sp;
+ if (idx < m_modules.size())
+ module_sp = m_modules[idx];
+ return module_sp;
+}
+
+size_t
+ModuleList::FindFunctions (const ConstString &name,
+ uint32_t name_type_mask,
+ bool include_symbols,
+ bool include_inlines,
+ bool append,
+ SymbolContextList &sc_list) const
+{
+ if (!append)
+ sc_list.Clear();
+
+ const size_t old_size = sc_list.GetSize();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name, name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctions (lookup_name,
+ NULL,
+ lookup_name_type_mask,
+ include_symbols,
+ include_inlines,
+ true,
+ sc_list);
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ }
+ else
+ {
+ 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, NULL, name_type_mask, include_symbols, include_inlines, true, sc_list);
+ }
+ }
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+ModuleList::FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list)
+{
+ const size_t old_size = sc_list.GetSize();
+
+ if (name_type_mask & eFunctionNameTypeAuto)
+ {
+ ConstString lookup_name;
+ uint32_t lookup_name_type_mask = 0;
+ bool match_name_after_lookup = false;
+ Module::PrepareForFunctionNameLookup (name, name_type_mask,
+ lookup_name,
+ lookup_name_type_mask,
+ match_name_after_lookup);
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctionSymbols (lookup_name,
+ lookup_name_type_mask,
+ sc_list);
+ }
+
+ if (match_name_after_lookup)
+ {
+ SymbolContext sc;
+ size_t i = old_size;
+ while (i<sc_list.GetSize())
+ {
+ if (sc_list.GetContextAtIndex(i, sc))
+ {
+ const char *func_name = sc.GetFunctionName().GetCString();
+ if (func_name && strstr (func_name, name.GetCString()) == NULL)
+ {
+ // Remove the current context
+ sc_list.RemoveContextAtIndex(i);
+ // Don't increment i and continue in the loop
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ }
+ else
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindFunctionSymbols (name, name_type_mask, sc_list);
+ }
+ }
+
+ return sc_list.GetSize() - old_size;
+}
+
+size_t
+ModuleList::FindCompileUnits (const FileSpec &path,
+ bool append,
+ SymbolContextList &sc_list) const
+{
+ if (!append)
+ sc_list.Clear();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->FindCompileUnits (path, true, sc_list);
+ }
+
+ return sc_list.GetSize();
+}
+
+size_t
+ModuleList::FindGlobalVariables (const ConstString &name,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const
+{
+ size_t initial_size = variable_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)->FindGlobalVariables (name, NULL, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+size_t
+ModuleList::FindGlobalVariables (const RegularExpression& regex,
+ bool append,
+ size_t max_matches,
+ VariableList& variable_list) const
+{
+ size_t initial_size = variable_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)->FindGlobalVariables (regex, append, max_matches, variable_list);
+ }
+ return variable_list.GetSize() - initial_size;
+}
+
+
+size_t
+ModuleList::FindSymbolsWithNameAndType (const ConstString &name,
+ SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (!append)
+ sc_list.Clear();
+ size_t initial_size = sc_list.GetSize();
+
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ (*pos)->FindSymbolsWithNameAndType (name, symbol_type, sc_list);
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+ModuleList::FindSymbolsMatchingRegExAndType (const RegularExpression &regex,
+ lldb::SymbolType symbol_type,
+ SymbolContextList &sc_list,
+ bool append) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ if (!append)
+ sc_list.Clear();
+ size_t initial_size = sc_list.GetSize();
+
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ (*pos)->FindSymbolsMatchingRegExAndType (regex, symbol_type, sc_list);
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+ModuleList::FindModules (const ModuleSpec &module_spec, ModuleList& matching_module_list) const
+{
+ size_t existing_matches = matching_module_list.GetSize();
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ ModuleSP module_sp(*pos);
+ if (module_sp->MatchesModuleSpec (module_spec))
+ matching_module_list.Append(module_sp);
+ }
+ return matching_module_list.GetSize() - existing_matches;
+}
+
+ModuleSP
+ModuleList::FindModule (const Module *module_ptr) const
+{
+ ModuleSP module_sp;
+
+ // Scope for "locker"
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == module_ptr)
+ {
+ module_sp = (*pos);
+ break;
+ }
+ }
+ }
+ return module_sp;
+
+}
+
+ModuleSP
+ModuleList::FindModule (const UUID &uuid) const
+{
+ ModuleSP module_sp;
+
+ if (uuid.IsValid())
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetUUID() == uuid)
+ {
+ module_sp = (*pos);
+ break;
+ }
+ }
+ }
+ return module_sp;
+}
+
+
+size_t
+ModuleList::FindTypes (const SymbolContext& sc, const ConstString &name, bool name_is_fully_qualified, size_t max_matches, TypeList& types) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+
+ size_t total_matches = 0;
+ collection::const_iterator pos, end = m_modules.end();
+ if (sc.module_sp)
+ {
+ // The symbol context "sc" contains a module so we want to search that
+ // one first if it is in our list...
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if (sc.module_sp.get() == (*pos).get())
+ {
+ total_matches += (*pos)->FindTypes (sc, name, name_is_fully_qualified, max_matches, types);
+
+ if (total_matches >= max_matches)
+ break;
+ }
+ }
+ }
+
+ if (total_matches < max_matches)
+ {
+ SymbolContext world_sc;
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ // Search the module if the module is not equal to the one in the symbol
+ // context "sc". If "sc" contains a empty module shared pointer, then
+ // the comparisong will always be true (valid_module_ptr != NULL).
+ if (sc.module_sp.get() != (*pos).get())
+ total_matches += (*pos)->FindTypes (world_sc, name, name_is_fully_qualified, max_matches, types);
+
+ if (total_matches >= max_matches)
+ break;
+ }
+ }
+
+ return total_matches;
+}
+
+bool
+ModuleList::FindSourceFile (const FileSpec &orig_spec, FileSpec &new_spec) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->FindSourceFile (orig_spec, new_spec))
+ return true;
+ }
+ return false;
+}
+
+
+
+ModuleSP
+ModuleList::FindFirstModule (const ModuleSpec &module_spec) const
+{
+ ModuleSP module_sp;
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ ModuleSP module_sp(*pos);
+ if (module_sp->MatchesModuleSpec (module_spec))
+ return module_sp;
+ }
+ return module_sp;
+
+}
+
+size_t
+ModuleList::GetSize() const
+{
+ size_t size = 0;
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ size = m_modules.size();
+ }
+ return size;
+}
+
+
+void
+ModuleList::Dump(Stream *s) const
+{
+// s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+// s.Indent();
+// s << "ModuleList\n";
+
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->Dump(s);
+ }
+}
+
+void
+ModuleList::LogUUIDAndPaths (Log *log, const char *prefix_cstr)
+{
+ if (log)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, begin = m_modules.begin(), end = m_modules.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ Module *module = pos->get();
+ const FileSpec &module_file_spec = module->GetFileSpec();
+ log->Printf ("%s[%u] %s (%s) \"%s\"",
+ prefix_cstr ? prefix_cstr : "",
+ (uint32_t)std::distance (begin, pos),
+ module->GetUUID().GetAsString().c_str(),
+ module->GetArchitecture().GetArchitectureName(),
+ module_file_spec.GetPath().c_str());
+ }
+ }
+}
+
+bool
+ModuleList::ResolveFileAddress (lldb::addr_t vm_addr, Address& so_addr) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->ResolveFileAddress (vm_addr, so_addr))
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextForAddress (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc) const
+{
+ // The address is already section offset so it has a module
+ uint32_t resolved_flags = 0;
+ ModuleSP module_sp (so_addr.GetModule());
+ if (module_sp)
+ {
+ resolved_flags = module_sp->ResolveSymbolContextForAddress (so_addr,
+ resolve_scope,
+ sc);
+ }
+ else
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ resolved_flags = (*pos)->ResolveSymbolContextForAddress (so_addr,
+ resolve_scope,
+ sc);
+ if (resolved_flags != 0)
+ break;
+ }
+ }
+
+ return resolved_flags;
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextForFilePath
+(
+ const char *file_path,
+ uint32_t line,
+ bool check_inlines,
+ uint32_t resolve_scope,
+ SymbolContextList& sc_list
+) const
+{
+ FileSpec file_spec(file_path, false);
+ return ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+}
+
+uint32_t
+ModuleList::ResolveSymbolContextsForFileSpec (const FileSpec &file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list) const
+{
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos, end = m_modules.end();
+ for (pos = m_modules.begin(); pos != end; ++pos)
+ {
+ (*pos)->ResolveSymbolContextsForFileSpec (file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+
+ return sc_list.GetSize();
+}
+
+size_t
+ModuleList::GetIndexForModule (const Module *module) const
+{
+ if (module)
+ {
+ Mutex::Locker locker(m_modules_mutex);
+ collection::const_iterator pos;
+ collection::const_iterator begin = m_modules.begin();
+ collection::const_iterator end = m_modules.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if ((*pos).get() == module)
+ return std::distance (begin, pos);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+static ModuleList &
+GetSharedModuleList ()
+{
+ // NOTE: Intentionally leak the module list so a program doesn't have to
+ // cleanup all modules and object files as it exits. This just wastes time
+ // doing a bunch of cleanup that isn't required.
+ static ModuleList *g_shared_module_list = NULL;
+ if (g_shared_module_list == NULL)
+ g_shared_module_list = new ModuleList(); // <--- Intentional leak!!!
+
+ return *g_shared_module_list;
+}
+
+bool
+ModuleList::ModuleIsInCache (const Module *module_ptr)
+{
+ if (module_ptr)
+ {
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ return shared_module_list.FindModule (module_ptr).get() != NULL;
+ }
+ return false;
+}
+
+size_t
+ModuleList::FindSharedModules (const ModuleSpec &module_spec, ModuleList &matching_module_list)
+{
+ return GetSharedModuleList ().FindModules (module_spec, matching_module_list);
+}
+
+size_t
+ModuleList::RemoveOrphanSharedModules (bool mandatory)
+{
+ return GetSharedModuleList ().RemoveOrphans(mandatory);
+}
+
+Error
+ModuleList::GetSharedModule
+(
+ const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr,
+ bool always_create
+)
+{
+ ModuleList &shared_module_list = GetSharedModuleList ();
+ Mutex::Locker locker(shared_module_list.m_modules_mutex);
+ char path[PATH_MAX];
+
+ Error error;
+
+ module_sp.reset();
+
+ if (did_create_ptr)
+ *did_create_ptr = false;
+ if (old_module_sp_ptr)
+ old_module_sp_ptr->reset();
+
+ const UUID *uuid_ptr = module_spec.GetUUIDPtr();
+ const FileSpec &module_file_spec = module_spec.GetFileSpec();
+ const ArchSpec &arch = module_spec.GetArchitecture();
+
+ // Make sure no one else can try and get or create a module while this
+ // function is actively working on it by doing an extra lock on the
+ // global mutex list.
+ if (always_create == false)
+ {
+ ModuleList matching_module_list;
+ const size_t num_matching_modules = shared_module_list.FindModules (module_spec, matching_module_list);
+ if (num_matching_modules > 0)
+ {
+ for (size_t module_idx = 0; module_idx < num_matching_modules; ++module_idx)
+ {
+ module_sp = matching_module_list.GetModuleAtIndex(module_idx);
+
+ // Make sure the file for the module hasn't been modified
+ if (module_sp->FileHasChanged())
+ {
+ if (old_module_sp_ptr && !old_module_sp_ptr->get())
+ *old_module_sp_ptr = module_sp;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_MODULES));
+ if (log)
+ log->Printf("module changed: %p, removing from global module list", module_sp.get());
+
+ shared_module_list.Remove (module_sp);
+ module_sp.reset();
+ }
+ else
+ {
+ // The module matches and the module was not modified from
+ // when it was last loaded.
+ return error;
+ }
+ }
+ }
+ }
+
+ if (module_sp)
+ return error;
+ else
+ {
+ module_sp.reset (new Module (module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp)
+ {
+ if (module_sp->GetObjectFile())
+ {
+ // If we get in here we got the correct arch, now we just need
+ // to verify the UUID if one was given
+ if (uuid_ptr && *uuid_ptr != module_sp->GetUUID())
+ module_sp.reset();
+ else
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ return error;
+ }
+ }
+ else
+ module_sp.reset();
+ }
+ }
+
+ // Either the file didn't exist where at the path, or no path was given, so
+ // we now have to use more extreme measures to try and find the appropriate
+ // module.
+
+ // Fixup the incoming path in case the path points to a valid file, yet
+ // the arch or UUID (if one was passed in) don't match.
+ FileSpec file_spec = Symbols::LocateExecutableObjectFile (module_spec);
+
+ // Don't look for the file if it appears to be the same one we already
+ // checked for above...
+ if (file_spec != module_file_spec)
+ {
+ if (!file_spec.Exists())
+ {
+ file_spec.GetPath(path, sizeof(path));
+ if (path[0] == '\0')
+ module_file_spec.GetPath(path, sizeof(path));
+ if (file_spec.Exists())
+ {
+ std::string uuid_str;
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (arch.IsValid())
+ {
+ if (!uuid_str.empty())
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture and UUID %s", path, arch.GetArchitectureName(), uuid_str.c_str());
+ else
+ error.SetErrorStringWithFormat("'%s' does not contain the %s architecture.", path, arch.GetArchitectureName());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'%s' does not exist", path);
+ }
+ if (error.Fail())
+ module_sp.reset();
+ return error;
+ }
+
+
+ // Make sure no one else can try and get or create a module while this
+ // function is actively working on it by doing an extra lock on the
+ // global mutex list.
+ ModuleSpec platform_module_spec(module_spec);
+ platform_module_spec.GetFileSpec() = file_spec;
+ platform_module_spec.GetPlatformFileSpec() = file_spec;
+ ModuleList matching_module_list;
+ if (shared_module_list.FindModules (platform_module_spec, matching_module_list) > 0)
+ {
+ module_sp = matching_module_list.GetModuleAtIndex(0);
+
+ // If we didn't have a UUID in mind when looking for the object file,
+ // then we should make sure the modification time hasn't changed!
+ if (platform_module_spec.GetUUIDPtr() == NULL)
+ {
+ TimeValue file_spec_mod_time(file_spec.GetModificationTime());
+ if (file_spec_mod_time.IsValid())
+ {
+ if (file_spec_mod_time != module_sp->GetModificationTime())
+ {
+ if (old_module_sp_ptr)
+ *old_module_sp_ptr = module_sp;
+ shared_module_list.Remove (module_sp);
+ module_sp.reset();
+ }
+ }
+ }
+ }
+
+ if (module_sp.get() == NULL)
+ {
+ module_sp.reset (new Module (platform_module_spec));
+ // Make sure there are a module and an object file since we can specify
+ // a valid file path with an architecture that might not be in that file.
+ // By getting the object file we can guarantee that the architecture matches
+ if (module_sp && module_sp->GetObjectFile())
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+
+ shared_module_list.ReplaceEquivalent(module_sp);
+ }
+ else
+ {
+ file_spec.GetPath(path, sizeof(path));
+
+ if (file_spec)
+ {
+ if (arch.IsValid())
+ error.SetErrorStringWithFormat("unable to open %s architecture in '%s'", arch.GetArchitectureName(), path);
+ else
+ error.SetErrorStringWithFormat("unable to open '%s'", path);
+ }
+ else
+ {
+ std::string uuid_str;
+ if (uuid_ptr && uuid_ptr->IsValid())
+ uuid_str = uuid_ptr->GetAsString();
+
+ if (!uuid_str.empty())
+ error.SetErrorStringWithFormat("cannot locate a module for UUID '%s'", uuid_str.c_str());
+ else
+ error.SetErrorStringWithFormat("cannot locate a module");
+ }
+ }
+ }
+ }
+
+ return error;
+}
+
+bool
+ModuleList::RemoveSharedModule (lldb::ModuleSP &module_sp)
+{
+ return GetSharedModuleList ().Remove (module_sp);
+}
+
+bool
+ModuleList::RemoveSharedModuleIfOrphaned (const Module *module_ptr)
+{
+ return GetSharedModuleList ().RemoveIfOrphaned (module_ptr);
+}
+
+bool
+ModuleList::LoadScriptingResourcesInTarget (Target *target,
+ std::list<Error>& errors,
+ Stream *feedback_stream,
+ bool continue_on_error)
+{
+ if (!target)
+ return false;
+ Mutex::Locker locker(m_modules_mutex);
+ for (auto module : m_modules)
+ {
+ Error error;
+ if (module)
+ {
+ if (!module->LoadScriptingResourceInTarget(target, error, feedback_stream))
+ {
+ if (error.Fail() && error.AsCString())
+ {
+ error.SetErrorStringWithFormat("unable to load scripting data for module %s - error reported was %s",
+ module->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ error.AsCString());
+ errors.push_back(error);
+ }
+ if (!continue_on_error)
+ return false;
+ }
+ }
+ }
+ return errors.size() == 0;
+}
diff --git a/source/Core/Opcode.cpp b/source/Core/Opcode.cpp
new file mode 100644
index 000000000000..d9878656e3f1
--- /dev/null
+++ b/source/Core/Opcode.cpp
@@ -0,0 +1,134 @@
+//===-- Opcode.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/Opcode.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Endian.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+int
+Opcode::Dump (Stream *s, uint32_t min_byte_width)
+{
+ int bytes_written = 0;
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid:
+ bytes_written = s->PutCString ("<invalid>");
+ break;
+ case Opcode::eType8:
+ bytes_written = s->Printf ("0x%2.2x", m_data.inst8);
+ break;
+ case Opcode::eType16:
+ bytes_written = s->Printf ("0x%4.4x", m_data.inst16);
+ break;
+ case Opcode::eType16_2:
+ case Opcode::eType32:
+ bytes_written = s->Printf ("0x%8.8x", m_data.inst32);
+ break;
+
+ case Opcode::eType64:
+ bytes_written = s->Printf ("0x%16.16" PRIx64, m_data.inst64);
+ break;
+
+ case Opcode::eTypeBytes:
+ {
+ for (uint32_t i=0; i<m_data.inst.length; ++i)
+ {
+ if (i > 0)
+ bytes_written += s->PutChar (' ');
+ bytes_written += s->Printf ("%2.2x", m_data.inst.bytes[i]);
+ }
+ }
+ break;
+ }
+
+ // Add spaces to make sure bytes dispay comes out even in case opcodes
+ // aren't all the same size
+ if (bytes_written < min_byte_width)
+ bytes_written = s->Printf ("%*s", min_byte_width - bytes_written, "");
+ return bytes_written;
+}
+
+lldb::ByteOrder
+Opcode::GetDataByteOrder () const
+{
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid: break;
+ case Opcode::eType8:
+ case Opcode::eType16:
+ case Opcode::eType16_2:
+ case Opcode::eType32:
+ case Opcode::eType64: return lldb::endian::InlHostByteOrder();
+ case Opcode::eTypeBytes:
+ break;
+ }
+ return eByteOrderInvalid;
+}
+
+uint32_t
+Opcode::GetData (DataExtractor &data) const
+{
+ uint32_t byte_size = GetByteSize ();
+
+ DataBufferSP buffer_sp;
+ if (byte_size > 0)
+ {
+ switch (m_type)
+ {
+ case Opcode::eTypeInvalid:
+ break;
+
+ case Opcode::eType8: buffer_sp.reset (new DataBufferHeap (&m_data.inst8, byte_size)); break;
+ case Opcode::eType16: buffer_sp.reset (new DataBufferHeap (&m_data.inst16, byte_size)); break;
+ case Opcode::eType16_2:
+ {
+ // 32 bit thumb instruction, we need to sizzle this a bit
+ uint8_t buf[4];
+ buf[0] = m_data.inst.bytes[2];
+ buf[1] = m_data.inst.bytes[3];
+ buf[2] = m_data.inst.bytes[0];
+ buf[3] = m_data.inst.bytes[1];
+ buffer_sp.reset (new DataBufferHeap (buf, byte_size));
+ }
+ break;
+ case Opcode::eType32:
+ buffer_sp.reset (new DataBufferHeap (&m_data.inst32, byte_size));
+ break;
+ case Opcode::eType64: buffer_sp.reset (new DataBufferHeap (&m_data.inst64, byte_size)); break;
+ case Opcode::eTypeBytes:buffer_sp.reset (new DataBufferHeap (GetOpcodeBytes(), byte_size)); break;
+ break;
+ }
+ }
+
+ if (buffer_sp)
+ {
+ data.SetByteOrder(GetDataByteOrder());
+ data.SetData (buffer_sp);
+ return byte_size;
+ }
+ data.Clear();
+ return 0;
+}
+
+
+
diff --git a/source/Core/PluginManager.cpp b/source/Core/PluginManager.cpp
new file mode 100644
index 000000000000..7a2d3772e6c3
--- /dev/null
+++ b/source/Core/PluginManager.cpp
@@ -0,0 +1,2064 @@
+//===-- PluginManager.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/PluginManager.h"
+
+#include <limits.h>
+
+#include <string>
+#include <vector>
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum PluginAction
+{
+ ePluginRegisterInstance,
+ ePluginUnregisterInstance,
+ ePluginGetInstanceAtIndex
+};
+
+
+typedef bool (*PluginInitCallback) (void);
+typedef void (*PluginTermCallback) (void);
+
+struct PluginInfo
+{
+ void *plugin_handle;
+ PluginInitCallback plugin_init_callback;
+ PluginTermCallback plugin_term_callback;
+};
+
+typedef std::map<FileSpec, PluginInfo> PluginTerminateMap;
+
+static Mutex &
+GetPluginMapMutex ()
+{
+ static Mutex g_plugin_map_mutex (Mutex::eMutexTypeRecursive);
+ return g_plugin_map_mutex;
+}
+
+static PluginTerminateMap &
+GetPluginMap ()
+{
+ static PluginTerminateMap g_plugin_map;
+ return g_plugin_map;
+}
+
+static bool
+PluginIsLoaded (const FileSpec &plugin_file_spec)
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+ return plugin_map.find (plugin_file_spec) != plugin_map.end();
+}
+
+static void
+SetPluginInfo (const FileSpec &plugin_file_spec, const PluginInfo &plugin_info)
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+ assert (plugin_map.find (plugin_file_spec) == plugin_map.end());
+ plugin_map[plugin_file_spec] = plugin_info;
+}
+
+
+static FileSpec::EnumerateDirectoryResult
+LoadPluginCallback
+(
+ void *baton,
+ FileSpec::FileType file_type,
+ const FileSpec &file_spec
+)
+{
+// PluginManager *plugin_manager = (PluginManager *)baton;
+ Error error;
+
+ // If we have a regular file, a symbolic link or unknown file type, try
+ // and process the file. We must handle unknown as sometimes the directory
+ // enumeration might be enumerating a file system that doesn't have correct
+ // file type information.
+ if (file_type == FileSpec::eFileTypeRegular ||
+ file_type == FileSpec::eFileTypeSymbolicLink ||
+ file_type == FileSpec::eFileTypeUnknown )
+ {
+ FileSpec plugin_file_spec (file_spec);
+ plugin_file_spec.ResolvePath();
+
+ if (PluginIsLoaded (plugin_file_spec))
+ return FileSpec::eEnumerateDirectoryResultNext;
+ else
+ {
+ PluginInfo plugin_info = { NULL, NULL, NULL };
+ uint32_t flags = Host::eDynamicLibraryOpenOptionLazy |
+ Host::eDynamicLibraryOpenOptionLocal |
+ Host::eDynamicLibraryOpenOptionLimitGetSymbol;
+
+ plugin_info.plugin_handle = Host::DynamicLibraryOpen (plugin_file_spec, flags, error);
+ if (plugin_info.plugin_handle)
+ {
+ bool success = false;
+ plugin_info.plugin_init_callback = (PluginInitCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginInitialize", error);
+ if (plugin_info.plugin_init_callback)
+ {
+ // Call the plug-in "bool LLDBPluginInitialize(void)" function
+ success = plugin_info.plugin_init_callback();
+ }
+
+ if (success)
+ {
+ // It is ok for the "LLDBPluginTerminate" symbol to be NULL
+ plugin_info.plugin_term_callback = (PluginTermCallback)Host::DynamicLibraryGetSymbol (plugin_info.plugin_handle, "LLDBPluginTerminate", error);
+ }
+ else
+ {
+ // The initialize function returned FALSE which means the
+ // plug-in might not be compatible, or might be too new or
+ // too old, or might not want to run on this machine.
+ Host::DynamicLibraryClose (plugin_info.plugin_handle);
+ plugin_info.plugin_handle = NULL;
+ plugin_info.plugin_init_callback = NULL;
+ }
+
+ // Regardless of success or failure, cache the plug-in load
+ // in our plug-in info so we don't try to load it again and
+ // again.
+ SetPluginInfo (plugin_file_spec, plugin_info);
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+ }
+ }
+ }
+
+ if (file_type == FileSpec::eFileTypeUnknown ||
+ file_type == FileSpec::eFileTypeDirectory ||
+ file_type == FileSpec::eFileTypeSymbolicLink )
+ {
+ // Try and recurse into anything that a directory or symbolic link.
+ // We must also do this for unknown as sometimes the directory enumeration
+ // might be enurating a file system that doesn't have correct file type
+ // information.
+ return FileSpec::eEnumerateDirectoryResultEnter;
+ }
+
+ return FileSpec::eEnumerateDirectoryResultNext;
+}
+
+
+void
+PluginManager::Initialize ()
+{
+#if 1
+ FileSpec dir_spec;
+ const bool find_directories = true;
+ const bool find_files = true;
+ const bool find_other = true;
+ char dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypeLLDBSystemPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ NULL);
+ }
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBUserPlugins, dir_spec))
+ {
+ if (dir_spec.Exists() && dir_spec.GetPath(dir_path, sizeof(dir_path)))
+ {
+ FileSpec::EnumerateDirectory (dir_path,
+ find_directories,
+ find_files,
+ find_other,
+ LoadPluginCallback,
+ NULL);
+ }
+ }
+#endif
+}
+
+void
+PluginManager::Terminate ()
+{
+ Mutex::Locker locker (GetPluginMapMutex ());
+ PluginTerminateMap &plugin_map = GetPluginMap ();
+
+ PluginTerminateMap::const_iterator pos, end = plugin_map.end();
+ for (pos = plugin_map.begin(); pos != end; ++pos)
+ {
+ // Call the plug-in "void LLDBPluginTerminate (void)" function if there
+ // is one (if the symbol was not NULL).
+ if (pos->second.plugin_handle)
+ {
+ if (pos->second.plugin_term_callback)
+ pos->second.plugin_term_callback();
+ Host::DynamicLibraryClose (pos->second.plugin_handle);
+ }
+ }
+ plugin_map.clear();
+}
+
+
+#pragma mark ABI
+
+
+struct ABIInstance
+{
+ ABIInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ABICreateInstance create_callback;
+};
+
+typedef std::vector<ABIInstance> ABIInstances;
+
+static Mutex &
+GetABIInstancesMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ABIInstances &
+GetABIInstances ()
+{
+ static ABIInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ ABICreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ ABIInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ GetABIInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ABICreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+
+ ABIInstances::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;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+ABICreateInstance
+PluginManager::GetABICreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetABIInstancesMutex ());
+ ABIInstances &instances = GetABIInstances ();
+
+ ABIInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark Disassembler
+
+
+struct DisassemblerInstance
+{
+ DisassemblerInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ DisassemblerCreateInstance create_callback;
+};
+
+typedef std::vector<DisassemblerInstance> DisassemblerInstances;
+
+static Mutex &
+GetDisassemblerMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static DisassemblerInstances &
+GetDisassemblerInstances ()
+{
+ static DisassemblerInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ DisassemblerCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ DisassemblerInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ GetDisassemblerInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DisassemblerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+
+ DisassemblerInstances::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;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+DisassemblerCreateInstance
+PluginManager::GetDisassemblerCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetDisassemblerMutex ());
+ DisassemblerInstances &instances = GetDisassemblerInstances ();
+
+ DisassemblerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark DynamicLoader
+
+
+struct DynamicLoaderInstance
+{
+ DynamicLoaderInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ DynamicLoaderCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<DynamicLoaderInstance> DynamicLoaderInstances;
+
+
+static Mutex &
+GetDynamicLoaderMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static DynamicLoaderInstances &
+GetDynamicLoaderInstances ()
+{
+ static DynamicLoaderInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ DynamicLoaderCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback
+)
+{
+ if (create_callback)
+ {
+ DynamicLoaderInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ GetDynamicLoaderInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (DynamicLoaderCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::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;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+DynamicLoaderCreateInstance
+PluginManager::GetDynamicLoaderCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark EmulateInstruction
+
+
+struct EmulateInstructionInstance
+{
+ EmulateInstructionInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ EmulateInstructionCreateInstance create_callback;
+};
+
+typedef std::vector<EmulateInstructionInstance> EmulateInstructionInstances;
+
+static Mutex &
+GetEmulateInstructionMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static EmulateInstructionInstances &
+GetEmulateInstructionInstances ()
+{
+ static EmulateInstructionInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ EmulateInstructionCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ EmulateInstructionInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ GetEmulateInstructionInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (EmulateInstructionCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+
+ EmulateInstructionInstances::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;
+}
+
+EmulateInstructionCreateInstance
+PluginManager::GetEmulateInstructionCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+EmulateInstructionCreateInstance
+PluginManager::GetEmulateInstructionCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetEmulateInstructionMutex ());
+ EmulateInstructionInstances &instances = GetEmulateInstructionInstances ();
+
+ EmulateInstructionInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+#pragma mark OperatingSystem
+
+
+struct OperatingSystemInstance
+{
+ OperatingSystemInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ OperatingSystemCreateInstance create_callback;
+};
+
+typedef std::vector<OperatingSystemInstance> OperatingSystemInstances;
+
+static Mutex &
+GetOperatingSystemMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static OperatingSystemInstances &
+GetOperatingSystemInstances ()
+{
+ static OperatingSystemInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ OperatingSystemCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ OperatingSystemInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ GetOperatingSystemInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (OperatingSystemCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+
+ OperatingSystemInstances::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;
+}
+
+OperatingSystemCreateInstance
+PluginManager::GetOperatingSystemCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+OperatingSystemCreateInstance
+PluginManager::GetOperatingSystemCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetOperatingSystemMutex ());
+ OperatingSystemInstances &instances = GetOperatingSystemInstances ();
+
+ OperatingSystemInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark LanguageRuntime
+
+
+struct LanguageRuntimeInstance
+{
+ LanguageRuntimeInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ LanguageRuntimeCreateInstance create_callback;
+};
+
+typedef std::vector<LanguageRuntimeInstance> LanguageRuntimeInstances;
+
+static Mutex &
+GetLanguageRuntimeMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static LanguageRuntimeInstances &
+GetLanguageRuntimeInstances ()
+{
+ static LanguageRuntimeInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ LanguageRuntimeCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LanguageRuntimeInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ GetLanguageRuntimeInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LanguageRuntimeCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+
+ LanguageRuntimeInstances::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;
+}
+
+LanguageRuntimeCreateInstance
+PluginManager::GetLanguageRuntimeCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+LanguageRuntimeCreateInstance
+PluginManager::GetLanguageRuntimeCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetLanguageRuntimeMutex ());
+ LanguageRuntimeInstances &instances = GetLanguageRuntimeInstances ();
+
+ LanguageRuntimeInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark ObjectFile
+
+struct ObjectFileInstance
+{
+ ObjectFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ create_memory_callback (NULL),
+ get_module_specifications (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ObjectFileCreateInstance create_callback;
+ ObjectFileCreateMemoryInstance create_memory_callback;
+ ObjectFileGetModuleSpecifications get_module_specifications;
+};
+
+typedef std::vector<ObjectFileInstance> ObjectFileInstances;
+
+static Mutex &
+GetObjectFileMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ObjectFileInstances &
+GetObjectFileInstances ()
+{
+ static ObjectFileInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectFileCreateInstance create_callback,
+ ObjectFileCreateMemoryInstance create_memory_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications)
+{
+ if (create_callback)
+ {
+ ObjectFileInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.create_memory_callback = create_memory_callback;
+ instance.get_module_specifications = get_module_specifications;
+ Mutex::Locker locker (GetObjectFileMutex ());
+ GetObjectFileInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::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;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+ObjectFileCreateMemoryInstance
+PluginManager::GetObjectFileCreateMemoryCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_memory_callback;
+ return NULL;
+}
+
+ObjectFileGetModuleSpecifications
+PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_module_specifications;
+ return NULL;
+}
+
+ObjectFileCreateInstance
+PluginManager::GetObjectFileCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+ObjectFileCreateMemoryInstance
+PluginManager::GetObjectFileCreateMemoryCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectFileMutex ());
+ ObjectFileInstances &instances = GetObjectFileInstances ();
+
+ ObjectFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_memory_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark ObjectContainer
+
+struct ObjectContainerInstance
+{
+ ObjectContainerInstance() :
+ name(),
+ description(),
+ create_callback (NULL),
+ get_module_specifications (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ObjectContainerCreateInstance create_callback;
+ ObjectFileGetModuleSpecifications get_module_specifications;
+
+};
+
+typedef std::vector<ObjectContainerInstance> ObjectContainerInstances;
+
+static Mutex &
+GetObjectContainerMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ObjectContainerInstances &
+GetObjectContainerInstances ()
+{
+ static ObjectContainerInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ObjectContainerCreateInstance create_callback,
+ ObjectFileGetModuleSpecifications get_module_specifications)
+{
+ if (create_callback)
+ {
+ ObjectContainerInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.get_module_specifications = get_module_specifications;
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ GetObjectContainerInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (ObjectContainerCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+
+ ObjectContainerInstances::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;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+ObjectContainerCreateInstance
+PluginManager::GetObjectContainerCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+
+ ObjectContainerInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+ObjectFileGetModuleSpecifications
+PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetObjectContainerMutex ());
+ ObjectContainerInstances &instances = GetObjectContainerInstances ();
+ if (idx < instances.size())
+ return instances[idx].get_module_specifications;
+ return NULL;
+}
+
+#pragma mark LogChannel
+
+struct LogInstance
+{
+ LogInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ LogChannelCreateInstance create_callback;
+};
+
+typedef std::vector<LogInstance> LogInstances;
+
+static Mutex &
+GetLogMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static LogInstances &
+GetLogInstances ()
+{
+ static LogInstances g_instances;
+ return g_instances;
+}
+
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ LogChannelCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ LogInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetLogMutex ());
+ GetLogInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (LogChannelCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+
+ LogInstances::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;
+}
+
+const char *
+PluginManager::GetLogChannelCreateNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+LogChannelCreateInstance
+PluginManager::GetLogChannelCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetLogMutex ());
+ LogInstances &instances = GetLogInstances ();
+
+ LogInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark Platform
+
+struct PlatformInstance
+{
+ PlatformInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback (NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ PlatformCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<PlatformInstance> PlatformInstances;
+
+static Mutex &
+GetPlatformInstancesMutex ()
+{
+ static Mutex g_platform_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_platform_instances_mutex;
+}
+
+static PlatformInstances &
+GetPlatformInstances ()
+{
+ static PlatformInstances g_platform_instances;
+ return g_platform_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ PlatformCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+
+ PlatformInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ GetPlatformInstances ().push_back (instance);
+ return true;
+ }
+ return false;
+}
+
+
+const char *
+PluginManager::GetPlatformPluginNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+const char *
+PluginManager::GetPlatformPluginDescriptionAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].description.c_str();
+ return NULL;
+}
+
+bool
+PluginManager::UnregisterPlugin (PlatformCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::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;
+}
+
+PlatformCreateInstance
+PluginManager::GetPlatformCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+PlatformCreateInstance
+PluginManager::GetPlatformCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+size_t
+PluginManager::AutoCompletePlatformName (const char *name, StringList &matches)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+ llvm::StringRef name_sref(name);
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ llvm::StringRef plugin_name (pos->name.GetCString());
+ if (plugin_name.startswith(name_sref))
+ matches.AppendString (plugin_name.data());
+ }
+ }
+ return matches.GetSize();
+}
+#pragma mark Process
+
+struct ProcessInstance
+{
+ ProcessInstance() :
+ name(),
+ description(),
+ create_callback(NULL),
+ debugger_init_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ ProcessCreateInstance create_callback;
+ DebuggerInitializeCallback debugger_init_callback;
+};
+
+typedef std::vector<ProcessInstance> ProcessInstances;
+
+static Mutex &
+GetProcessMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static ProcessInstances &
+GetProcessInstances ()
+{
+ static ProcessInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin (const ConstString &name,
+ const char *description,
+ ProcessCreateInstance create_callback,
+ DebuggerInitializeCallback debugger_init_callback)
+{
+ if (create_callback)
+ {
+ ProcessInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ instance.debugger_init_callback = debugger_init_callback;
+ Mutex::Locker locker (GetProcessMutex ());
+ GetProcessInstances ().push_back (instance);
+ }
+ return false;
+}
+
+const char *
+PluginManager::GetProcessPluginNameAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].name.GetCString();
+ return NULL;
+}
+
+const char *
+PluginManager::GetProcessPluginDescriptionAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].description.c_str();
+ return NULL;
+}
+
+bool
+PluginManager::UnregisterPlugin (ProcessCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+
+ ProcessInstances::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;
+}
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+ProcessCreateInstance
+PluginManager::GetProcessCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetProcessMutex ());
+ ProcessInstances &instances = GetProcessInstances ();
+
+ ProcessInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+#pragma mark SymbolFile
+
+struct SymbolFileInstance
+{
+ SymbolFileInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ SymbolFileCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolFileInstance> SymbolFileInstances;
+
+static Mutex &
+GetSymbolFileMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static SymbolFileInstances &
+GetSymbolFileInstances ()
+{
+ static SymbolFileInstances g_instances;
+ return g_instances;
+}
+
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ SymbolFileCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolFileInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ GetSymbolFileInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolFileCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+
+ SymbolFileInstances::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;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+SymbolFileCreateInstance
+PluginManager::GetSymbolFileCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetSymbolFileMutex ());
+ SymbolFileInstances &instances = GetSymbolFileInstances ();
+
+ SymbolFileInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+
+#pragma mark SymbolVendor
+
+struct SymbolVendorInstance
+{
+ SymbolVendorInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ SymbolVendorCreateInstance create_callback;
+};
+
+typedef std::vector<SymbolVendorInstance> SymbolVendorInstances;
+
+static Mutex &
+GetSymbolVendorMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static SymbolVendorInstances &
+GetSymbolVendorInstances ()
+{
+ static SymbolVendorInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ SymbolVendorCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ SymbolVendorInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ GetSymbolVendorInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (SymbolVendorCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+
+ SymbolVendorInstances::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;
+}
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+SymbolVendorCreateInstance
+PluginManager::GetSymbolVendorCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetSymbolVendorMutex ());
+ SymbolVendorInstances &instances = GetSymbolVendorInstances ();
+
+ SymbolVendorInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+
+#pragma mark UnwindAssembly
+
+struct UnwindAssemblyInstance
+{
+ UnwindAssemblyInstance() :
+ name(),
+ description(),
+ create_callback(NULL)
+ {
+ }
+
+ ConstString name;
+ std::string description;
+ UnwindAssemblyCreateInstance create_callback;
+};
+
+typedef std::vector<UnwindAssemblyInstance> UnwindAssemblyInstances;
+
+static Mutex &
+GetUnwindAssemblyMutex ()
+{
+ static Mutex g_instances_mutex (Mutex::eMutexTypeRecursive);
+ return g_instances_mutex;
+}
+
+static UnwindAssemblyInstances &
+GetUnwindAssemblyInstances ()
+{
+ static UnwindAssemblyInstances g_instances;
+ return g_instances;
+}
+
+bool
+PluginManager::RegisterPlugin
+(
+ const ConstString &name,
+ const char *description,
+ UnwindAssemblyCreateInstance create_callback
+)
+{
+ if (create_callback)
+ {
+ UnwindAssemblyInstance instance;
+ assert ((bool)name);
+ instance.name = name;
+ if (description && description[0])
+ instance.description = description;
+ instance.create_callback = create_callback;
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ GetUnwindAssemblyInstances ().push_back (instance);
+ }
+ return false;
+}
+
+bool
+PluginManager::UnregisterPlugin (UnwindAssemblyCreateInstance create_callback)
+{
+ if (create_callback)
+ {
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+
+ UnwindAssemblyInstances::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;
+}
+
+UnwindAssemblyCreateInstance
+PluginManager::GetUnwindAssemblyCreateCallbackAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+ if (idx < instances.size())
+ return instances[idx].create_callback;
+ return NULL;
+}
+
+
+UnwindAssemblyCreateInstance
+PluginManager::GetUnwindAssemblyCreateCallbackForPluginName (const ConstString &name)
+{
+ if (name)
+ {
+ Mutex::Locker locker (GetUnwindAssemblyMutex ());
+ UnwindAssemblyInstances &instances = GetUnwindAssemblyInstances ();
+
+ UnwindAssemblyInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (name == pos->name)
+ return pos->create_callback;
+ }
+ }
+ return NULL;
+}
+
+void
+PluginManager::DebuggerInitialize (Debugger &debugger)
+{
+ // Initialize the DynamicLoader plugins
+ {
+ Mutex::Locker locker (GetDynamicLoaderMutex ());
+ DynamicLoaderInstances &instances = GetDynamicLoaderInstances ();
+
+ DynamicLoaderInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+ // Initialize the Platform plugins
+ {
+ Mutex::Locker locker (GetPlatformInstancesMutex ());
+ PlatformInstances &instances = GetPlatformInstances ();
+
+ PlatformInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+ // Initialize the Process plugins
+ {
+ Mutex::Locker locker (GetProcessMutex());
+ ProcessInstances &instances = GetProcessInstances();
+
+ ProcessInstances::iterator pos, end = instances.end();
+ for (pos = instances.begin(); pos != end; ++ pos)
+ {
+ if (pos->debugger_init_callback)
+ pos->debugger_init_callback (debugger);
+ }
+ }
+
+}
+
+// This is the preferred new way to register plugin specific settings. e.g.
+// This will put a plugin's settings under e.g. "plugin.<plugin_type_name>.<plugin_type_desc>.SETTINGNAME".
+static lldb::OptionValuePropertiesSP
+GetDebuggerPropertyForPlugins (Debugger &debugger,
+ const ConstString &plugin_type_name,
+ const ConstString &plugin_type_desc,
+ bool can_create)
+{
+ lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties());
+ if (parent_properties_sp)
+ {
+ static ConstString g_property_name("plugin");
+
+ OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, g_property_name);
+ if (!plugin_properties_sp && can_create)
+ {
+ plugin_properties_sp.reset (new OptionValueProperties (g_property_name));
+ parent_properties_sp->AppendProperty (g_property_name,
+ ConstString("Settings specify to plugins."),
+ true,
+ plugin_properties_sp);
+ }
+
+ if (plugin_properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, plugin_type_name);
+ if (!plugin_type_properties_sp && can_create)
+ {
+ plugin_type_properties_sp.reset (new OptionValueProperties (plugin_type_name));
+ plugin_properties_sp->AppendProperty (plugin_type_name,
+ plugin_type_desc,
+ true,
+ plugin_type_properties_sp);
+ }
+ return plugin_type_properties_sp;
+ }
+ }
+ return lldb::OptionValuePropertiesSP();
+}
+
+// This is deprecated way to register plugin specific settings. e.g.
+// "<plugin_type_name>.plugin.<plugin_type_desc>.SETTINGNAME"
+// and Platform generic settings would be under "platform.SETTINGNAME".
+static lldb::OptionValuePropertiesSP
+GetDebuggerPropertyForPluginsOldStyle (Debugger &debugger,
+ const ConstString &plugin_type_name,
+ const ConstString &plugin_type_desc,
+ bool can_create)
+{
+ static ConstString g_property_name("plugin");
+ lldb::OptionValuePropertiesSP parent_properties_sp (debugger.GetValueProperties());
+ if (parent_properties_sp)
+ {
+ OptionValuePropertiesSP plugin_properties_sp = parent_properties_sp->GetSubProperty (NULL, plugin_type_name);
+ if (!plugin_properties_sp && can_create)
+ {
+ plugin_properties_sp.reset (new OptionValueProperties (plugin_type_name));
+ parent_properties_sp->AppendProperty (plugin_type_name,
+ plugin_type_desc,
+ true,
+ plugin_properties_sp);
+ }
+
+ if (plugin_properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp = plugin_properties_sp->GetSubProperty (NULL, g_property_name);
+ if (!plugin_type_properties_sp && can_create)
+ {
+ plugin_type_properties_sp.reset (new OptionValueProperties (g_property_name));
+ plugin_properties_sp->AppendProperty (g_property_name,
+ ConstString("Settings specific to plugins"),
+ true,
+ plugin_type_properties_sp);
+ }
+ return plugin_type_properties_sp;
+ }
+ }
+ return lldb::OptionValuePropertiesSP();
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForDynamicLoaderPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("dynamic-loader"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForDynamicLoaderPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("dynamic-loader"),
+ ConstString("Settings for dynamic loader plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForPlatformPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger,
+ ConstString("platform"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForPlatformPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPluginsOldStyle (debugger,
+ ConstString("platform"),
+ ConstString("Settings for platform plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+lldb::OptionValuePropertiesSP
+PluginManager::GetSettingForProcessPlugin (Debugger &debugger, const ConstString &setting_name)
+{
+ lldb::OptionValuePropertiesSP properties_sp;
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("process"),
+ ConstString(), // not creating to so we don't need the description
+ false));
+ if (plugin_type_properties_sp)
+ properties_sp = plugin_type_properties_sp->GetSubProperty (NULL, setting_name);
+ return properties_sp;
+}
+
+bool
+PluginManager::CreateSettingForProcessPlugin (Debugger &debugger,
+ const lldb::OptionValuePropertiesSP &properties_sp,
+ const ConstString &description,
+ bool is_global_property)
+{
+ if (properties_sp)
+ {
+ lldb::OptionValuePropertiesSP plugin_type_properties_sp (GetDebuggerPropertyForPlugins (debugger,
+ ConstString("process"),
+ ConstString("Settings for process plug-ins"),
+ true));
+ if (plugin_type_properties_sp)
+ {
+ plugin_type_properties_sp->AppendProperty (properties_sp->GetName(),
+ description,
+ is_global_property,
+ properties_sp);
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/source/Core/RegisterValue.cpp b/source/Core/RegisterValue.cpp
new file mode 100644
index 000000000000..91f5bea805c6
--- /dev/null
+++ b/source/Core/RegisterValue.cpp
@@ -0,0 +1,1272 @@
+//===-- RegisterValue.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/RegisterValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+RegisterValue::Dump (Stream *s,
+ const RegisterInfo *reg_info,
+ bool prefix_with_name,
+ bool prefix_with_alt_name,
+ Format format,
+ uint32_t reg_name_right_align_at) const
+{
+ DataExtractor data;
+ if (GetData (data))
+ {
+ bool name_printed = false;
+ // For simplicity, alignment of the register name printing applies only
+ // in the most common case where:
+ //
+ // prefix_with_name^prefix_with_alt_name is true
+ //
+ StreamString format_string;
+ if (reg_name_right_align_at && (prefix_with_name^prefix_with_alt_name))
+ format_string.Printf("%%%us", reg_name_right_align_at);
+ else
+ format_string.Printf("%%s");
+ const char *fmt = format_string.GetData();
+ if (prefix_with_name)
+ {
+ if (reg_info->name)
+ {
+ s->Printf (fmt, reg_info->name);
+ name_printed = true;
+ }
+ else if (reg_info->alt_name)
+ {
+ s->Printf (fmt, reg_info->alt_name);
+ prefix_with_alt_name = false;
+ name_printed = true;
+ }
+ }
+ if (prefix_with_alt_name)
+ {
+ if (name_printed)
+ s->PutChar ('/');
+ if (reg_info->alt_name)
+ {
+ s->Printf (fmt, reg_info->alt_name);
+ name_printed = true;
+ }
+ else if (!name_printed)
+ {
+ // No alternate name but we were asked to display a name, so show the main name
+ s->Printf (fmt, reg_info->name);
+ name_printed = true;
+ }
+ }
+ if (name_printed)
+ s->PutCString (" = ");
+
+ if (format == eFormatDefault)
+ format = reg_info->format;
+
+ data.Dump (s,
+ 0, // Offset in "data"
+ format, // Format to use when dumping
+ reg_info->byte_size, // item_byte_size
+ 1, // item_count
+ UINT32_MAX, // num_per_line
+ LLDB_INVALID_ADDRESS, // base_addr
+ 0, // item_bit_size
+ 0); // item_bit_offset
+ return true;
+ }
+ return false;
+}
+
+
+bool
+RegisterValue::GetData (DataExtractor &data) const
+{
+ return data.SetData(GetBytes(), GetByteSize(), GetByteOrder()) > 0;
+}
+
+
+uint32_t
+RegisterValue::GetAsMemoryData (const RegisterInfo *reg_info,
+ void *dst,
+ uint32_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const
+{
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return 0;
+ }
+
+ // ReadRegister should have already been called on tgus object prior to
+ // calling this.
+ if (GetType() == eTypeInvalid)
+ {
+ // No value has been read into this object...
+ error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
+ return 0;
+ }
+
+ if (dst_len > kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("destination is too big");
+ return 0;
+ }
+
+ const uint32_t src_len = reg_info->byte_size;
+
+ // Extract the register data into a data extractor
+ DataExtractor reg_data;
+ if (!GetData(reg_data))
+ {
+ error.SetErrorString ("invalid register value to copy into");
+ return 0;
+ }
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const uint32_t bytes_copied = reg_data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
+
+ return bytes_copied;
+}
+
+uint32_t
+RegisterValue::SetFromMemoryData (const RegisterInfo *reg_info,
+ const void *src,
+ uint32_t src_len,
+ lldb::ByteOrder src_byte_order,
+ Error &error)
+{
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return 0;
+ }
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > kMaxRegisterByteSize)
+ {
+ error.SetErrorStringWithFormat ("register buffer is too small to receive %u bytes of data.", src_len);
+ return 0;
+ }
+
+ const uint32_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len);
+ return 0;
+ }
+
+ // Use a data extractor to correctly copy and pad the bytes read into the
+ // register value
+ DataExtractor src_data (src, src_len, src_byte_order, 4);
+
+ // Given the register info, set the value type of this RegisterValue object
+ SetType (reg_info);
+ // And make sure we were able to figure out what that register value was
+ RegisterValue::Type value_type = GetType();
+ if (value_type == eTypeInvalid)
+ {
+ // No value has been read into this object...
+ error.SetErrorStringWithFormat("invalid register value type for register %s", reg_info->name);
+ return 0;
+ }
+ else if (value_type == eTypeBytes)
+ {
+ m_data.buffer.byte_order = src_byte_order;
+ // Make sure to set the buffer length of the destination buffer to avoid
+ // problems due to uninitalized variables.
+ m_data.buffer.length = src_len;
+ }
+
+ const uint32_t bytes_copied = src_data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ GetBytes(), // dst buffer
+ GetByteSize(), // dst length
+ GetByteOrder()); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorStringWithFormat("failed to copy data for register write of %s", reg_info->name);
+
+ return bytes_copied;
+}
+
+bool
+RegisterValue::GetScalarValue (Scalar &scalar) const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: scalar = m_data.uint8; return true;
+ case 2: scalar = m_data.uint16; return true;
+ case 4: scalar = m_data.uint32; return true;
+ case 8: scalar = m_data.uint64; return true;
+ }
+ }
+ case eTypeUInt8: scalar = m_data.uint8; return true;
+ case eTypeUInt16: scalar = m_data.uint16; return true;
+ case eTypeUInt32: scalar = m_data.uint32; return true;
+ case eTypeUInt64: scalar = m_data.uint64; return true;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: break;
+#endif
+ case eTypeFloat: scalar = m_data.ieee_float; return true;
+ case eTypeDouble: scalar = m_data.ieee_double; return true;
+ case eTypeLongDouble: scalar = m_data.ieee_long_double; return true;
+ }
+ return false;
+}
+
+void
+RegisterValue::Clear()
+{
+ m_type = eTypeInvalid;
+}
+
+RegisterValue::Type
+RegisterValue::SetType (const RegisterInfo *reg_info)
+{
+ m_type = eTypeInvalid;
+ const uint32_t byte_size = reg_info->byte_size;
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ if (byte_size == 1)
+ m_type = eTypeUInt8;
+ else if (byte_size <= 2)
+ m_type = eTypeUInt16;
+ else if (byte_size <= 4)
+ m_type = eTypeUInt32;
+ else if (byte_size <= 8)
+ m_type = eTypeUInt64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ else if (byte_size <= 16)
+ m_type = eTypeUInt128;
+#endif
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof(float))
+ m_type = eTypeFloat;
+ else if (byte_size == sizeof(double))
+ m_type = eTypeDouble;
+ else if (byte_size == sizeof(long double))
+ m_type = eTypeLongDouble;
+ break;
+
+ case eEncodingVector:
+ m_type = eTypeBytes;
+ break;
+ }
+ return m_type;
+}
+
+Error
+RegisterValue::SetValueFromData (const RegisterInfo *reg_info, DataExtractor &src, lldb::offset_t src_offset, bool partial_data_ok)
+{
+ Error error;
+
+ if (src.GetByteSize() == 0)
+ {
+ error.SetErrorString ("empty data.");
+ return error;
+ }
+
+ if (reg_info->byte_size == 0)
+ {
+ error.SetErrorString ("invalid register info.");
+ return error;
+ }
+
+ uint32_t src_len = src.GetByteSize() - src_offset;
+
+ if (!partial_data_ok && (src_len < reg_info->byte_size))
+ {
+ error.SetErrorString ("not enough data.");
+ return error;
+ }
+
+ // Cap the data length if there is more than enough bytes for this register
+ // value
+ if (src_len > reg_info->byte_size)
+ src_len = reg_info->byte_size;
+
+ // Zero out the value in case we get partial data...
+ memset (m_data.buffer.bytes, 0, sizeof (m_data.buffer.bytes));
+
+ switch (SetType (reg_info))
+ {
+ case eTypeInvalid:
+ error.SetErrorString("");
+ break;
+ case eTypeUInt8: SetUInt8 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt16: SetUInt16 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt32: SetUInt32 (src.GetMaxU32 (&src_offset, src_len)); break;
+ case eTypeUInt64: SetUInt64 (src.GetMaxU64 (&src_offset, src_len)); break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ {
+ __uint128_t data1 = src.GetU64 (&src_offset);
+ __uint128_t data2 = src.GetU64 (&src_offset);
+ if (src.GetByteSize() == eByteOrderBig)
+ SetUInt128 (data1 << 64 + data2);
+ else
+ SetUInt128 (data2 << 64 + data1);
+ }
+ break;
+#endif
+ case eTypeFloat: SetFloat (src.GetFloat (&src_offset)); break;
+ case eTypeDouble: SetDouble(src.GetDouble (&src_offset)); break;
+ case eTypeLongDouble: SetFloat (src.GetLongDouble (&src_offset)); break;
+ case eTypeBytes:
+ {
+ m_data.buffer.length = reg_info->byte_size;
+ m_data.buffer.byte_order = src.GetByteOrder();
+ assert (m_data.buffer.length <= kMaxRegisterByteSize);
+ if (m_data.buffer.length > kMaxRegisterByteSize)
+ m_data.buffer.length = kMaxRegisterByteSize;
+ if (src.CopyByteOrderedData (src_offset, // offset within "src" to start extracting data
+ src_len, // src length
+ m_data.buffer.bytes, // dst buffer
+ m_data.buffer.length, // dst length
+ m_data.buffer.byte_order) == 0)// dst byte order
+ {
+ error.SetErrorString ("data copy failed data.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+#include "llvm/ADT/StringRef.h"
+#include <vector>
+static inline void StripSpaces(llvm::StringRef &Str)
+{
+ while (!Str.empty() && isspace(Str[0]))
+ Str = Str.substr(1);
+ while (!Str.empty() && isspace(Str.back()))
+ Str = Str.substr(0, Str.size()-1);
+}
+static inline void LStrip(llvm::StringRef &Str, char c)
+{
+ if (!Str.empty() && Str.front() == c)
+ Str = Str.substr(1);
+}
+static inline void RStrip(llvm::StringRef &Str, char c)
+{
+ if (!Str.empty() && Str.back() == c)
+ Str = Str.substr(0, Str.size()-1);
+}
+// Helper function for RegisterValue::SetValueFromCString()
+static bool
+ParseVectorEncoding(const RegisterInfo *reg_info, const char *vector_str, const uint32_t byte_size, RegisterValue *reg_value)
+{
+ // Example: vector_str = "{0x2c 0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e}".
+ llvm::StringRef Str(vector_str);
+ StripSpaces(Str);
+ LStrip(Str, '{');
+ RStrip(Str, '}');
+ StripSpaces(Str);
+
+ char Sep = ' ';
+
+ // The first split should give us:
+ // ('0x2c', '0x4b 0x2a 0x3e 0xd0 0x4f 0x2a 0x3e 0xac 0x4a 0x2a 0x3e 0x84 0x4f 0x2a 0x3e').
+ std::pair<llvm::StringRef, llvm::StringRef> Pair = Str.split(Sep);
+ std::vector<uint8_t> bytes;
+ unsigned byte = 0;
+
+ // Using radix auto-sensing by passing 0 as the radix.
+ // Keep on processing the vector elements as long as the parsing succeeds and the vector size is < byte_size.
+ while (!Pair.first.getAsInteger(0, byte) && bytes.size() < byte_size) {
+ bytes.push_back(byte);
+ Pair = Pair.second.split(Sep);
+ }
+
+ // Check for vector of exact byte_size elements.
+ if (bytes.size() != byte_size)
+ return false;
+
+ reg_value->SetBytes(&(bytes.front()), byte_size, eByteOrderLittle);
+ return true;
+}
+Error
+RegisterValue::SetValueFromCString (const RegisterInfo *reg_info, const char *value_str)
+{
+ Error error;
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("Invalid register info argument.");
+ return error;
+ }
+
+ if (value_str == NULL || value_str[0] == '\0')
+ {
+ error.SetErrorString ("Invalid c-string value string.");
+ return error;
+ }
+ bool success = false;
+ const uint32_t byte_size = reg_info->byte_size;
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ error.SetErrorString ("Invalid encoding.");
+ break;
+
+ case eEncodingUint:
+ if (byte_size <= sizeof (uint64_t))
+ {
+ uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
+ else if (!Args::UInt64ValueIsValidForByteSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte unsigned integer value", uval64, byte_size);
+ else
+ {
+ if (!SetUInt (uval64, reg_info->byte_size))
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size <= sizeof (long long))
+ {
+ uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
+ else if (!Args::SInt64ValueIsValidForByteSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %u byte signed integer value", sval64, byte_size);
+ else
+ {
+ if (!SetUInt (sval64, reg_info->byte_size))
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof (float))
+ {
+ if (::sscanf (value_str, "%f", &m_data.ieee_float) == 1)
+ m_type = eTypeFloat;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (double))
+ {
+ if (::sscanf (value_str, "%lf", &m_data.ieee_double) == 1)
+ m_type = eTypeDouble;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (long double))
+ {
+ if (::sscanf (value_str, "%Lf", &m_data.ieee_long_double) == 1)
+ m_type = eTypeLongDouble;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported float byte size: %u", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ if (!ParseVectorEncoding(reg_info, value_str, byte_size, this))
+ error.SetErrorString ("unrecognized vector encoding string value.");
+ break;
+ }
+ if (error.Fail())
+ m_type = eTypeInvalid;
+
+ return error;
+}
+
+
+bool
+RegisterValue::SignExtend (uint32_t sign_bitpos)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (sign_bitpos == (8-1))
+ return true;
+ else if (sign_bitpos < (8-1))
+ {
+ uint8_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint8 & sign_bit)
+ {
+ const uint8_t mask = ~(sign_bit) + 1u;
+ m_data.uint8 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (sign_bitpos == (16-1))
+ return true;
+ else if (sign_bitpos < (16-1))
+ {
+ uint16_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint16 & sign_bit)
+ {
+ const uint16_t mask = ~(sign_bit) + 1u;
+ m_data.uint16 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (sign_bitpos == (32-1))
+ return true;
+ else if (sign_bitpos < (32-1))
+ {
+ uint32_t sign_bit = 1u << sign_bitpos;
+ if (m_data.uint32 & sign_bit)
+ {
+ const uint32_t mask = ~(sign_bit) + 1u;
+ m_data.uint32 |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (sign_bitpos == (64-1))
+ return true;
+ else if (sign_bitpos < (64-1))
+ {
+ uint64_t sign_bit = 1ull << sign_bitpos;
+ if (m_data.uint64 & sign_bit)
+ {
+ const uint64_t mask = ~(sign_bit) + 1ull;
+ m_data.uint64 |= mask;
+ }
+ return true;
+ }
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sign_bitpos == (128-1))
+ return true;
+ else if (sign_bitpos < (128-1))
+ {
+ __uint128_t sign_bit = (__uint128_t)1u << sign_bitpos;
+ if (m_data.uint128 & sign_bit)
+ {
+ const uint128_t mask = ~(sign_bit) + 1u;
+ m_data.uint128 |= mask;
+ }
+ return true;
+ }
+ break;
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ case eTypeBytes:
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterValue::CopyValue (const RegisterValue &rhs)
+{
+ m_type = rhs.m_type;
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ return false;
+ case eTypeUInt8: m_data.uint8 = rhs.m_data.uint8; break;
+ case eTypeUInt16: m_data.uint16 = rhs.m_data.uint16; break;
+ case eTypeUInt32: m_data.uint32 = rhs.m_data.uint32; break;
+ case eTypeUInt64: m_data.uint64 = rhs.m_data.uint64; break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: m_data.uint128 = rhs.m_data.uint128; break;
+#endif
+ case eTypeFloat: m_data.ieee_float = rhs.m_data.ieee_float; break;
+ case eTypeDouble: m_data.ieee_double = rhs.m_data.ieee_double; break;
+ case eTypeLongDouble: m_data.ieee_long_double = rhs.m_data.ieee_long_double; break;
+ case eTypeBytes:
+ assert (rhs.m_data.buffer.length <= kMaxRegisterByteSize);
+ ::memcpy (m_data.buffer.bytes, rhs.m_data.buffer.bytes, kMaxRegisterByteSize);
+ m_data.buffer.length = rhs.m_data.buffer.length;
+ m_data.buffer.byte_order = rhs.m_data.buffer.byte_order;
+ break;
+ }
+ return true;
+}
+
+uint16_t
+RegisterValue::GetAsUInt16 (uint16_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint32_t
+RegisterValue::GetAsUInt32 (uint32_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(uint32_t))
+ return m_data.uint32;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+RegisterValue::GetAsUInt64 (uint64_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeUInt64: return m_data.uint64;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(uint64_t))
+ return m_data.uint64;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default: break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ case 8: return m_data.uint64;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+__uint128_t
+RegisterValue::GetAsUInt128 (__uint128_t fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt8: return m_data.uint8;
+ case eTypeUInt16: return m_data.uint16;
+ case eTypeUInt32: return m_data.uint32;
+ case eTypeUInt64: return m_data.uint64;
+ case eTypeUInt128: return m_data.uint128;
+ case eTypeFloat:
+ if (sizeof(float) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeDouble:
+ if (sizeof(double) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(long double) == sizeof(__uint128_t))
+ return m_data.uint128;
+ break;
+ case eTypeBytes:
+ {
+ switch (m_data.buffer.length)
+ {
+ default:
+ break;
+ case 1: return m_data.uint8;
+ case 2: return m_data.uint16;
+ case 4: return m_data.uint32;
+ case 8: return m_data.uint64;
+ case 16: return m_data.uint128;
+ }
+ }
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+#endif
+float
+RegisterValue::GetAsFloat (float fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default: break;
+ case eTypeUInt32:
+ if (sizeof(float) == sizeof(m_data.uint32))
+ return m_data.ieee_float;
+ break;
+ case eTypeUInt64:
+ if (sizeof(float) == sizeof(m_data.uint64))
+ return m_data.ieee_float;
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(float) == sizeof(m_data.uint128))
+ return m_data.ieee_float;
+ break;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble:
+ if (sizeof(float) == sizeof(double))
+ return m_data.ieee_float;
+ break;
+ case eTypeLongDouble:
+ if (sizeof(float) == sizeof(long double))
+ return m_data.ieee_float;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+double
+RegisterValue::GetAsDouble (double fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default:
+ break;
+
+ case eTypeUInt32:
+ if (sizeof(double) == sizeof(m_data.uint32))
+ return m_data.ieee_double;
+ break;
+
+ case eTypeUInt64:
+ if (sizeof(double) == sizeof(m_data.uint64))
+ return m_data.ieee_double;
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(double) == sizeof(m_data.uint128))
+ return m_data.ieee_double;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double;
+
+ case eTypeLongDouble:
+ if (sizeof(double) == sizeof(long double))
+ return m_data.ieee_double;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+long double
+RegisterValue::GetAsLongDouble (long double fail_value, bool *success_ptr) const
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (m_type)
+ {
+ default:
+ break;
+
+ case eTypeUInt32:
+ if (sizeof(long double) == sizeof(m_data.uint32))
+ return m_data.ieee_long_double;
+ break;
+
+ case eTypeUInt64:
+ if (sizeof(long double) == sizeof(m_data.uint64))
+ return m_data.ieee_long_double;
+ break;
+
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (sizeof(long double) == sizeof(m_data.uint128))
+ return m_data.ieee_long_double;
+#endif
+ case eTypeFloat: return m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double;
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+const void *
+RegisterValue::GetBytes () const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return &m_data.uint8;
+ case eTypeUInt16: return &m_data.uint16;
+ case eTypeUInt32: return &m_data.uint32;
+ case eTypeUInt64: return &m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return &m_data.uint128;
+#endif
+ case eTypeFloat: return &m_data.ieee_float;
+ case eTypeDouble: return &m_data.ieee_double;
+ case eTypeLongDouble: return &m_data.ieee_long_double;
+ case eTypeBytes: return m_data.buffer.bytes;
+ }
+ return NULL;
+}
+
+void *
+RegisterValue::GetBytes ()
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return &m_data.uint8;
+ case eTypeUInt16: return &m_data.uint16;
+ case eTypeUInt32: return &m_data.uint32;
+ case eTypeUInt64: return &m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return &m_data.uint128;
+#endif
+ case eTypeFloat: return &m_data.ieee_float;
+ case eTypeDouble: return &m_data.ieee_double;
+ case eTypeLongDouble: return &m_data.ieee_long_double;
+ case eTypeBytes: return m_data.buffer.bytes;
+ }
+ return NULL;
+}
+
+uint32_t
+RegisterValue::GetByteSize () const
+{
+ switch (m_type)
+ {
+ case eTypeInvalid: break;
+ case eTypeUInt8: return sizeof(m_data.uint8);
+ case eTypeUInt16: return sizeof(m_data.uint16);
+ case eTypeUInt32: return sizeof(m_data.uint32);
+ case eTypeUInt64: return sizeof(m_data.uint64);
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return sizeof(m_data.uint128);
+#endif
+ case eTypeFloat: return sizeof(m_data.ieee_float);
+ case eTypeDouble: return sizeof(m_data.ieee_double);
+ case eTypeLongDouble: return sizeof(m_data.ieee_long_double);
+ case eTypeBytes: return m_data.buffer.length;
+ }
+ return 0;
+}
+
+
+bool
+RegisterValue::SetUInt (uint64_t uint, uint32_t byte_size)
+{
+ if (byte_size == 0)
+ {
+ SetUInt64 (uint);
+ }
+ else if (byte_size == 1)
+ {
+ SetUInt8 (uint);
+ }
+ else if (byte_size <= 2)
+ {
+ SetUInt16 (uint);
+ }
+ else if (byte_size <= 4)
+ {
+ SetUInt32 (uint);
+ }
+ else if (byte_size <= 8)
+ {
+ SetUInt64 (uint);
+ }
+#if defined (ENABLE_128_BIT_SUPPORT)
+ else if (byte_size <= 16)
+ {
+ SetUInt128 (uint);
+ }
+#endif
+ else
+ return false;
+ return true;
+}
+
+void
+RegisterValue::SetBytes (const void *bytes, size_t length, lldb::ByteOrder byte_order)
+{
+ // If this assertion fires off we need to increase the size of
+ // m_data.buffer.bytes, or make it something that is allocated on
+ // the heap. Since the data buffer is in a union, we can't make it
+ // a collection class like SmallVector...
+ if (bytes && length > 0)
+ {
+ assert (length <= sizeof (m_data.buffer.bytes) && "Storing too many bytes in a RegisterValue.");
+ m_type = eTypeBytes;
+ m_data.buffer.length = length;
+ memcpy (m_data.buffer.bytes, bytes, length);
+ m_data.buffer.byte_order = byte_order;
+ }
+ else
+ {
+ m_type = eTypeInvalid;
+ m_data.buffer.length = 0;
+ }
+}
+
+
+bool
+RegisterValue::operator == (const RegisterValue &rhs) const
+{
+ if (m_type == rhs.m_type)
+ {
+ switch (m_type)
+ {
+ case eTypeInvalid: return true;
+ case eTypeUInt8: return m_data.uint8 == rhs.m_data.uint8;
+ case eTypeUInt16: return m_data.uint16 == rhs.m_data.uint16;
+ case eTypeUInt32: return m_data.uint32 == rhs.m_data.uint32;
+ case eTypeUInt64: return m_data.uint64 == rhs.m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return m_data.uint128 == rhs.m_data.uint128;
+#endif
+ case eTypeFloat: return m_data.ieee_float == rhs.m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double == rhs.m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double == rhs.m_data.ieee_long_double;
+ case eTypeBytes:
+ if (m_data.buffer.length != rhs.m_data.buffer.length)
+ return false;
+ else
+ {
+ uint8_t length = m_data.buffer.length;
+ if (length > kMaxRegisterByteSize)
+ length = kMaxRegisterByteSize;
+ return memcmp (m_data.buffer.bytes, rhs.m_data.buffer.bytes, length) == 0;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterValue::operator != (const RegisterValue &rhs) const
+{
+ if (m_type != rhs.m_type)
+ return true;
+ switch (m_type)
+ {
+ case eTypeInvalid: return false;
+ case eTypeUInt8: return m_data.uint8 != rhs.m_data.uint8;
+ case eTypeUInt16: return m_data.uint16 != rhs.m_data.uint16;
+ case eTypeUInt32: return m_data.uint32 != rhs.m_data.uint32;
+ case eTypeUInt64: return m_data.uint64 != rhs.m_data.uint64;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128: return m_data.uint128 != rhs.m_data.uint128;
+#endif
+ case eTypeFloat: return m_data.ieee_float != rhs.m_data.ieee_float;
+ case eTypeDouble: return m_data.ieee_double != rhs.m_data.ieee_double;
+ case eTypeLongDouble: return m_data.ieee_long_double != rhs.m_data.ieee_long_double;
+ case eTypeBytes:
+ if (m_data.buffer.length != rhs.m_data.buffer.length)
+ {
+ return true;
+ }
+ else
+ {
+ uint8_t length = m_data.buffer.length;
+ if (length > kMaxRegisterByteSize)
+ length = kMaxRegisterByteSize;
+ return memcmp (m_data.buffer.bytes, rhs.m_data.buffer.bytes, length) != 0;
+ }
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterValue::ClearBit (uint32_t bit)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (bit < 8)
+ {
+ m_data.uint8 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (bit < 16)
+ {
+ m_data.uint16 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (bit < 32)
+ {
+ m_data.uint32 &= ~(1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (bit < 64)
+ {
+ m_data.uint64 &= ~(1ull << (uint64_t)bit);
+ return true;
+ }
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (bit < 64)
+ {
+ m_data.uint128 &= ~((__uint128_t)1ull << (__uint128_t)bit);
+ return true;
+ }
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (m_data.buffer.byte_order == eByteOrderBig || m_data.buffer.byte_order == eByteOrderLittle)
+ {
+ uint32_t byte_idx;
+ if (m_data.buffer.byte_order == eByteOrderBig)
+ byte_idx = m_data.buffer.length - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < m_data.buffer.length)
+ {
+ m_data.buffer.bytes[byte_idx] &= ~(1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+
+bool
+RegisterValue::SetBit (uint32_t bit)
+{
+ switch (m_type)
+ {
+ case eTypeInvalid:
+ break;
+
+ case eTypeUInt8:
+ if (bit < 8)
+ {
+ m_data.uint8 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt16:
+ if (bit < 16)
+ {
+ m_data.uint16 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt32:
+ if (bit < 32)
+ {
+ m_data.uint32 |= (1u << bit);
+ return true;
+ }
+ break;
+
+ case eTypeUInt64:
+ if (bit < 64)
+ {
+ m_data.uint64 |= (1ull << (uint64_t)bit);
+ return true;
+ }
+ break;
+#if defined (ENABLE_128_BIT_SUPPORT)
+ case eTypeUInt128:
+ if (bit < 64)
+ {
+ m_data.uint128 |= ((__uint128_t)1ull << (__uint128_t)bit);
+ return true;
+ }
+#endif
+ case eTypeFloat:
+ case eTypeDouble:
+ case eTypeLongDouble:
+ break;
+
+ case eTypeBytes:
+ if (m_data.buffer.byte_order == eByteOrderBig || m_data.buffer.byte_order == eByteOrderLittle)
+ {
+ uint32_t byte_idx;
+ if (m_data.buffer.byte_order == eByteOrderBig)
+ byte_idx = m_data.buffer.length - (bit / 8) - 1;
+ else
+ byte_idx = bit / 8;
+
+ const uint32_t byte_bit = bit % 8;
+ if (byte_idx < m_data.buffer.length)
+ {
+ m_data.buffer.bytes[byte_idx] |= (1u << byte_bit);
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
diff --git a/source/Core/RegularExpression.cpp b/source/Core/RegularExpression.cpp
new file mode 100644
index 000000000000..4ccd7748b13e
--- /dev/null
+++ b/source/Core/RegularExpression.cpp
@@ -0,0 +1,279 @@
+//===-- RegularExpression.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RegularExpression.h"
+#include "llvm/ADT/StringRef.h"
+#include <string.h>
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression() :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(REG_EXTENDED)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(const char* re, int flags) :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(flags)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re);
+}
+
+//----------------------------------------------------------------------
+// Constructor that compiles "re" using "flags" and stores the
+// resulting compiled regular expression into this object.
+//----------------------------------------------------------------------
+RegularExpression::RegularExpression(const char* re) :
+ m_re(),
+ m_comp_err (1),
+ m_preg(),
+ m_compile_flags(REG_EXTENDED)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(re);
+}
+
+RegularExpression::RegularExpression(const RegularExpression &rhs)
+{
+ memset(&m_preg,0,sizeof(m_preg));
+ Compile(rhs.GetText(), rhs.GetCompileFlags());
+}
+
+const RegularExpression &
+RegularExpression::operator= (const RegularExpression &rhs)
+{
+ if (&rhs != this)
+ {
+ Compile (rhs.GetText(), rhs.GetCompileFlags());
+ }
+ return *this;
+}
+//----------------------------------------------------------------------
+// Destructor
+//
+// Any previosuly compiled regular expression contained in this
+// object will be freed.
+//----------------------------------------------------------------------
+RegularExpression::~RegularExpression()
+{
+ Free();
+}
+
+//----------------------------------------------------------------------
+// Compile a regular expression using the supplied regular
+// expression text and flags. The compied regular expression lives
+// in this object so that it can be readily used for regular
+// expression matches. Execute() can be called after the regular
+// expression is compiled. Any previosuly compiled regular
+// expression contained in this object will be freed.
+//
+// RETURNS
+// True of the refular expression compiles successfully, false
+// otherwise.
+//----------------------------------------------------------------------
+bool
+RegularExpression::Compile(const char* re)
+{
+ return Compile (re, m_compile_flags);
+}
+
+bool
+RegularExpression::Compile(const char* re, int flags)
+{
+ Free();
+ m_compile_flags = flags;
+
+ if (re && re[0])
+ {
+ m_re = re;
+ m_comp_err = ::regcomp (&m_preg, re, flags);
+ }
+ else
+ {
+ // No valid regular expression
+ m_comp_err = 1;
+ }
+
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Execute a regular expression match using the compiled regular
+// expression that is already in this object against the match
+// string "s". If any parens are used for regular expression
+// matches "match_count" should indicate the number of regmatch_t
+// values that are present in "match_ptr". The regular expression
+// will be executed using the "execute_flags".
+//---------------------------------------------------------------------
+bool
+RegularExpression::Execute(const char* s, Match *match, int execute_flags) const
+{
+ int err = 1;
+ if (s != NULL && m_comp_err == 0)
+ {
+ if (match)
+ {
+ err = ::regexec (&m_preg,
+ s,
+ match->GetSize(),
+ match->GetData(),
+ execute_flags);
+ }
+ else
+ {
+ err = ::regexec (&m_preg,
+ s,
+ 0,
+ NULL,
+ execute_flags);
+ }
+ }
+
+ if (err != 0)
+ {
+ // The regular expression didn't compile, so clear the matches
+ if (match)
+ match->Clear();
+ return false;
+ }
+ return true;
+}
+
+bool
+RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, std::string& match_str) const
+{
+ if (idx < m_matches.size())
+ {
+ 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;
+ }
+ }
+ return false;
+}
+
+bool
+RegularExpression::Match::GetMatchAtIndex (const char* s, uint32_t idx, llvm::StringRef& match_str) const
+{
+ if (idx < m_matches.size())
+ {
+ if (m_matches[idx].rm_eo == m_matches[idx].rm_so)
+ {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ }
+ else if (m_matches[idx].rm_eo > m_matches[idx].rm_so)
+ {
+ match_str = llvm::StringRef (s + m_matches[idx].rm_so, m_matches[idx].rm_eo - m_matches[idx].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegularExpression::Match::GetMatchSpanningIndices (const char* s, uint32_t idx1, uint32_t idx2, llvm::StringRef& match_str) const
+{
+ if (idx1 < m_matches.size() && idx2 < m_matches.size())
+ {
+ if (m_matches[idx1].rm_so == m_matches[idx2].rm_eo)
+ {
+ // Matched the empty string...
+ match_str = llvm::StringRef();
+ return true;
+ }
+ else if (m_matches[idx1].rm_so < m_matches[idx2].rm_eo)
+ {
+ match_str = llvm::StringRef (s + m_matches[idx1].rm_so, m_matches[idx2].rm_eo - m_matches[idx1].rm_so);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Returns true if the regular expression compiled and is ready
+// for execution.
+//----------------------------------------------------------------------
+bool
+RegularExpression::IsValid () const
+{
+ return m_comp_err == 0;
+}
+
+//----------------------------------------------------------------------
+// Returns the text that was used to compile the current regular
+// expression.
+//----------------------------------------------------------------------
+const char*
+RegularExpression::GetText () const
+{
+ if (m_re.empty())
+ return NULL;
+ return m_re.c_str();
+}
+
+//----------------------------------------------------------------------
+// Free any contained compiled regular expressions.
+//----------------------------------------------------------------------
+void
+RegularExpression::Free()
+{
+ if (m_comp_err == 0)
+ {
+ m_re.clear();
+ regfree(&m_preg);
+ // Set a compile error since we no longer have a valid regex
+ m_comp_err = 1;
+ }
+}
+
+size_t
+RegularExpression::GetErrorAsCString (char *err_str, size_t err_str_max_len) const
+{
+ if (m_comp_err == 0)
+ {
+ if (err_str && err_str_max_len)
+ *err_str = '\0';
+ return 0;
+ }
+
+ return ::regerror (m_comp_err, &m_preg, err_str, err_str_max_len);
+}
+
+bool
+RegularExpression::operator < (const RegularExpression& rhs) const
+{
+ return (m_re < rhs.m_re);
+}
+
diff --git a/source/Core/Scalar.cpp b/source/Core/Scalar.cpp
new file mode 100644
index 000000000000..26f743796254
--- /dev/null
+++ b/source/Core/Scalar.cpp
@@ -0,0 +1,2279 @@
+//===-- Scalar.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/Scalar.h"
+
+#include <math.h>
+#include <inttypes.h>
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Host/Endian.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Promote to max type currently follows the ANSI C rule for type
+// promotion in expressions.
+//----------------------------------------------------------------------
+static Scalar::Type
+PromoteToMaxType
+(
+ const Scalar& lhs, // The const left hand side object
+ const Scalar& rhs, // The const right hand side object
+ Scalar& temp_value, // A modifiable temp value than can be used to hold either the promoted lhs or rhs object
+ const Scalar* &promoted_lhs_ptr, // Pointer to the resulting possibly promoted value of lhs (at most one of lhs/rhs will get promoted)
+ const Scalar* &promoted_rhs_ptr // Pointer to the resulting possibly promoted value of rhs (at most one of lhs/rhs will get promoted)
+)
+{
+ Scalar result;
+ // Initialize the promoted values for both the right and left hand side values
+ // to be the objects themselves. If no promotion is needed (both right and left
+ // have the same type), then the temp_value will not get used.
+ promoted_lhs_ptr = &lhs;
+ promoted_rhs_ptr = &rhs;
+ // Extract the types of both the right and left hand side values
+ Scalar::Type lhs_type = lhs.GetType();
+ Scalar::Type rhs_type = rhs.GetType();
+
+ if (lhs_type > rhs_type)
+ {
+ // Right hand side need to be promoted
+ temp_value = rhs; // Copy right hand side into the temp value
+ if (temp_value.Promote(lhs_type)) // Promote it
+ promoted_rhs_ptr = &temp_value; // Update the pointer for the promoted right hand side
+ }
+ else if (lhs_type < rhs_type)
+ {
+ // Left hand side need to be promoted
+ temp_value = lhs; // Copy left hand side value into the temp value
+ if (temp_value.Promote(rhs_type)) // Promote it
+ promoted_lhs_ptr = &temp_value; // Update the pointer for the promoted left hand side
+ }
+
+ // Make sure our type promotion worked as exptected
+ if (promoted_lhs_ptr->GetType() == promoted_rhs_ptr->GetType())
+ return promoted_lhs_ptr->GetType(); // Return the resulting max type
+
+ // Return the void type (zero) if we fail to promote either of the values.
+ return Scalar::e_void;
+}
+
+
+//----------------------------------------------------------------------
+// Scalar constructor
+//----------------------------------------------------------------------
+Scalar::Scalar() :
+ m_type(e_void),
+ m_data()
+{
+}
+
+//----------------------------------------------------------------------
+// Scalar copy constructor
+//----------------------------------------------------------------------
+Scalar::Scalar(const Scalar& rhs) :
+ m_type(rhs.m_type),
+ m_data(rhs.m_data) // TODO: verify that for C++ this will correctly copy the union??
+{
+}
+
+//Scalar::Scalar(const RegisterValue& reg) :
+// m_type(e_void),
+// m_data()
+//{
+// switch (reg.info.encoding)
+// {
+// case eEncodingUint: // unsigned integer
+// switch (reg.info.byte_size)
+// {
+// case 1: m_type = e_uint; m_data.uint = reg.value.uint8; break;
+// case 2: m_type = e_uint; m_data.uint = reg.value.uint16; break;
+// case 4: m_type = e_uint; m_data.uint = reg.value.uint32; break;
+// case 8: m_type = e_ulonglong; m_data.ulonglong = reg.value.uint64; break;
+// break;
+// }
+// break;
+//
+// case eEncodingSint: // signed integer
+// switch (reg.info.byte_size)
+// {
+// case 1: m_type = e_sint; m_data.sint = reg.value.sint8; break;
+// case 2: m_type = e_sint; m_data.sint = reg.value.sint16; break;
+// case 4: m_type = e_sint; m_data.sint = reg.value.sint32; break;
+// case 8: m_type = e_slonglong; m_data.slonglong = reg.value.sint64; break;
+// break;
+// }
+// break;
+//
+// case eEncodingIEEE754: // float
+// switch (reg.info.byte_size)
+// {
+// case 4: m_type = e_float; m_data.flt = reg.value.float32; break;
+// case 8: m_type = e_double; m_data.dbl = reg.value.float64; break;
+// break;
+// }
+// break;
+// case eEncodingVector: // vector registers
+// break;
+// }
+//}
+
+bool
+Scalar::GetData (DataExtractor &data, size_t limit_byte_size) const
+{
+ size_t byte_size = GetByteSize();
+ if (byte_size > 0)
+ {
+ if (limit_byte_size < byte_size)
+ {
+ if (lldb::endian::InlHostByteOrder() == eByteOrderLittle)
+ {
+ // On little endian systems if we want fewer bytes from the
+ // current type we just specify fewer bytes since the LSByte
+ // is first...
+ data.SetData((uint8_t*)&m_data, limit_byte_size, lldb::endian::InlHostByteOrder());
+ }
+ else if (lldb::endian::InlHostByteOrder() == eByteOrderBig)
+ {
+ // On big endian systems if we want fewer bytes from the
+ // current type have to advance our initial byte pointer and
+ // trim down the number of bytes since the MSByte is first
+ data.SetData(((uint8_t*)&m_data) + byte_size - limit_byte_size, limit_byte_size, lldb::endian::InlHostByteOrder());
+ }
+ }
+ else
+ {
+ // We want all of the data
+ data.SetData((uint8_t*)&m_data, byte_size, lldb::endian::InlHostByteOrder());
+ }
+ return true;
+ }
+ data.Clear();
+ return false;
+}
+
+size_t
+Scalar::GetByteSize() const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: return sizeof(m_data.sint);
+ case e_uint: return sizeof(m_data.uint);
+ case e_slong: return sizeof(m_data.slong);
+ case e_ulong: return sizeof(m_data.ulong);
+ case e_slonglong: return sizeof(m_data.slonglong);
+ case e_ulonglong: return sizeof(m_data.ulonglong);
+ case e_float: return sizeof(m_data.flt);
+ case e_double: return sizeof(m_data.dbl);
+ case e_long_double: return sizeof(m_data.ldbl);
+ }
+ return 0;
+}
+
+bool
+Scalar::IsZero() const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: return m_data.sint == 0;
+ case e_uint: return m_data.uint == 0;
+ case e_slong: return m_data.slong == 0;
+ case e_ulong: return m_data.ulong == 0;
+ case e_slonglong: return m_data.slonglong == 0;
+ case e_ulonglong: return m_data.ulonglong == 0;
+ case e_float: return m_data.flt == 0.0f;
+ case e_double: return m_data.dbl == 0.0;
+ case e_long_double: return m_data.ldbl == 0.0;
+ }
+ return false;
+}
+
+void
+Scalar::GetValue (Stream *s, bool show_type) const
+{
+ if (show_type)
+ s->Printf("(%s) ", GetTypeAsCString());
+
+ switch (m_type)
+ {
+ case e_void:
+ break;
+ case e_sint: s->Printf("%i", m_data.sint); break;
+ case e_uint: s->Printf("0x%8.8x", m_data.uint); break;
+ case e_slong: s->Printf("%li", m_data.slong); break;
+ case e_ulong: s->Printf("0x%8.8lx", m_data.ulong); break;
+ case e_slonglong: s->Printf("%lli", m_data.slonglong); break;
+ case e_ulonglong: s->Printf("0x%16.16llx", m_data.ulonglong); break;
+ case e_float: s->Printf("%f", m_data.flt); break;
+ case e_double: s->Printf("%g", m_data.dbl); break;
+ case e_long_double: s->Printf("%Lg", m_data.ldbl); break;
+ }
+}
+
+const char *
+Scalar::GetTypeAsCString() const
+{
+ switch (m_type)
+ {
+ case e_void: return "void";
+ case e_sint: return "int";
+ case e_uint: return "unsigned int";
+ case e_slong: return "long";
+ case e_ulong: return "unsigned long";
+ case e_slonglong: return "long long";
+ case e_ulonglong: return "unsigned long long";
+ case e_float: return "float";
+ case e_double: return "double";
+ case e_long_double: return "long double";
+ }
+ return "<invalid Scalar type>";
+}
+
+
+
+//----------------------------------------------------------------------
+// Scalar copy constructor
+//----------------------------------------------------------------------
+Scalar&
+Scalar::operator=(const Scalar& rhs)
+{
+ if (this != &rhs)
+ {
+ m_type = rhs.m_type;
+ ::memcpy (&m_data, &rhs.m_data, sizeof(m_data));
+ }
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (const int v)
+{
+ m_type = e_sint;
+ m_data.sint = v;
+ return *this;
+}
+
+
+Scalar&
+Scalar::operator= (unsigned int v)
+{
+ m_type = e_uint;
+ m_data.uint = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long v)
+{
+ m_type = e_slong;
+ m_data.slong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (unsigned long v)
+{
+ m_type = e_ulong;
+ m_data.ulong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long long v)
+{
+ m_type = e_slonglong;
+ m_data.slonglong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (unsigned long long v)
+{
+ m_type = e_ulonglong;
+ m_data.ulonglong = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (float v)
+{
+ m_type = e_float;
+ m_data.flt = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (double v)
+{
+ m_type = e_double;
+ m_data.dbl = v;
+ return *this;
+}
+
+Scalar&
+Scalar::operator= (long double v)
+{
+ m_type = e_long_double;
+ m_data.ldbl = v;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Scalar::~Scalar()
+{
+}
+
+bool
+Scalar::Promote(Scalar::Type type)
+{
+ bool success = false;
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ switch (type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_data.uint = m_data.sint; success = true; break;
+ case e_slong: m_data.slong = m_data.sint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.sint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.sint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.sint; success = true; break;
+ case e_float: m_data.flt = m_data.sint; success = true; break;
+ case e_double: m_data.dbl = m_data.sint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.sint; success = true; break;
+ }
+ break;
+
+ case e_uint:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: break;
+ case e_uint: success = true; break;
+ case e_slong: m_data.slong = m_data.uint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.uint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.uint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.uint; success = true; break;
+ case e_float: m_data.flt = m_data.uint; success = true; break;
+ case e_double: m_data.dbl = m_data.uint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.uint; success = true; break;
+ }
+ break;
+
+ case e_slong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint: break;
+ case e_slong: success = true; break;
+ case e_ulong: m_data.ulong = m_data.slong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.slong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slong; success = true; break;
+ case e_float: m_data.flt = m_data.slong; success = true; break;
+ case e_double: m_data.dbl = m_data.slong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slong; success = true; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong: break;
+ case e_ulong: success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ulong; success = true; break;
+ case e_float: m_data.flt = m_data.ulong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulong; success = true; break;
+ }
+ break;
+
+ case e_slonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong: break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slonglong; success = true; break;
+ case e_float: m_data.flt = m_data.slonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.slonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slonglong; success = true; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong: break;
+ case e_ulonglong: success = true; break;
+ case e_float: m_data.flt = m_data.ulonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_float:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong: break;
+ case e_float: success = true; break;
+ case e_double: m_data.dbl = m_data.flt; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong:
+ case e_float: break;
+ case e_double: success = true; break;
+ case e_long_double: m_data.ldbl = m_data.dbl; success = true; break;
+ }
+ break;
+
+ case e_long_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint:
+ case e_uint:
+ case e_slong:
+ case e_ulong:
+ case e_slonglong:
+ case e_ulonglong:
+ case e_float:
+ case e_double: break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+const char *
+Scalar::GetValueTypeAsCString (Scalar::Type type)
+{
+ switch (type)
+ {
+ case e_void: return "void";
+ case e_sint: return "int";
+ case e_uint: return "unsigned int";
+ case e_slong: return "long";
+ case e_ulong: return "unsigned long";
+ case e_slonglong: return "long long";
+ case e_ulonglong: return "unsigned long long";
+ case e_float: return "float";
+ case e_double: return "double";
+ case e_long_double: return "long double";
+ }
+ return "???";
+}
+
+
+Scalar::Type
+Scalar::GetValueTypeForSignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(sint_t))
+ return e_sint;
+ if (byte_size <= sizeof(slong_t))
+ return e_slong;
+ if (byte_size <= sizeof(slonglong_t))
+ return e_slonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForUnsignedIntegerWithByteSize (size_t byte_size)
+{
+ if (byte_size <= sizeof(uint_t))
+ return e_uint;
+ if (byte_size <= sizeof(ulong_t))
+ return e_ulong;
+ if (byte_size <= sizeof(ulonglong_t))
+ return e_ulonglong;
+ return e_void;
+}
+
+Scalar::Type
+Scalar::GetValueTypeForFloatWithByteSize (size_t byte_size)
+{
+ if (byte_size == sizeof(float_t))
+ return e_float;
+ if (byte_size == sizeof(double_t))
+ return e_double;
+ if (byte_size == sizeof(long_double_t))
+ return e_long_double;
+ return e_void;
+}
+
+bool
+Scalar::Cast(Scalar::Type type)
+{
+ bool success = false;
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ switch (type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_data.uint = m_data.sint; success = true; break;
+ case e_slong: m_data.slong = m_data.sint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.sint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.sint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.sint; success = true; break;
+ case e_float: m_data.flt = m_data.sint; success = true; break;
+ case e_double: m_data.dbl = m_data.sint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.sint; success = true; break;
+ }
+ break;
+
+ case e_uint:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = m_data.uint; success = true; break;
+ case e_uint: success = true; break;
+ case e_slong: m_data.slong = m_data.uint; success = true; break;
+ case e_ulong: m_data.ulong = m_data.uint; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.uint; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.uint; success = true; break;
+ case e_float: m_data.flt = m_data.uint; success = true; break;
+ case e_double: m_data.dbl = m_data.uint; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.uint; success = true; break;
+ }
+ break;
+
+ case e_slong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.slong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.slong; success = true; break;
+ case e_slong: success = true; break;
+ case e_ulong: m_data.ulong = m_data.slong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.slong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slong; success = true; break;
+ case e_float: m_data.flt = m_data.slong; success = true; break;
+ case e_double: m_data.dbl = m_data.slong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slong; success = true; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ulong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ulong; success = true; break;
+ case e_slong: m_data.slong = m_data.ulong; success = true; break;
+ case e_ulong: success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulong; success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.ulong; success = true; break;
+ case e_float: m_data.flt = m_data.ulong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulong; success = true; break;
+ }
+ break;
+
+ case e_slonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.slonglong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.slonglong; success = true; break;
+ case e_slong: m_data.slong = m_data.slonglong; success = true; break;
+ case e_ulong: m_data.ulong = m_data.slonglong; success = true; break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_data.ulonglong = m_data.slonglong; success = true; break;
+ case e_float: m_data.flt = m_data.slonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.slonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.slonglong; success = true; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ulonglong; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ulonglong; success = true; break;
+ case e_slong: m_data.slong = m_data.ulonglong; success = true; break;
+ case e_ulong: m_data.ulong = m_data.ulonglong; success = true; break;
+ case e_slonglong: m_data.slonglong = m_data.ulonglong; success = true; break;
+ case e_ulonglong: success = true; break;
+ case e_float: m_data.flt = m_data.ulonglong; success = true; break;
+ case e_double: m_data.dbl = m_data.ulonglong; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.ulonglong; success = true; break;
+ }
+ break;
+
+ case e_float:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.flt; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.flt; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.flt; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.flt; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.flt; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.flt; success = true; break;
+ case e_float: success = true; break;
+ case e_double: m_data.dbl = m_data.flt; success = true; break;
+ case e_long_double: m_data.ldbl = m_data.flt; success = true; break;
+ }
+ break;
+
+ case e_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.dbl; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.dbl; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.dbl; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.dbl; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.dbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.dbl; success = true; break;
+ case e_float: m_data.flt = (float_t)m_data.dbl; success = true; break;
+ case e_double: success = true; break;
+ case e_long_double: m_data.ldbl = m_data.dbl; success = true; break;
+ }
+ break;
+
+ case e_long_double:
+ switch (type)
+ {
+ case e_void:
+ case e_sint: m_data.sint = (sint_t)m_data.ldbl; success = true; break;
+ case e_uint: m_data.uint = (uint_t)m_data.ldbl; success = true; break;
+ case e_slong: m_data.slong = (slong_t)m_data.ldbl; success = true; break;
+ case e_ulong: m_data.ulong = (ulong_t)m_data.ldbl; success = true; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)m_data.ldbl; success = true; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)m_data.ldbl; success = true; break;
+ case e_float: m_data.flt = (float_t)m_data.ldbl; success = true; break;
+ case e_double: m_data.dbl = (double_t)m_data.ldbl; success = true; break;
+ case e_long_double: success = true; break;
+ }
+ break;
+ }
+
+ if (success)
+ m_type = type;
+ return success;
+}
+
+bool
+Scalar::MakeSigned ()
+{
+ bool success = false;
+
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: success = true; break;
+ case e_uint: m_type = e_sint; success = true; break;
+ case e_slong: success = true; break;
+ case e_ulong: m_type = e_slong; success = true; break;
+ case e_slonglong: success = true; break;
+ case e_ulonglong: m_type = e_slonglong; success = true; break;
+ case e_float: success = true; break;
+ case e_double: success = true; break;
+ case e_long_double: success = true; break;
+ }
+
+ return success;
+}
+
+int
+Scalar::SInt(int fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return m_data.sint;
+ case e_uint: return (int)m_data.uint;
+ case e_slong: return (int)m_data.slong;
+ case e_ulong: return (int)m_data.ulong;
+ case e_slonglong: return (int)m_data.slonglong;
+ case e_ulonglong: return (int)m_data.ulonglong;
+ case e_float: return (int)m_data.flt;
+ case e_double: return (int)m_data.dbl;
+ case e_long_double: return (int)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+unsigned int
+Scalar::UInt(unsigned int fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned int)m_data.sint;
+ case e_uint: return (unsigned int)m_data.uint;
+ case e_slong: return (unsigned int)m_data.slong;
+ case e_ulong: return (unsigned int)m_data.ulong;
+ case e_slonglong: return (unsigned int)m_data.slonglong;
+ case e_ulonglong: return (unsigned int)m_data.ulonglong;
+ case e_float: return (unsigned int)m_data.flt;
+ case e_double: return (unsigned int)m_data.dbl;
+ case e_long_double: return (unsigned int)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+long
+Scalar::SLong(long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long)m_data.sint;
+ case e_uint: return (long)m_data.uint;
+ case e_slong: return (long)m_data.slong;
+ case e_ulong: return (long)m_data.ulong;
+ case e_slonglong: return (long)m_data.slonglong;
+ case e_ulonglong: return (long)m_data.ulonglong;
+ case e_float: return (long)m_data.flt;
+ case e_double: return (long)m_data.dbl;
+ case e_long_double: return (long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+
+unsigned long
+Scalar::ULong(unsigned long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned long)m_data.sint;
+ case e_uint: return (unsigned long)m_data.uint;
+ case e_slong: return (unsigned long)m_data.slong;
+ case e_ulong: return (unsigned long)m_data.ulong;
+ case e_slonglong: return (unsigned long)m_data.slonglong;
+ case e_ulonglong: return (unsigned long)m_data.ulonglong;
+ case e_float: return (unsigned long)m_data.flt;
+ case e_double: return (unsigned long)m_data.dbl;
+ case e_long_double: return (unsigned long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+uint64_t
+Scalar::GetRawBits64(uint64_t fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ case e_uint:
+ return m_data.uint;
+
+ case e_slong:
+ case e_ulong:
+ return m_data.ulong;
+
+ case e_slonglong:
+ case e_ulonglong:
+ return m_data.ulonglong;
+
+ case e_float:
+ if (sizeof(m_data.flt) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.flt) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.flt) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.dbl) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.dbl) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(m_data.uint))
+ return m_data.uint;
+ else if (sizeof(m_data.ldbl) == sizeof(m_data.ulong))
+ return m_data.ulong;
+ else if (sizeof(m_data.ldbl) == sizeof(m_data.ulonglong))
+ return m_data.ulonglong;
+ break;
+ }
+ return fail_value;
+}
+
+
+
+long long
+Scalar::SLongLong(long long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long long)m_data.sint;
+ case e_uint: return (long long)m_data.uint;
+ case e_slong: return (long long)m_data.slong;
+ case e_ulong: return (long long)m_data.ulong;
+ case e_slonglong: return (long long)m_data.slonglong;
+ case e_ulonglong: return (long long)m_data.ulonglong;
+ case e_float: return (long long)m_data.flt;
+ case e_double: return (long long)m_data.dbl;
+ case e_long_double: return (long long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+unsigned long long
+Scalar::ULongLong(unsigned long long fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (unsigned long long)m_data.sint;
+ case e_uint: return (unsigned long long)m_data.uint;
+ case e_slong: return (unsigned long long)m_data.slong;
+ case e_ulong: return (unsigned long long)m_data.ulong;
+ case e_slonglong: return (unsigned long long)m_data.slonglong;
+ case e_ulonglong: return (unsigned long long)m_data.ulonglong;
+ case e_float: return (unsigned long long)m_data.flt;
+ case e_double: return (unsigned long long)m_data.dbl;
+ case e_long_double: return (unsigned long long)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+float
+Scalar::Float(float fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (float)m_data.sint;
+ case e_uint: return (float)m_data.uint;
+ case e_slong: return (float)m_data.slong;
+ case e_ulong: return (float)m_data.ulong;
+ case e_slonglong: return (float)m_data.slonglong;
+ case e_ulonglong: return (float)m_data.ulonglong;
+ case e_float: return (float)m_data.flt;
+ case e_double: return (float)m_data.dbl;
+ case e_long_double: return (float)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+double
+Scalar::Double(double fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (double)m_data.sint;
+ case e_uint: return (double)m_data.uint;
+ case e_slong: return (double)m_data.slong;
+ case e_ulong: return (double)m_data.ulong;
+ case e_slonglong: return (double)m_data.slonglong;
+ case e_ulonglong: return (double)m_data.ulonglong;
+ case e_float: return (double)m_data.flt;
+ case e_double: return (double)m_data.dbl;
+ case e_long_double: return (double)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+long double
+Scalar::LongDouble(long double fail_value) const
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: return (long double)m_data.sint;
+ case e_uint: return (long double)m_data.uint;
+ case e_slong: return (long double)m_data.slong;
+ case e_ulong: return (long double)m_data.ulong;
+ case e_slonglong: return (long double)m_data.slonglong;
+ case e_ulonglong: return (long double)m_data.ulonglong;
+ case e_float: return (long double)m_data.flt;
+ case e_double: return (long double)m_data.dbl;
+ case e_long_double: return (long double)m_data.ldbl;
+ }
+ return fail_value;
+}
+
+
+Scalar&
+Scalar::operator+= (const Scalar& rhs)
+{
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((m_type = PromoteToMaxType(*this, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: m_data.sint = a->m_data.sint + b->m_data.sint; break;
+ case e_uint: m_data.uint = a->m_data.uint + b->m_data.uint; break;
+ case e_slong: m_data.slong = a->m_data.slong + b->m_data.slong; break;
+ case e_ulong: m_data.ulong = a->m_data.ulong + b->m_data.ulong; break;
+ case e_slonglong: m_data.slonglong = a->m_data.slonglong + b->m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong = a->m_data.ulonglong + b->m_data.ulonglong; break;
+ case e_float: m_data.flt = a->m_data.flt + b->m_data.flt; break;
+ case e_double: m_data.dbl = a->m_data.dbl + b->m_data.dbl; break;
+ case e_long_double: m_data.ldbl = a->m_data.ldbl + b->m_data.ldbl; break;
+ }
+ }
+ return *this;
+}
+
+Scalar&
+Scalar::operator<<= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint <<= rhs.m_data.sint; break;
+ case e_uint: m_data.sint <<= rhs.m_data.uint; break;
+ case e_slong: m_data.sint <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint <<= rhs.m_data.sint; break;
+ case e_uint: m_data.uint <<= rhs.m_data.uint; break;
+ case e_slong: m_data.uint <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.slong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.slong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong <<= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong <<= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong <<= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong <<= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong <<= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong <<= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+bool
+Scalar::ShiftRightLogical(const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.uint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.uint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slonglong:
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return m_type != e_void;
+}
+
+
+Scalar&
+Scalar::operator>>= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.sint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.sint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint >>= rhs.m_data.sint; break;
+ case e_uint: m_data.uint >>= rhs.m_data.uint; break;
+ case e_slong: m_data.uint >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.slong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.slong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong >>= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong >>= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong >>= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong >>= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong >>= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong >>= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+
+Scalar&
+Scalar::operator&= (const Scalar& rhs)
+{
+ switch (m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+
+ case e_sint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.sint &= rhs.m_data.sint; break;
+ case e_uint: m_data.sint &= rhs.m_data.uint; break;
+ case e_slong: m_data.sint &= rhs.m_data.slong; break;
+ case e_ulong: m_data.sint &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.sint &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.sint &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_uint:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.uint &= rhs.m_data.sint; break;
+ case e_uint: m_data.uint &= rhs.m_data.uint; break;
+ case e_slong: m_data.uint &= rhs.m_data.slong; break;
+ case e_ulong: m_data.uint &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.uint &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.uint &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_slong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slong &= rhs.m_data.sint; break;
+ case e_uint: m_data.slong &= rhs.m_data.uint; break;
+ case e_slong: m_data.slong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.slong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulong &= rhs.m_data.sint; break;
+ case e_uint: m_data.ulong &= rhs.m_data.uint; break;
+ case e_slong: m_data.ulong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+ case e_slonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.slonglong &= rhs.m_data.sint; break;
+ case e_uint: m_data.slonglong &= rhs.m_data.uint; break;
+ case e_slong: m_data.slonglong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.slonglong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.slonglong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.slonglong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+
+ case e_ulonglong:
+ switch (rhs.m_type)
+ {
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ m_type = e_void;
+ break;
+ case e_sint: m_data.ulonglong &= rhs.m_data.sint; break;
+ case e_uint: m_data.ulonglong &= rhs.m_data.uint; break;
+ case e_slong: m_data.ulonglong &= rhs.m_data.slong; break;
+ case e_ulong: m_data.ulonglong &= rhs.m_data.ulong; break;
+ case e_slonglong: m_data.ulonglong &= rhs.m_data.slonglong; break;
+ case e_ulonglong: m_data.ulonglong &= rhs.m_data.ulonglong; break;
+ }
+ break;
+ }
+ return *this;
+}
+
+
+
+bool
+Scalar::AbsoluteValue()
+{
+ switch (m_type)
+ {
+ case e_void:
+ break;
+
+ case e_sint:
+ if (m_data.sint < 0)
+ m_data.sint = -m_data.sint;
+ return true;
+
+ case e_slong:
+ if (m_data.slong < 0)
+ m_data.slong = -m_data.slong;
+ return true;
+
+ case e_slonglong:
+ if (m_data.slonglong < 0)
+ m_data.slonglong = -m_data.slonglong;
+ return true;
+
+ case e_uint:
+ case e_ulong:
+ case e_ulonglong: return true;
+ case e_float: m_data.flt = fabsf(m_data.flt); return true;
+ case e_double: m_data.dbl = fabs(m_data.dbl); return true;
+ case e_long_double: m_data.ldbl = fabsl(m_data.ldbl); return true;
+ }
+ return false;
+}
+
+
+bool
+Scalar::UnaryNegate()
+{
+ switch (m_type)
+ {
+ case e_void: break;
+ case e_sint: m_data.sint = -m_data.sint; return true;
+ case e_uint: m_data.uint = -m_data.uint; return true;
+ case e_slong: m_data.slong = -m_data.slong; return true;
+ case e_ulong: m_data.ulong = -m_data.ulong; return true;
+ case e_slonglong: m_data.slonglong = -m_data.slonglong; return true;
+ case e_ulonglong: m_data.ulonglong = -m_data.ulonglong; return true;
+ case e_float: m_data.flt = -m_data.flt; return true;
+ case e_double: m_data.dbl = -m_data.dbl; return true;
+ case e_long_double: m_data.ldbl = -m_data.ldbl; return true;
+ }
+ return false;
+}
+
+bool
+Scalar::OnesComplement()
+{
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = ~m_data.sint; return true;
+ case e_uint: m_data.uint = ~m_data.uint; return true;
+ case e_slong: m_data.slong = ~m_data.slong; return true;
+ case e_ulong: m_data.ulong = ~m_data.ulong; return true;
+ case e_slonglong: m_data.slonglong = ~m_data.slonglong; return true;
+ case e_ulonglong: m_data.ulonglong = ~m_data.ulonglong; return true;
+
+ case e_void:
+ case e_float:
+ case e_double:
+ case e_long_double:
+ break;
+ }
+ return false;
+}
+
+
+const Scalar
+lldb_private::operator+ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint + b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint + b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong + b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong + b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong + b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong + b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt + b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl + b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl + b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+
+const Scalar
+lldb_private::operator- (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint - b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint - b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong - b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong - b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong - b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong - b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt - b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl - b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl - b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator/ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+
+ case Scalar::e_sint: if (b->m_data.sint != 0) { result.m_data.sint = a->m_data.sint/ b->m_data.sint; return result; } break;
+ case Scalar::e_uint: if (b->m_data.uint != 0) { result.m_data.uint = a->m_data.uint / b->m_data.uint; return result; } break;
+ case Scalar::e_slong: if (b->m_data.slong != 0) { result.m_data.slong = a->m_data.slong / b->m_data.slong; return result; } break;
+ case Scalar::e_ulong: if (b->m_data.ulong != 0) { result.m_data.ulong = a->m_data.ulong / b->m_data.ulong; return result; } break;
+ case Scalar::e_slonglong: if (b->m_data.slonglong != 0) { result.m_data.slonglong = a->m_data.slonglong / b->m_data.slonglong; return result; } break;
+ case Scalar::e_ulonglong: if (b->m_data.ulonglong != 0) { result.m_data.ulonglong = a->m_data.ulonglong / b->m_data.ulonglong; return result; } break;
+ case Scalar::e_float: if (b->m_data.flt != 0.0f) { result.m_data.flt = a->m_data.flt / b->m_data.flt; return result; } break;
+ case Scalar::e_double: if (b->m_data.dbl != 0.0) { result.m_data.dbl = a->m_data.dbl / b->m_data.dbl; return result; } break;
+ case Scalar::e_long_double: if (b->m_data.ldbl != 0.0) { result.m_data.ldbl = a->m_data.ldbl / b->m_data.ldbl; return result; } break;
+ }
+ }
+ // For division only, the only way it should make it here is if a promotion failed,
+ // or if we are trying to do a divide by zero.
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar
+lldb_private::operator* (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint * b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint * b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong * b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong * b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong * b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong * b->m_data.ulonglong; break;
+ case Scalar::e_float: result.m_data.flt = a->m_data.flt * b->m_data.flt; break;
+ case Scalar::e_double: result.m_data.dbl = a->m_data.dbl * b->m_data.dbl; break;
+ case Scalar::e_long_double: result.m_data.ldbl = a->m_data.ldbl * b->m_data.ldbl; break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator& (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint & b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint & b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong & b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong & b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong & b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong & b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator| (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint | b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint | b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong | b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong | b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong | b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong | b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator% (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ default: break;
+ case Scalar::e_sint: if (b->m_data.sint != 0) { result.m_data.sint = a->m_data.sint % b->m_data.sint; return result; } break;
+ case Scalar::e_uint: if (b->m_data.uint != 0) { result.m_data.uint = a->m_data.uint % b->m_data.uint; return result; } break;
+ case Scalar::e_slong: if (b->m_data.slong != 0) { result.m_data.slong = a->m_data.slong % b->m_data.slong; return result; } break;
+ case Scalar::e_ulong: if (b->m_data.ulong != 0) { result.m_data.ulong = a->m_data.ulong % b->m_data.ulong; return result; } break;
+ case Scalar::e_slonglong: if (b->m_data.slonglong != 0) { result.m_data.slonglong = a->m_data.slonglong % b->m_data.slonglong; return result; } break;
+ case Scalar::e_ulonglong: if (b->m_data.ulonglong != 0) { result.m_data.ulonglong = a->m_data.ulonglong % b->m_data.ulonglong; return result; } break;
+ }
+ }
+ result.m_type = Scalar::e_void;
+ return result;
+}
+
+const Scalar
+lldb_private::operator^ (const Scalar& lhs, const Scalar& rhs)
+{
+ Scalar result;
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ if ((result.m_type = PromoteToMaxType(lhs, rhs, temp_value, a, b)) != Scalar::e_void)
+ {
+ switch (result.m_type)
+ {
+ case Scalar::e_sint: result.m_data.sint = a->m_data.sint ^ b->m_data.sint; break;
+ case Scalar::e_uint: result.m_data.uint = a->m_data.uint ^ b->m_data.uint; break;
+ case Scalar::e_slong: result.m_data.slong = a->m_data.slong ^ b->m_data.slong; break;
+ case Scalar::e_ulong: result.m_data.ulong = a->m_data.ulong ^ b->m_data.ulong; break;
+ case Scalar::e_slonglong: result.m_data.slonglong = a->m_data.slonglong ^ b->m_data.slonglong; break;
+ case Scalar::e_ulonglong: result.m_data.ulonglong = a->m_data.ulonglong ^ b->m_data.ulonglong; break;
+
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ // No bitwise AND on floats, doubles of long doubles
+ result.m_type = Scalar::e_void;
+ break;
+ }
+ }
+ return result;
+}
+
+const Scalar
+lldb_private::operator<< (const Scalar& lhs, const Scalar &rhs)
+{
+ Scalar result = lhs;
+ result <<= rhs;
+ return result;
+}
+
+const Scalar
+lldb_private::operator>> (const Scalar& lhs, const Scalar &rhs)
+{
+ Scalar result = lhs;
+ result >>= rhs;
+ return result;
+}
+
+// Return the raw unsigned integer without any casting or conversion
+unsigned int
+Scalar::RawUInt () const
+{
+ return m_data.uint;
+}
+
+// Return the raw unsigned long without any casting or conversion
+unsigned long
+Scalar::RawULong () const
+{
+ return m_data.ulong;
+}
+
+// Return the raw unsigned long long without any casting or conversion
+unsigned long long
+Scalar::RawULongLong () const
+{
+ return m_data.ulonglong;
+}
+
+
+Error
+Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t byte_size)
+{
+ Error error;
+ if (value_str == NULL || value_str[0] == '\0')
+ {
+ error.SetErrorString ("Invalid c-string value string.");
+ return error;
+ }
+ bool success = false;
+ switch (encoding)
+ {
+ case eEncodingInvalid:
+ error.SetErrorString ("Invalid encoding.");
+ break;
+
+ case eEncodingUint:
+ if (byte_size <= sizeof (unsigned long long))
+ {
+ uint64_t uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid unsigned integer string value", value_str);
+ else if (!UIntValueIsValidForSize (uval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte unsigned integer value", uval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForUnsignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_uint: m_data.uint = (uint_t)uval64; break;
+ case e_ulong: m_data.ulong = (ulong_t)uval64; break;
+ case e_ulonglong: m_data.ulonglong = (ulonglong_t)uval64; break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingSint:
+ if (byte_size <= sizeof (long long))
+ {
+ uint64_t sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat ("'%s' is not a valid signed integer string value", value_str);
+ else if (!SIntValueIsValidForSize (sval64, byte_size))
+ error.SetErrorStringWithFormat ("value 0x%" PRIx64 " is too large to fit in a %zu byte signed integer value", sval64, byte_size);
+ else
+ {
+ m_type = Scalar::GetValueTypeForSignedIntegerWithByteSize (byte_size);
+ switch (m_type)
+ {
+ case e_sint: m_data.sint = (sint_t)sval64; break;
+ case e_slong: m_data.slong = (slong_t)sval64; break;
+ case e_slonglong: m_data.slonglong = (slonglong_t)sval64; break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingIEEE754:
+ if (byte_size == sizeof (float))
+ {
+ if (::sscanf (value_str, "%f", &m_data.flt) == 1)
+ m_type = e_float;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (double))
+ {
+ if (::sscanf (value_str, "%lf", &m_data.dbl) == 1)
+ m_type = e_double;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else if (byte_size == sizeof (long double))
+ {
+ if (::sscanf (value_str, "%Lf", &m_data.ldbl) == 1)
+ m_type = e_long_double;
+ else
+ error.SetErrorStringWithFormat ("'%s' is not a valid float string value", value_str);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ return error;
+ }
+ break;
+
+ case eEncodingVector:
+ error.SetErrorString ("vector encoding unsupported.");
+ break;
+ }
+ if (error.Fail())
+ m_type = e_void;
+
+ return error;
+}
+
+Error
+Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t byte_size)
+{
+ Error error;
+
+ switch (encoding)
+ {
+ case lldb::eEncodingInvalid:
+ error.SetErrorString ("invalid encoding");
+ break;
+ case lldb::eEncodingVector:
+ error.SetErrorString ("vector encoding unsupported");
+ break;
+ case lldb::eEncodingUint:
+ {
+ lldb::offset_t offset;
+
+ switch (byte_size)
+ {
+ case 1: operator=((uint8_t)data.GetU8(&offset)); break;
+ case 2: operator=((uint16_t)data.GetU16(&offset)); break;
+ case 4: operator=((uint32_t)data.GetU32(&offset)); break;
+ case 8: operator=((uint64_t)data.GetU64(&offset)); break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ break;
+ case lldb::eEncodingSint:
+ {
+ lldb::offset_t offset;
+
+ switch (byte_size)
+ {
+ case 1: operator=((int8_t)data.GetU8(&offset)); break;
+ case 2: operator=((int16_t)data.GetU16(&offset)); break;
+ case 4: operator=((int32_t)data.GetU32(&offset)); break;
+ case 8: operator=((int64_t)data.GetU64(&offset)); break;
+ default:
+ error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+ break;
+ }
+ }
+ break;
+ case lldb::eEncodingIEEE754:
+ {
+ lldb::offset_t offset;
+
+ if (byte_size == sizeof (float))
+ operator=((float)data.GetFloat(&offset));
+ else if (byte_size == sizeof (double))
+ operator=((double)data.GetDouble(&offset));
+ else if (byte_size == sizeof (long double))
+ operator=((long double)data.GetLongDouble(&offset));
+ else
+ error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+ }
+ break;
+ }
+
+ return error;
+}
+
+bool
+Scalar::SignExtend (uint32_t sign_bit_pos)
+{
+ const uint32_t max_bit_pos = GetByteSize() * 8;
+
+ if (sign_bit_pos < max_bit_pos)
+ {
+ switch (m_type)
+ {
+ case Scalar::e_void:
+ case Scalar::e_float:
+ case Scalar::e_double:
+ case Scalar::e_long_double:
+ return false;
+
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned int sign_bit = 1u << sign_bit_pos;
+ if (m_data.uint & sign_bit)
+ {
+ const unsigned int mask = ~(sign_bit) + 1u;
+ m_data.uint |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned long sign_bit = 1ul << sign_bit_pos;
+ if (m_data.ulong & sign_bit)
+ {
+ const unsigned long mask = ~(sign_bit) + 1ul;
+ m_data.ulong |= mask;
+ }
+ return true;
+ }
+ break;
+
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ if (max_bit_pos == sign_bit_pos)
+ return true;
+ else if (sign_bit_pos < (max_bit_pos-1))
+ {
+ unsigned long long sign_bit = 1ull << sign_bit_pos;
+ if (m_data.ulonglong & sign_bit)
+ {
+ const unsigned long long mask = ~(sign_bit) + 1ull;
+ m_data.ulonglong |= mask;
+ }
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+size_t
+Scalar::GetAsMemoryData (void *dst,
+ size_t dst_len,
+ lldb::ByteOrder dst_byte_order,
+ Error &error) const
+{
+ // Get a data extractor that points to the native scalar data
+ DataExtractor data;
+ if (!GetData(data))
+ {
+ error.SetErrorString ("invalid scalar value");
+ return 0;
+ }
+
+ const size_t src_len = data.GetByteSize();
+
+ // Prepare a memory buffer that contains some or all of the register value
+ const size_t bytes_copied = data.CopyByteOrderedData (0, // src offset
+ src_len, // src length
+ dst, // dst buffer
+ dst_len, // dst length
+ dst_byte_order); // dst byte order
+ if (bytes_copied == 0)
+ error.SetErrorString ("failed to copy data");
+
+ return bytes_copied;
+}
+
+bool
+Scalar::ExtractBitfield (uint32_t bit_size,
+ uint32_t bit_offset)
+{
+ if (bit_size == 0)
+ return true;
+
+ uint32_t msbit = bit_offset + bit_size - 1;
+ uint32_t lsbit = bit_offset;
+ switch (m_type)
+ {
+ case Scalar::e_void:
+ break;
+
+ case e_float:
+ if (sizeof(m_data.flt) == sizeof(sint_t))
+ m_data.sint = (sint_t)SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.flt) == sizeof(ulong_t))
+ m_data.slong = (slong_t)SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.flt) == sizeof(ulonglong_t))
+ m_data.slonglong = (slonglong_t)SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case e_double:
+ if (sizeof(m_data.dbl) == sizeof(sint_t))
+ m_data.sint = SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.dbl) == sizeof(ulong_t))
+ m_data.slong = SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.dbl) == sizeof(ulonglong_t))
+ m_data.slonglong = SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case e_long_double:
+ if (sizeof(m_data.ldbl) == sizeof(sint_t))
+ m_data.sint = SignedBits (m_data.sint, msbit, lsbit);
+ else if (sizeof(m_data.ldbl) == sizeof(ulong_t))
+ m_data.slong = SignedBits (m_data.slong, msbit, lsbit);
+ else if (sizeof(m_data.ldbl) == sizeof(ulonglong_t))
+ m_data.slonglong = SignedBits (m_data.slonglong, msbit, lsbit);
+ else
+ return false;
+ return true;
+
+ case Scalar::e_sint:
+ m_data.sint = (sint_t)SignedBits (m_data.sint, msbit, lsbit);
+ return true;
+
+ case Scalar::e_uint:
+ m_data.uint = (uint_t)UnsignedBits (m_data.uint, msbit, lsbit);
+ return true;
+
+ case Scalar::e_slong:
+ m_data.slong = (slong_t)SignedBits (m_data.slong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_ulong:
+ m_data.ulong = (ulong_t)UnsignedBits (m_data.ulong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_slonglong:
+ m_data.slonglong = (slonglong_t)SignedBits (m_data.slonglong, msbit, lsbit);
+ return true;
+
+ case Scalar::e_ulonglong:
+ m_data.ulonglong = (ulonglong_t)UnsignedBits (m_data.ulonglong, msbit, lsbit);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+bool
+lldb_private::operator== (const Scalar& lhs, const Scalar& rhs)
+{
+ // If either entry is void then we can just compare the types
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return lhs.m_type == rhs.m_type;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint == b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint == b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong == b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong == b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong == b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong == b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt == b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl == b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl == b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator!= (const Scalar& lhs, const Scalar& rhs)
+{
+ // If either entry is void then we can just compare the types
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return lhs.m_type != rhs.m_type;
+
+ Scalar temp_value; // A temp value that might get a copy of either promoted value
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint != b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint != b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong != b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong != b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong != b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong != b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt != b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl != b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl != b->m_data.ldbl;
+ }
+ return true;
+}
+
+bool
+lldb_private::operator< (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint < b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint < b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong < b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong < b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong < b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong < b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt < b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl < b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl < b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator<= (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint <= b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint <= b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong <= b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong <= b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong <= b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong <= b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt <= b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl <= b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl <= b->m_data.ldbl;
+ }
+ return false;
+}
+
+
+bool
+lldb_private::operator> (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint > b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint > b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong > b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong > b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong > b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong > b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt > b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl > b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl > b->m_data.ldbl;
+ }
+ return false;
+}
+
+bool
+lldb_private::operator>= (const Scalar& lhs, const Scalar& rhs)
+{
+ if (lhs.m_type == Scalar::e_void || rhs.m_type == Scalar::e_void)
+ return false;
+
+ Scalar temp_value;
+ const Scalar* a;
+ const Scalar* b;
+ switch (PromoteToMaxType(lhs, rhs, temp_value, a, b))
+ {
+ case Scalar::e_void: break;
+ case Scalar::e_sint: return a->m_data.sint >= b->m_data.sint;
+ case Scalar::e_uint: return a->m_data.uint >= b->m_data.uint;
+ case Scalar::e_slong: return a->m_data.slong >= b->m_data.slong;
+ case Scalar::e_ulong: return a->m_data.ulong >= b->m_data.ulong;
+ case Scalar::e_slonglong: return a->m_data.slonglong >= b->m_data.slonglong;
+ case Scalar::e_ulonglong: return a->m_data.ulonglong >= b->m_data.ulonglong;
+ case Scalar::e_float: return a->m_data.flt >= b->m_data.flt;
+ case Scalar::e_double: return a->m_data.dbl >= b->m_data.dbl;
+ case Scalar::e_long_double: return a->m_data.ldbl >= b->m_data.ldbl;
+ }
+ return false;
+}
+
+
+
+
diff --git a/source/Core/SearchFilter.cpp b/source/Core/SearchFilter.cpp
new file mode 100644
index 000000000000..54937c0afeca
--- /dev/null
+++ b/source/Core/SearchFilter.cpp
@@ -0,0 +1,816 @@
+//===-- SearchFilter.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/lldb-private.h"
+#include "lldb/Core/SearchFilter.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SearchFilter constructor
+//----------------------------------------------------------------------
+Searcher::Searcher ()
+{
+
+}
+
+Searcher::~Searcher ()
+{
+
+}
+
+void
+Searcher::GetDescription (Stream *s)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter constructor
+//----------------------------------------------------------------------
+SearchFilter::SearchFilter(const TargetSP &target_sp) :
+ m_target_sp (target_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter copy constructor
+//----------------------------------------------------------------------
+SearchFilter::SearchFilter(const SearchFilter& rhs) :
+ m_target_sp (rhs.m_target_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilter assignment operator
+//----------------------------------------------------------------------
+const SearchFilter&
+SearchFilter::operator=(const SearchFilter& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilter::~SearchFilter()
+{
+}
+
+bool
+SearchFilter::ModulePasses (const FileSpec &spec)
+{
+ return true;
+}
+
+bool
+SearchFilter::ModulePasses (const ModuleSP &module_sp)
+{
+ return true;
+}
+
+bool
+SearchFilter::AddressPasses (Address &address)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilter::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+uint32_t
+SearchFilter::GetFilterRequiredItems()
+{
+ return (lldb::SymbolContextItem) 0;
+}
+
+void
+SearchFilter::GetDescription (Stream *s)
+{
+}
+
+void
+SearchFilter::Dump (Stream *s) const
+{
+
+}
+
+//----------------------------------------------------------------------
+// UTILITY Functions to help iterate down through the elements of the
+// SymbolContext.
+//----------------------------------------------------------------------
+
+void
+SearchFilter::Search (Searcher &searcher)
+{
+ SymbolContext empty_sc;
+
+ if (!m_target_sp)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ DoModuleIteration(empty_sc, searcher);
+}
+
+void
+SearchFilter::SearchInModuleList (Searcher &searcher, ModuleList &modules)
+{
+ SymbolContext empty_sc;
+
+ if (!m_target_sp)
+ return;
+ empty_sc.target_sp = m_target_sp;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ else
+ {
+ Mutex::Locker modules_locker(modules.GetMutex());
+ const size_t numModules = modules.GetSize();
+
+ for (size_t i = 0; i < numModules; i++)
+ {
+ ModuleSP module_sp(modules.GetModuleAtIndexUnlocked(i));
+ if (ModulePasses(module_sp))
+ {
+ if (DoModuleIteration(module_sp, searcher) == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+ }
+}
+
+
+Searcher::CallbackReturn
+SearchFilter::DoModuleIteration (const lldb::ModuleSP& module_sp, Searcher &searcher)
+{
+ SymbolContext matchingContext (m_target_sp, module_sp);
+ return DoModuleIteration(matchingContext, searcher);
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoModuleIteration (const SymbolContext &context, Searcher &searcher)
+{
+ if (searcher.GetDepth () >= Searcher::eDepthModule)
+ {
+ if (context.module_sp)
+ {
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(context.module_sp.get());
+ searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ else
+ {
+ return DoCUIteration(context.module_sp, context, searcher);
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target_sp->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ size_t n_modules = target_images.GetSize();
+ for (size_t i = 0; i < n_modules; i++)
+ {
+ // If this is the last level supplied, then call the callback directly,
+ // otherwise descend.
+ ModuleSP module_sp(target_images.GetModuleAtIndexUnlocked (i));
+ if (!ModulePasses (module_sp))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthModule)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+
+ Searcher::CallbackReturn shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+ if (shouldContinue == Searcher::eCallbackReturnStop
+ || shouldContinue == Searcher::eCallbackReturnPop)
+ return shouldContinue;
+ }
+ else
+ {
+ Searcher::CallbackReturn shouldContinue = DoCUIteration(module_sp, context, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnPop)
+ continue;
+ }
+ }
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoCUIteration (const ModuleSP &module_sp, const SymbolContext &context, Searcher &searcher)
+{
+ Searcher::CallbackReturn shouldContinue;
+ if (context.comp_unit == NULL)
+ {
+ const size_t num_comp_units = module_sp->GetNumCompileUnits();
+ for (size_t i = 0; i < num_comp_units; i++)
+ {
+ CompUnitSP cu_sp (module_sp->GetCompileUnitAtIndex (i));
+ if (cu_sp)
+ {
+ if (!CompUnitPasses (*(cu_sp.get())))
+ continue;
+
+ if (searcher.GetDepth () == Searcher::eDepthCompUnit)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp, cu_sp.get());
+
+ shouldContinue = searcher.SearchCallback (*this, matchingContext, NULL, false);
+
+ if (shouldContinue == Searcher::eCallbackReturnPop)
+ return Searcher::eCallbackReturnContinue;
+ else if (shouldContinue == Searcher::eCallbackReturnStop)
+ return shouldContinue;
+ }
+ else
+ {
+ // FIXME Descend to block.
+ }
+ }
+ }
+ }
+ else
+ {
+ if (CompUnitPasses(*context.comp_unit))
+ {
+ SymbolContext matchingContext (m_target_sp, module_sp, context.comp_unit);
+ return searcher.SearchCallback (*this, matchingContext, NULL, false);
+ }
+ }
+ return Searcher::eCallbackReturnContinue;
+}
+
+Searcher::CallbackReturn
+SearchFilter::DoFunctionIteration (Function *function, const SymbolContext &context, Searcher &searcher)
+{
+ // FIXME: Implement...
+ return Searcher::eCallbackReturnContinue;
+}
+
+//----------------------------------------------------------------------
+// SearchFilterForNonModuleSpecificSearches:
+// 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;
+ }
+
+//----------------------------------------------------------------------
+// SearchFilterByModule:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModule constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModule::SearchFilterByModule (const lldb::TargetSP &target_sp, const FileSpec &module) :
+ SearchFilter (target_sp),
+ m_module_spec (module)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModule copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModule::SearchFilterByModule(const SearchFilterByModule& rhs) :
+ SearchFilter (rhs),
+ m_module_spec (rhs.m_module_spec)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModule assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModule&
+SearchFilterByModule::operator=(const SearchFilterByModule& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec = rhs.m_module_spec;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModule::~SearchFilterByModule()
+{
+}
+
+bool
+SearchFilterByModule::ModulePasses (const ModuleSP &module_sp)
+{
+ if (module_sp && FileSpec::Equal(module_sp->GetFileSpec(), m_module_spec, false))
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModule::ModulePasses (const FileSpec &spec)
+{
+ // Do a full match only if "spec" has a directory
+ const bool full_match = spec.GetDirectory();
+ return FileSpec::Equal(spec, m_module_spec, full_match);
+}
+
+bool
+SearchFilterByModule::AddressPasses (Address &address)
+{
+ // FIXME: Not yet implemented
+ return true;
+}
+
+
+bool
+SearchFilterByModule::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilterByModule::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilterByModule::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ const ModuleList &target_modules = m_target_sp->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 = target_modules.GetModulePointerAtIndexUnlocked(i);
+ const bool full_match = m_module_spec.GetDirectory();
+ if (FileSpec::Equal (m_module_spec, module->GetFileSpec(), full_match))
+ {
+ SymbolContext matchingContext(m_target_sp, module->shared_from_this());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModule::GetDescription (Stream *s)
+{
+ s->PutCString(", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec.GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec.GetFilename().AsCString("<unknown>"));
+ }
+}
+
+uint32_t
+SearchFilterByModule::GetFilterRequiredItems()
+{
+ return eSymbolContextModule;
+}
+
+void
+SearchFilterByModule::Dump (Stream *s) const
+{
+
+}
+//----------------------------------------------------------------------
+// SearchFilterByModuleList:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModuleList::SearchFilterByModuleList (const lldb::TargetSP &target_sp, const FileSpecList &module_list) :
+ SearchFilter (target_sp),
+ m_module_spec_list (module_list)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModuleList::SearchFilterByModuleList(const SearchFilterByModuleList& rhs) :
+ SearchFilter (rhs),
+ m_module_spec_list (rhs.m_module_spec_list)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleList assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModuleList&
+SearchFilterByModuleList::operator=(const SearchFilterByModuleList& rhs)
+{
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec_list = rhs.m_module_spec_list;
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModuleList::~SearchFilterByModuleList()
+{
+}
+
+bool
+SearchFilterByModuleList::ModulePasses (const ModuleSP &module_sp)
+{
+ if (m_module_spec_list.GetSize() == 0)
+ return true;
+
+ if (module_sp && m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != UINT32_MAX)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModuleList::ModulePasses (const FileSpec &spec)
+{
+ if (m_module_spec_list.GetSize() == 0)
+ return true;
+
+ if (m_module_spec_list.FindFileIndex(0, spec, true) != UINT32_MAX)
+ return true;
+ else
+ return false;
+}
+
+bool
+SearchFilterByModuleList::AddressPasses (Address &address)
+{
+ // FIXME: Not yet implemented
+ return true;
+}
+
+
+bool
+SearchFilterByModuleList::CompUnitPasses (FileSpec &fileSpec)
+{
+ return true;
+}
+
+bool
+SearchFilterByModuleList::CompUnitPasses (CompileUnit &compUnit)
+{
+ return true;
+}
+
+void
+SearchFilterByModuleList::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ const ModuleList &target_modules = m_target_sp->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 = target_modules.GetModulePointerAtIndexUnlocked(i);
+ if (m_module_spec_list.FindFileIndex(0, module->GetFileSpec(), false) != UINT32_MAX)
+ {
+ SymbolContext matchingContext(m_target_sp, module->shared_from_this());
+ Searcher::CallbackReturn shouldContinue;
+
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+}
+
+void
+SearchFilterByModuleList::GetDescription (Stream *s)
+{
+ size_t num_modules = m_module_spec_list.GetSize();
+ if (num_modules == 1)
+ {
+ s->Printf (", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ }
+ }
+ else
+ {
+ s->Printf (", modules(%zu) = ", num_modules);
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ }
+ if (i != num_modules - 1)
+ s->PutCString (", ");
+ }
+ }
+}
+
+uint32_t
+SearchFilterByModuleList::GetFilterRequiredItems()
+{
+ return eSymbolContextModule;
+}
+
+void
+SearchFilterByModuleList::Dump (Stream *s) const
+{
+
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU:
+// Selects a shared library matching a given file spec
+//----------------------------------------------------------------------
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU constructors
+//----------------------------------------------------------------------
+
+SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU (const lldb::TargetSP &target_sp,
+ const FileSpecList &module_list,
+ const FileSpecList &cu_list) :
+ SearchFilterByModuleList (target_sp, module_list),
+ m_cu_spec_list (cu_list)
+{
+}
+
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU copy constructor
+//----------------------------------------------------------------------
+SearchFilterByModuleListAndCU::SearchFilterByModuleListAndCU(const SearchFilterByModuleListAndCU& rhs) :
+ SearchFilterByModuleList (rhs),
+ m_cu_spec_list (rhs.m_cu_spec_list)
+{
+}
+
+//----------------------------------------------------------------------
+// SearchFilterByModuleListAndCU assignment operator
+//----------------------------------------------------------------------
+const SearchFilterByModuleListAndCU&
+SearchFilterByModuleListAndCU::operator=(const SearchFilterByModuleListAndCU& rhs)
+{
+ if (&rhs != this)
+ {
+ m_target_sp = rhs.m_target_sp;
+ m_module_spec_list = rhs.m_module_spec_list;
+ m_cu_spec_list = rhs.m_cu_spec_list;
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SearchFilterByModuleListAndCU::~SearchFilterByModuleListAndCU()
+{
+}
+
+bool
+SearchFilterByModuleListAndCU::AddressPasses (Address &address)
+{
+ return true;
+}
+
+
+bool
+SearchFilterByModuleListAndCU::CompUnitPasses (FileSpec &fileSpec)
+{
+ return m_cu_spec_list.FindFileIndex(0, fileSpec, false) != UINT32_MAX;
+}
+
+bool
+SearchFilterByModuleListAndCU::CompUnitPasses (CompileUnit &compUnit)
+{
+ bool in_cu_list = m_cu_spec_list.FindFileIndex(0, compUnit, false) != UINT32_MAX;
+ if (in_cu_list)
+ {
+ ModuleSP module_sp(compUnit.GetModule());
+ if (module_sp)
+ {
+ bool module_passes = SearchFilterByModuleList::ModulePasses(module_sp);
+ return module_passes;
+ }
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+void
+SearchFilterByModuleListAndCU::Search (Searcher &searcher)
+{
+ if (!m_target_sp)
+ return;
+
+ if (searcher.GetDepth() == Searcher::eDepthTarget)
+ {
+ SymbolContext empty_sc;
+ empty_sc.target_sp = m_target_sp;
+ searcher.SearchCallback (*this, empty_sc, NULL, false);
+ }
+
+ // If the module file spec is a full path, then we can just find the one
+ // filespec that passes. Otherwise, we need to go through all modules and
+ // find the ones that match the file name.
+
+ ModuleList matching_modules;
+ const ModuleList &target_images = m_target_sp->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ const size_t num_modules = target_images.GetSize ();
+ bool no_modules_in_filter = m_module_spec_list.GetSize() == 0;
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ lldb::ModuleSP module_sp = target_images.GetModuleAtIndexUnlocked(i);
+ if (no_modules_in_filter || m_module_spec_list.FindFileIndex(0, module_sp->GetFileSpec(), false) != UINT32_MAX)
+ {
+ SymbolContext matchingContext(m_target_sp, module_sp);
+ Searcher::CallbackReturn shouldContinue;
+
+ if (searcher.GetDepth() == Searcher::eDepthModule)
+ {
+ shouldContinue = DoModuleIteration(matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ else
+ {
+ const size_t num_cu = module_sp->GetNumCompileUnits();
+ for (size_t cu_idx = 0; cu_idx < num_cu; cu_idx++)
+ {
+ CompUnitSP cu_sp = module_sp->GetCompileUnitAtIndex(cu_idx);
+ matchingContext.comp_unit = cu_sp.get();
+ if (matchingContext.comp_unit)
+ {
+ if (m_cu_spec_list.FindFileIndex(0, *matchingContext.comp_unit, false) != UINT32_MAX)
+ {
+ shouldContinue = DoCUIteration(module_sp, matchingContext, searcher);
+ if (shouldContinue == Searcher::eCallbackReturnStop)
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+SearchFilterByModuleListAndCU::GetDescription (Stream *s)
+{
+ size_t num_modules = m_module_spec_list.GetSize();
+ if (num_modules == 1)
+ {
+ s->Printf (", module = ");
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(0).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(0).GetFilename().AsCString("<unknown>"));
+ }
+ }
+ else if (num_modules > 0)
+ {
+ s->Printf (", modules(%zd) = ", num_modules);
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (s->GetVerbose())
+ {
+ char buffer[2048];
+ m_module_spec_list.GetFileSpecAtIndex(i).GetPath(buffer, 2047);
+ s->PutCString(buffer);
+ }
+ else
+ {
+ s->PutCString(m_module_spec_list.GetFileSpecAtIndex(i).GetFilename().AsCString("<unknown>"));
+ }
+ if (i != num_modules - 1)
+ s->PutCString (", ");
+ }
+ }
+}
+
+uint32_t
+SearchFilterByModuleListAndCU::GetFilterRequiredItems()
+{
+ return eSymbolContextModule | eSymbolContextCompUnit;
+}
+
+void
+SearchFilterByModuleListAndCU::Dump (Stream *s) const
+{
+
+}
+
diff --git a/source/Core/Section.cpp b/source/Core/Section.cpp
new file mode 100644
index 000000000000..e2a084ceb2f2
--- /dev/null
+++ b/source/Core/Section.cpp
@@ -0,0 +1,562 @@
+//===-- Section.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/Section.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Section::Section (const ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags) :
+ ModuleChild (module_sp),
+ UserID (sect_id),
+ Flags (flags),
+ m_obj_file (obj_file),
+ m_type (sect_type),
+ m_parent_wp (),
+ m_name (name),
+ m_file_addr (file_addr),
+ m_byte_size (byte_size),
+ m_file_offset (file_offset),
+ m_file_size (file_size),
+ m_children (),
+ m_fake (false),
+ m_encrypted (false),
+ m_thread_specific (false)
+{
+// 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());
+}
+
+Section::Section (const lldb::SectionSP &parent_section_sp,
+ const ModuleSP &module_sp,
+ ObjectFile *obj_file,
+ user_id_t sect_id,
+ const ConstString &name,
+ SectionType sect_type,
+ addr_t file_addr,
+ addr_t byte_size,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ uint32_t flags) :
+ ModuleChild (module_sp),
+ UserID (sect_id),
+ Flags (flags),
+ m_obj_file (obj_file),
+ m_type (sect_type),
+ m_parent_wp (),
+ m_name (name),
+ m_file_addr (file_addr),
+ m_byte_size (byte_size),
+ m_file_offset (file_offset),
+ m_file_size (file_size),
+ m_children (),
+ m_fake (false),
+ m_encrypted (false),
+ m_thread_specific (false)
+{
+// 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());
+ if (parent_section_sp)
+ m_parent_wp = parent_section_sp;
+}
+
+Section::~Section()
+{
+// printf ("Section::~Section(%p)\n", this);
+}
+
+addr_t
+Section::GetFileAddress () const
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ // This section has a parent which means m_file_addr is an offset into
+ // the parent section, so the file address for this section is the file
+ // address of the parent plus the offset
+ return parent_sp->GetFileAddress() + m_file_addr;
+ }
+ // This section has no parent, so m_file_addr is the file base address
+ return m_file_addr;
+}
+
+bool
+Section::SetFileAddress (lldb::addr_t file_addr)
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ if (m_file_addr >= file_addr)
+ return parent_sp->SetFileAddress (m_file_addr - file_addr);
+ return false;
+ }
+ else
+ {
+ // This section has no parent, so m_file_addr is the file base address
+ m_file_addr = file_addr;
+ return true;
+ }
+}
+
+lldb::addr_t
+Section::GetOffset () const
+{
+ // This section has a parent which means m_file_addr is an offset.
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ return m_file_addr;
+
+ // This section has no parent, so there is no offset to be had
+ return 0;
+}
+
+addr_t
+Section::GetLoadBaseAddress (Target *target) const
+{
+ addr_t load_base_addr = LLDB_INVALID_ADDRESS;
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ load_base_addr = parent_sp->GetLoadBaseAddress (target);
+ if (load_base_addr != LLDB_INVALID_ADDRESS)
+ load_base_addr += GetOffset();
+ }
+ else
+ {
+ load_base_addr = target->GetSectionLoadList().GetSectionLoadAddress (const_cast<Section *>(this)->shared_from_this());
+ }
+ return load_base_addr;
+}
+
+bool
+Section::ResolveContainedAddress (addr_t offset, Address &so_addr) const
+{
+ const size_t num_children = m_children.GetSize();
+ if (num_children > 0)
+ {
+ for (size_t i=0; i<num_children; i++)
+ {
+ Section* child_section = m_children.GetSectionAtIndex (i).get();
+
+ addr_t child_offset = child_section->GetOffset();
+ if (child_offset <= offset && offset - child_offset < child_section->GetByteSize())
+ return child_section->ResolveContainedAddress (offset - child_offset, so_addr);
+ }
+ }
+ so_addr.SetOffset(offset);
+ so_addr.SetSection(const_cast<Section *>(this)->shared_from_this());
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // For debug builds, ensure that there are no orphaned (i.e., moduleless) sections.
+ assert(GetModule().get());
+#endif
+ return true;
+}
+
+bool
+Section::ContainsFileAddress (addr_t vm_addr) const
+{
+ const addr_t file_addr = GetFileAddress();
+ if (file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (file_addr <= vm_addr)
+ {
+ const addr_t offset = vm_addr - file_addr;
+ return offset < GetByteSize();
+ }
+ }
+ return false;
+}
+
+int
+Section::Compare (const Section& a, const Section& b)
+{
+ if (&a == &b)
+ return 0;
+
+ const ModuleSP a_module_sp = a.GetModule();
+ const ModuleSP b_module_sp = b.GetModule();
+ if (a_module_sp == b_module_sp)
+ {
+ user_id_t a_sect_uid = a.GetID();
+ user_id_t b_sect_uid = b.GetID();
+ if (a_sect_uid < b_sect_uid)
+ return -1;
+ if (a_sect_uid > b_sect_uid)
+ return 1;
+ return 0;
+ }
+ else
+ {
+ // The modules are different, just compare the module pointers
+ if (a_module_sp.get() < b_module_sp.get())
+ return -1;
+ else
+ return 1; // We already know the modules aren't equal
+ }
+}
+
+
+void
+Section::Dump (Stream *s, Target *target, uint32_t depth) const
+{
+// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("0x%8.8" PRIx64 " %-16s ", GetID(), GetSectionTypeAsCString (m_type));
+ bool resolved = true;
+ addr_t addr = LLDB_INVALID_ADDRESS;
+
+ if (GetByteSize() == 0)
+ s->Printf("%39s", "");
+ else
+ {
+ if (target)
+ addr = GetLoadBaseAddress (target);
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ if (target)
+ resolved = false;
+ addr = GetFileAddress();
+ }
+
+ VMRange range(addr, addr + m_byte_size);
+ range.Dump (s, 0);
+ }
+
+ s->Printf("%c 0x%8.8" PRIx64 " 0x%8.8" PRIx64 " 0x%8.8x ", resolved ? ' ' : '*', m_file_offset, m_file_size, Get());
+
+ DumpName (s);
+
+ s->EOL();
+
+ if (depth > 0)
+ m_children.Dump(s, target, false, depth - 1);
+}
+
+void
+Section::DumpName (Stream *s) const
+{
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ {
+ parent_sp->DumpName (s);
+ s->PutChar('.');
+ }
+ else
+ {
+ // The top most section prints the module basename
+ const char * name = NULL;
+ ModuleSP module_sp (GetModule());
+ const FileSpec &file_spec = m_obj_file->GetFileSpec();
+
+ if (m_obj_file)
+ name = file_spec.GetFilename().AsCString();
+ if ((!name || !name[0]) && module_sp)
+ name = module_sp->GetFileSpec().GetFilename().AsCString();
+ if (name && name[0])
+ s->Printf("%s.", name);
+ }
+ m_name.Dump(s);
+}
+
+bool
+Section::IsDescendant (const Section *section)
+{
+ if (this == section)
+ return true;
+ SectionSP parent_sp (GetParent ());
+ if (parent_sp)
+ return parent_sp->IsDescendant (section);
+ return false;
+}
+
+bool
+Section::Slide (addr_t slide_amount, bool slide_children)
+{
+ if (m_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (slide_amount == 0)
+ return true;
+
+ m_file_addr += slide_amount;
+
+ if (slide_children)
+ m_children.Slide (slide_amount, slide_children);
+
+ return true;
+ }
+ return false;
+}
+
+#pragma mark SectionList
+
+SectionList::SectionList () :
+ m_sections()
+{
+}
+
+
+SectionList::~SectionList ()
+{
+}
+
+SectionList &
+SectionList::operator = (const SectionList& rhs)
+{
+ if (this != &rhs)
+ m_sections = rhs.m_sections;
+ return *this;
+}
+
+size_t
+SectionList::AddSection (const lldb::SectionSP& section_sp)
+{
+ assert (section_sp.get());
+ size_t section_index = m_sections.size();
+ m_sections.push_back(section_sp);
+ return section_index;
+}
+
+// Warning, this can be slow as it's removing items from a std::vector.
+bool
+SectionList::DeleteSection (size_t idx)
+{
+ if (idx < m_sections.size())
+ {
+ m_sections.erase (m_sections.begin() + idx);
+ return true;
+ }
+ return false;
+}
+
+size_t
+SectionList::FindSectionIndex (const Section* sect)
+{
+ iterator sect_iter;
+ iterator begin = m_sections.begin();
+ iterator end = m_sections.end();
+ for (sect_iter = begin; sect_iter != end; ++sect_iter)
+ {
+ if (sect_iter->get() == sect)
+ {
+ // The secton was already in this section list
+ return std::distance (begin, sect_iter);
+ }
+ }
+ return UINT32_MAX;
+}
+
+size_t
+SectionList::AddUniqueSection (const lldb::SectionSP& sect_sp)
+{
+ size_t sect_idx = FindSectionIndex (sect_sp.get());
+ if (sect_idx == UINT32_MAX)
+ {
+ sect_idx = AddSection (sect_sp);
+ }
+ return sect_idx;
+}
+
+bool
+SectionList::ReplaceSection (user_id_t sect_id, const lldb::SectionSP& sect_sp, uint32_t depth)
+{
+ iterator sect_iter, end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ if ((*sect_iter)->GetID() == sect_id)
+ {
+ *sect_iter = sect_sp;
+ return true;
+ }
+ else if (depth > 0)
+ {
+ if ((*sect_iter)->GetChildren().ReplaceSection(sect_id, sect_sp, depth - 1))
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t
+SectionList::GetNumSections (uint32_t depth) const
+{
+ size_t count = m_sections.size();
+ if (depth > 0)
+ {
+ const_iterator sect_iter, end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ count += (*sect_iter)->GetChildren().GetNumSections(depth - 1);
+ }
+ }
+ return count;
+}
+
+SectionSP
+SectionList::GetSectionAtIndex (size_t idx) const
+{
+ SectionSP sect_sp;
+ if (idx < m_sections.size())
+ sect_sp = m_sections[idx];
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionByName (const ConstString &section_dstr) const
+{
+ SectionSP sect_sp;
+ // Check if we have a valid section string
+ if (section_dstr && !m_sections.empty())
+ {
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ Section *child_section = sect_iter->get();
+ assert (child_section);
+ if (child_section->GetName() == section_dstr)
+ {
+ sect_sp = *sect_iter;
+ }
+ else
+ {
+ sect_sp = child_section->GetChildren().FindSectionByName(section_dstr);
+ }
+ }
+ }
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionByID (user_id_t sect_id) const
+{
+ SectionSP sect_sp;
+ if (sect_id)
+ {
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ if ((*sect_iter)->GetID() == sect_id)
+ {
+ sect_sp = *sect_iter;
+ break;
+ }
+ else
+ {
+ sect_sp = (*sect_iter)->GetChildren().FindSectionByID (sect_id);
+ }
+ }
+ }
+ return sect_sp;
+}
+
+
+SectionSP
+SectionList::FindSectionByType (SectionType sect_type, bool check_children, size_t start_idx) const
+{
+ SectionSP sect_sp;
+ size_t num_sections = m_sections.size();
+ for (size_t idx = start_idx; idx < num_sections; ++idx)
+ {
+ if (m_sections[idx]->GetType() == sect_type)
+ {
+ sect_sp = m_sections[idx];
+ break;
+ }
+ else if (check_children)
+ {
+ sect_sp = m_sections[idx]->GetChildren().FindSectionByType (sect_type, check_children, 0);
+ if (sect_sp)
+ break;
+ }
+ }
+ return sect_sp;
+}
+
+SectionSP
+SectionList::FindSectionContainingFileAddress (addr_t vm_addr, uint32_t depth) const
+{
+ SectionSP sect_sp;
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end && sect_sp.get() == NULL; ++sect_iter)
+ {
+ Section *sect = sect_iter->get();
+ if (sect->ContainsFileAddress (vm_addr))
+ {
+ // The file address is in this section. We need to make sure one of our child
+ // sections doesn't contain this address as well as obeying the depth limit
+ // that was passed in.
+ if (depth > 0)
+ sect_sp = sect->GetChildren().FindSectionContainingFileAddress(vm_addr, depth - 1);
+
+ if (sect_sp.get() == NULL && !sect->IsFake())
+ sect_sp = *sect_iter;
+ }
+ }
+ return sect_sp;
+}
+
+bool
+SectionList::ContainsSection(user_id_t sect_id) const
+{
+ return FindSectionByID (sect_id).get() != NULL;
+}
+
+void
+SectionList::Dump (Stream *s, Target *target, bool show_header, uint32_t depth) const
+{
+ bool target_has_loaded_sections = target && !target->GetSectionLoadList().IsEmpty();
+ if (show_header && !m_sections.empty())
+ {
+ s->Indent();
+ s->Printf( "SectID Type %s Address File Off. File Size Flags Section Name\n", target_has_loaded_sections ? "Load" : "File");
+ s->Indent();
+ s->PutCString("---------- ---------------- --------------------------------------- ---------- ---------- ---------- ----------------------------\n");
+ }
+
+
+ const_iterator sect_iter;
+ const_iterator end = m_sections.end();
+ for (sect_iter = m_sections.begin(); sect_iter != end; ++sect_iter)
+ {
+ (*sect_iter)->Dump(s, target_has_loaded_sections ? target : NULL, depth);
+ }
+
+ if (show_header && !m_sections.empty())
+ s->IndentLess();
+
+}
+
+size_t
+SectionList::Slide (addr_t slide_amount, bool slide_children)
+{
+ size_t count = 0;
+ const_iterator pos, end = m_sections.end();
+ for (pos = m_sections.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->Slide(slide_amount, slide_children))
+ ++count;
+ }
+ return count;
+}
diff --git a/source/Core/SourceManager.cpp b/source/Core/SourceManager.cpp
new file mode 100644
index 000000000000..9f289348fd91
--- /dev/null
+++ b/source/Core/SourceManager.cpp
@@ -0,0 +1,651 @@
+//===-- SourceManager.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/SourceManager.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static inline bool is_newline_char(char ch)
+{
+ return ch == '\n' || ch == '\r';
+}
+
+
+//----------------------------------------------------------------------
+// SourceManager constructor
+//----------------------------------------------------------------------
+SourceManager::SourceManager(const TargetSP &target_sp) :
+ m_last_file_sp (),
+ m_last_line (0),
+ m_last_count (0),
+ m_default_set(false),
+ m_target_wp (target_sp),
+ m_debugger_wp(target_sp->GetDebugger().shared_from_this())
+{
+}
+
+SourceManager::SourceManager(const DebuggerSP &debugger_sp) :
+ m_last_file_sp (),
+ m_last_line (0),
+ m_last_count (0),
+ m_default_set(false),
+ m_target_wp (),
+ m_debugger_wp (debugger_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SourceManager::~SourceManager()
+{
+}
+
+SourceManager::FileSP
+SourceManager::GetFile (const FileSpec &file_spec)
+{
+ bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec);
+
+ DebuggerSP debugger_sp (m_debugger_wp.lock());
+ FileSP file_sp;
+ if (same_as_previous)
+ file_sp = m_last_file_sp;
+ else if (debugger_sp)
+ file_sp = debugger_sp->GetSourceFileCache().FindSourceFile (file_spec);
+
+ TargetSP target_sp (m_target_wp.lock());
+
+ // It the target source path map has been updated, get this file again so we
+ // can successfully remap the source file
+ if (target_sp && file_sp && file_sp->GetSourceMapModificationID() != target_sp->GetSourcePathMap().GetModificationID())
+ file_sp.reset();
+
+ // If file_sp is no good or it points to a non-existent file, reset it.
+ if (!file_sp || !file_sp->GetFileSpec().Exists())
+ {
+ file_sp.reset (new File (file_spec, target_sp.get()));
+
+ if (debugger_sp)
+ debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
+ }
+ return file_sp;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile (uint32_t start_line,
+ uint32_t count,
+ uint32_t curr_line,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs)
+{
+ if (count == 0)
+ return 0;
+ size_t return_value = 0;
+ if (start_line == 0)
+ {
+ if (m_last_line != 0 && m_last_line != UINT32_MAX)
+ start_line = m_last_line + m_last_count;
+ else
+ start_line = 1;
+ }
+
+ if (!m_default_set)
+ {
+ FileSpec tmp_spec;
+ uint32_t tmp_line;
+ GetDefaultFileAndLine(tmp_spec, tmp_line);
+ }
+
+ m_last_line = start_line;
+ m_last_count = count;
+
+ if (m_last_file_sp.get())
+ {
+ const uint32_t end_line = start_line + count - 1;
+ for (uint32_t line = start_line; line <= end_line; ++line)
+ {
+ if (!m_last_file_sp->LineIsValid (line))
+ {
+ m_last_line = UINT32_MAX;
+ break;
+ }
+
+ char prefix[32] = "";
+ if (bp_locs)
+ {
+ uint32_t bp_count = bp_locs->NumLineEntriesWithLine (line);
+
+ if (bp_count > 0)
+ ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count);
+ else
+ ::snprintf (prefix, sizeof (prefix), " ");
+ }
+
+ return_value += s->Printf("%s%2.2s %-4u\t",
+ prefix,
+ line == curr_line ? current_line_cstr : "",
+ line);
+ size_t this_line_size = m_last_file_sp->DisplaySourceLines (line, 0, 0, s);
+ if (this_line_size == 0)
+ {
+ m_last_line = UINT32_MAX;
+ break;
+ }
+ else
+ return_value += this_line_size;
+ }
+ }
+ return return_value;
+}
+
+size_t
+SourceManager::DisplaySourceLinesWithLineNumbers
+(
+ const FileSpec &file_spec,
+ uint32_t line,
+ uint32_t context_before,
+ uint32_t context_after,
+ const char* current_line_cstr,
+ Stream *s,
+ const SymbolContextList *bp_locs
+)
+{
+ FileSP file_sp (GetFile (file_spec));
+
+ uint32_t start_line;
+ uint32_t count = context_before + context_after + 1;
+ if (line > context_before)
+ start_line = line - context_before;
+ else
+ start_line = 1;
+
+ if (m_last_file_sp.get() != file_sp.get())
+ {
+ if (line == 0)
+ m_last_line = 0;
+ m_last_file_sp = file_sp;
+ }
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (start_line, count, line, current_line_cstr, s, bp_locs);
+}
+
+size_t
+SourceManager::DisplayMoreWithLineNumbers (Stream *s,
+ uint32_t count,
+ bool reverse,
+ const SymbolContextList *bp_locs)
+{
+ // If we get called before anybody has set a default file and line, then try to figure it out here.
+ const bool have_default_file_line = m_last_file_sp && m_last_line > 0;
+ if (!m_default_set)
+ {
+ FileSpec tmp_spec;
+ uint32_t tmp_line;
+ GetDefaultFileAndLine(tmp_spec, tmp_line);
+ }
+
+ if (m_last_file_sp)
+ {
+ if (m_last_line == UINT32_MAX)
+ return 0;
+
+ if (reverse && m_last_line == 1)
+ return 0;
+
+ if (count > 0)
+ m_last_count = count;
+ else if (m_last_count == 0)
+ m_last_count = 10;
+
+ if (m_last_line > 0)
+ {
+ if (reverse)
+ {
+ // If this is the first time we've done a reverse, then back up one more time so we end
+ // up showing the chunk before the last one we've shown:
+ if (m_last_line > m_last_count)
+ m_last_line -= m_last_count;
+ else
+ m_last_line = 1;
+ }
+ else if (have_default_file_line)
+ m_last_line += m_last_count;
+ }
+ else
+ m_last_line = 1;
+
+ return DisplaySourceLinesWithLineNumbersUsingLastFile (m_last_line, m_last_count, UINT32_MAX, "", s, bp_locs);
+ }
+ return 0;
+}
+
+bool
+SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line)
+{
+ FileSP old_file_sp = m_last_file_sp;
+ m_last_file_sp = GetFile (file_spec);
+
+ m_default_set = true;
+ if (m_last_file_sp)
+ {
+ m_last_line = line;
+ return true;
+ }
+ else
+ {
+ m_last_file_sp = old_file_sp;
+ return false;
+ }
+}
+
+bool
+SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line)
+{
+ if (m_last_file_sp)
+ {
+ file_spec = m_last_file_sp->GetFileSpec();
+ line = m_last_line;
+ return true;
+ }
+ else if (!m_default_set)
+ {
+ TargetSP target_sp (m_target_wp.lock());
+
+ if (target_sp)
+ {
+ // If nobody has set the default file and line then try here. If there's no executable, then we
+ // will try again later when there is one. Otherwise, if we can't find it we won't look again,
+ // somebody will have to set it (for instance when we stop somewhere...)
+ Module *executable_ptr = target_sp->GetExecutableModulePointer();
+ if (executable_ptr)
+ {
+ SymbolContextList sc_list;
+ ConstString main_name("main");
+ bool symbols_okay = false; // Force it to be a debug symbol.
+ bool inlines_okay = true;
+ bool append = false;
+ size_t num_matches = executable_ptr->FindFunctions (main_name,
+ NULL,
+ lldb::eFunctionNameTypeBase,
+ inlines_okay,
+ symbols_okay,
+ append,
+ sc_list);
+ for (size_t idx = 0; idx < num_matches; idx++)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(idx, sc);
+ if (sc.function)
+ {
+ lldb_private::LineEntry line_entry;
+ if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry))
+ {
+ SetDefaultFileAndLine (line_entry.file,
+ line_entry.line);
+ file_spec = m_last_file_sp->GetFileSpec();
+ line = m_last_line;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void
+SourceManager::FindLinesMatchingRegex (FileSpec &file_spec,
+ RegularExpression& regex,
+ uint32_t start_line,
+ uint32_t end_line,
+ std::vector<uint32_t> &match_lines)
+{
+ match_lines.clear();
+ FileSP file_sp = GetFile (file_spec);
+ if (!file_sp)
+ return;
+ return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines);
+}
+
+SourceManager::File::File(const FileSpec &file_spec, Target *target) :
+ m_file_spec_orig (file_spec),
+ m_file_spec(file_spec),
+ m_mod_time (file_spec.GetModificationTime()),
+ m_source_map_mod_id (0),
+ m_data_sp(),
+ m_offsets()
+{
+ if (!m_mod_time.IsValid())
+ {
+ if (target)
+ {
+ m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
+
+ if (!file_spec.GetDirectory() && file_spec.GetFilename())
+ {
+ // If this is just a file name, lets see if we can find it in the target:
+ bool check_inlines = false;
+ SymbolContextList sc_list;
+ size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(),
+ 0,
+ check_inlines,
+ lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit,
+ sc_list);
+ bool got_multiple = false;
+ if (num_matches != 0)
+ {
+ if (num_matches > 1)
+ {
+ SymbolContext sc;
+ FileSpec *test_cu_spec = NULL;
+
+ for (unsigned i = 0; i < num_matches; i++)
+ {
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.comp_unit)
+ {
+ if (test_cu_spec)
+ {
+ if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit))
+ got_multiple = true;
+ break;
+ }
+ else
+ test_cu_spec = sc.comp_unit;
+ }
+ }
+ }
+ if (!got_multiple)
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex (0, sc);
+ m_file_spec = sc.comp_unit;
+ m_mod_time = m_file_spec.GetModificationTime();
+ }
+ }
+ }
+ // Try remapping if m_file_spec does not correspond to an existing file.
+ if (!m_file_spec.Exists())
+ {
+ FileSpec new_file_spec;
+ // Check target specific source remappings first, then fall back to
+ // modules objects can have individual path remappings that were detected
+ // when the debug info for a module was found.
+ // then
+ if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) ||
+ target->GetImages().FindSourceFile (m_file_spec, new_file_spec))
+ {
+ m_file_spec = new_file_spec;
+ m_mod_time = m_file_spec.GetModificationTime();
+ }
+ }
+ }
+ }
+
+ if (m_mod_time.IsValid())
+ m_data_sp = m_file_spec.ReadFileContents ();
+}
+
+SourceManager::File::~File()
+{
+}
+
+uint32_t
+SourceManager::File::GetLineOffset (uint32_t line)
+{
+ if (line == 0)
+ return UINT32_MAX;
+
+ if (line == 1)
+ return 0;
+
+ if (CalculateLineOffsets (line))
+ {
+ if (line < m_offsets.size())
+ return m_offsets[line - 1]; // yes we want "line - 1" in the index
+ }
+ return UINT32_MAX;
+}
+
+bool
+SourceManager::File::LineIsValid (uint32_t line)
+{
+ if (line == 0)
+ return false;
+
+ if (CalculateLineOffsets (line))
+ return line < m_offsets.size();
+ return false;
+}
+
+size_t
+SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s)
+{
+ // TODO: use host API to sign up for file modifications to anything in our
+ // source cache and only update when we determine a file has been updated.
+ // For now we check each time we want to display info for the file.
+ TimeValue curr_mod_time (m_file_spec.GetModificationTime());
+
+ if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time)
+ {
+ m_mod_time = curr_mod_time;
+ m_data_sp = m_file_spec.ReadFileContents ();
+ m_offsets.clear();
+ }
+
+ // Sanity check m_data_sp before proceeding.
+ if (!m_data_sp)
+ return 0;
+
+ const uint32_t start_line = line <= context_before ? 1 : line - context_before;
+ const uint32_t start_line_offset = GetLineOffset (start_line);
+ if (start_line_offset != UINT32_MAX)
+ {
+ const uint32_t end_line = line + context_after;
+ uint32_t end_line_offset = GetLineOffset (end_line + 1);
+ if (end_line_offset == UINT32_MAX)
+ end_line_offset = m_data_sp->GetByteSize();
+
+ assert (start_line_offset <= end_line_offset);
+ size_t bytes_written = 0;
+ if (start_line_offset < end_line_offset)
+ {
+ size_t count = end_line_offset - start_line_offset;
+ const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset;
+ bytes_written = s->Write(cstr, count);
+ if (!is_newline_char(cstr[count-1]))
+ bytes_written += s->EOL();
+ }
+ return bytes_written;
+ }
+ return 0;
+}
+
+void
+SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines)
+{
+ TimeValue curr_mod_time (m_file_spec.GetModificationTime());
+ if (m_mod_time != curr_mod_time)
+ {
+ m_mod_time = curr_mod_time;
+ m_data_sp = m_file_spec.ReadFileContents ();
+ m_offsets.clear();
+ }
+
+ match_lines.clear();
+
+ if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line)))
+ return;
+ if (start_line > end_line)
+ return;
+
+ for (uint32_t line_no = start_line; line_no < end_line; line_no++)
+ {
+ std::string buffer;
+ if (!GetLine (line_no, buffer))
+ break;
+ if (regex.Execute(buffer.c_str()))
+ {
+ match_lines.push_back(line_no);
+ }
+ }
+}
+
+bool
+SourceManager::File::FileSpecMatches (const FileSpec &file_spec)
+{
+ return FileSpec::Equal (m_file_spec, file_spec, false);
+}
+
+bool
+lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs)
+{
+ if (lhs.m_file_spec == rhs.m_file_spec)
+ {
+ if (lhs.m_mod_time.IsValid())
+ {
+ if (rhs.m_mod_time.IsValid())
+ return lhs.m_mod_time == rhs.m_mod_time;
+ else
+ return false;
+ }
+ else if (rhs.m_mod_time.IsValid())
+ return false;
+ else
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+SourceManager::File::CalculateLineOffsets (uint32_t line)
+{
+ line = UINT32_MAX; // TODO: take this line out when we support partial indexing
+ if (line == UINT32_MAX)
+ {
+ // Already done?
+ if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX)
+ return true;
+
+ if (m_offsets.empty())
+ {
+ if (m_data_sp.get() == NULL)
+ return false;
+
+ const char *start = (char *)m_data_sp->GetBytes();
+ if (start)
+ {
+ const char *end = start + m_data_sp->GetByteSize();
+
+ // Calculate all line offsets from scratch
+
+ // Push a 1 at index zero to indicate the file has been completely indexed.
+ m_offsets.push_back(UINT32_MAX);
+ register const char *s;
+ for (s = start; s < end; ++s)
+ {
+ register char curr_ch = *s;
+ if (is_newline_char (curr_ch))
+ {
+ if (s + 1 < end)
+ {
+ register char next_ch = s[1];
+ if (is_newline_char (next_ch))
+ {
+ if (curr_ch != next_ch)
+ ++s;
+ }
+ }
+ m_offsets.push_back(s + 1 - start);
+ }
+ }
+ if (!m_offsets.empty())
+ {
+ if (m_offsets.back() < end - start)
+ m_offsets.push_back(end - start);
+ }
+ return true;
+ }
+ }
+ else
+ {
+ // Some lines have been populated, start where we last left off
+ assert("Not implemented yet" == NULL);
+ }
+
+ }
+ else
+ {
+ // Calculate all line offsets up to "line"
+ assert("Not implemented yet" == NULL);
+ }
+ return false;
+}
+
+bool
+SourceManager::File::GetLine (uint32_t line_no, std::string &buffer)
+{
+ if (!LineIsValid(line_no))
+ return false;
+
+ size_t start_offset = GetLineOffset (line_no);
+ size_t end_offset = GetLineOffset (line_no + 1);
+ if (end_offset == UINT32_MAX)
+ {
+ end_offset = m_data_sp->GetByteSize();
+ }
+ buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset);
+
+ return true;
+}
+
+void
+SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp)
+{
+ FileSpec file_spec;
+ FileCache::iterator pos = m_file_cache.find(file_spec);
+ if (pos == m_file_cache.end())
+ m_file_cache[file_spec] = file_sp;
+ else
+ {
+ if (file_sp != pos->second)
+ m_file_cache[file_spec] = file_sp;
+ }
+}
+
+SourceManager::FileSP
+SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const
+{
+ FileSP file_sp;
+ FileCache::const_iterator pos = m_file_cache.find(file_spec);
+ if (pos != m_file_cache.end())
+ file_sp = pos->second;
+ return file_sp;
+}
+
diff --git a/source/Core/State.cpp b/source/Core/State.cpp
new file mode 100644
index 000000000000..7d9ccda532a2
--- /dev/null
+++ b/source/Core/State.cpp
@@ -0,0 +1,115 @@
+//===-- State.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/Core/State.h"
+#include <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+lldb_private::StateAsCString (StateType state)
+{
+ switch (state)
+ {
+ case eStateInvalid: return "invalid";
+ case eStateUnloaded: return "unloaded";
+ case eStateConnected: return "connected";
+ case eStateAttaching: return "attaching";
+ case eStateLaunching: return "launching";
+ case eStateStopped: return "stopped";
+ case eStateRunning: return "running";
+ case eStateStepping: return "stepping";
+ case eStateCrashed: return "crashed";
+ case eStateDetached: return "detached";
+ case eStateExited: return "exited";
+ case eStateSuspended: return "suspended";
+ }
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "StateType = %i", state);
+ return unknown_state_string;
+}
+
+const char *
+lldb_private::GetPermissionsAsCString (uint32_t permissions)
+{
+ switch (permissions)
+ {
+ case 0: return "---";
+ case ePermissionsWritable: return "-w-";
+ case ePermissionsReadable: return "r--";
+ case ePermissionsExecutable: return "--x";
+ case ePermissionsReadable |
+ ePermissionsWritable: return "rw-";
+ case ePermissionsReadable |
+ ePermissionsExecutable: return "r-x";
+ case ePermissionsWritable |
+ ePermissionsExecutable: return "-wx";
+ case ePermissionsReadable |
+ ePermissionsWritable |
+ ePermissionsExecutable: return "rwx";
+ default:
+ break;
+ }
+ return "???";
+}
+
+bool
+lldb_private::StateIsRunningState (StateType state)
+{
+ switch (state)
+ {
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ return true;
+
+ case eStateConnected:
+ case eStateDetached:
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateExited:
+ case eStateSuspended:
+ break;
+ }
+ return false;
+}
+
+bool
+lldb_private::StateIsStoppedState (StateType state, bool must_exist)
+{
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateDetached:
+ break;
+
+ case eStateUnloaded:
+ case eStateExited:
+ return !must_exist;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+ return false;
+}
diff --git a/source/Core/Stream.cpp b/source/Core/Stream.cpp
new file mode 100644
index 000000000000..49c15d63c361
--- /dev/null
+++ b/source/Core/Stream.cpp
@@ -0,0 +1,786 @@
+//===-- Stream.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/Stream.h"
+#include "lldb/Host/Endian.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <inttypes.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream::Stream (uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ m_flags (flags),
+ m_addr_size (addr_size),
+ m_byte_order (byte_order),
+ m_indent_level(0)
+{
+}
+
+Stream::Stream () :
+ m_flags (0),
+ m_addr_size (4),
+ m_byte_order (lldb::endian::InlHostByteOrder()),
+ m_indent_level(0)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+Stream::~Stream ()
+{
+}
+
+ByteOrder
+Stream::SetByteOrder (ByteOrder byte_order)
+{
+ ByteOrder old_byte_order = m_byte_order;
+ m_byte_order = byte_order;
+ return old_byte_order;
+}
+
+//------------------------------------------------------------------
+// Put an offset "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+void
+Stream::Offset (uint32_t uval, const char *format)
+{
+ Printf (format, uval);
+}
+
+//------------------------------------------------------------------
+// Put an SLEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t
+Stream::PutSLEB128 (int64_t sval)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ bool more = true;
+ while (more)
+ {
+ uint8_t byte = sval & 0x7fu;
+ sval >>= 7;
+ /* sign bit of byte is 2nd high order bit (0x40) */
+ if ((sval == 0 && !(byte & 0x40)) ||
+ (sval == -1 && (byte & 0x40)) )
+ more = false;
+ else
+ // more bytes to come
+ byte |= 0x80u;
+ bytes_written += Write(&byte, 1);
+ }
+ }
+ else
+ {
+ bytes_written = Printf ("0x%" PRIi64, sval);
+ }
+
+ return bytes_written;
+
+}
+
+//------------------------------------------------------------------
+// Put an ULEB128 "uval" out to the stream using the printf format
+// in "format".
+//------------------------------------------------------------------
+size_t
+Stream::PutULEB128 (uint64_t uval)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ do
+ {
+
+ uint8_t byte = uval & 0x7fu;
+ uval >>= 7;
+ if (uval != 0)
+ {
+ // more bytes to come
+ byte |= 0x80u;
+ }
+ bytes_written += Write(&byte, 1);
+ } while (uval != 0);
+ }
+ else
+ {
+ bytes_written = Printf ("0x%" PRIx64, uval);
+ }
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print a raw NULL terminated C string to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::PutCString (const char *cstr)
+{
+ size_t cstr_len = strlen(cstr);
+ // when in binary mode, emit the NULL terminator
+ if (m_flags.Test(eBinary))
+ ++cstr_len;
+ return Write (cstr, cstr_len);
+}
+
+//------------------------------------------------------------------
+// Print a double quoted NULL terminated C string to the stream
+// using the printf format in "format".
+//------------------------------------------------------------------
+void
+Stream::QuotedCString (const char *cstr, const char *format)
+{
+ Printf (format, cstr);
+}
+
+//------------------------------------------------------------------
+// Put an address "addr" out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void
+Stream::Address (uint64_t addr, uint32_t addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix == NULL)
+ prefix = "";
+ if (suffix == NULL)
+ suffix = "";
+// int addr_width = m_addr_size << 1;
+// Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_width, addr, suffix);
+ Printf ("%s0x%0*" PRIx64 "%s", prefix, addr_size * 2, (uint64_t)addr, suffix);
+}
+
+//------------------------------------------------------------------
+// Put an address range out to the stream with optional prefix
+// and suffix strings.
+//------------------------------------------------------------------
+void
+Stream::AddressRange(uint64_t lo_addr, uint64_t hi_addr, uint32_t addr_size, const char *prefix, const char *suffix)
+{
+ if (prefix && prefix[0])
+ PutCString (prefix);
+ Address (lo_addr, addr_size, "[");
+ Address (hi_addr, addr_size, "-", ")");
+ if (suffix && suffix[0])
+ PutCString (suffix);
+}
+
+
+size_t
+Stream::PutChar (char ch)
+{
+ return Write (&ch, 1);
+}
+
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::Printf (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ size_t result = PrintfVarArg(format, args);
+ va_end (args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+Stream::PrintfVarArg (const char *format, va_list args)
+{
+ char str[1024];
+ va_list args_copy;
+
+ va_copy (args_copy, args);
+
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ bytes_written = Write (str, length);
+ }
+ else
+ {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf (&str_ptr, format, args_copy);
+ if (str_ptr)
+ {
+ // Include the NULL termination byte for binary output
+ if (m_flags.Test(eBinary))
+ length += 1;
+ bytes_written = Write (str_ptr, length);
+ ::free (str_ptr);
+ }
+ }
+ va_end (args_copy);
+ return bytes_written;
+}
+
+//------------------------------------------------------------------
+// Print and End of Line character to the stream
+//------------------------------------------------------------------
+size_t
+Stream::EOL()
+{
+ return PutChar ('\n');
+}
+
+//------------------------------------------------------------------
+// Indent the current line using the current indentation level and
+// print an optional string following the idenatation spaces.
+//------------------------------------------------------------------
+size_t
+Stream::Indent(const char *s)
+{
+ return Printf ("%*.*s%s", m_indent_level, m_indent_level, "", s ? s : "");
+}
+
+//------------------------------------------------------------------
+// Stream a character "ch" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (char ch)
+{
+ PutChar (ch);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the NULL terminated C string out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (const char *s)
+{
+ Printf ("%s", s);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream the pointer value out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (void *p)
+{
+ Printf ("0x%.*tx", (int)sizeof(void*) * 2, (ptrdiff_t)p);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint8_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint8_t uval)
+{
+ PutHex8(uval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint16_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint16_t uval)
+{
+ PutHex16(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint32_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint32_t uval)
+{
+ PutHex32(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a uint64_t "uval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (uint64_t uval)
+{
+ PutHex64(uval, m_byte_order);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int8_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int8_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int16_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int16_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int32_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int32_t sval)
+{
+ Printf ("%i", (int)sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Stream a int64_t "sval" out to this stream.
+//------------------------------------------------------------------
+Stream&
+Stream::operator<< (int64_t sval)
+{
+ Printf ("%" PRIi64, sval);
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Get the current indentation level
+//------------------------------------------------------------------
+int
+Stream::GetIndentLevel() const
+{
+ return m_indent_level;
+}
+
+//------------------------------------------------------------------
+// Set the current indentation level
+//------------------------------------------------------------------
+void
+Stream::SetIndentLevel(int indent_level)
+{
+ m_indent_level = indent_level;
+}
+
+//------------------------------------------------------------------
+// Increment the current indentation level
+//------------------------------------------------------------------
+void
+Stream::IndentMore(int amount)
+{
+ m_indent_level += amount;
+}
+
+//------------------------------------------------------------------
+// Decrement the current indentation level
+//------------------------------------------------------------------
+void
+Stream::IndentLess (int amount)
+{
+ if (m_indent_level >= amount)
+ m_indent_level -= amount;
+ else
+ m_indent_level = 0;
+}
+
+//------------------------------------------------------------------
+// Get the address size in bytes
+//------------------------------------------------------------------
+uint32_t
+Stream::GetAddressByteSize() const
+{
+ return m_addr_size;
+}
+
+//------------------------------------------------------------------
+// Set the address size in bytes
+//------------------------------------------------------------------
+void
+Stream::SetAddressByteSize(uint32_t addr_size)
+{
+ m_addr_size = addr_size;
+}
+
+//------------------------------------------------------------------
+// Returns true if the verbose flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetVerbose() const
+{
+ return m_flags.Test(eVerbose);
+}
+
+//------------------------------------------------------------------
+// Returns true if the debug flag bit is set in this stream.
+//------------------------------------------------------------------
+bool
+Stream::GetDebug() const
+{
+ return m_flags.Test(eDebug);
+}
+
+//------------------------------------------------------------------
+// The flags get accessor
+//------------------------------------------------------------------
+Flags&
+Stream::GetFlags()
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The flags const get accessor
+//------------------------------------------------------------------
+const Flags&
+Stream::GetFlags() const
+{
+ return m_flags;
+}
+
+//------------------------------------------------------------------
+// The byte order get accessor
+//------------------------------------------------------------------
+
+lldb::ByteOrder
+Stream::GetByteOrder() const
+{
+ return m_byte_order;
+}
+
+size_t
+Stream::PrintfAsRawHex8 (const char *format, ...)
+{
+ va_list args;
+ va_list args_copy;
+ va_start (args, format);
+ va_copy (args, args_copy); // Copy this so we
+
+ char str[1024];
+ size_t bytes_written = 0;
+ // Try and format our string into a fixed buffer first and see if it fits
+ size_t length = ::vsnprintf (str, sizeof(str), format, args);
+ if (length < sizeof(str))
+ {
+ // The formatted string fit into our stack based buffer, so we can just
+ // append that to our packet
+ for (size_t i=0; i<length; ++i)
+ bytes_written += _PutHex8 (str[i], false);
+ }
+ else
+ {
+ // Our stack buffer wasn't big enough to contain the entire formatted
+ // string, so lets let vasprintf create the string for us!
+ char *str_ptr = NULL;
+ length = ::vasprintf (&str_ptr, format, args_copy);
+ if (str_ptr)
+ {
+ for (size_t i=0; i<length; ++i)
+ bytes_written += _PutHex8 (str_ptr[i], false);
+ ::free (str_ptr);
+ }
+ }
+ va_end (args);
+ va_end (args_copy);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutNHex8 (size_t n, uint8_t uvalue)
+{
+ size_t bytes_written = 0;
+ for (size_t i=0; i<n; ++i)
+ bytes_written += _PutHex8 (uvalue, m_flags.Test(eAddPrefix));
+ return bytes_written;
+}
+
+size_t
+Stream::_PutHex8 (uint8_t uvalue, bool add_prefix)
+{
+ size_t bytes_written = 0;
+ if (m_flags.Test(eBinary))
+ {
+ bytes_written = Write (&uvalue, 1);
+ }
+ else
+ {
+ if (add_prefix)
+ PutCString("0x");
+
+ static char g_hex_to_ascii_hex_char[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+ char nibble_chars[2];
+ nibble_chars[0] = g_hex_to_ascii_hex_char[(uvalue >> 4) & 0xf];
+ nibble_chars[1] = g_hex_to_ascii_hex_char[(uvalue >> 0) & 0xf];
+ bytes_written = Write (nibble_chars, sizeof(nibble_chars));
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex8 (uint8_t uvalue)
+{
+ return _PutHex8 (uvalue, m_flags.Test(eAddPrefix));
+}
+
+size_t
+Stream::PutHex16 (uint16_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex32(uint32_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutHex64(uint64_t uvalue, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ bool add_prefix = m_flags.Test(eAddPrefix);
+ size_t bytes_written = 0;
+ if (byte_order == eByteOrderLittle)
+ {
+ for (size_t byte = 0; byte < sizeof(uvalue); ++byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ else
+ {
+ for (size_t byte = sizeof(uvalue)-1; byte < sizeof(uvalue); --byte, add_prefix = false)
+ bytes_written += _PutHex8 ((uint8_t)(uvalue >> (byte * 8)), add_prefix);
+ }
+ return bytes_written;
+}
+
+size_t
+Stream::PutMaxHex64
+(
+ uint64_t uvalue,
+ size_t byte_size,
+ lldb::ByteOrder byte_order
+)
+{
+ switch (byte_size)
+ {
+ case 1: return PutHex8 ((uint8_t)uvalue);
+ case 2: return PutHex16 ((uint16_t)uvalue);
+ case 4: return PutHex32 ((uint32_t)uvalue);
+ case 8: return PutHex64 (uvalue);
+ }
+ return 0;
+}
+
+size_t
+Stream::PutPointer (void *ptr)
+{
+ return PutRawBytes (&ptr, sizeof(ptr), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+}
+
+size_t
+Stream::PutFloat(float f, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&f, sizeof(f), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutDouble(double d, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&d, sizeof(d), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutLongDouble(long double ld, ByteOrder byte_order)
+{
+ if (byte_order == eByteOrderInvalid)
+ byte_order = m_byte_order;
+
+ return PutRawBytes (&ld, sizeof(ld), lldb::endian::InlHostByteOrder(), byte_order);
+}
+
+size_t
+Stream::PutRawBytes (const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order)
+{
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_was_set = m_flags.Test (eBinary);
+ if (!binary_was_set)
+ m_flags.Set (eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (size_t i = src_len-1; i < src_len; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (!binary_was_set)
+ m_flags.Clear (eBinary);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutBytesAsRawHex8 (const void *s, size_t src_len, ByteOrder src_byte_order, ByteOrder dst_byte_order)
+{
+ if (src_byte_order == eByteOrderInvalid)
+ src_byte_order = m_byte_order;
+
+ if (dst_byte_order == eByteOrderInvalid)
+ dst_byte_order = m_byte_order;
+
+ size_t bytes_written = 0;
+ const uint8_t *src = (const uint8_t *)s;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ if (src_byte_order == dst_byte_order)
+ {
+ for (size_t i = 0; i < src_len; ++i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ else
+ {
+ for (size_t i = src_len-1; i < src_len; --i)
+ bytes_written += _PutHex8 (src[i], false);
+ }
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+
+ return bytes_written;
+}
+
+size_t
+Stream::PutCStringAsRawHex8 (const char *s)
+{
+ size_t bytes_written = 0;
+ bool binary_is_set = m_flags.Test(eBinary);
+ m_flags.Clear(eBinary);
+ do
+ {
+ bytes_written += _PutHex8 (*s, false);
+ ++s;
+ } while (*s);
+ if (binary_is_set)
+ m_flags.Set(eBinary);
+ return bytes_written;
+}
+
+void
+Stream::UnitTest(Stream *s)
+{
+ s->PutHex8(0x12);
+
+ s->PutChar(' ');
+ s->PutHex16(0x3456, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex16(0x3456, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex32(0x789abcde, eByteOrderLittle);
+
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, lldb::endian::InlHostByteOrder());
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderBig);
+ s->PutChar(' ');
+ s->PutHex64(0x1122334455667788ull, eByteOrderLittle);
+
+ const char *hola = "Hello World!!!";
+ s->PutChar(' ');
+ s->PutCString (hola);
+
+ s->PutChar(' ');
+ s->Write (hola, 5);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8 (hola);
+
+ s->PutChar(' ');
+ s->PutCStringAsRawHex8 ("01234");
+
+ s->PutChar(' ');
+ s->Printf ("pid=%i", 12733);
+
+ s->PutChar(' ');
+ s->PrintfAsRawHex8 ("pid=%i", 12733);
+ s->PutChar('\n');
+}
+
diff --git a/source/Core/StreamAsynchronousIO.cpp b/source/Core/StreamAsynchronousIO.cpp
new file mode 100644
index 000000000000..b9e5cdfde721
--- /dev/null
+++ b/source/Core/StreamAsynchronousIO.cpp
@@ -0,0 +1,52 @@
+//===-- StreamBroadcast.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamAsynchronousIO.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
+ Stream (0, 4, eByteOrderBig),
+ m_broadcaster (broadcaster),
+ m_broadcast_event_type (broadcast_event_type),
+ m_accumulated_data ()
+{
+}
+
+StreamAsynchronousIO::~StreamAsynchronousIO ()
+{
+}
+
+void
+StreamAsynchronousIO::Flush ()
+{
+ if (m_accumulated_data.GetSize() > 0)
+ {
+ std::unique_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
+ // Let's swap the bytes to avoid LARGE string copies.
+ data_bytes_ap->SwapBytes (m_accumulated_data.GetString());
+ EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
+ m_broadcaster.BroadcastEvent (new_event_sp);
+ m_accumulated_data.Clear();
+ }
+}
+
+size_t
+StreamAsynchronousIO::Write (const void *s, size_t length)
+{
+ m_accumulated_data.Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamCallback.cpp b/source/Core/StreamCallback.cpp
new file mode 100644
index 000000000000..d144b16755e7
--- /dev/null
+++ b/source/Core/StreamCallback.cpp
@@ -0,0 +1,64 @@
+//===-- StreamCallback.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdio.h>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/StreamCallback.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+StreamCallback::StreamCallback (lldb::LogOutputCallback callback, void *baton) :
+ Stream (0, 4, eByteOrderBig),
+ m_callback (callback),
+ m_baton (baton),
+ m_accumulated_data (),
+ m_collection_mutex ()
+{
+}
+
+StreamCallback::~StreamCallback ()
+{
+}
+
+StreamString &
+StreamCallback::FindStreamForThread(lldb::tid_t cur_tid)
+{
+ Mutex::Locker locker(m_collection_mutex);
+ collection::iterator iter = m_accumulated_data.find (cur_tid);
+ if (iter == m_accumulated_data.end())
+ {
+ std::pair<collection::iterator, bool> ret;
+ ret = m_accumulated_data.insert(std::pair<lldb::tid_t,StreamString>(cur_tid, StreamString()));
+ iter = ret.first;
+ }
+ return (*iter).second;
+}
+
+void
+StreamCallback::Flush ()
+{
+ lldb::tid_t cur_tid = Host::GetCurrentThreadID();
+ StreamString &out_stream = FindStreamForThread(cur_tid);
+ m_callback (out_stream.GetData(), m_baton);
+ out_stream.Clear();
+}
+
+size_t
+StreamCallback::Write (const void *s, size_t length)
+{
+ lldb::tid_t cur_tid = Host::GetCurrentThreadID();
+ FindStreamForThread(cur_tid).Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamFile.cpp b/source/Core/StreamFile.cpp
new file mode 100644
index 000000000000..9a4eb796dbea
--- /dev/null
+++ b/source/Core/StreamFile.cpp
@@ -0,0 +1,72 @@
+//===-- StreamFile.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/StreamFile.h"
+
+// C Includes
+#include <stdio.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StreamFile constructor
+//----------------------------------------------------------------------
+StreamFile::StreamFile () :
+ Stream (),
+ m_file ()
+{
+}
+
+StreamFile::StreamFile (uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ Stream (flags, addr_size, byte_order),
+ m_file ()
+{
+}
+
+StreamFile::StreamFile (int fd, bool transfer_ownership) :
+ Stream (),
+ m_file (fd, transfer_ownership)
+{
+}
+
+StreamFile::StreamFile (FILE *fh, bool transfer_ownership) :
+ Stream (),
+ m_file (fh, transfer_ownership)
+{
+}
+
+StreamFile::StreamFile (const char *path) :
+ Stream (),
+ m_file (path, File::eOpenOptionWrite | File::eOpenOptionCanCreate, File::ePermissionsDefault)
+{
+}
+
+
+StreamFile::~StreamFile()
+{
+}
+
+void
+StreamFile::Flush ()
+{
+ m_file.Flush();
+}
+
+size_t
+StreamFile::Write (const void *s, size_t length)
+{
+ m_file.Write (s, length);
+ return length;
+}
diff --git a/source/Core/StreamString.cpp b/source/Core/StreamString.cpp
new file mode 100644
index 000000000000..8d7d039fd65c
--- /dev/null
+++ b/source/Core/StreamString.cpp
@@ -0,0 +1,100 @@
+//===-- StreamString.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 <stdio.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+StreamString::StreamString () :
+ Stream (0, 4, eByteOrderBig)
+{
+}
+
+StreamString::StreamString(uint32_t flags, uint32_t addr_size, ByteOrder byte_order) :
+ Stream (flags, addr_size, byte_order),
+ m_packet ()
+{
+}
+
+StreamString::~StreamString()
+{
+}
+
+void
+StreamString::Flush ()
+{
+ // Nothing to do when flushing a buffer based stream...
+}
+
+size_t
+StreamString::Write (const void *s, size_t length)
+{
+ m_packet.append ((char *)s, length);
+ return length;
+}
+
+void
+StreamString::Clear()
+{
+ m_packet.clear();
+}
+
+bool
+StreamString::Empty() const
+{
+ return GetSize() == 0;
+}
+
+const char *
+StreamString::GetData () const
+{
+ return m_packet.c_str();
+}
+
+size_t
+StreamString::GetSize () const
+{
+ return m_packet.size();
+}
+
+std::string &
+StreamString::GetString()
+{
+ return m_packet;
+}
+
+const std::string &
+StreamString::GetString() const
+{
+ return m_packet;
+}
+
+void
+StreamString::FillLastLineToColumn (uint32_t column, char fill_char)
+{
+ 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)
+ {
+ last_line_begin_pos = 0;
+ }
+ else
+ {
+ ++last_line_begin_pos;
+ }
+
+ const size_t line_columns = length - last_line_begin_pos;
+ if (column > line_columns)
+ {
+ m_packet.append(column - line_columns, fill_char);
+ }
+}
+
diff --git a/source/Core/StringList.cpp b/source/Core/StringList.cpp
new file mode 100644
index 000000000000..994975116789
--- /dev/null
+++ b/source/Core/StringList.cpp
@@ -0,0 +1,290 @@
+//===-- StringList.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/StringList.h"
+
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+
+#include <string>
+
+using namespace lldb_private;
+
+StringList::StringList () :
+ m_strings ()
+{
+}
+
+StringList::StringList (const char *str) :
+ m_strings ()
+{
+ if (str)
+ m_strings.push_back (str);
+}
+
+StringList::StringList (const char **strv, int strc) :
+ m_strings ()
+{
+ for (int i = 0; i < strc; ++i)
+ {
+ if (strv[i])
+ m_strings.push_back (strv[i]);
+ }
+}
+
+StringList::~StringList ()
+{
+}
+
+void
+StringList::AppendString (const char *str)
+{
+ if (str)
+ m_strings.push_back (str);
+}
+
+void
+StringList::AppendString (const std::string &s)
+{
+ m_strings.push_back (s);
+}
+
+void
+StringList::AppendString (const char *str, size_t str_len)
+{
+ if (str)
+ m_strings.push_back (std::string (str, str_len));
+}
+
+void
+StringList::AppendList (const char **strv, int strc)
+{
+ for (int i = 0; i < strc; ++i)
+ {
+ if (strv[i])
+ m_strings.push_back (strv[i]);
+ }
+}
+
+void
+StringList::AppendList (StringList strings)
+{
+ size_t len = strings.GetSize();
+
+ for (size_t i = 0; i < len; ++i)
+ m_strings.push_back (strings.GetStringAtIndex(i));
+}
+
+bool
+StringList::ReadFileLines (FileSpec &input_file)
+{
+ return input_file.ReadFileLines (m_strings);
+}
+
+size_t
+StringList::GetSize () const
+{
+ return m_strings.size();
+}
+
+const char *
+StringList::GetStringAtIndex (size_t idx) const
+{
+ if (idx < m_strings.size())
+ return m_strings[idx].c_str();
+ return NULL;
+}
+
+void
+StringList::Join (const char *separator, Stream &strm)
+{
+ size_t size = GetSize();
+
+ if (size == 0)
+ return;
+
+ for (uint32_t i = 0; i < size; ++i)
+ {
+ if (i > 0)
+ strm.PutCString(separator);
+ strm.PutCString(GetStringAtIndex(i));
+ }
+}
+
+void
+StringList::Clear ()
+{
+ m_strings.clear();
+}
+
+void
+StringList::LongestCommonPrefix (std::string &common_prefix)
+{
+ //arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t pos = 0;
+ size_t end = m_strings.size();
+
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = m_strings[pos];
+
+ for (++pos; pos != end; ++pos)
+ {
+ size_t new_size = strlen (m_strings[pos].c_str());
+
+ // First trim common_prefix if it is longer than the current element:
+ if (common_prefix.size() > new_size)
+ common_prefix.erase (new_size);
+
+ // Then trim it at the first disparity:
+
+ for (size_t i = 0; i < common_prefix.size(); i++)
+ {
+ if (m_strings[pos][i] != common_prefix[i])
+ {
+ common_prefix.erase(i);
+ break;
+ }
+ }
+
+ // If we've emptied the common prefix, we're done.
+ if (common_prefix.empty())
+ break;
+ }
+}
+
+void
+StringList::InsertStringAtIndex (size_t idx, const char *str)
+{
+ if (str)
+ {
+ if (idx < m_strings.size())
+ m_strings.insert (m_strings.begin() + idx, str);
+ else
+ m_strings.push_back (str);
+ }
+}
+
+void
+StringList::DeleteStringAtIndex (size_t idx)
+{
+ if (idx < m_strings.size())
+ m_strings.erase (m_strings.begin() + idx);
+}
+
+size_t
+StringList::SplitIntoLines (const char *lines, size_t len)
+{
+ const size_t orig_size = m_strings.size();
+
+ if (len == 0)
+ return 0;
+
+ const char *k_newline_chars = "\r\n";
+ const char *p = lines;
+ const char *end = lines + len;
+ while (p < end)
+ {
+ size_t count = strcspn (p, k_newline_chars);
+ if (count == 0)
+ {
+ if (p[count] == '\r' || p[count] == '\n')
+ m_strings.push_back(std::string());
+ else
+ break;
+ }
+ else
+ {
+ if (p + count > end)
+ count = end - p;
+ m_strings.push_back(std::string(p, count));
+ }
+ if (p[count] == '\r' && p[count+1] == '\n')
+ count++; // Skip an extra newline char for the DOS newline
+ count++; // Skip the newline character
+ p += count;
+ }
+ return m_strings.size() - orig_size;
+}
+
+void
+StringList::RemoveBlankLines ()
+{
+ if (GetSize() == 0)
+ return;
+
+ size_t idx = 0;
+ while (idx < m_strings.size())
+ {
+ if (m_strings[idx].empty())
+ DeleteStringAtIndex(idx);
+ else
+ idx++;
+ }
+}
+
+std::string
+StringList::CopyList(const char* item_preamble,
+ const char* items_sep)
+{
+ StreamString strm;
+ for (size_t i = 0; i < GetSize(); i++)
+ {
+ if (i && items_sep && items_sep[0])
+ strm << items_sep;
+ if (item_preamble)
+ strm << item_preamble;
+ strm << GetStringAtIndex(i);
+ }
+ return std::string(strm.GetData());
+}
+
+StringList&
+StringList::operator << (const char* str)
+{
+ AppendString(str);
+ return *this;
+}
+
+StringList&
+StringList::operator << (StringList strings)
+{
+ AppendList(strings);
+ return *this;
+}
+
+size_t
+StringList::AutoComplete (const char *s, StringList &matches, size_t &exact_idx) const
+{
+ matches.Clear();
+ exact_idx = SIZE_MAX;
+ if (s && s[0])
+ {
+ const size_t s_len = strlen (s);
+ const size_t num_strings = m_strings.size();
+
+ for (size_t i=0; i<num_strings; ++i)
+ {
+ if (m_strings[i].find(s) == 0)
+ {
+ if (exact_idx == SIZE_MAX && m_strings[i].size() == s_len)
+ exact_idx = matches.GetSize();
+ matches.AppendString (m_strings[i]);
+ }
+ }
+ }
+ else
+ {
+ // No string, so it matches everything
+ matches = *this;
+ }
+ return matches.GetSize();
+}
+
diff --git a/source/Core/Timer.cpp b/source/Core/Timer.cpp
new file mode 100644
index 000000000000..b1416bdaf62e
--- /dev/null
+++ b/source/Core/Timer.cpp
@@ -0,0 +1,250 @@
+//===-- Timer.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/Timer.h"
+
+#include <map>
+#include <vector>
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Mutex.h"
+
+#include <stdio.h>
+
+using namespace lldb_private;
+
+#define TIMER_INDENT_AMOUNT 2
+static bool g_quiet = true;
+uint32_t Timer::g_depth = 0;
+uint32_t Timer::g_display_depth = 0;
+FILE * Timer::g_file = NULL;
+typedef std::vector<Timer *> TimerStack;
+typedef std::map<const char *, uint64_t> TimerCategoryMap;
+static pthread_key_t g_key;
+
+static Mutex &
+GetCategoryMutex()
+{
+ static Mutex g_category_mutex(Mutex::eMutexTypeNormal);
+ return g_category_mutex;
+}
+
+static TimerCategoryMap &
+GetCategoryMap()
+{
+ static TimerCategoryMap g_category_map;
+ return g_category_map;
+}
+
+
+static TimerStack *
+GetTimerStackForCurrentThread ()
+{
+ void *timer_stack = ::pthread_getspecific (g_key);
+ if (timer_stack == NULL)
+ {
+ ::pthread_setspecific (g_key, new TimerStack);
+ timer_stack = ::pthread_getspecific (g_key);
+ }
+ return (TimerStack *)timer_stack;
+}
+
+void
+ThreadSpecificCleanup (void *p)
+{
+ delete (TimerStack *)p;
+}
+
+void
+Timer::SetQuiet (bool value)
+{
+ g_quiet = value;
+}
+
+void
+Timer::Initialize ()
+{
+ Timer::g_file = stdout;
+ ::pthread_key_create (&g_key, ThreadSpecificCleanup);
+
+}
+
+Timer::Timer (const char *category, const char *format, ...) :
+ m_category (category),
+ m_total_start (),
+ m_timer_start (),
+ m_total_ticks (0),
+ m_timer_ticks (0)
+{
+ if (g_depth++ < g_display_depth)
+ {
+ if (g_quiet == false)
+ {
+ // Indent
+ ::fprintf (g_file, "%*s", g_depth * TIMER_INDENT_AMOUNT, "");
+ // Print formatted string
+ va_list args;
+ va_start (args, format);
+ ::vfprintf (g_file, format, args);
+ va_end (args);
+
+ // Newline
+ ::fprintf (g_file, "\n");
+ }
+ TimeValue start_time(TimeValue::Now());
+ m_total_start = start_time;
+ m_timer_start = start_time;
+ TimerStack *stack = GetTimerStackForCurrentThread ();
+ if (stack)
+ {
+ if (stack->empty() == false)
+ stack->back()->ChildStarted (start_time);
+ stack->push_back(this);
+ }
+ }
+}
+
+
+Timer::~Timer()
+{
+ if (m_total_start.IsValid())
+ {
+ TimeValue stop_time = TimeValue::Now();
+ if (m_total_start.IsValid())
+ {
+ m_total_ticks += (stop_time - m_total_start);
+ m_total_start.Clear();
+ }
+ if (m_timer_start.IsValid())
+ {
+ m_timer_ticks += (stop_time - m_timer_start);
+ m_timer_start.Clear();
+ }
+
+ TimerStack *stack = GetTimerStackForCurrentThread ();
+ if (stack)
+ {
+ assert (stack->back() == this);
+ stack->pop_back();
+ if (stack->empty() == false)
+ stack->back()->ChildStopped(stop_time);
+ }
+
+ const uint64_t total_nsec_uint = GetTotalElapsedNanoSeconds();
+ const uint64_t timer_nsec_uint = GetTimerElapsedNanoSeconds();
+ const double total_nsec = total_nsec_uint;
+ const double timer_nsec = timer_nsec_uint;
+
+ if (g_quiet == false)
+ {
+
+ ::fprintf (g_file,
+ "%*s%.9f sec (%.9f sec)\n",
+ (g_depth - 1) *TIMER_INDENT_AMOUNT, "",
+ total_nsec / 1000000000.0,
+ timer_nsec / 1000000000.0);
+ }
+
+ // Keep total results for each category so we can dump results.
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ category_map[m_category] += timer_nsec_uint;
+ }
+ if (g_depth > 0)
+ --g_depth;
+}
+
+uint64_t
+Timer::GetTotalElapsedNanoSeconds()
+{
+ uint64_t total_ticks = m_total_ticks;
+
+ // If we are currently running, we need to add the current
+ // elapsed time of the running timer...
+ if (m_total_start.IsValid())
+ total_ticks += (TimeValue::Now() - m_total_start);
+
+ return total_ticks;
+}
+
+uint64_t
+Timer::GetTimerElapsedNanoSeconds()
+{
+ uint64_t timer_ticks = m_timer_ticks;
+
+ // If we are currently running, we need to add the current
+ // elapsed time of the running timer...
+ if (m_timer_start.IsValid())
+ timer_ticks += (TimeValue::Now() - m_timer_start);
+
+ return timer_ticks;
+}
+
+void
+Timer::ChildStarted (const TimeValue& start_time)
+{
+ if (m_timer_start.IsValid())
+ {
+ m_timer_ticks += (start_time - m_timer_start);
+ m_timer_start.Clear();
+ }
+}
+
+void
+Timer::ChildStopped (const TimeValue& stop_time)
+{
+ if (!m_timer_start.IsValid())
+ m_timer_start = stop_time;
+}
+
+void
+Timer::SetDisplayDepth (uint32_t depth)
+{
+ g_display_depth = depth;
+}
+
+
+/* binary function predicate:
+ * - returns whether a person is less than another person
+ */
+static bool
+CategoryMapIteratorSortCriterion (const TimerCategoryMap::const_iterator& lhs, const TimerCategoryMap::const_iterator& rhs)
+{
+ return lhs->second > rhs->second;
+}
+
+
+void
+Timer::ResetCategoryTimes ()
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ category_map.clear();
+}
+
+void
+Timer::DumpCategoryTimes (Stream *s)
+{
+ Mutex::Locker locker (GetCategoryMutex());
+ TimerCategoryMap &category_map = GetCategoryMap();
+ std::vector<TimerCategoryMap::const_iterator> sorted_iterators;
+ TimerCategoryMap::const_iterator pos, end = category_map.end();
+ for (pos = category_map.begin(); pos != end; ++pos)
+ {
+ sorted_iterators.push_back (pos);
+ }
+ std::sort (sorted_iterators.begin(), sorted_iterators.end(), CategoryMapIteratorSortCriterion);
+
+ const size_t count = sorted_iterators.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const double timer_nsec = sorted_iterators[i]->second;
+ s->Printf("%.9f sec for %s\n", timer_nsec / 1000000000.0, sorted_iterators[i]->first);
+ }
+}
diff --git a/source/Core/UUID.cpp b/source/Core/UUID.cpp
new file mode 100644
index 000000000000..c1b3eb13d656
--- /dev/null
+++ b/source/Core/UUID.cpp
@@ -0,0 +1,279 @@
+//===-- UUID.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/UUID.h"
+// C Includes
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+namespace lldb_private {
+
+UUID::UUID() : m_num_uuid_bytes(16)
+{
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+}
+
+UUID::UUID(const UUID& rhs)
+{
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+}
+
+UUID::UUID (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ SetBytes (uuid_bytes, num_uuid_bytes);
+}
+
+const UUID&
+UUID::operator=(const UUID& rhs)
+{
+ if (this != &rhs)
+ {
+ m_num_uuid_bytes = rhs.m_num_uuid_bytes;
+ ::memcpy (m_uuid, rhs.m_uuid, sizeof (m_uuid));
+ }
+ return *this;
+}
+
+UUID::~UUID()
+{
+}
+
+void
+UUID::Clear()
+{
+ m_num_uuid_bytes = 16;
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+}
+
+const void *
+UUID::GetBytes() const
+{
+ return m_uuid;
+}
+
+std::string
+UUID::GetAsString (const char *separator) const
+{
+ std::string result;
+ char buf[256];
+ if (!separator)
+ separator = "-";
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ if (sizeof (buf) > (size_t)snprintf (buf,
+ sizeof (buf),
+ "%2.2X%2.2X%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
+ u[0],u[1],u[2],u[3],separator,
+ u[4],u[5],separator,
+ u[6],u[7],separator,
+ u[8],u[9],separator,
+ u[10],u[11],u[12],u[13],u[14],u[15]))
+ {
+ result.append (buf);
+ if (m_num_uuid_bytes == 20)
+ {
+ if (sizeof (buf) > (size_t)snprintf (buf, sizeof (buf), "%s%2.2X%2.2X%2.2X%2.2X", separator,u[16],u[17],u[18],u[19]))
+ result.append (buf);
+ }
+ }
+ return result;
+}
+
+void
+UUID::Dump (Stream *s) const
+{
+ const uint8_t *u = (const uint8_t *)GetBytes();
+ s->Printf ("%2.2X%2.2X%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X-%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
+ u[0],u[1],u[2],u[3],u[4],u[5],u[6],u[7],u[8],u[9],u[10],u[11],u[12],u[13],u[14],u[15]);
+ if (m_num_uuid_bytes == 20)
+ {
+ s->Printf ("-%2.2X%2.2X%2.2X%2.2X", u[16],u[17],u[18],u[19]);
+ }
+}
+
+bool
+UUID::SetBytes (const void *uuid_bytes, uint32_t num_uuid_bytes)
+{
+ if (uuid_bytes)
+ {
+ switch (num_uuid_bytes)
+ {
+ case 20:
+ m_num_uuid_bytes = 20;
+ break;
+ case 16:
+ m_num_uuid_bytes = 16;
+ m_uuid[16] = m_uuid[17] = m_uuid[18] = m_uuid[19] = 0;
+ break;
+ default:
+ // Unsupported UUID byte size
+ m_num_uuid_bytes = 0;
+ break;
+ }
+
+ if (m_num_uuid_bytes > 0)
+ {
+ ::memcpy (m_uuid, uuid_bytes, m_num_uuid_bytes);
+ return true;
+ }
+ }
+ ::memset (m_uuid, 0, sizeof(m_uuid));
+ return false;
+}
+
+size_t
+UUID::GetByteSize()
+{
+ return m_num_uuid_bytes;
+}
+
+bool
+UUID::IsValid () const
+{
+ return m_uuid[0] ||
+ m_uuid[1] ||
+ m_uuid[2] ||
+ m_uuid[3] ||
+ m_uuid[4] ||
+ m_uuid[5] ||
+ m_uuid[6] ||
+ m_uuid[7] ||
+ m_uuid[8] ||
+ m_uuid[9] ||
+ m_uuid[10] ||
+ m_uuid[11] ||
+ m_uuid[12] ||
+ m_uuid[13] ||
+ m_uuid[14] ||
+ m_uuid[15] ||
+ m_uuid[16] ||
+ m_uuid[17] ||
+ m_uuid[18] ||
+ m_uuid[19];
+}
+
+static inline int
+xdigit_to_int (char ch)
+{
+ ch = tolower(ch);
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ return ch - '0';
+}
+
+size_t
+UUID::DecodeUUIDBytesFromCString (const char *p, ValueType &uuid_bytes, const char **end, uint32_t num_uuid_bytes)
+{
+ size_t uuid_byte_idx = 0;
+ if (p)
+ {
+ while (*p)
+ {
+ if (isxdigit(p[0]) && isxdigit(p[1]))
+ {
+ int hi_nibble = xdigit_to_int(p[0]);
+ int lo_nibble = xdigit_to_int(p[1]);
+ // Translate the two hex nibble characters into a byte
+ uuid_bytes[uuid_byte_idx] = (hi_nibble << 4) + lo_nibble;
+
+ // Skip both hex digits
+ p += 2;
+
+ // Increment the byte that we are decoding within the UUID value
+ // and break out if we are done
+ if (++uuid_byte_idx == num_uuid_bytes)
+ break;
+ }
+ else if (*p == '-')
+ {
+ // Skip dashes
+ p++;
+ }
+ else
+ {
+ // UUID values can only consist of hex characters and '-' chars
+ break;
+ }
+ }
+ }
+ if (end)
+ *end = p;
+ // Clear trailing bytes to 0.
+ for (uint32_t i = uuid_byte_idx; i < sizeof(ValueType); i++)
+ uuid_bytes[i] = 0;
+ return uuid_byte_idx;
+}
+size_t
+UUID::SetFromCString (const char *cstr, uint32_t num_uuid_bytes)
+{
+ if (cstr == NULL)
+ return 0;
+
+ const char *p = cstr;
+
+ // Skip leading whitespace characters
+ while (isspace(*p))
+ ++p;
+
+ const size_t uuid_byte_idx = UUID::DecodeUUIDBytesFromCString (p, m_uuid, &p, num_uuid_bytes);
+
+ // If we successfully decoded a UUID, return the amount of characters that
+ // were consumed
+ if (uuid_byte_idx == num_uuid_bytes)
+ return p - cstr;
+
+ // Else return zero to indicate we were not able to parse a UUID value
+ return 0;
+}
+
+}
+
+bool
+lldb_private::operator == (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) == 0;
+}
+
+bool
+lldb_private::operator != (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) != 0;
+}
+
+bool
+lldb_private::operator < (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) < 0;
+}
+
+bool
+lldb_private::operator <= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) <= 0;
+}
+
+bool
+lldb_private::operator > (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) > 0;
+}
+
+bool
+lldb_private::operator >= (const lldb_private::UUID &lhs, const lldb_private::UUID &rhs)
+{
+ return ::memcmp (lhs.GetBytes(), rhs.GetBytes(), sizeof (lldb_private::UUID::ValueType)) >= 0;
+}
diff --git a/source/Core/UserID.cpp b/source/Core/UserID.cpp
new file mode 100644
index 000000000000..f3d6e5b22185
--- /dev/null
+++ b/source/Core/UserID.cpp
@@ -0,0 +1,23 @@
+//===-- UserID.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/UserID.h"
+#include "lldb/Core/Stream.h"
+
+#include <inttypes.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+Stream&
+lldb_private::operator << (Stream& strm, const UserID& uid)
+{
+ strm.Printf("{0x%8.8" PRIx64 "}", uid.GetID());
+ return strm;
+}
diff --git a/source/Core/UserSettingsController.cpp b/source/Core/UserSettingsController.cpp
new file mode 100644
index 000000000000..63a5dd9ed51f
--- /dev/null
+++ b/source/Core/UserSettingsController.cpp
@@ -0,0 +1,111 @@
+//====-- UserSettingsController.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 <string.h>
+#include <algorithm>
+
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+lldb::OptionValueSP
+Properties::GetPropertyValue (const ExecutionContext *exe_ctx,
+ const char *path,
+ bool will_modify,
+ Error &error) const
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->GetSubValue(exe_ctx, path, will_modify, error);
+ return lldb::OptionValueSP();
+}
+
+Error
+Properties::SetPropertyValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *path,
+ const char *value)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->SetSubValue(exe_ctx, op, path, value);
+ Error error;
+ error.SetErrorString ("no properties");
+ return error;
+}
+
+void
+Properties::DumpAllPropertyValues (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->DumpValue (exe_ctx, strm, dump_mask);
+}
+
+void
+Properties::DumpAllDescriptions (CommandInterpreter &interpreter,
+ Stream &strm) const
+{
+ strm.PutCString("Top level variables:\n\n");
+
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->DumpAllDescriptions (interpreter, strm);
+}
+
+
+
+Error
+Properties::DumpPropertyValue (const ExecutionContext *exe_ctx, Stream &strm, const char *property_path, uint32_t dump_mask)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ {
+ return properties_sp->DumpPropertyValue (exe_ctx,
+ strm,
+ property_path,
+ dump_mask);
+ }
+ Error error;
+ error.SetErrorString("empty property list");
+ return error;
+}
+
+size_t
+Properties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ {
+ properties_sp->Apropos (keyword, matching_properties);
+ }
+ return matching_properties.size();
+}
+
+
+lldb::OptionValuePropertiesSP
+Properties::GetSubProperty (const ExecutionContext *exe_ctx,
+ const ConstString &name)
+{
+ OptionValuePropertiesSP properties_sp (GetValueProperties ());
+ if (properties_sp)
+ return properties_sp->GetSubProperty (exe_ctx, name);
+ return lldb::OptionValuePropertiesSP();
+}
+
diff --git a/source/Core/VMRange.cpp b/source/Core/VMRange.cpp
new file mode 100644
index 000000000000..902489e1ff38
--- /dev/null
+++ b/source/Core/VMRange.cpp
@@ -0,0 +1,112 @@
+//===-- VMRange.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/Core/Stream.h"
+#include "lldb/Core/VMRange.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+VMRange::ContainsValue(const VMRange::collection& coll, lldb::addr_t value)
+{
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if( coll.begin(), end, in_range_predicate );
+ if (pos != end)
+ return true;
+ return false;
+}
+
+bool
+VMRange::ContainsRange(const VMRange::collection& coll, const VMRange& range)
+{
+ RangeInRangeUnaryPredicate in_range_predicate(range);
+ VMRange::const_iterator pos;
+ VMRange::const_iterator end = coll.end();
+ pos = std::find_if( coll.begin(), end, in_range_predicate );
+ if (pos != end)
+ return true;
+ return false;
+}
+
+size_t
+VMRange::FindRangeIndexThatContainsValue (const VMRange::collection& coll, lldb::addr_t value)
+{
+ ValueInRangeUnaryPredicate in_range_predicate(value);
+ VMRange::const_iterator begin = coll.begin();
+ VMRange::const_iterator end = coll.end();
+ VMRange::const_iterator pos = std::find_if (begin, end, in_range_predicate);
+ if (pos != end)
+ return std::distance (begin, pos);
+ return UINT32_MAX;
+}
+
+void
+VMRange::Dump(Stream *s, lldb::addr_t offset, uint32_t addr_width) const
+{
+ s->AddressRange(offset + GetBaseAddress(), offset + GetEndAddress(), addr_width);
+}
+
+bool
+lldb_private::operator== (const VMRange& lhs, const VMRange& rhs)
+{
+ return lhs.GetBaseAddress() == rhs.GetBaseAddress() && lhs.GetEndAddress() == rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator!= (const VMRange& lhs, const VMRange& rhs)
+{
+ return lhs.GetBaseAddress() != rhs.GetBaseAddress() || lhs.GetEndAddress() != rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator< (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() < rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator<= (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() <= rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator> (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() > rhs.GetEndAddress();
+}
+
+bool
+lldb_private::operator>= (const VMRange& lhs, const VMRange& rhs)
+{
+ if (lhs.GetBaseAddress() > rhs.GetBaseAddress())
+ return true;
+ else if (lhs.GetBaseAddress() < rhs.GetBaseAddress())
+ return false;
+ return lhs.GetEndAddress() >= rhs.GetEndAddress();
+}
+
diff --git a/source/Core/Value.cpp b/source/Core/Value.cpp
new file mode 100644
index 000000000000..3fe75d3d4ce5
--- /dev/null
+++ b/source/Core/Value.cpp
@@ -0,0 +1,761 @@
+//===-- Value.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/Value.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Value::Value() :
+ m_value (),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeScalar),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+}
+
+Value::Value(const Scalar& scalar) :
+ m_value (scalar),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeScalar),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+}
+
+
+Value::Value(const uint8_t *bytes, int len) :
+ m_value (),
+ m_vector (),
+ m_clang_type (),
+ m_context (NULL),
+ m_value_type (eValueTypeHostAddress),
+ m_context_type (eContextTypeInvalid),
+ m_data_buffer ()
+{
+ m_data_buffer.CopyData(bytes, len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+Value::Value(const Value &v) :
+ m_value (v.m_value),
+ m_vector (v.m_vector),
+ m_clang_type (v.m_clang_type),
+ m_context (v.m_context),
+ m_value_type (v.m_value_type),
+ m_context_type (v.m_context_type),
+ m_data_buffer ()
+{
+ if ((uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)v.m_data_buffer.GetBytes())
+ {
+ m_data_buffer.CopyData(v.m_data_buffer.GetBytes(),
+ v.m_data_buffer.GetByteSize());
+
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+ }
+}
+
+Value &
+Value::operator=(const Value &rhs)
+{
+ if (this != &rhs)
+ {
+ m_value = rhs.m_value;
+ m_vector = rhs.m_vector;
+ m_clang_type = rhs.m_clang_type;
+ m_context = rhs.m_context;
+ m_value_type = rhs.m_value_type;
+ m_context_type = rhs.m_context_type;
+ if ((uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS) == (uintptr_t)rhs.m_data_buffer.GetBytes())
+ {
+ m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(),
+ rhs.m_data_buffer.GetByteSize());
+
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+ }
+ }
+ return *this;
+}
+
+void
+Value::Dump (Stream* strm)
+{
+ m_value.GetValue (strm, true);
+ strm->Printf(", value_type = %s, context = %p, context_type = %s",
+ Value::GetValueTypeAsCString(m_value_type),
+ m_context,
+ Value::GetContextTypeAsCString(m_context_type));
+}
+
+Value::ValueType
+Value::GetValueType() const
+{
+ return m_value_type;
+}
+
+AddressType
+Value::GetValueAddressType () const
+{
+ switch (m_value_type)
+ {
+ default:
+ case eValueTypeScalar:
+ break;
+ case eValueTypeLoadAddress: return eAddressTypeLoad;
+ case eValueTypeFileAddress: return eAddressTypeFile;
+ case eValueTypeHostAddress: return eAddressTypeHost;
+ }
+ return eAddressTypeInvalid;
+}
+
+RegisterInfo *
+Value::GetRegisterInfo() const
+{
+ if (m_context_type == eContextTypeRegisterInfo)
+ return static_cast<RegisterInfo *> (m_context);
+ return NULL;
+}
+
+Type *
+Value::GetType()
+{
+ if (m_context_type == eContextTypeLLDBType)
+ return static_cast<Type *> (m_context);
+ return NULL;
+}
+
+void
+Value::ResizeData(size_t len)
+{
+ m_value_type = eValueTypeHostAddress;
+ m_data_buffer.SetByteSize(len);
+ m_value = (uintptr_t)m_data_buffer.GetBytes();
+}
+
+bool
+Value::ValueOf(ExecutionContext *exe_ctx)
+{
+ switch (m_context_type)
+ {
+ case eContextTypeInvalid:
+ case eContextTypeRegisterInfo: // RegisterInfo *
+ case eContextTypeLLDBType: // Type *
+ break;
+
+ case eContextTypeVariable: // Variable *
+ ResolveValue(exe_ctx);
+ return true;
+ }
+ return false;
+}
+
+uint64_t
+Value::GetValueByteSize (Error *error_ptr)
+{
+ uint64_t byte_size = 0;
+
+ switch (m_context_type)
+ {
+ case eContextTypeRegisterInfo: // RegisterInfo *
+ if (GetRegisterInfo())
+ byte_size = GetRegisterInfo()->byte_size;
+ break;
+
+ case eContextTypeInvalid:
+ case eContextTypeLLDBType: // Type *
+ case eContextTypeVariable: // Variable *
+ {
+ const ClangASTType &ast_type = GetClangType();
+ if (ast_type.IsValid())
+ byte_size = ast_type.GetByteSize();
+ }
+ break;
+ }
+
+ if (error_ptr)
+ {
+ if (byte_size == 0)
+ {
+ if (error_ptr->Success())
+ error_ptr->SetErrorString("Unable to determine byte size.");
+ }
+ else
+ {
+ error_ptr->Clear();
+ }
+ }
+ return byte_size;
+}
+
+const ClangASTType &
+Value::GetClangType ()
+{
+ if (!m_clang_type.IsValid())
+ {
+ switch (m_context_type)
+ {
+ case eContextTypeInvalid:
+ break;
+
+ case eContextTypeRegisterInfo:
+ break; // TODO: Eventually convert into a clang type?
+
+ case eContextTypeLLDBType:
+ {
+ Type *lldb_type = GetType();
+ if (lldb_type)
+ m_clang_type = lldb_type->GetClangForwardType();
+ }
+ break;
+
+ case eContextTypeVariable:
+ {
+ Variable *variable = GetVariable();
+ if (variable)
+ {
+ Type *variable_type = variable->GetType();
+ if (variable_type)
+ m_clang_type = variable_type->GetClangForwardType();
+ }
+ }
+ break;
+ }
+ }
+
+ return m_clang_type;
+}
+
+void
+Value::SetClangType (const ClangASTType &clang_type)
+{
+ m_clang_type = clang_type;
+}
+
+lldb::Format
+Value::GetValueDefaultFormat ()
+{
+ switch (m_context_type)
+ {
+ case eContextTypeRegisterInfo:
+ if (GetRegisterInfo())
+ return GetRegisterInfo()->format;
+ break;
+
+ case eContextTypeInvalid:
+ case eContextTypeLLDBType:
+ case eContextTypeVariable:
+ {
+ const ClangASTType &ast_type = GetClangType();
+ if (ast_type.IsValid())
+ return ast_type.GetFormat();
+ }
+ break;
+
+ }
+
+ // Return a good default in case we can't figure anything out
+ return eFormatHex;
+}
+
+bool
+Value::GetData (DataExtractor &data)
+{
+ switch (m_value_type)
+ {
+ default:
+ break;
+
+ case eValueTypeScalar:
+ if (m_value.GetData (data))
+ return true;
+ break;
+
+ case eValueTypeLoadAddress:
+ case eValueTypeFileAddress:
+ case eValueTypeHostAddress:
+ if (m_data_buffer.GetByteSize())
+ {
+ data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(), data.GetByteOrder());
+ return true;
+ }
+ break;
+ }
+
+ return false;
+
+}
+
+Error
+Value::GetValueAsData (ExecutionContext *exe_ctx,
+ DataExtractor &data,
+ uint32_t data_offset,
+ Module *module)
+{
+ data.Clear();
+
+ Error error;
+ lldb::addr_t address = LLDB_INVALID_ADDRESS;
+ AddressType address_type = eAddressTypeFile;
+ Address file_so_addr;
+ const ClangASTType &ast_type = GetClangType();
+ switch (m_value_type)
+ {
+ case eValueTypeVector:
+ if (ast_type.IsValid())
+ data.SetAddressByteSize (ast_type.GetPointerByteSize());
+ else
+ data.SetAddressByteSize(sizeof(void *));
+ data.SetData(m_vector.bytes, m_vector.length, m_vector.byte_order);
+ break;
+
+ case eValueTypeScalar:
+ data.SetByteOrder (lldb::endian::InlHostByteOrder());
+ if (ast_type.IsValid())
+ data.SetAddressByteSize (ast_type.GetPointerByteSize());
+ else
+ data.SetAddressByteSize(sizeof(void *));
+ if (m_value.GetData (data))
+ return error; // Success;
+ error.SetErrorStringWithFormat("extracting data from value failed");
+ break;
+
+ case eValueTypeLoadAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("can't read load address (no execution context)");
+ }
+ else
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process == NULL || !process->IsAlive())
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ // Allow expressions to run and evaluate things when the target
+ // has memory sections loaded. This allows you to use "target modules load"
+ // to load your executable and any shared libraries, then execute
+ // commands where you can look at types in data sections.
+ const SectionLoadList &target_sections = target->GetSectionLoadList();
+ if (!target_sections.IsEmpty())
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if (target_sections.ResolveLoadAddress(address, file_so_addr))
+ {
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+ else
+ address = LLDB_INVALID_ADDRESS;
+ }
+// else
+// {
+// ModuleSP exe_module_sp (target->GetExecutableModule());
+// if (exe_module_sp)
+// {
+// address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+// if (address != LLDB_INVALID_ADDRESS)
+// {
+// if (exe_module_sp->ResolveFileAddress(address, file_so_addr))
+// {
+// data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+// data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+// address_type = eAddressTypeFile;
+// }
+// else
+// {
+// address = LLDB_INVALID_ADDRESS;
+// }
+// }
+// }
+// }
+ }
+ else
+ {
+ error.SetErrorString ("can't read load address (invalid process)");
+ }
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(process->GetTarget().GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(process->GetTarget().GetArchitecture().GetAddressByteSize());
+ }
+ }
+ break;
+
+ case eValueTypeFileAddress:
+ if (exe_ctx == NULL)
+ {
+ error.SetErrorString ("can't read file address (no execution context)");
+ }
+ else if (exe_ctx->GetTargetPtr() == NULL)
+ {
+ error.SetErrorString ("can't read file address (invalid target)");
+ }
+ else
+ {
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString ("invalid file address");
+ }
+ else
+ {
+ if (module == NULL)
+ {
+ // The only thing we can currently lock down to a module so that
+ // we can resolve a file address, is a variable.
+ Variable *variable = GetVariable();
+ if (variable)
+ {
+ SymbolContext var_sc;
+ variable->CalculateSymbolContext(&var_sc);
+ module = var_sc.module_sp.get();
+ }
+ }
+
+ if (module)
+ {
+ bool resolved = false;
+ ObjectFile *objfile = module->GetObjectFile();
+ if (objfile)
+ {
+ Address so_addr(address, objfile->GetSectionList());
+ addr_t load_address = so_addr.GetLoadAddress (exe_ctx->GetTargetPtr());
+ bool process_launched_and_stopped = exe_ctx->GetProcessPtr()
+ ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), true /* must_exist */)
+ : false;
+ // Don't use the load address if the process has exited.
+ if (load_address != LLDB_INVALID_ADDRESS && process_launched_and_stopped)
+ {
+ resolved = true;
+ address = load_address;
+ address_type = eAddressTypeLoad;
+ data.SetByteOrder(exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(exe_ctx->GetTargetRef().GetArchitecture().GetAddressByteSize());
+ }
+ else
+ {
+ if (so_addr.IsSectionOffset())
+ {
+ resolved = true;
+ file_so_addr = so_addr;
+ data.SetByteOrder(objfile->GetByteOrder());
+ data.SetAddressByteSize(objfile->GetAddressByteSize());
+ }
+ }
+ }
+ if (!resolved)
+ {
+ Variable *variable = GetVariable();
+
+ if (module)
+ {
+ if (variable)
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s' in %s",
+ address,
+ variable->GetName().AsCString(""),
+ module->GetFileSpec().GetPath().c_str());
+ else
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " in %s",
+ address,
+ module->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ if (variable)
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64 " for variable '%s'",
+ address,
+ variable->GetName().AsCString(""));
+ else
+ error.SetErrorStringWithFormat ("unable to resolve the module for file address 0x%" PRIx64, address);
+ }
+ }
+ }
+ else
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ error.SetErrorString ("can't read memory from file address without more context");
+ }
+ }
+ }
+ break;
+
+ case eValueTypeHostAddress:
+ address = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ address_type = eAddressTypeHost;
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ break;
+ }
+ }
+ // fallback to host settings
+ data.SetByteOrder(lldb::endian::InlHostByteOrder());
+ data.SetAddressByteSize(sizeof(void *));
+ break;
+ }
+
+ // Bail if we encountered any errors
+ if (error.Fail())
+ return error;
+
+ if (address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorStringWithFormat ("invalid %s address", address_type == eAddressTypeHost ? "host" : "load");
+ return error;
+ }
+
+ // If we got here, we need to read the value from memory
+ size_t byte_size = GetValueByteSize (&error);
+
+ // Bail if we encountered any errors getting the byte size
+ if (error.Fail())
+ return error;
+
+ // Make sure we have enough room within "data", and if we don't make
+ // something large enough that does
+ if (!data.ValidOffsetForDataOfSize (data_offset, byte_size))
+ {
+ DataBufferSP data_sp(new DataBufferHeap (data_offset + byte_size, '\0'));
+ data.SetData(data_sp);
+ }
+
+ uint8_t* dst = const_cast<uint8_t*>(data.PeekData (data_offset, byte_size));
+ if (dst != NULL)
+ {
+ if (address_type == eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy (dst, (uint8_t*)NULL + address, byte_size);
+ }
+ else if ((address_type == eAddressTypeLoad) || (address_type == eAddressTypeFile))
+ {
+ if (file_so_addr.IsValid())
+ {
+ // We have a file address that we were able to translate into a
+ // section offset address so we might be able to read this from
+ // the object files if we don't have a live process. Lets always
+ // try and read from the process if we have one though since we
+ // want to read the actual value by setting "prefer_file_cache"
+ // to false.
+ const bool prefer_file_cache = false;
+ if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, prefer_file_cache, dst, byte_size, error) != byte_size)
+ {
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", (uint64_t)address);
+ }
+ }
+ else
+ {
+ // The execution context might have a NULL process, but it
+ // might have a valid process in the exe_ctx->target, so use
+ // the ExecutionContext::GetProcess accessor to ensure we
+ // get the process if there is one.
+ Process *process = exe_ctx->GetProcessPtr();
+
+ if (process)
+ {
+ const size_t bytes_read = process->ReadMemory(address, dst, byte_size, error);
+ if (bytes_read != byte_size)
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
+ (uint64_t)address,
+ (uint32_t)bytes_read,
+ (uint32_t)byte_size);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed (invalid process)", (uint64_t)address);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unsupported AddressType value (%i)", address_type);
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("out of memory");
+ }
+
+ return error;
+}
+
+Scalar &
+Value::ResolveValue(ExecutionContext *exe_ctx)
+{
+ const ClangASTType &clang_type = GetClangType();
+ if (clang_type.IsValid())
+ {
+ switch (m_value_type)
+ {
+ case eValueTypeScalar: // raw scalar value
+ break;
+
+ default:
+ case eValueTypeFileAddress:
+ case eValueTypeLoadAddress: // load address value
+ case eValueTypeHostAddress: // host address value (for memory in the process that is using liblldb)
+ {
+ DataExtractor data;
+ lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS);
+ Error error (GetValueAsData (exe_ctx, data, 0, NULL));
+ if (error.Success())
+ {
+ Scalar scalar;
+ if (clang_type.GetValueAsScalar (data, 0, data.GetByteSize(), scalar))
+ {
+ m_value = scalar;
+ m_value_type = eValueTypeScalar;
+ }
+ else
+ {
+ if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
+ {
+ m_value.Clear();
+ m_value_type = eValueTypeScalar;
+ }
+ }
+ }
+ else
+ {
+ if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes())
+ {
+ m_value.Clear();
+ m_value_type = eValueTypeScalar;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return m_value;
+}
+
+Variable *
+Value::GetVariable()
+{
+ if (m_context_type == eContextTypeVariable)
+ return static_cast<Variable *> (m_context);
+ return NULL;
+}
+
+void
+Value::Clear()
+{
+ m_value.Clear();
+ m_vector.Clear();
+ m_clang_type.Clear();
+ m_value_type = eValueTypeScalar;
+ m_context = NULL;
+ m_context_type = eContextTypeInvalid;
+ m_data_buffer.Clear();
+}
+
+
+const char *
+Value::GetValueTypeAsCString (ValueType value_type)
+{
+ switch (value_type)
+ {
+ case eValueTypeScalar: return "scalar";
+ case eValueTypeVector: return "vector";
+ case eValueTypeFileAddress: return "file address";
+ case eValueTypeLoadAddress: return "load address";
+ case eValueTypeHostAddress: return "host address";
+ };
+ return "???";
+}
+
+const char *
+Value::GetContextTypeAsCString (ContextType context_type)
+{
+ switch (context_type)
+ {
+ case eContextTypeInvalid: return "invalid";
+ case eContextTypeRegisterInfo: return "RegisterInfo *";
+ case eContextTypeLLDBType: return "Type *";
+ case eContextTypeVariable: return "Variable *";
+ };
+ return "???";
+}
+
+ValueList::ValueList (const ValueList &rhs)
+{
+ m_values = rhs.m_values;
+}
+
+const ValueList &
+ValueList::operator= (const ValueList &rhs)
+{
+ m_values = rhs.m_values;
+ return *this;
+}
+
+void
+ValueList::PushValue (const Value &value)
+{
+ m_values.push_back (value);
+}
+
+size_t
+ValueList::GetSize()
+{
+ return m_values.size();
+}
+
+Value *
+ValueList::GetValueAtIndex (size_t idx)
+{
+ if (idx < GetSize())
+ {
+ return &(m_values[idx]);
+ }
+ else
+ return NULL;
+}
+
+void
+ValueList::Clear ()
+{
+ m_values.clear();
+}
+
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
new file mode 100644
index 000000000000..a30cc1306c6b
--- /dev/null
+++ b/source/Core/ValueObject.cpp
@@ -0,0 +1,4199 @@
+//===-- ValueObject.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/ValueObject.h"
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/Support/raw_ostream.h"
+#include "clang/AST/Type.h"
+
+// 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/Core/ValueObjectCast.h"
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectDynamicValue.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+#include "lldb/Host/Endian.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_utility;
+
+static user_id_t g_value_obj_uid = 0;
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject (ValueObject &parent) :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_parent (&parent),
+ m_root (NULL),
+ m_update_point (parent.GetUpdatePoint ()),
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_value_str (),
+ m_old_value_str (),
+ m_location_str (),
+ m_summary_str (),
+ m_object_desc_str (),
+ m_manager(parent.GetManager()),
+ m_children (),
+ m_synthetic_children (),
+ m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
+ m_deref_valobj(NULL),
+ m_format (eFormatDefault),
+ m_last_format (eFormatDefault),
+ m_last_format_mgr_revision(0),
+ m_type_summary_sp(),
+ m_type_format_sp(),
+ m_synthetic_children_sp(),
+ m_user_id_of_forced_summary(),
+ m_address_type_of_ptr_or_ref_children(eAddressTypeInvalid),
+ m_value_is_valid (false),
+ m_value_did_change (false),
+ m_children_count_valid (false),
+ m_old_value_valid (false),
+ m_is_deref_of_parent (false),
+ m_is_array_item_for_pointer(false),
+ 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_manager->ManageObject(this);
+}
+
+//----------------------------------------------------------------------
+// ValueObject constructor
+//----------------------------------------------------------------------
+ValueObject::ValueObject (ExecutionContextScope *exe_scope,
+ AddressType child_ptr_or_ref_addr_type) :
+ UserID (++g_value_obj_uid), // Unique identifier for every value object
+ m_parent (NULL),
+ m_root (NULL),
+ m_update_point (exe_scope),
+ m_name (),
+ m_data (),
+ m_value (),
+ m_error (),
+ m_value_str (),
+ m_old_value_str (),
+ m_location_str (),
+ m_summary_str (),
+ m_object_desc_str (),
+ m_manager(),
+ m_children (),
+ m_synthetic_children (),
+ m_dynamic_value (NULL),
+ m_synthetic_value(NULL),
+ m_deref_valobj(NULL),
+ m_format (eFormatDefault),
+ m_last_format (eFormatDefault),
+ m_last_format_mgr_revision(0),
+ m_type_summary_sp(),
+ m_type_format_sp(),
+ m_synthetic_children_sp(),
+ m_user_id_of_forced_summary(),
+ m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type),
+ m_value_is_valid (false),
+ m_value_did_change (false),
+ m_children_count_valid (false),
+ m_old_value_valid (false),
+ m_is_deref_of_parent (false),
+ m_is_array_item_for_pointer(false),
+ 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_manager = new ValueObjectManager();
+ m_manager->ManageObject (this);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ValueObject::~ValueObject ()
+{
+}
+
+bool
+ValueObject::UpdateValueIfNeeded (bool update_format)
+{
+
+ bool did_change_formats = false;
+
+ if (update_format)
+ did_change_formats = UpdateFormatsIfNeeded();
+
+ // If this is a constant value, then our success is predicated on whether
+ // we have an error or not
+ if (GetIsConstant())
+ {
+ // if you were asked to update your formatters, but did not get a chance to do it
+ // clear your own values (this serves the purpose of faking a stop-id for frozen
+ // objects (which are regarded as constant, but could have changes behind their backs
+ // because of the frozen-pointer depth limit)
+ // TODO: decouple summary from value and then remove this code and only force-clear the summary
+ if (update_format && !did_change_formats)
+ ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
+ return m_error.Success();
+ }
+
+ bool first_update = m_update_point.IsFirstEvaluation();
+
+ if (m_update_point.NeedsUpdating())
+ {
+ m_update_point.SetUpdated();
+
+ // Save the old value using swap to avoid a string copy which
+ // also will clear our m_value_str
+ if (m_value_str.empty())
+ {
+ m_old_value_valid = false;
+ }
+ else
+ {
+ m_old_value_valid = true;
+ m_old_value_str.swap (m_value_str);
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+ }
+
+ ClearUserVisibleData();
+
+ if (IsInScope())
+ {
+ const bool value_was_valid = GetValueIsValid();
+ SetValueDidChange (false);
+
+ m_error.Clear();
+
+ // Call the pure virtual function to update the value
+ bool success = UpdateValue ();
+
+ SetValueIsValid (success);
+
+ if (first_update)
+ SetValueDidChange (false);
+ else if (!m_value_did_change && success == false)
+ {
+ // The value wasn't gotten successfully, so we mark this
+ // as changed if the value used to be valid and now isn't
+ SetValueDidChange (value_was_valid);
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("out of scope");
+ }
+ }
+ return m_error.Success();
+}
+
+bool
+ValueObject::UpdateFormatsIfNeeded()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+ if (log)
+ log->Printf("[%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d",
+ GetName().GetCString(),
+ this,
+ m_last_format_mgr_revision,
+ DataVisualization::GetCurrentRevision());
+
+ bool any_change = false;
+
+ if ( (m_last_format_mgr_revision != DataVisualization::GetCurrentRevision()))
+ {
+ SetValueFormat(DataVisualization::ValueFormats::GetFormat (*this, eNoDynamicValues));
+ SetSummaryFormat(DataVisualization::GetSummaryFormat (*this, GetDynamicValueType()));
+#ifndef LLDB_DISABLE_PYTHON
+ SetSyntheticChildren(DataVisualization::GetSyntheticChildren (*this, GetDynamicValueType()));
+#endif
+
+ m_last_format_mgr_revision = DataVisualization::GetCurrentRevision();
+
+ any_change = true;
+ }
+
+ return any_change;
+
+}
+
+void
+ValueObject::SetNeedsUpdate ()
+{
+ m_update_point.SetNeedsUpdate();
+ // We have to clear the value string here so ConstResult children will notice if their values are
+ // changed by hand (i.e. with SetValueAsCString).
+ ClearUserVisibleData(eClearUserVisibleDataItemsValue);
+}
+
+void
+ValueObject::ClearDynamicTypeInformation ()
+{
+ m_did_calculate_complete_objc_class_type = false;
+ m_last_format_mgr_revision = 0;
+ m_override_type = ClangASTType();
+ SetValueFormat(lldb::TypeFormatImplSP());
+ SetSummaryFormat(lldb::TypeSummaryImplSP());
+ SetSyntheticChildren(lldb::SyntheticChildrenSP());
+}
+
+ClangASTType
+ValueObject::MaybeCalculateCompleteType ()
+{
+ ClangASTType clang_type(GetClangTypeImpl());
+
+ if (m_did_calculate_complete_objc_class_type)
+ {
+ if (m_override_type.IsValid())
+ return m_override_type;
+ else
+ return clang_type;
+ }
+
+ ClangASTType class_type;
+ bool is_pointer_type = false;
+
+ if (clang_type.IsObjCObjectPointerType(&class_type))
+ {
+ is_pointer_type = true;
+ }
+ else if (clang_type.IsObjCObjectOrInterfaceType())
+ {
+ class_type = clang_type;
+ }
+ else
+ {
+ return clang_type;
+ }
+
+ m_did_calculate_complete_objc_class_type = true;
+
+ if (class_type)
+ {
+ ConstString class_name (class_type.GetConstTypeName());
+
+ if (class_name)
+ {
+ ProcessSP process_sp(GetUpdatePoint().GetExecutionContextRef().GetProcessSP());
+
+ if (process_sp)
+ {
+ ObjCLanguageRuntime *objc_language_runtime(process_sp->GetObjCLanguageRuntime());
+
+ if (objc_language_runtime)
+ {
+ TypeSP complete_objc_class_type_sp = objc_language_runtime->LookupInCompleteClassCache(class_name);
+
+ if (complete_objc_class_type_sp)
+ {
+ ClangASTType complete_class(complete_objc_class_type_sp->GetClangFullType());
+
+ if (complete_class.GetCompleteType())
+ {
+ if (is_pointer_type)
+ {
+ m_override_type = complete_class.GetPointerType();
+ }
+ else
+ {
+ m_override_type = complete_class;
+ }
+
+ if (m_override_type.IsValid())
+ return m_override_type;
+ }
+ }
+ }
+ }
+ }
+ }
+ return clang_type;
+}
+
+ClangASTType
+ValueObject::GetClangType ()
+{
+ return MaybeCalculateCompleteType();
+}
+
+DataExtractor &
+ValueObject::GetDataExtractor ()
+{
+ UpdateValueIfNeeded(false);
+ return m_data;
+}
+
+const Error &
+ValueObject::GetError()
+{
+ UpdateValueIfNeeded(false);
+ return m_error;
+}
+
+const ConstString &
+ValueObject::GetName() const
+{
+ return m_name;
+}
+
+const char *
+ValueObject::GetLocationAsCString ()
+{
+ return GetLocationAsCStringImpl(m_value,
+ m_data);
+}
+
+const char *
+ValueObject::GetLocationAsCStringImpl (const Value& value,
+ const DataExtractor& data)
+{
+ if (UpdateValueIfNeeded(false))
+ {
+ if (m_location_str.empty())
+ {
+ StreamString sstr;
+
+ Value::ValueType value_type = value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ if (value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = value.GetRegisterInfo();
+ if (reg_info)
+ {
+ if (reg_info->name)
+ m_location_str = reg_info->name;
+ else if (reg_info->alt_name)
+ m_location_str = reg_info->alt_name;
+ if (m_location_str.empty())
+ m_location_str = (reg_info->encoding == lldb::eEncodingVector) ? "vector" : "scalar";
+ }
+ }
+ if (m_location_str.empty())
+ m_location_str = (value_type == Value::eValueTypeVector) ? "vector" : "scalar";
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ uint32_t addr_nibble_size = data.GetAddressByteSize() * 2;
+ sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS));
+ m_location_str.swap(sstr.GetString());
+ }
+ break;
+ }
+ }
+ }
+ return m_location_str.c_str();
+}
+
+Value &
+ValueObject::GetValue()
+{
+ return m_value;
+}
+
+const Value &
+ValueObject::GetValue() const
+{
+ return m_value;
+}
+
+bool
+ValueObject::ResolveValue (Scalar &scalar)
+{
+ if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Value tmp_value(m_value);
+ scalar = tmp_value.ResolveValue(&exe_ctx);
+ if (scalar.IsValid())
+ {
+ const uint32_t bitfield_bit_size = GetBitfieldBitSize();
+ if (bitfield_bit_size)
+ return scalar.ExtractBitfield (bitfield_bit_size, GetBitfieldBitOffset());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ValueObject::GetValueIsValid () const
+{
+ return m_value_is_valid;
+}
+
+
+void
+ValueObject::SetValueIsValid (bool b)
+{
+ m_value_is_valid = b;
+}
+
+bool
+ValueObject::GetValueDidChange ()
+{
+ GetValueAsCString ();
+ return m_value_did_change;
+}
+
+void
+ValueObject::SetValueDidChange (bool value_changed)
+{
+ m_value_did_change = value_changed;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndex (size_t idx, bool can_create)
+{
+ ValueObjectSP child_sp;
+ // We may need to update our value if we are dynamic
+ if (IsPossibleDynamicType ())
+ UpdateValueIfNeeded(false);
+ if (idx < GetNumChildren())
+ {
+ // Check if we have already made the child value object?
+ if (can_create && !m_children.HasChildAtIndex(idx))
+ {
+ // No we haven't created the child at this index, so lets have our
+ // subclass do it and cache the result for quick future access.
+ m_children.SetChildAtIndex(idx,CreateChildAtIndex (idx, false, 0));
+ }
+
+ ValueObject* child = m_children.GetChildAtIndex(idx);
+ if (child != NULL)
+ return child->GetSP();
+ }
+ return child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list<size_t>& idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (size_t idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx, true);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx;
+ return root;
+ }
+ }
+ return root;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list< std::pair<size_t, bool> >& idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (std::pair<size_t, bool> idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx.first, idx.second);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx.first;
+ return root;
+ }
+ }
+ return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector<size_t> &idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (size_t idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx, true);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx;
+ return root;
+ }
+ }
+ return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs,
+ size_t* index_of_error)
+{
+ if (idxs.size() == 0)
+ return GetSP();
+ ValueObjectSP root(GetSP());
+ for (std::pair<size_t, bool> idx : idxs)
+ {
+ root = root->GetChildAtIndex(idx.first, idx.second);
+ if (!root)
+ {
+ if (index_of_error)
+ *index_of_error = idx.first;
+ return root;
+ }
+ }
+ return root;
+}
+
+size_t
+ValueObject::GetIndexOfChildWithName (const ConstString &name)
+{
+ bool omit_empty_base_classes = true;
+ return GetClangType().GetIndexOfChildWithName (name.GetCString(), omit_empty_base_classes);
+}
+
+ValueObjectSP
+ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ // when getting a child by name, it could be buried inside some base
+ // classes (which really aren't part of the expression path), so we
+ // need a vector of indexes that can get us down to the correct child
+ ValueObjectSP child_sp;
+
+ // We may need to update our value if we are dynamic
+ if (IsPossibleDynamicType ())
+ UpdateValueIfNeeded(false);
+
+ std::vector<uint32_t> child_indexes;
+ bool omit_empty_base_classes = true;
+ const size_t num_child_indexes = GetClangType().GetIndexOfChildMemberWithName (name.GetCString(),
+ omit_empty_base_classes,
+ child_indexes);
+ if (num_child_indexes > 0)
+ {
+ std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
+ std::vector<uint32_t>::const_iterator end = child_indexes.end ();
+
+ child_sp = GetChildAtIndex(*pos, can_create);
+ for (++pos; pos != end; ++pos)
+ {
+ if (child_sp)
+ {
+ ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
+ child_sp = new_child_sp;
+ }
+ else
+ {
+ child_sp.reset();
+ }
+
+ }
+ }
+ return child_sp;
+}
+
+
+size_t
+ValueObject::GetNumChildren ()
+{
+ UpdateValueIfNeeded();
+ if (!m_children_count_valid)
+ {
+ SetNumChildren (CalculateNumChildren());
+ }
+ return m_children.GetChildrenCount();
+}
+
+bool
+ValueObject::MightHaveChildren()
+{
+ bool has_children = false;
+ const uint32_t type_info = GetTypeInfo();
+ if (type_info)
+ {
+ if (type_info & (ClangASTType::eTypeHasChildren |
+ ClangASTType::eTypeIsPointer |
+ ClangASTType::eTypeIsReference))
+ has_children = true;
+ }
+ else
+ {
+ has_children = GetNumChildren () > 0;
+ }
+ return has_children;
+}
+
+// Should only be called by ValueObject::GetNumChildren()
+void
+ValueObject::SetNumChildren (size_t num_children)
+{
+ m_children_count_valid = true;
+ m_children.SetChildrenCount(num_children);
+}
+
+void
+ValueObject::SetName (const ConstString &name)
+{
+ m_name = name;
+}
+
+ValueObject *
+ValueObject::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *valobj = NULL;
+
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = synthetic_array_member;
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+
+ const bool transparent_pointers = synthetic_array_member == false;
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ child_clang_type = GetClangType().GetChildClangTypeAtIndex (&exe_ctx,
+ GetName().GetCString(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type)
+ {
+ if (synthetic_index)
+ child_byte_offset += child_byte_size * synthetic_index;
+
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ valobj = new ValueObjectChild (*this,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent,
+ eAddressTypeInvalid);
+ //if (valobj)
+ // valobj->SetAddressTypeOfChildren(eAddressTypeInvalid);
+ }
+
+ return valobj;
+}
+
+bool
+ValueObject::GetSummaryAsCString (TypeSummaryImpl* summary_ptr,
+ std::string& destination)
+{
+ destination.clear();
+
+ // ideally we would like to bail out if passing NULL, but if we do so
+ // we end up not providing the summary for function pointers anymore
+ if (/*summary_ptr == NULL ||*/ m_is_getting_summary)
+ return false;
+
+ m_is_getting_summary = true;
+
+ // this is a hot path in code and we prefer to avoid setting this string all too often also clearing out other
+ // information that we might care to see in a crash log. might be useful in very specific situations though.
+ /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. Summary provider's description is %s",
+ GetTypeName().GetCString(),
+ GetName().GetCString(),
+ summary_ptr->GetDescription().c_str());*/
+
+ if (UpdateValueIfNeeded (false))
+ {
+ 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, ')');
+ }
+ }
+ }
+ }
+ }
+ m_is_getting_summary = false;
+ return !destination.empty();
+}
+
+const char *
+ValueObject::GetSummaryAsCString ()
+{
+ if (UpdateValueIfNeeded(true) && m_summary_str.empty())
+ {
+ GetSummaryAsCString(GetSummaryFormat().get(),
+ m_summary_str);
+ }
+ if (m_summary_str.empty())
+ return NULL;
+ return m_summary_str.c_str();
+}
+
+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) &&
+ pointee_or_element_clang_type.IsCharType ());
+ if (!is_char_arr_ptr)
+ return false;
+ if (!check_pointer)
+ return true;
+ if (type_flags.Test(ClangASTType::eTypeIsArray))
+ return true;
+ addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+ cstr_address = GetAddressOf (true, &cstr_address_type);
+ return (cstr_address != LLDB_INVALID_ADDRESS);
+}
+
+size_t
+ValueObject::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ 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;
+ if (!(is_pointer_type || is_array_type))
+ return 0;
+
+ if (item_count == 0)
+ return 0;
+
+ const uint64_t item_type_size = pointee_or_element_clang_type.GetByteSize();
+ const uint64_t bytes = item_count * item_type_size;
+ const uint64_t offset = item_idx * item_type_size;
+
+ if (item_idx == 0 && item_count == 1) // simply a deref
+ {
+ if (is_pointer_type)
+ {
+ Error error;
+ ValueObjectSP pointee_sp = Dereference(error);
+ if (error.Fail() || pointee_sp.get() == NULL)
+ return 0;
+ return pointee_sp->GetDataExtractor().Copy(data);
+ }
+ else
+ {
+ ValueObjectSP child_sp = GetChildAtIndex(0, true);
+ if (child_sp.get() == NULL)
+ return 0;
+ return child_sp->GetDataExtractor().Copy(data);
+ }
+ return true;
+ }
+ else /* (items > 1) */
+ {
+ Error error;
+ lldb_private::DataBufferHeap* heap_buf_ptr = NULL;
+ lldb::DataBufferSP data_sp(heap_buf_ptr = new lldb_private::DataBufferHeap());
+
+ AddressType addr_type;
+ lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type) : GetAddressOf(true, &addr_type);
+
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ addr = addr + offset;
+ Address so_addr;
+ module_sp->ResolveFileAddress(addr, so_addr);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target* target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ heap_buf_ptr->SetByteSize(bytes);
+ size_t bytes_read = target->ReadMemory(so_addr, false, heap_buf_ptr->GetBytes(), bytes, error);
+ if (error.Success())
+ {
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ }
+ }
+ break;
+ case eAddressTypeLoad:
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ heap_buf_ptr->SetByteSize(bytes);
+ size_t bytes_read = process->ReadMemory(addr + offset, heap_buf_ptr->GetBytes(), bytes, error);
+ if (error.Success())
+ {
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ }
+ break;
+ case eAddressTypeHost:
+ {
+ const uint64_t max_bytes = GetClangType().GetByteSize();
+ if (max_bytes > offset)
+ {
+ size_t bytes_read = std::min<uint64_t>(max_bytes - offset, bytes);
+ heap_buf_ptr->CopyData((uint8_t*)(addr + offset), bytes_read);
+ data.SetData(data_sp);
+ return bytes_read;
+ }
+ }
+ break;
+ case eAddressTypeInvalid:
+ break;
+ }
+ }
+ return 0;
+}
+
+uint64_t
+ValueObject::GetData (DataExtractor& data)
+{
+ UpdateValueIfNeeded(false);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Error error = m_value.GetValueAsData(&exe_ctx, data, 0, GetModule().get());
+ if (error.Fail())
+ {
+ if (m_data.GetByteSize())
+ {
+ data = m_data;
+ return data.GetByteSize();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ data.SetAddressByteSize(m_data.GetAddressByteSize());
+ data.SetByteOrder(m_data.GetByteOrder());
+ return data.GetByteSize();
+}
+
+bool
+ValueObject::SetData (DataExtractor &data, Error &error)
+{
+ error.Clear();
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t count = 0;
+ const Encoding encoding = GetClangType().GetEncoding(count);
+
+ const size_t byte_size = GetByteSize();
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeScalar:
+ {
+ Error set_error = m_value.GetScalar().SetValueFromData(data, encoding, byte_size);
+
+ if (!set_error.Success())
+ {
+ error.SetErrorStringWithFormat("unable to set scalar value: %s", set_error.AsCString());
+ return false;
+ }
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ {
+ // If it is a load address, then the scalar value is the storage location
+ // of the data, and we have to shove this value down to that load location.
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ size_t bytes_written = process->WriteMemory(target_addr,
+ data.GetDataStart(),
+ byte_size,
+ error);
+ if (!error.Success())
+ return false;
+ if (bytes_written != byte_size)
+ {
+ error.SetErrorString("unable to write value to memory");
+ return false;
+ }
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
+ DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0));
+ m_data.SetData(buffer_sp, 0);
+ data.CopyByteOrderedData (0,
+ byte_size,
+ const_cast<uint8_t *>(m_data.GetDataStart()),
+ byte_size,
+ m_data.GetByteOrder());
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeVector:
+ break;
+ }
+
+ // If we have reached this point, then we have successfully changed the value.
+ SetNeedsUpdate();
+ return true;
+}
+
+// will compute strlen(str), but without consuming more than
+// maxlen bytes out of str (this serves the purpose of reading
+// chunks of a string without having to worry about
+// missing NULL terminators in the chunk)
+// of course, if strlen(str) > maxlen, the function will return
+// maxlen_value (which should be != maxlen, because that allows you
+// to know whether strlen(str) == maxlen or strlen(str) > maxlen)
+static uint32_t
+strlen_or_inf (const char* str,
+ uint32_t maxlen,
+ uint32_t maxlen_value)
+{
+ uint32_t len = 0;
+ if (str)
+ {
+ while(*str)
+ {
+ len++;str++;
+ if (len >= maxlen)
+ return maxlen_value;
+ }
+ }
+ return len;
+}
+
+size_t
+ValueObject::ReadPointedString (Stream& s,
+ Error& error,
+ uint32_t max_length,
+ bool honor_array,
+ Format item_format)
+{
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target* target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ s << "<no target to read from>";
+ error.SetErrorString("no target to read from");
+ return 0;
+ }
+
+ if (max_length == 0)
+ max_length = target->GetMaximumSizeOfStringSummary();
+
+ size_t bytes_read = 0;
+ size_t total_bytes_read = 0;
+
+ 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) &&
+ elem_or_pointee_clang_type.IsCharType ())
+ {
+ addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+
+ size_t cstr_len = 0;
+ bool capped_data = false;
+ if (type_flags.Test (ClangASTType::eTypeIsArray))
+ {
+ // We have an array
+ uint64_t array_size = 0;
+ if (clang_type.IsArrayType(NULL, &array_size, NULL))
+ {
+ cstr_len = array_size;
+ if (cstr_len > max_length)
+ {
+ capped_data = true;
+ cstr_len = max_length;
+ }
+ }
+ cstr_address = GetAddressOf (true, &cstr_address_type);
+ }
+ else
+ {
+ // We have a pointer
+ cstr_address = GetPointerValue (&cstr_address_type);
+ }
+
+ if (cstr_address == 0 || cstr_address == LLDB_INVALID_ADDRESS)
+ {
+ s << "<invalid address>";
+ error.SetErrorString("invalid address");
+ return 0;
+ }
+
+ Address cstr_so_addr (cstr_address);
+ DataExtractor data;
+ if (cstr_len > 0 && honor_array)
+ {
+ // 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
+ 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;
+ bool capped_cstr = false;
+ // 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
+ while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0)
+ {
+ total_bytes_read += bytes_read;
+ const char *cstr = data.PeekCStr(0);
+ 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;
+ if (len > bytes_read)
+ len = bytes_read;
+ 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
+
+ if (len < k_max_buf_size)
+ break;
+
+ if (len >= cstr_len)
+ {
+ capped_cstr = true;
+ break;
+ }
+
+ cstr_len -= len;
+ offset += len;
+ }
+
+ if (cstr_len_displayed >= 0)
+ {
+ s << '"';
+ if (capped_cstr)
+ s << "...";
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("not a string object");
+ s << "<not a string object>";
+ }
+ return total_bytes_read;
+}
+
+const char *
+ValueObject::GetObjectDescription ()
+{
+
+ if (!UpdateValueIfNeeded (true))
+ return NULL;
+
+ if (!m_object_desc_str.empty())
+ return m_object_desc_str.c_str();
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return NULL;
+
+ StreamString s;
+
+ LanguageType language = GetObjectRuntimeLanguage();
+ LanguageRuntime *runtime = process->GetLanguageRuntime(language);
+
+ if (runtime == NULL)
+ {
+ // Aw, hell, if the things a pointer, or even just an integer, let's try ObjC anyway...
+ ClangASTType clang_type = GetClangType();
+ if (clang_type)
+ {
+ bool is_signed;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType ())
+ {
+ runtime = process->GetLanguageRuntime(eLanguageTypeObjC);
+ }
+ }
+ }
+
+ if (runtime && runtime->GetObjectDescription(s, *this))
+ {
+ m_object_desc_str.append (s.GetData());
+ }
+
+ if (m_object_desc_str.empty())
+ return NULL;
+ else
+ return m_object_desc_str.c_str();
+}
+
+bool
+ValueObject::GetValueAsCString (lldb::Format format,
+ std::string& destination)
+{
+ if (GetClangType().IsAggregateType () == false && UpdateValueIfNeeded(false))
+ {
+ const Value::ContextType context_type = m_value.GetContextType();
+
+ if (context_type == Value::eContextTypeRegisterInfo)
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ StreamString reg_sstr;
+ m_data.Dump (&reg_sstr,
+ 0,
+ format,
+ reg_info->byte_size,
+ 1,
+ UINT32_MAX,
+ LLDB_INVALID_ADDRESS,
+ 0,
+ 0,
+ exe_ctx.GetBestExecutionContextScope());
+ destination.swap(reg_sstr.GetString());
+ }
+ }
+ else
+ {
+ ClangASTType clang_type = GetClangType ();
+ if (clang_type)
+ {
+ // put custom bytes to display in this DataExtractor to override the default value logic
+ lldb_private::DataExtractor special_format_data;
+ if (format == eFormatCString)
+ {
+ Flags type_flags(clang_type.GetTypeInfo(NULL));
+ if (type_flags.Test(ClangASTType::eTypeIsPointer) && !type_flags.Test(ClangASTType::eTypeIsObjC))
+ {
+ // if we are dumping a pointer as a c-string, get the pointee data as a string
+ TargetSP target_sp(GetTargetSP());
+ if (target_sp)
+ {
+ size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
+ Error error;
+ DataBufferSP buffer_sp(new DataBufferHeap(max_len+1,0));
+ Address address(GetPointerValue());
+ if (target_sp->ReadCStringFromMemory(address, (char*)buffer_sp->GetBytes(), max_len, error) && error.Success())
+ special_format_data.SetData(buffer_sp);
+ }
+ }
+ }
+
+ StreamString sstr;
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ clang_type.DumpTypeValue (&sstr, // The stream to use for display
+ format, // Format to display this type with
+ special_format_data.GetByteSize() ?
+ special_format_data: m_data, // Data to extract from
+ 0, // Byte offset into "m_data"
+ GetByteSize(), // Byte size of item in "m_data"
+ GetBitfieldBitSize(), // Bitfield bit size
+ GetBitfieldBitOffset(), // Bitfield bit offset
+ exe_ctx.GetBestExecutionContextScope());
+ // Don't set the m_error to anything here otherwise
+ // we won't be able to re-format as anything else. The
+ // code for ClangASTType::DumpTypeValue() should always
+ // return something, even if that something contains
+ // an error messsage. "m_error" is used to detect errors
+ // when reading the valid object, not for formatting errors.
+ if (sstr.GetString().empty())
+ destination.clear();
+ else
+ destination.swap(sstr.GetString());
+ }
+ }
+ return !destination.empty();
+ }
+ else
+ return false;
+}
+
+const char *
+ValueObject::GetValueAsCString ()
+{
+ if (UpdateValueIfNeeded(true))
+ {
+ lldb::Format my_format = GetFormat();
+ if (my_format == lldb::eFormatDefault)
+ {
+ if (m_type_format_sp)
+ my_format = m_type_format_sp->GetFormat();
+ else
+ {
+ if (m_is_bitfield_for_scalar)
+ my_format = eFormatUnsigned;
+ else
+ {
+ if (m_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ const RegisterInfo *reg_info = m_value.GetRegisterInfo();
+ if (reg_info)
+ my_format = reg_info->format;
+ }
+ else
+ {
+ my_format = GetClangType().GetFormat();
+ }
+ }
+ }
+ }
+ if (my_format != m_last_format || m_value_str.empty())
+ {
+ m_last_format = my_format;
+ if (GetValueAsCString(my_format, m_value_str))
+ {
+ if (!m_value_did_change && m_old_value_valid)
+ {
+ // The value was gotten successfully, so we consider the
+ // value as changed if the value string differs
+ SetValueDidChange (m_old_value_str != m_value_str);
+ }
+ }
+ }
+ }
+ if (m_value_str.empty())
+ return NULL;
+ return m_value_str.c_str();
+}
+
+// if > 8bytes, 0 is returned. this method should mostly be used
+// to read address values out of pointers
+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())
+ {
+ Scalar scalar;
+ if (ResolveValue (scalar))
+ {
+ if (success)
+ *success = true;
+ return scalar.ULongLong(fail_value);
+ }
+ // fallthrough, otherwise...
+ }
+
+ if (success)
+ *success = false;
+ return fail_value;
+}
+
+// if any more "special cases" are added to ValueObject::DumpPrintableRepresentation() please keep
+// this call up to date by returning true for your new special cases. We will eventually move
+// to checking this call result before trying to display special cases
+bool
+ValueObject::HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display,
+ Format custom_format)
+{
+ Flags flags(GetTypeInfo());
+ if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
+ {
+ if (IsCStringContainer(true) &&
+ (custom_format == eFormatCString ||
+ custom_format == eFormatCharArray ||
+ custom_format == eFormatChar ||
+ custom_format == eFormatVectorOfChar))
+ return true;
+
+ if (flags.Test(ClangASTType::eTypeIsArray))
+ {
+ if ((custom_format == eFormatBytes) ||
+ (custom_format == eFormatBytesWithASCII))
+ return true;
+
+ if ((custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatVectorOfFloat32) ||
+ (custom_format == eFormatVectorOfFloat64) ||
+ (custom_format == eFormatVectorOfSInt16) ||
+ (custom_format == eFormatVectorOfSInt32) ||
+ (custom_format == eFormatVectorOfSInt64) ||
+ (custom_format == eFormatVectorOfSInt8) ||
+ (custom_format == eFormatVectorOfUInt128) ||
+ (custom_format == eFormatVectorOfUInt16) ||
+ (custom_format == eFormatVectorOfUInt32) ||
+ (custom_format == eFormatVectorOfUInt64) ||
+ (custom_format == eFormatVectorOfUInt8))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ValueObject::DumpPrintableRepresentation(Stream& s,
+ ValueObjectRepresentationStyle val_obj_display,
+ Format custom_format,
+ PrintableRepresentationSpecialCases special)
+{
+
+ Flags flags(GetTypeInfo());
+
+ bool allow_special = ((special & ePrintableRepresentationSpecialCasesAllow) == ePrintableRepresentationSpecialCasesAllow);
+ bool only_special = ((special & ePrintableRepresentationSpecialCasesOnly) == ePrintableRepresentationSpecialCasesOnly);
+
+ if (allow_special)
+ {
+ if (flags.AnySet(ClangASTType::eTypeIsArray | ClangASTType::eTypeIsPointer)
+ && val_obj_display == ValueObject::eValueObjectRepresentationStyleValue)
+ {
+ // when being asked to get a printable display an array or pointer type directly,
+ // try to "do the right thing"
+
+ if (IsCStringContainer(true) &&
+ (custom_format == eFormatCString ||
+ custom_format == eFormatCharArray ||
+ custom_format == eFormatChar ||
+ custom_format == eFormatVectorOfChar)) // print char[] & char* directly
+ {
+ Error error;
+ ReadPointedString(s,
+ error,
+ 0,
+ (custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatCharArray));
+ return !error.Fail();
+ }
+
+ if (custom_format == eFormatEnum)
+ return false;
+
+ // 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 ((custom_format == eFormatBytes) ||
+ (custom_format == eFormatBytesWithASCII))
+ {
+ const size_t count = GetNumChildren();
+
+ s << '[';
+ for (size_t low = 0; low < count; low++)
+ {
+
+ if (low)
+ s << ',';
+
+ ValueObjectSP child = GetChildAtIndex(low,true);
+ if (!child.get())
+ {
+ s << "<invalid child>";
+ continue;
+ }
+ child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, custom_format);
+ }
+
+ s << ']';
+
+ return true;
+ }
+
+ if ((custom_format == eFormatVectorOfChar) ||
+ (custom_format == eFormatVectorOfFloat32) ||
+ (custom_format == eFormatVectorOfFloat64) ||
+ (custom_format == eFormatVectorOfSInt16) ||
+ (custom_format == eFormatVectorOfSInt32) ||
+ (custom_format == eFormatVectorOfSInt64) ||
+ (custom_format == eFormatVectorOfSInt8) ||
+ (custom_format == eFormatVectorOfUInt128) ||
+ (custom_format == eFormatVectorOfUInt16) ||
+ (custom_format == eFormatVectorOfUInt32) ||
+ (custom_format == eFormatVectorOfUInt64) ||
+ (custom_format == eFormatVectorOfUInt8)) // arrays of bytes, bytes with ASCII or any vector format should be printed directly
+ {
+ const size_t count = GetNumChildren();
+
+ Format format = FormatManager::GetSingleItemFormat(custom_format);
+
+ s << '[';
+ for (size_t low = 0; low < count; low++)
+ {
+
+ if (low)
+ s << ',';
+
+ ValueObjectSP child = GetChildAtIndex(low,true);
+ if (!child.get())
+ {
+ s << "<invalid child>";
+ continue;
+ }
+ child->DumpPrintableRepresentation(s, ValueObject::eValueObjectRepresentationStyleValue, format);
+ }
+
+ s << ']';
+
+ return true;
+ }
+ }
+
+ if ((custom_format == eFormatBoolean) ||
+ (custom_format == eFormatBinary) ||
+ (custom_format == eFormatChar) ||
+ (custom_format == eFormatCharPrintable) ||
+ (custom_format == eFormatComplexFloat) ||
+ (custom_format == eFormatDecimal) ||
+ (custom_format == eFormatHex) ||
+ (custom_format == eFormatHexUppercase) ||
+ (custom_format == eFormatFloat) ||
+ (custom_format == eFormatOctal) ||
+ (custom_format == eFormatOSType) ||
+ (custom_format == eFormatUnicode16) ||
+ (custom_format == eFormatUnicode32) ||
+ (custom_format == eFormatUnsigned) ||
+ (custom_format == eFormatPointer) ||
+ (custom_format == eFormatComplexInteger) ||
+ (custom_format == eFormatComplex) ||
+ (custom_format == eFormatDefault)) // use the [] operator
+ return false;
+ }
+ }
+
+ if (only_special)
+ return false;
+
+ bool var_success = false;
+
+ {
+ const char *cstr = NULL;
+
+ // this is a local stream that we are using to ensure that the data pointed to by cstr survives
+ // long enough for us to copy it to its destination - it is necessary to have this temporary storage
+ // area for cases where our desired output is not backed by some other longer-term storage
+ StreamString strm;
+
+ if (custom_format != eFormatInvalid)
+ SetFormat(custom_format);
+
+ switch(val_obj_display)
+ {
+ case eValueObjectRepresentationStyleValue:
+ cstr = GetValueAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleSummary:
+ cstr = GetSummaryAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleLanguageSpecific:
+ cstr = GetObjectDescription();
+ break;
+
+ case eValueObjectRepresentationStyleLocation:
+ cstr = GetLocationAsCString();
+ break;
+
+ case eValueObjectRepresentationStyleChildrenCount:
+ strm.Printf("%zu", GetNumChildren());
+ cstr = strm.GetString().c_str();
+ break;
+
+ case eValueObjectRepresentationStyleType:
+ cstr = GetTypeName().AsCString();
+ break;
+
+ case eValueObjectRepresentationStyleName:
+ cstr = GetName().AsCString();
+ break;
+
+ case eValueObjectRepresentationStyleExpressionPath:
+ GetExpressionPath(strm, false);
+ cstr = strm.GetString().c_str();
+ break;
+ }
+
+ if (!cstr)
+ {
+ if (val_obj_display == eValueObjectRepresentationStyleValue)
+ cstr = GetSummaryAsCString();
+ else if (val_obj_display == eValueObjectRepresentationStyleSummary)
+ {
+ if (GetClangType().IsAggregateType())
+ {
+ strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString());
+ cstr = strm.GetString().c_str();
+ }
+ else
+ cstr = GetValueAsCString();
+ }
+ }
+
+ if (cstr)
+ s.PutCString(cstr);
+ else
+ {
+ if (m_error.Fail())
+ s.Printf("<%s>", m_error.AsCString());
+ else if (val_obj_display == eValueObjectRepresentationStyleSummary)
+ s.PutCString("<no summary available>");
+ else if (val_obj_display == eValueObjectRepresentationStyleValue)
+ s.PutCString("<no value available>");
+ else if (val_obj_display == eValueObjectRepresentationStyleLanguageSpecific)
+ s.PutCString("<not a valid Objective-C object>"); // edit this if we have other runtimes that support a description
+ else
+ s.PutCString("<no printable representation>");
+ }
+
+ // we should only return false here if we could not do *anything*
+ // even if we have an error message as output, that's a success
+ // from our callers' perspective, so return true
+ var_success = true;
+
+ if (custom_format != eFormatInvalid)
+ SetFormat(eFormatDefault);
+ }
+
+ return var_success;
+}
+
+addr_t
+ValueObject::GetAddressOf (bool scalar_is_load_address, AddressType *address_type)
+{
+ if (!UpdateValueIfNeeded(false))
+ return LLDB_INVALID_ADDRESS;
+
+ switch (m_value.GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ if (scalar_is_load_address)
+ {
+ if(address_type)
+ *address_type = eAddressTypeLoad;
+ return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ }
+ break;
+
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ if(address_type)
+ *address_type = m_value.GetValueAddressType ();
+ return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ }
+ break;
+ }
+ if (address_type)
+ *address_type = eAddressTypeInvalid;
+ return LLDB_INVALID_ADDRESS;
+}
+
+addr_t
+ValueObject::GetPointerValue (AddressType *address_type)
+{
+ addr_t address = LLDB_INVALID_ADDRESS;
+ if(address_type)
+ *address_type = eAddressTypeInvalid;
+
+ if (!UpdateValueIfNeeded(false))
+ return address;
+
+ switch (m_value.GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ break;
+
+ case Value::eValueTypeHostAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ {
+ lldb::offset_t data_offset = 0;
+ address = m_data.GetPointer(&data_offset);
+ }
+ break;
+ }
+
+ if (address_type)
+ *address_type = GetAddressTypeOfChildren();
+
+ return address;
+}
+
+bool
+ValueObject::SetValueFromCString (const char *value_str, Error& error)
+{
+ error.Clear();
+ // Make sure our value is up to date first so that our location and location
+ // type is valid.
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t count = 0;
+ const Encoding encoding = GetClangType().GetEncoding (count);
+
+ const size_t byte_size = GetByteSize();
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ if (value_type == Value::eValueTypeScalar)
+ {
+ // If the value is already a scalar, then let the scalar change itself:
+ m_value.GetScalar().SetValueFromCString (value_str, encoding, byte_size);
+ }
+ else if (byte_size <= Scalar::GetMaxByteSize())
+ {
+ // If the value fits in a scalar, then make a new scalar and again let the
+ // scalar code do the conversion, then figure out where to put the new value.
+ Scalar new_scalar;
+ error = new_scalar.SetValueFromCString (value_str, encoding, byte_size);
+ if (error.Success())
+ {
+ switch (value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ {
+ // If it is a load address, then the scalar value is the storage location
+ // of the data, and we have to shove this value down to that load location.
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ size_t bytes_written = process->WriteScalarToMemory (target_addr,
+ new_scalar,
+ byte_size,
+ error);
+ if (!error.Success())
+ return false;
+ if (bytes_written != byte_size)
+ {
+ error.SetErrorString("unable to write value to memory");
+ return false;
+ }
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
+ DataExtractor new_data;
+ new_data.SetByteOrder (m_data.GetByteOrder());
+
+ DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0));
+ m_data.SetData(buffer_sp, 0);
+ bool success = new_scalar.GetData(new_data);
+ if (success)
+ {
+ new_data.CopyByteOrderedData (0,
+ byte_size,
+ const_cast<uint8_t *>(m_data.GetDataStart()),
+ byte_size,
+ m_data.GetByteOrder());
+ }
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ break;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // We don't support setting things bigger than a scalar at present.
+ error.SetErrorString("unable to write aggregate data type");
+ return false;
+ }
+
+ // If we have reached this point, then we have successfully changed the value.
+ SetNeedsUpdate();
+ return true;
+}
+
+bool
+ValueObject::GetDeclaration (Declaration &decl)
+{
+ decl.Clear();
+ return false;
+}
+
+ConstString
+ValueObject::GetTypeName()
+{
+ return GetClangType().GetConstTypeName();
+}
+
+ConstString
+ValueObject::GetQualifiedTypeName()
+{
+ return GetClangType().GetConstQualifiedTypeName();
+}
+
+
+LanguageType
+ValueObject::GetObjectRuntimeLanguage ()
+{
+ return GetClangType().GetMinimumLanguage ();
+}
+
+void
+ValueObject::AddSyntheticChild (const ConstString &key, ValueObject *valobj)
+{
+ m_synthetic_children[key] = valobj;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChild (const ConstString &key) const
+{
+ ValueObjectSP synthetic_child_sp;
+ std::map<ConstString, ValueObject *>::const_iterator pos = m_synthetic_children.find (key);
+ if (pos != m_synthetic_children.end())
+ synthetic_child_sp = pos->second->GetSP();
+ return synthetic_child_sp;
+}
+
+uint32_t
+ValueObject::GetTypeInfo (ClangASTType *pointee_or_element_clang_type)
+{
+ return GetClangType().GetTypeInfo (pointee_or_element_clang_type);
+}
+
+bool
+ValueObject::IsPointerType ()
+{
+ return GetClangType().IsPointerType();
+}
+
+bool
+ValueObject::IsArrayType ()
+{
+ return GetClangType().IsArrayType (NULL, NULL, NULL);
+}
+
+bool
+ValueObject::IsScalarType ()
+{
+ return GetClangType().IsScalarType ();
+}
+
+bool
+ValueObject::IsIntegerType (bool &is_signed)
+{
+ return GetClangType().IsIntegerType (is_signed);
+}
+
+bool
+ValueObject::IsPointerOrReferenceType ()
+{
+ return GetClangType().IsPointerOrReferenceType ();
+}
+
+bool
+ValueObject::IsPossibleDynamicType ()
+{
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ return process->IsPossibleDynamicValue(*this);
+ else
+ return GetClangType().IsPossibleDynamicType (NULL, true, true);
+}
+
+bool
+ValueObject::IsObjCNil ()
+{
+ const uint32_t mask = ClangASTType::eTypeIsObjC | ClangASTType::eTypeIsPointer;
+ bool isObjCpointer = (((GetClangType().GetTypeInfo(NULL)) & mask) == mask);
+ if (!isObjCpointer)
+ return false;
+ bool canReadValue = true;
+ bool isZero = GetValueAsUnsigned(0,&canReadValue) == 0;
+ return canReadValue && isZero;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMember (size_t index, bool can_create)
+{
+ const uint32_t type_info = GetTypeInfo ();
+ if (type_info & ClangASTType::eTypeIsArray)
+ return GetSyntheticArrayMemberFromArray(index, can_create);
+
+ if (type_info & ClangASTType::eTypeIsPointer)
+ return GetSyntheticArrayMemberFromPointer(index, can_create);
+
+ return ValueObjectSP();
+
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromPointer (size_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsPointerType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ ValueObject *synthetic_child;
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_array_item_for_pointer = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+// This allows you to create an array member using and index
+// that doesn't not fall in the normal bounds of the array.
+// Many times structure can be defined as:
+// struct Collection
+// {
+// uint32_t item_count;
+// Item item_array[0];
+// };
+// The size of the "item_array" is 1, but many times in practice
+// there are more items in "item_array".
+
+ValueObjectSP
+ValueObject::GetSyntheticArrayMemberFromArray (size_t index, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsArrayType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%zu]", index);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ ValueObject *synthetic_child;
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child = CreateChildAtIndex(0, true, index);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_array_item_for_pointer = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ if (IsScalarType ())
+ {
+ char index_str[64];
+ snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to);
+ ConstString index_const_str(index_str);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (index_const_str);
+ if (!synthetic_child_sp)
+ {
+ // We haven't made a synthetic array member for INDEX yet, so
+ // lets make one and cache it for any future reference.
+ ValueObjectChild *synthetic_child = new ValueObjectChild (*this,
+ GetClangType(),
+ index_const_str,
+ GetByteSize(),
+ 0,
+ to-from+1,
+ from,
+ false,
+ false,
+ eAddressTypeInvalid);
+
+ // Cache the value if we got one back...
+ if (synthetic_child)
+ {
+ AddSyntheticChild(index_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(ConstString(index_str));
+ synthetic_child_sp->m_is_bitfield_for_scalar = true;
+ }
+ }
+ }
+ return synthetic_child_sp;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+
+ ValueObjectSP synthetic_child_sp;
+
+ char name_str[64];
+ snprintf(name_str, sizeof(name_str), "@%i", offset);
+ ConstString name_const_str(name_str);
+
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_str);
+
+ if (synthetic_child_sp.get())
+ return synthetic_child_sp;
+
+ if (!can_create)
+ return ValueObjectSP();
+
+ ValueObjectChild *synthetic_child = new ValueObjectChild(*this,
+ type,
+ name_const_str,
+ type.GetByteSize(),
+ offset,
+ 0,
+ 0,
+ false,
+ false,
+ eAddressTypeInvalid);
+ if (synthetic_child)
+ {
+ AddSyntheticChild(name_const_str, synthetic_child);
+ synthetic_child_sp = synthetic_child->GetSP();
+ synthetic_child_sp->SetName(name_const_str);
+ synthetic_child_sp->m_is_child_at_offset = true;
+ }
+ return synthetic_child_sp;
+}
+
+// your expression path needs to have a leading . or ->
+// (unless it somehow "looks like" an array, in which case it has
+// a leading [ symbol). while the [ is meaningful and should be shown
+// to the user, . and -> are just parser design, but by no means
+// added information for the user.. strip them off
+static const char*
+SkipLeadingExpressionPathSeparators(const char* expression)
+{
+ if (!expression || !expression[0])
+ return expression;
+ if (expression[0] == '.')
+ return expression+1;
+ if (expression[0] == '-' && expression[1] == '>')
+ return expression+2;
+ return expression;
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_create)
+{
+ ValueObjectSP synthetic_child_sp;
+ ConstString name_const_string(expression);
+ // Check if we have already created a synthetic array member in this
+ // valid object. If we have we will re-use it.
+ synthetic_child_sp = GetSyntheticChild (name_const_string);
+ if (!synthetic_child_sp)
+ {
+ // We haven't made a synthetic array member for expression yet, so
+ // lets make one and cache it for any future reference.
+ synthetic_child_sp = GetValueForExpressionPath(expression,
+ NULL, NULL, NULL,
+ GetValueForExpressionPathOptions().DontAllowSyntheticChildren());
+
+ // Cache the value if we got one back...
+ if (synthetic_child_sp.get())
+ {
+ // FIXME: this causes a "real" child to end up with its name changed to the contents of expression
+ AddSyntheticChild(name_const_string, synthetic_child_sp.get());
+ synthetic_child_sp->SetName(ConstString(SkipLeadingExpressionPathSeparators(expression)));
+ }
+ }
+ return synthetic_child_sp;
+}
+
+void
+ValueObject::CalculateSyntheticValue (bool use_synthetic)
+{
+ if (use_synthetic == false)
+ return;
+
+ TargetSP target_sp(GetTargetSP());
+ if (target_sp && (target_sp->GetEnableSyntheticValue() == false || target_sp->GetSuppressSyntheticValue() == true))
+ {
+ m_synthetic_value = NULL;
+ return;
+ }
+
+ lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp);
+
+ if (!UpdateFormatsIfNeeded() && m_synthetic_value)
+ return;
+
+ if (m_synthetic_children_sp.get() == NULL)
+ return;
+
+ if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value)
+ return;
+
+ m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp);
+}
+
+void
+ValueObject::CalculateDynamicValue (DynamicValueType use_dynamic)
+{
+ if (use_dynamic == eNoDynamicValues)
+ return;
+
+ if (!m_dynamic_value && !IsDynamic())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && process->IsPossibleDynamicValue(*this))
+ {
+ ClearDynamicTypeInformation ();
+ m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic);
+ }
+ }
+}
+
+ValueObjectSP
+ValueObject::GetDynamicValue (DynamicValueType use_dynamic)
+{
+ if (use_dynamic == eNoDynamicValues)
+ return ValueObjectSP();
+
+ if (!IsDynamic() && m_dynamic_value == NULL)
+ {
+ CalculateDynamicValue(use_dynamic);
+ }
+ if (m_dynamic_value)
+ return m_dynamic_value->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+ValueObjectSP
+ValueObject::GetStaticValue()
+{
+ return GetSP();
+}
+
+lldb::ValueObjectSP
+ValueObject::GetNonSyntheticValue ()
+{
+ return GetSP();
+}
+
+ValueObjectSP
+ValueObject::GetSyntheticValue (bool use_synthetic)
+{
+ if (use_synthetic == false)
+ return ValueObjectSP();
+
+ CalculateSyntheticValue(use_synthetic);
+
+ if (m_synthetic_value)
+ return m_synthetic_value->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+bool
+ValueObject::HasSyntheticValue()
+{
+ UpdateFormatsIfNeeded();
+
+ if (m_synthetic_children_sp.get() == NULL)
+ return false;
+
+ CalculateSyntheticValue(true);
+
+ if (m_synthetic_value)
+ return true;
+ else
+ return false;
+}
+
+bool
+ValueObject::GetBaseClassPath (Stream &s)
+{
+ if (IsBaseClass())
+ {
+ bool parent_had_base_class = GetParent() && GetParent()->GetBaseClassPath (s);
+ ClangASTType clang_type = GetClangType();
+ std::string cxx_class_name;
+ bool this_had_base_class = clang_type.GetCXXClassName (cxx_class_name);
+ if (this_had_base_class)
+ {
+ if (parent_had_base_class)
+ s.PutCString("::");
+ s.PutCString(cxx_class_name.c_str());
+ }
+ return parent_had_base_class || this_had_base_class;
+ }
+ return false;
+}
+
+
+ValueObject *
+ValueObject::GetNonBaseClassParent()
+{
+ if (GetParent())
+ {
+ if (GetParent()->IsBaseClass())
+ return GetParent()->GetNonBaseClassParent();
+ else
+ return GetParent();
+ }
+ return NULL;
+}
+
+void
+ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
+{
+ const bool is_deref_of_parent = IsDereferenceOfParent ();
+
+ if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
+ {
+ // this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely
+ // fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName.
+ // the eHonorPointers mode is meant to produce strings in this latter format
+ s.PutCString("*(");
+ }
+
+ ValueObject* parent = GetParent();
+
+ if (parent)
+ parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat);
+
+ // if we are a deref_of_parent just because we are synthetic array
+ // members made up to allow ptr[%d] syntax to work in variable
+ // printing, then add our name ([%d]) to the expression path
+ if (m_is_array_item_for_pointer && epformat == eGetExpressionPathFormatHonorPointers)
+ s.PutCString(m_name.AsCString());
+
+ if (!IsBaseClass())
+ {
+ if (!is_deref_of_parent)
+ {
+ ValueObject *non_base_class_parent = GetNonBaseClassParent();
+ if (non_base_class_parent)
+ {
+ ClangASTType non_base_class_parent_clang_type = non_base_class_parent->GetClangType();
+ if (non_base_class_parent_clang_type)
+ {
+ if (parent && parent->IsDereferenceOfParent() && epformat == eGetExpressionPathFormatHonorPointers)
+ {
+ s.PutCString("->");
+ }
+ else
+ {
+ 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)
+ {
+ s.PutCString("->");
+ }
+ else if ((non_base_class_parent_type_info & ClangASTType::eTypeHasChildren) &&
+ !(non_base_class_parent_type_info & ClangASTType::eTypeIsArray))
+ {
+ s.PutChar('.');
+ }
+ }
+ }
+ }
+
+ const char *name = GetName().GetCString();
+ if (name)
+ {
+ if (qualify_cxx_base_classes)
+ {
+ if (GetBaseClassPath (s))
+ s.PutCString("::");
+ }
+ s.PutCString(name);
+ }
+ }
+ }
+
+ if (is_deref_of_parent && epformat == eGetExpressionPathFormatDereferencePointers)
+ {
+ s.PutChar(')');
+ }
+}
+
+ValueObjectSP
+ValueObject::GetValueForExpressionPath(const char* expression,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target)
+{
+
+ const char* dummy_first_unparsed;
+ ExpressionPathScanEndReason dummy_reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnknown;
+ ExpressionPathEndResultType dummy_final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+
+ ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+
+ if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing)
+ return ret_val;
+
+ if (ret_val.get() && ((final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress of plain objects
+ {
+ if ( (final_task_on_target ? *final_task_on_target : dummy_final_task_on_target) == ValueObject::eExpressionPathAftermathDereference)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->Dereference(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ if (final_task_on_target)
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ return final_value;
+ }
+ }
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->AddressOf(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ if (final_task_on_target)
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ return final_value;
+ }
+ }
+ }
+ return ret_val; // final_task_on_target will still have its original value, so you know I did not do it
+}
+
+int
+ValueObject::GetValuesForExpressionPath(const char* expression,
+ ValueObjectListSP& list,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_value_type,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* final_task_on_target)
+{
+ const char* dummy_first_unparsed;
+ ExpressionPathScanEndReason dummy_reason_to_stop;
+ ExpressionPathEndResultType dummy_final_value_type;
+ ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+
+ ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+
+ if (!ret_val.get()) // if there are errors, I add nothing to the list
+ return 0;
+
+ if ( (reason_to_stop ? *reason_to_stop : dummy_reason_to_stop) != eExpressionPathScanEndReasonArrayRangeOperatorMet)
+ {
+ // I need not expand a range, just post-process the final value and return
+ if (!final_task_on_target || *final_task_on_target == ValueObject::eExpressionPathAftermathNothing)
+ {
+ list->Append(ret_val);
+ return 1;
+ }
+ if (ret_val.get() && (final_value_type ? *final_value_type : dummy_final_value_type) == eExpressionPathEndResultTypePlain) // I can only deref and takeaddress of plain objects
+ {
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathDereference)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->Dereference(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ list->Append(final_value);
+ return 1;
+ }
+ }
+ if (*final_task_on_target == ValueObject::eExpressionPathAftermathTakeAddress)
+ {
+ Error error;
+ ValueObjectSP final_value = ret_val->AddressOf(error);
+ if (error.Fail() || !final_value.get())
+ {
+ if (reason_to_stop)
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonTakingAddressFailed;
+ if (final_value_type)
+ *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
+ list->Append(final_value);
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ return ExpandArraySliceExpression(first_unparsed ? *first_unparsed : dummy_first_unparsed,
+ first_unparsed ? first_unparsed : &dummy_first_unparsed,
+ ret_val,
+ list,
+ reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
+ final_value_type ? final_value_type : &dummy_final_value_type,
+ options,
+ final_task_on_target ? final_task_on_target : &dummy_final_task_on_target);
+ }
+ // in any non-covered case, just do the obviously right thing
+ list->Append(ret_val);
+ return 1;
+}
+
+ValueObjectSP
+ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr,
+ const char** first_unparsed,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_result,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* what_next)
+{
+ ValueObjectSP root = GetSP();
+
+ if (!root.get())
+ return ValueObjectSP();
+
+ *first_unparsed = expression_cstr;
+
+ while (true)
+ {
+
+ const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr
+
+ ClangASTType root_clang_type = root->GetClangType();
+ ClangASTType pointee_clang_type;
+ Flags pointee_clang_type_info;
+
+ Flags root_clang_type_info(root_clang_type.GetTypeInfo(&pointee_clang_type));
+ if (pointee_clang_type)
+ pointee_clang_type_info.Reset(pointee_clang_type.GetTypeInfo());
+
+ if (!expression_cstr || *expression_cstr == '\0')
+ {
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ return root;
+ }
+
+ switch (*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
+ {
+ *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) &&
+ options.m_no_fragile_ivar)
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (expression_cstr[1] != '>')
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ expression_cstr++; // skip the -
+ }
+ 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
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ expression_cstr++; // skip .
+ const char *next_separator = strpbrk(expression_cstr+1,"-.[");
+ ConstString child_name;
+ if (!next_separator) // if no other separator just expand this last layer
+ {
+ child_name.SetCString (expression_cstr);
+ ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true);
+
+ if (child_valobj_sp.get()) // we know we are done, so just return
+ {
+ *first_unparsed = "";
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ return child_valobj_sp;
+ }
+ else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ {
+ if (root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+
+ child_valobj_sp = root->GetSyntheticValue();
+ if (child_valobj_sp.get())
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+
+ // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
+ // so we hit the "else" branch, and return an error
+ if(child_valobj_sp.get()) // if it worked, just return
+ {
+ *first_unparsed = "";
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ return child_valobj_sp;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else // other layers do expand
+ {
+ child_name.SetCStringWithLength(expression_cstr, next_separator - expression_cstr);
+ ValueObjectSP child_valobj_sp = root->GetChildMemberWithName(child_name, true);
+ if (child_valobj_sp.get()) // store the new root and move on
+ {
+ root = child_valobj_sp;
+ *first_unparsed = next_separator;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else if (options.m_no_synthetic_children == false) // let's try with synthetic children
+ {
+ if (root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+
+ child_valobj_sp = root->GetSyntheticValue(true);
+ if (child_valobj_sp)
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+
+ // if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
+ // so we hit the "else" branch, and return an error
+ if(child_valobj_sp.get()) // if it worked, move on
+ {
+ root = child_valobj_sp;
+ *first_unparsed = next_separator;
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ break;
+ }
+ 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(ClangASTType::eTypeIsScalar)) // if this is not even a scalar...
+ {
+ if (options.m_no_synthetic_children) // ...only chance left is synthetic
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else // even if something follows, we cannot expand unbounded ranges, just let the caller do it
+ {
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange;
+ return root;
+ }
+ }
+ const char *separator_position = ::strchr(expression_cstr+1,'-');
+ const char *close_bracket_position = ::strchr(expression_cstr+1,']');
+ if (!close_bracket_position) // if there is no ], this is a syntax error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N]
+ {
+ char *end = NULL;
+ unsigned long index = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
+ {
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeUnboundedRange;
+ return root;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ // from here on we do have a valid index
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
+ if (!child_valobj_sp)
+ child_valobj_sp = root->GetSyntheticArrayMemberFromArray(index, true);
+ if (!child_valobj_sp)
+ if (root->HasSyntheticValue() && root->GetSyntheticValue()->GetNumChildren() > index)
+ child_valobj_sp = root->GetSyntheticValue()->GetChildAtIndex(index, true);
+ if (child_valobj_sp)
+ {
+ root = child_valobj_sp;
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::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))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *what_next = eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ if (root->GetClangType().GetMinimumLanguage() == eLanguageTypeObjC
+ && pointee_clang_type_info.AllClear(ClangASTType::eTypeIsPointer)
+ && root->HasSyntheticValue()
+ && options.m_no_synthetic_children == false)
+ {
+ root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
+ }
+ else
+ root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ root = root->GetSyntheticBitFieldChild(index, index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
+ {
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
+ return root;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::eTypeIsVector))
+ {
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ else if (options.m_no_synthetic_children == false)
+ {
+ if (root->HasSyntheticValue())
+ root = root->GetSyntheticValue();
+ else if (!root->IsSynthetic())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ // if we are here, then root itself is a synthetic VO.. should be good to go
+
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *final_result = ValueObject::eExpressionPathEndResultTypePlain;
+ continue;
+ }
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ }
+ else // we have a low and a high index
+ {
+ char *end = NULL;
+ unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != separator_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ unsigned long index_higher = ::strtoul (separator_position+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ if (index_lower > index_higher) // swap indices if required
+ {
+ unsigned long temp = index_lower;
+ index_lower = index_higher;
+ index_higher = temp;
+ }
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ {
+ root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
+ 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
+ *what_next == ValueObject::eExpressionPathAftermathDereference &&
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ }
+ else
+ {
+ *what_next = ValueObject::eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
+ *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange;
+ return root;
+ }
+ }
+ break;
+ }
+ default: // some non-separator is in the way
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return ValueObjectSP();
+ break;
+ }
+ }
+ }
+}
+
+int
+ValueObject::ExpandArraySliceExpression(const char* expression_cstr,
+ const char** first_unparsed,
+ ValueObjectSP root,
+ ValueObjectListSP& list,
+ ExpressionPathScanEndReason* reason_to_stop,
+ ExpressionPathEndResultType* final_result,
+ const GetValueForExpressionPathOptions& options,
+ ExpressionPathAftermath* what_next)
+{
+ if (!root.get())
+ return 0;
+
+ *first_unparsed = expression_cstr;
+
+ while (true)
+ {
+
+ const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr
+
+ ClangASTType root_clang_type = root->GetClangType();
+ ClangASTType pointee_clang_type;
+ Flags pointee_clang_type_info;
+ Flags root_clang_type_info(root_clang_type.GetTypeInfo(&pointee_clang_type));
+ if (pointee_clang_type)
+ pointee_clang_type_info.Reset(pointee_clang_type.GetTypeInfo());
+
+ if (!expression_cstr || *expression_cstr == '\0')
+ {
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
+ list->Append(root);
+ return 1;
+ }
+
+ switch (*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(ClangASTType::eTypeIsScalar)) // if this is not even a scalar, this syntax is just plain wrong!
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ }
+ if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays
+ {
+ if (!root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else // expand this into list
+ {
+ const size_t max_index = root->GetNumChildren() - 1;
+ for (size_t index = 0; index < max_index; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return max_index; // tell me number of items I added to the VOList
+ }
+ }
+ const char *separator_position = ::strchr(expression_cstr+1,'-');
+ const char *close_bracket_position = ::strchr(expression_cstr+1,']');
+ if (!close_bracket_position) // if there is no ], this is a syntax error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N]
+ {
+ char *end = NULL;
+ unsigned long index = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays
+ {
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ const size_t max_index = root->GetNumChildren() - 1;
+ for (size_t index = 0; index < max_index; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = expression_cstr+2;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return max_index; // tell me number of items I added to the VOList
+ }
+ else
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ }
+ // from here on we do have a valid index
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsArray))
+ {
+ root = root->GetChildAtIndex(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ else if (root_clang_type_info.Test(ClangASTType::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))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *what_next = eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ root = root->GetSyntheticArrayMemberFromPointer(index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ }
+ else /*if (ClangASTContext::IsScalarType(root_clang_type))*/
+ {
+ root = root->GetSyntheticBitFieldChild(index, index, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return 1;
+ }
+ }
+ }
+ else // we have a low and a high index
+ {
+ char *end = NULL;
+ unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0);
+ if (!end || end != separator_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ unsigned long index_higher = ::strtoul (separator_position+1, &end, 0);
+ if (!end || end != close_bracket_position) // if something weird is in our way return an error
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ if (index_lower > index_higher) // swap indices if required
+ {
+ unsigned long temp = index_lower;
+ index_lower = index_higher;
+ index_higher = temp;
+ }
+ if (root_clang_type_info.Test(ClangASTType::eTypeIsScalar)) // expansion only works for scalars
+ {
+ root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true);
+ if (!root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ list->Append(root);
+ *first_unparsed = end+1; // skip ]
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ 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
+ *what_next == ValueObject::eExpressionPathAftermathDereference &&
+ pointee_clang_type_info.Test(ClangASTType::eTypeIsScalar))
+ {
+ Error error;
+ root = root->Dereference(error);
+ if (error.Fail() || !root.get())
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ }
+ else
+ {
+ *what_next = ValueObject::eExpressionPathAftermathNothing;
+ continue;
+ }
+ }
+ else
+ {
+ for (unsigned long index = index_lower;
+ index <= index_higher; index++)
+ {
+ ValueObjectSP child =
+ root->GetChildAtIndex(index, true);
+ list->Append(child);
+ }
+ *first_unparsed = end+1;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonRangeOperatorExpanded;
+ *final_result = ValueObject::eExpressionPathEndResultTypeValueObjectList;
+ return index_higher-index_lower+1; // tell me number of items I added to the VOList
+ }
+ }
+ break;
+ }
+ default: // some non-[ separator, or something entirely wrong, is in the way
+ {
+ *first_unparsed = expression_cstr;
+ *reason_to_stop = ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
+ *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
+ return 0;
+ break;
+ }
+ }
+ }
+}
+
+static void
+DumpValueObject_Impl (Stream &s,
+ ValueObject *valobj,
+ const ValueObject::DumpValueObjectOptions& options,
+ uint32_t ptr_depth,
+ uint32_t curr_depth)
+{
+ if (valobj)
+ {
+ bool update_success = valobj->UpdateValueIfNeeded (true);
+
+ const char *root_valobj_name =
+ options.m_root_valobj_name.empty() ?
+ valobj->GetName().AsCString() :
+ options.m_root_valobj_name.c_str();
+
+ if (update_success && options.m_use_dynamic != eNoDynamicValues)
+ {
+ ValueObject *dynamic_value = valobj->GetDynamicValue(options.m_use_dynamic).get();
+ if (dynamic_value)
+ valobj = dynamic_value;
+ }
+
+ ClangASTType clang_type = valobj->GetClangType();
+ const Flags type_flags (clang_type.GetTypeInfo ());
+ const char *err_cstr = NULL;
+ const bool has_children = type_flags.Test (ClangASTType::eTypeHasChildren);
+ const bool has_value = type_flags.Test (ClangASTType::eTypeHasValue);
+
+ const bool print_valobj = options.m_flat_output == false || has_value;
+
+ if (print_valobj)
+ {
+ if (options.m_show_location)
+ {
+ s.Printf("%s: ", valobj->GetLocationAsCString());
+ }
+
+ s.Indent();
+
+ bool show_type = true;
+ // if we are at the root-level and been asked to hide the root's type, then hide it
+ if (curr_depth == 0 && options.m_hide_root_type)
+ show_type = false;
+ else
+ // otherwise decide according to the usual rules (asked to show types - always at the root level)
+ show_type = options.m_show_types || (curr_depth == 0 && !options.m_flat_output);
+
+ if (show_type)
+ {
+ // Some ValueObjects don't have types (like registers sets). Only print
+ // the type if there is one to print
+ ConstString qualified_type_name(valobj->GetQualifiedTypeName());
+ if (qualified_type_name)
+ s.Printf("(%s) ", qualified_type_name.GetCString());
+ }
+
+ if (options.m_flat_output)
+ {
+ // If we are showing types, also qualify the C++ base classes
+ const bool qualify_cxx_base_classes = options.m_show_types;
+ if (!options.m_hide_name)
+ {
+ valobj->GetExpressionPath(s, qualify_cxx_base_classes);
+ s.PutCString(" =");
+ }
+ }
+ else if (!options.m_hide_name)
+ {
+ const char *name_cstr = root_valobj_name ? root_valobj_name : valobj->GetName().AsCString("");
+ s.Printf ("%s =", name_cstr);
+ }
+
+ if (!options.m_scope_already_checked && !valobj->IsInScope())
+ {
+ err_cstr = "out of scope";
+ }
+ }
+
+ std::string summary_str;
+ std::string value_str;
+ const char *val_cstr = NULL;
+ const char *sum_cstr = NULL;
+ TypeSummaryImpl* entry = options.m_summary_sp ? options.m_summary_sp.get() : valobj->GetSummaryFormat().get();
+
+ if (options.m_omit_summary_depth > 0)
+ entry = NULL;
+
+ bool is_nil = valobj->IsObjCNil();
+
+ if (err_cstr == NULL)
+ {
+ if (options.m_format != eFormatDefault && options.m_format != valobj->GetFormat())
+ {
+ valobj->GetValueAsCString(options.m_format,
+ value_str);
+ }
+ else
+ {
+ val_cstr = valobj->GetValueAsCString();
+ if (val_cstr)
+ value_str = val_cstr;
+ }
+ err_cstr = valobj->GetError().AsCString();
+ }
+
+ if (err_cstr)
+ {
+ s.Printf (" <%s>\n", err_cstr);
+ }
+ else
+ {
+ const bool is_ref = type_flags.Test (ClangASTType::eTypeIsReference);
+ if (print_valobj)
+ {
+ if (is_nil)
+ sum_cstr = "nil";
+ else if (options.m_omit_summary_depth == 0)
+ {
+ if (options.m_summary_sp)
+ {
+ valobj->GetSummaryAsCString(entry, summary_str);
+ sum_cstr = summary_str.c_str();
+ }
+ else
+ sum_cstr = valobj->GetSummaryAsCString();
+ }
+
+ // Make sure we have a value and make sure the summary didn't
+ // specify that the value should not be printed - and do not print
+ // the value if this thing is nil
+ // (but show the value if the user passes a format explicitly)
+ if (!is_nil && !value_str.empty() && (entry == NULL || (entry->DoesPrintValue() || options.m_format != eFormatDefault) || sum_cstr == NULL) && !options.m_hide_value)
+ s.Printf(" %s", value_str.c_str());
+
+ if (sum_cstr)
+ s.Printf(" %s", sum_cstr);
+
+ // let's avoid the overly verbose no description error for a nil thing
+ if (options.m_use_objc && !is_nil)
+ {
+ if (!options.m_hide_value || !options.m_hide_name)
+ s.Printf(" ");
+ const char *object_desc = valobj->GetObjectDescription();
+ if (object_desc)
+ s.Printf("%s\n", object_desc);
+ else
+ s.Printf ("[no Objective-C description available]\n");
+ return;
+ }
+ }
+
+ if (curr_depth < options.m_max_depth)
+ {
+ // We will show children for all concrete types. We won't show
+ // pointer contents unless a pointer depth has been specified.
+ // We won't reference contents unless the reference is the
+ // root object (depth of zero).
+ bool print_children = true;
+
+ // Use a new temporary pointer depth in case we override the
+ // current pointer depth below...
+ uint32_t curr_ptr_depth = ptr_depth;
+
+ const bool is_ptr = type_flags.Test (ClangASTType::eTypeIsPointer);
+ if (is_ptr || is_ref)
+ {
+ // We have a pointer or reference whose value is an address.
+ // Make sure that address is not NULL
+ AddressType ptr_address_type;
+ if (valobj->GetPointerValue (&ptr_address_type) == 0)
+ print_children = false;
+
+ else if (is_ref && curr_depth == 0)
+ {
+ // If this is the root object (depth is zero) that we are showing
+ // and it is a reference, and no pointer depth has been supplied
+ // print out what it references. Don't do this at deeper depths
+ // otherwise we can end up with infinite recursion...
+ curr_ptr_depth = 1;
+ }
+
+ if (curr_ptr_depth == 0)
+ print_children = false;
+ }
+
+ if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
+ {
+ ValueObjectSP synth_valobj_sp = valobj->GetSyntheticValue (options.m_use_synthetic);
+ ValueObject* synth_valobj = (synth_valobj_sp ? synth_valobj_sp.get() : valobj);
+
+ size_t num_children = synth_valobj->GetNumChildren();
+ bool print_dotdotdot = false;
+ if (num_children)
+ {
+ if (options.m_flat_output)
+ {
+ if (print_valobj)
+ s.EOL();
+ }
+ else
+ {
+ if (print_valobj)
+ s.PutCString(is_ref ? ": {\n" : " {\n");
+ s.IndentMore();
+ }
+
+ const size_t max_num_children = valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+
+ if (num_children > max_num_children && !options.m_ignore_cap)
+ {
+ num_children = max_num_children;
+ print_dotdotdot = true;
+ }
+
+ ValueObject::DumpValueObjectOptions child_options(options);
+ child_options.SetFormat(options.m_format).SetSummary().SetRootValueObjectName();
+ child_options.SetScopeChecked(true).SetHideName(options.m_hide_name).SetHideValue(options.m_hide_value)
+ .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 ? child_options.m_omit_summary_depth - 1 : 0);
+ for (size_t idx=0; idx<num_children; ++idx)
+ {
+ ValueObjectSP child_sp(synth_valobj->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ DumpValueObject_Impl (s,
+ child_sp.get(),
+ child_options,
+ (is_ptr || is_ref) ? curr_ptr_depth - 1 : curr_ptr_depth,
+ curr_depth + 1);
+ }
+ }
+
+ if (!options.m_flat_output)
+ {
+ if (print_dotdotdot)
+ {
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ target->GetDebugger().GetCommandInterpreter().ChildrenTruncated();
+ s.Indent("...\n");
+ }
+ s.IndentLess();
+ s.Indent("}\n");
+ }
+ }
+ else if (has_children)
+ {
+ // Aggregate, no children...
+ if (print_valobj)
+ s.PutCString(" {}\n");
+ }
+ else
+ {
+ if (print_valobj)
+ s.EOL();
+ }
+
+ }
+ else
+ {
+ s.EOL();
+ }
+ }
+ else
+ {
+ if (has_children && print_valobj)
+ {
+ s.PutCString("{...}\n");
+ }
+ }
+ }
+ }
+}
+
+void
+ValueObject::LogValueObject (Log *log,
+ ValueObject *valobj)
+{
+ if (log && valobj)
+ return LogValueObject (log, valobj, DumpValueObjectOptions::DefaultOptions());
+}
+
+void
+ValueObject::LogValueObject (Log *log,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options)
+{
+ if (log && valobj)
+ {
+ StreamString s;
+ ValueObject::DumpValueObject (s, valobj, options);
+ if (s.GetSize())
+ log->PutCString(s.GetData());
+ }
+}
+
+void
+ValueObject::DumpValueObject (Stream &s,
+ ValueObject *valobj)
+{
+
+ if (!valobj)
+ return;
+
+ DumpValueObject_Impl(s,
+ valobj,
+ DumpValueObjectOptions::DefaultOptions(),
+ 0,
+ 0);
+}
+
+void
+ValueObject::DumpValueObject (Stream &s,
+ ValueObject *valobj,
+ const DumpValueObjectOptions& options)
+{
+ DumpValueObject_Impl(s,
+ valobj,
+ options,
+ options.m_max_ptr_depth, // max pointer depth allowed, we will go down from here
+ 0 // current object depth is 0 since we are just starting
+ );
+}
+
+ValueObjectSP
+ValueObject::CreateConstantValue (const ConstString &name)
+{
+ ValueObjectSP valobj_sp;
+
+ if (UpdateValueIfNeeded(false) && m_error.Success())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ DataExtractor data;
+ data.SetByteOrder (m_data.GetByteOrder());
+ data.SetAddressByteSize(m_data.GetAddressByteSize());
+
+ if (IsBitfield())
+ {
+ Value v(Scalar(GetValueAsUnsigned(UINT64_MAX)));
+ m_error = v.GetValueAsData (&exe_ctx, data, 0, GetModule().get());
+ }
+ else
+ m_error = m_value.GetValueAsData (&exe_ctx, data, 0, GetModule().get());
+
+ valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ GetClangType(),
+ name,
+ data,
+ GetAddressOf());
+ }
+
+ if (!valobj_sp)
+ {
+ valobj_sp = ValueObjectConstResult::Create (NULL, m_error);
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::Dereference (Error &error)
+{
+ if (m_deref_valobj)
+ return m_deref_valobj->GetSP();
+
+ const bool is_pointer_type = IsPointerType();
+ if (is_pointer_type)
+ {
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = false;
+
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+ const bool transparent_pointers = false;
+ ClangASTType clang_type = GetClangType();
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
+ GetName().GetCString(),
+ 0,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type && child_byte_size)
+ {
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ m_deref_valobj = new ValueObjectChild (*this,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent,
+ eAddressTypeInvalid);
+ }
+ }
+
+ if (m_deref_valobj)
+ {
+ error.Clear();
+ return m_deref_valobj->GetSP();
+ }
+ else
+ {
+ StreamString strm;
+ GetExpressionPath(strm, true);
+
+ if (is_pointer_type)
+ error.SetErrorStringWithFormat("dereference failed: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
+ else
+ error.SetErrorStringWithFormat("not a pointer type: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+}
+
+ValueObjectSP
+ValueObject::AddressOf (Error &error)
+{
+ if (m_addr_of_valobj_sp)
+ return m_addr_of_valobj_sp;
+
+ AddressType address_type = eAddressTypeInvalid;
+ const bool scalar_is_load_address = false;
+ addr_t addr = GetAddressOf (scalar_is_load_address, &address_type);
+ error.Clear();
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ switch (address_type)
+ {
+ case eAddressTypeInvalid:
+ {
+ StreamString expr_path_strm;
+ GetExpressionPath(expr_path_strm, true);
+ error.SetErrorStringWithFormat("'%s' is not in memory", expr_path_strm.GetString().c_str());
+ }
+ break;
+
+ case eAddressTypeFile:
+ case eAddressTypeLoad:
+ case eAddressTypeHost:
+ {
+ ClangASTType clang_type = GetClangType();
+ if (clang_type)
+ {
+ std::string name (1, '&');
+ name.append (m_name.AsCString(""));
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_addr_of_valobj_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ clang_type.GetPointerType(),
+ ConstString (name.c_str()),
+ addr,
+ eAddressTypeInvalid,
+ m_data.GetAddressByteSize());
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ StreamString expr_path_strm;
+ GetExpressionPath(expr_path_strm, true);
+ error.SetErrorStringWithFormat("'%s' doesn't have a valid address", expr_path_strm.GetString().c_str());
+ }
+
+ return m_addr_of_valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::Cast (const ClangASTType &clang_ast_type)
+{
+ return ValueObjectCast::Create (*this, GetName(), clang_ast_type);
+}
+
+ValueObjectSP
+ValueObject::CastPointerType (const char *name, ClangASTType &clang_ast_type)
+{
+ ValueObjectSP valobj_sp;
+ AddressType address_type;
+ addr_t ptr_value = GetPointerValue (&address_type);
+
+ if (ptr_value != LLDB_INVALID_ADDRESS)
+ {
+ Address ptr_addr (ptr_value);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
+ name,
+ ptr_addr,
+ clang_ast_type);
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP
+ValueObject::CastPointerType (const char *name, TypeSP &type_sp)
+{
+ ValueObjectSP valobj_sp;
+ AddressType address_type;
+ addr_t ptr_value = GetPointerValue (&address_type);
+
+ if (ptr_value != LLDB_INVALID_ADDRESS)
+ {
+ Address ptr_addr (ptr_value);
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ valobj_sp = ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
+ name,
+ ptr_addr,
+ type_sp);
+ }
+ return valobj_sp;
+}
+
+ValueObject::EvaluationPoint::EvaluationPoint () :
+ m_mod_id(),
+ m_exe_ctx_ref(),
+ m_needs_update (true),
+ m_first_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)
+{
+ ExecutionContext exe_ctx(exe_scope);
+ TargetSP target_sp (exe_ctx.GetTargetSP());
+ if (target_sp)
+ {
+ m_exe_ctx_ref.SetTargetSP (target_sp);
+ ProcessSP process_sp (exe_ctx.GetProcessSP());
+ if (!process_sp)
+ process_sp = target_sp->GetProcessSP();
+
+ if (process_sp)
+ {
+ m_mod_id = process_sp->GetModID();
+ m_exe_ctx_ref.SetProcessSP (process_sp);
+
+ ThreadSP thread_sp (exe_ctx.GetThreadSP());
+
+ if (!thread_sp)
+ {
+ if (use_selected)
+ thread_sp = process_sp->GetThreadList().GetSelectedThread();
+ }
+
+ if (thread_sp)
+ {
+ m_exe_ctx_ref.SetThreadSP(thread_sp);
+
+ StackFrameSP frame_sp (exe_ctx.GetFrameSP());
+ if (!frame_sp)
+ {
+ if (use_selected)
+ frame_sp = thread_sp->GetSelectedFrame();
+ }
+ if (frame_sp)
+ m_exe_ctx_ref.SetFrameSP(frame_sp);
+ }
+ }
+ }
+}
+
+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)
+{
+}
+
+ValueObject::EvaluationPoint::~EvaluationPoint ()
+{
+}
+
+// This function checks the EvaluationPoint against the current process state. If the current
+// state matches the evaluation point, or the evaluation point is already invalid, then we return
+// false, meaning "no change". If the current state is different, we update our state, and return
+// true meaning "yes, change". If we did see a change, we also set m_needs_update to true, so
+// future calls to NeedsUpdate will return true.
+// exe_scope will be set to the current execution context scope.
+
+bool
+ValueObject::EvaluationPoint::SyncWithProcessState()
+{
+
+ // Start with the target, if it is NULL, then we're obviously not going to get any further:
+ ExecutionContext exe_ctx(m_exe_ctx_ref.Lock());
+
+ if (exe_ctx.GetTargetPtr() == NULL)
+ return false;
+
+ // If we don't have a process nothing can change.
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return false;
+
+ // If our stop id is the current stop ID, nothing has changed:
+ ProcessModID current_mod_id = process->GetModID();
+
+ // If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
+ // In either case, we aren't going to be able to sync with the process state.
+ if (current_mod_id.GetStopID() == 0)
+ return false;
+
+ bool changed = false;
+ const bool was_valid = m_mod_id.IsValid();
+ if (was_valid)
+ {
+ if (m_mod_id == current_mod_id)
+ {
+ // Everything is already up to date in this object, no need to
+ // update the execution context scope.
+ changed = false;
+ }
+ else
+ {
+ m_mod_id = current_mod_id;
+ m_needs_update = true;
+ changed = true;
+ }
+ }
+
+ // Now re-look up the thread and frame in case the underlying objects have gone away & been recreated.
+ // That way we'll be sure to return a valid exe_scope.
+ // If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid.
+
+ if (m_exe_ctx_ref.HasThreadRef())
+ {
+ ThreadSP thread_sp (m_exe_ctx_ref.GetThreadSP());
+ if (thread_sp)
+ {
+ if (m_exe_ctx_ref.HasFrameRef())
+ {
+ StackFrameSP frame_sp (m_exe_ctx_ref.GetFrameSP());
+ if (!frame_sp)
+ {
+ // We used to have a frame, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
+ }
+ }
+ else
+ {
+ // We used to have a thread, but now it is gone
+ SetInvalid();
+ changed = was_valid;
+ }
+
+ }
+ return changed;
+}
+
+void
+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;
+}
+
+
+
+void
+ValueObject::ClearUserVisibleData(uint32_t clear_mask)
+{
+ if ((clear_mask & eClearUserVisibleDataItemsValue) == eClearUserVisibleDataItemsValue)
+ m_value_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsLocation) == eClearUserVisibleDataItemsLocation)
+ m_location_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsSummary) == eClearUserVisibleDataItemsSummary)
+ {
+ m_summary_str.clear();
+ }
+
+ if ((clear_mask & eClearUserVisibleDataItemsDescription) == eClearUserVisibleDataItemsDescription)
+ m_object_desc_str.clear();
+
+ if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) == eClearUserVisibleDataItemsSyntheticChildren)
+ {
+ if (m_synthetic_value)
+ m_synthetic_value = NULL;
+ }
+}
+
+SymbolContextScope *
+ValueObject::GetSymbolContextScope()
+{
+ if (m_parent)
+ {
+ if (!m_parent->IsPointerOrReferenceType())
+ return m_parent->GetSymbolContextScope();
+ }
+ return NULL;
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromExpression (const char* name,
+ const char* expression,
+ const ExecutionContext& exe_ctx)
+{
+ lldb::ValueObjectSP retval_sp;
+ lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
+ if (!target_sp)
+ return retval_sp;
+ if (!expression || !*expression)
+ return retval_sp;
+ target_sp->EvaluateExpression (expression,
+ exe_ctx.GetFrameSP().get(),
+ retval_sp);
+ if (retval_sp && name && *name)
+ retval_sp->SetName(ConstString(name));
+ return retval_sp;
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromAddress (const char* name,
+ uint64_t address,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ if (type)
+ {
+ ClangASTType pointer_type(type.GetPointerType());
+ if (pointer_type)
+ {
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&address,sizeof(lldb::addr_t)));
+ lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ pointer_type,
+ ConstString(name),
+ buffer,
+ lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetAddressByteSize()));
+ if (ptr_result_valobj_sp)
+ {
+ ptr_result_valobj_sp->GetValue().SetValueType(Value::eValueTypeLoadAddress);
+ Error err;
+ ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
+ if (ptr_result_valobj_sp && name && *name)
+ ptr_result_valobj_sp->SetName(ConstString(name));
+ }
+ return ptr_result_valobj_sp;
+ }
+ }
+ return lldb::ValueObjectSP();
+}
+
+lldb::ValueObjectSP
+ValueObject::CreateValueObjectFromData (const char* name,
+ DataExtractor& data,
+ const ExecutionContext& exe_ctx,
+ ClangASTType type)
+{
+ lldb::ValueObjectSP new_value_sp;
+ new_value_sp = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ type,
+ ConstString(name),
+ data,
+ LLDB_INVALID_ADDRESS);
+ new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
+ if (new_value_sp && name && *name)
+ new_value_sp->SetName(ConstString(name));
+ return new_value_sp;
+}
+
+ModuleSP
+ValueObject::GetModule ()
+{
+ ValueObject* root(GetRoot());
+ if (root != this)
+ return root->GetModule();
+ return lldb::ModuleSP();
+}
+
+ValueObject*
+ValueObject::GetRoot ()
+{
+ if (m_root)
+ return m_root;
+ ValueObject* parent = m_parent;
+ if (!parent)
+ return (m_root = this);
+ while (parent->m_parent)
+ {
+ if (parent->m_root)
+ return (m_root = parent->m_root);
+ parent = parent->m_parent;
+ }
+ return (m_root = parent);
+}
+
+AddressType
+ValueObject::GetAddressTypeOfChildren()
+{
+ if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid)
+ {
+ ValueObject* root(GetRoot());
+ if (root != this)
+ return root->GetAddressTypeOfChildren();
+ }
+ return m_address_type_of_ptr_or_ref_children;
+}
+
+lldb::DynamicValueType
+ValueObject::GetDynamicValueType ()
+{
+ ValueObject* with_dv_info = this;
+ while (with_dv_info)
+ {
+ if (with_dv_info->HasDynamicValueTypeInfo())
+ return with_dv_info->GetDynamicValueTypeImpl();
+ with_dv_info = with_dv_info->m_parent;
+ }
+ return lldb::eNoDynamicValues;
+}
+
+lldb::Format
+ValueObject::GetFormat () const
+{
+ const ValueObject* with_fmt_info = this;
+ while (with_fmt_info)
+ {
+ if (with_fmt_info->m_format != lldb::eFormatDefault)
+ return with_fmt_info->m_format;
+ with_fmt_info = with_fmt_info->m_parent;
+ }
+ return m_format;
+}
diff --git a/source/Core/ValueObjectCast.cpp b/source/Core/ValueObjectCast.cpp
new file mode 100644
index 000000000000..4f4f8cc681d0
--- /dev/null
+++ b/source/Core/ValueObjectCast.cpp
@@ -0,0 +1,129 @@
+//===-- ValueObjectDynamicValue.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/ValueObjectCast.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+lldb::ValueObjectSP
+ValueObjectCast::Create (ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type)
+{
+ ValueObjectCast *cast_valobj_ptr = new ValueObjectCast (parent, name, cast_type);
+ return cast_valobj_ptr->GetSP();
+}
+
+ValueObjectCast::ValueObjectCast
+(
+ ValueObject &parent,
+ const ConstString &name,
+ const ClangASTType &cast_type
+) :
+ ValueObject(parent),
+ m_cast_type (cast_type)
+{
+ SetName (name);
+ //m_value.SetContext (Value::eContextTypeClangType, cast_type.GetOpaqueQualType());
+ m_value.SetClangType (cast_type);
+}
+
+ValueObjectCast::~ValueObjectCast()
+{
+}
+
+ClangASTType
+ValueObjectCast::GetClangTypeImpl ()
+{
+ return m_cast_type;
+}
+
+size_t
+ValueObjectCast::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+uint64_t
+ValueObjectCast::GetByteSize()
+{
+ return m_value.GetValueByteSize(NULL);
+}
+
+lldb::ValueType
+ValueObjectCast::GetValueType() const
+{
+ // Let our parent answer global, local, argument, etc...
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectCast::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (m_parent->UpdateValueIfNeeded(false))
+ {
+ Value old_value(m_value);
+ m_update_point.SetUpdated();
+ m_value = m_parent->GetValue();
+ ClangASTType clang_type (GetClangType());
+ //m_value.SetContext (Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren());
+ if (clang_type.IsAggregateType ())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_error = m_value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ SetValueDidChange (m_parent->GetValueDidChange());
+ return true;
+ }
+
+ // The dynamic value failed to get an error, pass the error along
+ if (m_error.Success() && m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ SetValueIsValid (false);
+ return false;
+}
+
+bool
+ValueObjectCast::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
new file mode 100644
index 000000000000..23add1ccf0e8
--- /dev/null
+++ b/source/Core/ValueObjectChild.cpp
@@ -0,0 +1,234 @@
+//===-- ValueObjectChild.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/ValueObjectChild.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+ValueObjectChild::ValueObjectChild
+(
+ ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint64_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent,
+ AddressType child_ptr_or_ref_addr_type
+) :
+ ValueObject (parent),
+ m_clang_type (clang_type),
+ m_byte_size (byte_size),
+ m_byte_offset (byte_offset),
+ m_bitfield_bit_size (bitfield_bit_size),
+ m_bitfield_bit_offset (bitfield_bit_offset),
+ m_is_base_class (is_base_class),
+ m_is_deref_of_parent (is_deref_of_parent)
+{
+ m_name = name;
+ SetAddressTypeOfChildren(child_ptr_or_ref_addr_type);
+}
+
+ValueObjectChild::~ValueObjectChild()
+{
+}
+
+lldb::ValueType
+ValueObjectChild::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+size_t
+ValueObjectChild::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+ConstString
+ValueObjectChild::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ {
+ m_type_name = GetClangType().GetConstTypeName ();
+ if (m_type_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = m_type_name.AsCString();
+ if (clang_type_name)
+ {
+ std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
+ ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ m_type_name.SetCString(&bitfield_type_name.front());
+ }
+ }
+ }
+ }
+ return m_type_name;
+}
+
+ConstString
+ValueObjectChild::GetQualifiedTypeName()
+{
+ ConstString qualified_name = GetClangType().GetConstTypeName();
+ if (qualified_name)
+ {
+ if (m_bitfield_bit_size > 0)
+ {
+ const char *clang_type_name = qualified_name.AsCString();
+ if (clang_type_name)
+ {
+ std::vector<char> bitfield_type_name (strlen(clang_type_name) + 32, 0);
+ ::snprintf (&bitfield_type_name.front(), bitfield_type_name.size(), "%s:%u", clang_type_name, m_bitfield_bit_size);
+ qualified_name.SetCString(&bitfield_type_name.front());
+ }
+ }
+ }
+ return qualified_name;
+}
+
+bool
+ValueObjectChild::UpdateValue ()
+{
+ m_error.Clear();
+ SetValueIsValid (false);
+ ValueObject* parent = m_parent;
+ if (parent)
+ {
+ if (parent->UpdateValueIfNeeded(false))
+ {
+ m_value.SetClangType(GetClangType());
+
+ // Copy the parent scalar value and the scalar value type
+ m_value.GetScalar() = parent->GetValue().GetScalar();
+ Value::ValueType value_type = parent->GetValue().GetValueType();
+ m_value.SetValueType (value_type);
+
+ if (parent->GetClangType().IsPointerOrReferenceType ())
+ {
+ lldb::addr_t addr = parent->GetPointerValue ();
+ m_value.GetScalar() = addr;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ m_error.SetErrorString ("parent address is invalid.");
+ }
+ else if (addr == 0)
+ {
+ m_error.SetErrorString ("parent is NULL");
+ }
+ else
+ {
+ m_value.GetScalar() += m_byte_offset;
+ AddressType addr_type = parent->GetAddressTypeOfChildren();
+
+ switch (addr_type)
+ {
+ case eAddressTypeFile:
+ {
+ lldb::ProcessSP process_sp (GetProcessSP());
+ if (process_sp && process_sp->IsAlive() == true)
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ else
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ }
+ break;
+ case eAddressTypeLoad:
+ m_value.SetValueType (Value::eValueTypeLoadAddress);
+ break;
+ case eAddressTypeHost:
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ break;
+ case eAddressTypeInvalid:
+ // TODO: does this make sense?
+ m_value.SetValueType(Value::eValueTypeScalar);
+ break;
+ }
+ }
+ }
+ else
+ {
+ switch (value_type)
+ {
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeHostAddress:
+ {
+ lldb::addr_t addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ m_error.SetErrorString ("parent address is invalid.");
+ }
+ else if (addr == 0)
+ {
+ m_error.SetErrorString ("parent is NULL");
+ }
+ else
+ {
+ // Set this object's scalar value to the address of its
+ // value by adding its byte offset to the parent address
+ m_value.GetScalar() += GetByteOffset();
+ }
+ }
+ break;
+
+ case Value::eValueTypeScalar:
+ // TODO: What if this is a register value? Do we try and
+ // extract the child value from within the parent data?
+ // Probably...
+ default:
+ m_error.SetErrorString ("parent has invalid value.");
+ break;
+ }
+ }
+
+ if (m_error.Success())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef().Lock());
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ }
+ }
+ else
+ {
+ m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", parent->GetError().AsCString());
+ }
+ }
+ else
+ {
+ m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject.");
+ }
+
+ return m_error.Success();
+}
+
+
+bool
+ValueObjectChild::IsInScope ()
+{
+ ValueObject* root(GetRoot());
+ if (root)
+ return root->IsInScope ();
+ return false;
+}
diff --git a/source/Core/ValueObjectConstResult.cpp b/source/Core/ValueObjectConstResult.cpp
new file mode 100644
index 000000000000..d6d86381358d
--- /dev/null
+++ b/source/Core/ValueObjectConstResult.cpp
@@ -0,0 +1,354 @@
+//===-- ValueObjectConstResult.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/ValueObjectConstResult.h"
+
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResultChild.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectDynamicValue.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ byte_order,
+ addr_byte_size,
+ address))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ ByteOrder byte_order,
+ uint32_t addr_byte_size,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ SetIsConstant ();
+ SetValueIsValid(true);
+ m_data.SetByteOrder(byte_order);
+ m_data.SetAddressByteSize(addr_byte_size);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create
+(
+ ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address
+)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ data,
+ address))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const DataExtractor &data,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_data = data;
+
+ if (!m_data.GetSharedDataBuffer())
+ {
+ DataBufferSP shared_data_buffer(new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
+ m_data.SetData(shared_data_buffer);
+ }
+
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.SetClangType(clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &data_sp,
+ lldb::ByteOrder data_byte_order,
+ uint32_t data_addr_size,
+ lldb::addr_t address)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ data_sp,
+ data_byte_order,
+ data_addr_size,
+ address))->GetSP();
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ Value &value,
+ const ConstString &name)
+{
+ return (new ValueObjectConstResult (exe_scope, value, name))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ const lldb::DataBufferSP &data_sp,
+ lldb::ByteOrder data_byte_order,
+ uint32_t data_addr_size,
+ lldb::addr_t address) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_data.SetByteOrder(data_byte_order);
+ m_data.SetAddressByteSize(data_addr_size);
+ m_data.SetData(data_sp);
+ m_value.GetScalar() = (uintptr_t)data_sp->GetBytes();
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ //m_value.SetContext(Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ clang_type,
+ name,
+ address,
+ address_type,
+ addr_byte_size))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ lldb::addr_t address,
+ AddressType address_type,
+ uint32_t addr_byte_size) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this, address)
+{
+ m_value.GetScalar() = address;
+ m_data.SetAddressByteSize(addr_byte_size);
+ m_value.GetScalar().GetData (m_data, addr_byte_size);
+ //m_value.SetValueType(Value::eValueTypeHostAddress);
+ switch (address_type)
+ {
+ case eAddressTypeInvalid: m_value.SetValueType(Value::eValueTypeScalar); break;
+ case eAddressTypeFile: m_value.SetValueType(Value::eValueTypeFileAddress); break;
+ case eAddressTypeLoad: m_value.SetValueType(Value::eValueTypeLoadAddress); break;
+ case eAddressTypeHost: m_value.SetValueType(Value::eValueTypeHostAddress); break;
+ }
+// m_value.SetContext(Value::eContextTypeClangType, clang_type);
+ m_value.SetClangType (clang_type);
+ m_name = name;
+ SetIsConstant ();
+ SetValueIsValid(true);
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+}
+
+ValueObjectSP
+ValueObjectConstResult::Create
+(
+ ExecutionContextScope *exe_scope,
+ const Error& error
+)
+{
+ return (new ValueObjectConstResult (exe_scope,
+ error))->GetSP();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Error& error) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this)
+{
+ m_error = error;
+ SetIsConstant ();
+}
+
+ValueObjectConstResult::ValueObjectConstResult (ExecutionContextScope *exe_scope,
+ const Value &value,
+ const ConstString &name) :
+ ValueObject (exe_scope),
+ m_type_name (),
+ m_byte_size (0),
+ m_impl(this)
+{
+ m_value = value;
+ m_value.GetData(m_data);
+}
+
+ValueObjectConstResult::~ValueObjectConstResult()
+{
+}
+
+ClangASTType
+ValueObjectConstResult::GetClangTypeImpl()
+{
+ return m_value.GetClangType();
+}
+
+lldb::ValueType
+ValueObjectConstResult::GetValueType() const
+{
+ return eValueTypeConstResult;
+}
+
+uint64_t
+ValueObjectConstResult::GetByteSize()
+{
+ if (m_byte_size == 0)
+ m_byte_size = GetClangType().GetByteSize();
+ return m_byte_size;
+}
+
+void
+ValueObjectConstResult::SetByteSize (size_t size)
+{
+ m_byte_size = size;
+}
+
+size_t
+ValueObjectConstResult::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren (true);
+}
+
+ConstString
+ValueObjectConstResult::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ m_type_name = GetClangType().GetConstTypeName ();
+ return m_type_name;
+}
+
+bool
+ValueObjectConstResult::UpdateValue ()
+{
+ // Const value is always valid
+ SetValueIsValid (true);
+ return true;
+}
+
+
+bool
+ValueObjectConstResult::IsInScope ()
+{
+ // A const result value is always in scope since it serializes all
+ // information needed to contain the constant value.
+ return true;
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::Dereference (Error &error)
+{
+ return m_impl.Dereference(error);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ return m_impl.GetSyntheticChildAtOffset(offset, type, can_create);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::AddressOf (Error &error)
+{
+ return m_impl.AddressOf(error);
+}
+
+lldb::addr_t
+ValueObjectConstResult::GetAddressOf (bool scalar_is_load_address,
+ AddressType *address_type)
+{
+ return m_impl.GetAddressOf(scalar_is_load_address, address_type);
+}
+
+ValueObject *
+ValueObjectConstResult::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ return m_impl.CreateChildAtIndex(idx, synthetic_array_member, synthetic_index);
+}
+
+size_t
+ValueObjectConstResult::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ return m_impl.GetPointeeData(data, item_idx, item_count);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResult::GetDynamicValue (lldb::DynamicValueType use_dynamic)
+{
+ // Always recalculate dynamic values for const results as the memory that
+ // they might point to might have changed at any time.
+ if (use_dynamic != eNoDynamicValues)
+ {
+ if (!IsDynamic())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process && process->IsPossibleDynamicValue(*this))
+ m_dynamic_value = new ValueObjectDynamicValue (*this, use_dynamic);
+ }
+ if (m_dynamic_value)
+ return m_dynamic_value->GetSP();
+ }
+ return ValueObjectSP();
+}
+
diff --git a/source/Core/ValueObjectConstResultChild.cpp b/source/Core/ValueObjectConstResultChild.cpp
new file mode 100644
index 000000000000..64425ea50969
--- /dev/null
+++ b/source/Core/ValueObjectConstResultChild.cpp
@@ -0,0 +1,80 @@
+//===-- ValueObjectConstResultChild.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/ValueObjectConstResultChild.h"
+
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTContext.h"
+
+using namespace lldb_private;
+
+ValueObjectConstResultChild::ValueObjectConstResultChild
+(
+ ValueObject &parent,
+ const ClangASTType &clang_type,
+ const ConstString &name,
+ uint32_t byte_size,
+ int32_t byte_offset,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool is_base_class,
+ bool is_deref_of_parent
+) :
+ ValueObjectChild (parent,
+ clang_type,
+ name,
+ byte_size,
+ byte_offset,
+ bitfield_bit_size,
+ bitfield_bit_offset,
+ is_base_class,
+ is_deref_of_parent,
+ eAddressTypeLoad),
+ m_impl(this)
+{
+ m_name = name;
+}
+
+ValueObjectConstResultChild::~ValueObjectConstResultChild()
+{
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::Dereference (Error &error)
+{
+ return m_impl.Dereference(error);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::GetSyntheticChildAtOffset(uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ return m_impl.GetSyntheticChildAtOffset(offset, type, can_create);
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultChild::AddressOf (Error &error)
+{
+ return m_impl.AddressOf(error);
+}
+
+ValueObject *
+ValueObjectConstResultChild::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ return m_impl.CreateChildAtIndex(idx, synthetic_array_member, synthetic_index);
+}
+
+size_t
+ValueObjectConstResultChild::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ return m_impl.GetPointeeData(data, item_idx, item_count);
+}
diff --git a/source/Core/ValueObjectConstResultImpl.cpp b/source/Core/ValueObjectConstResultImpl.cpp
new file mode 100644
index 000000000000..e0757f60cdba
--- /dev/null
+++ b/source/Core/ValueObjectConstResultImpl.cpp
@@ -0,0 +1,236 @@
+//===-- ValueObjectConstResultImpl.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/ValueObjectConstResultImpl.h"
+
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectConstResultChild.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// this macro enables a simpler implementation for some method calls in this object that relies only upon
+// ValueObject knowning how to set the address type of its children correctly. the alternative implementation
+// 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),
+ m_live_address(live_address),
+ m_live_address_type(eAddressTypeLoad),
+ m_load_addr_backend(),
+ m_address_of_backend()
+{
+}
+
+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 *
+ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ if (m_impl_backend == NULL)
+ return NULL;
+
+ m_impl_backend->UpdateValueIfNeeded(false);
+
+ ValueObjectConstResultChild *valobj = NULL;
+
+ bool omit_empty_base_classes = true;
+ bool ignore_array_bounds = synthetic_array_member;
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
+
+ const bool transparent_pointers = synthetic_array_member == false;
+ ClangASTType clang_type = m_impl_backend->GetClangType();
+ ClangASTType child_clang_type;
+
+ ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
+
+ child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
+ m_impl_backend->GetName().GetCString(),
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type && child_byte_size)
+ {
+ if (synthetic_index)
+ child_byte_offset += child_byte_size * synthetic_index;
+
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ valobj = new ValueObjectConstResultChild (*m_impl_backend,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
+ }
+
+ return valobj;
+}
+
+lldb::ValueObjectSP
+ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const ClangASTType& type, bool can_create)
+{
+ 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
+ValueObjectConstResultImpl::AddressOf (Error &error)
+{
+ if (m_address_of_backend.get() != NULL)
+ return m_address_of_backend;
+
+ if (m_impl_backend == NULL)
+ return lldb::ValueObjectSP();
+ if (m_live_address != LLDB_INVALID_ADDRESS)
+ {
+ ClangASTType clang_type(m_impl_backend->GetClangType());
+
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&m_live_address,sizeof(lldb::addr_t)));
+
+ std::string new_name("&");
+ new_name.append(m_impl_backend->GetName().AsCString(""));
+ ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
+ m_address_of_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
+ clang_type.GetPointerType(),
+ ConstString(new_name.c_str()),
+ buffer,
+ lldb::endian::InlHostByteOrder(),
+ exe_ctx.GetAddressByteSize());
+
+ m_address_of_backend->GetValue().SetValueType(Value::eValueTypeScalar);
+ m_address_of_backend->GetValue().GetScalar() = m_live_address;
+
+ return m_address_of_backend;
+ }
+ else
+ return lldb::ValueObjectSP();
+}
+
+lldb::addr_t
+ValueObjectConstResultImpl::GetAddressOf (bool scalar_is_load_address,
+ AddressType *address_type)
+{
+
+ if (m_impl_backend == NULL)
+ return 0;
+
+ if (m_live_address == LLDB_INVALID_ADDRESS)
+ {
+ return m_impl_backend->ValueObject::GetAddressOf (scalar_is_load_address,
+ address_type);
+ }
+
+ if (address_type)
+ *address_type = m_live_address_type;
+
+ return m_live_address;
+}
+
+size_t
+ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
+ uint32_t item_idx,
+ uint32_t item_count)
+{
+ 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
new file mode 100644
index 000000000000..977cc4cd3132
--- /dev/null
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -0,0 +1,372 @@
+//===-- ValueObjectDynamicValue.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/ValueObjectDynamicValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent, lldb::DynamicValueType use_dynamic) :
+ ValueObject(parent),
+ m_address (),
+ m_dynamic_type_info(),
+ m_use_dynamic (use_dynamic)
+{
+ SetName (parent.GetName());
+}
+
+ValueObjectDynamicValue::~ValueObjectDynamicValue()
+{
+ m_owning_valobj_sp.reset();
+}
+
+ClangASTType
+ValueObjectDynamicValue::GetClangTypeImpl ()
+{
+ if (m_dynamic_type_info.HasTypeSP())
+ return m_value.GetClangType();
+ else
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectDynamicValue::GetTypeName()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success)
+ {
+ if (m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetConstTypeName();
+ if (m_dynamic_type_info.HasName())
+ return m_dynamic_type_info.GetName();
+ }
+ return m_parent->GetTypeName();
+}
+
+ConstString
+ValueObjectDynamicValue::GetQualifiedTypeName()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success)
+ {
+ if (m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetConstQualifiedTypeName ();
+ if (m_dynamic_type_info.HasName())
+ return m_dynamic_type_info.GetName();
+ }
+ return m_parent->GetTypeName();
+}
+
+size_t
+ValueObjectDynamicValue::CalculateNumChildren()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success && m_dynamic_type_info.HasTypeSP())
+ return GetClangType().GetNumChildren (true);
+ else
+ return m_parent->GetNumChildren();
+}
+
+uint64_t
+ValueObjectDynamicValue::GetByteSize()
+{
+ const bool success = UpdateValueIfNeeded(false);
+ if (success && m_dynamic_type_info.HasTypeSP())
+ return m_value.GetValueByteSize(NULL);
+ else
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectDynamicValue::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectDynamicValue::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded(false))
+ {
+ // The dynamic value failed to get an error, pass the error along
+ if (m_error.Success() && m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ return false;
+ }
+
+ // Setting our type_sp to NULL will route everything back through our
+ // parent which is equivalent to not using dynamic values.
+ if (m_use_dynamic == lldb::eNoDynamicValues)
+ {
+ m_dynamic_type_info.Clear();
+ return true;
+ }
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ // First make sure our Type and/or Address haven't changed:
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!process)
+ return false;
+
+ TypeAndOrName class_type_or_name;
+ Address dynamic_address;
+ bool found_dynamic_type = false;
+
+ lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
+ if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
+ if (runtime)
+ found_dynamic_type = runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+ }
+ else
+ {
+ LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
+ if (cpp_runtime)
+ found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+
+ if (!found_dynamic_type)
+ {
+ LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
+ if (objc_runtime)
+ found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address);
+ }
+ }
+
+ // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really
+ // don't...
+
+ m_update_point.SetUpdated();
+
+ // If we don't have a dynamic type, then make ourselves just a echo of our parent.
+ // Or we could return false, and make ourselves an echo of our parent?
+ if (!found_dynamic_type)
+ {
+ if (m_dynamic_type_info)
+ SetValueDidChange(true);
+ ClearDynamicTypeInformation();
+ m_dynamic_type_info.Clear();
+ m_value = m_parent->GetValue();
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ return m_error.Success();
+ }
+
+ Value old_value(m_value);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
+
+ bool has_changed_type = false;
+
+ if (!m_dynamic_type_info)
+ {
+ m_dynamic_type_info = class_type_or_name;
+ has_changed_type = true;
+ }
+ else if (class_type_or_name != m_dynamic_type_info)
+ {
+ // We are another type, we need to tear down our children...
+ m_dynamic_type_info = class_type_or_name;
+ SetValueDidChange (true);
+ has_changed_type = true;
+ }
+
+ if (has_changed_type)
+ ClearDynamicTypeInformation ();
+
+ if (!m_address.IsValid() || m_address != dynamic_address)
+ {
+ if (m_address.IsValid())
+ SetValueDidChange (true);
+
+ // We've moved, so we should be fine...
+ m_address = dynamic_address;
+ lldb::TargetSP target_sp (GetTargetSP());
+ lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
+ m_value.GetScalar() = load_address;
+ }
+
+ ClangASTType corrected_type;
+ if (m_dynamic_type_info.HasTypeSP())
+ {
+ // The type will always be the type of the dynamic object. If our parent's type was a pointer,
+ // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type
+ // should be okay...
+ ClangASTType orig_type = m_dynamic_type_info.GetTypeSP()->GetClangForwardType();
+ corrected_type = orig_type;
+ if (m_parent->IsPointerType())
+ corrected_type = orig_type.GetPointerType ();
+ else if (m_parent->IsPointerOrReferenceType())
+ corrected_type = orig_type.GetLValueReferenceType ();
+ }
+ else /*if (m_dynamic_type_info.HasName())*/
+ {
+ // If we are here we need to adjust our dynamic type name to include the correct & or * symbol
+ std::string type_name_buf (m_dynamic_type_info.GetName().GetCString());
+ if (m_parent->IsPointerType())
+ type_name_buf.append(" *");
+ else if (m_parent->IsPointerOrReferenceType())
+ type_name_buf.append(" &");
+ corrected_type = m_parent->GetClangType();
+ m_dynamic_type_info.SetName(type_name_buf.c_str());
+ }
+
+ //m_value.SetContext (Value::eContextTypeClangType, corrected_type);
+ m_value.SetClangType (corrected_type);
+
+ // Our address is the location of the dynamic type stored in memory. It isn't a load address,
+ // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us...
+ m_value.SetValueType(Value::eValueTypeScalar);
+
+ if (has_changed_type && log)
+ log->Printf("[%s %p] has a new dynamic type %s",
+ GetName().GetCString(),
+ this,
+ GetTypeName().GetCString());
+
+ if (m_address.IsValid() && m_dynamic_type_info)
+ {
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ if (m_error.Success())
+ {
+ if (GetClangType().IsAggregateType ())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+
+ SetValueIsValid (true);
+ return true;
+ }
+ }
+
+ // We get here if we've failed above...
+ SetValueIsValid (false);
+ return false;
+}
+
+
+
+bool
+ValueObjectDynamicValue::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
+bool
+ValueObjectDynamicValue::SetValueFromCString (const char *value_str, Error& error)
+{
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
+ uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
+
+ if (my_value == UINT64_MAX || parent_value == UINT64_MAX)
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ // if we are at an offset from our parent, in order to set ourselves correctly we would need
+ // to change the new value so that it refers to the correct dynamic type. we choose not to deal
+ // with that - if anything more than a value overwrite is required, you should be using the
+ // expression parser instead of the value editing facility
+ if (my_value != parent_value)
+ {
+ // but NULL'ing out a value should always be allowed
+ if (strcmp(value_str,"0"))
+ {
+ error.SetErrorString("unable to modify dynamic value, use 'expression' command");
+ return false;
+ }
+ }
+
+ bool ret_val = m_parent->SetValueFromCString(value_str,error);
+ SetNeedsUpdate();
+ return ret_val;
+}
+
+bool
+ValueObjectDynamicValue::SetData (DataExtractor &data, Error &error)
+{
+ if (!UpdateValueIfNeeded(false))
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
+ uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
+
+ if (my_value == UINT64_MAX || parent_value == UINT64_MAX)
+ {
+ error.SetErrorString("unable to read value");
+ return false;
+ }
+
+ // if we are at an offset from our parent, in order to set ourselves correctly we would need
+ // to change the new value so that it refers to the correct dynamic type. we choose not to deal
+ // with that - if anything more than a value overwrite is required, you should be using the
+ // expression parser instead of the value editing facility
+ if (my_value != parent_value)
+ {
+ // but NULL'ing out a value should always be allowed
+ lldb::offset_t offset = 0;
+
+ if (data.GetPointer(&offset) != 0)
+ {
+ error.SetErrorString("unable to modify dynamic value, use 'expression' command");
+ return false;
+ }
+ }
+
+ bool ret_val = m_parent->SetData(data, error);
+ SetNeedsUpdate();
+ return ret_val;
+}
diff --git a/source/Core/ValueObjectList.cpp b/source/Core/ValueObjectList.cpp
new file mode 100644
index 000000000000..180d4a0eaf12
--- /dev/null
+++ b/source/Core/ValueObjectList.cpp
@@ -0,0 +1,166 @@
+//===-- ValueObjectList.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/ValueObjectList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObjectChild.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectList::ValueObjectList () :
+ m_value_objects()
+{
+}
+
+ValueObjectList::ValueObjectList (const ValueObjectList &rhs) :
+ m_value_objects(rhs.m_value_objects)
+{
+}
+
+
+ValueObjectList::~ValueObjectList ()
+{
+}
+
+const ValueObjectList &
+ValueObjectList::operator = (const ValueObjectList &rhs)
+{
+ if (this != &rhs)
+ m_value_objects = rhs.m_value_objects;
+ return *this;
+}
+
+void
+ValueObjectList::Append (const ValueObjectSP &val_obj_sp)
+{
+ m_value_objects.push_back(val_obj_sp);
+}
+
+void
+ValueObjectList::Append (const ValueObjectList &valobj_list)
+{
+ std::copy(valobj_list.m_value_objects.begin(), // source begin
+ valobj_list.m_value_objects.end(), // source end
+ back_inserter(m_value_objects)); // destination
+
+}
+
+
+size_t
+ValueObjectList::GetSize() const
+{
+ return m_value_objects.size();
+}
+
+void
+ValueObjectList::Resize (size_t size)
+{
+ m_value_objects.resize (size);
+}
+
+lldb::ValueObjectSP
+ValueObjectList::GetValueObjectAtIndex (size_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ valobj_sp = m_value_objects[idx];
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP
+ValueObjectList::RemoveValueObjectAtIndex (size_t idx)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (idx < m_value_objects.size())
+ {
+ valobj_sp = m_value_objects[idx];
+ m_value_objects.erase (m_value_objects.begin() + idx);
+ }
+ return valobj_sp;
+}
+
+void
+ValueObjectList::SetValueObjectAtIndex (size_t idx, const ValueObjectSP &valobj_sp)
+{
+ if (idx >= m_value_objects.size())
+ m_value_objects.resize (idx + 1);
+ m_value_objects[idx] = valobj_sp;
+}
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByValueName (const char *name)
+{
+ ConstString name_const_str(name);
+ ValueObjectSP val_obj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj->GetName() == name_const_str)
+ {
+ val_obj_sp = *pos;
+ break;
+ }
+ }
+ return val_obj_sp;
+}
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByUID (lldb::user_id_t uid)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ // Watch out for NULL objects in our list as the list
+ // might get resized to a specific size and lazily filled in
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj->GetID() == uid)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+
+ValueObjectSP
+ValueObjectList::FindValueObjectByPointer (ValueObject *find_valobj)
+{
+ ValueObjectSP valobj_sp;
+ collection::iterator pos, end = m_value_objects.end();
+
+ for (pos = m_value_objects.begin(); pos != end; ++pos)
+ {
+ ValueObject *valobj = (*pos).get();
+ if (valobj && valobj == find_valobj)
+ {
+ valobj_sp = *pos;
+ break;
+ }
+ }
+ return valobj_sp;
+}
+
+void
+ValueObjectList::Swap (ValueObjectList &value_object_list)
+{
+ m_value_objects.swap (value_object_list.m_value_objects);
+}
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
new file mode 100644
index 000000000000..42fd0e8fffba
--- /dev/null
+++ b/source/Core/ValueObjectMemory.cpp
@@ -0,0 +1,275 @@
+//===-- ValueObjectMemory.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/ValueObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ValueObjectSP
+ValueObjectMemory::Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp)
+{
+ return (new ValueObjectMemory (exe_scope, name, address, type_sp))->GetSP();
+}
+
+ValueObjectSP
+ValueObjectMemory::Create (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type)
+{
+ return (new ValueObjectMemory (exe_scope, name, address, ast_type))->GetSP();
+}
+
+ValueObjectMemory::ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp) :
+ ValueObject(exe_scope),
+ m_address (address),
+ m_type_sp(type_sp),
+ m_clang_type()
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_type_sp.get() != NULL);
+ SetName (ConstString(name));
+ m_value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ TargetSP target_sp (GetTargetSP());
+ lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
+ if (load_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_address;
+ }
+ else
+ {
+ lldb::addr_t file_address = m_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ m_value.GetScalar() = file_address;
+ }
+ else
+ {
+ m_value.GetScalar() = m_address.GetOffset();
+ m_value.SetValueType (Value::eValueTypeScalar);
+ }
+ }
+}
+
+ValueObjectMemory::ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ const ClangASTType &ast_type) :
+ ValueObject(exe_scope),
+ m_address (address),
+ m_type_sp(),
+ m_clang_type(ast_type)
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_clang_type.GetASTContext());
+ assert (m_clang_type.GetOpaqueQualType());
+
+ TargetSP target_sp (GetTargetSP());
+
+ SetName (ConstString(name));
+// m_value.SetContext(Value::eContextTypeClangType, m_clang_type.GetOpaqueQualType());
+ m_value.SetClangType(m_clang_type);
+ lldb::addr_t load_address = m_address.GetLoadAddress (target_sp.get());
+ if (load_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_address;
+ }
+ else
+ {
+ lldb::addr_t file_address = m_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ m_value.GetScalar() = file_address;
+ }
+ else
+ {
+ m_value.GetScalar() = m_address.GetOffset();
+ m_value.SetValueType (Value::eValueTypeScalar);
+ }
+ }
+}
+
+ValueObjectMemory::~ValueObjectMemory()
+{
+}
+
+ClangASTType
+ValueObjectMemory::GetClangTypeImpl ()
+{
+ if (m_type_sp)
+ return m_type_sp->GetClangForwardType();
+ return m_clang_type;
+}
+
+ConstString
+ValueObjectMemory::GetTypeName()
+{
+ if (m_type_sp)
+ return m_type_sp->GetName();
+ return m_clang_type.GetConstTypeName();
+}
+
+size_t
+ValueObjectMemory::CalculateNumChildren()
+{
+ if (m_type_sp)
+ return m_type_sp->GetNumChildren(true);
+ const bool omit_empty_base_classes = true;
+ return m_clang_type.GetNumChildren (omit_empty_base_classes);
+}
+
+uint64_t
+ValueObjectMemory::GetByteSize()
+{
+ if (m_type_sp)
+ return m_type_sp->GetByteSize();
+ return m_clang_type.GetByteSize ();
+}
+
+lldb::ValueType
+ValueObjectMemory::GetValueType() const
+{
+ // RETHINK: Should this be inherited from somewhere?
+ return lldb::eValueTypeVariableGlobal;
+}
+
+bool
+ValueObjectMemory::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ Value old_value(m_value);
+ if (m_address.IsValid())
+ {
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ default:
+ assert(!"Unhandled expression result value kind...");
+ break;
+
+ case Value::eValueTypeScalar:
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ // The DWARF expression result was an address in the inferior
+ // process. If this variable is an aggregate type, we just need
+ // the address as the main value as all child variable objects
+ // will rely upon this location and add an offset and then read
+ // their own values as needed. If this variable is a simple
+ // type, we read all data for it into m_data.
+ // 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.
+ if (value_type == Value::eValueTypeFileAddress && exe_ctx.GetProcessPtr())
+ {
+ lldb::addr_t load_addr = m_address.GetLoadAddress(target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_addr;
+ }
+ }
+
+ if (GetClangType().IsAggregateType())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ else
+ {
+ // Copy the Value and set the context to use our Variable
+ // so it can extract read its value into m_data appropriately
+ Value value(m_value);
+ if (m_type_sp)
+ value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ else
+ {
+ //value.SetContext(Value::eContextTypeClangType, m_clang_type.GetOpaqueQualType());
+ value.SetClangType(m_clang_type);
+ }
+
+ m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+ return m_error.Success();
+}
+
+
+
+bool
+ValueObjectMemory::IsInScope ()
+{
+ // FIXME: Maybe try to read the memory address, and if that works, then
+ // we are in scope?
+ return true;
+}
+
+
+lldb::ModuleSP
+ValueObjectMemory::GetModule()
+{
+ return m_address.GetModule();
+}
+
+
diff --git a/source/Core/ValueObjectRegister.cpp b/source/Core/ValueObjectRegister.cpp
new file mode 100644
index 000000000000..4f21457519ec
--- /dev/null
+++ b/source/Core/ValueObjectRegister.cpp
@@ -0,0 +1,431 @@
+//===-- ValueObjectRegister.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/ValueObjectRegister.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark ValueObjectRegisterContext
+
+ValueObjectRegisterContext::ValueObjectRegisterContext (ValueObject &parent, RegisterContextSP &reg_ctx) :
+ ValueObject (parent),
+ m_reg_ctx_sp (reg_ctx)
+{
+ assert (reg_ctx);
+ m_name.SetCString("Registers");
+ SetValueIsValid (true);
+}
+
+ValueObjectRegisterContext::~ValueObjectRegisterContext()
+{
+}
+
+ClangASTType
+ValueObjectRegisterContext::GetClangTypeImpl ()
+{
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectRegisterContext::GetTypeName()
+{
+ return ConstString();
+}
+
+ConstString
+ValueObjectRegisterContext::GetQualifiedTypeName()
+{
+ return ConstString();
+}
+
+size_t
+ValueObjectRegisterContext::CalculateNumChildren()
+{
+ return m_reg_ctx_sp->GetRegisterSetCount();
+}
+
+uint64_t
+ValueObjectRegisterContext::GetByteSize()
+{
+ return 0;
+}
+
+bool
+ValueObjectRegisterContext::UpdateValue ()
+{
+ m_error.Clear();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ m_reg_ctx_sp = frame->GetRegisterContext();
+ else
+ m_reg_ctx_sp.reset();
+
+ if (m_reg_ctx_sp.get() == NULL)
+ {
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError();
+ }
+ else
+ SetValueIsValid (true);
+
+ return m_error.Success();
+}
+
+ValueObject *
+ValueObjectRegisterContext::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *new_valobj = NULL;
+
+ const size_t num_children = GetNumChildren();
+ if (idx < num_children)
+ {
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ new_valobj = new ValueObjectRegisterSet(exe_ctx.GetBestExecutionContextScope(), m_reg_ctx_sp, idx);
+ }
+
+ return new_valobj;
+}
+
+
+#pragma mark -
+#pragma mark ValueObjectRegisterSet
+
+ValueObjectSP
+ValueObjectRegisterSet::Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t set_idx)
+{
+ return (new ValueObjectRegisterSet (exe_scope, reg_ctx_sp, set_idx))->GetSP();
+}
+
+
+ValueObjectRegisterSet::ValueObjectRegisterSet (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx, uint32_t reg_set_idx) :
+ ValueObject (exe_scope),
+ m_reg_ctx_sp (reg_ctx),
+ m_reg_set (NULL),
+ m_reg_set_idx (reg_set_idx)
+{
+ assert (reg_ctx);
+ m_reg_set = reg_ctx->GetRegisterSet(m_reg_set_idx);
+ if (m_reg_set)
+ {
+ m_name.SetCString (m_reg_set->name);
+ }
+}
+
+ValueObjectRegisterSet::~ValueObjectRegisterSet()
+{
+}
+
+ClangASTType
+ValueObjectRegisterSet::GetClangTypeImpl ()
+{
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectRegisterSet::GetTypeName()
+{
+ return ConstString();
+}
+
+ConstString
+ValueObjectRegisterSet::GetQualifiedTypeName()
+{
+ return ConstString();
+}
+
+size_t
+ValueObjectRegisterSet::CalculateNumChildren()
+{
+ const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet(m_reg_set_idx);
+ if (reg_set)
+ return reg_set->num_registers;
+ return 0;
+}
+
+uint64_t
+ValueObjectRegisterSet::GetByteSize()
+{
+ return 0;
+}
+
+bool
+ValueObjectRegisterSet::UpdateValue ()
+{
+ m_error.Clear();
+ SetValueDidChange (false);
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ m_reg_ctx_sp.reset();
+ else
+ {
+ m_reg_ctx_sp = frame->GetRegisterContext ();
+ if (m_reg_ctx_sp)
+ {
+ const RegisterSet *reg_set = m_reg_ctx_sp->GetRegisterSet (m_reg_set_idx);
+ if (reg_set == NULL)
+ m_reg_ctx_sp.reset();
+ else if (m_reg_set != reg_set)
+ {
+ SetValueDidChange (true);
+ m_name.SetCString(reg_set->name);
+ }
+ }
+ }
+ if (m_reg_ctx_sp)
+ {
+ SetValueIsValid (true);
+ }
+ else
+ {
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError ();
+ m_children.Clear();
+ }
+ return m_error.Success();
+}
+
+
+ValueObject *
+ValueObjectRegisterSet::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
+{
+ ValueObject *valobj = NULL;
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const size_t num_children = GetNumChildren();
+ if (idx < num_children)
+ valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, m_reg_set->registers[idx]);
+ }
+ return valobj;
+}
+
+lldb::ValueObjectSP
+ValueObjectRegisterSet::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ ValueObject *valobj = NULL;
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName (name.AsCString());
+ if (reg_info != NULL)
+ valobj = new ValueObjectRegister(*this, m_reg_ctx_sp, reg_info->kinds[eRegisterKindLLDB]);
+ }
+ if (valobj)
+ return valobj->GetSP();
+ else
+ return ValueObjectSP();
+}
+
+size_t
+ValueObjectRegisterSet::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (m_reg_ctx_sp && m_reg_set)
+ {
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoByName (name.AsCString());
+ if (reg_info != NULL)
+ return reg_info->kinds[eRegisterKindLLDB];
+ }
+ return UINT32_MAX;
+}
+
+#pragma mark -
+#pragma mark ValueObjectRegister
+
+void
+ValueObjectRegister::ConstructObject (uint32_t reg_num)
+{
+ const RegisterInfo *reg_info = m_reg_ctx_sp->GetRegisterInfoAtIndex (reg_num);
+ if (reg_info)
+ {
+ m_reg_info = *reg_info;
+ if (reg_info->name)
+ m_name.SetCString(reg_info->name);
+ else if (reg_info->alt_name)
+ m_name.SetCString(reg_info->alt_name);
+ }
+}
+
+ValueObjectRegister::ValueObjectRegister (ValueObject &parent, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num) :
+ ValueObject (parent),
+ m_reg_ctx_sp (reg_ctx_sp),
+ m_reg_info (),
+ m_reg_value (),
+ m_type_name (),
+ m_clang_type ()
+{
+ assert (reg_ctx_sp.get());
+ ConstructObject(reg_num);
+}
+
+ValueObjectSP
+ValueObjectRegister::Create (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx_sp, uint32_t reg_num)
+{
+ return (new ValueObjectRegister (exe_scope, reg_ctx_sp, reg_num))->GetSP();
+}
+
+ValueObjectRegister::ValueObjectRegister (ExecutionContextScope *exe_scope, lldb::RegisterContextSP &reg_ctx, uint32_t reg_num) :
+ ValueObject (exe_scope),
+ m_reg_ctx_sp (reg_ctx),
+ m_reg_info (),
+ m_reg_value (),
+ m_type_name (),
+ m_clang_type ()
+{
+ assert (reg_ctx);
+ ConstructObject(reg_num);
+}
+
+ValueObjectRegister::~ValueObjectRegister()
+{
+}
+
+ClangASTType
+ValueObjectRegister::GetClangTypeImpl ()
+{
+ if (!m_clang_type.IsValid())
+ {
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ Module *exe_module = target->GetExecutableModulePointer();
+ if (exe_module)
+ {
+ m_clang_type = exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize (m_reg_info.encoding,
+ m_reg_info.byte_size * 8);
+ }
+ }
+ }
+ return m_clang_type;
+}
+
+ConstString
+ValueObjectRegister::GetTypeName()
+{
+ if (m_type_name.IsEmpty())
+ m_type_name = GetClangType().GetConstTypeName ();
+ return m_type_name;
+}
+
+size_t
+ValueObjectRegister::CalculateNumChildren()
+{
+ return GetClangType().GetNumChildren(true);
+}
+
+uint64_t
+ValueObjectRegister::GetByteSize()
+{
+ return m_reg_info.byte_size;
+}
+
+bool
+ValueObjectRegister::UpdateValue ()
+{
+ m_error.Clear();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ {
+ m_reg_ctx_sp.reset();
+ m_reg_value.Clear();
+ }
+
+
+ if (m_reg_ctx_sp)
+ {
+ if (m_reg_ctx_sp->ReadRegister (&m_reg_info, m_reg_value))
+ {
+ if (m_reg_value.GetData (m_data))
+ {
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ m_data.SetAddressByteSize(process->GetAddressByteSize());
+ m_value.SetContext(Value::eContextTypeRegisterInfo, (void *)&m_reg_info);
+ m_value.SetValueType(Value::eValueTypeHostAddress);
+ m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+ SetValueIsValid (true);
+ return true;
+ }
+ }
+ }
+
+ SetValueIsValid (false);
+ m_error.SetErrorToGenericError ();
+ return false;
+}
+
+bool
+ValueObjectRegister::SetValueFromCString (const char *value_str, Error& error)
+{
+ // The new value will be in the m_data. Copy that into our register value.
+ error = m_reg_value.SetValueFromCString (&m_reg_info, value_str);
+ if (error.Success())
+ {
+ if (m_reg_ctx_sp->WriteRegister (&m_reg_info, m_reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+bool
+ValueObjectRegister::SetData (DataExtractor &data, Error &error)
+{
+ error = m_reg_value.SetValueFromData(&m_reg_info, data, 0, false);
+ if (error.Success())
+ {
+ if (m_reg_ctx_sp->WriteRegister (&m_reg_info, m_reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+bool
+ValueObjectRegister::ResolveValue (Scalar &scalar)
+{
+ if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything
+ return m_reg_value.GetScalarValue(scalar);
+ return false;
+}
+
+void
+ValueObjectRegister::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
+{
+ s.Printf("$%s", m_reg_info.name);
+}
+
+
diff --git a/source/Core/ValueObjectSyntheticFilter.cpp b/source/Core/ValueObjectSyntheticFilter.cpp
new file mode 100644
index 000000000000..522ca082a691
--- /dev/null
+++ b/source/Core/ValueObjectSyntheticFilter.cpp
@@ -0,0 +1,270 @@
+//===-- ValueObjectSyntheticFilter.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Core/ValueObjectSyntheticFilter.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+
+using namespace lldb_private;
+
+class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd
+{
+public:
+ DummySyntheticFrontEnd(ValueObject &backend) :
+ SyntheticChildrenFrontEnd(backend)
+ {}
+
+ size_t
+ CalculateNumChildren()
+ {
+ return 0;
+ }
+
+ lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ return lldb::ValueObjectSP();
+ }
+
+ size_t
+ GetIndexOfChildWithName (const ConstString &name)
+ {
+ return UINT32_MAX;
+ }
+
+ bool
+ MightHaveChildren ()
+ {
+ return true;
+ }
+
+ bool
+ Update()
+ {
+ return false;
+ }
+
+};
+
+ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter) :
+ ValueObject(parent),
+ m_synth_sp(filter),
+ m_children_byindex(),
+ m_name_toindex(),
+ m_synthetic_children_count(UINT32_MAX),
+ m_parent_type_name(parent.GetTypeName()),
+ m_might_have_children(eLazyBoolCalculate)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ std::string new_name(parent.GetName().AsCString());
+ new_name += "$$__synth__";
+ SetName (ConstString(new_name.c_str()));
+#else
+ SetName(parent.GetName());
+#endif
+ CopyParentData();
+ CreateSynthFilter();
+}
+
+ValueObjectSynthetic::~ValueObjectSynthetic()
+{
+}
+
+ClangASTType
+ValueObjectSynthetic::GetClangTypeImpl ()
+{
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectSynthetic::GetTypeName()
+{
+ return m_parent->GetTypeName();
+}
+
+ConstString
+ValueObjectSynthetic::GetQualifiedTypeName()
+{
+ return m_parent->GetQualifiedTypeName();
+}
+
+size_t
+ValueObjectSynthetic::CalculateNumChildren()
+{
+ UpdateValueIfNeeded();
+ if (m_synthetic_children_count < UINT32_MAX)
+ return m_synthetic_children_count;
+ return (m_synthetic_children_count = m_synth_filter_ap->CalculateNumChildren());
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetDynamicValue (lldb::DynamicValueType valueType)
+{
+ if (!m_parent)
+ return lldb::ValueObjectSP();
+ if (IsDynamic() && GetDynamicValueType() == valueType)
+ return GetSP();
+ return m_parent->GetDynamicValue(valueType);
+}
+
+bool
+ValueObjectSynthetic::MightHaveChildren()
+{
+ if (m_might_have_children == eLazyBoolCalculate)
+ m_might_have_children = (m_synth_filter_ap->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
+ return (m_might_have_children == eLazyBoolNo ? false : true);
+}
+
+uint64_t
+ValueObjectSynthetic::GetByteSize()
+{
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectSynthetic::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+void
+ValueObjectSynthetic::CreateSynthFilter ()
+{
+ m_synth_filter_ap = (m_synth_sp->GetFrontEnd(*m_parent));
+ if (!m_synth_filter_ap.get())
+ m_synth_filter_ap.reset(new DummySyntheticFrontEnd(*m_parent));
+}
+
+bool
+ValueObjectSynthetic::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded(false))
+ {
+ // our parent could not update.. as we are meaningless without a parent, just stop
+ if (m_parent->GetError().Fail())
+ m_error = m_parent->GetError();
+ return false;
+ }
+
+ // regenerate the synthetic filter if our typename changes
+ // <rdar://problem/12424824>
+ ConstString new_parent_type_name = m_parent->GetTypeName();
+ if (new_parent_type_name != m_parent_type_name)
+ {
+ m_parent_type_name = new_parent_type_name;
+ CreateSynthFilter();
+ }
+
+ // let our backend do its update
+ if (m_synth_filter_ap->Update() == false)
+ {
+ // filter said that cached values are stale
+ 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
+ m_children_count_valid = false;
+ m_synthetic_children_count = UINT32_MAX;
+ m_might_have_children = eLazyBoolCalculate;
+ }
+
+ CopyParentData();
+
+ SetValueIsValid(true);
+ return true;
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetChildAtIndex (size_t idx, bool can_create)
+{
+ UpdateValueIfNeeded();
+
+ ByIndexIterator iter = m_children_byindex.find(idx);
+
+ if (iter == m_children_byindex.end())
+ {
+ 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();
+ return synth_guy;
+ }
+ else
+ return lldb::ValueObjectSP();
+ }
+ else
+ return iter->second->GetSP();
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create)
+{
+ UpdateValueIfNeeded();
+
+ uint32_t index = GetIndexOfChildWithName(name);
+
+ if (index == UINT32_MAX)
+ return lldb::ValueObjectSP();
+
+ return GetChildAtIndex(index, can_create);
+}
+
+size_t
+ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
+{
+ UpdateValueIfNeeded();
+
+ NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
+
+ if (iter == m_name_toindex.end() && 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;
+ return index;
+ }
+ else if (iter == m_name_toindex.end() && m_synth_filter_ap.get() == NULL)
+ return UINT32_MAX;
+ else /*if (iter != m_name_toindex.end())*/
+ return iter->second;
+}
+
+bool
+ValueObjectSynthetic::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
+lldb::ValueObjectSP
+ValueObjectSynthetic::GetNonSyntheticValue ()
+{
+ return m_parent->GetSP();
+}
+
+void
+ValueObjectSynthetic::CopyParentData ()
+{
+ m_value = m_parent->GetValue();
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+}
diff --git a/source/Core/ValueObjectVariable.cpp b/source/Core/ValueObjectVariable.cpp
new file mode 100644
index 000000000000..38c0d91324ad
--- /dev/null
+++ b/source/Core/ValueObjectVariable.cpp
@@ -0,0 +1,386 @@
+//===-- ValueObjectVariable.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/ValueObjectVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb_private;
+
+lldb::ValueObjectSP
+ValueObjectVariable::Create (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp)
+{
+ return (new ValueObjectVariable (exe_scope, var_sp))->GetSP();
+}
+
+ValueObjectVariable::ValueObjectVariable (ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp) :
+ ValueObject(exe_scope),
+ m_variable_sp(var_sp)
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_variable_sp.get() != NULL);
+ m_name = var_sp->GetName();
+}
+
+ValueObjectVariable::~ValueObjectVariable()
+{
+}
+
+ClangASTType
+ValueObjectVariable::GetClangTypeImpl ()
+{
+ Type *var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetClangForwardType();
+ return ClangASTType();
+}
+
+ConstString
+ValueObjectVariable::GetTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetName();
+ return ConstString();
+}
+
+ConstString
+ValueObjectVariable::GetQualifiedTypeName()
+{
+ Type * var_type = m_variable_sp->GetType();
+ if (var_type)
+ return var_type->GetQualifiedName();
+ return ConstString();
+}
+
+size_t
+ValueObjectVariable::CalculateNumChildren()
+{
+ ClangASTType type(GetClangType());
+
+ if (!type.IsValid())
+ return 0;
+
+ const bool omit_empty_base_classes = true;
+ return type.GetNumChildren(omit_empty_base_classes);
+}
+
+uint64_t
+ValueObjectVariable::GetByteSize()
+{
+ ClangASTType type(GetClangType());
+
+ if (!type.IsValid())
+ return 0;
+
+ return type.GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectVariable::GetValueType() const
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetScope();
+ return lldb::eValueTypeInvalid;
+}
+
+bool
+ValueObjectVariable::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ Variable *variable = m_variable_sp.get();
+ DWARFExpression &expr = variable->LocationExpression();
+
+ if (variable->GetLocationIsConstantValueData())
+ {
+ // expr doesn't contain DWARF bytes, it contains the constant variable
+ // value bytes themselves...
+ if (expr.GetExpressionData(m_data))
+ m_value.SetContext(Value::eContextTypeVariable, variable);
+ else
+ m_error.SetErrorString ("empty constant data");
+ // constant bytes can't be edited - sorry
+ m_resolved_value.SetContext(Value::eContextTypeInvalid, NULL);
+ }
+ else
+ {
+ lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;
+ ExecutionContext exe_ctx (GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
+ }
+
+ if (expr.IsLocationList())
+ {
+ SymbolContext sc;
+ variable->CalculateSymbolContext (&sc);
+ if (sc.function)
+ loclist_base_load_addr = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (target);
+ }
+ Value old_value(m_value);
+ if (expr.Evaluate (&exe_ctx, NULL, NULL, NULL, loclist_base_load_addr, NULL, m_value, &m_error))
+ {
+ m_resolved_value = m_value;
+ m_value.SetContext(Value::eContextTypeVariable, variable);
+
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ case Value::eValueTypeFileAddress:
+ SetAddressTypeOfChildren(eAddressTypeFile);
+ break;
+ case Value::eValueTypeHostAddress:
+ SetAddressTypeOfChildren(eAddressTypeHost);
+ break;
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ SetAddressTypeOfChildren(eAddressTypeLoad);
+ break;
+ }
+
+ switch (value_type)
+ {
+ case Value::eValueTypeVector:
+ // fall through
+ case Value::eValueTypeScalar:
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get());
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ // The DWARF expression result was an address in the inferior
+ // process. If this variable is an aggregate type, we just need
+ // the address as the main value as all child variable objects
+ // will rely upon this location and add an offset and then read
+ // their own values as needed. If this variable is a simple
+ // type, we read all data for it into m_data.
+ // 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())
+ {
+ lldb::addr_t file_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ if (file_addr != LLDB_INVALID_ADDRESS)
+ {
+ SymbolContext var_sc;
+ variable->CalculateSymbolContext(&var_sc);
+ if (var_sc.module_sp)
+ {
+ ObjectFile *objfile = var_sc.module_sp->GetObjectFile();
+ if (objfile)
+ {
+ Address so_addr(file_addr, objfile->GetSectionList());
+ lldb::addr_t load_addr = so_addr.GetLoadAddress (target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_addr;
+ }
+ }
+ }
+ }
+ }
+
+ if (GetClangType().IsAggregateType())
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ else
+ {
+ // Copy the Value and set the context to use our Variable
+ // so it can extract read its value into m_data appropriately
+ Value value(m_value);
+ value.SetContext(Value::eContextTypeVariable, variable);
+ m_error = value.GetValueAsData(&exe_ctx, m_data, 0, GetModule().get());
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+ else
+ {
+ // could not find location, won't allow editing
+ m_resolved_value.SetContext(Value::eContextTypeInvalid, NULL);
+ }
+ }
+ return m_error.Success();
+}
+
+
+
+bool
+ValueObjectVariable::IsInScope ()
+{
+ const ExecutionContextRef &exe_ctx_ref = GetExecutionContextRef();
+ if (exe_ctx_ref.HasFrameRef())
+ {
+ ExecutionContext exe_ctx (exe_ctx_ref);
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ {
+ return m_variable_sp->IsInScope (frame);
+ }
+ else
+ {
+ // This ValueObject had a frame at one time, but now we
+ // can't locate it, so return false since we probably aren't
+ // in scope.
+ return false;
+ }
+ }
+ // We have a variable that wasn't tied to a frame, which
+ // means it is a global and is always in scope.
+ return true;
+
+}
+
+lldb::ModuleSP
+ValueObjectVariable::GetModule()
+{
+ if (m_variable_sp)
+ {
+ SymbolContextScope *sc_scope = m_variable_sp->GetSymbolContextScope();
+ if (sc_scope)
+ {
+ return sc_scope->CalculateSymbolContextModule();
+ }
+ }
+ return lldb::ModuleSP();
+}
+
+SymbolContextScope *
+ValueObjectVariable::GetSymbolContextScope()
+{
+ if (m_variable_sp)
+ return m_variable_sp->GetSymbolContextScope();
+ return NULL;
+}
+
+bool
+ValueObjectVariable::GetDeclaration (Declaration &decl)
+{
+ if (m_variable_sp)
+ {
+ decl = m_variable_sp->GetDeclaration();
+ return true;
+ }
+ return false;
+}
+
+const char *
+ValueObjectVariable::GetLocationAsCString ()
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ return GetLocationAsCStringImpl(m_resolved_value,
+ m_data);
+ else
+ return ValueObject::GetLocationAsCString();
+}
+
+bool
+ValueObjectVariable::SetValueFromCString (const char *value_str, Error& error)
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ RegisterValue reg_value;
+ if (!reg_info || !reg_ctx)
+ {
+ error.SetErrorString("unable to retrieve register info");
+ return false;
+ }
+ error = reg_value.SetValueFromCString(reg_info, value_str);
+ if (error.Fail())
+ return false;
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ {
+ error.SetErrorString("unable to write back to register");
+ return false;
+ }
+ }
+ else
+ return ValueObject::SetValueFromCString(value_str, error);
+}
+
+bool
+ValueObjectVariable::SetData (DataExtractor &data, Error &error)
+{
+ if (m_resolved_value.GetContextType() == Value::eContextTypeRegisterInfo)
+ {
+ RegisterInfo *reg_info = m_resolved_value.GetRegisterInfo();
+ ExecutionContext exe_ctx(GetExecutionContextRef());
+ RegisterContext *reg_ctx = exe_ctx.GetRegisterContext();
+ RegisterValue reg_value;
+ if (!reg_info || !reg_ctx)
+ {
+ error.SetErrorString("unable to retrieve register info");
+ return false;
+ }
+ error = reg_value.SetValueFromData(reg_info, data, 0, false);
+ if (error.Fail())
+ return false;
+ if (reg_ctx->WriteRegister (reg_info, reg_value))
+ {
+ SetNeedsUpdate();
+ return true;
+ }
+ else
+ {
+ error.SetErrorString("unable to write back to register");
+ return false;
+ }
+ }
+ else
+ return ValueObject::SetData(data, error);
+}
diff --git a/source/DataFormatters/CF.cpp b/source/DataFormatters/CF.cpp
new file mode 100644
index 000000000000..a4b7a1235ffa
--- /dev/null
+++ b/source/DataFormatters/CF.cpp
@@ -0,0 +1,299 @@
+//===-- CF.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool
+lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ time_t epoch = GetOSXEpoch();
+ epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
+ tm *tm_date = localtime(&epoch);
+ if (!tm_date)
+ return false;
+ std::string buffer(1024,0);
+ if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
+ return false;
+ stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
+ return true;
+}
+
+bool
+lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok = false; // check to see if this is a CFBag we know about
+ if (descriptor->IsCFType())
+ {
+ ConstString type_name(valobj.GetTypeName());
+ if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag"))
+ {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (is_type_ok == false)
+ {
+ StackFrameSP frame_sp(valobj.GetFrameSP());
+ if (!frame_sp)
+ return false;
+ ValueObjectSP count_sp;
+ StreamString expr;
+ expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
+ if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
+ return false;
+ if (!count_sp)
+ return false;
+ count = count_sp->GetValueAsUnsigned(0);
+ }
+ else
+ {
+ uint32_t offset = 2*ptr_size+4 + valobj_addr;
+ Error error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ stream.Printf("@\"%u value%s\"",
+ count,(count == 1 ? "" : "s"));
+ return true;
+}
+
+bool
+lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok = false; // check to see if this is a CFBag we know about
+ if (descriptor->IsCFType())
+ {
+ ConstString type_name(valobj.GetTypeName());
+ if (type_name == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef"))
+ {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (is_type_ok == false)
+ return false;
+
+ Error error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
+ addr_t data_ptr = process_sp->ReadPointerFromMemory(valobj_addr+2*ptr_size+2*ptr_size, error);
+ if (error.Fail())
+ return false;
+ // make sure we do not try to read huge amounts of data
+ if (num_bytes > 1024)
+ num_bytes = 1024;
+ DataBufferSP buffer_sp(new DataBufferHeap(num_bytes,0));
+ num_bytes = process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
+ if (error.Fail() || num_bytes == 0)
+ return false;
+ uint8_t *bytes = buffer_sp->GetBytes();
+ for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
+ {
+ uint8_t byte = bytes[byte_idx];
+ bool bit0 = (byte & 1) == 1;
+ bool bit1 = (byte & 2) == 2;
+ bool bit2 = (byte & 4) == 4;
+ bool bit3 = (byte & 8) == 8;
+ bool bit4 = (byte & 16) == 16;
+ bool bit5 = (byte & 32) == 32;
+ bool bit6 = (byte & 64) == 64;
+ bool bit7 = (byte & 128) == 128;
+ stream.Printf("%c%c%c%c %c%c%c%c ",
+ (bit7 ? '1' : '0'),
+ (bit6 ? '1' : '0'),
+ (bit5 ? '1' : '0'),
+ (bit4 ? '1' : '0'),
+ (bit3 ? '1' : '0'),
+ (bit2 ? '1' : '0'),
+ (bit1 ? '1' : '0'),
+ (bit0 ? '1' : '0'));
+ count -= 8;
+ }
+ {
+ // print the last byte ensuring we do not print spurious bits
+ uint8_t byte = bytes[num_bytes-1];
+ bool bit0 = (byte & 1) == 1;
+ bool bit1 = (byte & 2) == 2;
+ bool bit2 = (byte & 4) == 4;
+ bool bit3 = (byte & 8) == 8;
+ bool bit4 = (byte & 16) == 16;
+ bool bit5 = (byte & 32) == 32;
+ bool bit6 = (byte & 64) == 64;
+ bool bit7 = (byte & 128) == 128;
+ if (count)
+ {
+ stream.Printf("%c",bit7 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit6 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit5 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit4 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit3 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit2 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ {
+ stream.Printf("%c",bit1 ? '1' : '0');
+ count -= 1;
+ }
+ if (count)
+ stream.Printf("%c",bit0 ? '1' : '0');
+ }
+ return true;
+}
+
+bool
+lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint32_t count = 0;
+
+ bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about
+ if (descriptor->IsCFType())
+ {
+ ConstString type_name(valobj.GetTypeName());
+ if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap"))
+ {
+ if (valobj.IsPointerType())
+ is_type_ok = true;
+ }
+ }
+
+ if (is_type_ok == false)
+ {
+ StackFrameSP frame_sp(valobj.GetFrameSP());
+ if (!frame_sp)
+ return false;
+ ValueObjectSP count_sp;
+ StreamString expr;
+ expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
+ if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted)
+ return false;
+ if (!count_sp)
+ return false;
+ count = count_sp->GetValueAsUnsigned(0);
+ }
+ else
+ {
+ uint32_t offset = 2*ptr_size;
+ Error error;
+ count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ stream.Printf("@\"%u item%s\"",
+ count,(count == 1 ? "" : "s"));
+ return true;
+}
diff --git a/source/DataFormatters/CXXFormatterFunctions.cpp b/source/DataFormatters/CXXFormatterFunctions.cpp
new file mode 100644
index 000000000000..fba92170d832
--- /dev/null
+++ b/source/DataFormatters/CXXFormatterFunctions.cpp
@@ -0,0 +1,1351 @@
+//===-- CXXFormatterFunctions.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 "llvm/Support/ConvertUTF.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool
+lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
+ const char* target_type,
+ const char* selector,
+ uint64_t &value)
+{
+ if (!target_type || !*target_type)
+ return false;
+ if (!selector || !*selector)
+ return false;
+ StreamString expr;
+ expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+ lldb::ValueObjectSP result_sp;
+ Target* target = exe_ctx.GetTargetPtr();
+ StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ if (!target || !stack_frame)
+ return false;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true);
+
+ target->EvaluateExpression(expr.GetData(),
+ stack_frame,
+ result_sp,
+ options);
+ if (!result_sp)
+ return false;
+ value = result_sp->GetValueAsUnsigned(0);
+ return true;
+}
+
+bool
+lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
+ const char* target_type,
+ const char* selector,
+ Stream &stream)
+{
+ if (!target_type || !*target_type)
+ return false;
+ if (!selector || !*selector)
+ return false;
+ StreamString expr;
+ expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+ lldb::ValueObjectSP result_sp;
+ Target* target = exe_ctx.GetTargetPtr();
+ StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ if (!target || !stack_frame)
+ return false;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+
+ target->EvaluateExpression(expr.GetData(),
+ stack_frame,
+ result_sp,
+ options);
+ if (!result_sp)
+ return false;
+ stream.Printf("%s",result_sp->GetSummaryAsCString());
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
+ const char* return_type,
+ const char* selector,
+ uint64_t index)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (!return_type || !*return_type)
+ return valobj_sp;
+ if (!selector || !*selector)
+ return valobj_sp;
+ StreamString expr_path_stream;
+ valobj.GetExpressionPath(expr_path_stream, false);
+ StreamString expr;
+ expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+ lldb::ValueObjectSP result_sp;
+ Target* target = exe_ctx.GetTargetPtr();
+ StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ if (!target || !stack_frame)
+ return valobj_sp;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+
+ target->EvaluateExpression(expr.GetData(),
+ stack_frame,
+ valobj_sp,
+ options);
+ return valobj_sp;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
+ const char* return_type,
+ const char* selector,
+ const char* key)
+{
+ lldb::ValueObjectSP valobj_sp;
+ if (!return_type || !*return_type)
+ return valobj_sp;
+ if (!selector || !*selector)
+ return valobj_sp;
+ if (!key || !*key)
+ return valobj_sp;
+ StreamString expr_path_stream;
+ valobj.GetExpressionPath(expr_path_stream, false);
+ StreamString expr;
+ expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+ lldb::ValueObjectSP result_sp;
+ Target* target = exe_ctx.GetTargetPtr();
+ StackFrame* stack_frame = exe_ctx.GetFramePtr();
+ if (!target || !stack_frame)
+ return valobj_sp;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+
+ target->EvaluateExpression(expr.GetData(),
+ stack_frame,
+ valobj_sp,
+ options);
+ 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)
+{
+ 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; 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)
+ {
+ 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;
+ }
+ 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)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
+ options.SetLocation(valobj_addr);
+ options.SetConversionFunction(ConvertUTF16toUTF8);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('u');
+
+ if (!ReadUTFBufferAndDumpToStream(options))
+ {
+ stream.Printf("Summary Unavailable");
+ return true;
+ }
+
+ return true;
+}
+
+bool
+lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
+ options.SetLocation(valobj_addr);
+ options.SetConversionFunction(ConvertUTF32toUTF8);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('U');
+
+ if (!ReadUTFBufferAndDumpToStream(options))
+ {
+ stream.Printf("Summary Unavailable");
+ return true;
+ }
+
+ return true;
+}
+
+bool
+lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ lldb::addr_t data_addr = 0;
+
+ if (valobj.IsPointerType())
+ data_addr = valobj.GetValueAsUnsigned(0);
+ else if (valobj.IsArrayType())
+ data_addr = valobj.GetAddressOf();
+
+ if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
+ 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();
+
+ 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);
+ }
+ 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);
+ }
+ 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);
+ }
+ default:
+ stream.Printf("size for wchar_t is not valid");
+ return true;
+ }
+ return true;
+}
+
+bool
+lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ DataExtractor data;
+ valobj.GetData(data);
+
+ std::string value;
+ valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
+ if (!value.empty())
+ stream.Printf("%s ", value.c_str());
+
+ return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
+}
+
+bool
+lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ DataExtractor data;
+ valobj.GetData(data);
+
+ std::string value;
+ valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
+ if (!value.empty())
+ stream.Printf("%s ", value.c_str());
+
+ return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
+}
+
+bool
+lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ DataExtractor data;
+ valobj.GetData(data);
+
+ 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;
+
+ 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;
+}
+
+// the field layout in a libc++ string (cap, side, data or data, size, cap)
+enum LibcxxStringLayoutMode
+{
+ eLibcxxStringLayoutModeCSD = 0,
+ eLibcxxStringLayoutModeDSC = 1,
+ eLibcxxStringLayoutModeInvalid = 0xffff
+};
+
+// this function abstracts away the layout and mode details of a libc++ string
+// and returns the address of the data and the size ready for callers to consume
+static bool
+ExtractLibcxxStringInfo (ValueObject& valobj,
+ ValueObjectSP &location_sp,
+ uint64_t& size)
+{
+ ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
+ if (!D)
+ return false;
+
+ ValueObjectSP layout_decider(D->GetChildAtIndexPath({0,0}));
+
+ // this child should exist
+ if (!layout_decider)
+ return false;
+
+ ConstString g_data_name("__data_");
+ ConstString g_size_name("__size_");
+ bool short_mode = false; // this means the string is in short-mode and the data is stored inline
+ LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) ? eLibcxxStringLayoutModeDSC : eLibcxxStringLayoutModeCSD;
+ uint64_t size_mode_value = 0;
+
+ if (layout == eLibcxxStringLayoutModeDSC)
+ {
+ ValueObjectSP size_mode(D->GetChildAtIndexPath({1,1,0}));
+ if (!size_mode)
+ return false;
+
+ if (size_mode->GetName() != g_size_name)
+ {
+ // we are hitting the padding structure, move along
+ size_mode = D->GetChildAtIndexPath({1,1,1});
+ if (!size_mode)
+ return false;
+ }
+
+ size_mode_value = (size_mode->GetValueAsUnsigned(0));
+ short_mode = ((size_mode_value & 0x80) == 0);
+ }
+ else
+ {
+ ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
+ if (!size_mode)
+ return false;
+
+ size_mode_value = (size_mode->GetValueAsUnsigned(0));
+ short_mode = ((size_mode_value & 1) == 0);
+ }
+
+ if (short_mode)
+ {
+ ValueObjectSP s(D->GetChildAtIndex(1, true));
+ if (!s)
+ return false;
+ location_sp = s->GetChildAtIndex((layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
+ size = (layout == eLibcxxStringLayoutModeDSC) ? size_mode_value : ((size_mode_value >> 1) % 256);
+ return (location_sp.get() != nullptr);
+ }
+ else
+ {
+ ValueObjectSP l(D->GetChildAtIndex(0, true));
+ if (!l)
+ return false;
+ // we can use the layout_decider object as the data pointer
+ location_sp = (layout == eLibcxxStringLayoutModeDSC) ? layout_decider : l->GetChildAtIndex(2, true);
+ ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
+ if (!size_vo || !location_sp)
+ return false;
+ size = size_vo->GetValueAsUnsigned(0);
+ return true;
+ }
+}
+
+bool
+lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ uint64_t size = 0;
+ ValueObjectSP location_sp((ValueObject*)nullptr);
+ if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
+ return false;
+ if (size == 0)
+ {
+ stream.Printf("L\"\"");
+ return true;
+ }
+ if (!location_sp)
+ return false;
+ return WCharStringSummaryProvider(*location_sp.get(), stream);
+}
+
+bool
+lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ 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();
+}
+
+bool
+lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ stream.Printf("%s",class_name);
+ return true;
+}
+
+class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
+{
+public:
+ ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd(*valobj_sp.get())
+ {
+ }
+
+ virtual size_t
+ CalculateNumChildren ()
+ {
+ return 0;
+ }
+
+ virtual lldb::ValueObjectSP
+ GetChildAtIndex (size_t idx)
+ {
+ return lldb::ValueObjectSP();
+ }
+
+ virtual bool
+ Update()
+ {
+ return false;
+ }
+
+ virtual bool
+ MightHaveChildren ()
+ {
+ return false;
+ }
+
+ virtual size_t
+ GetIndexOfChildWithName (const ConstString &name)
+ {
+ return UINT32_MAX;
+ }
+
+ virtual
+ ~ObjCClassSyntheticChildrenFrontEnd ()
+ {
+ }
+};
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
+}
+
+template<bool needs_at>
+bool
+lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ bool is_64bit = (process_sp->GetAddressByteSize() == 8);
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"NSConcreteData") ||
+ !strcmp(class_name,"NSConcreteMutableData") ||
+ !strcmp(class_name,"__NSCFData"))
+ {
+ uint32_t offset = (is_64bit ? 16 : 8);
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ else
+ {
+ if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
+ return false;
+ }
+
+ stream.Printf("%s%" PRIu64 " byte%s%s",
+ (needs_at ? "@\"" : ""),
+ value,
+ (value != 1 ? "s" : ""),
+ (needs_at ? "\"" : ""));
+
+ return true;
+}
+
+static bool
+ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
+ lldb::ProcessSP& process_sp,
+ Stream& dest,
+ uint32_t size = 0,
+ Error* error = NULL,
+ size_t *data_read = NULL,
+ char prefix_token = '@',
+ char quote = '"')
+{
+ Error my_error;
+ size_t my_data_read;
+ if (!process_sp || location == 0)
+ return false;
+
+ if (!size)
+ size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
+ else
+ size = std::min(size,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
+
+ my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
+
+ if (error)
+ *error = my_error;
+ if (data_read)
+ *data_read = my_data_read;
+
+ if (my_error.Fail())
+ return false;
+
+ dest.Printf("%c%c",prefix_token,quote);
+
+ if (my_data_read)
+ dest.Printf("%s",(char*)buffer_sp->GetBytes());
+
+ dest.Printf("%c",quote);
+
+ return true;
+}
+
+bool
+lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ uint64_t info_bits_location = valobj_addr + ptr_size;
+ if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
+ info_bits_location += 3;
+
+ Error error;
+
+ uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
+ if (error.Fail())
+ return false;
+
+ bool is_mutable = (info_bits & 1) == 1;
+ bool is_inline = (info_bits & 0x60) == 0;
+ bool has_explicit_length = (info_bits & (1 | 4)) != 4;
+ bool is_unicode = (info_bits & 0x10) == 0x10;
+ bool is_special = strcmp(class_name,"NSPathStore2") == 0;
+ bool has_null = (info_bits & 8) == 8;
+
+ size_t explicit_length = 0;
+ if (!has_null && has_explicit_length && !is_special)
+ {
+ lldb::addr_t explicit_length_offset = 2*ptr_size;
+ if (is_mutable and not is_inline)
+ explicit_length_offset = explicit_length_offset + ptr_size; // notInlineMutable.length;
+ else if (is_inline)
+ explicit_length = explicit_length + 0; // inline1.length;
+ else if (not is_inline and not is_mutable)
+ explicit_length_offset = explicit_length_offset + ptr_size; // notInlineImmutable1.length;
+ else
+ explicit_length_offset = 0;
+
+ if (explicit_length_offset)
+ {
+ explicit_length_offset = valobj_addr + explicit_length_offset;
+ explicit_length = process_sp->ReadUnsignedIntegerFromMemory(explicit_length_offset, 4, 0, error);
+ }
+ }
+
+ if (strcmp(class_name,"NSString") &&
+ strcmp(class_name,"CFStringRef") &&
+ strcmp(class_name,"CFMutableStringRef") &&
+ strcmp(class_name,"__NSCFConstantString") &&
+ strcmp(class_name,"__NSCFString") &&
+ strcmp(class_name,"NSCFConstantString") &&
+ strcmp(class_name,"NSCFString") &&
+ strcmp(class_name,"NSPathStore2"))
+ {
+ // not one of us - but tell me class name
+ stream.Printf("class name = %s",class_name);
+ return true;
+ }
+
+ if (is_mutable)
+ {
+ uint64_t location = 2 * ptr_size + valobj_addr;
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ return false;
+ if (has_explicit_length and is_unicode)
+ {
+ ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
+ options.SetConversionFunction(ConvertUTF16toUTF8);
+ options.SetLocation(location);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('@');
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetNeedsZeroTermination(false);
+ return ReadUTFBufferAndDumpToStream (options);
+ }
+ else
+ return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream, explicit_length);
+ }
+ else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
+ {
+ uint64_t location = 3 * ptr_size + valobj_addr;
+ return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
+ }
+ else if (is_unicode)
+ {
+ uint64_t location = valobj_addr + 2*ptr_size;
+ if (is_inline)
+ {
+ if (!has_explicit_length)
+ {
+ stream.Printf("found new combo");
+ return true;
+ }
+ else
+ location += ptr_size;
+ }
+ else
+ {
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ return false;
+ }
+ ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
+ options.SetConversionFunction(ConvertUTF16toUTF8);
+ options.SetLocation(location);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('@');
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetNeedsZeroTermination(has_explicit_length == false);
+ return ReadUTFBufferAndDumpToStream (options);
+ }
+ else if (is_special)
+ {
+ uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
+ ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
+ options.SetConversionFunction(ConvertUTF16toUTF8);
+ options.SetLocation(location);
+ options.SetProcessSP(process_sp);
+ options.SetStream(&stream);
+ options.SetPrefixToken('@');
+ options.SetQuote('"');
+ options.SetSourceSize(explicit_length);
+ options.SetNeedsZeroTermination(has_explicit_length == false);
+ return ReadUTFBufferAndDumpToStream (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);
+ }
+ else
+ {
+ uint64_t location = valobj_addr + 2*ptr_size;
+ location = process_sp->ReadPointerFromMemory(location, error);
+ if (error.Fail())
+ 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);
+ }
+
+ stream.Printf("class name = %s",class_name);
+ return true;
+
+}
+
+bool
+lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ TargetSP target_sp(valobj.GetTargetSP());
+ if (!target_sp)
+ return false;
+ uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
+ uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
+ if (!pointer_value)
+ return false;
+ pointer_value += addr_size;
+ ClangASTType type(valobj.GetClangType());
+ ExecutionContext exe_ctx(target_sp,false);
+ ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointer_value, exe_ctx, type));
+ if (!child_ptr_sp)
+ return false;
+ DataExtractor data;
+ child_ptr_sp->GetData(data);
+ 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 false;
+}
+
+bool
+lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ return NSAttributedStringSummaryProvider(valobj, stream);
+}
+
+bool
+lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ stream.Printf("%s",valobj.GetObjectDescription());
+ return true;
+}
+
+bool
+lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ const uint32_t type_info = valobj.GetClangType().GetTypeInfo();
+
+ ValueObjectSP real_guy_sp = valobj.GetSP();
+
+ if (type_info & ClangASTType::eTypeIsPointer)
+ {
+ Error err;
+ real_guy_sp = valobj.Dereference(err);
+ if (err.Fail() || !real_guy_sp)
+ return false;
+ }
+ else if (type_info & ClangASTType::eTypeIsReference)
+ {
+ real_guy_sp = valobj.GetChildAtIndex(0, true);
+ if (!real_guy_sp)
+ return false;
+ }
+ uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
+ if (value == 0)
+ {
+ stream.Printf("NO");
+ return true;
+ }
+ stream.Printf("YES");
+ return true;
+}
+
+template <bool is_sel_ptr>
+bool
+lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ lldb::ValueObjectSP valobj_sp;
+
+ ClangASTType charstar (valobj.GetClangType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType());
+
+ if (!charstar)
+ return false;
+
+ ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
+
+ if (is_sel_ptr)
+ {
+ lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (data_address == LLDB_INVALID_ADDRESS)
+ return false;
+ valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
+ }
+ else
+ {
+ DataExtractor data;
+ valobj.GetData(data);
+ valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
+ }
+
+ if (!valobj_sp)
+ return false;
+
+ stream.Printf("%s",valobj_sp->GetSummaryAsCString());
+ return true;
+}
+
+// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
+// this call gives the POSIX equivalent of the Cocoa epoch
+time_t
+lldb_private::formatters::GetOSXEpoch ()
+{
+ static time_t epoch = 0;
+ if (!epoch)
+ {
+ tzset();
+ tm tm_epoch;
+ tm_epoch.tm_sec = 0;
+ tm_epoch.tm_hour = 0;
+ tm_epoch.tm_min = 0;
+ tm_epoch.tm_mon = 0;
+ tm_epoch.tm_mday = 1;
+ tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
+ tm_epoch.tm_isdst = -1;
+ tm_epoch.tm_gmtoff = 0;
+ tm_epoch.tm_zone = NULL;
+ epoch = timegm(&tm_epoch);
+ }
+ return epoch;
+}
+
+size_t
+lldb_private::formatters::ExtractIndexFromString (const char* item_name)
+{
+ if (!item_name || !*item_name)
+ return UINT32_MAX;
+ if (*item_name != '[')
+ return UINT32_MAX;
+ item_name++;
+ char* endptr = NULL;
+ unsigned long int idx = ::strtoul(item_name, &endptr, 0);
+ if (idx == 0 && endptr == item_name)
+ return UINT32_MAX;
+ if (idx == ULONG_MAX)
+ return UINT32_MAX;
+ return idx;
+}
+
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
+ ConstString item_name) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_item_name(item_name),
+m_item_sp()
+{
+ if (valobj_sp)
+ Update();
+}
+
+bool
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
+{
+ m_item_sp.reset();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+
+ if (!valobj_sp)
+ return false;
+
+ ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
+ if (!item_ptr)
+ return false;
+ if (item_ptr->GetValueAsUnsigned(0) == 0)
+ 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());
+ if (err.Fail())
+ m_item_sp.reset();
+ return false;
+}
+
+size_t
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return 1;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx == 0)
+ return m_item_sp;
+ return lldb::ValueObjectSP();
+}
+
+bool
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (name == ConstString("item"))
+ return 0;
+ return UINT32_MAX;
+}
+
+lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
+{
+}
+
+template bool
+lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
+
+template bool
+lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
+
+template bool
+lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
+
+template bool
+lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
diff --git a/source/DataFormatters/Cocoa.cpp b/source/DataFormatters/Cocoa.cpp
new file mode 100644
index 000000000000..555954db0bb7
--- /dev/null
+++ b/source/DataFormatters/Cocoa.cpp
@@ -0,0 +1,565 @@
+//===-- Cocoa.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool
+lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"NSBundle"))
+ {
+ uint64_t offset = 5 * ptr_size;
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
+
+ StreamString summary_stream;
+ bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0)
+ {
+ stream.Printf("%s",summary_stream.GetData());
+ return true;
+ }
+ }
+ // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
+ // which is encoded differently and needs to be handled by running code
+ return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
+}
+
+bool
+lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"__NSTimeZone"))
+ {
+ 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);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0)
+ {
+ stream.Printf("%s",summary_stream.GetData());
+ return true;
+ }
+ }
+ return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
+}
+
+bool
+lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"NSConcreteNotification"))
+ {
+ 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);
+ if (was_nsstring_ok && summary_stream.GetSize() > 0)
+ {
+ stream.Printf("%s",summary_stream.GetData());
+ return true;
+ }
+ }
+ // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
+ // which is encoded differently and needs to be handled by running code
+ return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
+}
+
+bool
+lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ uint64_t port_number = 0;
+
+ do
+ {
+ if (!strcmp(class_name,"NSMachPort"))
+ {
+ uint64_t offset = (ptr_size == 4 ? 12 : 20);
+ Error error;
+ port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
+ if (error.Success())
+ break;
+ }
+ if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
+ return false;
+ } while (false);
+
+ stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
+ return true;
+}
+
+bool
+lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ uint64_t count = 0;
+
+ do {
+ if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
+ {
+ Error error;
+ uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
+ if (error.Fail())
+ return false;
+ // this means the set is empty - count = 0
+ if ((mode & 1) == 1)
+ {
+ count = 0;
+ break;
+ }
+ if ((mode & 2) == 2)
+ mode = 1; // this means the set only has one range
+ else
+ mode = 2; // this means the set has multiple ranges
+ if (mode == 1)
+ {
+ count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ else
+ {
+ // read a pointer to the data at 2*ptr_size
+ count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ // read the data at 2*ptr_size from the first location
+ count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ }
+ else
+ {
+ if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
+ return false;
+ }
+ } while (false);
+ stream.Printf("%" PRIu64 " index%s",
+ count,
+ (count == 1 ? "" : "es"));
+ return true;
+}
+
+bool
+lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
+ {
+ uint64_t value = 0;
+ uint64_t i_bits = 0;
+ if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
+ {
+ switch (i_bits)
+ {
+ case 0:
+ stream.Printf("(char)%hhd",(char)value);
+ break;
+ case 1:
+ case 4:
+ stream.Printf("(short)%hd",(short)value);
+ break;
+ case 2:
+ case 8:
+ stream.Printf("(int)%d",(int)value);
+ break;
+ case 3:
+ case 12:
+ stream.Printf("(long)%" PRId64,value);
+ break;
+ default:
+ stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
+ break;
+ }
+ return true;
+ }
+ else
+ {
+ Error error;
+ uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
+ uint64_t data_location = valobj_addr + 2*ptr_size;
+ uint64_t value = 0;
+ if (error.Fail())
+ return false;
+ switch (data_type)
+ {
+ case 1: // 0B00001
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
+ if (error.Fail())
+ return false;
+ stream.Printf("(char)%hhd",(char)value);
+ break;
+ case 2: // 0B0010
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
+ if (error.Fail())
+ return false;
+ stream.Printf("(short)%hd",(short)value);
+ break;
+ case 3: // 0B0011
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
+ if (error.Fail())
+ return false;
+ stream.Printf("(int)%d",(int)value);
+ break;
+ case 17: // 0B10001
+ data_location += 8;
+ case 4: // 0B0100
+ value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
+ if (error.Fail())
+ return false;
+ stream.Printf("(long)%" PRId64,value);
+ break;
+ case 5: // 0B0101
+ {
+ uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
+ if (error.Fail())
+ return false;
+ float flt_value = *((float*)&flt_as_int);
+ stream.Printf("(float)%f",flt_value);
+ break;
+ }
+ case 6: // 0B0110
+ {
+ uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
+ if (error.Fail())
+ return false;
+ double dbl_value = *((double*)&dbl_as_lng);
+ stream.Printf("(double)%g",dbl_value);
+ break;
+ }
+ default:
+ stream.Printf("unexpected value: dt=%d",data_type);
+ break;
+ }
+ return true;
+ }
+ }
+ else
+ {
+ return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
+ }
+}
+
+bool
+lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (strcmp(class_name, "NSURL") == 0)
+ {
+ uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
+ uint64_t offset_base = offset_text + ptr_size;
+ ClangASTType type(valobj.GetClangType());
+ ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
+ ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
+ if (!text)
+ return false;
+ if (text->GetValueAsUnsigned(0) == 0)
+ return false;
+ StreamString summary;
+ if (!NSStringSummaryProvider(*text, summary))
+ return false;
+ if (base && base->GetValueAsUnsigned(0))
+ {
+ if (summary.GetSize() > 0)
+ summary.GetString().resize(summary.GetSize()-1);
+ summary.Printf(" -- ");
+ StreamString base_summary;
+ if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0)
+ summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
+ }
+ if (summary.GetSize())
+ {
+ stream.Printf("%s",summary.GetData());
+ return true;
+ }
+ }
+ else
+ {
+ return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
+ }
+ return false;
+}
+
+bool
+lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t date_value_bits = 0;
+ double date_value = 0.0;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (strcmp(class_name,"NSDate") == 0 ||
+ strcmp(class_name,"__NSDate") == 0 ||
+ strcmp(class_name,"__NSTaggedDate") == 0)
+ {
+ uint64_t info_bits=0,value_bits = 0;
+ if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
+ {
+ date_value_bits = ((value_bits << 8) | (info_bits << 4));
+ date_value = *((double*)&date_value_bits);
+ }
+ else
+ {
+ Error error;
+ date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
+ date_value = *((double*)&date_value_bits);
+ if (error.Fail())
+ return false;
+ }
+ }
+ else if (!strcmp(class_name,"NSCalendarDate"))
+ {
+ Error error;
+ date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
+ date_value = *((double*)&date_value_bits);
+ if (error.Fail())
+ return false;
+ }
+ else
+ {
+ if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
+ return false;
+ date_value = *((double*)&date_value_bits);
+ }
+ if (date_value == -63114076800)
+ {
+ stream.Printf("0001-12-30 00:00:00 +0000");
+ return true;
+ }
+ // this snippet of code assumes that time_t == seconds since Jan-1-1970
+ // this is generally true and POSIXly happy, but might break if a library
+ // vendor decides to get creative
+ time_t epoch = GetOSXEpoch();
+ epoch = epoch + (time_t)date_value;
+ tm *tm_date = localtime(&epoch);
+ if (!tm_date)
+ return false;
+ std::string buffer(1024,0);
+ if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
+ return false;
+ stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
+ return true;
+}
diff --git a/source/DataFormatters/DataVisualization.cpp b/source/DataFormatters/DataVisualization.cpp
new file mode 100644
index 000000000000..c1ef359049b6
--- /dev/null
+++ b/source/DataFormatters/DataVisualization.cpp
@@ -0,0 +1,279 @@
+//===-- DataVisualization.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/DataVisualization.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Debugger.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static FormatManager&
+GetFormatManager()
+{
+ static FormatManager g_format_manager;
+ return g_format_manager;
+}
+
+void
+DataVisualization::ForceUpdate ()
+{
+ GetFormatManager().Changed();
+}
+
+uint32_t
+DataVisualization::GetCurrentRevision ()
+{
+ return GetFormatManager().GetCurrentRevision();
+}
+
+lldb::TypeFormatImplSP
+DataVisualization::ValueFormats::GetFormat (ValueObject& valobj, lldb::DynamicValueType use_dynamic)
+{
+ lldb::TypeFormatImplSP entry;
+ GetFormatManager().GetValueNavigator().Get(valobj, entry, use_dynamic);
+ return entry;
+}
+
+lldb::TypeFormatImplSP
+DataVisualization::ValueFormats::GetFormat (const ConstString &type)
+{
+ lldb::TypeFormatImplSP entry;
+ GetFormatManager().GetValueNavigator().Get(type, entry);
+ return entry;
+}
+
+void
+DataVisualization::ValueFormats::Add (const ConstString &type, const lldb::TypeFormatImplSP &entry)
+{
+ GetFormatManager().GetValueNavigator().Add(FormatManager::GetValidTypeName(type),entry);
+}
+
+bool
+DataVisualization::ValueFormats::Delete (const ConstString &type)
+{
+ return GetFormatManager().GetValueNavigator().Delete(type);
+}
+
+void
+DataVisualization::ValueFormats::Clear ()
+{
+ GetFormatManager().GetValueNavigator().Clear();
+}
+
+void
+DataVisualization::ValueFormats::LoopThrough (TypeFormatImpl::ValueCallback callback, void* callback_baton)
+{
+ GetFormatManager().GetValueNavigator().LoopThrough(callback, callback_baton);
+}
+
+size_t
+DataVisualization::ValueFormats::GetCount ()
+{
+ return GetFormatManager().GetValueNavigator().GetCount();
+}
+
+lldb::TypeNameSpecifierImplSP
+DataVisualization::ValueFormats::GetTypeNameSpecifierForFormatAtIndex (size_t index)
+{
+ return GetFormatManager().GetValueNavigator().GetTypeNameSpecifierAtIndex(index);
+}
+
+lldb::TypeFormatImplSP
+DataVisualization::ValueFormats::GetFormatAtIndex (size_t index)
+{
+ return GetFormatManager().GetValueNavigator().GetAtIndex(index);
+}
+
+lldb::TypeSummaryImplSP
+DataVisualization::GetSummaryFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ return GetFormatManager().GetSummaryFormat(valobj, use_dynamic);
+}
+
+lldb::TypeSummaryImplSP
+DataVisualization::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ return GetFormatManager().GetSummaryForType(type_sp);
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SyntheticChildrenSP
+DataVisualization::GetSyntheticChildren (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ return GetFormatManager().GetSyntheticChildren(valobj, use_dynamic);
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SyntheticChildrenSP
+DataVisualization::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ return GetFormatManager().GetSyntheticChildrenForType(type_sp);
+}
+#endif
+
+lldb::TypeFilterImplSP
+DataVisualization::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ return GetFormatManager().GetFilterForType(type_sp);
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::ScriptedSyntheticChildrenSP
+DataVisualization::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ return GetFormatManager().GetSyntheticForType(type_sp);
+}
+#endif
+
+bool
+DataVisualization::AnyMatches (ConstString type_name,
+ TypeCategoryImpl::FormatCategoryItems items,
+ bool only_enabled,
+ const char** matching_category,
+ TypeCategoryImpl::FormatCategoryItems* matching_type)
+{
+ return GetFormatManager().AnyMatches(type_name,
+ items,
+ only_enabled,
+ matching_category,
+ matching_type);
+}
+
+bool
+DataVisualization::Categories::GetCategory (const ConstString &category, lldb::TypeCategoryImplSP &entry,
+ bool allow_create)
+{
+ entry = GetFormatManager().GetCategory(category, allow_create);
+ return (entry.get() != NULL);
+}
+
+void
+DataVisualization::Categories::Add (const ConstString &category)
+{
+ GetFormatManager().GetCategory(category);
+}
+
+bool
+DataVisualization::Categories::Delete (const ConstString &category)
+{
+ GetFormatManager().DisableCategory(category);
+ return GetFormatManager().DeleteCategory(category);
+}
+
+void
+DataVisualization::Categories::Clear ()
+{
+ GetFormatManager().ClearCategories();
+}
+
+void
+DataVisualization::Categories::Clear (const ConstString &category)
+{
+ GetFormatManager().GetCategory(category)->Clear(eFormatCategoryItemSummary | eFormatCategoryItemRegexSummary);
+}
+
+void
+DataVisualization::Categories::Enable (const ConstString& category,
+ TypeCategoryMap::Position pos)
+{
+ if (GetFormatManager().GetCategory(category)->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+ GetFormatManager().EnableCategory(category, pos);
+}
+
+void
+DataVisualization::Categories::Disable (const ConstString& category)
+{
+ if (GetFormatManager().GetCategory(category)->IsEnabled() == true)
+ GetFormatManager().DisableCategory(category);
+}
+
+void
+DataVisualization::Categories::Enable (const lldb::TypeCategoryImplSP& category,
+ TypeCategoryMap::Position pos)
+{
+ if (category.get())
+ {
+ if (category->IsEnabled())
+ GetFormatManager().DisableCategory(category);
+ GetFormatManager().EnableCategory(category, pos);
+ }
+}
+
+void
+DataVisualization::Categories::Disable (const lldb::TypeCategoryImplSP& category)
+{
+ if (category.get() && category->IsEnabled() == true)
+ GetFormatManager().DisableCategory(category);
+}
+
+void
+DataVisualization::Categories::LoopThrough (FormatManager::CategoryCallback callback, void* callback_baton)
+{
+ GetFormatManager().LoopThroughCategories(callback, callback_baton);
+}
+
+uint32_t
+DataVisualization::Categories::GetCount ()
+{
+ return GetFormatManager().GetCategoriesCount();
+}
+
+lldb::TypeCategoryImplSP
+DataVisualization::Categories::GetCategoryAtIndex (size_t index)
+{
+ return GetFormatManager().GetCategoryAtIndex(index);
+}
+
+bool
+DataVisualization::NamedSummaryFormats::GetSummaryFormat (const ConstString &type, lldb::TypeSummaryImplSP &entry)
+{
+ return GetFormatManager().GetNamedSummaryNavigator().Get(type,entry);
+}
+
+void
+DataVisualization::NamedSummaryFormats::Add (const ConstString &type, const lldb::TypeSummaryImplSP &entry)
+{
+ GetFormatManager().GetNamedSummaryNavigator().Add(FormatManager::GetValidTypeName(type),entry);
+}
+
+bool
+DataVisualization::NamedSummaryFormats::Delete (const ConstString &type)
+{
+ return GetFormatManager().GetNamedSummaryNavigator().Delete(type);
+}
+
+void
+DataVisualization::NamedSummaryFormats::Clear ()
+{
+ GetFormatManager().GetNamedSummaryNavigator().Clear();
+}
+
+void
+DataVisualization::NamedSummaryFormats::LoopThrough (TypeSummaryImpl::SummaryCallback callback, void* callback_baton)
+{
+ GetFormatManager().GetNamedSummaryNavigator().LoopThrough(callback, callback_baton);
+}
+
+uint32_t
+DataVisualization::NamedSummaryFormats::GetCount ()
+{
+ return GetFormatManager().GetNamedSummaryNavigator().GetCount();
+}
diff --git a/source/DataFormatters/FormatCache.cpp b/source/DataFormatters/FormatCache.cpp
new file mode 100644
index 000000000000..af7b1c386c32
--- /dev/null
+++ b/source/DataFormatters/FormatCache.cpp
@@ -0,0 +1,169 @@
+//===-- FormatCache.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"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/DataFormatters/FormatCache.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+FormatCache::Entry::Entry () :
+m_summary_cached(false),
+m_synthetic_cached(false),
+m_summary_sp(),
+m_synthetic_sp()
+{}
+
+FormatCache::Entry::Entry (lldb::TypeSummaryImplSP summary_sp) :
+m_synthetic_cached(false),
+m_synthetic_sp()
+{
+ SetSummary (summary_sp);
+}
+
+FormatCache::Entry::Entry (lldb::SyntheticChildrenSP synthetic_sp) :
+m_summary_cached(false),
+m_summary_sp()
+{
+ SetSynthetic (synthetic_sp);
+}
+
+FormatCache::Entry::Entry (lldb::TypeSummaryImplSP summary_sp,lldb::SyntheticChildrenSP synthetic_sp)
+{
+ SetSummary (summary_sp);
+ SetSynthetic (synthetic_sp);
+}
+
+bool
+FormatCache::Entry::IsSummaryCached ()
+{
+ return m_summary_cached;
+}
+
+bool
+FormatCache::Entry::IsSyntheticCached ()
+{
+ return m_synthetic_cached;
+}
+
+lldb::TypeSummaryImplSP
+FormatCache::Entry::GetSummary ()
+{
+ return m_summary_sp;
+}
+
+lldb::SyntheticChildrenSP
+FormatCache::Entry::GetSynthetic ()
+{
+ return m_synthetic_sp;
+}
+
+void
+FormatCache::Entry::SetSummary (lldb::TypeSummaryImplSP summary_sp)
+{
+ m_summary_cached = true;
+ m_summary_sp = summary_sp;
+}
+
+void
+FormatCache::Entry::SetSynthetic (lldb::SyntheticChildrenSP synthetic_sp)
+{
+ m_synthetic_cached = true;
+ m_synthetic_sp = synthetic_sp;
+}
+
+FormatCache::FormatCache () :
+m_map(),
+m_mutex (Mutex::eMutexTypeRecursive)
+#ifdef LLDB_CONFIGURATION_DEBUG
+,m_cache_hits(0),m_cache_misses(0)
+#endif
+{
+}
+
+FormatCache::Entry&
+FormatCache::GetEntry (const ConstString& type)
+{
+ auto i = m_map.find(type),
+ e = m_map.end();
+ if (i != e)
+ return i->second;
+ m_map[type] = FormatCache::Entry();
+ return m_map[type];
+}
+
+bool
+FormatCache::GetSummary (const ConstString& type,lldb::TypeSummaryImplSP& summary_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ auto entry = GetEntry(type);
+ if (entry.IsSummaryCached())
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_hits++;
+#endif
+ summary_sp = entry.GetSummary();
+ return true;
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_misses++;
+#endif
+ summary_sp.reset();
+ return false;
+}
+
+bool
+FormatCache::GetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& synthetic_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ auto entry = GetEntry(type);
+ if (entry.IsSyntheticCached())
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_hits++;
+#endif
+ synthetic_sp = entry.GetSynthetic();
+ return true;
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ m_cache_misses++;
+#endif
+ synthetic_sp.reset();
+ return false;
+}
+
+void
+FormatCache::SetSummary (const ConstString& type,lldb::TypeSummaryImplSP& summary_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ GetEntry(type).SetSummary(summary_sp);
+}
+
+void
+FormatCache::SetSynthetic (const ConstString& type,lldb::SyntheticChildrenSP& synthetic_sp)
+{
+ Mutex::Locker lock(m_mutex);
+ GetEntry(type).SetSynthetic(synthetic_sp);
+}
+
+void
+FormatCache::Clear ()
+{
+ Mutex::Locker lock(m_mutex);
+ m_map.clear();
+}
+
diff --git a/source/DataFormatters/FormatClasses.cpp b/source/DataFormatters/FormatClasses.cpp
new file mode 100644
index 000000000000..c67f86a7493d
--- /dev/null
+++ b/source/DataFormatters/FormatClasses.cpp
@@ -0,0 +1,33 @@
+//===-- FormatClasses.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"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/DataFormatters/FormatClasses.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
diff --git a/source/DataFormatters/FormatManager.cpp b/source/DataFormatters/FormatManager.cpp
new file mode 100644
index 000000000000..eeae8bc9a19d
--- /dev/null
+++ b/source/DataFormatters/FormatManager.cpp
@@ -0,0 +1,1083 @@
+//===-- FormatManager.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/FormatManager.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/DataFormatters/CXXFormatterFunctions.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+struct FormatInfo
+{
+ Format format;
+ const char format_char; // One or more format characters that can be used for this format.
+ const char *format_name; // Long format name that can be used to specify the current format
+};
+
+static FormatInfo
+g_format_infos[] =
+{
+ { eFormatDefault , '\0' , "default" },
+ { eFormatBoolean , 'B' , "boolean" },
+ { eFormatBinary , 'b' , "binary" },
+ { eFormatBytes , 'y' , "bytes" },
+ { eFormatBytesWithASCII , 'Y' , "bytes with ASCII" },
+ { eFormatChar , 'c' , "character" },
+ { eFormatCharPrintable , 'C' , "printable character" },
+ { eFormatComplexFloat , 'F' , "complex float" },
+ { eFormatCString , 's' , "c-string" },
+ { eFormatDecimal , 'd' , "decimal" },
+ { eFormatEnum , 'E' , "enumeration" },
+ { eFormatHex , 'x' , "hex" },
+ { eFormatHexUppercase , 'X' , "uppercase hex" },
+ { eFormatFloat , 'f' , "float" },
+ { eFormatOctal , 'o' , "octal" },
+ { eFormatOSType , 'O' , "OSType" },
+ { eFormatUnicode16 , 'U' , "unicode16" },
+ { eFormatUnicode32 , '\0' , "unicode32" },
+ { eFormatUnsigned , 'u' , "unsigned decimal" },
+ { eFormatPointer , 'p' , "pointer" },
+ { eFormatVectorOfChar , '\0' , "char[]" },
+ { eFormatVectorOfSInt8 , '\0' , "int8_t[]" },
+ { eFormatVectorOfUInt8 , '\0' , "uint8_t[]" },
+ { eFormatVectorOfSInt16 , '\0' , "int16_t[]" },
+ { eFormatVectorOfUInt16 , '\0' , "uint16_t[]" },
+ { eFormatVectorOfSInt32 , '\0' , "int32_t[]" },
+ { eFormatVectorOfUInt32 , '\0' , "uint32_t[]" },
+ { eFormatVectorOfSInt64 , '\0' , "int64_t[]" },
+ { eFormatVectorOfUInt64 , '\0' , "uint64_t[]" },
+ { eFormatVectorOfFloat32, '\0' , "float32[]" },
+ { eFormatVectorOfFloat64, '\0' , "float64[]" },
+ { eFormatVectorOfUInt128, '\0' , "uint128_t[]" },
+ { eFormatComplexInteger , 'I' , "complex integer" },
+ { eFormatCharArray , 'a' , "character array" },
+ { eFormatAddressInfo , 'A' , "address" },
+ { eFormatHexFloat , '\0' , "hex float" },
+ { eFormatInstruction , 'i' , "instruction" },
+ { eFormatVoid , 'v' , "void" }
+};
+
+static uint32_t
+g_num_format_infos = sizeof(g_format_infos)/sizeof(FormatInfo);
+
+static bool
+GetFormatFromFormatChar (char format_char, Format &format)
+{
+ for (uint32_t i=0; i<g_num_format_infos; ++i)
+ {
+ if (g_format_infos[i].format_char == format_char)
+ {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+ format = eFormatInvalid;
+ return false;
+}
+
+static bool
+GetFormatFromFormatName (const char *format_name, bool partial_match_ok, Format &format)
+{
+ uint32_t i;
+ for (i=0; i<g_num_format_infos; ++i)
+ {
+ if (strcasecmp (g_format_infos[i].format_name, format_name) == 0)
+ {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+
+ if (partial_match_ok)
+ {
+ for (i=0; i<g_num_format_infos; ++i)
+ {
+ if (strcasestr (g_format_infos[i].format_name, format_name) == g_format_infos[i].format_name)
+ {
+ format = g_format_infos[i].format;
+ return true;
+ }
+ }
+ }
+ format = eFormatInvalid;
+ return false;
+}
+
+bool
+FormatManager::GetFormatFromCString (const char *format_cstr,
+ bool partial_match_ok,
+ lldb::Format &format)
+{
+ bool success = false;
+ if (format_cstr && format_cstr[0])
+ {
+ if (format_cstr[1] == '\0')
+ {
+ success = GetFormatFromFormatChar (format_cstr[0], format);
+ if (success)
+ return true;
+ }
+
+ success = GetFormatFromFormatName (format_cstr, partial_match_ok, format);
+ }
+ if (!success)
+ format = eFormatInvalid;
+ return success;
+}
+
+char
+FormatManager::GetFormatAsFormatChar (lldb::Format format)
+{
+ for (uint32_t i=0; i<g_num_format_infos; ++i)
+ {
+ if (g_format_infos[i].format == format)
+ return g_format_infos[i].format_char;
+ }
+ return '\0';
+}
+
+const char *
+FormatManager::GetFormatAsCString (Format format)
+{
+ if (format >= eFormatDefault && format < kNumFormats)
+ return g_format_infos[format].format_name;
+ return NULL;
+}
+
+lldb::TypeSummaryImplSP
+FormatManager::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ if (!type_sp)
+ return lldb::TypeSummaryImplSP();
+ lldb::TypeSummaryImplSP summary_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::TypeSummaryImplSP summary_current_sp = category_sp->GetSummaryForType(type_sp);
+ if (summary_current_sp && (summary_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
+ {
+ prio_category = category_sp->GetEnabledPosition();
+ summary_chosen_sp = summary_current_sp;
+ }
+ }
+ return summary_chosen_sp;
+}
+
+lldb::TypeFilterImplSP
+FormatManager::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ if (!type_sp)
+ return lldb::TypeFilterImplSP();
+ lldb::TypeFilterImplSP filter_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::TypeFilterImplSP filter_current_sp((TypeFilterImpl*)category_sp->GetFilterForType(type_sp).get());
+ if (filter_current_sp && (filter_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
+ {
+ prio_category = category_sp->GetEnabledPosition();
+ filter_chosen_sp = filter_current_sp;
+ }
+ }
+ return filter_chosen_sp;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::ScriptedSyntheticChildrenSP
+FormatManager::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ if (!type_sp)
+ return lldb::ScriptedSyntheticChildrenSP();
+ lldb::ScriptedSyntheticChildrenSP synth_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::ScriptedSyntheticChildrenSP synth_current_sp((ScriptedSyntheticChildren*)category_sp->GetSyntheticForType(type_sp).get());
+ if (synth_current_sp && (synth_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
+ {
+ prio_category = category_sp->GetEnabledPosition();
+ synth_chosen_sp = synth_current_sp;
+ }
+ }
+ return synth_chosen_sp;
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SyntheticChildrenSP
+FormatManager::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ if (!type_sp)
+ return lldb::SyntheticChildrenSP();
+ lldb::TypeFilterImplSP filter_sp = GetFilterForType(type_sp);
+ lldb::ScriptedSyntheticChildrenSP synth_sp = GetSyntheticForType(type_sp);
+ if (filter_sp->GetRevision() > synth_sp->GetRevision())
+ return lldb::SyntheticChildrenSP(filter_sp.get());
+ else
+ return lldb::SyntheticChildrenSP(synth_sp.get());
+}
+#endif
+
+lldb::TypeCategoryImplSP
+FormatManager::GetCategory (const ConstString& category_name,
+ bool can_create)
+{
+ if (!category_name)
+ return GetCategory(m_default_category_name);
+ lldb::TypeCategoryImplSP category;
+ if (m_categories_map.Get(category_name, category))
+ return category;
+
+ if (!can_create)
+ return lldb::TypeCategoryImplSP();
+
+ m_categories_map.Add(category_name,lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name)));
+ return GetCategory(category_name);
+}
+
+lldb::Format
+FormatManager::GetSingleItemFormat(lldb::Format vector_format)
+{
+ switch(vector_format)
+ {
+ case eFormatVectorOfChar:
+ return eFormatCharArray;
+
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfSInt64:
+ return eFormatDecimal;
+
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfUInt128:
+ return eFormatHex;
+
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ return eFormatFloat;
+
+ default:
+ return lldb::eFormatInvalid;
+ }
+}
+
+ConstString
+FormatManager::GetValidTypeName (const ConstString& type)
+{
+ return ::GetValidTypeName_Impl(type);
+}
+
+ConstString
+GetTypeForCache (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ if (use_dynamic == lldb::eNoDynamicValues)
+ {
+ if (valobj.IsDynamic())
+ {
+ if (valobj.GetStaticValue())
+ return valobj.GetStaticValue()->GetQualifiedTypeName();
+ else
+ return ConstString();
+ }
+ else
+ return valobj.GetQualifiedTypeName();
+ }
+ if (valobj.IsDynamic())
+ return valobj.GetQualifiedTypeName();
+ if (valobj.GetDynamicValue(use_dynamic))
+ return valobj.GetDynamicValue(use_dynamic)->GetQualifiedTypeName();
+ return ConstString();
+}
+
+lldb::TypeSummaryImplSP
+FormatManager::GetSummaryFormat (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ TypeSummaryImplSP 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::GetSummaryFormat] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
+ if (m_format_cache.GetSummary(valobj_type,retval))
+ {
+ if (log)
+ {
+ log->Printf("[FormatManager::GetSummaryFormat] Cache search success. Returning.");
+ if (log->GetDebug())
+ log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ }
+ return retval;
+ }
+ if (log)
+ log->Printf("[FormatManager::GetSummaryFormat] Cache search failed. Going normal route");
+ }
+ retval = m_categories_map.GetSummaryFormat(valobj, use_dynamic);
+ if (valobj_type)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s",retval.get(),valobj_type.AsCString("<invalid>"));
+ m_format_cache.SetSummary(valobj_type,retval);
+ }
+ if (log && log->GetDebug())
+ log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ return retval;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SyntheticChildrenSP
+FormatManager::GetSyntheticChildren (ValueObject& valobj,
+ lldb::DynamicValueType use_dynamic)
+{
+ SyntheticChildrenSP 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::GetSyntheticChildren] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
+ if (m_format_cache.GetSynthetic(valobj_type,retval))
+ {
+ if (log)
+ {
+ log->Printf("[FormatManager::GetSyntheticChildren] Cache search success. Returning.");
+ if (log->GetDebug())
+ log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ }
+ return retval;
+ }
+ if (log)
+ log->Printf("[FormatManager::GetSyntheticChildren] Cache search failed. Going normal route");
+ }
+ retval = m_categories_map.GetSyntheticChildren(valobj, use_dynamic);
+ if (valobj_type)
+ {
+ if (log)
+ log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s",retval.get(),valobj_type.AsCString("<invalid>"));
+ m_format_cache.SetSynthetic(valobj_type,retval);
+ }
+ if (log && log->GetDebug())
+ log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
+ return retval;
+}
+#endif
+
+FormatManager::FormatManager() :
+ m_format_cache(),
+ m_value_nav("format",this),
+ m_named_summaries_map(this),
+ m_last_revision(0),
+ m_categories_map(this),
+ m_default_category_name(ConstString("default")),
+ m_system_category_name(ConstString("system")),
+ m_gnu_cpp_category_name(ConstString("gnu-libstdc++")),
+ m_libcxx_category_name(ConstString("libcxx")),
+ m_objc_category_name(ConstString("objc")),
+ m_corefoundation_category_name(ConstString("CoreFoundation")),
+ m_coregraphics_category_name(ConstString("CoreGraphics")),
+ m_coreservices_category_name(ConstString("CoreServices")),
+ m_vectortypes_category_name(ConstString("VectorTypes")),
+ m_appkit_category_name(ConstString("AppKit"))
+{
+ LoadSystemFormatters();
+ LoadLibStdcppFormatters();
+ LoadLibcxxFormatters();
+ LoadObjCFormatters();
+
+ EnableCategory(m_objc_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_corefoundation_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_appkit_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_coreservices_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_coregraphics_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_gnu_cpp_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_libcxx_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_vectortypes_category_name,TypeCategoryMap::Last);
+ EnableCategory(m_system_category_name,TypeCategoryMap::Last);
+}
+
+static void
+AddStringSummary(TypeCategoryImpl::SharedPointer category_sp,
+ const char* string,
+ ConstString type_name,
+ TypeSummaryImpl::Flags flags,
+ bool regex = false)
+{
+ lldb::TypeSummaryImplSP summary_sp(new StringSummaryFormat(flags,
+ string));
+
+ if (regex)
+ category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
+ else
+ category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+static void
+AddScriptSummary(TypeCategoryImpl::SharedPointer category_sp,
+ const char* funct_name,
+ ConstString type_name,
+ TypeSummaryImpl::Flags flags,
+ bool regex = false)
+{
+
+ std::string code(" ");
+ code.append(funct_name).append("(valobj,internal_dict)");
+
+ lldb::TypeSummaryImplSP summary_sp(new ScriptSummaryFormat(flags,
+ funct_name,
+ code.c_str()));
+ if (regex)
+ category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
+ else
+ category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+static void
+AddCXXSummary (TypeCategoryImpl::SharedPointer category_sp,
+ CXXFunctionSummaryFormat::Callback funct,
+ const char* description,
+ ConstString type_name,
+ TypeSummaryImpl::Flags flags,
+ bool regex = false)
+{
+ lldb::TypeSummaryImplSP summary_sp(new CXXFunctionSummaryFormat(flags,funct,description));
+ if (regex)
+ category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())),summary_sp);
+ else
+ category_sp->GetSummaryNavigator()->Add(type_name, summary_sp);
+}
+#endif
+
+#ifndef LLDB_DISABLE_PYTHON
+static void AddCXXSynthetic (TypeCategoryImpl::SharedPointer category_sp,
+ CXXSyntheticChildren::CreateFrontEndCallback generator,
+ const char* description,
+ ConstString type_name,
+ ScriptedSyntheticChildren::Flags flags,
+ bool regex = false)
+{
+ lldb::SyntheticChildrenSP synth_sp(new CXXSyntheticChildren(flags,description,generator));
+ if (regex)
+ category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression(type_name.AsCString())), synth_sp);
+ else
+ category_sp->GetSyntheticNavigator()->Add(type_name,synth_sp);
+}
+#endif
+
+void
+FormatManager::LoadLibStdcppFormatters()
+{
+ TypeSummaryImpl::Flags stl_summary_flags;
+ stl_summary_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ lldb::TypeSummaryImplSP std_string_summary_sp(new StringSummaryFormat(stl_summary_flags,
+ "${var._M_dataplus._M_p}"));
+
+ TypeCategoryImpl::SharedPointer gnu_category_sp = GetCategory(m_gnu_cpp_category_name);
+
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::string"),
+ std_string_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char>"),
+ std_string_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char,std::char_traits<char>,std::allocator<char> >"),
+ std_string_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"),
+ std_string_summary_sp);
+
+ // making sure we force-pick the summary for printing wstring (_M_p is a wchar_t*)
+ lldb::TypeSummaryImplSP std_wstring_summary_sp(new StringSummaryFormat(stl_summary_flags,
+ "${var._M_dataplus._M_p%S}"));
+
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::wstring"),
+ std_wstring_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t>"),
+ std_wstring_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >"),
+ std_wstring_summary_sp);
+ gnu_category_sp->GetSummaryNavigator()->Add(ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >"),
+ std_wstring_summary_sp);
+
+
+#ifndef LLDB_DISABLE_PYTHON
+
+ SyntheticChildren::Flags stl_synth_flags;
+ stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
+
+ gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider")));
+ gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider")));
+ gnu_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
+ "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider")));
+
+ stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(true);
+ gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::vector<.+>(( )?&)?$")),
+ TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
+ "size=${svar%#}")));
+ gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::map<.+> >(( )?&)?$")),
+ TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
+ "size=${svar%#}")));
+ gnu_category_sp->GetRegexSummaryNavigator()->Add(RegularExpressionSP(new RegularExpression("^std::list<.+>(( )?&)?$")),
+ TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags,
+ "size=${svar%#}")));
+
+ 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->GetSummaryNavigator()->Add(ConstString("std::vector<std::allocator<bool> >"),
+ TypeSummaryImplSP(new StringSummaryFormat(stl_summary_flags, "size=${svar%#}")));
+
+ gnu_category_sp->GetSyntheticNavigator()->Add(ConstString("std::vector<std::allocator<bool> >"),
+ SyntheticChildrenSP(new CXXSyntheticChildren(stl_synth_flags,"libc++ std::vector<bool> synthetic children",lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator)));
+
+#endif
+}
+
+void
+FormatManager::LoadLibcxxFormatters()
+{
+ TypeSummaryImpl::Flags stl_summary_flags;
+ stl_summary_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+#ifndef LLDB_DISABLE_PYTHON
+ //std::string code(" lldb.formatters.cpp.libcxx.stdstring_SummaryProvider(valobj,internal_dict)");
+ //lldb::TypeSummaryImplSP std_string_summary_sp(new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.libcxx.stdstring_SummaryProvider",code.c_str()));
+
+ lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, "std::string summary provider"));
+ lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider"));
+
+ TypeCategoryImpl::SharedPointer libcxx_category_sp = GetCategory(m_libcxx_category_name);
+
+ libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::string"),
+ std_string_summary_sp);
+ libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
+ std_string_summary_sp);
+
+ libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::wstring"),
+ std_wstring_summary_sp);
+ libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
+ std_wstring_summary_sp);
+
+ SyntheticChildren::Flags stl_synth_flags;
+ stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
+
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, "libc++ std::list synthetic children", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::map synthetic children", ConstString("^std::__1::map<.+> >(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator, "libc++ std::vector<bool> synthetic children", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_synth_flags);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::set synthetic children", ConstString("^std::__1::set<.+> >(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multiset synthetic children", ConstString("^std::__1::multiset<.+> >(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, "libc++ std::multimap synthetic children", ConstString("^std::__1::multimap<.+> >(( )?&)?$"), stl_synth_flags, true);
+
+ libcxx_category_sp->GetRegexSyntheticNavigator()->Add(RegularExpressionSP(new RegularExpression("^(std::__1::)deque<.+>(( )?&)?$")),
+ SyntheticChildrenSP(new ScriptedSyntheticChildren(stl_synth_flags,
+ "lldb.formatters.cpp.libcxx.stddeque_SynthProvider")));
+
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "shared_ptr synthetic children", ConstString("^(std::__1::)shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, "weak_ptr synthetic children", ConstString("^(std::__1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
+
+ stl_summary_flags.SetDontShowChildren(false);stl_summary_flags.SetSkipPointers(false);
+
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", ConstString("^std::__1::vector<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", ConstString("^std::__1::list<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::map summary provider", ConstString("^std::__1::map<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::deque summary provider", ConstString("^std::__1::deque<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector<bool> summary provider", ConstString("std::__1::vector<std::__1::allocator<bool> >"), stl_summary_flags);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::set summary provider", ConstString("^std::__1::set<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multiset summary provider", ConstString("^std::__1::multiset<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddCXXSummary(libcxx_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::multimap summary provider", ConstString("^std::__1::multimap<.+>(( )?&)?$"), stl_summary_flags, true);
+
+ stl_summary_flags.SetSkipPointers(true);
+ AddStringSummary(libcxx_category_sp, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}", ConstString("^std::__1::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
+ AddStringSummary(libcxx_category_sp, "{${var.__ptr_%S}} (strong=${var.count} weak=${var.weak_count})}", ConstString("^std::__1::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, true);
+
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, "std::vector iterator synthetic children", ConstString("^std::__1::__wrap_iter<.+>$"), stl_synth_flags, true);
+
+ AddCXXSynthetic(libcxx_category_sp, lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, "std::map iterator synthetic children", ConstString("^std::__1::__map_iterator<.+>$"), stl_synth_flags, true);
+
+#endif
+}
+
+void
+FormatManager::LoadSystemFormatters()
+{
+
+ TypeSummaryImpl::Flags string_flags;
+ string_flags.SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ lldb::TypeSummaryImplSP string_format(new StringSummaryFormat(string_flags, "${var%s}"));
+
+
+ lldb::TypeSummaryImplSP string_array_format(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false),
+ "${var%s}"));
+
+ lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]"));
+
+ TypeCategoryImpl::SharedPointer sys_category_sp = GetCategory(m_system_category_name);
+
+ sys_category_sp->GetSummaryNavigator()->Add(ConstString("char *"), string_format);
+ sys_category_sp->GetSummaryNavigator()->Add(ConstString("unsigned char *"), string_format);
+ sys_category_sp->GetRegexSummaryNavigator()->Add(any_size_char_arr, string_array_format);
+
+ lldb::TypeSummaryImplSP ostype_summary(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false),
+ "${var%O}"));
+
+ sys_category_sp->GetSummaryNavigator()->Add(ConstString("OSType"), ostype_summary);
+
+#ifndef LLDB_DISABLE_PYTHON
+ // FIXME because of a bug in the FormatNavigator we need to add a summary for both X* and const X* (<rdar://problem/12717717>)
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "char16_t * summary provider", ConstString("char16_t *"), string_flags);
+
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char32StringSummaryProvider, "char32_t * summary provider", ConstString("char32_t *"), string_flags);
+
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::WCharStringSummaryProvider, "wchar_t * summary provider", ConstString("wchar_t *"), string_flags);
+
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16StringSummaryProvider, "unichar * summary provider", ConstString("unichar *"), string_flags);
+
+ TypeSummaryImpl::Flags widechar_flags;
+ widechar_flags.SetDontShowValue(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetCascades(true)
+ .SetDontShowChildren(true)
+ .SetHideItemNames(true)
+ .SetShowMembersOneLiner(false);
+
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16SummaryProvider, "char16_t summary provider", ConstString("char16_t"), widechar_flags);
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char32SummaryProvider, "char32_t summary provider", ConstString("char32_t"), widechar_flags);
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::WCharSummaryProvider, "wchar_t summary provider", ConstString("wchar_t"), widechar_flags);
+
+ AddCXXSummary(sys_category_sp, lldb_private::formatters::Char16SummaryProvider, "unichar summary provider", ConstString("unichar"), widechar_flags);
+
+#endif
+}
+
+void
+FormatManager::LoadObjCFormatters()
+{
+ TypeSummaryImpl::Flags objc_flags;
+ objc_flags.SetCascades(false)
+ .SetSkipPointers(true)
+ .SetSkipReferences(true)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(true)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ TypeCategoryImpl::SharedPointer objc_category_sp = GetCategory(m_objc_category_name);
+
+ lldb::TypeSummaryImplSP ObjC_BOOL_summary(new CXXFunctionSummaryFormat(objc_flags, lldb_private::formatters::ObjCBOOLSummaryProvider,""));
+ objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL"),
+ ObjC_BOOL_summary);
+ objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL &"),
+ ObjC_BOOL_summary);
+ objc_category_sp->GetSummaryNavigator()->Add(ConstString("BOOL *"),
+ ObjC_BOOL_summary);
+
+#ifndef LLDB_DISABLE_PYTHON
+ // we need to skip pointers here since we are special casing a SEL* when retrieving its value
+ objc_flags.SetSkipPointers(true);
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<false>, "SEL summary provider", ConstString("SEL"), objc_flags);
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<false>, "SEL summary provider", ConstString("struct objc_selector"), objc_flags);
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<false>, "SEL summary provider", ConstString("objc_selector"), objc_flags);
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<true>, "SEL summary provider", ConstString("objc_selector *"), objc_flags);
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCSELSummaryProvider<true>, "SEL summary provider", ConstString("SEL *"), objc_flags);
+
+ AddCXXSummary(objc_category_sp, lldb_private::formatters::ObjCClassSummaryProvider, "Class summary provider", ConstString("Class"), objc_flags);
+
+ SyntheticChildren::Flags class_synth_flags;
+ class_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
+
+ AddCXXSynthetic(objc_category_sp, lldb_private::formatters::ObjCClassSyntheticFrontEndCreator, "Class synthetic children", ConstString("Class"), class_synth_flags);
+#endif // LLDB_DISABLE_PYTHON
+
+ objc_flags.SetSkipPointers(false);
+ objc_flags.SetCascades(true);
+ objc_flags.SetSkipReferences(false);
+
+ AddStringSummary (objc_category_sp,
+ "${var.__FuncPtr%A}",
+ 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"),
+ objc_flags);
+ AddStringSummary(corefoundation_category_sp,
+ "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,
+ "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,
+ "(${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);
+
+ AddStringSummary(coreservices_category_sp,
+ "red=${var.red} green=${var.green} blue=${var.blue}",
+ ConstString("RGBColor"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "(t=${var.top}, l=${var.left}, b=${var.bottom}, r=${var.right})",
+ ConstString("Rect"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "(v=${var.v}, h=${var.h})",
+ ConstString("Point"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "${var.month}/${var.day}/${var.year} ${var.hour} :${var.minute} :${var.second} dayOfWeek:${var.dayOfWeek}",
+ ConstString("DateTimeRect *"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "${var.ld.month}/${var.ld.day}/${var.ld.year} ${var.ld.hour} :${var.ld.minute} :${var.ld.second} dayOfWeek:${var.ld.dayOfWeek}",
+ ConstString("LongDateRect"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "(x=${var.x}, y=${var.y})",
+ ConstString("HIPoint"),
+ objc_flags);
+ AddStringSummary(coreservices_category_sp,
+ "origin=${var.origin} size=${var.size}",
+ ConstString("HIRect"),
+ objc_flags);
+
+ TypeCategoryImpl::SharedPointer appkit_category_sp = GetCategory(m_appkit_category_name);
+
+ TypeSummaryImpl::Flags appkit_flags;
+ appkit_flags.SetCascades(true)
+ .SetSkipPointers(false)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(false)
+ .SetHideItemNames(false);
+
+ appkit_flags.SetDontShowChildren(false);
+
+
+#ifndef LLDB_DISABLE_PYTHON
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("NSArray"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("NSMutableArray"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("__NSArrayI"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("__NSArrayM"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("__NSCFArray"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("CFArrayRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSArraySummaryProvider, "NSArray summary provider", ConstString("CFMutableArrayRef"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<false>, "NSDictionary summary provider", ConstString("NSDictionary"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<false>, "NSDictionary summary provider", ConstString("NSMutableDictionary"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSCFDictionary"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryI"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<false>, "NSDictionary summary provider", ConstString("__NSDictionaryM"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<true>, "NSDictionary summary provider", ConstString("CFDictionaryRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDictionarySummaryProvider<true>, "NSDictionary summary provider", ConstString("CFMutableDictionaryRef"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "NSSet summary", ConstString("NSSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "NSMutableSet summary", ConstString("NSMutableSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<true>, "CFSetRef summary", ConstString("CFSetRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<true>, "CFMutableSetRef summary", ConstString("CFMutableSetRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "__NSCFSet summary", ConstString("__NSCFSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "__NSSetI summary", ConstString("__NSSetI"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "__NSSetM summary", ConstString("__NSSetM"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "NSCountedSet summary", ConstString("NSCountedSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "NSMutableSet summary", ConstString("NSMutableSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "NSOrderedSet summary", ConstString("NSOrderedSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "__NSOrderedSetI summary", ConstString("__NSOrderedSetI"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSSetSummaryProvider<false>, "__NSOrderedSetM summary", ConstString("__NSOrderedSetM"), appkit_flags);
+
+ // AddSummary(appkit_category_sp, "${var.key%@} -> ${var.value%@}", ConstString("$_lldb_typegen_nspair"), appkit_flags);
+
+ appkit_flags.SetDontShowChildren(true);
+
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("__NSArrayM"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("__NSArrayI"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("NSArray"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("NSMutableArray"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("__NSCFArray"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("CFMutableArrayRef"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSArraySyntheticFrontEndCreator, "NSArray synthetic children", ConstString("CFArrayRef"), ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("__NSDictionaryM"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("__NSDictionaryI"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("NSDictionary"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("NSMutableDictionary"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("CFDictionaryRef"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSDictionarySyntheticFrontEndCreator, "NSDictionary synthetic children", ConstString("CFMutableDictionaryRef"), ScriptedSyntheticChildren::Flags());
+
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSSet synthetic children", ConstString("NSSet"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSSetI synthetic children", ConstString("__NSSetI"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "__NSSetM synthetic children", ConstString("__NSSetM"), ScriptedSyntheticChildren::Flags());
+ AddCXXSynthetic(appkit_category_sp, lldb_private::formatters::NSSetSyntheticFrontEndCreator, "NSMutableSet synthetic children", ConstString("NSMutableSet"), ScriptedSyntheticChildren::Flags());
+ 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());
+
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("CFBagRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("__CFBag"), appkit_flags);
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("const struct __CFBag"), appkit_flags);
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBagSummaryProvider, "CFBag summary provider", ConstString("CFMutableBagRef"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBinaryHeapSummaryProvider, "CFBinaryHeap summary provider", ConstString("CFBinaryHeapRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp,lldb_private::formatters::CFBinaryHeapSummaryProvider, "CFBinaryHeap summary provider", ConstString("__CFBinaryHeap"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("CFStringRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("CFMutableStringRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSMutableString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("__NSCFConstantString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("__NSCFString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSCFConstantString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSCFString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSStringSummaryProvider, "NSString summary provider", ConstString("NSPathStore2"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSAttributedStringSummaryProvider, "NSAttributedString summary provider", ConstString("NSAttributedString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSMutableAttributedStringSummaryProvider, "NSMutableAttributedString summary provider", ConstString("NSMutableAttributedString"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSMutableAttributedStringSummaryProvider, "NSMutableAttributedString summary provider", ConstString("NSConcreteMutableAttributedString"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSBundleSummaryProvider, "NSBundle summary provider", ConstString("NSBundle"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSData"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteData"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("NSConcreteMutableData"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<false>, "NSData summary provider", ConstString("__NSCFData"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>, "NSData summary provider", ConstString("CFDataRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDataSummaryProvider<true>, "NSData summary provider", ConstString("CFMutableDataRef"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSMachPortSummaryProvider, "NSMachPort summary provider", ConstString("NSMachPort"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNotificationSummaryProvider, "NSNotification summary provider", ConstString("NSNotification"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNotificationSummaryProvider, "NSNotification summary provider", ConstString("NSConcreteNotification"), appkit_flags);
+
+ AddStringSummary(appkit_category_sp, "domain: ${var._domain} - code: ${var._code}", ConstString("NSError"), appkit_flags);
+ AddStringSummary(appkit_category_sp,"name:${var.name%S} reason:${var.reason%S}",ConstString("NSException"),appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSNumber"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("__NSCFBoolean"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("__NSCFNumber"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSCFBoolean"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSNumberSummaryProvider, "NSNumber summary provider", ConstString("NSCFNumber"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider, "NSDecimalNumber summary provider", ConstString("NSDecimalNumber"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider, "NSHost summary provider", ConstString("NSHost"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider, "NSTask summary provider", ConstString("NSTask"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider, "NSValue summary provider", ConstString("NSValue"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", ConstString("NSURL"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSURLSummaryProvider, "NSURL summary provider", ConstString("CFURLRef"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("NSDate"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("__NSDate"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("__NSTaggedDate"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSDateSummaryProvider, "NSDate summary provider", ConstString("NSCalendarDate"), appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("NSTimeZone"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("CFTimeZoneRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSTimeZoneSummaryProvider, "NSTimeZone summary provider", ConstString("__NSTimeZone"), appkit_flags);
+
+ // CFAbsoluteTime is actually a double rather than a pointer to an object
+ // we do not care about the numeric value, since it is probably meaningless to users
+ appkit_flags.SetDontShowValue(true);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFAbsoluteTimeSummaryProvider, "CFAbsoluteTime summary provider", ConstString("CFAbsoluteTime"), appkit_flags);
+ appkit_flags.SetDontShowValue(false);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", ConstString("NSIndexSet"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::NSIndexSetSummaryProvider, "NSIndexSet summary provider", ConstString("NSMutableIndexSet"), appkit_flags);
+
+ AddStringSummary(appkit_category_sp,
+ "@\"${var.month%d}/${var.day%d}/${var.year%d} ${var.hour%d}:${var.minute%d}:${var.second}\"",
+ ConstString("CFGregorianDate"),
+ appkit_flags);
+
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", ConstString("CFBitVectorRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", ConstString("CFMutableBitVectorRef"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", ConstString("__CFBitVector"), appkit_flags);
+ AddCXXSummary(appkit_category_sp, lldb_private::formatters::CFBitVectorSummaryProvider, "CFBitVector summary provider", ConstString("__CFMutableBitVector"), appkit_flags);
+#endif // LLDB_DISABLE_PYTHON
+
+ TypeCategoryImpl::SharedPointer vectors_category_sp = GetCategory(m_vectortypes_category_name);
+
+ TypeSummaryImpl::Flags vector_flags;
+ vector_flags.SetCascades(true)
+ .SetSkipPointers(true)
+ .SetSkipReferences(false)
+ .SetDontShowChildren(true)
+ .SetDontShowValue(false)
+ .SetShowMembersOneLiner(true)
+ .SetHideItemNames(true);
+
+ AddStringSummary(vectors_category_sp,
+ "${var.uint128}",
+ ConstString("builtin_type_vec128"),
+ objc_flags);
+
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("float [4]"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("int32_t [4]"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("int16_t [8]"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vDouble"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vFloat"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vSInt8"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vSInt16"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vSInt32"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vUInt16"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vUInt8"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vUInt16"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vUInt32"),
+ vector_flags);
+ AddStringSummary(vectors_category_sp,
+ "",
+ ConstString("vBool32"),
+ vector_flags);
+}
diff --git a/source/DataFormatters/LibCxx.cpp b/source/DataFormatters/LibCxx.cpp
new file mode 100644
index 000000000000..cdc57f6bd937
--- /dev/null
+++ b/source/DataFormatters/LibCxx.cpp
@@ -0,0 +1,519 @@
+//===-- LibCxx.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/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_count(0),
+m_base_data_address(0),
+m_options()
+{
+ if (valobj_sp)
+ Update();
+ m_options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+}
+
+size_t
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return m_count;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx >= m_count)
+ return ValueObjectSP();
+ if (m_base_data_address == 0 || m_count == 0)
+ return ValueObjectSP();
+ size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
+ size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
+ lldb::addr_t byte_location = m_base_data_address + byte_idx;
+ ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
+ if (!process_sp)
+ return ValueObjectSP();
+ uint8_t byte = 0;
+ uint8_t mask = 0;
+ Error err;
+ size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
+ if (err.Fail() || bytes_read == 0)
+ return ValueObjectSP();
+ switch (bit_index)
+ {
+ case 0:
+ mask = 1; break;
+ case 1:
+ mask = 2; break;
+ case 2:
+ mask = 4; break;
+ case 3:
+ mask = 8; break;
+ case 4:
+ mask = 16; break;
+ case 5:
+ mask = 32; break;
+ case 6:
+ mask = 64; break;
+ case 7:
+ mask = 128; break;
+ default:
+ return ValueObjectSP();
+ }
+ bool bit_set = ((byte & mask) != 0);
+ Target& target(process_sp->GetTarget());
+ ValueObjectSP retval_sp;
+ if (bit_set)
+ target.EvaluateExpression("(bool)true", NULL, retval_sp);
+ else
+ target.EvaluateExpression("(bool)false", NULL, retval_sp);
+ StreamString name; name.Printf("[%zu]",idx);
+ if (retval_sp)
+ retval_sp->SetName(ConstString(name.GetData()));
+ return retval_sp;
+}
+
+/*(std::__1::vector<std::__1::allocator<bool> >) vBool = {
+ __begin_ = 0x00000001001000e0
+ __size_ = 56
+ __cap_alloc_ = {
+ std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = {
+ __first_ = 1
+ }
+ }
+ }*/
+
+bool
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update()
+{
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true));
+ if (!size_sp)
+ return false;
+ m_count = size_sp->GetValueAsUnsigned(0);
+ if (!m_count)
+ return true;
+ ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true));
+ if (!begin_sp)
+ {
+ m_count = 0;
+ return false;
+ }
+ m_base_data_address = begin_sp->GetValueAsUnsigned(0);
+ if (!m_base_data_address)
+ {
+ m_count = 0;
+ return false;
+ }
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_count || !m_base_data_address)
+ return UINT32_MAX;
+ const char* item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp));
+}
+
+/*
+ (lldb) fr var ibeg --raw --ptr-depth 1
+ (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
+ __i_ = {
+ __ptr_ = 0x0000000100103870 {
+ std::__1::__tree_node_base<void *> = {
+ std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
+ __left_ = 0x0000000000000000
+ }
+ __right_ = 0x0000000000000000
+ __parent_ = 0x00000001001038b0
+ __is_black_ = true
+ }
+ __value_ = {
+ first = 0
+ second = { std::string }
+ */
+
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::LibCxxMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_pair_ptr()
+{
+ if (valobj_sp)
+ Update();
+}
+
+bool
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update()
+{
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+
+ if (!target_sp)
+ return false;
+
+ if (!valobj_sp)
+ return false;
+
+ // this must be a ValueObject* because it is a child of the ValueObject we are producing children for
+ // it if were a ValueObjectSP, we would end up with a loop (iterator -> synthetic -> child -> parent == iterator)
+ // and that would in turn leak memory by never allowing the ValueObjects to die and free their memory
+ m_pair_ptr = valobj_sp->GetValueForExpressionPath(".__i_.__ptr_->__value_",
+ NULL,
+ NULL,
+ NULL,
+ ValueObject::GetValueForExpressionPathOptions().DontCheckDotVsArrowSyntax().DontAllowSyntheticChildren(),
+ NULL).get();
+
+ return false;
+}
+
+size_t
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return 2;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_pair_ptr)
+ return lldb::ValueObjectSP();
+ return m_pair_ptr->GetChildAtIndex(idx, true);
+}
+
+bool
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (name == ConstString("first"))
+ return 0;
+ if (name == ConstString("second"))
+ return 1;
+ return UINT32_MAX;
+}
+
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::~LibCxxMapIteratorSyntheticFrontEnd ()
+{
+ // this will be deleted when its parent dies (since it's a child object)
+ //delete m_pair_ptr;
+}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp));
+}
+
+/*
+ (lldb) fr var ibeg --raw --ptr-depth 1 -T
+ (std::__1::__wrap_iter<int *>) ibeg = {
+ (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
+ (int) *__i = 1
+ }
+ }
+*/
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ static ConstString g_item_name;
+ if (!g_item_name)
+ g_item_name.SetCString("__i");
+ if (!valobj_sp)
+ return NULL;
+ return (new VectorIteratorSyntheticFrontEnd(valobj_sp,g_item_name));
+}
+
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::LibcxxSharedPtrSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_cntrl(NULL),
+m_count_sp(),
+m_weak_count_sp(),
+m_ptr_size(0),
+m_byte_order(lldb::eByteOrderInvalid)
+{
+ if (valobj_sp)
+ Update();
+}
+
+size_t
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return (m_cntrl ? 1 : 0);
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_cntrl)
+ return lldb::ValueObjectSP();
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return lldb::ValueObjectSP();
+
+ if (idx == 0)
+ return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
+
+ if (idx > 2)
+ return lldb::ValueObjectSP();
+
+ if (idx == 1)
+ {
+ if (!m_count_sp)
+ {
+ ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(ConstString("__shared_owners_"),true));
+ if (!shared_owners_sp)
+ 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());
+ }
+ return m_count_sp;
+ }
+ else /* if (idx == 2) */
+ {
+ if (!m_weak_count_sp)
+ {
+ ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(ConstString("__shared_weak_owners_"),true));
+ if (!shared_weak_owners_sp)
+ 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());
+ }
+ return m_weak_count_sp;
+ }
+}
+
+bool
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update()
+{
+ m_count_sp.reset();
+ m_weak_count_sp.reset();
+ m_cntrl = NULL;
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+ if (!target_sp)
+ return false;
+
+ m_byte_order = target_sp->GetArchitecture().GetByteOrder();
+ m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
+
+ lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"),true));
+
+ m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular dependency
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (name == ConstString("__ptr_"))
+ return 0;
+ if (name == ConstString("count"))
+ return 1;
+ if (name == ConstString("weak_count"))
+ return 2;
+ return UINT32_MAX;
+}
+
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::~LibcxxSharedPtrSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ 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("[%zu]",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)
+{
+ if (valobj.IsPointerType())
+ {
+ uint64_t value = valobj.GetValueAsUnsigned(0);
+ if (!value)
+ return false;
+ stream.Printf("0x%016" PRIx64 " ", value);
+ }
+ return Debugger::FormatPrompt("size=${svar%#}", NULL, NULL, NULL, stream, &valobj);
+}
diff --git a/source/DataFormatters/LibCxxList.cpp b/source/DataFormatters/LibCxxList.cpp
new file mode 100644
index 000000000000..de2ca1b20459
--- /dev/null
+++ b/source/DataFormatters/LibCxxList.cpp
@@ -0,0 +1,310 @@
+//===-- LibCxxList.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+class ListEntry
+{
+public:
+ ListEntry () {}
+ ListEntry (ValueObjectSP entry_sp) : m_entry_sp(entry_sp) {}
+ ListEntry (const ListEntry& rhs) : m_entry_sp(rhs.m_entry_sp) {}
+ ListEntry (ValueObject* entry) : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
+
+ ValueObjectSP
+ next ()
+ {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetChildMemberWithName(ConstString("__next_"), true);
+ }
+
+ ValueObjectSP
+ prev ()
+ {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetChildMemberWithName(ConstString("__prev_"), true);
+ }
+
+ uint64_t
+ value ()
+ {
+ if (!m_entry_sp)
+ return 0;
+ return m_entry_sp->GetValueAsUnsigned(0);
+ }
+
+ bool
+ null()
+ {
+ return (value() == 0);
+ }
+
+ ValueObjectSP
+ GetEntry ()
+ {
+ return m_entry_sp;
+ }
+
+ void
+ SetEntry (ValueObjectSP entry)
+ {
+ m_entry_sp = entry;
+ }
+
+ bool
+ operator == (const ListEntry& rhs) const
+ {
+ return (rhs.m_entry_sp.get() == m_entry_sp.get());
+ }
+
+private:
+ ValueObjectSP m_entry_sp;
+};
+
+class ListIterator
+{
+public:
+ ListIterator () {}
+ ListIterator (ListEntry entry) : m_entry(entry) {}
+ ListIterator (ValueObjectSP entry) : m_entry(entry) {}
+ ListIterator (const ListIterator& rhs) : m_entry(rhs.m_entry) {}
+ ListIterator (ValueObject* entry) : m_entry(entry) {}
+
+ ValueObjectSP
+ value ()
+ {
+ return m_entry.GetEntry();
+ }
+
+ ValueObjectSP
+ advance (size_t count)
+ {
+ if (count == 0)
+ return m_entry.GetEntry();
+ if (count == 1)
+ {
+ next ();
+ return m_entry.GetEntry();
+ }
+ while (count > 0)
+ {
+ next ();
+ count--;
+ if (m_entry.null())
+ return lldb::ValueObjectSP();
+ }
+ return m_entry.GetEntry();
+ }
+
+ bool
+ operator == (const ListIterator& rhs) const
+ {
+ return (rhs.m_entry == m_entry);
+ }
+
+protected:
+ void
+ next ()
+ {
+ m_entry.SetEntry(m_entry.next());
+ }
+
+ void
+ prev ()
+ {
+ m_entry.SetEntry(m_entry.prev());
+ }
+private:
+ ListEntry m_entry;
+};
+
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::LibcxxStdListSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_list_capping_size(0),
+m_node_address(),
+m_head(NULL),
+m_tail(NULL),
+m_element_type(),
+m_count(UINT32_MAX),
+m_children()
+{
+ if (valobj_sp)
+ Update();
+}
+
+bool
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::HasLoop()
+{
+ if (g_use_loop_detect == false)
+ return false;
+ ListEntry slow(m_head);
+ ListEntry fast1(m_head);
+ ListEntry fast2(m_head);
+ while (slow.next() && slow.next()->GetValueAsUnsigned(0) != m_node_address)
+ {
+ auto slow_value = slow.value();
+ fast1.SetEntry(fast2.next());
+ fast2.SetEntry(fast1.next());
+ if (fast1.value() == slow_value || fast2.value() == slow_value)
+ return true;
+ slow.SetEntry(slow.next());
+ }
+ return false;
+}
+
+size_t
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (m_count != UINT32_MAX)
+ return m_count;
+ if (!m_head || !m_tail || m_node_address == 0)
+ return 0;
+ ValueObjectSP size_alloc(m_backend.GetChildMemberWithName(ConstString("__size_alloc_"), true));
+ if (size_alloc)
+ {
+ ValueObjectSP first(size_alloc->GetChildMemberWithName(ConstString("__first_"), true));
+ if (first)
+ {
+ m_count = first->GetValueAsUnsigned(UINT32_MAX);
+ }
+ }
+ if (m_count != UINT32_MAX)
+ {
+ if (!HasLoop())
+ return m_count;
+ return m_count = 0;
+ }
+ else
+ {
+ uint64_t next_val = m_head->GetValueAsUnsigned(0);
+ uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
+ if (next_val == 0 || prev_val == 0)
+ return 0;
+ if (next_val == m_node_address)
+ 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()->GetValueAsUnsigned(0) != m_node_address)
+ {
+ size++;
+ current.SetEntry(current.next());
+ if (size > m_list_capping_size)
+ break;
+ }
+ return m_count = (size-1);
+ }
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+
+ if (!m_head || !m_tail || m_node_address == 0)
+ return lldb::ValueObjectSP();
+
+ auto cached = m_children.find(idx);
+ if (cached != m_children.end())
+ return cached->second;
+
+ ListIterator current(m_head);
+ ValueObjectSP current_sp(current.advance(idx));
+ if (!current_sp)
+ return lldb::ValueObjectSP();
+ current_sp = current_sp->GetChildMemberWithName(ConstString("__value_"), true);
+ if (!current_sp)
+ return lldb::ValueObjectSP();
+ // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
+ DataExtractor data;
+ current_sp->GetData(data);
+ StreamString name;
+ name.Printf("[%zu]",idx);
+ return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
+}
+
+bool
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::Update()
+{
+ m_head = m_tail = NULL;
+ m_node_address = 0;
+ m_count = UINT32_MAX;
+ Error err;
+ ValueObjectSP backend_addr(m_backend.AddressOf(err));
+ m_list_capping_size = 0;
+ if (m_backend.GetTargetSP())
+ m_list_capping_size = m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
+ if (m_list_capping_size == 0)
+ m_list_capping_size = 255;
+ if (err.Fail() || backend_addr.get() == NULL)
+ return false;
+ m_node_address = backend_addr->GetValueAsUnsigned(0);
+ if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
+ return false;
+ ValueObjectSP impl_sp(m_backend.GetChildMemberWithName(ConstString("__end_"),true));
+ if (!impl_sp)
+ return false;
+ ClangASTType list_type = m_backend.GetClangType();
+ if (list_type.IsReferenceType())
+ list_type = list_type.GetNonReferenceType();
+
+ if (list_type.GetNumTemplateArguments() == 0)
+ return false;
+ lldb::TemplateArgumentKind kind;
+ m_element_type = list_type.GetTemplateArgument(0, kind);
+ m_head = impl_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
+ m_tail = impl_sp->GetChildMemberWithName(ConstString("__prev_"), true).get();
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::formatters::LibcxxStdListSyntheticFrontEnd::~LibcxxStdListSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibcxxStdListSyntheticFrontEnd(valobj_sp));
+}
+
diff --git a/source/DataFormatters/LibCxxMap.cpp b/source/DataFormatters/LibCxxMap.cpp
new file mode 100644
index 000000000000..5daa40f15f3d
--- /dev/null
+++ b/source/DataFormatters/LibCxxMap.cpp
@@ -0,0 +1,409 @@
+//===-- LibCxxList.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+class MapEntry
+{
+public:
+ MapEntry () {}
+ 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()) {}
+
+ ValueObjectSP
+ left ()
+ {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetChildMemberWithName(ConstString("__left_"), true);
+ }
+
+ ValueObjectSP
+ right ()
+ {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetChildMemberWithName(ConstString("__right_"), true);
+ }
+
+ ValueObjectSP
+ parent ()
+ {
+ if (!m_entry_sp)
+ return m_entry_sp;
+ return m_entry_sp->GetChildMemberWithName(ConstString("__parent_"), true);
+ }
+
+ uint64_t
+ value ()
+ {
+ if (!m_entry_sp)
+ return 0;
+ return m_entry_sp->GetValueAsUnsigned(0);
+ }
+
+ bool
+ error ()
+ {
+ if (!m_entry_sp)
+ return true;
+ return m_entry_sp->GetError().Fail();
+ }
+
+ bool
+ null()
+ {
+ return (value() == 0);
+ }
+
+ ValueObjectSP
+ GetEntry ()
+ {
+ return m_entry_sp;
+ }
+
+ void
+ SetEntry (ValueObjectSP entry)
+ {
+ m_entry_sp = entry;
+ }
+
+ bool
+ operator == (const MapEntry& rhs) const
+ {
+ return (rhs.m_entry_sp.get() == m_entry_sp.get());
+ }
+
+private:
+ ValueObjectSP m_entry_sp;
+};
+
+class MapIterator
+{
+public:
+ MapIterator () {}
+ MapIterator (MapEntry entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
+ MapIterator (ValueObjectSP entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
+ MapIterator (const MapIterator& rhs) : m_entry(rhs.m_entry),m_max_depth(rhs.m_max_depth), m_error(false) {}
+ MapIterator (ValueObject* entry, size_t depth = 0) : m_entry(entry), m_max_depth(depth), m_error(false) {}
+
+ ValueObjectSP
+ value ()
+ {
+ return m_entry.GetEntry();
+ }
+
+ ValueObjectSP
+ advance (size_t count)
+ {
+ if (m_error)
+ return lldb::ValueObjectSP();
+ if (count == 0)
+ return m_entry.GetEntry();
+ if (count == 1)
+ {
+ next ();
+ return m_entry.GetEntry();
+ }
+ 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();
+ }
+ return m_entry.GetEntry();
+ }
+protected:
+ void
+ next ()
+ {
+ m_entry.SetEntry(increment(m_entry.GetEntry()));
+ }
+
+private:
+ ValueObjectSP
+ tree_min (ValueObjectSP x_sp)
+ {
+ MapEntry x(x_sp);
+ if (x.null())
+ return ValueObjectSP();
+ MapEntry left(x.left());
+ size_t steps = 0;
+ while (left.null() == false)
+ {
+ if (left.error())
+ {
+ m_error = true;
+ return lldb::ValueObjectSP();
+ }
+ x.SetEntry(left.GetEntry());
+ 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 x.GetEntry();
+ }
+
+ bool
+ is_left_child (ValueObjectSP x_sp)
+ {
+ MapEntry x(x_sp);
+ if (x.null())
+ return false;
+ MapEntry rhs(x.parent());
+ rhs.SetEntry(rhs.left());
+ 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;
+};
+
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::LibcxxStdMapSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_tree(NULL),
+m_root_node(NULL),
+m_element_type(),
+m_skip_size(UINT32_MAX),
+m_count(UINT32_MAX),
+m_children()
+{
+ if (valobj_sp)
+ Update();
+}
+
+size_t
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (m_count != UINT32_MAX)
+ return m_count;
+ if (m_tree == NULL)
+ return 0;
+ ValueObjectSP m_item(m_tree->GetChildMemberWithName(ConstString("__pair3_"), true));
+ if (!m_item)
+ return 0;
+ m_item = m_item->GetChildMemberWithName(ConstString("__first_"), true);
+ if (!m_item)
+ return 0;
+ m_count = m_item->GetValueAsUnsigned(0);
+ return m_count;
+}
+
+bool
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetDataType()
+{
+ if (m_element_type.GetOpaqueQualType() && m_element_type.GetASTContext())
+ return true;
+ m_element_type.Clear();
+ ValueObjectSP deref;
+ Error error;
+ deref = m_root_node->Dereference(error);
+ if (!deref || error.Fail())
+ return false;
+ deref = deref->GetChildMemberWithName(ConstString("__value_"), true);
+ if (!deref)
+ return false;
+ m_element_type = deref->GetClangType();
+ return true;
+}
+
+void
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetValueOffset (const lldb::ValueObjectSP& node)
+{
+ if (m_skip_size != UINT32_MAX)
+ return;
+ if (!node)
+ return;
+ ClangASTType node_type(node->GetClangType());
+ uint64_t bit_offset;
+ if (node_type.GetIndexOfFieldWithName("__value_", NULL, &bit_offset) == UINT32_MAX)
+ return;
+ m_skip_size = bit_offset / 8u;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ if (m_tree == NULL || m_root_node == NULL)
+ return lldb::ValueObjectSP();
+
+ auto cached = m_children.find(idx);
+ if (cached != m_children.end())
+ return cached->second;
+
+ bool need_to_skip = (idx > 0);
+ MapIterator iterator(m_root_node, CalculateNumChildren());
+ ValueObjectSP iterated_sp(iterator.advance(idx));
+ if (iterated_sp.get() == NULL)
+ {
+ // this tree is garbage - stop
+ m_tree = NULL; // this will stop all future searches until an Update() happens
+ return iterated_sp;
+ }
+ if (GetDataType())
+ {
+ if (!need_to_skip)
+ {
+ Error error;
+ iterated_sp = iterated_sp->Dereference(error);
+ if (!iterated_sp || error.Fail())
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
+ GetValueOffset(iterated_sp);
+ iterated_sp = iterated_sp->GetChildMemberWithName(ConstString("__value_"), true);
+ if (!iterated_sp)
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
+ }
+ else
+ {
+ // because of the way our debug info is made, we need to read item 0 first
+ // so that we can cache information used to generate other elements
+ if (m_skip_size == UINT32_MAX)
+ GetChildAtIndex(0);
+ if (m_skip_size == UINT32_MAX)
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
+ iterated_sp = iterated_sp->GetSyntheticChildAtOffset(m_skip_size, m_element_type, true);
+ if (!iterated_sp)
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
+ }
+ }
+ else
+ {
+ m_tree = NULL;
+ return lldb::ValueObjectSP();
+ }
+ // at this point we have a valid
+ // we need to copy current_sp into a new object otherwise we will end up with all items named __value_
+ DataExtractor data;
+ iterated_sp->GetData(data);
+ StreamString name;
+ name.Printf("[%zu]",idx);
+ return (m_children[idx] = ValueObject::CreateValueObjectFromData(name.GetData(), data, m_backend.GetExecutionContextRef(), m_element_type));
+}
+
+bool
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::Update()
+{
+ m_count = UINT32_MAX;
+ m_tree = m_root_node = NULL;
+ m_children.clear();
+ m_tree = m_backend.GetChildMemberWithName(ConstString("__tree_"), true).get();
+ if (!m_tree)
+ return false;
+ m_root_node = m_tree->GetChildMemberWithName(ConstString("__begin_node_"), true).get();
+ return false;
+}
+
+bool
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ return ExtractIndexFromString(name.GetCString());
+}
+
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEnd::~LibcxxStdMapSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibcxxStdMapSyntheticFrontEnd(valobj_sp));
+}
diff --git a/source/DataFormatters/LibStdcpp.cpp b/source/DataFormatters/LibStdcpp.cpp
new file mode 100644
index 000000000000..e0f23cc35e3f
--- /dev/null
+++ b/source/DataFormatters/LibStdcpp.cpp
@@ -0,0 +1,331 @@
+//===-- LibStdcpp.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_count(0),
+m_base_data_address(0),
+m_options()
+{
+ if (valobj_sp)
+ Update();
+ m_options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+}
+
+size_t
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return m_count;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx >= m_count)
+ return ValueObjectSP();
+ if (m_base_data_address == 0 || m_count == 0)
+ return ValueObjectSP();
+ size_t byte_idx = (idx >> 3); // divide by 8 to get byte index
+ size_t bit_index = (idx & 7); // efficient idx % 8 for bit index
+ lldb::addr_t byte_location = m_base_data_address + byte_idx;
+ ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
+ if (!process_sp)
+ return ValueObjectSP();
+ uint8_t byte = 0;
+ uint8_t mask = 0;
+ Error err;
+ size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err);
+ if (err.Fail() || bytes_read == 0)
+ return ValueObjectSP();
+ switch (bit_index)
+ {
+ case 0:
+ mask = 1; break;
+ case 1:
+ mask = 2; break;
+ case 2:
+ mask = 4; break;
+ case 3:
+ mask = 8; break;
+ case 4:
+ mask = 16; break;
+ case 5:
+ mask = 32; break;
+ case 6:
+ mask = 64; break;
+ case 7:
+ mask = 128; break;
+ default:
+ return ValueObjectSP();
+ }
+ bool bit_set = ((byte & mask) != 0);
+ Target& target(process_sp->GetTarget());
+ ValueObjectSP retval_sp;
+ if (bit_set)
+ target.EvaluateExpression("(bool)true", NULL, retval_sp);
+ else
+ target.EvaluateExpression("(bool)false", NULL, retval_sp);
+ StreamString name; name.Printf("[%zu]",idx);
+ if (retval_sp)
+ retval_sp->SetName(ConstString(name.GetData()));
+ return retval_sp;
+}
+
+/*((std::vector<std::allocator<bool> >) vBool = {
+ (std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = {
+ (std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = {
+ (std::_Bit_iterator) _M_start = {
+ (std::_Bit_iterator_base) std::_Bit_iterator_base = {
+ (_Bit_type *) _M_p = 0x0016b160
+ (unsigned int) _M_offset = 0
+ }
+ }
+ (std::_Bit_iterator) _M_finish = {
+ (std::_Bit_iterator_base) std::_Bit_iterator_base = {
+ (_Bit_type *) _M_p = 0x0016b16c
+ (unsigned int) _M_offset = 16
+ }
+ }
+ (_Bit_type *) _M_end_of_storage = 0x0016b170
+ }
+ }
+ }
+ */
+
+bool
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::Update()
+{
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ ValueObjectSP m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true));
+ if (!m_impl_sp)
+ return false;
+
+ ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true));
+ ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true));
+
+ ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp;
+
+ if (!m_start_sp || !m_finish_sp)
+ return false;
+
+ start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true);
+ finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true);
+ finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true);
+
+ if (!start_p_sp || !finish_offset_sp || !finish_p_sp)
+ return false;
+
+ m_base_data_address = start_p_sp->GetValueAsUnsigned(0);
+ if (!m_base_data_address)
+ return false;
+
+ lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0));
+ if (!end_data_address)
+ return false;
+
+ if (end_data_address < m_base_data_address)
+ return false;
+ else
+ m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8;
+
+ return true;
+}
+
+bool
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_count || !m_base_data_address)
+ return UINT32_MAX;
+ const char* item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp));
+}
+
+/*
+ (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) ibeg = {
+ (_Base_ptr) _M_node = 0x0000000100103910 {
+ (std::_Rb_tree_color) _M_color = _S_black
+ (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
+ (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
+ (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
+ }
+ }
+ */
+
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd(*valobj_sp.get()),
+ m_exe_ctx_ref(),
+ m_pair_address(0),
+ m_pair_type(),
+ m_options(),
+ m_pair_sp()
+{
+ if (valobj_sp)
+ Update();
+ m_options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetKeepInMemory(true)
+ .SetUseDynamic(lldb::eDynamicCanRunTarget);
+}
+
+bool
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::Update()
+{
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+
+ if (!target_sp)
+ return false;
+
+ bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
+
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+
+ ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
+ if (!_M_node_sp)
+ return false;
+
+ m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
+ if (m_pair_address == 0)
+ return false;
+
+ m_pair_address += (is_64bit ? 32 : 16);
+
+ ClangASTType my_type(valobj_sp->GetClangType());
+ if (my_type.GetNumTemplateArguments() >= 1)
+ {
+ TemplateArgumentKind kind;
+ ClangASTType pair_type = my_type.GetTemplateArgument(0, kind);
+ if (kind != eTemplateArgumentKindType && kind != eTemplateArgumentKindTemplate && kind != eTemplateArgumentKindTemplateExpansion)
+ return false;
+ m_pair_type = pair_type;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
+{
+ return 2;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ 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);
+ if (m_pair_sp)
+ return m_pair_sp->GetChildAtIndex(idx, true);
+ }
+ return lldb::ValueObjectSP();
+}
+
+bool
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (name == ConstString("first"))
+ return 0;
+ if (name == ConstString("second"))
+ return 1;
+ return UINT32_MAX;
+}
+
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEnd::~LibstdcppMapIteratorSyntheticFrontEnd ()
+{}
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ if (!valobj_sp)
+ return NULL;
+ return (new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp));
+}
+
+/*
+ (lldb) fr var ibeg --ptr-depth 1
+ (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) ibeg = {
+ _M_current = 0x00000001001037a0 {
+ *_M_current = 1
+ }
+ }
+ */
+
+SyntheticChildrenFrontEnd*
+lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ static ConstString g_item_name;
+ if (!g_item_name)
+ g_item_name.SetCString("_M_current");
+ if (!valobj_sp)
+ return NULL;
+ return (new VectorIteratorSyntheticFrontEnd(valobj_sp,g_item_name));
+}
diff --git a/source/DataFormatters/NSArray.cpp b/source/DataFormatters/NSArray.cpp
new file mode 100644
index 000000000000..d8ee9bfa8a47
--- /dev/null
+++ b/source/DataFormatters/NSArray.cpp
@@ -0,0 +1,371 @@
+//===-- NSArray.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+bool
+lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"__NSArrayI"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ else if (!strcmp(class_name,"__NSArrayM"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ else if (!strcmp(class_name,"__NSCFArray"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ }
+ else
+ {
+ if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
+ return false;
+ }
+
+ stream.Printf("@\"%" PRIu64 " object%s\"",
+ value,
+ value == 1 ? "" : "s");
+ return true;
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd(*valobj_sp.get()),
+ m_exe_ctx_ref(),
+ m_ptr_size(8),
+ m_data_32(NULL),
+ m_data_64(NULL)
+{
+ if (valobj_sp)
+ {
+ clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
+ if (ast)
+ m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
+ }
+}
+
+size_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (m_data_32)
+ return m_data_32->_used;
+ if (m_data_64)
+ return m_data_64->_used;
+ return 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_data_32 && !m_data_64)
+ return lldb::ValueObjectSP();
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data);
+ size_t pyhs_idx = idx;
+ pyhs_idx += (m_data_32 ? m_data_32->offset : m_data_64->offset);
+ if ((m_data_32 ? m_data_32->_size : m_data_64->_size) <= pyhs_idx)
+ pyhs_idx -= (m_data_32 ? m_data_32->_size : m_data_64->_size);
+ object_at_idx += (pyhs_idx * m_ptr_size);
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(),
+ object_at_idx,
+ m_exe_ctx_ref,
+ m_id_type);
+ m_children.push_back(retval_sp);
+ return retval_sp;
+}
+
+bool
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update()
+{
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ if (!m_data_32 && !m_data_64)
+ return UINT32_MAX;
+ const char* item_name = name.GetCString();
+ uint32_t idx = ExtractIndexFromString(item_name);
+ if (idx < UINT32_MAX && idx >= CalculateNumChildren())
+ return UINT32_MAX;
+ return idx;
+}
+
+lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+ SyntheticChildrenFrontEnd (*valobj_sp.get()),
+ m_exe_ctx_ref (),
+ m_ptr_size (8),
+ m_items (0),
+ m_data_ptr (0)
+{
+ if (valobj_sp)
+ {
+ clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext();
+ if (ast)
+ m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy);
+ }
+}
+
+lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd ()
+{
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd::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;
+}
+
+size_t
+lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren ()
+{
+ return m_items;
+}
+
+bool
+lldb_private::formatters::NSArrayISyntheticFrontEnd::Update()
+{
+ m_ptr_size = 0;
+ m_items = 0;
+ m_data_ptr = 0;
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ m_items = process_sp->ReadPointerFromMemory(data_location, error);
+ if (error.Fail())
+ return false;
+ m_data_ptr = data_location+m_ptr_size;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (idx >= CalculateNumChildren())
+ return lldb::ValueObjectSP();
+ lldb::addr_t object_at_idx = m_data_ptr;
+ object_at_idx += (idx * m_ptr_size);
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Error error;
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type);
+ m_children.push_back(retval_sp);
+ return retval_sp;
+}
+
+SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return NULL;
+ ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+ if (!runtime)
+ return NULL;
+
+ if (!valobj_sp->IsPointerType())
+ {
+ Error error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return NULL;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return NULL;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return NULL;
+
+ if (!strcmp(class_name,"__NSArrayI"))
+ {
+ return (new NSArrayISyntheticFrontEnd(valobj_sp));
+ }
+ else if (!strcmp(class_name,"__NSArrayM"))
+ {
+ return (new NSArrayMSyntheticFrontEnd(valobj_sp));
+ }
+ else
+ {
+ return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp));
+ }
+}
+
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get())
+{}
+
+size_t
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
+{
+ uint64_t count = 0;
+ if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
+ return count;
+ return 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx);
+ if (valobj_sp)
+ valobj_sp->SetName(ConstString(idx_name.GetData()));
+ return valobj_sp;
+}
+
+bool
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update()
+{
+ return false;
+}
+
+bool
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ return 0;
+}
+
+lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd ()
+{}
diff --git a/source/DataFormatters/NSDictionary.cpp b/source/DataFormatters/NSDictionary.cpp
new file mode 100644
index 000000000000..05a5dda39e53
--- /dev/null
+++ b/source/DataFormatters/NSDictionary.cpp
@@ -0,0 +1,579 @@
+//===-- NSDictionary.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+#include "clang/AST/DeclCXX.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+static ClangASTType
+GetLLDBNSPairType (TargetSP target_sp)
+{
+ ClangASTType clang_type;
+
+ ClangASTContext *target_ast_context = target_sp->GetScratchClangASTContext();
+
+ if (target_ast_context)
+ {
+ clang::ASTContext *ast = target_ast_context->getASTContext();
+
+ if (ast)
+ {
+ const char* type_name = "__lldb_autogen_nspair";
+
+ 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)
+ {
+ 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();
+ }
+ }
+ }
+ }
+ return clang_type;
+}
+
+template<bool name_entries>
+bool
+lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+ bool is_64bit = (ptr_size == 8);
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"__NSDictionaryI"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ else if (!strcmp(class_name,"__NSDictionaryM"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ /*else if (!strcmp(class_name,"__NSCFDictionary"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
+ if (error.Fail())
+ return false;
+ if (is_64bit)
+ value &= ~0x0f1f000000000000UL;
+ }*/
+ else
+ {
+ if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
+ return false;
+ }
+
+ stream.Printf("%s%" PRIu64 " %s%s",
+ (name_entries ? "@\"" : ""),
+ value,
+ (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")),
+ (name_entries ? "\"" : ""));
+ return true;
+}
+
+SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+
+ lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return NULL;
+ ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+ if (!runtime)
+ return NULL;
+
+ if (!valobj_sp->IsPointerType())
+ {
+ Error error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return NULL;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return NULL;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return NULL;
+
+ if (!strcmp(class_name,"__NSDictionaryI"))
+ {
+ return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
+ }
+ else if (!strcmp(class_name,"__NSDictionaryM"))
+ {
+ return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
+ }
+ else
+ {
+ return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp));
+ }
+}
+
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get())
+{}
+
+size_t
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren ()
+{
+ uint64_t count = 0;
+ if (ExtractValueFromObjCExpression(m_backend, "int", "count", count))
+ return count;
+ return 0;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ StreamString key_fetcher_expr;
+ key_fetcher_expr.Printf("(id)[(NSArray*)[(id)0x%" PRIx64 " allKeys] objectAtIndex:%zu]",m_backend.GetPointerValue(),idx);
+ StreamString value_fetcher_expr;
+ value_fetcher_expr.Printf("(id)[(id)0x%" PRIx64 " objectForKey:(%s)]",m_backend.GetPointerValue(),key_fetcher_expr.GetData());
+ StreamString object_fetcher_expr;
+ object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData());
+ lldb::ValueObjectSP child_sp;
+ m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp,
+ EvaluateExpressionOptions().SetKeepInMemory(true));
+ if (child_sp)
+ child_sp->SetName(ConstString(idx_name.GetData()));
+ return child_sp;
+}
+
+bool
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update()
+{
+ return false;
+}
+
+bool
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
+{
+ return 0;
+}
+
+lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd ()
+{}
+
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_ptr_size(8),
+m_order(lldb::eByteOrderInvalid),
+m_data_32(NULL),
+m_data_64(NULL),
+m_pair_type()
+{
+}
+
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+size_t
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::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;
+}
+
+size_t
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update()
+{
+ m_children.clear();
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ m_ptr_size = 0;
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ m_data_ptr = data_location + m_ptr_size;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty())
+ {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while(tries < num_children)
+ {
+ key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size);
+ val_at_idx = key_at_idx + m_ptr_size;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Error error;
+ key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!key_at_idx || !val_at_idx)
+ continue;
+ tries++;
+
+ DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ DictionaryItemDescriptor &dict_item = m_children[idx];
+ if (!dict_item.valobj_sp)
+ {
+ if (!m_pair_type.IsValid())
+ {
+ TargetSP target_sp(m_backend.GetTargetSP());
+ if (!target_sp)
+ return ValueObjectSP();
+ m_pair_type = GetLLDBNSPairType(target_sp);
+ }
+ if (!m_pair_type.IsValid())
+ return ValueObjectSP();
+
+ DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
+
+ if (m_ptr_size == 8)
+ {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr+1) = dict_item.val_ptr;
+ }
+ else
+ {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr+1) = dict_item.val_ptr;
+ }
+
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",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);
+ }
+ return dict_item.valobj_sp;
+}
+
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_ptr_size(8),
+m_order(lldb::eByteOrderInvalid),
+m_data_32(NULL),
+m_data_64(NULL),
+m_pair_type()
+{
+}
+
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+size_t
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::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;
+}
+
+size_t
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update()
+{
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ m_order = process_sp->GetByteOrder();
+ uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
+ lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
+
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty())
+ {
+ // do the scan phase
+ lldb::addr_t key_at_idx = 0, val_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while(tries < num_children)
+ {
+ key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
+ val_at_idx = m_values_ptr + (test_idx * m_ptr_size);;
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Error error;
+ key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+ val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!key_at_idx || !val_at_idx)
+ continue;
+ tries++;
+
+ DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ DictionaryItemDescriptor &dict_item = m_children[idx];
+ if (!dict_item.valobj_sp)
+ {
+ if (!m_pair_type.IsValid())
+ {
+ TargetSP target_sp(m_backend.GetTargetSP());
+ if (!target_sp)
+ return ValueObjectSP();
+ m_pair_type = GetLLDBNSPairType(target_sp);
+ }
+ if (!m_pair_type.IsValid())
+ return ValueObjectSP();
+
+ DataBufferSP buffer_sp(new DataBufferHeap(2*m_ptr_size,0));
+
+ if (m_ptr_size == 8)
+ {
+ uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr+1) = dict_item.val_ptr;
+ }
+ else
+ {
+ uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
+ *data_ptr = dict_item.key_ptr;
+ *(data_ptr+1) = dict_item.val_ptr;
+ }
+
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",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);
+ }
+ return dict_item.valobj_sp;
+}
+
+template bool
+lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ;
+
+template bool
+lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ;
diff --git a/source/DataFormatters/NSSet.cpp b/source/DataFormatters/NSSet.cpp
new file mode 100644
index 000000000000..02eb2bfc124f
--- /dev/null
+++ b/source/DataFormatters/NSSet.cpp
@@ -0,0 +1,513 @@
+//===-- NSSet.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/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::formatters;
+
+template<bool cf_style>
+bool
+lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+ ProcessSP process_sp = valobj.GetProcessSP();
+ if (!process_sp)
+ return false;
+
+ ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+
+ if (!runtime)
+ return false;
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return false;
+
+ uint32_t ptr_size = process_sp->GetAddressByteSize();
+ bool is_64bit = (ptr_size == 8);
+
+ lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+
+ if (!valobj_addr)
+ return false;
+
+ uint64_t value = 0;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return false;
+
+ if (!strcmp(class_name,"__NSSetI"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ else if (!strcmp(class_name,"__NSSetM"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
+ }
+ /*else if (!strcmp(class_name,"__NSCFSet"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error);
+ if (error.Fail())
+ return false;
+ if (is_64bit)
+ value &= ~0x1fff000000000000UL;
+ }
+ else if (!strcmp(class_name,"NSCountedSet"))
+ {
+ Error error;
+ value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error);
+ if (error.Fail())
+ return false;
+ value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error);
+ if (error.Fail())
+ return false;
+ if (is_64bit)
+ value &= ~0x1fff000000000000UL;
+ }*/
+ else
+ {
+ if (!ExtractValueFromObjCExpression(valobj, "int", "count", value))
+ return false;
+ }
+
+ stream.Printf("%s%" PRIu64 " %s%s",
+ (cf_style ? "@\"" : ""),
+ value,
+ (cf_style ? (value == 1 ? "value" : "values") : (value == 1 ? "object" : "objects")),
+ (cf_style ? "\"" : ""));
+ return true;
+}
+
+SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
+{
+ lldb::ProcessSP process_sp (valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return NULL;
+ ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+ if (!runtime)
+ return NULL;
+
+ if (!valobj_sp->IsPointerType())
+ {
+ Error error;
+ valobj_sp = valobj_sp->AddressOf(error);
+ if (error.Fail() || !valobj_sp)
+ return NULL;
+ }
+
+ ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get()));
+
+ if (!descriptor.get() || !descriptor->IsValid())
+ return NULL;
+
+ const char* class_name = descriptor->GetClassName().GetCString();
+
+ if (!class_name || !*class_name)
+ return NULL;
+
+ if (!strcmp(class_name,"__NSSetI"))
+ {
+ return (new NSSetISyntheticFrontEnd(valobj_sp));
+ }
+ else if (!strcmp(class_name,"__NSSetM"))
+ {
+ return (new NSSetMSyntheticFrontEnd(valobj_sp));
+ }
+ else if ((!strcmp(class_name,"__NSOrderedSetI")) || (!strcmp(class_name,"__NSOrderedSetM")))
+ {
+ return new NSOrderedSetSyntheticFrontEnd(valobj_sp); // this runs code
+ }
+ else
+ {
+ return /*(new NSSetCodeRunningSyntheticFrontEnd(valobj_sp))*/ NULL;
+ }
+}
+
+lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_ptr_size(8),
+m_data_32(NULL),
+m_data_64(NULL)
+{
+ if (valobj_sp)
+ Update();
+}
+
+lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+size_t
+lldb_private::formatters::NSSetISyntheticFrontEnd::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;
+}
+
+size_t
+lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool
+lldb_private::formatters::NSSetISyntheticFrontEnd::Update()
+{
+ m_children.clear();
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ m_ptr_size = 0;
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ if (valobj_sp->IsPointerType())
+ {
+ valobj_sp = valobj_sp->Dereference(error);
+ if (error.Fail() || !valobj_sp)
+ return false;
+ }
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ m_data_ptr = data_location + m_ptr_size;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty())
+ {
+ // do the scan phase
+ lldb::addr_t obj_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while(tries < num_children)
+ {
+ obj_at_idx = m_data_ptr + (test_idx * m_ptr_size);
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Error error;
+ obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!obj_at_idx)
+ continue;
+ tries++;
+
+ SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ SetItemDescriptor &set_item = m_children[idx];
+ if (!set_item.valobj_sp)
+ {
+ // make the new ValueObject
+ StreamString expr;
+ expr.Printf("(id)%" PRIu64,set_item.item_ptr);
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
+ }
+ return set_item.valobj_sp;
+}
+
+lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_exe_ctx_ref(),
+m_ptr_size(8),
+m_data_32(NULL),
+m_data_64(NULL)
+{
+ if (valobj_sp)
+ Update ();
+}
+
+lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd ()
+{
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+}
+
+size_t
+lldb_private::formatters::NSSetMSyntheticFrontEnd::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;
+}
+
+size_t
+lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (!m_data_32 && !m_data_64)
+ return 0;
+ return (m_data_32 ? m_data_32->_used : m_data_64->_used);
+}
+
+bool
+lldb_private::formatters::NSSetMSyntheticFrontEnd::Update()
+{
+ m_children.clear();
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ m_ptr_size = 0;
+ delete m_data_32;
+ m_data_32 = NULL;
+ delete m_data_64;
+ m_data_64 = NULL;
+ if (!valobj_sp)
+ return false;
+ if (!valobj_sp)
+ return false;
+ m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
+ Error error;
+ if (valobj_sp->IsPointerType())
+ {
+ valobj_sp = valobj_sp->Dereference(error);
+ if (error.Fail() || !valobj_sp)
+ return false;
+ }
+ error.Clear();
+ lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
+ if (!process_sp)
+ return false;
+ m_ptr_size = process_sp->GetAddressByteSize();
+ uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size;
+ if (m_ptr_size == 4)
+ {
+ m_data_32 = new DataDescriptor_32();
+ process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error);
+ }
+ else
+ {
+ m_data_64 = new DataDescriptor_64();
+ process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error);
+ }
+ if (error.Fail())
+ return false;
+ return false;
+}
+
+bool
+lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr);
+
+ uint32_t num_children = CalculateNumChildren();
+
+ if (idx >= num_children)
+ return lldb::ValueObjectSP();
+
+ if (m_children.empty())
+ {
+ // do the scan phase
+ lldb::addr_t obj_at_idx = 0;
+
+ uint32_t tries = 0;
+ uint32_t test_idx = 0;
+
+ while(tries < num_children)
+ {
+ obj_at_idx = m_objs_addr + (test_idx * m_ptr_size);
+ ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
+ if (!process_sp)
+ return lldb::ValueObjectSP();
+ Error error;
+ obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error);
+ if (error.Fail())
+ return lldb::ValueObjectSP();
+
+ test_idx++;
+
+ if (!obj_at_idx)
+ continue;
+ tries++;
+
+ SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()};
+
+ m_children.push_back(descriptor);
+ }
+ }
+
+ if (idx >= m_children.size()) // should never happen
+ return lldb::ValueObjectSP();
+
+ SetItemDescriptor &set_item = m_children[idx];
+ if (!set_item.valobj_sp)
+ {
+ // make the new ValueObject
+ StreamString expr;
+ expr.Printf("(id)%" PRIu64,set_item.item_ptr);
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref);
+ }
+ return set_item.valobj_sp;
+}
+
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
+SyntheticChildrenFrontEnd(*valobj_sp.get()),
+m_count(UINT32_MAX),
+m_children()
+{}
+
+size_t
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren ()
+{
+ if (m_count != UINT32_MAX)
+ return m_count;
+ uint64_t count_temp;
+ if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp))
+ return (m_count = count_temp);
+ return (m_count = 0);
+}
+
+lldb::ValueObjectSP
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx)
+{
+ auto iter = m_children.find(idx);
+ if (iter == m_children.end())
+ {
+ lldb::ValueObjectSP retval_sp;
+ if (idx <= m_count)
+ {
+ retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx);
+ if (retval_sp)
+ {
+ StreamString idx_name;
+ idx_name.Printf("[%zu]",idx);
+ retval_sp->SetName(ConstString(idx_name.GetData()));
+ }
+ m_children[idx] = retval_sp;
+ }
+ return retval_sp;
+ }
+ else
+ return iter->second;
+}
+
+bool
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update()
+{
+ return false;
+}
+
+bool
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren ()
+{
+ return true;
+}
+
+size_t
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::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;
+}
+
+lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticFrontEnd ()
+{
+}
+
+template bool
+lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream);
+
+template bool
+lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream);
diff --git a/source/DataFormatters/TypeCategory.cpp b/source/DataFormatters/TypeCategory.cpp
new file mode 100644
index 000000000000..c887be5da496
--- /dev/null
+++ b/source/DataFormatters/TypeCategory.cpp
@@ -0,0 +1,382 @@
+//===-- TypeCategory.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/TypeCategory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeCategoryImpl::TypeCategoryImpl(IFormatChangeListener* clist,
+ ConstString name) :
+m_summary_nav(new SummaryNavigator("summary",clist)),
+m_regex_summary_nav(new RegexSummaryNavigator("regex-summary",clist)),
+m_filter_nav(new FilterNavigator("filter",clist)),
+m_regex_filter_nav(new RegexFilterNavigator("regex-filter",clist)),
+#ifndef LLDB_DISABLE_PYTHON
+m_synth_nav(new SynthNavigator("synth",clist)),
+m_regex_synth_nav(new RegexSynthNavigator("regex-synth",clist)),
+#endif
+m_enabled(false),
+m_change_listener(clist),
+m_mutex(Mutex::eMutexTypeRecursive),
+m_name(name)
+{}
+
+bool
+TypeCategoryImpl::Get (ValueObject& valobj,
+ lldb::TypeSummaryImplSP& entry,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t* reason)
+{
+ if (!IsEnabled())
+ return false;
+ if (GetSummaryNavigator()->Get(valobj, entry, use_dynamic, reason))
+ return true;
+ bool regex = GetRegexSummaryNavigator()->Get(valobj, entry, use_dynamic, reason);
+ if (regex && reason)
+ *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionSummary;
+ return regex;
+}
+
+bool
+TypeCategoryImpl::Get(ValueObject& valobj,
+ lldb::SyntheticChildrenSP& entry_sp,
+ lldb::DynamicValueType use_dynamic,
+ uint32_t* reason)
+{
+ if (!IsEnabled())
+ return false;
+ TypeFilterImpl::SharedPointer filter_sp;
+ uint32_t reason_filter = 0;
+ bool regex_filter = false;
+ // first find both Filter and Synth, and then check which is most recent
+
+ if (!GetFilterNavigator()->Get(valobj, filter_sp, use_dynamic, &reason_filter))
+ regex_filter = GetRegexFilterNavigator()->Get (valobj, filter_sp, use_dynamic, &reason_filter);
+
+#ifndef LLDB_DISABLE_PYTHON
+ bool regex_synth = false;
+ uint32_t reason_synth = 0;
+ bool pick_synth = false;
+ ScriptedSyntheticChildren::SharedPointer synth;
+ if (!GetSyntheticNavigator()->Get(valobj, synth, use_dynamic, &reason_synth))
+ regex_synth = GetRegexSyntheticNavigator()->Get (valobj, synth, use_dynamic, &reason_synth);
+ if (!filter_sp.get() && !synth.get())
+ return false;
+ else if (!filter_sp.get() && synth.get())
+ pick_synth = true;
+
+ else if (filter_sp.get() && !synth.get())
+ pick_synth = false;
+
+ else /*if (filter_sp.get() && synth.get())*/
+ {
+ if (filter_sp->GetRevision() > synth->GetRevision())
+ pick_synth = false;
+ else
+ pick_synth = true;
+ }
+ if (pick_synth)
+ {
+ if (regex_synth && reason)
+ *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter;
+ entry_sp = synth;
+ return true;
+ }
+ else
+ {
+ if (regex_filter && reason)
+ *reason |= lldb_private::eFormatterChoiceCriterionRegularExpressionFilter;
+ entry_sp = filter_sp;
+ return true;
+ }
+
+#else
+ if (filter_sp)
+ {
+ entry_sp = filter_sp;
+ return true;
+ }
+#endif
+
+ return false;
+
+}
+
+void
+TypeCategoryImpl::Clear (FormatCategoryItems items)
+{
+ if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
+ m_summary_nav->Clear();
+ if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
+ m_regex_summary_nav->Clear();
+ if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter )
+ m_filter_nav->Clear();
+ if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
+ m_regex_filter_nav->Clear();
+#ifndef LLDB_DISABLE_PYTHON
+ if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth )
+ m_synth_nav->Clear();
+ if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
+ m_regex_synth_nav->Clear();
+#endif
+}
+
+bool
+TypeCategoryImpl::Delete (ConstString name,
+ FormatCategoryItems items)
+{
+ bool success = false;
+ if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
+ success = m_summary_nav->Delete(name) || success;
+ if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
+ success = m_regex_summary_nav->Delete(name) || success;
+ if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter )
+ success = m_filter_nav->Delete(name) || success;
+ if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
+ success = m_regex_filter_nav->Delete(name) || success;
+#ifndef LLDB_DISABLE_PYTHON
+ if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth )
+ success = m_synth_nav->Delete(name) || success;
+ if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
+ success = m_regex_synth_nav->Delete(name) || success;
+#endif
+ return success;
+}
+
+uint32_t
+TypeCategoryImpl::GetCount (FormatCategoryItems items)
+{
+ uint32_t count = 0;
+ if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
+ count += m_summary_nav->GetCount();
+ if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
+ count += m_regex_summary_nav->GetCount();
+ if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter )
+ count += m_filter_nav->GetCount();
+ if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
+ count += m_regex_filter_nav->GetCount();
+#ifndef LLDB_DISABLE_PYTHON
+ if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth )
+ count += m_synth_nav->GetCount();
+ if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
+ count += m_regex_synth_nav->GetCount();
+#endif
+ return count;
+}
+
+bool
+TypeCategoryImpl::AnyMatches(ConstString type_name,
+ FormatCategoryItems items,
+ bool only_enabled,
+ const char** matching_category,
+ FormatCategoryItems* matching_type)
+{
+ if (!IsEnabled() && only_enabled)
+ return false;
+
+ lldb::TypeSummaryImplSP summary;
+ TypeFilterImpl::SharedPointer filter;
+#ifndef LLDB_DISABLE_PYTHON
+ ScriptedSyntheticChildren::SharedPointer synth;
+#endif
+
+ if ( (items & eFormatCategoryItemSummary) == eFormatCategoryItemSummary )
+ {
+ if (m_summary_nav->Get(type_name, summary))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemSummary;
+ return true;
+ }
+ }
+ if ( (items & eFormatCategoryItemRegexSummary) == eFormatCategoryItemRegexSummary )
+ {
+ if (m_regex_summary_nav->Get(type_name, summary))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemRegexSummary;
+ return true;
+ }
+ }
+ if ( (items & eFormatCategoryItemFilter) == eFormatCategoryItemFilter )
+ {
+ if (m_filter_nav->Get(type_name, filter))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemFilter;
+ return true;
+ }
+ }
+ if ( (items & eFormatCategoryItemRegexFilter) == eFormatCategoryItemRegexFilter )
+ {
+ if (m_regex_filter_nav->Get(type_name, filter))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemRegexFilter;
+ return true;
+ }
+ }
+#ifndef LLDB_DISABLE_PYTHON
+ if ( (items & eFormatCategoryItemSynth) == eFormatCategoryItemSynth )
+ {
+ if (m_synth_nav->Get(type_name, synth))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemSynth;
+ return true;
+ }
+ }
+ if ( (items & eFormatCategoryItemRegexSynth) == eFormatCategoryItemRegexSynth )
+ {
+ if (m_regex_synth_nav->Get(type_name, synth))
+ {
+ if (matching_category)
+ *matching_category = m_name.GetCString();
+ if (matching_type)
+ *matching_type = eFormatCategoryItemRegexSynth;
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+TypeCategoryImpl::SummaryNavigator::MapValueType
+TypeCategoryImpl::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ SummaryNavigator::MapValueType retval;
+
+ if (type_sp)
+ {
+ if (type_sp->IsRegex())
+ m_regex_summary_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ else
+ m_summary_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ }
+
+ return retval;
+}
+
+TypeCategoryImpl::FilterNavigator::MapValueType
+TypeCategoryImpl::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ FilterNavigator::MapValueType retval;
+
+ if (type_sp)
+ {
+ if (type_sp->IsRegex())
+ m_regex_filter_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ else
+ m_filter_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ }
+
+ return retval;
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+TypeCategoryImpl::SynthNavigator::MapValueType
+TypeCategoryImpl::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
+{
+ SynthNavigator::MapValueType retval;
+
+ if (type_sp)
+ {
+ if (type_sp->IsRegex())
+ m_regex_synth_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ else
+ m_synth_nav->GetExact(ConstString(type_sp->GetName()),retval);
+ }
+
+ return retval;
+}
+#endif
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForSummaryAtIndex (size_t index)
+{
+ if (index < m_summary_nav->GetCount())
+ return m_summary_nav->GetTypeNameSpecifierAtIndex(index);
+ else
+ return m_regex_summary_nav->GetTypeNameSpecifierAtIndex(index-m_summary_nav->GetCount());
+}
+
+TypeCategoryImpl::SummaryNavigator::MapValueType
+TypeCategoryImpl::GetSummaryAtIndex (size_t index)
+{
+ if (index < m_summary_nav->GetCount())
+ return m_summary_nav->GetAtIndex(index);
+ else
+ return m_regex_summary_nav->GetAtIndex(index-m_summary_nav->GetCount());
+}
+
+TypeCategoryImpl::FilterNavigator::MapValueType
+TypeCategoryImpl::GetFilterAtIndex (size_t index)
+{
+ if (index < m_filter_nav->GetCount())
+ return m_filter_nav->GetAtIndex(index);
+ else
+ return m_regex_filter_nav->GetAtIndex(index-m_filter_nav->GetCount());
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForFilterAtIndex (size_t index)
+{
+ if (index < m_filter_nav->GetCount())
+ return m_filter_nav->GetTypeNameSpecifierAtIndex(index);
+ else
+ return m_regex_filter_nav->GetTypeNameSpecifierAtIndex(index-m_filter_nav->GetCount());
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+TypeCategoryImpl::SynthNavigator::MapValueType
+TypeCategoryImpl::GetSyntheticAtIndex (size_t index)
+{
+ if (index < m_synth_nav->GetCount())
+ return m_synth_nav->GetAtIndex(index);
+ else
+ return m_regex_synth_nav->GetAtIndex(index-m_synth_nav->GetCount());
+}
+
+lldb::TypeNameSpecifierImplSP
+TypeCategoryImpl::GetTypeNameSpecifierForSyntheticAtIndex (size_t index)
+{
+ if (index < m_synth_nav->GetCount())
+ return m_synth_nav->GetTypeNameSpecifierAtIndex(index);
+ else
+ return m_regex_synth_nav->GetTypeNameSpecifierAtIndex(index - m_synth_nav->GetCount());
+}
+#endif
+
+void
+TypeCategoryImpl::Enable (bool value, uint32_t position)
+{
+ Mutex::Locker locker(m_mutex);
+ 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
new file mode 100644
index 000000000000..4b7222adbec7
--- /dev/null
+++ b/source/DataFormatters/TypeCategoryMap.cpp
@@ -0,0 +1,285 @@
+//===-- TypeCategoryMap.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/TypeCategoryMap.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeCategoryMap::TypeCategoryMap (IFormatChangeListener* lst) :
+m_map_mutex(Mutex::eMutexTypeRecursive),
+listener(lst),
+m_map(),
+m_active_categories()
+{
+ ConstString default_cs("default");
+ lldb::TypeCategoryImplSP default_sp = lldb::TypeCategoryImplSP(new TypeCategoryImpl(listener, default_cs));
+ Add(default_cs,default_sp);
+ Enable(default_cs,First);
+}
+
+void
+TypeCategoryMap::Add (KeyType name, const ValueSP& entry)
+{
+ Mutex::Locker locker(m_map_mutex);
+ m_map[name] = entry;
+ if (listener)
+ listener->Changed();
+}
+
+bool
+TypeCategoryMap::Delete (KeyType name)
+{
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ m_map.erase(name);
+ Disable(name);
+ if (listener)
+ listener->Changed();
+ return true;
+}
+
+bool
+TypeCategoryMap::Enable (KeyType category_name, Position pos)
+{
+ Mutex::Locker locker(m_map_mutex);
+ ValueSP category;
+ if (!Get(category_name,category))
+ return false;
+ return Enable(category, pos);
+}
+
+bool
+TypeCategoryMap::Disable (KeyType category_name)
+{
+ Mutex::Locker locker(m_map_mutex);
+ ValueSP category;
+ if (!Get(category_name,category))
+ return false;
+ return Disable(category);
+}
+
+bool
+TypeCategoryMap::Enable (ValueSP category, Position pos)
+{
+ Mutex::Locker locker(m_map_mutex);
+ if (category.get())
+ {
+ Position pos_w = pos;
+ if (pos == First || m_active_categories.size() == 0)
+ m_active_categories.push_front(category);
+ else if (pos == Last || pos == m_active_categories.size())
+ m_active_categories.push_back(category);
+ else if (pos < m_active_categories.size())
+ {
+ ActiveCategoriesList::iterator iter = m_active_categories.begin();
+ while (pos_w)
+ {
+ pos_w--,iter++;
+ }
+ m_active_categories.insert(iter,category);
+ }
+ else
+ return false;
+ category->Enable(true,
+ pos);
+ return true;
+ }
+ return false;
+}
+
+bool
+TypeCategoryMap::Disable (ValueSP category)
+{
+ Mutex::Locker locker(m_map_mutex);
+ if (category.get())
+ {
+ m_active_categories.remove_if(delete_matching_categories(category));
+ category->Disable();
+ return true;
+ }
+ return false;
+}
+
+void
+TypeCategoryMap::Clear ()
+{
+ Mutex::Locker locker(m_map_mutex);
+ m_map.clear();
+ m_active_categories.clear();
+ if (listener)
+ listener->Changed();
+}
+
+bool
+TypeCategoryMap::Get (KeyType name, ValueSP& entry)
+{
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.find(name);
+ if (iter == m_map.end())
+ return false;
+ entry = iter->second;
+ return true;
+}
+
+bool
+TypeCategoryMap::Get (uint32_t pos, ValueSP& entry)
+{
+ Mutex::Locker locker(m_map_mutex);
+ MapIterator iter = m_map.begin();
+ MapIterator end = m_map.end();
+ while (pos > 0)
+ {
+ iter++;
+ pos--;
+ if (iter == end)
+ return false;
+ }
+ entry = iter->second;
+ return false;
+}
+
+bool
+TypeCategoryMap::AnyMatches (ConstString type_name,
+ TypeCategoryImpl::FormatCategoryItems items,
+ bool only_enabled,
+ const char** matching_category,
+ TypeCategoryImpl::FormatCategoryItems* matching_type)
+{
+ Mutex::Locker locker(m_map_mutex);
+
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++)
+ {
+ if (pos->second->AnyMatches(type_name,
+ items,
+ only_enabled,
+ matching_category,
+ matching_type))
+ return true;
+ }
+ return false;
+}
+
+lldb::TypeSummaryImplSP
+TypeCategoryMap::GetSummaryFormat (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));
+
+ for (begin = m_active_categories.begin(); begin != end; begin++)
+ {
+ lldb::TypeCategoryImplSP category_sp = *begin;
+ lldb::TypeSummaryImplSP current_format;
+ if (log)
+ log->Printf("\n[CategoryMap::GetSummaryFormat] Trying to use category %s", category_sp->GetName());
+ if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why))
+ continue;
+ return current_format;
+ }
+ if (log)
+ log->Printf("[CategoryMap::GetSummaryFormat] nothing found - returning empty SP");
+ return lldb::TypeSummaryImplSP();
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+lldb::SyntheticChildrenSP
+TypeCategoryMap::GetSyntheticChildren (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));
+
+ for (begin = m_active_categories.begin(); begin != end; begin++)
+ {
+ lldb::TypeCategoryImplSP category_sp = *begin;
+ lldb::SyntheticChildrenSP current_format;
+ if (log)
+ log->Printf("\n[CategoryMap::GetSyntheticChildren] Trying to use category %s", category_sp->GetName());
+ if (!category_sp->Get(valobj, current_format, use_dynamic, &reason_why))
+ continue;
+ return current_format;
+ }
+ if (log)
+ log->Printf("[CategoryMap::GetSyntheticChildren] nothing found - returning empty SP");
+ return lldb::SyntheticChildrenSP();
+}
+#endif
+
+void
+TypeCategoryMap::LoopThrough(CallbackType callback, void* param)
+{
+ if (callback)
+ {
+ Mutex::Locker locker(m_map_mutex);
+
+ // loop through enabled categories in respective order
+ {
+ ActiveCategoriesIterator begin, end = m_active_categories.end();
+ for (begin = m_active_categories.begin(); begin != end; begin++)
+ {
+ lldb::TypeCategoryImplSP category = *begin;
+ ConstString type = ConstString(category->GetName());
+ if (!callback(param, category))
+ break;
+ }
+ }
+
+ // loop through disabled categories in just any order
+ {
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++)
+ {
+ if (pos->second->IsEnabled())
+ continue;
+ KeyType type = pos->first;
+ if (!callback(param, pos->second))
+ break;
+ }
+ }
+ }
+}
+
+TypeCategoryImplSP
+TypeCategoryMap::GetAtIndex (uint32_t index)
+{
+ Mutex::Locker locker(m_map_mutex);
+
+ if (index < m_map.size())
+ {
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++)
+ {
+ if (index == 0)
+ return pos->second;
+ index--;
+ }
+ }
+
+ return TypeCategoryImplSP();
+}
diff --git a/source/DataFormatters/TypeFormat.cpp b/source/DataFormatters/TypeFormat.cpp
new file mode 100644
index 000000000000..279704f2af12
--- /dev/null
+++ b/source/DataFormatters/TypeFormat.cpp
@@ -0,0 +1,52 @@
+//===-- TypeFormat.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"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/DataFormatters/TypeFormat.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeFormatImpl::TypeFormatImpl (lldb::Format f,
+ const Flags& flags) :
+m_flags(flags),
+m_format (f)
+{
+}
+
+std::string
+TypeFormatImpl::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf ("%s%s%s%s\n",
+ FormatManager::GetFormatAsCString (GetFormat()),
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+ return sstr.GetString();
+}
+
diff --git a/source/DataFormatters/TypeSummary.cpp b/source/DataFormatters/TypeSummary.cpp
new file mode 100644
index 000000000000..8c4d3f71c050
--- /dev/null
+++ b/source/DataFormatters/TypeSummary.cpp
@@ -0,0 +1,250 @@
+//===-- TypeSummary.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"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/DataFormatters/TypeSummary.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TypeSummaryImpl::TypeSummaryImpl (const TypeSummaryImpl::Flags& flags) :
+m_flags(flags)
+{
+}
+
+
+StringSummaryFormat::StringSummaryFormat (const TypeSummaryImpl::Flags& flags,
+ const char *format_cstr) :
+TypeSummaryImpl(flags),
+m_format()
+{
+ if (format_cstr)
+ m_format.assign(format_cstr);
+}
+
+bool
+StringSummaryFormat::FormatObject (ValueObject *valobj,
+ std::string& retval)
+{
+ if (!valobj)
+ {
+ retval.assign("NULL ValueObject");
+ return false;
+ }
+
+ StreamString s;
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ SymbolContext sc;
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame)
+ sc = frame->GetSymbolContext(lldb::eSymbolContextEverything);
+
+ if (IsOneliner())
+ {
+ ValueObject* object;
+
+ ValueObjectSP synth_valobj = valobj->GetSyntheticValue();
+ if (synth_valobj)
+ object = synth_valobj.get();
+ else
+ object = valobj;
+
+ const uint32_t num_children = object->GetNumChildren();
+ if (num_children)
+ {
+ s.PutChar('(');
+
+ for (uint32_t idx=0; idx<num_children; ++idx)
+ {
+ lldb::ValueObjectSP child_sp(object->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ if (idx)
+ s.PutCString(", ");
+ if (!HideNames())
+ {
+ s.PutCString(child_sp.get()->GetName().AsCString());
+ s.PutCString(" = ");
+ }
+ child_sp.get()->DumpPrintableRepresentation(s,
+ ValueObject::eValueObjectRepresentationStyleSummary,
+ lldb::eFormatInvalid,
+ ValueObject::ePrintableRepresentationSpecialCasesDisable);
+ }
+ }
+
+ s.PutChar(')');
+
+ retval.assign(s.GetString());
+ return true;
+ }
+ else
+ {
+ retval.assign("error: oneliner for no children");
+ return false;
+ }
+
+ }
+ else
+ {
+ if (Debugger::FormatPrompt(m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, valobj))
+ {
+ retval.assign(s.GetString());
+ return true;
+ }
+ else
+ {
+ retval.assign("error: summary string parsing error");
+ return false;
+ }
+ }
+}
+
+std::string
+StringSummaryFormat::GetDescription ()
+{
+ StreamString sstr;
+
+ sstr.Printf ("`%s`%s%s%s%s%s%s%s", m_format.c_str(),
+ Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren() ? "" : " (show children)",
+ !DoesPrintValue() ? " (hide value)" : "",
+ IsOneliner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames() ? " (hide member names)" : "");
+ return sstr.GetString();
+}
+
+CXXFunctionSummaryFormat::CXXFunctionSummaryFormat (const TypeSummaryImpl::Flags& flags,
+ Callback impl,
+ const char* description) :
+TypeSummaryImpl(flags),
+m_impl(impl),
+m_description(description ? description : "")
+{
+}
+
+bool
+CXXFunctionSummaryFormat::FormatObject (ValueObject *valobj,
+ std::string& dest)
+{
+ dest.clear();
+ StreamString stream;
+ if (!m_impl || m_impl(*valobj,stream) == false)
+ return false;
+ dest.assign(stream.GetData());
+ return true;
+}
+
+std::string
+CXXFunctionSummaryFormat::GetDescription ()
+{
+ StreamString sstr;
+ sstr.Printf ("`%s (%p) `%s%s%s%s%s%s%s", m_description.c_str(),m_impl,
+ Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren() ? "" : " (show children)",
+ !DoesPrintValue() ? " (hide value)" : "",
+ IsOneliner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames() ? " (hide member names)" : "");
+ return sstr.GetString();
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+
+
+ScriptSummaryFormat::ScriptSummaryFormat (const TypeSummaryImpl::Flags& flags,
+ const char * function_name,
+ const char * python_script) :
+TypeSummaryImpl(flags),
+m_function_name(),
+m_python_script(),
+m_script_function_sp()
+{
+ if (function_name)
+ m_function_name.assign(function_name);
+ if (python_script)
+ m_python_script.assign(python_script);
+}
+
+bool
+ScriptSummaryFormat::FormatObject (ValueObject *valobj,
+ std::string& retval)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ if (!valobj)
+ return false;
+
+ Host::SetCrashDescriptionWithFormat("[Python summary] Name: %s - Function: %s",
+ valobj->GetName().AsCString("unknown"),
+ m_function_name.c_str());
+
+ TargetSP target_sp(valobj->GetTargetSP());
+
+ if (!target_sp)
+ {
+ retval.assign("error: no target");
+ return false;
+ }
+
+ ScriptInterpreter *script_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+
+ if (!script_interpreter)
+ {
+ retval.assign("error: no ScriptInterpreter");
+ return false;
+ }
+
+ return script_interpreter->GetScriptedSummary(m_function_name.c_str(),
+ valobj->GetSP(),
+ m_script_function_sp,
+ retval);
+
+}
+
+std::string
+ScriptSummaryFormat::GetDescription ()
+{
+ StreamString sstr;
+ sstr.Printf ("%s%s%s%s%s%s%s\n%s", Cascades() ? "" : " (not cascading)",
+ !DoesPrintChildren() ? "" : " (show children)",
+ !DoesPrintValue() ? " (hide value)" : "",
+ IsOneliner() ? " (one-line printout)" : "",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ HideNames() ? " (hide member names)" : "",
+ m_python_script.c_str());
+ return sstr.GetString();
+
+}
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/DataFormatters/TypeSynthetic.cpp b/source/DataFormatters/TypeSynthetic.cpp
new file mode 100644
index 000000000000..972be486b783
--- /dev/null
+++ b/source/DataFormatters/TypeSynthetic.cpp
@@ -0,0 +1,114 @@
+//===-- TypeSynthetic.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"
+
+// C Includes
+
+// C++ Includes
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/DataFormatters/TypeSynthetic.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+std::string
+TypeFilterImpl::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf("%s%s%s {\n",
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "");
+
+ for (size_t i = 0; i < GetCount(); i++)
+ {
+ sstr.Printf(" %s\n",
+ GetExpressionPathAtIndex(i));
+ }
+
+ sstr.Printf("}");
+ return sstr.GetString();
+}
+
+std::string
+CXXSyntheticChildren::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf("%s%s%s Generator at %p - %s",
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ m_create_callback,
+ m_description.c_str());
+
+ return sstr.GetString();
+}
+
+#ifndef LLDB_DISABLE_PYTHON
+
+ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, ValueObject &backend) :
+SyntheticChildrenFrontEnd(backend),
+m_python_class(pclass),
+m_wrapper_sp(),
+m_interpreter(NULL)
+{
+ if (backend == LLDB_INVALID_UID)
+ return;
+
+ TargetSP target_sp = backend.GetTargetSP();
+
+ if (!target_sp)
+ return;
+
+ m_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+
+ if (m_interpreter != NULL)
+ m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider(m_python_class.c_str(), backend.GetSP());
+}
+
+ScriptedSyntheticChildren::FrontEnd::~FrontEnd()
+{
+}
+
+lldb::ValueObjectSP
+ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex (size_t idx)
+{
+ if (!m_wrapper_sp || !m_interpreter)
+ return lldb::ValueObjectSP();
+
+ return m_interpreter->GetChildAtIndex(m_wrapper_sp, idx);
+}
+
+std::string
+ScriptedSyntheticChildren::GetDescription()
+{
+ StreamString sstr;
+ sstr.Printf("%s%s%s Python class %s",
+ Cascades() ? "" : " (not cascading)",
+ SkipsPointers() ? " (skip pointers)" : "",
+ SkipsReferences() ? " (skip references)" : "",
+ m_python_class.c_str());
+
+ return sstr.GetString();
+}
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/Expression/ASTDumper.cpp b/source/Expression/ASTDumper.cpp
new file mode 100644
index 000000000000..5210d149e666
--- /dev/null
+++ b/source/Expression/ASTDumper.cpp
@@ -0,0 +1,132 @@
+//===-- ASTDumper.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/Expression/ASTDumper.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace lldb_private;
+
+ASTDumper::ASTDumper (clang::Decl *decl)
+{
+ clang::DeclContext *decl_ctx = llvm::dyn_cast<clang::DeclContext>(decl);
+
+ bool has_external_lexical_storage;
+ bool has_external_visible_storage;
+
+ if (decl_ctx)
+ {
+ has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage();
+ has_external_visible_storage = decl_ctx->hasExternalVisibleStorage();
+ decl_ctx->setHasExternalLexicalStorage(false);
+ decl_ctx->setHasExternalVisibleStorage(false);
+ }
+
+ llvm::raw_string_ostream os(m_dump);
+ decl->print (os);
+ os.flush();
+
+ if (decl_ctx)
+ {
+ decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage);
+ decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage);
+ }
+}
+
+ASTDumper::ASTDumper (clang::DeclContext *decl_ctx)
+{
+ bool has_external_lexical_storage = decl_ctx->hasExternalLexicalStorage();
+ bool has_external_visible_storage = decl_ctx->hasExternalVisibleStorage();
+
+ decl_ctx->setHasExternalLexicalStorage(false);
+ decl_ctx->setHasExternalVisibleStorage(false);
+
+ if (clang::Decl *decl = llvm::dyn_cast<clang::Decl>(decl_ctx))
+ {
+ llvm::raw_string_ostream os(m_dump);
+ decl->print (os);
+ os.flush();
+ }
+ else
+ {
+ m_dump.assign("<DeclContext is not a Decl>");
+ }
+
+ decl_ctx->setHasExternalLexicalStorage(has_external_lexical_storage);
+ decl_ctx->setHasExternalVisibleStorage(has_external_visible_storage);
+}
+
+ASTDumper::ASTDumper (const clang::Type *type)
+{
+ m_dump = clang::QualType(type, 0).getAsString();
+}
+
+ASTDumper::ASTDumper (clang::QualType type)
+{
+ m_dump = type.getAsString();
+}
+
+ASTDumper::ASTDumper (lldb::clang_type_t type)
+{
+ m_dump = clang::QualType::getFromOpaquePtr(type).getAsString();
+}
+
+ASTDumper::ASTDumper (const ClangASTType &clang_type)
+{
+ m_dump = clang_type.GetQualType().getAsString();
+}
+
+
+const char *
+ASTDumper::GetCString()
+{
+ return m_dump.c_str();
+}
+
+void ASTDumper::ToSTDERR()
+{
+ fprintf(stderr, "%s\n", m_dump.c_str());
+}
+
+void ASTDumper::ToLog(Log *log, const char *prefix)
+{
+ size_t len = m_dump.length() + 1;
+
+ char *alloc = (char*)malloc(len);
+ char *str = alloc;
+
+ memcpy(str, m_dump.c_str(), len);
+
+ char *end = NULL;
+
+ end = strchr(str, '\n');
+
+ while (end)
+ {
+ *end = '\0';
+
+ log->Printf("%s%s", prefix, str);
+
+ *end = '\n';
+
+ str = end + 1;
+ end = strchr(str, '\n');
+ }
+
+ log->Printf("%s%s", prefix, str);
+
+ free(alloc);
+}
+
+void ASTDumper::ToStream(lldb::StreamSP &stream)
+{
+ stream->PutCString(m_dump.c_str());
+}
diff --git a/source/Expression/ASTResultSynthesizer.cpp b/source/Expression/ASTResultSynthesizer.cpp
new file mode 100644
index 000000000000..76c2577af533
--- /dev/null
+++ b/source/Expression/ASTResultSynthesizer.cpp
@@ -0,0 +1,512 @@
+//===-- ASTResultSynthesizer.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 "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Expression/ASTResultSynthesizer.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Target/Target.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
+ Target &target) :
+ m_ast_context (NULL),
+ m_passthrough (passthrough),
+ m_passthrough_sema (NULL),
+ m_target (target),
+ m_sema (NULL)
+{
+ if (!m_passthrough)
+ return;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTResultSynthesizer::~ASTResultSynthesizer()
+{
+}
+
+void
+ASTResultSynthesizer::Initialize(ASTContext &Context)
+{
+ m_ast_context = &Context;
+
+ if (m_passthrough)
+ m_passthrough->Initialize(Context);
+}
+
+void
+ASTResultSynthesizer::TransformTopLevelDecl(Decl* D)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D))
+ {
+ if (log && log->GetVerbose())
+ {
+ if (named_decl->getIdentifier())
+ log->Printf("TransformTopLevelDecl(%s)", named_decl->getIdentifier()->getNameStart());
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
+ log->Printf("TransformTopLevelDecl(%s)", method_decl->getSelector().getAsString().c_str());
+ else
+ log->Printf("TransformTopLevelDecl(<complex>)");
+ }
+
+ }
+
+ if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D))
+ {
+ RecordDecl::decl_iterator decl_iterator;
+
+ for (decl_iterator = linkage_spec_decl->decls_begin();
+ decl_iterator != linkage_spec_decl->decls_end();
+ ++decl_iterator)
+ {
+ TransformTopLevelDecl(*decl_iterator);
+ }
+ }
+ else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
+ {
+ if (m_ast_context &&
+ !method_decl->getSelector().getAsString().compare("$__lldb_expr:"))
+ {
+ RecordPersistentTypes(method_decl);
+ SynthesizeObjCMethodResult(method_decl);
+ }
+ }
+ else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D))
+ {
+ if (m_ast_context &&
+ !function_decl->getNameInfo().getAsString().compare("$__lldb_expr"))
+ {
+ RecordPersistentTypes(function_decl);
+ SynthesizeFunctionResult(function_decl);
+ }
+ }
+}
+
+bool
+ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
+{
+ DeclGroupRef::iterator decl_iterator;
+
+ for (decl_iterator = D.begin();
+ decl_iterator != D.end();
+ ++decl_iterator)
+ {
+ Decl *decl = *decl_iterator;
+
+ TransformTopLevelDecl(decl);
+ }
+
+ if (m_passthrough)
+ return m_passthrough->HandleTopLevelDecl(D);
+ return true;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeFunctionResult (FunctionDecl *FunDecl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!m_sema)
+ return false;
+
+ FunctionDecl *function_decl = FunDecl;
+
+ if (!function_decl)
+ return false;
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ function_decl->print(os);
+
+ os.flush();
+
+ log->Printf ("Untransformed function AST:\n%s", s.c_str());
+ }
+
+ Stmt *function_body = function_decl->getBody();
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
+
+ bool ret = SynthesizeBodyResult (compound_stmt,
+ function_decl);
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ function_decl->print(os);
+
+ os.flush();
+
+ log->Printf ("Transformed function AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeObjCMethodResult (ObjCMethodDecl *MethodDecl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!m_sema)
+ return false;
+
+ if (!MethodDecl)
+ return false;
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ MethodDecl->print(os);
+
+ os.flush();
+
+ log->Printf ("Untransformed method AST:\n%s", s.c_str());
+ }
+
+ Stmt *method_body = MethodDecl->getBody();
+
+ if (!method_body)
+ return false;
+
+ CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
+
+ bool ret = SynthesizeBodyResult (compound_stmt,
+ MethodDecl);
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream os(s);
+
+ MethodDecl->print(os);
+
+ os.flush();
+
+ log->Printf("Transformed method AST:\n%s", s.c_str());
+ }
+
+ return ret;
+}
+
+bool
+ASTResultSynthesizer::SynthesizeBodyResult (CompoundStmt *Body,
+ DeclContext *DC)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ASTContext &Ctx(*m_ast_context);
+
+ if (!Body)
+ return false;
+
+ if (Body->body_empty())
+ return false;
+
+ Stmt **last_stmt_ptr = Body->body_end() - 1;
+ Stmt *last_stmt = *last_stmt_ptr;
+
+ while (dyn_cast<NullStmt>(last_stmt))
+ {
+ if (last_stmt_ptr != Body->body_begin())
+ {
+ last_stmt_ptr--;
+ last_stmt = *last_stmt_ptr;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ Expr *last_expr = dyn_cast<Expr>(last_stmt);
+
+ if (!last_expr)
+ // No auxiliary variable necessary; expression returns void
+ return true;
+
+ // In C++11, last_expr can be a LValueToRvalue implicit cast. Strip that off if that's the
+ // case.
+
+ do {
+ ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr);
+
+ if (!implicit_cast)
+ break;
+
+ if (implicit_cast->getCastKind() != CK_LValueToRValue)
+ break;
+
+ last_expr = implicit_cast->getSubExpr();
+ } while (0);
+
+ // is_lvalue is used to record whether the expression returns an assignable Lvalue or an
+ // Rvalue. This is relevant because they are handled differently.
+ //
+ // For Lvalues
+ //
+ // - In AST result synthesis (here!) the expression E is transformed into an initialization
+ // T *$__lldb_expr_result_ptr = &E.
+ //
+ // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
+ // passed into the expression.
+ //
+ // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at
+ // an entry in the struct ($__lldb_arg) passed into the expression. (Other persistent
+ // variables are treated similarly, having been materialized as references, but in those
+ // cases the value of the reference itself is never modified.)
+ //
+ // - During materialization, $0 (the result persistent variable) is ignored.
+ //
+ // - During dematerialization, $0 is marked up as a load address with value equal to the
+ // contents of the structure entry.
+ //
+ // For Rvalues
+ //
+ // - In AST result synthesis the expression E is transformed into an initialization
+ // static T $__lldb_expr_result = E.
+ //
+ // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be
+ // passed into the expression.
+ //
+ // - In IR transformations, an instruction is inserted at the beginning of the function to
+ // dereference the pointer resident in the slot. Reads and writes to $__lldb_expr_result
+ // are redirected at that dereferenced version. Guard variables for the static variable
+ // are excised.
+ //
+ // - During materialization, $0 (the result persistent variable) is populated with the location
+ // of a newly-allocated area of memory.
+ //
+ // - During dematerialization, $0 is ignored.
+
+ bool is_lvalue =
+ (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) &&
+ (last_expr->getObjectKind() == OK_Ordinary);
+
+ QualType expr_qual_type = last_expr->getType();
+ const clang::Type *expr_type = expr_qual_type.getTypePtr();
+
+ if (!expr_type)
+ return false;
+
+ if (expr_type->isVoidType())
+ return true;
+
+ if (log)
+ {
+ std::string s = expr_qual_type.getAsString();
+
+ log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
+ }
+
+ clang::VarDecl *result_decl = NULL;
+
+ if (is_lvalue)
+ {
+ IdentifierInfo *result_ptr_id;
+
+ if (expr_type->isFunctionType())
+ result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should be treated like function pointers
+ else
+ result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
+
+ m_sema->RequireCompleteType(SourceLocation(), expr_qual_type, clang::diag::err_incomplete_type);
+
+ QualType ptr_qual_type;
+
+ if (expr_qual_type->getAs<ObjCObjectType>() != NULL)
+ ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
+ else
+ ptr_qual_type = Ctx.getPointerType(expr_qual_type);
+
+ result_decl = VarDecl::Create(Ctx,
+ DC,
+ SourceLocation(),
+ SourceLocation(),
+ result_ptr_id,
+ ptr_qual_type,
+ NULL,
+ SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
+
+ m_sema->AddInitializerToDecl(result_decl, address_of_expr.take(), true, false);
+ }
+ else
+ {
+ IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
+
+ result_decl = VarDecl::Create(Ctx,
+ DC,
+ SourceLocation(),
+ SourceLocation(),
+ &result_id,
+ expr_qual_type,
+ NULL,
+ SC_Static);
+
+ if (!result_decl)
+ return false;
+
+ m_sema->AddInitializerToDecl(result_decl, last_expr, true, false);
+ }
+
+ DC->addDecl(result_decl);
+
+ ///////////////////////////////
+ // call AddInitializerToDecl
+ //
+
+ //m_sema->AddInitializerToDecl(result_decl, last_expr);
+
+ /////////////////////////////////
+ // call ConvertDeclToDeclGroup
+ //
+
+ Sema::DeclGroupPtrTy result_decl_group_ptr;
+
+ result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
+
+ ////////////////////////
+ // call ActOnDeclStmt
+ //
+
+ StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(result_decl_group_ptr,
+ SourceLocation(),
+ SourceLocation()));
+
+ ////////////////////////////////////////////////
+ // replace the old statement with the new one
+ //
+
+ *last_stmt_ptr = reinterpret_cast<Stmt*>(result_initialization_stmt_result.take());
+
+ return true;
+}
+
+void
+ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
+{
+ if (m_passthrough)
+ m_passthrough->HandleTranslationUnit(Ctx);
+}
+
+void
+ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx)
+{
+ typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
+
+ for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
+ e = TypeDeclIterator(FunDeclCtx->decls_end());
+ i != e;
+ ++i)
+ {
+ MaybeRecordPersistentType(*i);
+ }
+}
+
+void
+ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D)
+{
+ if (!D->getIdentifier())
+ return;
+
+ StringRef name = D->getName();
+
+ if (name.size() == 0 || name[0] != '$')
+ return;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ConstString name_cs(name.str().c_str());
+
+ if (log)
+ log->Printf ("Recording persistent type %s\n", name_cs.GetCString());
+
+ Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(m_target.GetScratchClangASTContext()->getASTContext(),
+ m_ast_context,
+ D);
+
+ if (TypeDecl *TypeDecl_scratch = dyn_cast<TypeDecl>(D_scratch))
+ m_target.GetPersistentVariables().RegisterPersistentType(name_cs, TypeDecl_scratch);
+}
+
+void
+ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
+{
+ if (m_passthrough)
+ m_passthrough->HandleTagDeclDefinition(D);
+}
+
+void
+ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
+{
+ if (m_passthrough)
+ m_passthrough->CompleteTentativeDefinition(D);
+}
+
+void
+ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
+{
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD, DefinitionRequired);
+}
+
+void
+ASTResultSynthesizer::PrintStats()
+{
+ if (m_passthrough)
+ m_passthrough->PrintStats();
+}
+
+void
+ASTResultSynthesizer::InitializeSema(Sema &S)
+{
+ m_sema = &S;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->InitializeSema(S);
+}
+
+void
+ASTResultSynthesizer::ForgetSema()
+{
+ m_sema = NULL;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/source/Expression/ASTStructExtractor.cpp b/source/Expression/ASTStructExtractor.cpp
new file mode 100644
index 000000000000..d1f21923deb4
--- /dev/null
+++ b/source/Expression/ASTStructExtractor.cpp
@@ -0,0 +1,220 @@
+//===-- ASTStructExtractor.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 "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/ASTStructExtractor.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ASTStructExtractor::ASTStructExtractor(ASTConsumer *passthrough,
+ const char *struct_name,
+ ClangFunction &function) :
+ m_ast_context (NULL),
+ m_passthrough (passthrough),
+ m_passthrough_sema (NULL),
+ m_sema (NULL),
+ m_action (NULL),
+ m_function (function),
+ m_struct_name (struct_name)
+{
+ if (!m_passthrough)
+ return;
+
+ m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ASTStructExtractor::~ASTStructExtractor()
+{
+}
+
+void
+ASTStructExtractor::Initialize(ASTContext &Context)
+{
+ m_ast_context = &Context;
+
+ if (m_passthrough)
+ m_passthrough->Initialize(Context);
+}
+
+void
+ASTStructExtractor::ExtractFromFunctionDecl(FunctionDecl *F)
+{
+ if (!F->hasBody())
+ return;
+
+ Stmt *body_stmt = F->getBody();
+ CompoundStmt *body_compound_stmt = dyn_cast<CompoundStmt>(body_stmt);
+
+ if (!body_compound_stmt)
+ return; // do we have to handle this?
+
+ RecordDecl *struct_decl = NULL;
+
+ StringRef desired_name(m_struct_name.c_str());
+
+ for (CompoundStmt::const_body_iterator bi = body_compound_stmt->body_begin(), be = body_compound_stmt->body_end();
+ bi != be;
+ ++bi)
+ {
+ Stmt *curr_stmt = *bi;
+ DeclStmt *curr_decl_stmt = dyn_cast<DeclStmt>(curr_stmt);
+ if (!curr_decl_stmt)
+ continue;
+ DeclGroupRef decl_group = curr_decl_stmt->getDeclGroup();
+ for (Decl *candidate_decl : decl_group)
+ {
+ RecordDecl *candidate_record_decl = dyn_cast<RecordDecl>(candidate_decl);
+ if (!candidate_record_decl)
+ continue;
+ if (candidate_record_decl->getName() == desired_name)
+ {
+ struct_decl = candidate_record_decl;
+ break;
+ }
+ }
+ if (struct_decl)
+ break;
+ }
+
+ if (!struct_decl)
+ return;
+
+ const ASTRecordLayout* struct_layout(&m_ast_context->getASTRecordLayout (struct_decl));
+
+ if (!struct_layout)
+ return;
+
+ m_function.m_struct_size = struct_layout->getSize().getQuantity(); // TODO Store m_struct_size as CharUnits
+ m_function.m_return_offset = struct_layout->getFieldOffset(struct_layout->getFieldCount() - 1) / 8;
+ m_function.m_return_size = struct_layout->getDataSize().getQuantity() - m_function.m_return_offset;
+
+ for (unsigned field_index = 0, num_fields = struct_layout->getFieldCount();
+ field_index < num_fields;
+ ++field_index)
+ {
+ m_function.m_member_offsets.push_back(struct_layout->getFieldOffset(field_index) / 8);
+ }
+
+ m_function.m_struct_valid = true;
+}
+
+void
+ASTStructExtractor::ExtractFromTopLevelDecl(Decl* D)
+{
+ LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
+
+ if (linkage_spec_decl)
+ {
+ RecordDecl::decl_iterator decl_iterator;
+
+ for (decl_iterator = linkage_spec_decl->decls_begin();
+ decl_iterator != linkage_spec_decl->decls_end();
+ ++decl_iterator)
+ {
+ ExtractFromTopLevelDecl(*decl_iterator);
+ }
+ }
+
+ FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
+
+ if (m_ast_context &&
+ function_decl &&
+ !m_function.m_wrapper_function_name.compare(function_decl->getNameAsString().c_str()))
+ {
+ ExtractFromFunctionDecl(function_decl);
+ }
+}
+
+bool
+ASTStructExtractor::HandleTopLevelDecl(DeclGroupRef D)
+{
+ DeclGroupRef::iterator decl_iterator;
+
+ for (decl_iterator = D.begin();
+ decl_iterator != D.end();
+ ++decl_iterator)
+ {
+ Decl *decl = *decl_iterator;
+
+ ExtractFromTopLevelDecl(decl);
+ }
+
+ if (m_passthrough)
+ return m_passthrough->HandleTopLevelDecl(D);
+ return true;
+}
+
+void
+ASTStructExtractor::HandleTranslationUnit(ASTContext &Ctx)
+{
+ if (m_passthrough)
+ m_passthrough->HandleTranslationUnit(Ctx);
+}
+
+void
+ASTStructExtractor::HandleTagDeclDefinition(TagDecl *D)
+{
+ if (m_passthrough)
+ m_passthrough->HandleTagDeclDefinition(D);
+}
+
+void
+ASTStructExtractor::CompleteTentativeDefinition(VarDecl *D)
+{
+ if (m_passthrough)
+ m_passthrough->CompleteTentativeDefinition(D);
+}
+
+void
+ASTStructExtractor::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired)
+{
+ if (m_passthrough)
+ m_passthrough->HandleVTable(RD, DefinitionRequired);
+}
+
+void
+ASTStructExtractor::PrintStats()
+{
+ if (m_passthrough)
+ m_passthrough->PrintStats();
+}
+
+void
+ASTStructExtractor::InitializeSema(Sema &S)
+{
+ m_sema = &S;
+ m_action = reinterpret_cast<Action*>(m_sema);
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->InitializeSema(S);
+}
+
+void
+ASTStructExtractor::ForgetSema()
+{
+ m_sema = NULL;
+ m_action = NULL;
+
+ if (m_passthrough_sema)
+ m_passthrough_sema->ForgetSema();
+}
diff --git a/source/Expression/ClangASTSource.cpp b/source/Expression/ClangASTSource.cpp
new file mode 100644
index 000000000000..49513d740f30
--- /dev/null
+++ b/source/Expression/ClangASTSource.cpp
@@ -0,0 +1,1866 @@
+//===-- ClangASTSource.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Expression/ASTDumper.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+ClangASTSource::~ClangASTSource()
+{
+ m_ast_importer->ForgetDestination(m_ast_context);
+
+ // We are in the process of destruction, don't create clang ast context on demand
+ // by passing false to Target::GetScratchClangASTContext(create_on_demand).
+ ClangASTContext *scratch_clang_ast_context = m_target->GetScratchClangASTContext(false);
+
+ if (!scratch_clang_ast_context)
+ return;
+
+ clang::ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
+
+ if (!scratch_ast_context)
+ return;
+
+ if (m_ast_context != scratch_ast_context)
+ m_ast_importer->ForgetSource(scratch_ast_context, m_ast_context);
+}
+
+void
+ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer)
+{
+ if (!m_ast_context)
+ return;
+
+ m_ast_context->getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ m_ast_context->getTranslationUnitDecl()->setHasExternalLexicalStorage();
+}
+
+// The core lookup interface.
+bool
+ClangASTSource::FindExternalVisibleDeclsByName
+(
+ const DeclContext *decl_ctx,
+ DeclarationName clang_decl_name
+)
+{
+ if (!m_ast_context)
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ if (GetImportInProgress())
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ std::string decl_name (clang_decl_name.getAsString());
+
+// if (m_decl_map.DoingASTImport ())
+// return DeclContext::lookup_result();
+//
+ switch (clang_decl_name.getNameKind()) {
+ // Normal identifiers.
+ case DeclarationName::Identifier:
+ {
+ clang::IdentifierInfo *identifier_info = clang_decl_name.getAsIdentifierInfo();
+
+ if (!identifier_info ||
+ identifier_info->getBuiltinID() != 0)
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ }
+ break;
+
+ // Operator names. Not important for now.
+ case DeclarationName::CXXOperatorName:
+ case DeclarationName::CXXLiteralOperatorName:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ // Using directives found in this context.
+ // Tell Sema we didn't find any or we'll end up getting asked a *lot*.
+ case DeclarationName::CXXUsingDirective:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case DeclarationName::ObjCZeroArgSelector:
+ case DeclarationName::ObjCOneArgSelector:
+ case DeclarationName::ObjCMultiArgSelector:
+ {
+ llvm::SmallVector<NamedDecl*, 1> method_decls;
+
+ NameSearchContext method_search_context (*this, method_decls, clang_decl_name, decl_ctx);
+
+ FindObjCMethodDecls(method_search_context);
+
+ SetExternalVisibleDeclsForName (decl_ctx, clang_decl_name, method_decls);
+ return (method_decls.size() > 0);
+ }
+ // These aren't possible in the global context.
+ case DeclarationName::CXXConstructorName:
+ case DeclarationName::CXXDestructorName:
+ case DeclarationName::CXXConversionFunctionName:
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+
+ if (!GetLookupsEnabled())
+ {
+ // Wait until we see a '$' at the start of a name before we start doing
+ // any lookups so we can avoid lookup up all of the builtin types.
+ if (!decl_name.empty() && decl_name[0] == '$')
+ {
+ SetLookupsEnabled (true);
+ }
+ else
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ }
+
+ ConstString const_decl_name(decl_name.c_str());
+
+ const char *uniqued_const_decl_name = const_decl_name.GetCString();
+ if (m_active_lookups.find (uniqued_const_decl_name) != m_active_lookups.end())
+ {
+ // We are currently looking up this name...
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ m_active_lookups.insert(uniqued_const_decl_name);
+// static uint32_t g_depth = 0;
+// ++g_depth;
+// printf("[%5u] FindExternalVisibleDeclsByName() \"%s\"\n", g_depth, uniqued_const_decl_name);
+ llvm::SmallVector<NamedDecl*, 4> name_decls;
+ NameSearchContext name_search_context(*this, name_decls, clang_decl_name, decl_ctx);
+ FindExternalVisibleDecls(name_search_context);
+ SetExternalVisibleDeclsForName (decl_ctx, clang_decl_name, name_decls);
+// --g_depth;
+ m_active_lookups.erase (uniqued_const_decl_name);
+ return (name_decls.size() != 0);
+}
+
+void
+ClangASTSource::CompleteType (TagDecl *tag_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ log->Printf(" CompleteTagDecl[%u] on (ASTContext*)%p Completing (TagDecl*)%p named %s",
+ current_id,
+ m_ast_context,
+ tag_decl,
+ tag_decl->getName().str().c_str());
+
+ log->Printf(" CTD[%u] Before:", current_id);
+ ASTDumper dumper((Decl*)tag_decl);
+ dumper.ToLog(log, " [CTD] ");
+ }
+
+ if (!m_ast_importer->CompleteTagDecl (tag_decl))
+ {
+ // We couldn't complete the type. Maybe there's a definition
+ // somewhere else that can be completed.
+
+ if (log)
+ log->Printf(" CTD[%u] Type could not be completed in the module in which it was first found.", current_id);
+
+ bool found = false;
+
+ DeclContext *decl_ctx = tag_decl->getDeclContext();
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(decl_ctx))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CTD[%u] Inspecting namespace map %p (%d entries)",
+ current_id,
+ namespace_map.get(),
+ (int)namespace_map->size());
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e && !found;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CTD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ TypeList types;
+
+ SymbolContext null_sc;
+ ConstString name(tag_decl->getName().str().c_str());
+
+ i->first->FindTypesInNamespace(null_sc, name, &i->second, UINT32_MAX, types);
+
+ for (uint32_t ti = 0, te = types.GetSize();
+ ti != te && !found;
+ ++ti)
+ {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
+
+ if (!type)
+ continue;
+
+ ClangASTType clang_type (type->GetClangFullType());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+ found = true;
+ }
+ }
+ }
+ else
+ {
+ TypeList types;
+
+ SymbolContext null_sc;
+ ConstString name(tag_decl->getName().str().c_str());
+ ClangNamespaceDecl namespace_decl;
+
+ const ModuleList &module_list = m_target->GetImages();
+
+ bool exact_match = false;
+ module_list.FindTypes (null_sc, name, exact_match, UINT32_MAX, types);
+
+ for (uint32_t ti = 0, te = types.GetSize();
+ ti != te && !found;
+ ++ti)
+ {
+ lldb::TypeSP type = types.GetTypeAtIndex(ti);
+
+ if (!type)
+ continue;
+
+ ClangASTType clang_type (type->GetClangFullType());
+
+ if (!clang_type)
+ continue;
+
+ const TagType *tag_type = clang_type.GetQualType()->getAs<TagType>();
+
+ if (!tag_type)
+ continue;
+
+ TagDecl *candidate_tag_decl = const_cast<TagDecl*>(tag_type->getDecl());
+
+ if (m_ast_importer->CompleteTagDeclWithOrigin (tag_decl, candidate_tag_decl))
+ found = true;
+ }
+ }
+ }
+
+ if (log)
+ {
+ log->Printf(" [CTD] After:");
+ ASTDumper dumper((Decl*)tag_decl);
+ dumper.ToLog(log, " [CTD] ");
+ }
+}
+
+void
+ClangASTSource::CompleteType (clang::ObjCInterfaceDecl *interface_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ log->Printf(" [CompleteObjCInterfaceDecl] on (ASTContext*)%p Completing an ObjCInterfaceDecl named %s", m_ast_context, interface_decl->getName().str().c_str());
+ log->Printf(" [COID] Before:");
+ ASTDumper dumper((Decl*)interface_decl);
+ dumper.ToLog(log, " [COID] ");
+ }
+
+ m_ast_importer->CompleteObjCInterfaceDecl (interface_decl);
+
+ if (log)
+ {
+ log->Printf(" [COID] After:");
+ ASTDumper dumper((Decl*)interface_decl);
+ dumper.ToLog(log, " [COID] ");
+ }
+}
+
+clang::ObjCInterfaceDecl *
+ClangASTSource::GetCompleteObjCInterface (clang::ObjCInterfaceDecl *interface_decl)
+{
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return NULL;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ return NULL;
+
+ ConstString class_name(interface_decl->getNameAsString().c_str());
+
+ lldb::TypeSP complete_type_sp(language_runtime->LookupInCompleteClassCache(class_name));
+
+ if (!complete_type_sp)
+ return NULL;
+
+ TypeFromUser complete_type = TypeFromUser(complete_type_sp->GetClangFullType());
+ lldb::clang_type_t complete_opaque_type = complete_type.GetOpaqueQualType();
+
+ if (!complete_opaque_type)
+ return NULL;
+
+ const clang::Type *complete_clang_type = QualType::getFromOpaquePtr(complete_opaque_type).getTypePtr();
+ const ObjCInterfaceType *complete_interface_type = dyn_cast<ObjCInterfaceType>(complete_clang_type);
+
+ if (!complete_interface_type)
+ return NULL;
+
+ ObjCInterfaceDecl *complete_iface_decl(complete_interface_type->getDecl());
+
+ return complete_iface_decl;
+}
+
+clang::ExternalLoadResult
+ClangASTSource::FindExternalLexicalDecls (const DeclContext *decl_context,
+ bool (*predicate)(Decl::Kind),
+ llvm::SmallVectorImpl<Decl*> &decls)
+{
+ ClangASTMetrics::RegisterLexicalQuery();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const Decl *context_decl = dyn_cast<Decl>(decl_context);
+
+ if (!context_decl)
+ return ELR_Failure;
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in '%s' (%sDecl*)%p with %s predicate",
+ current_id,
+ m_ast_context,
+ context_named_decl->getNameAsString().c_str(),
+ context_decl->getDeclKindName(),
+ context_decl,
+ (predicate ? "non-null" : "null"));
+ else if(context_decl)
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in (%sDecl*)%p with %s predicate",
+ current_id,
+ m_ast_context,
+ context_decl->getDeclKindName(),
+ context_decl,
+ (predicate ? "non-null" : "null"));
+ else
+ log->Printf("FindExternalLexicalDecls[%u] on (ASTContext*)%p in a NULL context with %s predicate",
+ current_id,
+ m_ast_context,
+ (predicate ? "non-null" : "null"));
+ }
+
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ if (!m_ast_importer->ResolveDeclOrigin(context_decl, &original_decl, &original_ctx))
+ return ELR_Failure;
+
+ if (log)
+ {
+ log->Printf(" FELD[%u] Original decl (ASTContext*)%p (Decl*)%p:", current_id, original_ctx, original_decl);
+ ASTDumper(original_decl).ToLog(log, " ");
+ }
+
+ if (ObjCInterfaceDecl *original_iface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl))
+ {
+ ObjCInterfaceDecl *complete_iface_decl = GetCompleteObjCInterface(original_iface_decl);
+
+ if (complete_iface_decl && (complete_iface_decl != original_iface_decl))
+ {
+ original_decl = complete_iface_decl;
+ original_ctx = &complete_iface_decl->getASTContext();
+
+ m_ast_importer->SetDeclOrigin(context_decl, original_iface_decl);
+ }
+ }
+
+ if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl))
+ {
+ ExternalASTSource *external_source = original_ctx->getExternalSource();
+
+ if (external_source)
+ external_source->CompleteType (original_tag_decl);
+ }
+
+ const DeclContext *original_decl_context = dyn_cast<DeclContext>(original_decl);
+
+ if (!original_decl_context)
+ return ELR_Failure;
+
+ for (TagDecl::decl_iterator iter = original_decl_context->decls_begin();
+ iter != original_decl_context->decls_end();
+ ++iter)
+ {
+ Decl *decl = *iter;
+
+ if (!predicate || predicate(decl->getKind()))
+ {
+ if (log)
+ {
+ ASTDumper ast_dumper(decl);
+ if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context_decl))
+ log->Printf(" FELD[%d] Adding [to %sDecl %s] lexical %sDecl %s", current_id, context_named_decl->getDeclKindName(), context_named_decl->getNameAsString().c_str(), decl->getDeclKindName(), ast_dumper.GetCString());
+ else
+ log->Printf(" FELD[%d] Adding lexical %sDecl %s", current_id, decl->getDeclKindName(), ast_dumper.GetCString());
+ }
+
+ Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, original_ctx, decl);
+
+ if (!copied_decl)
+ continue;
+
+ if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl))
+ {
+ QualType copied_field_type = copied_field->getType();
+
+ m_ast_importer->RequireCompleteType(copied_field_type);
+ }
+
+ decls.push_back(copied_decl);
+
+ DeclContext *decl_context_non_const = const_cast<DeclContext *>(decl_context);
+
+ if (copied_decl->getDeclContext() != decl_context)
+ {
+ if (copied_decl->getDeclContext()->containsDecl(copied_decl))
+ copied_decl->getDeclContext()->removeDecl(copied_decl);
+ copied_decl->setDeclContext(decl_context_non_const);
+ }
+
+ if (!decl_context_non_const->containsDecl(copied_decl))
+ decl_context_non_const->addDeclInternal(copied_decl);
+ }
+ }
+
+ return ELR_AlreadyLoaded;
+}
+
+void
+ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context)
+{
+ assert (m_ast_context);
+
+ ClangASTMetrics::RegisterVisibleQuery();
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (!context.m_decl_context)
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a NULL DeclContext", current_id, m_ast_context, name.GetCString());
+ else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context))
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in '%s'", current_id, m_ast_context, name.GetCString(), context_named_decl->getNameAsString().c_str());
+ else
+ log->Printf("ClangASTSource::FindExternalVisibleDecls[%u] on (ASTContext*)%p for '%s' in a '%s'", current_id, m_ast_context, name.GetCString(), context.m_decl_context->getDeclKindName());
+ }
+
+ context.m_namespace_map.reset(new ClangASTImporter::NamespaceMap);
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CAS::FEVD[%u] Inspecting namespace map %p (%d entries)",
+ current_id,
+ namespace_map.get(),
+ (int)namespace_map->size());
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ FindExternalVisibleDecls(context,
+ i->first,
+ i->second,
+ current_id);
+ }
+ }
+ else if (isa<ObjCInterfaceDecl>(context.m_decl_context))
+ {
+ FindObjCPropertyAndIvarDecls(context);
+ }
+ else if (!isa<TranslationUnitDecl>(context.m_decl_context))
+ {
+ // we shouldn't be getting FindExternalVisibleDecls calls for these
+ return;
+ }
+ else
+ {
+ ClangNamespaceDecl namespace_decl;
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Searching the root namespace", current_id);
+
+ FindExternalVisibleDecls(context,
+ lldb::ModuleSP(),
+ namespace_decl,
+ current_id);
+ }
+
+ if (!context.m_namespace_map->empty())
+ {
+ if (log && log->GetVerbose())
+ log->Printf(" CAS::FEVD[%u] Registering namespace map %p (%d entries)",
+ current_id,
+ context.m_namespace_map.get(),
+ (int)context.m_namespace_map->size());
+
+ NamespaceDecl *clang_namespace_decl = AddNamespace(context, context.m_namespace_map);
+
+ if (clang_namespace_decl)
+ clang_namespace_decl->setHasExternalVisibleStorage();
+ }
+}
+
+void
+ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module_sp,
+ ClangNamespaceDecl &namespace_decl,
+ unsigned int current_id)
+{
+ assert (m_ast_context);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ SymbolContextList sc_list;
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ const char *name_unique_cstr = name.GetCString();
+
+ static ConstString id_name("id");
+ static ConstString Class_name("Class");
+
+ if (name == id_name || name == Class_name)
+ return;
+
+ if (name_unique_cstr == NULL)
+ return;
+
+ // The ClangASTSource is not responsible for finding $-names.
+ if (name_unique_cstr[0] == '$')
+ return;
+
+ if (module_sp && namespace_decl)
+ {
+ ClangNamespaceDecl found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
+
+ if (symbol_vendor)
+ {
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
+
+ if (found_namespace_decl)
+ {
+ context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(module_sp, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ module_sp->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target->GetImages();
+ Mutex::Locker modules_locker (target_images.GetMutex());
+
+ for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
+ {
+ lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
+
+ if (!image)
+ continue;
+
+ ClangNamespaceDecl found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = image->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &namespace_decl);
+
+ if (found_namespace_decl)
+ {
+ context.m_namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(image, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CAS::FEVD[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ image->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ }
+
+ do
+ {
+ TypeList types;
+ SymbolContext null_sc;
+ const bool exact_match = false;
+
+ if (module_sp && namespace_decl)
+ module_sp->FindTypesInNamespace(null_sc, name, &namespace_decl, 1, types);
+ else
+ m_target->GetImages().FindTypes(null_sc, name, exact_match, 1, types);
+
+ if (types.GetSize())
+ {
+ lldb::TypeSP type_sp = types.GetTypeAtIndex(0);
+
+ if (log)
+ {
+ const char *name_string = type_sp->GetName().GetCString();
+
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\": %s",
+ current_id,
+ name.GetCString(),
+ (name_string ? name_string : "<anonymous>"));
+ }
+
+ ClangASTType full_type = type_sp->GetClangFullType();
+
+ ClangASTType copied_clang_type (GuardedCopyType(full_type));
+
+ if (!copied_clang_type)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type",
+ current_id);
+
+ break;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+ }
+ else
+ {
+ do
+ {
+ // Couldn't find any types elsewhere. Try the Objective-C runtime if one exists.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ break;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ break;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ if (log)
+ {
+ log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime",
+ current_id,
+ name.GetCString());
+ }
+
+ ClangASTType copied_clang_type (GuardedCopyType(types[0]));
+
+ if (!copied_clang_type)
+ {
+ if (log)
+ log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
+ current_id);
+
+ break;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+ }
+ while(0);
+ }
+
+ } while(0);
+}
+
+template <class D> class TaggedASTDecl {
+public:
+ TaggedASTDecl() : decl(NULL) { }
+ TaggedASTDecl(D *_decl) : decl(_decl) { }
+ bool IsValid() const { return (decl != NULL); }
+ bool IsInvalid() const { return !IsValid(); }
+ D *operator->() const { return decl; }
+ D *decl;
+};
+
+template <class D2, template <class D> class TD, class D1>
+TD<D2>
+DynCast(TD<D1> source)
+{
+ return TD<D2> (dyn_cast<D2>(source.decl));
+}
+
+template <class D = Decl> class DeclFromParser;
+template <class D = Decl> class DeclFromUser;
+
+template <class D> class DeclFromParser : public TaggedASTDecl<D> {
+public:
+ DeclFromParser() : TaggedASTDecl<D>() { }
+ DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }
+
+ DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
+};
+
+template <class D> class DeclFromUser : public TaggedASTDecl<D> {
+public:
+ DeclFromUser() : TaggedASTDecl<D>() { }
+ DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
+
+ DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
+};
+
+template <class D>
+DeclFromUser<D>
+DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
+{
+ DeclFromUser <> origin_decl;
+ importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
+ if (origin_decl.IsInvalid())
+ return DeclFromUser<D>();
+ return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
+}
+
+template <class D>
+DeclFromParser<D>
+DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx)
+{
+ DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl));
+ if (parser_generic_decl.IsInvalid())
+ return DeclFromParser<D>();
+ return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
+}
+
+static bool
+FindObjCMethodDeclsWithOrigin (unsigned int current_id,
+ NameSearchContext &context,
+ ObjCInterfaceDecl *original_interface_decl,
+ clang::ASTContext *ast_context,
+ ClangASTImporter *ast_importer,
+ const char *log_info)
+{
+ const DeclarationName &decl_name(context.m_decl_name);
+ clang::ASTContext *original_ctx = &original_interface_decl->getASTContext();
+
+ Selector original_selector;
+
+ if (decl_name.isObjCZeroArgSelector())
+ {
+ IdentifierInfo *ident = &original_ctx->Idents.get(decl_name.getAsString());
+ original_selector = original_ctx->Selectors.getSelector(0, &ident);
+ }
+ else if (decl_name.isObjCOneArgSelector())
+ {
+ const std::string &decl_name_string = decl_name.getAsString();
+ std::string decl_name_string_without_colon(decl_name_string.c_str(), decl_name_string.length() - 1);
+ IdentifierInfo *ident = &original_ctx->Idents.get(decl_name_string_without_colon.c_str());
+ original_selector = original_ctx->Selectors.getSelector(1, &ident);
+ }
+ else
+ {
+ SmallVector<IdentifierInfo *, 4> idents;
+
+ clang::Selector sel = decl_name.getObjCSelector();
+
+ unsigned num_args = sel.getNumArgs();
+
+ for (unsigned i = 0;
+ i != num_args;
+ ++i)
+ {
+ idents.push_back(&original_ctx->Idents.get(sel.getNameForSlot(i)));
+ }
+
+ original_selector = original_ctx->Selectors.getSelector(num_args, idents.data());
+ }
+
+ DeclarationName original_decl_name(original_selector);
+
+ ObjCInterfaceDecl::lookup_result result = original_interface_decl->lookup(original_decl_name);
+
+ if (result.empty())
+ return false;
+
+ if (!result[0])
+ return false;
+
+ ObjCMethodDecl *result_method = dyn_cast<ObjCMethodDecl>(result[0]);
+
+ if (!result_method)
+ return false;
+
+ Decl *copied_decl = ast_importer->CopyDecl(ast_context, &result_method->getASTContext(), result_method);
+
+ if (!copied_decl)
+ return false;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ ASTDumper dumper((Decl*)copied_method_decl);
+ log->Printf(" CAS::FOMD[%d] found (%s) %s", current_id, log_info, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(copied_method_decl);
+
+ return true;
+}
+
+void
+ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ const DeclarationName &decl_name(context.m_decl_name);
+ const DeclContext *decl_ctx(context.m_decl_context);
+
+ const ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl_ctx);
+
+ if (!interface_decl)
+ return;
+
+ do
+ {
+ Decl *original_decl = NULL;
+ ASTContext *original_ctx = NULL;
+
+ m_ast_importer->ResolveDeclOrigin(interface_decl, &original_decl, &original_ctx);
+
+ if (!original_decl)
+ break;
+
+ ObjCInterfaceDecl *original_interface_decl = dyn_cast<ObjCInterfaceDecl>(original_decl);
+
+ if (FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ original_interface_decl,
+ m_ast_context,
+ m_ast_importer,
+ "at origin"))
+ return; // found it, no need to look any further
+ } while (0);
+
+ StreamString ss;
+
+ if (decl_name.isObjCZeroArgSelector())
+ {
+ ss.Printf("%s", decl_name.getAsString().c_str());
+ }
+ else if (decl_name.isObjCOneArgSelector())
+ {
+ ss.Printf("%s", decl_name.getAsString().c_str());
+ }
+ else
+ {
+ clang::Selector sel = decl_name.getObjCSelector();
+
+ for (unsigned i = 0, e = sel.getNumArgs();
+ i != e;
+ ++i)
+ {
+ llvm::StringRef r = sel.getNameForSlot(i);
+ ss.Printf("%s:", r.str().c_str());
+ }
+ }
+ ss.Flush();
+
+ ConstString selector_name(ss.GetData());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCMethodDecls[%d] on (ASTContext*)%p for selector [%s %s]",
+ current_id,
+ m_ast_context,
+ interface_decl->getNameAsString().c_str(),
+ selector_name.AsCString());
+ SymbolContextList sc_list;
+
+ const bool include_symbols = false;
+ const bool include_inlines = false;
+ const bool append = false;
+
+ std::string interface_name = interface_decl->getNameAsString();
+
+ do
+ {
+ StreamString ms;
+ ms.Printf("-[%s %s]", interface_name.c_str(), selector_name.AsCString());
+ ms.Flush();
+ ConstString instance_method_name(ms.GetData());
+
+ m_target->GetImages().FindFunctions(instance_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list);
+
+ if (sc_list.GetSize())
+ break;
+
+ ms.Clear();
+ ms.Printf("+[%s %s]", interface_name.c_str(), selector_name.AsCString());
+ ms.Flush();
+ ConstString class_method_name(ms.GetData());
+
+ m_target->GetImages().FindFunctions(class_method_name, lldb::eFunctionNameTypeFull, include_symbols, include_inlines, append, sc_list);
+
+ if (sc_list.GetSize())
+ break;
+
+ // Fall back and check for methods in categories. If we find methods this way, we need to check that they're actually in
+ // categories on the desired class.
+
+ SymbolContextList candidate_sc_list;
+
+ m_target->GetImages().FindFunctions(selector_name, lldb::eFunctionNameTypeSelector, include_symbols, include_inlines, append, candidate_sc_list);
+
+ for (uint32_t ci = 0, ce = candidate_sc_list.GetSize();
+ ci != ce;
+ ++ci)
+ {
+ SymbolContext candidate_sc;
+
+ if (!candidate_sc_list.GetContextAtIndex(ci, candidate_sc))
+ continue;
+
+ if (!candidate_sc.function)
+ continue;
+
+ const char *candidate_name = candidate_sc.function->GetName().AsCString();
+
+ const char *cursor = candidate_name;
+
+ if (*cursor != '+' && *cursor != '-')
+ continue;
+
+ ++cursor;
+
+ if (*cursor != '[')
+ continue;
+
+ ++cursor;
+
+ size_t interface_len = interface_name.length();
+
+ if (strncmp(cursor, interface_name.c_str(), interface_len))
+ continue;
+
+ cursor += interface_len;
+
+ if (*cursor == ' ' || *cursor == '(')
+ sc_list.Append(candidate_sc);
+ }
+ }
+ while (0);
+
+ if (sc_list.GetSize())
+ {
+ // We found a good function symbol. Use that.
+
+ for (uint32_t i = 0, e = sc_list.GetSize();
+ i != e;
+ ++i)
+ {
+ SymbolContext sc;
+
+ if (!sc_list.GetContextAtIndex(i, sc))
+ continue;
+
+ if (!sc.function)
+ continue;
+
+ DeclContext *function_ctx = sc.function->GetClangDeclContext();
+
+ if (!function_ctx)
+ continue;
+
+ ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(function_ctx);
+
+ if (!method_decl)
+ continue;
+
+ ObjCInterfaceDecl *found_interface_decl = method_decl->getClassInterface();
+
+ if (!found_interface_decl)
+ continue;
+
+ if (found_interface_decl->getName() == interface_decl->getName())
+ {
+ Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, &method_decl->getASTContext(), method_decl);
+
+ if (!copied_decl)
+ continue;
+
+ ObjCMethodDecl *copied_method_decl = dyn_cast<ObjCMethodDecl>(copied_decl);
+
+ if (!copied_method_decl)
+ continue;
+
+ if (log)
+ {
+ ASTDumper dumper((Decl*)copied_method_decl);
+ log->Printf(" CAS::FOMD[%d] found (in symbols) %s", current_id, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(copied_method_decl);
+ }
+ }
+
+ return;
+ }
+
+ // Try the debug information.
+
+ do
+ {
+ ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(interface_decl));
+
+ if (!complete_interface_decl)
+ break;
+
+ // We found the complete interface. The runtime never needs to be queried in this scenario.
+
+ DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
+
+ if (complete_interface_decl == interface_decl)
+ break; // already checked this one
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ complete_interface_decl,
+ &complete_iface_decl->getASTContext());
+
+ FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ complete_interface_decl,
+ m_ast_context,
+ m_ast_importer,
+ "in debug info");
+
+ return;
+ }
+ while (0);
+
+ do
+ {
+ // Check the runtime only if the debug information didn't have a complete interface.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ break;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ break;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ ConstString interface_name(interface_decl->getNameAsString().c_str());
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(interface_name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
+
+ const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
+
+ if (!runtime_interface_type)
+ break;
+
+ ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();
+
+ FindObjCMethodDeclsWithOrigin(current_id,
+ context,
+ runtime_interface_decl,
+ m_ast_context,
+ m_ast_importer,
+ "in runtime");
+ }
+ while(0);
+}
+
+static bool
+FindObjCPropertyAndIvarDeclsWithOrigin (unsigned int current_id,
+ NameSearchContext &context,
+ clang::ASTContext &ast_context,
+ ClangASTImporter *ast_importer,
+ DeclFromUser<const ObjCInterfaceDecl> &origin_iface_decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (origin_iface_decl.IsInvalid())
+ return false;
+
+ std::string name_str = context.m_decl_name.getAsString();
+ StringRef name(name_str.c_str());
+ IdentifierInfo &name_identifier(origin_iface_decl->getASTContext().Idents.get(name));
+
+ DeclFromUser<ObjCPropertyDecl> origin_property_decl(origin_iface_decl->FindPropertyDeclaration(&name_identifier));
+
+ bool found = false;
+
+ if (origin_property_decl.IsValid())
+ {
+ DeclFromParser<ObjCPropertyDecl> parser_property_decl(origin_property_decl.Import(ast_importer, ast_context));
+ if (parser_property_decl.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper dumper((Decl*)parser_property_decl.decl);
+ log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(parser_property_decl.decl);
+ found = true;
+ }
+ }
+
+ DeclFromUser<ObjCIvarDecl> origin_ivar_decl(origin_iface_decl->getIvarDecl(&name_identifier));
+
+ if (origin_ivar_decl.IsValid())
+ {
+ DeclFromParser<ObjCIvarDecl> parser_ivar_decl(origin_ivar_decl.Import(ast_importer, ast_context));
+ if (parser_ivar_decl.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper dumper((Decl*)parser_ivar_decl.decl);
+ log->Printf(" CAS::FOPD[%d] found %s", current_id, dumper.GetCString());
+ }
+
+ context.AddNamedDecl(parser_ivar_decl.decl);
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+void
+ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ DeclFromParser<const ObjCInterfaceDecl> parser_iface_decl(cast<ObjCInterfaceDecl>(context.m_decl_context));
+ DeclFromUser<const ObjCInterfaceDecl> origin_iface_decl(parser_iface_decl.GetOrigin(m_ast_importer));
+
+ ConstString class_name(parser_iface_decl->getNameAsString().c_str());
+
+ if (log)
+ log->Printf("ClangASTSource::FindObjCPropertyAndIvarDecls[%d] on (ASTContext*)%p for '%s.%s'",
+ current_id,
+ m_ast_context,
+ parser_iface_decl->getNameAsString().c_str(),
+ context.m_decl_name.getAsString().c_str());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ origin_iface_decl))
+ return;
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] couldn't find the property on origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p, searching elsewhere...",
+ current_id,
+ origin_iface_decl.decl,
+ &origin_iface_decl->getASTContext());
+
+ SymbolContext null_sc;
+ TypeList type_list;
+
+ do
+ {
+ ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));
+
+ if (!complete_interface_decl)
+ break;
+
+ // We found the complete interface. The runtime never needs to be queried in this scenario.
+
+ DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);
+
+ if (complete_iface_decl.decl == origin_iface_decl.decl)
+ break; // already checked this one
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ complete_iface_decl.decl,
+ &complete_iface_decl->getASTContext());
+
+ FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ complete_iface_decl);
+
+ return;
+ }
+ while(0);
+
+ do
+ {
+ // Check the runtime only if the debug information didn't have a complete interface.
+
+ lldb::ProcessSP process(m_target->GetProcessSP());
+
+ if (!process)
+ return;
+
+ ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
+
+ if (!language_runtime)
+ return;
+
+ TypeVendor *type_vendor = language_runtime->GetTypeVendor();
+
+ if (!type_vendor)
+ break;
+
+ bool append = false;
+ uint32_t max_matches = 1;
+ std::vector <ClangASTType> types;
+
+ if (!type_vendor->FindTypes(class_name,
+ append,
+ max_matches,
+ types))
+ break;
+
+ const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
+
+ const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);
+
+ if (!runtime_interface_type)
+ break;
+
+ DeclFromUser<const ObjCInterfaceDecl> runtime_iface_decl(runtime_interface_type->getDecl());
+
+ if (log)
+ log->Printf("CAS::FOPD[%d] trying runtime (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
+ current_id,
+ runtime_iface_decl.decl,
+ &runtime_iface_decl->getASTContext());
+
+ if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
+ context,
+ *m_ast_context,
+ m_ast_importer,
+ runtime_iface_decl))
+ return;
+ }
+ while(0);
+}
+
+typedef llvm::DenseMap <const FieldDecl *, uint64_t> FieldOffsetMap;
+typedef llvm::DenseMap <const CXXRecordDecl *, CharUnits> BaseOffsetMap;
+
+template <class D, class O>
+static bool
+ImportOffsetMap (llvm::DenseMap <const D*, O> &destination_map,
+ llvm::DenseMap <const D*, O> &source_map,
+ ClangASTImporter *importer,
+ ASTContext &dest_ctx)
+{
+ typedef llvm::DenseMap <const D*, O> MapType;
+
+ for (typename MapType::iterator fi = source_map.begin(), fe = source_map.end();
+ fi != fe;
+ ++fi)
+ {
+ DeclFromUser <D> user_decl(const_cast<D*>(fi->first));
+ DeclFromParser <D> parser_decl(user_decl.Import(importer, dest_ctx));
+ if (parser_decl.IsInvalid())
+ return false;
+ destination_map.insert(std::pair<const D *, O>(parser_decl.decl, fi->second));
+ }
+
+ return true;
+}
+
+template <bool IsVirtual> bool ExtractBaseOffsets (const ASTRecordLayout &record_layout,
+ DeclFromUser<const CXXRecordDecl> &record,
+ BaseOffsetMap &base_offsets)
+{
+ for (CXXRecordDecl::base_class_const_iterator
+ bi = (IsVirtual ? record->vbases_begin() : record->bases_begin()),
+ be = (IsVirtual ? record->vbases_end() : record->bases_end());
+ bi != be;
+ ++bi)
+ {
+ if (!IsVirtual && bi->isVirtual())
+ continue;
+
+ const clang::Type *origin_base_type = bi->getType().getTypePtr();
+ const clang::RecordType *origin_base_record_type = origin_base_type->getAs<RecordType>();
+
+ if (!origin_base_record_type)
+ return false;
+
+ DeclFromUser <RecordDecl> origin_base_record(origin_base_record_type->getDecl());
+
+ if (origin_base_record.IsInvalid())
+ return false;
+
+ DeclFromUser <CXXRecordDecl> origin_base_cxx_record(DynCast<CXXRecordDecl>(origin_base_record));
+
+ if (origin_base_cxx_record.IsInvalid())
+ return false;
+
+ CharUnits base_offset;
+
+ if (IsVirtual)
+ base_offset = record_layout.getVBaseClassOffset(origin_base_cxx_record.decl);
+ else
+ base_offset = record_layout.getBaseClassOffset(origin_base_cxx_record.decl);
+
+ base_offsets.insert(std::pair<const CXXRecordDecl *, CharUnits>(origin_base_cxx_record.decl, base_offset));
+ }
+
+ return true;
+}
+
+bool
+ClangASTSource::layoutRecordType(const RecordDecl *record,
+ uint64_t &size,
+ uint64_t &alignment,
+ FieldOffsetMap &field_offsets,
+ BaseOffsetMap &base_offsets,
+ BaseOffsetMap &virtual_base_offsets)
+{
+ ClangASTMetrics::RegisterRecordLayout();
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ log->Printf("LayoutRecordType[%u] on (ASTContext*)%p for (RecordDecl*)%p [name = '%s']",
+ current_id,
+ m_ast_context,
+ record,
+ record->getNameAsString().c_str());
+ }
+
+
+ DeclFromParser <const RecordDecl> parser_record(record);
+ DeclFromUser <const RecordDecl> origin_record(parser_record.GetOrigin(m_ast_importer));
+
+ if (origin_record.IsInvalid())
+ return false;
+
+ FieldOffsetMap origin_field_offsets;
+ BaseOffsetMap origin_base_offsets;
+ BaseOffsetMap origin_virtual_base_offsets;
+
+ ClangASTContext::GetCompleteDecl(&origin_record->getASTContext(), const_cast<RecordDecl*>(origin_record.decl));
+
+ if (!origin_record.decl->getDefinition())
+ return false;
+
+ const ASTRecordLayout &record_layout(origin_record->getASTContext().getASTRecordLayout(origin_record.decl));
+
+ int field_idx = 0, field_count = record_layout.getFieldCount();
+
+ for (RecordDecl::field_iterator fi = origin_record->field_begin(), fe = origin_record->field_end();
+ fi != fe;
+ ++fi)
+ {
+ if (field_idx >= field_count)
+ return false; // Layout didn't go well. Bail out.
+
+ uint64_t field_offset = record_layout.getFieldOffset(field_idx);
+
+ origin_field_offsets.insert(std::pair<const FieldDecl *, uint64_t>(*fi, field_offset));
+
+ field_idx++;
+ }
+
+ ASTContext &parser_ast_context(record->getASTContext());
+
+ DeclFromUser <const CXXRecordDecl> origin_cxx_record(DynCast<const CXXRecordDecl>(origin_record));
+
+ if (origin_cxx_record.IsValid())
+ {
+ if (!ExtractBaseOffsets<false>(record_layout, origin_cxx_record, origin_base_offsets) ||
+ !ExtractBaseOffsets<true>(record_layout, origin_cxx_record, origin_virtual_base_offsets))
+ return false;
+ }
+
+ if (!ImportOffsetMap(field_offsets, origin_field_offsets, m_ast_importer, parser_ast_context) ||
+ !ImportOffsetMap(base_offsets, origin_base_offsets, m_ast_importer, parser_ast_context) ||
+ !ImportOffsetMap(virtual_base_offsets, origin_virtual_base_offsets, m_ast_importer, parser_ast_context))
+ return false;
+
+ size = record_layout.getSize().getQuantity() * m_ast_context->getCharWidth();
+ alignment = record_layout.getAlignment().getQuantity() * m_ast_context->getCharWidth();
+
+ if (log)
+ {
+ log->Printf("LRT[%u] returned:", current_id);
+ log->Printf("LRT[%u] Original = (RecordDecl*)%p", current_id, origin_record.decl);
+ log->Printf("LRT[%u] Size = %" PRId64, current_id, size);
+ log->Printf("LRT[%u] Alignment = %" PRId64, current_id, alignment);
+ log->Printf("LRT[%u] Fields:", current_id);
+ for (RecordDecl::field_iterator fi = record->field_begin(), fe = record->field_end();
+ fi != fe;
+ ++fi)
+ {
+ log->Printf("LRT[%u] (FieldDecl*)%p, Name = '%s', Offset = %" PRId64 " bits",
+ current_id,
+ *fi,
+ fi->getNameAsString().c_str(),
+ field_offsets[*fi]);
+ }
+ DeclFromParser <const CXXRecordDecl> parser_cxx_record = DynCast<const CXXRecordDecl>(parser_record);
+ if (parser_cxx_record.IsValid())
+ {
+ log->Printf("LRT[%u] Bases:", current_id);
+ for (CXXRecordDecl::base_class_const_iterator bi = parser_cxx_record->bases_begin(), be = parser_cxx_record->bases_end();
+ bi != be;
+ ++bi)
+ {
+ bool is_virtual = bi->isVirtual();
+
+ QualType base_type = bi->getType();
+ const RecordType *base_record_type = base_type->getAs<RecordType>();
+ DeclFromParser <RecordDecl> base_record(base_record_type->getDecl());
+ DeclFromParser <CXXRecordDecl> base_cxx_record = DynCast<CXXRecordDecl>(base_record);
+
+ log->Printf("LRT[%u] %s(CXXRecordDecl*)%p, Name = '%s', Offset = %" PRId64 " chars",
+ current_id,
+ (is_virtual ? "Virtual " : ""),
+ base_cxx_record.decl,
+ base_cxx_record.decl->getNameAsString().c_str(),
+ (is_virtual ? virtual_base_offsets[base_cxx_record.decl].getQuantity() :
+ base_offsets[base_cxx_record.decl].getQuantity()));
+ }
+ }
+ else
+ {
+ log->Printf("LRD[%u] Not a CXXRecord, so no bases", current_id);
+ }
+ }
+
+ return true;
+}
+
+void
+ClangASTSource::CompleteNamespaceMap (ClangASTImporter::NamespaceMapSP &namespace_map,
+ const ConstString &name,
+ ClangASTImporter::NamespaceMapSP &parent_map) const
+{
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ if (parent_map && parent_map->size())
+ log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s in namespace %s",
+ current_id,
+ m_ast_context,
+ name.GetCString(),
+ parent_map->begin()->second.GetNamespaceDecl()->getDeclName().getAsString().c_str());
+ else
+ log->Printf("CompleteNamespaceMap[%u] on (ASTContext*)%p Searching for namespace %s",
+ current_id,
+ m_ast_context,
+ name.GetCString());
+ }
+
+
+ if (parent_map)
+ {
+ for (ClangASTImporter::NamespaceMap::iterator i = parent_map->begin(), e = parent_map->end();
+ i != e;
+ ++i)
+ {
+ ClangNamespaceDecl found_namespace_decl;
+
+ lldb::ModuleSP module_sp = i->first;
+ ClangNamespaceDecl module_parent_namespace_decl = i->second;
+
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &module_parent_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(module_sp, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CMN[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ module_sp->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+ else
+ {
+ const ModuleList &target_images = m_target->GetImages();
+ Mutex::Locker modules_locker(target_images.GetMutex());
+
+ ClangNamespaceDecl null_namespace_decl;
+
+ for (size_t i = 0, e = target_images.GetSize(); i < e; ++i)
+ {
+ lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i);
+
+ if (!image)
+ continue;
+
+ ClangNamespaceDecl found_namespace_decl;
+
+ SymbolVendor *symbol_vendor = image->GetSymbolVendor();
+
+ if (!symbol_vendor)
+ continue;
+
+ SymbolContext null_sc;
+
+ found_namespace_decl = symbol_vendor->FindNamespace(null_sc, name, &null_namespace_decl);
+
+ if (!found_namespace_decl)
+ continue;
+
+ namespace_map->push_back(std::pair<lldb::ModuleSP, ClangNamespaceDecl>(image, found_namespace_decl));
+
+ if (log)
+ log->Printf(" CMN[%u] Found namespace %s in module %s",
+ current_id,
+ name.GetCString(),
+ image->GetFileSpec().GetFilename().GetCString());
+ }
+ }
+}
+
+NamespaceDecl *
+ClangASTSource::AddNamespace (NameSearchContext &context, ClangASTImporter::NamespaceMapSP &namespace_decls)
+{
+ if (!namespace_decls)
+ return NULL;
+
+ const ClangNamespaceDecl &namespace_decl = namespace_decls->begin()->second;
+
+ Decl *copied_decl = m_ast_importer->CopyDecl(m_ast_context, namespace_decl.GetASTContext(), namespace_decl.GetNamespaceDecl());
+
+ if (!copied_decl)
+ return NULL;
+
+ NamespaceDecl *copied_namespace_decl = dyn_cast<NamespaceDecl>(copied_decl);
+
+ if (!copied_namespace_decl)
+ return NULL;
+
+ context.m_decls.push_back(copied_namespace_decl);
+
+ m_ast_importer->RegisterNamespaceMap(copied_namespace_decl, namespace_decls);
+
+ return dyn_cast<NamespaceDecl>(copied_decl);
+}
+
+ClangASTType
+ClangASTSource::GuardedCopyType (const ClangASTType &src_type)
+{
+ ClangASTMetrics::RegisterLLDBImport();
+
+ SetImportInProgress(true);
+
+ QualType copied_qual_type = m_ast_importer->CopyType (m_ast_context, src_type.GetASTContext(), src_type.GetQualType());
+
+ SetImportInProgress(false);
+
+ if (copied_qual_type.getAsOpaquePtr() && copied_qual_type->getCanonicalTypeInternal().isNull())
+ // this shouldn't happen, but we're hardening because the AST importer seems to be generating bad types
+ // on occasion.
+ return ClangASTType();
+
+ return ClangASTType(m_ast_context, copied_qual_type);
+}
+
+clang::NamedDecl *
+NameSearchContext::AddVarDecl(const ClangASTType &type)
+{
+ assert (type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return NULL;
+
+ IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo();
+
+ clang::ASTContext *ast = type.GetASTContext();
+
+ clang::NamedDecl *Decl = VarDecl::Create(*ast,
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
+ SourceLocation(),
+ ii,
+ type.GetQualType(),
+ 0,
+ SC_Static);
+ m_decls.push_back(Decl);
+
+ return Decl;
+}
+
+clang::NamedDecl *
+NameSearchContext::AddFunDecl (const ClangASTType &type)
+{
+ assert (type && "Type for variable must be valid!");
+
+ if (!type.IsValid())
+ return NULL;
+
+ if (m_function_types.count(type))
+ return NULL;
+
+ m_function_types.insert(type);
+
+ QualType qual_type (type.GetQualType());
+
+ clang::ASTContext *ast = type.GetASTContext();
+
+ const bool isInlineSpecified = false;
+ const bool hasWrittenPrototype = true;
+ const bool isConstexprSpecified = false;
+
+ clang::FunctionDecl *func_decl = FunctionDecl::Create (*ast,
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
+ SourceLocation(),
+ m_decl_name.getAsIdentifierInfo(),
+ qual_type,
+ NULL,
+ SC_Static,
+ isInlineSpecified,
+ hasWrittenPrototype,
+ isConstexprSpecified);
+
+ // We have to do more than just synthesize the FunctionDecl. We have to
+ // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do
+ // this, we raid the function's FunctionProtoType for types.
+
+ const FunctionProtoType *func_proto_type = qual_type.getTypePtr()->getAs<FunctionProtoType>();
+
+ if (func_proto_type)
+ {
+ unsigned NumArgs = func_proto_type->getNumArgs();
+ unsigned ArgIndex;
+
+ SmallVector<ParmVarDecl *, 5> parm_var_decls;
+
+ for (ArgIndex = 0; ArgIndex < NumArgs; ++ArgIndex)
+ {
+ QualType arg_qual_type (func_proto_type->getArgType(ArgIndex));
+
+ parm_var_decls.push_back(ParmVarDecl::Create (*ast,
+ const_cast<DeclContext*>(m_decl_context),
+ SourceLocation(),
+ SourceLocation(),
+ NULL,
+ arg_qual_type,
+ NULL,
+ SC_Static,
+ NULL));
+ }
+
+ func_decl->setParams(ArrayRef<ParmVarDecl*>(parm_var_decls));
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("Function type wasn't a FunctionProtoType");
+ }
+
+ m_decls.push_back(func_decl);
+
+ return func_decl;
+}
+
+clang::NamedDecl *
+NameSearchContext::AddGenericFunDecl()
+{
+ FunctionProtoType::ExtProtoInfo proto_info;
+
+ proto_info.Variadic = true;
+
+ QualType generic_function_type(m_ast_source.m_ast_context->getFunctionType (m_ast_source.m_ast_context->UnknownAnyTy, // result
+ ArrayRef<QualType>(), // argument types
+ proto_info));
+
+ return AddFunDecl(ClangASTType (m_ast_source.m_ast_context, generic_function_type));
+}
+
+clang::NamedDecl *
+NameSearchContext::AddTypeDecl(const ClangASTType &clang_type)
+{
+ if (clang_type)
+ {
+ QualType qual_type = clang_type.GetQualType();
+
+ if (const TypedefType *typedef_type = llvm::dyn_cast<TypedefType>(qual_type))
+ {
+ TypedefNameDecl *typedef_name_decl = typedef_type->getDecl();
+
+ m_decls.push_back(typedef_name_decl);
+
+ return (NamedDecl*)typedef_name_decl;
+ }
+ else if (const TagType *tag_type = qual_type->getAs<TagType>())
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+
+ m_decls.push_back(tag_decl);
+
+ return tag_decl;
+ }
+ else if (const ObjCObjectType *objc_object_type = qual_type->getAs<ObjCObjectType>())
+ {
+ ObjCInterfaceDecl *interface_decl = objc_object_type->getInterface();
+
+ m_decls.push_back((NamedDecl*)interface_decl);
+
+ return (NamedDecl*)interface_decl;
+ }
+ }
+ return NULL;
+}
+
+void
+NameSearchContext::AddLookupResult (clang::DeclContextLookupConstResult result)
+{
+ for (clang::NamedDecl *decl : result)
+ m_decls.push_back (decl);
+}
+
+void
+NameSearchContext::AddNamedDecl (clang::NamedDecl *decl)
+{
+ m_decls.push_back (decl);
+}
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
new file mode 100644
index 000000000000..072e7819cd02
--- /dev/null
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -0,0 +1,1956 @@
+//===-- ClangExpressionDeclMap.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/Expression/ClangExpressionDeclMap.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/Decl.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ASTDumper.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangPersistentVariables.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory, ExecutionContext &exe_ctx) :
+ ClangASTSource (exe_ctx.GetTargetSP()),
+ m_found_entities (),
+ m_struct_members (),
+ m_keep_result_in_memory (keep_result_in_memory),
+ m_parser_vars (),
+ m_struct_vars ()
+{
+ EnableStructVars();
+}
+
+ClangExpressionDeclMap::~ClangExpressionDeclMap()
+{
+ // Note: The model is now that the parser's AST context and all associated
+ // data does not vanish until the expression has been executed. This means
+ // that valuable lookup data (like namespaces) doesn't vanish, but
+
+ DidParse();
+ DisableStructVars();
+}
+
+bool
+ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx,
+ Materializer *materializer)
+{
+ ClangASTMetrics::ClearLocalCounters();
+
+ EnableParserVars();
+ m_parser_vars->m_exe_ctx = exe_ctx;
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (exe_ctx.GetFramePtr())
+ m_parser_vars->m_sym_ctx = exe_ctx.GetFramePtr()->GetSymbolContext(lldb::eSymbolContextEverything);
+ else if (exe_ctx.GetThreadPtr() && exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0))
+ m_parser_vars->m_sym_ctx = exe_ctx.GetThreadPtr()->GetStackFrameAtIndex(0)->GetSymbolContext(lldb::eSymbolContextEverything);
+ else if (exe_ctx.GetProcessPtr())
+ {
+ m_parser_vars->m_sym_ctx.Clear(true);
+ m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP();
+ }
+ else if (target)
+ {
+ m_parser_vars->m_sym_ctx.Clear(true);
+ m_parser_vars->m_sym_ctx.target_sp = exe_ctx.GetTargetSP();
+ }
+
+ if (target)
+ {
+ m_parser_vars->m_persistent_vars = &target->GetPersistentVariables();
+
+ if (!target->GetScratchClangASTContext())
+ return false;
+ }
+
+ m_parser_vars->m_target_info = GetTargetInfo();
+ m_parser_vars->m_materializer = materializer;
+
+ return true;
+}
+
+void
+ClangExpressionDeclMap::DidParse()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ ClangASTMetrics::DumpCounters(log);
+
+ if (m_parser_vars.get())
+ {
+ for (size_t entity_index = 0, num_entities = m_found_entities.GetSize();
+ entity_index < num_entities;
+ ++entity_index)
+ {
+ ClangExpressionVariableSP var_sp(m_found_entities.GetVariableAtIndex(entity_index));
+ if (var_sp)
+ var_sp->DisableParserVars(GetParserID());
+ }
+
+ for (size_t pvar_index = 0, num_pvars = m_parser_vars->m_persistent_vars->GetSize();
+ pvar_index < num_pvars;
+ ++pvar_index)
+ {
+ ClangExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariableAtIndex(pvar_index));
+ if (pvar_sp)
+ pvar_sp->DisableParserVars(GetParserID());
+ }
+
+ DisableParserVars();
+ }
+}
+
+// Interface for IRForTarget
+
+ClangExpressionDeclMap::TargetInfo
+ClangExpressionDeclMap::GetTargetInfo()
+{
+ assert (m_parser_vars.get());
+
+ TargetInfo ret;
+
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ ret.byte_order = process->GetByteOrder();
+ ret.address_byte_size = process->GetAddressByteSize();
+ }
+ else
+ {
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ ret.byte_order = target->GetArchitecture().GetByteOrder();
+ ret.address_byte_size = target->GetArchitecture().GetAddressByteSize();
+ }
+ }
+
+ return ret;
+}
+
+bool
+ClangExpressionDeclMap::AddPersistentVariable
+(
+ const NamedDecl *decl,
+ const ConstString &name,
+ TypeFromParser parser_type,
+ bool is_result,
+ bool is_lvalue
+)
+{
+ assert (m_parser_vars.get());
+
+ if (m_parser_vars->m_materializer && is_result)
+ {
+ Error err;
+
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == NULL)
+ return false;
+
+ ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
+
+ TypeFromUser user_type(m_ast_importer->DeportType(context,
+ parser_type.GetASTContext(),
+ parser_type.GetOpaqueQualType()),
+ context);
+
+ uint32_t offset = m_parser_vars->m_materializer->AddResultVariable(user_type, is_lvalue, m_keep_result_in_memory, err);
+
+ ClangExpressionVariableSP var_sp = m_found_entities.CreateVariable(exe_ctx.GetBestExecutionContextScope(),
+ name,
+ user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size);
+
+ if (!var_sp)
+ return false;
+
+ var_sp->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+ parser_vars->m_parser_type = parser_type;
+
+ var_sp->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
+
+ jit_vars->m_offset = offset;
+
+ return true;
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target == NULL)
+ return false;
+
+ ASTContext *context(target->GetScratchClangASTContext()->getASTContext());
+
+ TypeFromUser user_type(m_ast_importer->DeportType(context,
+ parser_type.GetASTContext(),
+ parser_type.GetOpaqueQualType()),
+ context);
+
+ if (!user_type.GetOpaqueQualType())
+ {
+ if (log)
+ log->Printf("Persistent variable's type wasn't copied successfully");
+ return false;
+ }
+
+ if (!m_parser_vars->m_target_info.IsValid())
+ return false;
+
+ ClangExpressionVariableSP var_sp = m_parser_vars->m_persistent_vars->CreatePersistentVariable (exe_ctx.GetBestExecutionContextScope (),
+ name,
+ user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size);
+
+ if (!var_sp)
+ return false;
+
+ var_sp->m_frozen_sp->SetHasCompleteType();
+
+ if (is_result)
+ var_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
+ else
+ var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget; // explicitly-declared persistent variables should persist
+
+ if (is_lvalue)
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ }
+ else
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ var_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ }
+
+ if (m_keep_result_in_memory)
+ {
+ var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget;
+ }
+
+ if (log)
+ log->Printf("Created persistent variable with flags 0x%hx", var_sp->m_flags);
+
+ var_sp->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
+
+ parser_vars->m_named_decl = decl;
+ parser_vars->m_parser_type = parser_type;
+
+ return true;
+}
+
+bool
+ClangExpressionDeclMap::AddValueToStruct
+(
+ const NamedDecl *decl,
+ const ConstString &name,
+ llvm::Value *value,
+ size_t size,
+ off_t alignment
+)
+{
+ assert (m_struct_vars.get());
+ assert (m_parser_vars.get());
+
+ bool is_persistent_variable = false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ m_struct_vars->m_struct_laid_out = false;
+
+ if (m_struct_members.GetVariable(decl, GetParserID()))
+ return true;
+
+ ClangExpressionVariableSP var_sp (m_found_entities.GetVariable(decl, GetParserID()));
+
+ if (!var_sp)
+ {
+ var_sp = m_parser_vars->m_persistent_vars->GetVariable(decl, GetParserID());
+ is_persistent_variable = true;
+ }
+
+ if (!var_sp)
+ return false;
+
+ if (log)
+ log->Printf("Adding value for (NamedDecl*)%p [%s - %s] to the structure",
+ decl,
+ name.GetCString(),
+ var_sp->GetName().GetCString());
+
+ // We know entity->m_parser_vars is valid because we used a parser variable
+ // to find it
+
+ ClangExpressionVariable::ParserVars *parser_vars = var_sp->GetParserVars(GetParserID());
+
+ parser_vars->m_llvm_value = value;
+
+ if (ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID()))
+ {
+ // We already laid this out; do not touch
+
+ if (log)
+ log->Printf("Already placed at 0x%llx", (unsigned long long)jit_vars->m_offset);
+ }
+
+ var_sp->EnableJITVars(GetParserID());
+
+ ClangExpressionVariable::JITVars *jit_vars = var_sp->GetJITVars(GetParserID());
+
+ jit_vars->m_alignment = alignment;
+ jit_vars->m_size = size;
+
+ m_struct_members.AddVariable(var_sp);
+
+ if (m_parser_vars->m_materializer)
+ {
+ uint32_t offset = 0;
+
+ Error err;
+
+ if (is_persistent_variable)
+ {
+ offset = m_parser_vars->m_materializer->AddPersistentVariable(var_sp, err);
+ }
+ else
+ {
+ if (const lldb_private::Symbol *sym = parser_vars->m_lldb_sym)
+ offset = m_parser_vars->m_materializer->AddSymbol(*sym, err);
+ else if (const RegisterInfo *reg_info = var_sp->GetRegisterInfo())
+ offset = m_parser_vars->m_materializer->AddRegister(*reg_info, err);
+ else if (parser_vars->m_lldb_var)
+ offset = m_parser_vars->m_materializer->AddVariable(parser_vars->m_lldb_var, err);
+ }
+
+ if (!err.Success())
+ return false;
+
+ if (log)
+ log->Printf("Placed at 0x%llx", (unsigned long long)offset);
+
+ jit_vars->m_offset = offset; // TODO DoStructLayout() should not change this.
+ }
+
+ return true;
+}
+
+bool
+ClangExpressionDeclMap::DoStructLayout ()
+{
+ assert (m_struct_vars.get());
+
+ if (m_struct_vars->m_struct_laid_out)
+ return true;
+
+ if (!m_parser_vars->m_materializer)
+ return false;
+
+ m_struct_vars->m_struct_alignment = m_parser_vars->m_materializer->GetStructAlignment();
+ m_struct_vars->m_struct_size = m_parser_vars->m_materializer->GetStructByteSize();
+ m_struct_vars->m_struct_laid_out = true;
+ return true;
+}
+
+bool ClangExpressionDeclMap::GetStructInfo
+(
+ uint32_t &num_elements,
+ size_t &size,
+ off_t &alignment
+)
+{
+ assert (m_struct_vars.get());
+
+ if (!m_struct_vars->m_struct_laid_out)
+ return false;
+
+ num_elements = m_struct_members.GetSize();
+ size = m_struct_vars->m_struct_size;
+ alignment = m_struct_vars->m_struct_alignment;
+
+ return true;
+}
+
+bool
+ClangExpressionDeclMap::GetStructElement
+(
+ const NamedDecl *&decl,
+ llvm::Value *&value,
+ off_t &offset,
+ ConstString &name,
+ uint32_t index
+)
+{
+ assert (m_struct_vars.get());
+
+ if (!m_struct_vars->m_struct_laid_out)
+ return false;
+
+ if (index >= m_struct_members.GetSize())
+ return false;
+
+ ClangExpressionVariableSP member_sp(m_struct_members.GetVariableAtIndex(index));
+
+ if (!member_sp)
+ return false;
+
+ ClangExpressionVariable::ParserVars *parser_vars = member_sp->GetParserVars(GetParserID());
+ ClangExpressionVariable::JITVars *jit_vars = member_sp->GetJITVars(GetParserID());
+
+ if (!parser_vars ||
+ !jit_vars ||
+ !member_sp->GetValueObject())
+ return false;
+
+ decl = parser_vars->m_named_decl;
+ value = parser_vars->m_llvm_value;
+ offset = jit_vars->m_offset;
+ name = member_sp->GetName();
+
+ return true;
+}
+
+bool
+ClangExpressionDeclMap::GetFunctionInfo
+(
+ const NamedDecl *decl,
+ uint64_t &ptr
+)
+{
+ ClangExpressionVariableSP entity_sp(m_found_entities.GetVariable(decl, GetParserID()));
+
+ if (!entity_sp)
+ return false;
+
+ // We know m_parser_vars is valid since we searched for the variable by
+ // its NamedDecl
+
+ ClangExpressionVariable::ParserVars *parser_vars = entity_sp->GetParserVars(GetParserID());
+
+ ptr = parser_vars->m_lldb_value.GetScalar().ULongLong();
+
+ return true;
+}
+
+static void
+FindCodeSymbolInContext
+(
+ const ConstString &name,
+ SymbolContext &sym_ctx,
+ SymbolContextList &sc_list
+)
+{
+ SymbolContextList temp_sc_list;
+ if (sym_ctx.module_sp)
+ sym_ctx.module_sp->FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
+
+ if (!sc_list.GetSize() && sym_ctx.target_sp)
+ sym_ctx.target_sp->GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, temp_sc_list);
+
+ unsigned temp_sc_list_size = temp_sc_list.GetSize();
+ for (unsigned i = 0; i < temp_sc_list_size; i++)
+ {
+ SymbolContext sym_ctx;
+ temp_sc_list.GetContextAtIndex(i, sym_ctx);
+ if (sym_ctx.symbol)
+ {
+ switch (sym_ctx.symbol->GetType())
+ {
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ sc_list.Append(sym_ctx);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+bool
+ClangExpressionDeclMap::GetFunctionAddress
+(
+ const ConstString &name,
+ uint64_t &func_addr
+)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ ExecutionContext &exe_ctx = m_parser_vars->m_exe_ctx;
+ Target *target = exe_ctx.GetTargetPtr();
+ // Back out in all cases where we're not fully initialized
+ if (target == NULL)
+ return false;
+ if (!m_parser_vars->m_sym_ctx.target_sp)
+ return false;
+
+ SymbolContextList sc_list;
+
+ FindCodeSymbolInContext(name, m_parser_vars->m_sym_ctx, sc_list);
+
+ if (!sc_list.GetSize())
+ {
+ // We occasionally get debug information in which a const function is reported
+ // as non-const, so the mangled name is wrong. This is a hack to compensate.
+
+ if (!strncmp(name.GetCString(), "_ZN", 3) &&
+ strncmp(name.GetCString(), "_ZNK", 4))
+ {
+ std::string fixed_scratch("_ZNK");
+ fixed_scratch.append(name.GetCString() + 3);
+ ConstString fixed_name(fixed_scratch.c_str());
+
+ if (log)
+ log->Printf("Failed to find symbols given non-const name %s; trying %s", name.GetCString(), fixed_name.GetCString());
+
+ FindCodeSymbolInContext(fixed_name, m_parser_vars->m_sym_ctx, sc_list);
+ }
+ }
+
+ if (!sc_list.GetSize())
+ return false;
+
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(0, sym_ctx);
+
+ const Address *func_so_addr = NULL;
+ bool is_indirect_function = false;
+
+ if (sym_ctx.function)
+ func_so_addr = &sym_ctx.function->GetAddressRange().GetBaseAddress();
+ else if (sym_ctx.symbol) {
+ func_so_addr = &sym_ctx.symbol->GetAddress();
+ is_indirect_function = sym_ctx.symbol->IsIndirect();
+ } else
+ return false;
+
+ if (!func_so_addr || !func_so_addr->IsValid())
+ return false;
+
+ func_addr = func_so_addr->GetCallableLoadAddress (target, is_indirect_function);
+
+ return true;
+}
+
+addr_t
+ClangExpressionDeclMap::GetSymbolAddress (Target &target, Process *process, const ConstString &name, lldb::SymbolType symbol_type)
+{
+ SymbolContextList sc_list;
+
+ target.GetImages().FindSymbolsWithNameAndType(name, symbol_type, sc_list);
+
+ const uint32_t num_matches = sc_list.GetSize();
+ addr_t symbol_load_addr = LLDB_INVALID_ADDRESS;
+
+ for (uint32_t i=0; i<num_matches && (symbol_load_addr == 0 || symbol_load_addr == LLDB_INVALID_ADDRESS); i++)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+
+ const Address *sym_address = &sym_ctx.symbol->GetAddress();
+
+ if (!sym_address || !sym_address->IsValid())
+ continue;
+
+ if (sym_address)
+ {
+ switch (sym_ctx.symbol->GetType())
+ {
+ case eSymbolTypeCode:
+ case eSymbolTypeTrampoline:
+ symbol_load_addr = sym_address->GetCallableLoadAddress (&target);
+ break;
+
+ case eSymbolTypeResolver:
+ symbol_load_addr = sym_address->GetCallableLoadAddress (&target, true);
+ break;
+
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeInvalid:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeException:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ symbol_load_addr = sym_address->GetLoadAddress (&target);
+ break;
+ }
+ }
+ }
+
+ if (symbol_load_addr == LLDB_INVALID_ADDRESS && process)
+ {
+ ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime();
+
+ if (runtime)
+ {
+ symbol_load_addr = runtime->LookupRuntimeSymbol(name);
+ }
+ }
+
+ return symbol_load_addr;
+}
+
+addr_t
+ClangExpressionDeclMap::GetSymbolAddress (const ConstString &name, lldb::SymbolType symbol_type)
+{
+ assert (m_parser_vars.get());
+
+ if (!m_parser_vars->m_exe_ctx.GetTargetPtr())
+ return false;
+
+ return GetSymbolAddress(m_parser_vars->m_exe_ctx.GetTargetRef(), m_parser_vars->m_exe_ctx.GetProcessPtr(), name, symbol_type);
+}
+
+const Symbol *
+ClangExpressionDeclMap::FindGlobalDataSymbol (Target &target,
+ const ConstString &name)
+{
+ SymbolContextList sc_list;
+
+ target.GetImages().FindSymbolsWithNameAndType(name, eSymbolTypeAny, sc_list);
+
+ const uint32_t matches = sc_list.GetSize();
+ for (uint32_t i=0; i<matches; ++i)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(i, sym_ctx);
+ if (sym_ctx.symbol)
+ {
+ const Symbol *symbol = sym_ctx.symbol;
+ const Address *sym_address = &symbol->GetAddress();
+
+ if (sym_address && sym_address->IsValid())
+ {
+ switch (symbol->GetType())
+ {
+ case eSymbolTypeData:
+ case eSymbolTypeRuntime:
+ case eSymbolTypeAbsolute:
+ case eSymbolTypeObjCClass:
+ case eSymbolTypeObjCMetaClass:
+ case eSymbolTypeObjCIVar:
+ if (symbol->GetDemangledNameIsSynthesized())
+ {
+ // If the demangled name was synthesized, then don't use it
+ // for expressions. Only let the symbol match if the mangled
+ // named matches for these symbols.
+ if (symbol->GetMangled().GetMangledName() != name)
+ break;
+ }
+ return symbol;
+
+ case eSymbolTypeCode: // We already lookup functions elsewhere
+ case eSymbolTypeVariable:
+ case eSymbolTypeLocal:
+ case eSymbolTypeParam:
+ case eSymbolTypeTrampoline:
+ case eSymbolTypeInvalid:
+ case eSymbolTypeException:
+ case eSymbolTypeSourceFile:
+ case eSymbolTypeHeaderFile:
+ case eSymbolTypeObjectFile:
+ case eSymbolTypeCommonBlock:
+ case eSymbolTypeBlock:
+ case eSymbolTypeVariableType:
+ case eSymbolTypeLineEntry:
+ case eSymbolTypeLineHeader:
+ case eSymbolTypeScopeBegin:
+ case eSymbolTypeScopeEnd:
+ case eSymbolTypeAdditional:
+ case eSymbolTypeCompiler:
+ case eSymbolTypeInstrumentation:
+ case eSymbolTypeUndefined:
+ case eSymbolTypeResolver:
+ break;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+lldb::VariableSP
+ClangExpressionDeclMap::FindGlobalVariable
+(
+ Target &target,
+ ModuleSP &module,
+ const ConstString &name,
+ ClangNamespaceDecl *namespace_decl,
+ TypeFromUser *type
+)
+{
+ VariableList vars;
+
+ if (module && namespace_decl)
+ module->FindGlobalVariables (name, namespace_decl, true, -1, vars);
+ else
+ target.GetImages().FindGlobalVariables(name, true, -1, vars);
+
+ if (vars.GetSize())
+ {
+ if (type)
+ {
+ for (size_t i = 0; i < vars.GetSize(); ++i)
+ {
+ VariableSP var_sp = vars.GetVariableAtIndex(i);
+
+ if (ClangASTContext::AreTypesSame(*type, var_sp->GetType()->GetClangFullType()))
+ return var_sp;
+ }
+ }
+ else
+ {
+ return vars.GetVariableAtIndex(0);
+ }
+ }
+
+ return VariableSP();
+}
+
+// Interface for ClangASTSource
+
+void
+ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context)
+{
+ assert (m_ast_context);
+
+ ClangASTMetrics::RegisterVisibleQuery();
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (GetImportInProgress())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Ignoring a query during an import");
+ return;
+ }
+
+ static unsigned int invocation_id = 0;
+ unsigned int current_id = invocation_id++;
+
+ if (log)
+ {
+ if (!context.m_decl_context)
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in a NULL DeclContext", current_id, name.GetCString());
+ else if (const NamedDecl *context_named_decl = dyn_cast<NamedDecl>(context.m_decl_context))
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in '%s'", current_id, name.GetCString(), context_named_decl->getNameAsString().c_str());
+ else
+ log->Printf("ClangExpressionDeclMap::FindExternalVisibleDecls[%u] for '%s' in a '%s'", current_id, name.GetCString(), context.m_decl_context->getDeclKindName());
+ }
+
+ if (const NamespaceDecl *namespace_context = dyn_cast<NamespaceDecl>(context.m_decl_context))
+ {
+ ClangASTImporter::NamespaceMapSP namespace_map = m_ast_importer->GetNamespaceMap(namespace_context);
+
+ if (log && log->GetVerbose())
+ log->Printf(" CEDM::FEVD[%u] Inspecting (NamespaceMap*)%p (%d entries)",
+ current_id,
+ namespace_map.get(),
+ (int)namespace_map->size());
+
+ if (!namespace_map)
+ return;
+
+ for (ClangASTImporter::NamespaceMap::iterator i = namespace_map->begin(), e = namespace_map->end();
+ i != e;
+ ++i)
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Searching namespace %s in module %s",
+ current_id,
+ i->second.GetNamespaceDecl()->getNameAsString().c_str(),
+ i->first->GetFileSpec().GetFilename().GetCString());
+
+ FindExternalVisibleDecls(context,
+ i->first,
+ i->second,
+ current_id);
+ }
+ }
+ else if (isa<TranslationUnitDecl>(context.m_decl_context))
+ {
+ ClangNamespaceDecl namespace_decl;
+
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Searching the root namespace", current_id);
+
+ FindExternalVisibleDecls(context,
+ lldb::ModuleSP(),
+ namespace_decl,
+ current_id);
+ }
+
+ if (!context.m_found.variable)
+ ClangASTSource::FindExternalVisibleDecls(context);
+}
+
+void
+ClangExpressionDeclMap::FindExternalVisibleDecls (NameSearchContext &context,
+ lldb::ModuleSP module_sp,
+ ClangNamespaceDecl &namespace_decl,
+ unsigned int current_id)
+{
+ assert (m_ast_context);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ SymbolContextList sc_list;
+
+ const ConstString name(context.m_decl_name.getAsString().c_str());
+
+ const char *name_unique_cstr = name.GetCString();
+
+ if (name_unique_cstr == NULL)
+ return;
+
+ static ConstString id_name("id");
+ static ConstString Class_name("Class");
+
+ if (name == id_name || name == Class_name)
+ return;
+
+ // Only look for functions by name out in our symbols if the function
+ // doesn't start with our phony prefix of '$'
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+ StackFrame *frame = m_parser_vars->m_exe_ctx.GetFramePtr();
+ if (name_unique_cstr[0] == '$' && !namespace_decl)
+ {
+ static ConstString g_lldb_class_name ("$__lldb_class");
+
+ if (name == g_lldb_class_name)
+ {
+ // Clang is looking for the type of "this"
+
+ if (frame == NULL)
+ return;
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction);
+
+ if (!sym_ctx.function)
+ return;
+
+ // Get the block that defines the function
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ return;
+
+ clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_context);
+
+ if (method_decl)
+ {
+ clang::CXXRecordDecl *class_decl = method_decl->getParent();
+
+ QualType class_qual_type(class_decl->getTypeForDecl(), 0);
+
+ TypeFromUser class_user_type (class_qual_type.getAsOpaquePtr(),
+ &class_decl->getASTContext());
+
+ if (log)
+ {
+ ASTDumper ast_dumper(class_qual_type);
+ log->Printf(" CEDM::FEVD[%u] Adding type for $__lldb_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ TypeFromParser class_type = CopyClassType(class_user_type, current_id);
+
+ if (!class_type.IsValid())
+ return;
+
+ TypeSourceInfo *type_source_info = m_ast_context->getTrivialTypeSourceInfo(QualType::getFromOpaquePtr(class_type.GetOpaqueQualType()));
+
+ if (!type_source_info)
+ return;
+
+ TypedefDecl *typedef_decl = TypedefDecl::Create(*m_ast_context,
+ m_ast_context->getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ context.m_decl_name.getAsIdentifierInfo(),
+ type_source_info);
+
+
+ if (!typedef_decl)
+ return;
+
+ context.AddNamedDecl(typedef_decl);
+
+ if (method_decl->isInstance())
+ {
+ // self is a pointer to the object
+
+ QualType class_pointer_type = method_decl->getASTContext().getPointerType(class_qual_type);
+
+ TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
+ &method_decl->getASTContext());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+ }
+ else
+ {
+ // This branch will get hit if we are executing code in the context of a function that
+ // claims to have an object pointer (through DW_AT_object_pointer?) but is not formally a
+ // method of the class. In that case, just look up the "this" variable in the the current
+ // scope and use its type.
+ // FIXME: This code is formally correct, but clang doesn't currently emit DW_AT_object_pointer
+ // for C++ so it hasn't actually been tested.
+
+ VariableList *vars = frame->GetVariableList(false);
+
+ lldb::VariableSP this_var = vars->FindVariable(ConstString("this"));
+
+ if (this_var &&
+ this_var->IsInScope(frame) &&
+ this_var->LocationIsValidForFrame (frame))
+ {
+ Type *this_type = this_var->GetType();
+
+ if (!this_type)
+ return;
+
+ ClangASTType pointee_type = this_type->GetClangForwardType().GetPointeeType();
+
+ if (pointee_type.IsValid())
+ {
+ if (log)
+ {
+ ASTDumper ast_dumper(this_type->GetClangFullType());
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ TypeFromUser class_user_type(pointee_type);
+ AddOneType(context, class_user_type, current_id);
+
+
+ TypeFromUser this_user_type(this_type->GetClangFullType());
+ m_struct_vars->m_object_pointer_type = this_user_type;
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ static ConstString g_lldb_objc_class_name ("$__lldb_objc_class");
+ if (name == g_lldb_objc_class_name)
+ {
+ // Clang is looking for the type of "*self"
+
+ if (!frame)
+ return;
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction);
+
+ if (!sym_ctx.function)
+ return;
+
+ // Get the block that defines the function
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ return;
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ return;
+
+ clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context);
+
+ if (method_decl)
+ {
+ ObjCInterfaceDecl* self_interface = method_decl->getClassInterface();
+
+ if (!self_interface)
+ return;
+
+ const clang::Type *interface_type = self_interface->getTypeForDecl();
+
+ if (!interface_type)
+ return; // This is unlikely, but we have seen crashes where this occurred
+
+ TypeFromUser class_user_type(QualType(interface_type, 0).getAsOpaquePtr(),
+ &method_decl->getASTContext());
+
+ if (log)
+ {
+ ASTDumper ast_dumper(interface_type);
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ AddOneType(context, class_user_type, current_id);
+
+ if (method_decl->isInstanceMethod())
+ {
+ // self is a pointer to the object
+
+ QualType class_pointer_type = method_decl->getASTContext().getObjCObjectPointerType(QualType(interface_type, 0));
+
+ TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
+ &method_decl->getASTContext());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+ else
+ {
+ // self is a Class pointer
+ QualType class_type = method_decl->getASTContext().getObjCClassType();
+
+ TypeFromUser self_user_type(class_type.getAsOpaquePtr(),
+ &method_decl->getASTContext());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ }
+
+ return;
+ }
+ else
+ {
+ // This branch will get hit if we are executing code in the context of a function that
+ // claims to have an object pointer (through DW_AT_object_pointer?) but is not formally a
+ // method of the class. In that case, just look up the "self" variable in the the current
+ // scope and use its type.
+
+ VariableList *vars = frame->GetVariableList(false);
+
+ lldb::VariableSP self_var = vars->FindVariable(ConstString("self"));
+
+ if (self_var &&
+ self_var->IsInScope(frame) &&
+ self_var->LocationIsValidForFrame (frame))
+ {
+ Type *self_type = self_var->GetType();
+
+ if (!self_type)
+ return;
+
+ ClangASTType self_clang_type = self_type->GetClangFullType();
+
+ if (self_clang_type.IsObjCClassType())
+ {
+ return;
+ }
+ else if (self_clang_type.IsObjCObjectPointerType())
+ {
+ self_clang_type = self_clang_type.GetPointeeType();
+
+ if (!self_clang_type)
+ return;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(self_type->GetClangFullType());
+ log->Printf(" FEVD[%u] Adding type for $__lldb_objc_class: %s", current_id, ast_dumper.GetCString());
+ }
+
+ TypeFromUser class_user_type (self_clang_type);
+
+ AddOneType(context, class_user_type, current_id);
+
+ TypeFromUser self_user_type(self_type->GetClangFullType());
+
+ m_struct_vars->m_object_pointer_type = self_user_type;
+ return;
+ }
+ }
+ }
+
+ return;
+ }
+
+ // any other $__lldb names should be weeded out now
+ if (!::strncmp(name_unique_cstr, "$__lldb", sizeof("$__lldb") - 1))
+ return;
+
+ do
+ {
+ if (!target)
+ break;
+
+ ClangASTContext *scratch_clang_ast_context = target->GetScratchClangASTContext();
+
+ if (!scratch_clang_ast_context)
+ break;
+
+ ASTContext *scratch_ast_context = scratch_clang_ast_context->getASTContext();
+
+ if (!scratch_ast_context)
+ break;
+
+ TypeDecl *ptype_type_decl = m_parser_vars->m_persistent_vars->GetPersistentType(name);
+
+ if (!ptype_type_decl)
+ break;
+
+ Decl *parser_ptype_decl = m_ast_importer->CopyDecl(m_ast_context, scratch_ast_context, ptype_type_decl);
+
+ if (!parser_ptype_decl)
+ break;
+
+ TypeDecl *parser_ptype_type_decl = dyn_cast<TypeDecl>(parser_ptype_decl);
+
+ if (!parser_ptype_type_decl)
+ break;
+
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Found persistent type %s", current_id, name.GetCString());
+
+ context.AddNamedDecl(parser_ptype_type_decl);
+ } while (0);
+
+ ClangExpressionVariableSP pvar_sp(m_parser_vars->m_persistent_vars->GetVariable(name));
+
+ if (pvar_sp)
+ {
+ AddOneVariable(context, pvar_sp, current_id);
+ return;
+ }
+
+ const char *reg_name(&name.GetCString()[1]);
+
+ if (m_parser_vars->m_exe_ctx.GetRegisterContext())
+ {
+ const RegisterInfo *reg_info(m_parser_vars->m_exe_ctx.GetRegisterContext()->GetRegisterInfoByName(reg_name));
+
+ if (reg_info)
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Found register %s", current_id, reg_info->name);
+
+ AddOneRegister(context, reg_info, current_id);
+ }
+ }
+ }
+ else
+ {
+ ValueObjectSP valobj;
+ VariableSP var;
+ Error err;
+
+ if (frame && !namespace_decl)
+ {
+ valobj = frame->GetValueForVariableExpressionPath(name_unique_cstr,
+ eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember ||
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var,
+ err);
+
+ // If we found a variable in scope, no need to pull up function names
+ if (err.Success() && var)
+ {
+ AddOneVariable(context, var, valobj, current_id);
+ context.m_found.variable = true;
+ return;
+ }
+ }
+
+ if (target)
+ {
+ var = FindGlobalVariable (*target,
+ module_sp,
+ name,
+ &namespace_decl,
+ NULL);
+
+ if (var)
+ {
+ valobj = ValueObjectVariable::Create(target, var);
+ AddOneVariable(context, var, valobj, current_id);
+ context.m_found.variable = true;
+ return;
+ }
+ }
+
+ if (!context.m_found.variable)
+ {
+ const bool include_inlines = false;
+ const bool append = false;
+
+ if (namespace_decl && module_sp)
+ {
+ const bool include_symbols = false;
+
+ module_sp->FindFunctions(name,
+ &namespace_decl,
+ eFunctionNameTypeBase,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+ else if (target && !namespace_decl)
+ {
+ const bool include_symbols = true;
+
+ // TODO Fix FindFunctions so that it doesn't return
+ // instance methods for eFunctionNameTypeBase.
+
+ target->GetImages().FindFunctions(name,
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ }
+
+ if (sc_list.GetSize())
+ {
+ Symbol *generic_symbol = NULL;
+ Symbol *non_extern_symbol = NULL;
+
+ for (uint32_t index = 0, num_indices = sc_list.GetSize();
+ index < num_indices;
+ ++index)
+ {
+ SymbolContext sym_ctx;
+ sc_list.GetContextAtIndex(index, sym_ctx);
+
+ if (sym_ctx.function)
+ {
+ clang::DeclContext *decl_ctx = sym_ctx.function->GetClangDeclContext();
+
+ if (!decl_ctx)
+ continue;
+
+ // Filter out class/instance methods.
+ if (dyn_cast<clang::ObjCMethodDecl>(decl_ctx))
+ continue;
+ if (dyn_cast<clang::CXXMethodDecl>(decl_ctx))
+ continue;
+
+ AddOneFunction(context, sym_ctx.function, NULL, current_id);
+ context.m_found.function_with_type_info = true;
+ context.m_found.function = true;
+ }
+ else if (sym_ctx.symbol)
+ {
+ if (sym_ctx.symbol->IsExternal())
+ generic_symbol = sym_ctx.symbol;
+ else
+ non_extern_symbol = sym_ctx.symbol;
+ }
+ }
+
+ if (!context.m_found.function_with_type_info)
+ {
+ if (generic_symbol)
+ {
+ AddOneFunction (context, NULL, generic_symbol, current_id);
+ context.m_found.function = true;
+ }
+ else if (non_extern_symbol)
+ {
+ AddOneFunction (context, NULL, non_extern_symbol, current_id);
+ context.m_found.function = true;
+ }
+ }
+ }
+
+ if (target && !context.m_found.variable && !namespace_decl)
+ {
+ // We couldn't find a non-symbol variable for this. Now we'll hunt for a generic
+ // data symbol, and -- if it is found -- treat it as a variable.
+
+ const Symbol *data_symbol = FindGlobalDataSymbol(*target, name);
+
+ if (data_symbol)
+ {
+ AddOneGenericVariable(context, *data_symbol, current_id);
+ context.m_found.variable = true;
+ }
+ }
+ }
+ }
+}
+
+static clang_type_t
+MaybePromoteToBlockPointerType
+(
+ ASTContext *ast_context,
+ clang_type_t candidate_type
+)
+{
+ if (!candidate_type)
+ return candidate_type;
+
+ QualType candidate_qual_type = QualType::getFromOpaquePtr(candidate_type);
+
+ const PointerType *candidate_pointer_type = dyn_cast<PointerType>(candidate_qual_type);
+
+ if (!candidate_pointer_type)
+ return candidate_type;
+
+ QualType pointee_qual_type = candidate_pointer_type->getPointeeType();
+
+ const RecordType *pointee_record_type = dyn_cast<RecordType>(pointee_qual_type);
+
+ if (!pointee_record_type)
+ return candidate_type;
+
+ RecordDecl *pointee_record_decl = pointee_record_type->getDecl();
+
+ if (!pointee_record_decl->isRecord())
+ return candidate_type;
+
+ if (!pointee_record_decl->getName().startswith(llvm::StringRef("__block_literal_")))
+ return candidate_type;
+
+ QualType generic_function_type = ast_context->getFunctionNoProtoType(ast_context->UnknownAnyTy);
+ QualType block_pointer_type = ast_context->getBlockPointerType(generic_function_type);
+
+ return block_pointer_type.getAsOpaquePtr();
+}
+
+bool
+ClangExpressionDeclMap::GetVariableValue (VariableSP &var,
+ lldb_private::Value &var_location,
+ TypeFromUser *user_type,
+ TypeFromParser *parser_type)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Type *var_type = var->GetType();
+
+ if (!var_type)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no type");
+ return false;
+ }
+
+ ClangASTType var_clang_type = var_type->GetClangFullType();
+
+ if (!var_clang_type)
+ {
+ if (log)
+ log->PutCString("Skipped a definition because it has no Clang type");
+ return false;
+ }
+
+ // commented out because of <rdar://problem/11024417>
+ ASTContext *ast = var_type->GetClangASTContext().getASTContext();
+
+ if (!ast)
+ {
+ if (log)
+ log->PutCString("There is no AST context for the current execution context");
+ return false;
+ }
+ //var_clang_type = MaybePromoteToBlockPointerType (ast, var_clang_type);
+
+ DWARFExpression &var_location_expr = var->LocationExpression();
+
+ lldb::addr_t loclist_base_load_addr = LLDB_INVALID_ADDRESS;
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ if (var_location_expr.IsLocationList())
+ {
+ SymbolContext var_sc;
+ var->CalculateSymbolContext (&var_sc);
+ loclist_base_load_addr = var_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (target);
+ }
+ Error err;
+
+ if (var->GetLocationIsConstantValueData())
+ {
+ DataExtractor const_value_extractor;
+
+ if (var_location_expr.GetExpressionData(const_value_extractor))
+ {
+ var_location = Value(const_value_extractor.GetDataStart(), const_value_extractor.GetByteSize());
+ var_location.SetValueType(Value::eValueTypeHostAddress);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Error evaluating constant variable: %s", err.AsCString());
+ return false;
+ }
+ }
+
+ ClangASTType type_to_use = GuardedCopyType(var_clang_type);
+
+ if (!type_to_use)
+ {
+ if (log)
+ log->Printf("Couldn't copy a variable's type into the parser's AST context");
+
+ return false;
+ }
+
+ if (parser_type)
+ *parser_type = TypeFromParser(type_to_use);
+
+ if (var_location.GetContextType() == Value::eContextTypeInvalid)
+ var_location.SetClangType(type_to_use);
+
+ if (var_location.GetValueType() == Value::eValueTypeFileAddress)
+ {
+ SymbolContext var_sc;
+ var->CalculateSymbolContext(&var_sc);
+
+ if (!var_sc.module_sp)
+ return false;
+
+ Address so_addr(var_location.GetScalar().ULongLong(), var_sc.module_sp->GetSectionList());
+
+ lldb::addr_t load_addr = so_addr.GetLoadAddress(target);
+
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ var_location.GetScalar() = load_addr;
+ var_location.SetValueType(Value::eValueTypeLoadAddress);
+ }
+ }
+
+ if (user_type)
+ *user_type = TypeFromUser(var_clang_type);
+
+ return true;
+}
+
+void
+ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, VariableSP var, ValueObjectSP valobj, unsigned int current_id)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeFromUser ut;
+ TypeFromParser pt;
+ Value var_location;
+
+ if (!GetVariableValue (var, var_location, &ut, &pt))
+ return;
+
+ clang::QualType parser_opaque_type = QualType::getFromOpaquePtr(pt.GetOpaqueQualType());
+
+ if (parser_opaque_type.isNull())
+ return;
+
+ if (const clang::Type *parser_type = parser_opaque_type.getTypePtr())
+ {
+ if (const TagType *tag_type = dyn_cast<TagType>(parser_type))
+ CompleteType(tag_type->getDecl());
+ }
+
+
+ bool is_reference = pt.IsReferenceType();
+
+ NamedDecl *var_decl = NULL;
+ if (is_reference)
+ var_decl = context.AddVarDecl(pt);
+ else
+ var_decl = context.AddVarDecl(pt.GetLValueReferenceType());
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ ConstString entity_name(decl_name.c_str());
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (valobj));
+
+ assert (entity.get());
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
+ parser_vars->m_parser_type = pt;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value = var_location;
+ parser_vars->m_lldb_var = var;
+
+ if (is_reference)
+ entity->m_flags |= ClangExpressionVariable::EVTypeIsReference;
+
+ if (log)
+ {
+ ASTDumper orig_dumper(ut.GetOpaqueQualType());
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s (original %s)", current_id, decl_name.c_str(), ast_dumper.GetCString(), orig_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context,
+ ClangExpressionVariableSP &pvar_sp,
+ unsigned int current_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ TypeFromUser user_type (pvar_sp->GetTypeFromUser());
+
+ TypeFromParser parser_type (GuardedCopyType(user_type));
+
+ if (!parser_type.GetOpaqueQualType())
+ {
+ if (log)
+ log->Printf(" CEDM::FEVD[%u] Couldn't import type for pvar %s", current_id, pvar_sp->GetName().GetCString());
+ return;
+ }
+
+ NamedDecl *var_decl = context.AddVarDecl(parser_type.GetLValueReferenceType());
+
+ pvar_sp->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars = pvar_sp->GetParserVars(GetParserID());
+ parser_vars->m_parser_type = parser_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value.Clear();
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%u] Added pvar %s, returned %s", current_id, pvar_sp->GetName().GetCString(), ast_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context,
+ const Symbol &symbol,
+ unsigned int current_id)
+{
+ assert(m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ if (target == NULL)
+ return;
+
+ ASTContext *scratch_ast_context = target->GetScratchClangASTContext()->getASTContext();
+
+ TypeFromUser user_type (ClangASTContext::GetBasicType(scratch_ast_context, eBasicTypeVoid).GetPointerType().GetLValueReferenceType());
+ TypeFromParser parser_type (ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid).GetPointerType().GetLValueReferenceType());
+ NamedDecl *var_decl = context.AddVarDecl(parser_type);
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ ConstString entity_name(decl_name.c_str());
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope (),
+ entity_name,
+ user_type,
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ assert (entity.get());
+
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
+
+ const Address &symbol_address = symbol.GetAddress();
+ lldb::addr_t symbol_load_addr = symbol_address.GetLoadAddress(target);
+
+ //parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
+ parser_vars->m_lldb_value.SetClangType(user_type);
+ parser_vars->m_lldb_value.GetScalar() = symbol_load_addr;
+ parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress);
+
+ parser_vars->m_parser_type = parser_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_sym = &symbol;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+
+ log->Printf(" CEDM::FEVD[%u] Found variable %s, returned %s", current_id, decl_name.c_str(), ast_dumper.GetCString());
+ }
+}
+
+bool
+ClangExpressionDeclMap::ResolveUnknownTypes()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ ASTContext *scratch_ast_context = target->GetScratchClangASTContext()->getASTContext();
+
+ for (size_t index = 0, num_entities = m_found_entities.GetSize();
+ index < num_entities;
+ ++index)
+ {
+ ClangExpressionVariableSP entity = m_found_entities.GetVariableAtIndex(index);
+
+ ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
+
+ if (entity->m_flags & ClangExpressionVariable::EVUnknownType)
+ {
+ const NamedDecl *named_decl = parser_vars->m_named_decl;
+ const VarDecl *var_decl = dyn_cast<VarDecl>(named_decl);
+
+ if (!var_decl)
+ {
+ if (log)
+ log->Printf("Entity of unknown type does not have a VarDecl");
+ return false;
+ }
+
+ if (log)
+ {
+ ASTDumper ast_dumper(const_cast<VarDecl*>(var_decl));
+ log->Printf("Variable of unknown type now has Decl %s", ast_dumper.GetCString());
+ }
+
+ QualType var_type = var_decl->getType();
+ TypeFromParser parser_type(var_type.getAsOpaquePtr(), &var_decl->getASTContext());
+
+ lldb::clang_type_t copied_type = m_ast_importer->CopyType(scratch_ast_context, &var_decl->getASTContext(), var_type.getAsOpaquePtr());
+
+ if (!copied_type)
+ {
+ if (log)
+ log->Printf("ClangExpressionDeclMap::ResolveUnknownType - Couldn't import the type for a variable");
+
+ return (bool) lldb::ClangExpressionVariableSP();
+ }
+
+ TypeFromUser user_type(copied_type, scratch_ast_context);
+
+// parser_vars->m_lldb_value.SetContext(Value::eContextTypeClangType, user_type.GetOpaqueQualType());
+ parser_vars->m_lldb_value.SetClangType(user_type);
+ parser_vars->m_parser_type = parser_type;
+
+ entity->SetClangType(user_type);
+
+ entity->m_flags &= ~(ClangExpressionVariable::EVUnknownType);
+ }
+ }
+
+ return true;
+}
+
+void
+ClangExpressionDeclMap::AddOneRegister (NameSearchContext &context,
+ const RegisterInfo *reg_info,
+ unsigned int current_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ClangASTType clang_type = ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (m_ast_context,
+ reg_info->encoding,
+ reg_info->byte_size * 8);
+
+ if (!clang_type)
+ {
+ if (log)
+ log->Printf(" Tried to add a type for %s, but couldn't get one", context.m_decl_name.getAsString().c_str());
+ return;
+ }
+
+ TypeFromParser parser_clang_type (clang_type);
+
+ NamedDecl *var_decl = context.AddVarDecl(parser_clang_type);
+
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ assert (entity.get());
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ entity->SetName (ConstString (decl_name.c_str()));
+ entity->SetRegisterInfo (reg_info);
+ entity->EnableParserVars(GetParserID());
+ ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
+ parser_vars->m_parser_type = parser_clang_type;
+ parser_vars->m_named_decl = var_decl;
+ parser_vars->m_llvm_value = NULL;
+ parser_vars->m_lldb_value.Clear();
+ entity->m_flags |= ClangExpressionVariable::EVBareRegister;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(var_decl);
+ log->Printf(" CEDM::FEVD[%d] Added register %s, returned %s", current_id, context.m_decl_name.getAsString().c_str(), ast_dumper.GetCString());
+ }
+}
+
+void
+ClangExpressionDeclMap::AddOneFunction (NameSearchContext &context,
+ Function* function,
+ Symbol* symbol,
+ unsigned int current_id)
+{
+ assert (m_parser_vars.get());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ NamedDecl *function_decl = NULL;
+ const Address *fun_address = NULL;
+ ClangASTType function_clang_type;
+
+ bool is_indirect_function = false;
+
+ if (function)
+ {
+ Type *function_type = function->GetType();
+
+ if (!function_type)
+ {
+ if (log)
+ log->PutCString(" Skipped a function because it has no type");
+ return;
+ }
+
+ function_clang_type = function_type->GetClangFullType();
+
+ if (!function_clang_type)
+ {
+ if (log)
+ log->PutCString(" Skipped a function because it has no Clang type");
+ return;
+ }
+
+ fun_address = &function->GetAddressRange().GetBaseAddress();
+
+ ClangASTType copied_function_type = GuardedCopyType(function_clang_type);
+ if (copied_function_type)
+ {
+ function_decl = context.AddFunDecl(copied_function_type);
+
+ if (!function_decl)
+ {
+ if (log)
+ {
+ log->Printf (" Failed to create a function decl for '%s' {0x%8.8" PRIx64 "}",
+ function_type->GetName().GetCString(),
+ function_type->GetID());
+ }
+
+ return;
+ }
+ }
+ else
+ {
+ // We failed to copy the type we found
+ if (log)
+ {
+ log->Printf (" Failed to import the function type '%s' {0x%8.8" PRIx64 "} into the expression parser AST contenxt",
+ function_type->GetName().GetCString(),
+ function_type->GetID());
+ }
+
+ return;
+ }
+ }
+ else if (symbol)
+ {
+ fun_address = &symbol->GetAddress();
+ function_decl = context.AddGenericFunDecl();
+ is_indirect_function = symbol->IsIndirect();
+ }
+ else
+ {
+ if (log)
+ log->PutCString(" AddOneFunction called with no function and no symbol");
+ return;
+ }
+
+ Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
+
+ lldb::addr_t load_addr = fun_address->GetCallableLoadAddress(target, is_indirect_function);
+
+ ClangExpressionVariableSP entity(m_found_entities.CreateVariable (m_parser_vars->m_exe_ctx.GetBestExecutionContextScope (),
+ m_parser_vars->m_target_info.byte_order,
+ m_parser_vars->m_target_info.address_byte_size));
+ assert (entity.get());
+
+ std::string decl_name(context.m_decl_name.getAsString());
+ entity->SetName(ConstString(decl_name.c_str()));
+ entity->SetClangType (function_clang_type);
+ entity->EnableParserVars(GetParserID());
+
+ ClangExpressionVariable::ParserVars *parser_vars = entity->GetParserVars(GetParserID());
+
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ parser_vars->m_lldb_value.SetValueType(Value::eValueTypeLoadAddress);
+ parser_vars->m_lldb_value.GetScalar() = load_addr;
+ }
+ else
+ {
+ // We have to try finding a file address.
+
+ lldb::addr_t file_addr = fun_address->GetFileAddress();
+
+ parser_vars->m_lldb_value.SetValueType(Value::eValueTypeFileAddress);
+ parser_vars->m_lldb_value.GetScalar() = file_addr;
+ }
+
+
+ parser_vars->m_named_decl = function_decl;
+ parser_vars->m_llvm_value = NULL;
+
+ if (log)
+ {
+ ASTDumper ast_dumper(function_decl);
+
+ StreamString ss;
+
+ fun_address->Dump(&ss, m_parser_vars->m_exe_ctx.GetBestExecutionContextScope(), Address::DumpStyleResolvedDescription);
+
+ log->Printf(" CEDM::FEVD[%u] Found %s function %s (description %s), returned %s",
+ current_id,
+ (function ? "specific" : "generic"),
+ decl_name.c_str(),
+ ss.GetData(),
+ ast_dumper.GetCString());
+ }
+}
+
+TypeFromParser
+ClangExpressionDeclMap::CopyClassType(TypeFromUser &ut,
+ unsigned int current_id)
+{
+ ClangASTType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangExpressionDeclMap::CopyClassType - Couldn't import the type");
+
+ return TypeFromParser();
+ }
+
+ if (copied_clang_type.IsAggregateType() && copied_clang_type.GetCompleteType ())
+ {
+ ClangASTType void_clang_type = ClangASTContext::GetBasicType(m_ast_context, eBasicTypeVoid);
+ ClangASTType void_ptr_clang_type = void_clang_type.GetPointerType();
+
+ ClangASTType method_type = ClangASTContext::CreateFunctionType (m_ast_context,
+ void_clang_type,
+ &void_ptr_clang_type,
+ 1,
+ false,
+ copied_clang_type.GetTypeQualifiers());
+
+ const bool is_virtual = false;
+ const bool is_static = false;
+ const bool is_inline = false;
+ const bool is_explicit = false;
+ const bool is_attr_used = true;
+ const bool is_artificial = false;
+
+ copied_clang_type.AddMethodToCXXRecordType ("$__lldb_expr",
+ method_type,
+ lldb::eAccessPublic,
+ is_virtual,
+ is_static,
+ is_inline,
+ is_explicit,
+ is_attr_used,
+ is_artificial);
+ }
+
+ return TypeFromParser(copied_clang_type);
+}
+
+void
+ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
+ TypeFromUser &ut,
+ unsigned int current_id)
+{
+ ClangASTType copied_clang_type = GuardedCopyType(ut);
+
+ if (!copied_clang_type)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangExpressionDeclMap::AddOneType - Couldn't import the type");
+
+ return;
+ }
+
+ context.AddTypeDecl(copied_clang_type);
+}
diff --git a/source/Expression/ClangExpressionParser.cpp b/source/Expression/ClangExpressionParser.cpp
new file mode 100644
index 000000000000..98c0bfdca874
--- /dev/null
+++ b/source/Expression/ClangExpressionParser.cpp
@@ -0,0 +1,595 @@
+//===-- ClangExpressionParser.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/Expression/ClangExpressionParser.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangExpression.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRDynamicChecks.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Version.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Driver/CC1Options.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Parse/ParseAST.h"
+#include "clang/Rewrite/Frontend/FrontendActions.h"
+#include "clang/Sema/SemaConsumer.h"
+#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/TargetSelect.h"
+
+#if defined(__FreeBSD__)
+#define USE_STANDARD_JIT
+#endif
+
+#if defined (USE_STANDARD_JIT)
+#include "llvm/ExecutionEngine/JIT.h"
+#else
+#include "llvm/ExecutionEngine/MCJIT.h"
+#endif
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/DynamicLibrary.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/Signals.h"
+
+using namespace clang;
+using namespace llvm;
+using namespace lldb_private;
+
+//===----------------------------------------------------------------------===//
+// Utility Methods for Clang
+//===----------------------------------------------------------------------===//
+
+std::string GetBuiltinIncludePath(const char *Argv0) {
+ SmallString<128> P(llvm::sys::fs::getMainExecutable(
+ Argv0, (void *)(intptr_t) GetBuiltinIncludePath));
+
+ if (!P.empty()) {
+ llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang
+ llvm::sys::path::remove_filename(P); // Remove /bin from foo/bin
+
+ // Get foo/lib/clang/<version>/include
+ llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING,
+ "include");
+ }
+
+ return P.str();
+}
+
+
+//===----------------------------------------------------------------------===//
+// Main driver for Clang
+//===----------------------------------------------------------------------===//
+
+static void LLVMErrorHandler(void *UserData, const std::string &Message) {
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+
+ Diags.Report(diag::err_fe_error_backend) << Message;
+
+ // We cannot recover from llvm errors.
+ assert(0);
+}
+
+static FrontendAction *CreateFrontendBaseAction(CompilerInstance &CI) {
+ using namespace clang::frontend;
+
+ switch (CI.getFrontendOpts().ProgramAction) {
+ default:
+ llvm_unreachable("Invalid program action!");
+
+ case ASTDump: return new ASTDumpAction();
+ case ASTPrint: return new ASTPrintAction();
+ case ASTDumpXML: return new ASTDumpXMLAction();
+ case ASTView: return new ASTViewAction();
+ case DumpRawTokens: return new DumpRawTokensAction();
+ case DumpTokens: return new DumpTokensAction();
+ case EmitAssembly: return new EmitAssemblyAction();
+ case EmitBC: return new EmitBCAction();
+ case EmitHTML: return new HTMLPrintAction();
+ case EmitLLVM: return new EmitLLVMAction();
+ case EmitLLVMOnly: return new EmitLLVMOnlyAction();
+ case EmitCodeGenOnly: return new EmitCodeGenOnlyAction();
+ case EmitObj: return new EmitObjAction();
+ case FixIt: return new FixItAction();
+ case GeneratePCH: return new GeneratePCHAction();
+ case GeneratePTH: return new GeneratePTHAction();
+ case InitOnly: return new InitOnlyAction();
+ case ParseSyntaxOnly: return new SyntaxOnlyAction();
+
+ case PluginAction: {
+ for (FrontendPluginRegistry::iterator it =
+ FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end();
+ it != ie; ++it) {
+ if (it->getName() == CI.getFrontendOpts().ActionName) {
+ llvm::OwningPtr<PluginASTAction> P(it->instantiate());
+ if (!P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs))
+ return 0;
+ return P.take();
+ }
+ }
+
+ CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
+ << CI.getFrontendOpts().ActionName;
+ return 0;
+ }
+
+ case PrintDeclContext: return new DeclContextPrintAction();
+ case PrintPreamble: return new PrintPreambleAction();
+ case PrintPreprocessedInput: return new PrintPreprocessedAction();
+ case RewriteMacros: return new RewriteMacrosAction();
+ case RewriteObjC: return new RewriteObjCAction();
+ case RewriteTest: return new RewriteTestAction();
+ //case RunAnalysis: return new AnalysisAction();
+ case RunPreprocessorOnly: return new PreprocessOnlyAction();
+ }
+}
+
+static FrontendAction *CreateFrontendAction(CompilerInstance &CI) {
+ // Create the underlying action.
+ FrontendAction *Act = CreateFrontendBaseAction(CI);
+ if (!Act)
+ return 0;
+
+ // If there are any AST files to merge, create a frontend action
+ // adaptor to perform the merge.
+ if (!CI.getFrontendOpts().ASTMergeFiles.empty())
+ Act = new ASTMergeAction(Act, CI.getFrontendOpts().ASTMergeFiles);
+
+ return Act;
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation of ClangExpressionParser
+//===----------------------------------------------------------------------===//
+
+ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,
+ ClangExpression &expr) :
+ m_expr (expr),
+ m_compiler (),
+ m_code_generator ()
+{
+ // Initialize targets first, so that --version shows registered targets.
+ static struct InitializeLLVM {
+ InitializeLLVM() {
+ llvm::InitializeAllTargets();
+ llvm::InitializeAllAsmPrinters();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllDisassemblers();
+
+ llvm::DisablePrettyStackTrace = true;
+ }
+ } InitializeLLVM;
+
+ // 1. Create a new compiler instance.
+ m_compiler.reset(new CompilerInstance());
+
+ // 2. Install the target.
+
+ lldb::TargetSP target_sp;
+ if (exe_scope)
+ target_sp = exe_scope->CalculateTarget();
+
+ // TODO: figure out what to really do when we don't have a valid target.
+ // Sometimes this will be ok to just use the host target triple (when we
+ // evaluate say "2+3", but other expressions like breakpoint conditions
+ // and other things that _are_ target specific really shouldn't just be
+ // using the host triple. This needs to be fixed in a better way.
+ if (target_sp && target_sp->GetArchitecture().IsValid())
+ {
+ std::string triple = target_sp->GetArchitecture().GetTriple().str();
+
+ int dash_count = 0;
+ for (size_t i = 0; i < triple.size(); ++i)
+ {
+ if (triple[i] == '-')
+ dash_count++;
+ if (dash_count == 3)
+ {
+ triple.resize(i);
+ break;
+ }
+ }
+
+ m_compiler->getTargetOpts().Triple = triple;
+ }
+ else
+ {
+ m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+ }
+
+ if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 ||
+ target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64)
+ {
+ m_compiler->getTargetOpts().Features.push_back("+sse");
+ m_compiler->getTargetOpts().Features.push_back("+sse2");
+ }
+
+ if (m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos)
+ m_compiler->getTargetOpts().ABI = "apcs-gnu";
+
+ m_compiler->createDiagnostics();
+
+ // Create the target instance.
+ m_compiler->setTarget(TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(),
+ &m_compiler->getTargetOpts()));
+
+ assert (m_compiler->hasTarget());
+
+ // 3. Set options.
+
+ lldb::LanguageType language = expr.Language();
+
+ switch (language)
+ {
+ case lldb::eLanguageTypeC:
+ break;
+ case lldb::eLanguageTypeObjC:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ m_compiler->getLangOpts().CPlusPlus = true;
+ m_compiler->getLangOpts().CPlusPlus11 = true;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ default:
+ m_compiler->getLangOpts().ObjC1 = true;
+ m_compiler->getLangOpts().ObjC2 = true;
+ m_compiler->getLangOpts().CPlusPlus = true;
+ m_compiler->getLangOpts().CPlusPlus11 = true;
+ break;
+ }
+
+ m_compiler->getLangOpts().Bool = true;
+ m_compiler->getLangOpts().WChar = true;
+ m_compiler->getLangOpts().Blocks = true;
+ m_compiler->getLangOpts().DebuggerSupport = true; // Features specifically for debugger clients
+ if (expr.DesiredResultType() == ClangExpression::eResultTypeId)
+ m_compiler->getLangOpts().DebuggerCastResultToId = true;
+
+ // Spell checking is a nice feature, but it ends up completing a
+ // lot of types that we didn't strictly speaking need to complete.
+ // As a result, we spend a long time parsing and importing debug
+ // information.
+ m_compiler->getLangOpts().SpellChecking = false;
+
+ lldb::ProcessSP process_sp;
+ if (exe_scope)
+ process_sp = exe_scope->CalculateProcess();
+
+ if (process_sp && m_compiler->getLangOpts().ObjC1)
+ {
+ if (process_sp->GetObjCLanguageRuntime())
+ {
+ if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() == eAppleObjC_V2)
+ m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::MacOSX, VersionTuple(10, 7));
+ else
+ m_compiler->getLangOpts().ObjCRuntime.set(ObjCRuntime::FragileMacOSX, VersionTuple(10, 7));
+
+ if (process_sp->GetObjCLanguageRuntime()->HasNewLiteralsAndIndexing())
+ m_compiler->getLangOpts().DebuggerObjCLiteral = true;
+ }
+ }
+
+ m_compiler->getLangOpts().ThreadsafeStatics = false;
+ m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access
+ m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name
+
+ // Set CodeGen options
+ m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
+ m_compiler->getCodeGenOpts().InstrumentFunctions = false;
+
+ // Disable some warnings.
+ m_compiler->getDiagnostics().setDiagnosticGroupMapping("unused-value", clang::diag::MAP_IGNORE, SourceLocation());
+ m_compiler->getDiagnostics().setDiagnosticGroupMapping("odr", clang::diag::MAP_IGNORE, SourceLocation());
+
+ // Inform the target of the language options
+ //
+ // FIXME: We shouldn't need to do this, the target should be immutable once
+ // created. This complexity should be lifted elsewhere.
+ m_compiler->getTarget().setForcedLangOptions(m_compiler->getLangOpts());
+
+ // 4. Set up the diagnostic buffer for reporting errors
+
+ m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer);
+
+ // 5. Set up the source management objects inside the compiler
+
+ clang::FileSystemOptions file_system_options;
+ m_file_manager.reset(new clang::FileManager(file_system_options));
+
+ if (!m_compiler->hasSourceManager())
+ m_compiler->createSourceManager(*m_file_manager.get());
+
+ m_compiler->createFileManager();
+ m_compiler->createPreprocessor();
+
+ // 6. Most of this we get from the CompilerInstance, but we
+ // also want to give the context an ExternalASTSource.
+ m_selector_table.reset(new SelectorTable());
+ m_builtin_context.reset(new Builtin::Context());
+
+ std::unique_ptr<clang::ASTContext> ast_context(new ASTContext(m_compiler->getLangOpts(),
+ m_compiler->getSourceManager(),
+ &m_compiler->getTarget(),
+ m_compiler->getPreprocessor().getIdentifierTable(),
+ *m_selector_table.get(),
+ *m_builtin_context.get(),
+ 0));
+
+ ClangExpressionDeclMap *decl_map = m_expr.DeclMap();
+
+ if (decl_map)
+ {
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source(decl_map->CreateProxy());
+ decl_map->InstallASTContext(ast_context.get());
+ ast_context->setExternalSource(ast_source);
+ }
+
+ m_compiler->setASTContext(ast_context.release());
+
+ std::string module_name("$__lldb_module");
+
+ m_llvm_context.reset(new LLVMContext());
+ m_code_generator.reset(CreateLLVMCodeGen(m_compiler->getDiagnostics(),
+ module_name,
+ m_compiler->getCodeGenOpts(),
+ m_compiler->getTargetOpts(),
+ *m_llvm_context));
+}
+
+ClangExpressionParser::~ClangExpressionParser()
+{
+}
+
+unsigned
+ClangExpressionParser::Parse (Stream &stream)
+{
+ TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient());
+
+ diag_buf->FlushDiagnostics (m_compiler->getDiagnostics());
+
+ MemoryBuffer *memory_buffer = MemoryBuffer::getMemBufferCopy(m_expr.Text(), __FUNCTION__);
+ m_compiler->getSourceManager().createMainFileIDForMemBuffer (memory_buffer);
+
+ diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor());
+
+ ASTConsumer *ast_transformer = m_expr.ASTTransformer(m_code_generator.get());
+
+ if (ast_transformer)
+ ParseAST(m_compiler->getPreprocessor(), ast_transformer, m_compiler->getASTContext());
+ else
+ ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(), m_compiler->getASTContext());
+
+ diag_buf->EndSourceFile();
+
+ TextDiagnosticBuffer::const_iterator diag_iterator;
+
+ int num_errors = 0;
+
+ for (diag_iterator = diag_buf->warn_begin();
+ diag_iterator != diag_buf->warn_end();
+ ++diag_iterator)
+ stream.Printf("warning: %s\n", (*diag_iterator).second.c_str());
+
+ num_errors = 0;
+
+ for (diag_iterator = diag_buf->err_begin();
+ diag_iterator != diag_buf->err_end();
+ ++diag_iterator)
+ {
+ num_errors++;
+ stream.Printf("error: %s\n", (*diag_iterator).second.c_str());
+ }
+
+ for (diag_iterator = diag_buf->note_begin();
+ diag_iterator != diag_buf->note_end();
+ ++diag_iterator)
+ stream.Printf("note: %s\n", (*diag_iterator).second.c_str());
+
+ if (!num_errors)
+ {
+ if (m_expr.DeclMap() && !m_expr.DeclMap()->ResolveUnknownTypes())
+ {
+ stream.Printf("error: Couldn't infer the type of a variable\n");
+ num_errors++;
+ }
+ }
+
+ return num_errors;
+}
+
+static bool FindFunctionInModule (ConstString &mangled_name,
+ llvm::Module *module,
+ const char *orig_name)
+{
+ for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end();
+ fi != fe;
+ ++fi)
+ {
+ if (fi->getName().str().find(orig_name) != std::string::npos)
+ {
+ mangled_name.SetCString(fi->getName().str().c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Error
+ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,
+ lldb::addr_t &func_end,
+ std::unique_ptr<IRExecutionUnit> &execution_unit_ap,
+ ExecutionContext &exe_ctx,
+ bool &can_interpret,
+ ExecutionPolicy execution_policy)
+{
+ func_addr = LLDB_INVALID_ADDRESS;
+ func_end = LLDB_INVALID_ADDRESS;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ std::unique_ptr<llvm::ExecutionEngine> execution_engine_ap;
+
+ Error err;
+
+ std::unique_ptr<llvm::Module> module_ap (m_code_generator->ReleaseModule());
+
+ if (!module_ap.get())
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("IR doesn't contain a module");
+ return err;
+ }
+
+ // Find the actual name of the function (it's often mangled somehow)
+
+ ConstString function_name;
+
+ if (!FindFunctionInModule(function_name, module_ap.get(), m_expr.FunctionName()))
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName());
+ return err;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName());
+ }
+
+ m_execution_unit.reset(new IRExecutionUnit(m_llvm_context, // handed off here
+ module_ap, // handed off here
+ function_name,
+ exe_ctx.GetTargetSP(),
+ m_compiler->getTargetOpts().Features));
+
+ ClangExpressionDeclMap *decl_map = m_expr.DeclMap(); // result can be NULL
+
+ if (decl_map)
+ {
+ Stream *error_stream = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ error_stream = &target->GetDebugger().GetErrorStream();
+
+ IRForTarget ir_for_target(decl_map,
+ m_expr.NeedsVariableResolution(),
+ *m_execution_unit,
+ error_stream,
+ function_name.AsCString());
+
+ bool ir_can_run = ir_for_target.runOnModule(*m_execution_unit->GetModule());
+
+ Error interpret_error;
+
+ can_interpret = IRInterpreter::CanInterpret(*m_execution_unit->GetModule(), *m_execution_unit->GetFunction(), interpret_error);
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!ir_can_run)
+ {
+ err.SetErrorString("The expression could not be prepared to run in the target");
+ return err;
+ }
+
+ if (!can_interpret && execution_policy == eExecutionPolicyNever)
+ {
+ err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString());
+ return err;
+ }
+
+ if (!process && execution_policy == eExecutionPolicyAlways)
+ {
+ err.SetErrorString("Expression needed to run in the target, but the target can't be run");
+ return err;
+ }
+
+ if (execution_policy == eExecutionPolicyAlways || !can_interpret)
+ {
+ if (m_expr.NeedsValidation() && process)
+ {
+ if (!process->GetDynamicCheckers())
+ {
+ DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions();
+
+ StreamString install_errors;
+
+ if (!dynamic_checkers->Install(install_errors, exe_ctx))
+ {
+ if (install_errors.GetString().empty())
+ err.SetErrorString ("couldn't install checkers, unknown error");
+ else
+ err.SetErrorString (install_errors.GetString().c_str());
+
+ return err;
+ }
+
+ process->SetDynamicCheckers(dynamic_checkers);
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Finished installing dynamic checkers ==");
+ }
+
+ IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString());
+
+ if (!ir_dynamic_checks.runOnModule(*m_execution_unit->GetModule()))
+ {
+ err.SetErrorToGenericError();
+ err.SetErrorString("Couldn't add dynamic checks to the expression");
+ return err;
+ }
+ }
+
+ m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+ }
+ }
+ else
+ {
+ m_execution_unit->GetRunnableInfo(err, func_addr, func_end);
+ }
+
+ execution_unit_ap.reset (m_execution_unit.release());
+
+ return err;
+}
diff --git a/source/Expression/ClangExpressionVariable.cpp b/source/Expression/ClangExpressionVariable.cpp
new file mode 100644
index 000000000000..0d355ce341c9
--- /dev/null
+++ b/source/Expression/ClangExpressionVariable.cpp
@@ -0,0 +1,136 @@
+//===-- ClangExpressionVariable.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/Expression/ClangExpressionVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "clang/AST/ASTContext.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+ClangExpressionVariable::ClangExpressionVariable(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size) :
+ m_parser_vars(),
+ m_jit_vars (),
+ m_flags (EVNone),
+ m_frozen_sp (ValueObjectConstResult::Create (exe_scope, byte_order, addr_byte_size))
+{
+}
+
+ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) :
+ m_parser_vars(),
+ m_jit_vars (),
+ m_flags (EVNone),
+ m_frozen_sp (valobj_sp)
+{
+}
+
+//----------------------------------------------------------------------
+/// Return the variable's size in bytes
+//----------------------------------------------------------------------
+size_t
+ClangExpressionVariable::GetByteSize ()
+{
+ return m_frozen_sp->GetByteSize();
+}
+
+const ConstString &
+ClangExpressionVariable::GetName ()
+{
+ return m_frozen_sp->GetName();
+}
+
+lldb::ValueObjectSP
+ClangExpressionVariable::GetValueObject()
+{
+ return m_frozen_sp;
+}
+
+RegisterInfo *
+ClangExpressionVariable::GetRegisterInfo()
+{
+ return m_frozen_sp->GetValue().GetRegisterInfo();
+}
+
+void
+ClangExpressionVariable::SetRegisterInfo (const RegisterInfo *reg_info)
+{
+ return m_frozen_sp->GetValue().SetContext (Value::eContextTypeRegisterInfo, const_cast<RegisterInfo *>(reg_info));
+}
+
+ClangASTType
+ClangExpressionVariable::GetClangType()
+{
+ return m_frozen_sp->GetClangType();
+}
+
+void
+ClangExpressionVariable::SetClangType(const ClangASTType &clang_type)
+{
+ m_frozen_sp->GetValue().SetClangType(clang_type);
+}
+
+
+TypeFromUser
+ClangExpressionVariable::GetTypeFromUser()
+{
+ TypeFromUser tfu (m_frozen_sp->GetClangType());
+ return tfu;
+}
+
+uint8_t *
+ClangExpressionVariable::GetValueBytes()
+{
+ const size_t byte_size = m_frozen_sp->GetByteSize();
+ if (byte_size > 0)
+ {
+ if (m_frozen_sp->GetDataExtractor().GetByteSize() < byte_size)
+ {
+ m_frozen_sp->GetValue().ResizeData(byte_size);
+ m_frozen_sp->GetValue().GetData (m_frozen_sp->GetDataExtractor());
+ }
+ return const_cast<uint8_t *>(m_frozen_sp->GetDataExtractor().GetDataStart());
+ }
+ return NULL;
+}
+
+void
+ClangExpressionVariable::SetName (const ConstString &name)
+{
+ m_frozen_sp->SetName (name);
+}
+
+void
+ClangExpressionVariable::ValueUpdated ()
+{
+ m_frozen_sp->ValueUpdated ();
+}
+
+void
+ClangExpressionVariable::TransferAddress (bool force)
+{
+ if (m_live_sp.get() == NULL)
+ return;
+
+ if (m_frozen_sp.get() == NULL)
+ return;
+
+ if (force || (m_frozen_sp->GetLiveAddress() == LLDB_INVALID_ADDRESS))
+ m_frozen_sp->SetLiveAddress(m_live_sp->GetLiveAddress());
+}
diff --git a/source/Expression/ClangFunction.cpp b/source/Expression/ClangFunction.cpp
new file mode 100644
index 000000000000..177138df801b
--- /dev/null
+++ b/source/Expression/ClangFunction.cpp
@@ -0,0 +1,633 @@
+//===-- ClangFunction.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/Module.h"
+
+// Project includes
+#include "lldb/Expression/ASTStructExtractor.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ClangFunction constructor
+//----------------------------------------------------------------------
+ClangFunction::ClangFunction
+(
+ ExecutionContextScope &exe_scope,
+ const ClangASTType &return_type,
+ const Address& functionAddress,
+ const ValueList &arg_value_list
+) :
+ m_function_ptr (NULL),
+ m_function_addr (functionAddress),
+ m_function_return_type(return_type),
+ m_wrapper_function_name ("__lldb_caller_function"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_wrapper_args_addrs (),
+ m_arg_values (arg_value_list),
+ m_compiled (false),
+ m_JITted (false)
+{
+ m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ // Can't make a ClangFunction without a process.
+ assert (m_jit_process_wp.lock());
+}
+
+ClangFunction::ClangFunction
+(
+ ExecutionContextScope &exe_scope,
+ Function &function,
+ ClangASTContext *ast_context,
+ const ValueList &arg_value_list
+) :
+ m_function_ptr (&function),
+ m_function_addr (),
+ m_function_return_type (),
+ m_clang_ast_context (ast_context),
+ m_wrapper_function_name ("__lldb_function_caller"),
+ m_wrapper_struct_name ("__lldb_caller_struct"),
+ m_wrapper_args_addrs (),
+ m_arg_values (arg_value_list),
+ m_compiled (false),
+ m_JITted (false)
+{
+ m_jit_process_wp = lldb::ProcessWP(exe_scope.CalculateProcess());
+ // Can't make a ClangFunction without a process.
+ assert (m_jit_process_wp.lock());
+
+ m_function_addr = m_function_ptr->GetAddressRange().GetBaseAddress();
+ m_function_return_type = m_function_ptr->GetClangType().GetFunctionReturnType();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ClangFunction::~ClangFunction()
+{
+}
+
+unsigned
+ClangFunction::CompileFunction (Stream &errors)
+{
+ if (m_compiled)
+ return 0;
+
+ // FIXME: How does clang tell us there's no return value? We need to handle that case.
+ unsigned num_errors = 0;
+
+ std::string return_type_str (m_function_return_type.GetTypeName());
+
+ // Cons up the function we're going to wrap our call in, then compile it...
+ // We declare the function "extern "C"" because the compiler might be in C++
+ // mode which would mangle the name and then we couldn't find it again...
+ m_wrapper_function_text.clear();
+ m_wrapper_function_text.append ("extern \"C\" void ");
+ m_wrapper_function_text.append (m_wrapper_function_name);
+ m_wrapper_function_text.append (" (void *input)\n{\n struct ");
+ m_wrapper_function_text.append (m_wrapper_struct_name);
+ m_wrapper_function_text.append (" \n {\n");
+ m_wrapper_function_text.append (" ");
+ m_wrapper_function_text.append (return_type_str);
+ m_wrapper_function_text.append (" (*fn_ptr) (");
+
+ // Get the number of arguments. If we have a function type and it is prototyped,
+ // trust that, otherwise use the values we were given.
+
+ // FIXME: This will need to be extended to handle Variadic functions. We'll need
+ // to pull the defined arguments out of the function, then add the types from the
+ // arguments list for the variable arguments.
+
+ uint32_t num_args = UINT32_MAX;
+ bool trust_function = false;
+ // GetArgumentCount returns -1 for an unprototyped function.
+ ClangASTType function_clang_type;
+ if (m_function_ptr)
+ {
+ function_clang_type = m_function_ptr->GetClangType();
+ if (function_clang_type)
+ {
+ int num_func_args = function_clang_type.GetFunctionArgumentCount();
+ if (num_func_args >= 0)
+ {
+ trust_function = true;
+ num_args = num_func_args;
+ }
+ }
+ }
+
+ if (num_args == UINT32_MAX)
+ num_args = m_arg_values.GetSize();
+
+ std::string args_buffer; // This one stores the definition of all the args in "struct caller".
+ std::string args_list_buffer; // This one stores the argument list called from the structure.
+ for (size_t i = 0; i < num_args; i++)
+ {
+ std::string type_name;
+
+ if (trust_function)
+ {
+ type_name = function_clang_type.GetFunctionArgumentTypeAtIndex(i).GetTypeName();
+ }
+ else
+ {
+ ClangASTType clang_qual_type = m_arg_values.GetValueAtIndex(i)->GetClangType ();
+ if (clang_qual_type)
+ {
+ type_name = clang_qual_type.GetTypeName();
+ }
+ else
+ {
+ errors.Printf("Could not determine type of input value %lu.", i);
+ return 1;
+ }
+ }
+
+ m_wrapper_function_text.append (type_name);
+ if (i < num_args - 1)
+ m_wrapper_function_text.append (", ");
+
+ char arg_buf[32];
+ args_buffer.append (" ");
+ args_buffer.append (type_name);
+ snprintf(arg_buf, 31, "arg_%" PRIu64, (uint64_t)i);
+ args_buffer.push_back (' ');
+ args_buffer.append (arg_buf);
+ args_buffer.append (";\n");
+
+ args_list_buffer.append ("__lldb_fn_data->");
+ args_list_buffer.append (arg_buf);
+ if (i < num_args - 1)
+ args_list_buffer.append (", ");
+
+ }
+ m_wrapper_function_text.append (");\n"); // Close off the function calling prototype.
+
+ m_wrapper_function_text.append (args_buffer);
+
+ m_wrapper_function_text.append (" ");
+ m_wrapper_function_text.append (return_type_str);
+ m_wrapper_function_text.append (" return_value;");
+ m_wrapper_function_text.append ("\n };\n struct ");
+ m_wrapper_function_text.append (m_wrapper_struct_name);
+ m_wrapper_function_text.append ("* __lldb_fn_data = (struct ");
+ m_wrapper_function_text.append (m_wrapper_struct_name);
+ m_wrapper_function_text.append (" *) input;\n");
+
+ m_wrapper_function_text.append (" __lldb_fn_data->return_value = __lldb_fn_data->fn_ptr (");
+ m_wrapper_function_text.append (args_list_buffer);
+ m_wrapper_function_text.append (");\n}\n");
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ if (log)
+ log->Printf ("Expression: \n\n%s\n\n", m_wrapper_function_text.c_str());
+
+ // Okay, now compile this expression
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+ if (jit_process_sp)
+ {
+ m_parser.reset(new ClangExpressionParser(jit_process_sp.get(), *this));
+
+ num_errors = m_parser->Parse (errors);
+ }
+ else
+ {
+ errors.Printf("no process - unable to inject function");
+ num_errors = 1;
+ }
+
+ m_compiled = (num_errors == 0);
+
+ if (!m_compiled)
+ return num_errors;
+
+ return num_errors;
+}
+
+bool
+ClangFunction::WriteFunctionWrapper (ExecutionContext &exe_ctx, Stream &errors)
+{
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!process)
+ return false;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ if (!m_compiled)
+ return false;
+
+ if (m_JITted)
+ return true;
+
+ bool can_interpret = false; // should stay that way
+
+ Error jit_error (m_parser->PrepareForExecution (m_jit_start_addr,
+ m_jit_end_addr,
+ m_execution_unit_ap,
+ exe_ctx,
+ can_interpret,
+ eExecutionPolicyAlways));
+
+ if (!jit_error.Success())
+ return false;
+
+ if (process && m_jit_start_addr)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+
+ m_JITted = true;
+
+ return true;
+}
+
+bool
+ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ return WriteFunctionArguments(exe_ctx, args_addr_ref, m_function_addr, m_arg_values, errors);
+}
+
+// FIXME: Assure that the ValueList we were passed in is consistent with the one that defined this function.
+
+bool
+ClangFunction::WriteFunctionArguments (ExecutionContext &exe_ctx,
+ lldb::addr_t &args_addr_ref,
+ Address function_address,
+ ValueList &arg_values,
+ Stream &errors)
+{
+ // All the information to reconstruct the struct is provided by the
+ // StructExtractor.
+ if (!m_struct_valid)
+ {
+ errors.Printf("Argument information was not correctly parsed, so the function cannot be called.");
+ return false;
+ }
+
+ Error error;
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL)
+ return return_value;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ if (args_addr_ref == LLDB_INVALID_ADDRESS)
+ {
+ args_addr_ref = process->AllocateMemory(m_struct_size, lldb::ePermissionsReadable|lldb::ePermissionsWritable, error);
+ if (args_addr_ref == LLDB_INVALID_ADDRESS)
+ return false;
+ m_wrapper_args_addrs.push_back (args_addr_ref);
+ }
+ else
+ {
+ // Make sure this is an address that we've already handed out.
+ if (find (m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr_ref) == m_wrapper_args_addrs.end())
+ {
+ return false;
+ }
+ }
+
+ // TODO: verify fun_addr needs to be a callable address
+ Scalar fun_addr (function_address.GetCallableLoadAddress(exe_ctx.GetTargetPtr()));
+ uint64_t first_offset = m_member_offsets[0];
+ process->WriteScalarToMemory(args_addr_ref + first_offset, fun_addr, process->GetAddressByteSize(), error);
+
+ // FIXME: We will need to extend this for Variadic functions.
+
+ Error value_error;
+
+ size_t num_args = arg_values.GetSize();
+ if (num_args != m_arg_values.GetSize())
+ {
+ errors.Printf ("Wrong number of arguments - was: %lu should be: %lu", num_args, m_arg_values.GetSize());
+ return false;
+ }
+
+ for (size_t i = 0; i < num_args; i++)
+ {
+ // FIXME: We should sanity check sizes.
+
+ uint64_t offset = m_member_offsets[i+1]; // Clang sizes are in bytes.
+ Value *arg_value = arg_values.GetValueAtIndex(i);
+
+ // FIXME: For now just do scalars:
+
+ // Special case: if it's a pointer, don't do anything (the ABI supports passing cstrings)
+
+ if (arg_value->GetValueType() == Value::eValueTypeHostAddress &&
+ arg_value->GetContextType() == Value::eContextTypeInvalid &&
+ arg_value->GetClangType().IsPointerType())
+ continue;
+
+ const Scalar &arg_scalar = arg_value->ResolveValue(&exe_ctx);
+
+ if (!process->WriteScalarToMemory(args_addr_ref + offset, arg_scalar, arg_scalar.GetByteSize(), error))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ClangFunction::InsertFunction (ExecutionContext &exe_ctx, lldb::addr_t &args_addr_ref, Stream &errors)
+{
+ using namespace clang;
+
+ if (CompileFunction(errors) != 0)
+ return false;
+ if (!WriteFunctionWrapper(exe_ctx, errors))
+ return false;
+ if (!WriteFunctionArguments(exe_ctx, args_addr_ref, errors))
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("Call Address: 0x%" PRIx64 " Struct Address: 0x%" PRIx64 ".\n", m_jit_start_addr, args_addr_ref);
+
+ return true;
+}
+
+ThreadPlan *
+ClangFunction::GetThreadPlanToCallFunction (ExecutionContext &exe_ctx,
+ lldb::addr_t func_addr,
+ lldb::addr_t &args_addr,
+ Stream &errors,
+ bool stop_others,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *this_arg,
+ lldb::addr_t *cmd_arg)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("-- [ClangFunction::GetThreadPlanToCallFunction] Creating thread plan to call function --");
+
+ // FIXME: Use the errors Stream for better error reporting.
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread == NULL)
+ {
+ errors.Printf("Can't call a function without a valid thread.");
+ return NULL;
+ }
+
+ // Okay, now run the function:
+
+ Address wrapper_address (func_addr);
+ ThreadPlan *new_plan = new ThreadPlanCallFunction (*thread,
+ wrapper_address,
+ ClangASTType(),
+ args_addr,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ this_arg,
+ cmd_arg);
+ new_plan->SetIsMasterPlan(true);
+ new_plan->SetOkayToDiscard (false);
+ return new_plan;
+}
+
+bool
+ClangFunction::FetchFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr, Value &ret_value)
+{
+ // Read the return value - it is the last field in the struct:
+ // FIXME: How does clang tell us there's no return value? We need to handle that case.
+ // FIXME: Create our ThreadPlanCallFunction with the return ClangASTType, and then use GetReturnValueObject
+ // to fetch the value. That way we can fetch any values we need.
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("-- [ClangFunction::FetchFunctionResults] Fetching function results --");
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL)
+ return false;
+
+ lldb::ProcessSP jit_process_sp(m_jit_process_wp.lock());
+
+ if (process != jit_process_sp.get())
+ return false;
+
+ Error error;
+ ret_value.GetScalar() = process->ReadUnsignedIntegerFromMemory (args_addr + m_return_offset, m_return_size, 0, error);
+
+ if (error.Fail())
+ return false;
+
+ ret_value.SetClangType(m_function_return_type);
+ ret_value.SetValueType(Value::eValueTypeScalar);
+ return true;
+}
+
+void
+ClangFunction::DeallocateFunctionResults (ExecutionContext &exe_ctx, lldb::addr_t args_addr)
+{
+ std::list<lldb::addr_t>::iterator pos;
+ pos = std::find(m_wrapper_args_addrs.begin(), m_wrapper_args_addrs.end(), args_addr);
+ if (pos != m_wrapper_args_addrs.end())
+ m_wrapper_args_addrs.erase(pos);
+
+ exe_ctx.GetProcessRef().DeallocateMemory(args_addr);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, Value &results)
+{
+ return ExecuteFunction (exe_ctx, errors, 1000, true, results);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(ExecutionContext &exe_ctx, Stream &errors, bool stop_others, Value &results)
+{
+ const bool try_all_threads = false;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ return ExecuteFunction (exe_ctx, NULL, errors, stop_others, 0UL, try_all_threads,
+ unwind_on_error, ignore_breakpoints, results);
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exe_ctx,
+ Stream &errors,
+ uint32_t timeout_usec,
+ bool try_all_threads,
+ Value &results)
+{
+ const bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec,
+ try_all_threads, unwind_on_error, ignore_breakpoints, results);
+}
+
+// This is the static function
+ExecutionResults
+ClangFunction::ExecuteFunction (
+ ExecutionContext &exe_ctx,
+ lldb::addr_t function_address,
+ lldb::addr_t &void_arg,
+ bool stop_others,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ uint32_t timeout_usec,
+ Stream &errors,
+ lldb::addr_t *this_arg)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf("== [ClangFunction::ExecuteFunction] Executing function ==");
+
+ lldb::ThreadPlanSP call_plan_sp (ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
+ function_address,
+ void_arg,
+ errors,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ this_arg));
+ if (!call_plan_sp)
+ return eExecutionSetupError;
+
+ // <rdar://problem/12027563> we need to make sure we record the fact that we are running an expression here
+ // otherwise this fact will fail to be recorded when fetching an Objective-C object description
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
+
+ ExecutionResults results = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx, call_plan_sp,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ errors);
+
+ if (log)
+ {
+ if (results != eExecutionCompleted)
+ {
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution completed abnormally ==");
+ }
+ else
+ {
+ log->Printf("== [ClangFunction::ExecuteFunction] Execution completed normally ==");
+ }
+ }
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
+
+ return results;
+}
+
+ExecutionResults
+ClangFunction::ExecuteFunction(
+ ExecutionContext &exe_ctx,
+ lldb::addr_t *args_addr_ptr,
+ Stream &errors,
+ bool stop_others,
+ uint32_t timeout_usec,
+ bool try_all_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ Value &results)
+{
+ using namespace clang;
+ ExecutionResults return_value = eExecutionSetupError;
+
+ lldb::addr_t args_addr;
+
+ if (args_addr_ptr != NULL)
+ args_addr = *args_addr_ptr;
+ else
+ args_addr = LLDB_INVALID_ADDRESS;
+
+ if (CompileFunction(errors) != 0)
+ return eExecutionSetupError;
+
+ if (args_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (!InsertFunction(exe_ctx, args_addr, errors))
+ return eExecutionSetupError;
+ }
+
+ return_value = ClangFunction::ExecuteFunction (exe_ctx,
+ m_jit_start_addr,
+ args_addr,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ errors);
+
+ if (args_addr_ptr != NULL)
+ *args_addr_ptr = args_addr;
+
+ if (return_value != eExecutionCompleted)
+ return return_value;
+
+ FetchFunctionResults(exe_ctx, args_addr, results);
+
+ if (args_addr_ptr == NULL)
+ DeallocateFunctionResults(exe_ctx, args_addr);
+
+ return eExecutionCompleted;
+}
+
+clang::ASTConsumer *
+ClangFunction::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ return new ASTStructExtractor(passthrough, m_wrapper_struct_name.c_str(), *this);
+}
diff --git a/source/Expression/ClangPersistentVariables.cpp b/source/Expression/ClangPersistentVariables.cpp
new file mode 100644
index 000000000000..db062d2e20b6
--- /dev/null
+++ b/source/Expression/ClangPersistentVariables.cpp
@@ -0,0 +1,89 @@
+//===-- ClangPersistentVariables.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/Expression/ClangPersistentVariables.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Value.h"
+
+#include "llvm/ADT/StringMap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ClangPersistentVariables::ClangPersistentVariables () :
+ ClangExpressionVariableList(),
+ m_next_persistent_variable_id (0)
+{
+}
+
+ClangExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (const lldb::ValueObjectSP &valobj_sp)
+{
+ ClangExpressionVariableSP var_sp (CreateVariable(valobj_sp));
+ return var_sp;
+}
+
+ClangExpressionVariableSP
+ClangPersistentVariables::CreatePersistentVariable (ExecutionContextScope *exe_scope,
+ const ConstString &name,
+ const TypeFromUser& user_type,
+ lldb::ByteOrder byte_order,
+ uint32_t addr_byte_size)
+{
+ ClangExpressionVariableSP var_sp (GetVariable(name));
+
+ if (!var_sp)
+ var_sp = CreateVariable(exe_scope, name, user_type, byte_order, addr_byte_size);
+
+ return var_sp;
+}
+
+void
+ClangPersistentVariables::RemovePersistentVariable (lldb::ClangExpressionVariableSP variable)
+{
+ RemoveVariable(variable);
+
+ const char *name = variable->GetName().AsCString();
+
+ if (*name != '$')
+ return;
+ name++;
+
+ if (strtoul(name, NULL, 0) == m_next_persistent_variable_id - 1)
+ m_next_persistent_variable_id--;
+}
+
+ConstString
+ClangPersistentVariables::GetNextPersistentVariableName ()
+{
+ char name_cstr[256];
+ ::snprintf (name_cstr, sizeof(name_cstr), "$%u", m_next_persistent_variable_id++);
+ ConstString name(name_cstr);
+ return name;
+}
+
+void
+ClangPersistentVariables::RegisterPersistentType (const ConstString &name,
+ clang::TypeDecl *type_decl)
+{
+ m_persistent_types.insert(std::pair<const char*, clang::TypeDecl*>(name.GetCString(), type_decl));
+}
+
+clang::TypeDecl *
+ClangPersistentVariables::GetPersistentType (const ConstString &name)
+{
+ PersistentTypeMap::const_iterator i = m_persistent_types.find(name.GetCString());
+
+ if (i == m_persistent_types.end())
+ return NULL;
+ else
+ return i->second;
+}
diff --git a/source/Expression/ClangUserExpression.cpp b/source/Expression/ClangUserExpression.cpp
new file mode 100644
index 000000000000..7f09f6fa0942
--- /dev/null
+++ b/source/Expression/ClangUserExpression.cpp
@@ -0,0 +1,1091 @@
+//===-- ClangUserExpression.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+// C++ Includes
+#include <cstdlib>
+#include <string>
+#include <map>
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Expression/ASTResultSynthesizer.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangFunction.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallUserExpression.h"
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
+using namespace lldb_private;
+
+ClangUserExpression::ClangUserExpression (const char *expr,
+ const char *expr_prefix,
+ lldb::LanguageType language,
+ ResultType desired_type) :
+ ClangExpression (),
+ m_stack_frame_bottom (LLDB_INVALID_ADDRESS),
+ m_stack_frame_top (LLDB_INVALID_ADDRESS),
+ m_expr_text (expr),
+ m_expr_prefix (expr_prefix ? expr_prefix : ""),
+ m_language (language),
+ m_transformed_text (),
+ m_desired_type (desired_type),
+ m_enforce_valid_object (true),
+ m_cplusplus (false),
+ m_objectivec (false),
+ m_static_method(false),
+ m_needs_object_ptr (false),
+ m_const_object (false),
+ m_target (NULL),
+ m_can_interpret (false),
+ m_materialized_address (LLDB_INVALID_ADDRESS)
+{
+ switch (m_language)
+ {
+ case lldb::eLanguageTypeC_plus_plus:
+ m_allow_cxx = true;
+ break;
+ case lldb::eLanguageTypeObjC:
+ m_allow_objc = true;
+ break;
+ case lldb::eLanguageTypeObjC_plus_plus:
+ default:
+ m_allow_cxx = true;
+ m_allow_objc = true;
+ break;
+ }
+}
+
+ClangUserExpression::~ClangUserExpression ()
+{
+}
+
+clang::ASTConsumer *
+ClangUserExpression::ASTTransformer (clang::ASTConsumer *passthrough)
+{
+ ClangASTContext *clang_ast_context = m_target->GetScratchClangASTContext();
+
+ if (!clang_ast_context)
+ return NULL;
+
+ if (!m_result_synthesizer.get())
+ m_result_synthesizer.reset(new ASTResultSynthesizer(passthrough,
+ *m_target));
+
+ return m_result_synthesizer.get();
+}
+
+void
+ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Error &err)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("ClangUserExpression::ScanContext()");
+
+ m_target = exe_ctx.GetTargetPtr();
+
+ if (!(m_allow_cxx || m_allow_objc))
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Settings inhibit C++ and Objective-C");
+ return;
+ }
+
+ StackFrame *frame = exe_ctx.GetFramePtr();
+ if (frame == NULL)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null stack frame");
+ return;
+ }
+
+ SymbolContext sym_ctx = frame->GetSymbolContext(lldb::eSymbolContextFunction | lldb::eSymbolContextBlock);
+
+ if (!sym_ctx.function)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null function");
+ return;
+ }
+
+ // Find the block that defines the function represented by "sym_ctx"
+ Block *function_block = sym_ctx.GetFunctionBlock();
+
+ if (!function_block)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null function block");
+ return;
+ }
+
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (!decl_context)
+ {
+ if (log)
+ log->Printf(" [CUE::SC] Null decl context");
+ return;
+ }
+
+ if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_context))
+ {
+ if (m_allow_cxx && method_decl->isInstance())
+ {
+ if (m_enforce_valid_object)
+ {
+ lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
+
+ const char *thisErrorString = "Stopped in a C++ method, but 'this' isn't available; pretending we are in a generic context";
+
+ if (!variable_list_sp)
+ {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+
+ lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this")));
+
+ if (!this_var_sp ||
+ !this_var_sp->IsInScope(frame) ||
+ !this_var_sp->LocationIsValidForFrame (frame))
+ {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+ }
+
+ m_cplusplus = true;
+ m_needs_object_ptr = true;
+ }
+ }
+ else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_context))
+ {
+ if (m_allow_objc)
+ {
+ if (m_enforce_valid_object)
+ {
+ lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
+
+ const char *selfErrorString = "Stopped in an Objective-C method, but 'self' isn't available; pretending we are in a generic context";
+
+ if (!variable_list_sp)
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self"));
+
+ if (!self_variable_sp ||
+ !self_variable_sp->IsInScope(frame) ||
+ !self_variable_sp->LocationIsValidForFrame (frame))
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+ }
+
+ m_objectivec = true;
+ m_needs_object_ptr = true;
+
+ if (!method_decl->isInstanceMethod())
+ m_static_method = true;
+ }
+ }
+ else if (clang::FunctionDecl *function_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_context))
+ {
+ // We might also have a function that said in the debug information that it captured an
+ // object pointer. The best way to deal with getting to the ivars at present it by pretending
+ // that this is a method of a class in whatever runtime the debug info says the object pointer
+ // belongs to. Do that here.
+
+ ClangASTMetadata *metadata = ClangASTContext::GetMetadata (&decl_context->getParentASTContext(), function_decl);
+ if (metadata && metadata->HasObjectPtr())
+ {
+ lldb::LanguageType language = metadata->GetObjectPtrLanguage();
+ if (language == lldb::eLanguageTypeC_plus_plus)
+ {
+ if (m_enforce_valid_object)
+ {
+ lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
+
+ const char *thisErrorString = "Stopped in a context claiming to capture a C++ object pointer, but 'this' isn't available; pretending we are in a generic context";
+
+ if (!variable_list_sp)
+ {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+
+ lldb::VariableSP this_var_sp (variable_list_sp->FindVariable(ConstString("this")));
+
+ if (!this_var_sp ||
+ !this_var_sp->IsInScope(frame) ||
+ !this_var_sp->LocationIsValidForFrame (frame))
+ {
+ err.SetErrorString(thisErrorString);
+ return;
+ }
+ }
+
+ m_cplusplus = true;
+ m_needs_object_ptr = true;
+ }
+ else if (language == lldb::eLanguageTypeObjC)
+ {
+ if (m_enforce_valid_object)
+ {
+ lldb::VariableListSP variable_list_sp (function_block->GetBlockVariableList (true));
+
+ const char *selfErrorString = "Stopped in a context claiming to capture an Objective-C object pointer, but 'self' isn't available; pretending we are in a generic context";
+
+ if (!variable_list_sp)
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ lldb::VariableSP self_variable_sp = variable_list_sp->FindVariable(ConstString("self"));
+
+ if (!self_variable_sp ||
+ !self_variable_sp->IsInScope(frame) ||
+ !self_variable_sp->LocationIsValidForFrame (frame))
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ Type *self_type = self_variable_sp->GetType();
+
+ if (!self_type)
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ ClangASTType self_clang_type = self_type->GetClangForwardType();
+
+ if (!self_clang_type)
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+
+ if (self_clang_type.IsObjCClassType())
+ {
+ return;
+ }
+ else if (self_clang_type.IsObjCObjectPointerType())
+ {
+ m_objectivec = true;
+ m_needs_object_ptr = true;
+ }
+ else
+ {
+ err.SetErrorString(selfErrorString);
+ return;
+ }
+ }
+ else
+ {
+ m_objectivec = true;
+ m_needs_object_ptr = true;
+ }
+ }
+ }
+ }
+}
+
+void
+ClangUserExpression::InstallContext (ExecutionContext &exe_ctx)
+{
+ m_process_wp = exe_ctx.GetProcessSP();
+
+ lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP();
+
+ if (frame_sp)
+ m_address = frame_sp->GetFrameCodeAddress();
+}
+
+bool
+ClangUserExpression::LockAndCheckContext (ExecutionContext &exe_ctx,
+ lldb::TargetSP &target_sp,
+ lldb::ProcessSP &process_sp,
+ lldb::StackFrameSP &frame_sp)
+{
+ lldb::ProcessSP expected_process_sp = m_process_wp.lock();
+ process_sp = exe_ctx.GetProcessSP();
+
+ if (process_sp != expected_process_sp)
+ return false;
+
+ process_sp = exe_ctx.GetProcessSP();
+ target_sp = exe_ctx.GetTargetSP();
+ frame_sp = exe_ctx.GetFrameSP();
+
+ if (m_address.IsValid())
+ {
+ if (!frame_sp)
+ return false;
+ else
+ return (0 == Address::CompareLoadAddress(m_address, frame_sp->GetFrameCodeAddress(), target_sp.get()));
+ }
+
+ return true;
+}
+
+bool
+ClangUserExpression::MatchesContext (ExecutionContext &exe_ctx)
+{
+ lldb::TargetSP target_sp;
+ lldb::ProcessSP process_sp;
+ lldb::StackFrameSP frame_sp;
+
+ return LockAndCheckContext(exe_ctx, target_sp, process_sp, frame_sp);
+}
+
+// This is a really nasty hack, meant to fix Objective-C expressions of the form
+// (int)[myArray count]. Right now, because the type information for count is
+// not available, [myArray count] returns id, which can't be directly cast to
+// int without causing a clang error.
+static void
+ApplyObjcCastHack(std::string &expr)
+{
+#define OBJC_CAST_HACK_FROM "(int)["
+#define OBJC_CAST_HACK_TO "(int)(long long)["
+
+ size_t from_offset;
+
+ while ((from_offset = expr.find(OBJC_CAST_HACK_FROM)) != expr.npos)
+ expr.replace(from_offset, sizeof(OBJC_CAST_HACK_FROM) - 1, OBJC_CAST_HACK_TO);
+
+#undef OBJC_CAST_HACK_TO
+#undef OBJC_CAST_HACK_FROM
+}
+
+// Another hack, meant to allow use of unichar despite it not being available in
+// the type information. Although we could special-case it in type lookup,
+// hopefully we'll figure out a way to #include the same environment as is
+// present in the original source file rather than try to hack specific type
+// definitions in as needed.
+static void
+ApplyUnicharHack(std::string &expr)
+{
+#define UNICHAR_HACK_FROM "unichar"
+#define UNICHAR_HACK_TO "unsigned short"
+
+ size_t from_offset;
+
+ while ((from_offset = expr.find(UNICHAR_HACK_FROM)) != expr.npos)
+ expr.replace(from_offset, sizeof(UNICHAR_HACK_FROM) - 1, UNICHAR_HACK_TO);
+
+#undef UNICHAR_HACK_TO
+#undef UNICHAR_HACK_FROM
+}
+
+bool
+ClangUserExpression::Parse (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ bool keep_result_in_memory)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Error err;
+
+ InstallContext(exe_ctx);
+
+ ScanContext(exe_ctx, err);
+
+ if (!err.Success())
+ {
+ error_stream.Printf("warning: %s\n", err.AsCString());
+ }
+
+ StreamString m_transformed_stream;
+
+ ////////////////////////////////////
+ // Generate the expression
+ //
+
+ ApplyObjcCastHack(m_expr_text);
+ //ApplyUnicharHack(m_expr_text);
+
+ std::unique_ptr<ExpressionSourceCode> source_code (ExpressionSourceCode::CreateWrapped(m_expr_prefix.c_str(), m_expr_text.c_str()));
+
+ lldb::LanguageType lang_type;
+
+ if (m_cplusplus)
+ lang_type = lldb::eLanguageTypeC_plus_plus;
+ else if(m_objectivec)
+ lang_type = lldb::eLanguageTypeObjC;
+ else
+ lang_type = lldb::eLanguageTypeC;
+
+ if (!source_code->GetText(m_transformed_text, lang_type, m_const_object, m_static_method))
+ {
+ error_stream.PutCString ("error: couldn't construct expression body");
+ return false;
+ }
+
+ if (log)
+ log->Printf("Parsing the following code:\n%s", m_transformed_text.c_str());
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ error_stream.PutCString ("error: invalid target\n");
+ return false;
+ }
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ m_materializer_ap.reset(new Materializer());
+
+ m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx));
+
+ class OnExit
+ {
+ public:
+ typedef std::function <void (void)> Callback;
+
+ OnExit (Callback const &callback) :
+ m_callback(callback)
+ {
+ }
+
+ ~OnExit ()
+ {
+ m_callback();
+ }
+ private:
+ Callback m_callback;
+ };
+
+ OnExit on_exit([this]() { m_expr_decl_map.reset(); });
+
+ if (!m_expr_decl_map->WillParse(exe_ctx, m_materializer_ap.get()))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+ ExecutionContextScope *exe_scope = process;
+
+ if (!exe_scope)
+ exe_scope = exe_ctx.GetTargetPtr();
+
+ ClangExpressionParser parser(exe_scope, *this);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ m_expr_decl_map->DidParse();
+
+ return false;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////
+ // Prepare the output of the parser for execution, evaluating it statically if possible
+ //
+
+ Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
+ m_jit_end_addr,
+ m_execution_unit_ap,
+ exe_ctx,
+ m_can_interpret,
+ execution_policy);
+
+ if (jit_error.Success())
+ {
+ if (process && m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf ("error: %s\n", error_cstr);
+ else
+ error_stream.Printf ("error: expression can't be interpreted or run\n");
+ return false;
+ }
+}
+
+static lldb::addr_t
+GetObjectPointer (lldb::StackFrameSP frame_sp,
+ ConstString &object_name,
+ Error &err)
+{
+ err.Clear();
+
+ if (!frame_sp)
+ {
+ err.SetErrorStringWithFormat("Couldn't load '%s' because the context is incomplete", object_name.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ lldb::VariableSP var_sp;
+ lldb::ValueObjectSP valobj_sp;
+
+ valobj_sp = frame_sp->GetValueForVariableExpressionPath(object_name.AsCString(),
+ lldb::eNoDynamicValues,
+ StackFrame::eExpressionPathOptionCheckPtrVsMember ||
+ StackFrame::eExpressionPathOptionsAllowDirectIVarAccess ||
+ StackFrame::eExpressionPathOptionsNoFragileObjcIvar ||
+ StackFrame::eExpressionPathOptionsNoSyntheticChildren ||
+ StackFrame::eExpressionPathOptionsNoSyntheticArrayRange,
+ var_sp,
+ err);
+
+ if (!err.Success())
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = valobj_sp->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (ret == LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorStringWithFormat("Couldn't load '%s' because its value couldn't be evaluated", object_name.AsCString());
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ return ret;
+}
+
+bool
+ClangUserExpression::PrepareToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::addr_t &struct_address,
+ lldb::addr_t &object_ptr,
+ lldb::addr_t &cmd_ptr)
+{
+ lldb::TargetSP target;
+ lldb::ProcessSP process;
+ lldb::StackFrameSP frame;
+
+ if (!LockAndCheckContext(exe_ctx,
+ target,
+ process,
+ frame))
+ {
+ error_stream.Printf("The context has changed before we could JIT the expression!\n");
+ return false;
+ }
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
+ {
+ if (m_needs_object_ptr)
+ {
+ ConstString object_name;
+
+ if (m_cplusplus)
+ {
+ object_name.SetCString("this");
+ }
+ else if (m_objectivec)
+ {
+ object_name.SetCString("self");
+ }
+ else
+ {
+ error_stream.Printf("Need object pointer but don't know the language\n");
+ return false;
+ }
+
+ Error object_ptr_error;
+
+ object_ptr = GetObjectPointer(frame, object_name, object_ptr_error);
+
+ if (!object_ptr_error.Success())
+ {
+ error_stream.Printf("warning: couldn't get required object pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
+ object_ptr = 0;
+ }
+
+ if (m_objectivec)
+ {
+ ConstString cmd_name("_cmd");
+
+ cmd_ptr = GetObjectPointer(frame, cmd_name, object_ptr_error);
+
+ if (!object_ptr_error.Success())
+ {
+ error_stream.Printf("warning: couldn't get cmd pointer (substituting NULL): %s\n", object_ptr_error.AsCString());
+ cmd_ptr = 0;
+ }
+ }
+ }
+
+ if (m_materialized_address == LLDB_INVALID_ADDRESS)
+ {
+ Error alloc_error;
+
+ IRMemoryMap::AllocationPolicy policy = m_can_interpret ? IRMemoryMap::eAllocationPolicyHostOnly : IRMemoryMap::eAllocationPolicyMirror;
+
+ m_materialized_address = m_execution_unit_ap->Malloc(m_materializer_ap->GetStructByteSize(),
+ m_materializer_ap->GetStructAlignment(),
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ policy,
+ alloc_error);
+
+ if (!alloc_error.Success())
+ {
+ error_stream.Printf("Couldn't allocate space for materialized struct: %s\n", alloc_error.AsCString());
+ return false;
+ }
+ }
+
+ struct_address = m_materialized_address;
+
+ if (m_can_interpret && m_stack_frame_bottom == LLDB_INVALID_ADDRESS)
+ {
+ Error alloc_error;
+
+ const size_t stack_frame_size = 512 * 1024;
+
+ m_stack_frame_bottom = m_execution_unit_ap->Malloc(stack_frame_size,
+ 8,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ IRMemoryMap::eAllocationPolicyHostOnly,
+ alloc_error);
+
+ m_stack_frame_top = m_stack_frame_bottom + stack_frame_size;
+
+ if (!alloc_error.Success())
+ {
+ error_stream.Printf("Couldn't allocate space for the stack frame: %s\n", alloc_error.AsCString());
+ return false;
+ }
+ }
+
+ Error materialize_error;
+
+ m_dematerializer_sp = m_materializer_ap->Materialize(frame, *m_execution_unit_ap, struct_address, materialize_error);
+
+ if (!materialize_error.Success())
+ {
+ error_stream.Printf("Couldn't materialize struct: %s\n", materialize_error.AsCString());
+ return false;
+ }
+ }
+ return true;
+}
+
+ThreadPlan *
+ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ lldb::addr_t struct_address;
+
+ lldb::addr_t object_ptr = 0;
+ lldb::addr_t cmd_ptr = 0;
+
+ PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr);
+
+ // FIXME: This should really return a ThreadPlanCallUserExpression, in order to make sure that we don't release the
+ // ClangUserExpression resources before the thread plan finishes execution in the target. But because we are
+ // forcing unwind_on_error to be true here, in practical terms that can't happen.
+
+ const bool stop_others = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = false;
+ return ClangFunction::GetThreadPlanToCallFunction (exe_ctx,
+ m_jit_start_addr,
+ struct_address,
+ error_stream,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ (m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL);
+}
+
+bool
+ClangUserExpression::FinalizeJITExecution (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ lldb::ClangExpressionVariableSP &result,
+ lldb::addr_t function_stack_bottom,
+ lldb::addr_t function_stack_top)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::FinalizeJITExecution] Dematerializing after execution --");
+
+ if (!m_dematerializer_sp)
+ {
+ error_stream.Printf ("Couldn't apply expression side effects : no dematerializer is present");
+ return false;
+ }
+
+ Error dematerialize_error;
+
+ m_dematerializer_sp->Dematerialize(dematerialize_error, result, function_stack_bottom, function_stack_top);
+
+ if (!dematerialize_error.Success())
+ {
+ error_stream.Printf ("Couldn't apply expression side effects : %s\n", dematerialize_error.AsCString("unknown error"));
+ return false;
+ }
+
+ if (result)
+ result->TransferAddress();
+
+ m_dematerializer_sp.reset();
+
+ return true;
+}
+
+ExecutionResults
+ClangUserExpression::Execute (Stream &error_stream,
+ ExecutionContext &exe_ctx,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me,
+ lldb::ClangExpressionVariableSP &result,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ // The expression log is quite verbose, and if you're just tracking the execution of the
+ // expression, it's quite convenient to have these logs come out with the STEP log as well.
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS || m_can_interpret)
+ {
+ lldb::addr_t struct_address = LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t object_ptr = 0;
+ lldb::addr_t cmd_ptr = 0;
+
+ if (!PrepareToExecuteJITExpression (error_stream, exe_ctx, struct_address, object_ptr, cmd_ptr))
+ {
+ error_stream.Printf("Errored out in %s, couldn't PrepareToExecuteJITExpression", __FUNCTION__);
+ return eExecutionSetupError;
+ }
+
+ lldb::addr_t function_stack_bottom = LLDB_INVALID_ADDRESS;
+ lldb::addr_t function_stack_top = LLDB_INVALID_ADDRESS;
+
+ if (m_can_interpret)
+ {
+ llvm::Module *module = m_execution_unit_ap->GetModule();
+ llvm::Function *function = m_execution_unit_ap->GetFunction();
+
+ if (!module || !function)
+ {
+ error_stream.Printf("Supposed to interpret, but nothing is there");
+ return eExecutionSetupError;
+ }
+
+ Error interpreter_error;
+
+ llvm::SmallVector <lldb::addr_t, 3> args;
+
+ if (m_needs_object_ptr)
+ {
+ args.push_back(object_ptr);
+
+ if (m_objectivec)
+ args.push_back(cmd_ptr);
+ }
+
+ args.push_back(struct_address);
+
+ function_stack_bottom = m_stack_frame_bottom;
+ function_stack_top = m_stack_frame_top;
+
+ IRInterpreter::Interpret (*module,
+ *function,
+ args,
+ *m_execution_unit_ap.get(),
+ interpreter_error,
+ function_stack_bottom,
+ function_stack_top);
+
+ if (!interpreter_error.Success())
+ {
+ error_stream.Printf("Supposed to interpret, but failed: %s", interpreter_error.AsCString());
+ return eExecutionDiscarded;
+ }
+ }
+ else
+ {
+ const bool stop_others = true;
+ const bool try_all_threads = run_others;
+
+ Address wrapper_address (m_jit_start_addr);
+ lldb::ThreadPlanSP call_plan_sp(new ThreadPlanCallUserExpression (exe_ctx.GetThreadRef(),
+ wrapper_address,
+ struct_address,
+ stop_others,
+ unwind_on_error,
+ ignore_breakpoints,
+ (m_needs_object_ptr ? &object_ptr : NULL),
+ ((m_needs_object_ptr && m_objectivec) ? &cmd_ptr : NULL),
+ shared_ptr_to_me));
+
+ if (!call_plan_sp || !call_plan_sp->ValidatePlan (&error_stream))
+ return eExecutionSetupError;
+
+ lldb::addr_t function_stack_pointer = static_cast<ThreadPlanCallFunction *>(call_plan_sp.get())->GetFunctionStackPointer();
+
+ function_stack_bottom = function_stack_pointer - Host::GetPageSize();
+ function_stack_top = function_stack_pointer;
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::Execute] Execution of expression begins --");
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(true);
+
+ ExecutionResults execution_result = exe_ctx.GetProcessRef().RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_others,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_stream);
+
+ if (exe_ctx.GetProcessPtr())
+ exe_ctx.GetProcessPtr()->SetRunningUserExpression(false);
+
+ if (log)
+ log->Printf("-- [ClangUserExpression::Execute] Execution of expression completed --");
+
+ if (execution_result == eExecutionInterrupted || execution_result == eExecutionHitBreakpoint)
+ {
+ const char *error_desc = NULL;
+
+ if (call_plan_sp)
+ {
+ lldb::StopInfoSP real_stop_info_sp = call_plan_sp->GetRealStopInfo();
+ if (real_stop_info_sp)
+ error_desc = real_stop_info_sp->GetDescription();
+ }
+ if (error_desc)
+ error_stream.Printf ("Execution was interrupted, reason: %s.", error_desc);
+ else
+ error_stream.Printf ("Execution was interrupted.");
+
+ if ((execution_result == eExecutionInterrupted && unwind_on_error)
+ || (execution_result == eExecutionHitBreakpoint && ignore_breakpoints))
+ error_stream.Printf ("\nThe process has been returned to the state before expression evaluation.");
+ else
+ error_stream.Printf ("\nThe process has been left at the point where it was interrupted, use \"thread return -x\" to return to the state before expression evaluation.");
+
+ return execution_result;
+ }
+ else if (execution_result != eExecutionCompleted)
+ {
+ error_stream.Printf ("Couldn't execute function; result was %s\n", Process::ExecutionResultAsCString (execution_result));
+ return execution_result;
+ }
+ }
+
+ if (FinalizeJITExecution (error_stream, exe_ctx, result, function_stack_bottom, function_stack_top))
+ {
+ return eExecutionCompleted;
+ }
+ else
+ {
+ return eExecutionSetupError;
+ }
+ }
+ else
+ {
+ error_stream.Printf("Expression can't be run, because there is no JIT compiled function");
+ return eExecutionSetupError;
+ }
+}
+
+ExecutionResults
+ClangUserExpression::Evaluate (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ Error error;
+ return EvaluateWithError (exe_ctx,
+ execution_policy,
+ language,
+ desired_type,
+ unwind_on_error,
+ ignore_breakpoints,
+ expr_cstr,
+ expr_prefix,
+ result_valobj_sp,
+ error,
+ run_others,
+ timeout_usec);
+}
+
+ExecutionResults
+ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx,
+ lldb_private::ExecutionPolicy execution_policy,
+ lldb::LanguageType language,
+ ResultType desired_type,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ const char *expr_cstr,
+ const char *expr_prefix,
+ lldb::ValueObjectSP &result_valobj_sp,
+ Error &error,
+ bool run_others,
+ uint32_t timeout_usec)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP));
+
+ ExecutionResults execution_results = eExecutionSetupError;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process == NULL || process->GetState() != lldb::eStateStopped)
+ {
+ if (execution_policy == eExecutionPolicyAlways)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ error.SetErrorString ("expression needed to run but couldn't");
+
+ return execution_results;
+ }
+ }
+
+ if (process == NULL || !process->CanJIT())
+ execution_policy = eExecutionPolicyNever;
+
+ ClangUserExpressionSP user_expression_sp (new ClangUserExpression (expr_cstr, expr_prefix, language, desired_type));
+
+ StreamString error_stream;
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Parsing expression %s ==", expr_cstr);
+
+ const bool keep_expression_in_memory = true;
+
+ if (!user_expression_sp->Parse (error_stream, exe_ctx, execution_policy, keep_expression_in_memory))
+ {
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression failed to parse, unknown error");
+ else
+ error.SetErrorString (error_stream.GetString().c_str());
+ }
+ else
+ {
+ lldb::ClangExpressionVariableSP expr_result;
+
+ if (execution_policy == eExecutionPolicyNever &&
+ !user_expression_sp->CanInterpret())
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Expression may not run, but is not constant ==");
+
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression needed to run but couldn't");
+ }
+ else
+ {
+ error_stream.GetString().clear();
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Executing expression ==");
+
+ execution_results = user_expression_sp->Execute (error_stream,
+ exe_ctx,
+ unwind_on_error,
+ ignore_breakpoints,
+ user_expression_sp,
+ expr_result,
+ run_others,
+ timeout_usec);
+
+ if (execution_results != eExecutionCompleted)
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed abnormally ==");
+
+ if (error_stream.GetString().empty())
+ error.SetErrorString ("expression failed to execute, unknown error");
+ else
+ error.SetErrorString (error_stream.GetString().c_str());
+ }
+ else
+ {
+ if (expr_result)
+ {
+ result_valobj_sp = expr_result->GetValueObject();
+
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with result %s ==", result_valobj_sp->GetValueAsCString());
+ }
+ else
+ {
+ if (log)
+ log->Printf("== [ClangUserExpression::Evaluate] Execution completed normally with no result ==");
+
+ error.SetError(ClangUserExpression::kNoResult, lldb::eErrorTypeGeneric);
+ }
+ }
+ }
+ }
+
+ if (result_valobj_sp.get() == NULL)
+ result_valobj_sp = ValueObjectConstResult::Create (NULL, error);
+
+ return execution_results;
+}
diff --git a/source/Expression/ClangUtilityFunction.cpp b/source/Expression/ClangUtilityFunction.cpp
new file mode 100644
index 000000000000..c911c279993f
--- /dev/null
+++ b/source/Expression/ClangUtilityFunction.cpp
@@ -0,0 +1,169 @@
+//===-- ClangUserExpression.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+// C++ Includes
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionParser.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Expression/ExpressionSourceCode.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+//------------------------------------------------------------------
+/// Constructor
+///
+/// @param[in] text
+/// The text of the function. Must be a full translation unit.
+///
+/// @param[in] name
+/// The name of the function, as used in the text.
+//------------------------------------------------------------------
+ClangUtilityFunction::ClangUtilityFunction (const char *text,
+ const char *name) :
+ ClangExpression (),
+ m_function_text (ExpressionSourceCode::g_expression_prefix),
+ m_function_name (name)
+{
+ if (text && text[0])
+ m_function_text.append (text);
+}
+
+ClangUtilityFunction::~ClangUtilityFunction ()
+{
+}
+
+//------------------------------------------------------------------
+/// Install the utility function into a process
+///
+/// @param[in] error_stream
+/// A stream to print parse errors and warnings to.
+///
+/// @param[in] exe_ctx
+/// The execution context to install the utility function to.
+///
+/// @return
+/// True on success (no errors); false otherwise.
+//------------------------------------------------------------------
+bool
+ClangUtilityFunction::Install (Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ {
+ error_stream.PutCString("error: already installed\n");
+ return false;
+ }
+
+ ////////////////////////////////////
+ // Set up the target and compiler
+ //
+
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ {
+ error_stream.PutCString ("error: invalid target\n");
+ return false;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (!process)
+ {
+ error_stream.PutCString ("error: invalid process\n");
+ return false;
+ }
+
+ //////////////////////////
+ // Parse the expression
+ //
+
+ bool keep_result_in_memory = false;
+
+ m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory, exe_ctx));
+
+ if (!m_expr_decl_map->WillParse(exe_ctx, NULL))
+ {
+ error_stream.PutCString ("error: current process state is unsuitable for expression parsing\n");
+ return false;
+ }
+
+ ClangExpressionParser parser(exe_ctx.GetBestExecutionContextScope(), *this);
+
+ unsigned num_errors = parser.Parse (error_stream);
+
+ if (num_errors)
+ {
+ error_stream.Printf ("error: %d errors parsing expression\n", num_errors);
+
+ m_expr_decl_map.reset();
+
+ return false;
+ }
+
+ //////////////////////////////////
+ // JIT the output of the parser
+ //
+
+ bool can_interpret = false; // should stay that way
+
+ Error jit_error = parser.PrepareForExecution (m_jit_start_addr,
+ m_jit_end_addr,
+ m_execution_unit_ap,
+ exe_ctx,
+ can_interpret,
+ eExecutionPolicyAlways);
+
+ if (m_jit_start_addr != LLDB_INVALID_ADDRESS)
+ m_jit_process_wp = lldb::ProcessWP(process->shared_from_this());
+
+#if 0
+ // jingham: look here
+ StreamFile logfile ("/tmp/exprs.txt", "a");
+ logfile.Printf ("0x%16.16" PRIx64 ": func = %s, source =\n%s\n",
+ m_jit_start_addr,
+ m_function_name.c_str(),
+ m_function_text.c_str());
+#endif
+
+ m_expr_decl_map->DidParse();
+
+ m_expr_decl_map.reset();
+
+ if (jit_error.Success())
+ {
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = jit_error.AsCString();
+ if (error_cstr && error_cstr[0])
+ error_stream.Printf ("error: %s\n", error_cstr);
+ else
+ error_stream.Printf ("error: expression can't be interpreted or run\n");
+ return false;
+ }
+}
+
+
diff --git a/source/Expression/DWARFExpression.cpp b/source/Expression/DWARFExpression.cpp
new file mode 100644
index 000000000000..e2ae19e5ac7f
--- /dev/null
+++ b/source/Expression/DWARFExpression.cpp
@@ -0,0 +1,2691 @@
+//===-- DWARFExpression.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/Expression/DWARFExpression.h"
+
+#include <vector>
+
+#include "lldb/Core/DataEncoder.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/VMRange.h"
+
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StackID.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+DW_OP_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ switch (val) {
+ case 0x03: return "DW_OP_addr";
+ case 0x06: return "DW_OP_deref";
+ case 0x08: return "DW_OP_const1u";
+ case 0x09: return "DW_OP_const1s";
+ case 0x0a: return "DW_OP_const2u";
+ case 0x0b: return "DW_OP_const2s";
+ case 0x0c: return "DW_OP_const4u";
+ case 0x0d: return "DW_OP_const4s";
+ case 0x0e: return "DW_OP_const8u";
+ case 0x0f: return "DW_OP_const8s";
+ case 0x10: return "DW_OP_constu";
+ case 0x11: return "DW_OP_consts";
+ case 0x12: return "DW_OP_dup";
+ case 0x13: return "DW_OP_drop";
+ case 0x14: return "DW_OP_over";
+ case 0x15: return "DW_OP_pick";
+ case 0x16: return "DW_OP_swap";
+ case 0x17: return "DW_OP_rot";
+ case 0x18: return "DW_OP_xderef";
+ case 0x19: return "DW_OP_abs";
+ case 0x1a: return "DW_OP_and";
+ case 0x1b: return "DW_OP_div";
+ case 0x1c: return "DW_OP_minus";
+ case 0x1d: return "DW_OP_mod";
+ case 0x1e: return "DW_OP_mul";
+ case 0x1f: return "DW_OP_neg";
+ case 0x20: return "DW_OP_not";
+ case 0x21: return "DW_OP_or";
+ case 0x22: return "DW_OP_plus";
+ case 0x23: return "DW_OP_plus_uconst";
+ case 0x24: return "DW_OP_shl";
+ case 0x25: return "DW_OP_shr";
+ case 0x26: return "DW_OP_shra";
+ case 0x27: return "DW_OP_xor";
+ case 0x2f: return "DW_OP_skip";
+ case 0x28: return "DW_OP_bra";
+ case 0x29: return "DW_OP_eq";
+ case 0x2a: return "DW_OP_ge";
+ case 0x2b: return "DW_OP_gt";
+ case 0x2c: return "DW_OP_le";
+ case 0x2d: return "DW_OP_lt";
+ case 0x2e: return "DW_OP_ne";
+ case 0x30: return "DW_OP_lit0";
+ case 0x31: return "DW_OP_lit1";
+ case 0x32: return "DW_OP_lit2";
+ case 0x33: return "DW_OP_lit3";
+ case 0x34: return "DW_OP_lit4";
+ case 0x35: return "DW_OP_lit5";
+ case 0x36: return "DW_OP_lit6";
+ case 0x37: return "DW_OP_lit7";
+ case 0x38: return "DW_OP_lit8";
+ case 0x39: return "DW_OP_lit9";
+ case 0x3a: return "DW_OP_lit10";
+ case 0x3b: return "DW_OP_lit11";
+ case 0x3c: return "DW_OP_lit12";
+ case 0x3d: return "DW_OP_lit13";
+ case 0x3e: return "DW_OP_lit14";
+ case 0x3f: return "DW_OP_lit15";
+ case 0x40: return "DW_OP_lit16";
+ case 0x41: return "DW_OP_lit17";
+ case 0x42: return "DW_OP_lit18";
+ case 0x43: return "DW_OP_lit19";
+ case 0x44: return "DW_OP_lit20";
+ case 0x45: return "DW_OP_lit21";
+ case 0x46: return "DW_OP_lit22";
+ case 0x47: return "DW_OP_lit23";
+ case 0x48: return "DW_OP_lit24";
+ case 0x49: return "DW_OP_lit25";
+ case 0x4a: return "DW_OP_lit26";
+ case 0x4b: return "DW_OP_lit27";
+ case 0x4c: return "DW_OP_lit28";
+ case 0x4d: return "DW_OP_lit29";
+ case 0x4e: return "DW_OP_lit30";
+ case 0x4f: return "DW_OP_lit31";
+ case 0x50: return "DW_OP_reg0";
+ case 0x51: return "DW_OP_reg1";
+ case 0x52: return "DW_OP_reg2";
+ case 0x53: return "DW_OP_reg3";
+ case 0x54: return "DW_OP_reg4";
+ case 0x55: return "DW_OP_reg5";
+ case 0x56: return "DW_OP_reg6";
+ case 0x57: return "DW_OP_reg7";
+ case 0x58: return "DW_OP_reg8";
+ case 0x59: return "DW_OP_reg9";
+ case 0x5a: return "DW_OP_reg10";
+ case 0x5b: return "DW_OP_reg11";
+ case 0x5c: return "DW_OP_reg12";
+ case 0x5d: return "DW_OP_reg13";
+ case 0x5e: return "DW_OP_reg14";
+ case 0x5f: return "DW_OP_reg15";
+ case 0x60: return "DW_OP_reg16";
+ case 0x61: return "DW_OP_reg17";
+ case 0x62: return "DW_OP_reg18";
+ case 0x63: return "DW_OP_reg19";
+ case 0x64: return "DW_OP_reg20";
+ case 0x65: return "DW_OP_reg21";
+ case 0x66: return "DW_OP_reg22";
+ case 0x67: return "DW_OP_reg23";
+ case 0x68: return "DW_OP_reg24";
+ case 0x69: return "DW_OP_reg25";
+ case 0x6a: return "DW_OP_reg26";
+ case 0x6b: return "DW_OP_reg27";
+ case 0x6c: return "DW_OP_reg28";
+ case 0x6d: return "DW_OP_reg29";
+ case 0x6e: return "DW_OP_reg30";
+ case 0x6f: return "DW_OP_reg31";
+ case 0x70: return "DW_OP_breg0";
+ case 0x71: return "DW_OP_breg1";
+ case 0x72: return "DW_OP_breg2";
+ case 0x73: return "DW_OP_breg3";
+ case 0x74: return "DW_OP_breg4";
+ case 0x75: return "DW_OP_breg5";
+ case 0x76: return "DW_OP_breg6";
+ case 0x77: return "DW_OP_breg7";
+ case 0x78: return "DW_OP_breg8";
+ case 0x79: return "DW_OP_breg9";
+ case 0x7a: return "DW_OP_breg10";
+ case 0x7b: return "DW_OP_breg11";
+ case 0x7c: return "DW_OP_breg12";
+ case 0x7d: return "DW_OP_breg13";
+ case 0x7e: return "DW_OP_breg14";
+ case 0x7f: return "DW_OP_breg15";
+ case 0x80: return "DW_OP_breg16";
+ case 0x81: return "DW_OP_breg17";
+ case 0x82: return "DW_OP_breg18";
+ case 0x83: return "DW_OP_breg19";
+ case 0x84: return "DW_OP_breg20";
+ case 0x85: return "DW_OP_breg21";
+ case 0x86: return "DW_OP_breg22";
+ case 0x87: return "DW_OP_breg23";
+ case 0x88: return "DW_OP_breg24";
+ case 0x89: return "DW_OP_breg25";
+ case 0x8a: return "DW_OP_breg26";
+ case 0x8b: return "DW_OP_breg27";
+ case 0x8c: return "DW_OP_breg28";
+ case 0x8d: return "DW_OP_breg29";
+ case 0x8e: return "DW_OP_breg30";
+ case 0x8f: return "DW_OP_breg31";
+ case 0x90: return "DW_OP_regx";
+ case 0x91: return "DW_OP_fbreg";
+ case 0x92: return "DW_OP_bregx";
+ case 0x93: return "DW_OP_piece";
+ case 0x94: return "DW_OP_deref_size";
+ case 0x95: return "DW_OP_xderef_size";
+ case 0x96: return "DW_OP_nop";
+ case 0x97: return "DW_OP_push_object_address";
+ case 0x98: return "DW_OP_call2";
+ case 0x99: return "DW_OP_call4";
+ case 0x9a: return "DW_OP_call_ref";
+// case DW_OP_APPLE_array_ref: return "DW_OP_APPLE_array_ref";
+// case DW_OP_APPLE_extern: return "DW_OP_APPLE_extern";
+ case DW_OP_APPLE_uninit: return "DW_OP_APPLE_uninit";
+// case DW_OP_APPLE_assign: return "DW_OP_APPLE_assign";
+// case DW_OP_APPLE_address_of: return "DW_OP_APPLE_address_of";
+// case DW_OP_APPLE_value_of: return "DW_OP_APPLE_value_of";
+// case DW_OP_APPLE_deref_type: return "DW_OP_APPLE_deref_type";
+// case DW_OP_APPLE_expr_local: return "DW_OP_APPLE_expr_local";
+// case DW_OP_APPLE_constf: return "DW_OP_APPLE_constf";
+// case DW_OP_APPLE_scalar_cast: return "DW_OP_APPLE_scalar_cast";
+// case DW_OP_APPLE_clang_cast: return "DW_OP_APPLE_clang_cast";
+// case DW_OP_APPLE_clear: return "DW_OP_APPLE_clear";
+// case DW_OP_APPLE_error: return "DW_OP_APPLE_error";
+ default:
+ snprintf (invalid, sizeof(invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFExpression constructor
+//----------------------------------------------------------------------
+DWARFExpression::DWARFExpression() :
+ m_data(),
+ m_reg_kind (eRegisterKindDWARF),
+ m_loclist_slide (LLDB_INVALID_ADDRESS)
+{
+}
+
+DWARFExpression::DWARFExpression(const DWARFExpression& rhs) :
+ m_data(rhs.m_data),
+ m_reg_kind (rhs.m_reg_kind),
+ m_loclist_slide(rhs.m_loclist_slide)
+{
+}
+
+
+DWARFExpression::DWARFExpression(const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length) :
+ m_data(data, data_offset, data_length),
+ m_reg_kind (eRegisterKindDWARF),
+ m_loclist_slide(LLDB_INVALID_ADDRESS)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DWARFExpression::~DWARFExpression()
+{
+}
+
+
+bool
+DWARFExpression::IsValid() const
+{
+ return m_data.GetByteSize() > 0;
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data)
+{
+ m_data = data;
+}
+
+void
+DWARFExpression::CopyOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
+{
+ const uint8_t *bytes = data.PeekData(data_offset, data_length);
+ if (bytes)
+ {
+ m_data.SetData(DataBufferSP(new DataBufferHeap(bytes, data_length)));
+ m_data.SetByteOrder(data.GetByteOrder());
+ m_data.SetAddressByteSize(data.GetAddressByteSize());
+ }
+}
+
+void
+DWARFExpression::SetOpcodeData (const DataExtractor& data, lldb::offset_t data_offset, lldb::offset_t data_length)
+{
+ m_data.SetData(data, data_offset, data_length);
+}
+
+void
+DWARFExpression::DumpLocation (Stream *s, lldb::offset_t offset, lldb::offset_t length, lldb::DescriptionLevel level, ABI *abi) const
+{
+ if (!m_data.ValidOffsetForDataOfSize(offset, length))
+ return;
+ const lldb::offset_t start_offset = offset;
+ const lldb::offset_t end_offset = offset + length;
+ while (m_data.ValidOffset(offset) && offset < end_offset)
+ {
+ const lldb::offset_t op_offset = offset;
+ const uint8_t op = m_data.GetU8(&offset);
+
+ switch (level)
+ {
+ default:
+ break;
+
+ case lldb::eDescriptionLevelBrief:
+ if (offset > start_offset)
+ s->PutChar(' ');
+ break;
+
+ case lldb::eDescriptionLevelFull:
+ case lldb::eDescriptionLevelVerbose:
+ if (offset > start_offset)
+ s->EOL();
+ s->Indent();
+ if (level == lldb::eDescriptionLevelFull)
+ break;
+ // Fall through for verbose and print offset and DW_OP prefix..
+ s->Printf("0x%8.8" PRIx64 ": %s", op_offset, op >= DW_OP_APPLE_uninit ? "DW_OP_APPLE_" : "DW_OP_");
+ break;
+ }
+
+ switch (op)
+ {
+ case DW_OP_addr: *s << "DW_OP_addr(" << m_data.GetAddress(&offset) << ") "; break; // 0x03 1 address
+ case DW_OP_deref: *s << "DW_OP_deref"; break; // 0x06
+ case DW_OP_const1u: s->Printf("DW_OP_const1u(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x08 1 1-byte constant
+ case DW_OP_const1s: s->Printf("DW_OP_const1s(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x09 1 1-byte constant
+ case DW_OP_const2u: s->Printf("DW_OP_const2u(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0a 1 2-byte constant
+ case DW_OP_const2s: s->Printf("DW_OP_const2s(0x%4.4x) ", m_data.GetU16(&offset)); break; // 0x0b 1 2-byte constant
+ case DW_OP_const4u: s->Printf("DW_OP_const4u(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0c 1 4-byte constant
+ case DW_OP_const4s: s->Printf("DW_OP_const4s(0x%8.8x) ", m_data.GetU32(&offset)); break; // 0x0d 1 4-byte constant
+ case DW_OP_const8u: s->Printf("DW_OP_const8u(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; // 0x0e 1 8-byte constant
+ case DW_OP_const8s: s->Printf("DW_OP_const8s(0x%16.16" PRIx64 ") ", m_data.GetU64(&offset)); break; // 0x0f 1 8-byte constant
+ case DW_OP_constu: s->Printf("DW_OP_constu(0x%" PRIx64 ") ", m_data.GetULEB128(&offset)); break; // 0x10 1 ULEB128 constant
+ case DW_OP_consts: s->Printf("DW_OP_consts(0x%" PRId64 ") ", m_data.GetSLEB128(&offset)); break; // 0x11 1 SLEB128 constant
+ case DW_OP_dup: s->PutCString("DW_OP_dup"); break; // 0x12
+ case DW_OP_drop: s->PutCString("DW_OP_drop"); break; // 0x13
+ case DW_OP_over: s->PutCString("DW_OP_over"); break; // 0x14
+ case DW_OP_pick: s->Printf("DW_OP_pick(0x%2.2x) ", m_data.GetU8(&offset)); break; // 0x15 1 1-byte stack index
+ case DW_OP_swap: s->PutCString("DW_OP_swap"); break; // 0x16
+ case DW_OP_rot: s->PutCString("DW_OP_rot"); break; // 0x17
+ case DW_OP_xderef: s->PutCString("DW_OP_xderef"); break; // 0x18
+ case DW_OP_abs: s->PutCString("DW_OP_abs"); break; // 0x19
+ case DW_OP_and: s->PutCString("DW_OP_and"); break; // 0x1a
+ case DW_OP_div: s->PutCString("DW_OP_div"); break; // 0x1b
+ case DW_OP_minus: s->PutCString("DW_OP_minus"); break; // 0x1c
+ case DW_OP_mod: s->PutCString("DW_OP_mod"); break; // 0x1d
+ case DW_OP_mul: s->PutCString("DW_OP_mul"); break; // 0x1e
+ case DW_OP_neg: s->PutCString("DW_OP_neg"); break; // 0x1f
+ case DW_OP_not: s->PutCString("DW_OP_not"); break; // 0x20
+ case DW_OP_or: s->PutCString("DW_OP_or"); break; // 0x21
+ case DW_OP_plus: s->PutCString("DW_OP_plus"); break; // 0x22
+ case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
+ s->Printf("DW_OP_plus_uconst(0x%" PRIx64 ") ", m_data.GetULEB128(&offset));
+ break;
+
+ case DW_OP_shl: s->PutCString("DW_OP_shl"); break; // 0x24
+ case DW_OP_shr: s->PutCString("DW_OP_shr"); break; // 0x25
+ case DW_OP_shra: s->PutCString("DW_OP_shra"); break; // 0x26
+ case DW_OP_xor: s->PutCString("DW_OP_xor"); break; // 0x27
+ case DW_OP_skip: s->Printf("DW_OP_skip(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x2f 1 signed 2-byte constant
+ case DW_OP_bra: s->Printf("DW_OP_bra(0x%4.4x)", m_data.GetU16(&offset)); break; // 0x28 1 signed 2-byte constant
+ case DW_OP_eq: s->PutCString("DW_OP_eq"); break; // 0x29
+ case DW_OP_ge: s->PutCString("DW_OP_ge"); break; // 0x2a
+ case DW_OP_gt: s->PutCString("DW_OP_gt"); break; // 0x2b
+ case DW_OP_le: s->PutCString("DW_OP_le"); break; // 0x2c
+ case DW_OP_lt: s->PutCString("DW_OP_lt"); break; // 0x2d
+ case DW_OP_ne: s->PutCString("DW_OP_ne"); break; // 0x2e
+
+ case DW_OP_lit0: // 0x30
+ case DW_OP_lit1: // 0x31
+ case DW_OP_lit2: // 0x32
+ case DW_OP_lit3: // 0x33
+ case DW_OP_lit4: // 0x34
+ case DW_OP_lit5: // 0x35
+ case DW_OP_lit6: // 0x36
+ case DW_OP_lit7: // 0x37
+ case DW_OP_lit8: // 0x38
+ case DW_OP_lit9: // 0x39
+ case DW_OP_lit10: // 0x3A
+ case DW_OP_lit11: // 0x3B
+ case DW_OP_lit12: // 0x3C
+ case DW_OP_lit13: // 0x3D
+ case DW_OP_lit14: // 0x3E
+ case DW_OP_lit15: // 0x3F
+ case DW_OP_lit16: // 0x40
+ case DW_OP_lit17: // 0x41
+ case DW_OP_lit18: // 0x42
+ case DW_OP_lit19: // 0x43
+ case DW_OP_lit20: // 0x44
+ case DW_OP_lit21: // 0x45
+ case DW_OP_lit22: // 0x46
+ case DW_OP_lit23: // 0x47
+ case DW_OP_lit24: // 0x48
+ case DW_OP_lit25: // 0x49
+ case DW_OP_lit26: // 0x4A
+ case DW_OP_lit27: // 0x4B
+ case DW_OP_lit28: // 0x4C
+ case DW_OP_lit29: // 0x4D
+ case DW_OP_lit30: // 0x4E
+ case DW_OP_lit31: s->Printf("DW_OP_lit%i", op - DW_OP_lit0); break; // 0x4f
+
+ case DW_OP_reg0: // 0x50
+ case DW_OP_reg1: // 0x51
+ case DW_OP_reg2: // 0x52
+ case DW_OP_reg3: // 0x53
+ case DW_OP_reg4: // 0x54
+ case DW_OP_reg5: // 0x55
+ case DW_OP_reg6: // 0x56
+ case DW_OP_reg7: // 0x57
+ case DW_OP_reg8: // 0x58
+ case DW_OP_reg9: // 0x59
+ case DW_OP_reg10: // 0x5A
+ case DW_OP_reg11: // 0x5B
+ case DW_OP_reg12: // 0x5C
+ case DW_OP_reg13: // 0x5D
+ case DW_OP_reg14: // 0x5E
+ case DW_OP_reg15: // 0x5F
+ case DW_OP_reg16: // 0x60
+ case DW_OP_reg17: // 0x61
+ case DW_OP_reg18: // 0x62
+ case DW_OP_reg19: // 0x63
+ case DW_OP_reg20: // 0x64
+ case DW_OP_reg21: // 0x65
+ case DW_OP_reg22: // 0x66
+ case DW_OP_reg23: // 0x67
+ case DW_OP_reg24: // 0x68
+ case DW_OP_reg25: // 0x69
+ case DW_OP_reg26: // 0x6A
+ case DW_OP_reg27: // 0x6B
+ case DW_OP_reg28: // 0x6C
+ case DW_OP_reg29: // 0x6D
+ case DW_OP_reg30: // 0x6E
+ case DW_OP_reg31: // 0x6F
+ {
+ uint32_t reg_num = op - DW_OP_reg0;
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->PutCString (reg_info.name);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->PutCString (reg_info.alt_name);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_reg%u", reg_num); break;
+ }
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ {
+ uint32_t reg_num = op - DW_OP_breg0;
+ int64_t reg_offset = m_data.GetSLEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_breg%i(0x%" PRIx64 ")", reg_num, reg_offset);
+ }
+ break;
+
+ case DW_OP_regx: // 0x90 1 ULEB128 register
+ {
+ uint32_t reg_num = m_data.GetULEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->PutCString (reg_info.name);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->PutCString (reg_info.alt_name);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_regx(%" PRIu32 ")", reg_num); break;
+ }
+ break;
+ case DW_OP_fbreg: // 0x91 1 SLEB128 offset
+ s->Printf("DW_OP_fbreg(%" PRIi64 ")",m_data.GetSLEB128(&offset));
+ break;
+ case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
+ {
+ uint32_t reg_num = m_data.GetULEB128(&offset);
+ int64_t reg_offset = m_data.GetSLEB128(&offset);
+ if (abi)
+ {
+ RegisterInfo reg_info;
+ if (abi->GetRegisterInfoByKind(m_reg_kind, reg_num, reg_info))
+ {
+ if (reg_info.name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.name, reg_offset);
+ break;
+ }
+ else if (reg_info.alt_name)
+ {
+ s->Printf("[%s%+" PRIi64 "]", reg_info.alt_name, reg_offset);
+ break;
+ }
+ }
+ }
+ s->Printf("DW_OP_bregx(reg=%" PRIu32 ",offset=%" PRIi64 ")", reg_num, reg_offset);
+ }
+ break;
+ case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
+ s->Printf("DW_OP_piece(0x%" PRIx64 ")", m_data.GetULEB128(&offset));
+ break;
+ case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
+ s->Printf("DW_OP_deref_size(0x%2.2x)", m_data.GetU8(&offset));
+ break;
+ case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
+ s->Printf("DW_OP_xderef_size(0x%2.2x)", m_data.GetU8(&offset));
+ break;
+ case DW_OP_nop: s->PutCString("DW_OP_nop"); break; // 0x96
+ case DW_OP_push_object_address: s->PutCString("DW_OP_push_object_address"); break; // 0x97 DWARF3
+ case DW_OP_call2: // 0x98 DWARF3 1 2-byte offset of DIE
+ s->Printf("DW_OP_call2(0x%4.4x)", m_data.GetU16(&offset));
+ break;
+ case DW_OP_call4: // 0x99 DWARF3 1 4-byte offset of DIE
+ s->Printf("DW_OP_call4(0x%8.8x)", m_data.GetU32(&offset));
+ break;
+ case DW_OP_call_ref: // 0x9a DWARF3 1 4- or 8-byte offset of DIE
+ s->Printf("DW_OP_call_ref(0x%8.8" PRIx64 ")", m_data.GetAddress(&offset));
+ break;
+// case DW_OP_form_tls_address: s << "form_tls_address"; break; // 0x9b DWARF3
+// case DW_OP_call_frame_cfa: s << "call_frame_cfa"; break; // 0x9c DWARF3
+// case DW_OP_bit_piece: // 0x9d DWARF3 2
+// s->Printf("DW_OP_bit_piece(0x%x, 0x%x)", m_data.GetULEB128(&offset), m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_lo_user: s->PutCString("DW_OP_lo_user"); break; // 0xe0
+// case DW_OP_hi_user: s->PutCString("DW_OP_hi_user"); break; // 0xff
+// case DW_OP_APPLE_extern:
+// s->Printf("DW_OP_APPLE_extern(%" PRIu64 ")", m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_APPLE_array_ref:
+// s->PutCString("DW_OP_APPLE_array_ref");
+// break;
+ case DW_OP_APPLE_uninit:
+ s->PutCString("DW_OP_APPLE_uninit"); // 0xF0
+ break;
+// case DW_OP_APPLE_assign: // 0xF1 - pops value off and assigns it to second item on stack (2nd item must have assignable context)
+// s->PutCString("DW_OP_APPLE_assign");
+// break;
+// case DW_OP_APPLE_address_of: // 0xF2 - gets the address of the top stack item (top item must be a variable, or have value_type that is an address already)
+// s->PutCString("DW_OP_APPLE_address_of");
+// break;
+// case DW_OP_APPLE_value_of: // 0xF3 - pops the value off the stack and pushes the value of that object (top item must be a variable, or expression local)
+// s->PutCString("DW_OP_APPLE_value_of");
+// break;
+// case DW_OP_APPLE_deref_type: // 0xF4 - gets the address of the top stack item (top item must be a variable, or a clang type)
+// s->PutCString("DW_OP_APPLE_deref_type");
+// break;
+// case DW_OP_APPLE_expr_local: // 0xF5 - ULEB128 expression local index
+// s->Printf("DW_OP_APPLE_expr_local(%" PRIu64 ")", m_data.GetULEB128(&offset));
+// break;
+// case DW_OP_APPLE_constf: // 0xF6 - 1 byte float size, followed by constant float data
+// {
+// uint8_t float_length = m_data.GetU8(&offset);
+// s->Printf("DW_OP_APPLE_constf(<%u> ", float_length);
+// m_data.Dump(s, offset, eFormatHex, float_length, 1, UINT32_MAX, DW_INVALID_ADDRESS, 0, 0);
+// s->PutChar(')');
+// // Consume the float data
+// m_data.GetData(&offset, float_length);
+// }
+// break;
+// case DW_OP_APPLE_scalar_cast:
+// s->Printf("DW_OP_APPLE_scalar_cast(%s)", Scalar::GetValueTypeAsCString ((Scalar::Type)m_data.GetU8(&offset)));
+// break;
+// case DW_OP_APPLE_clang_cast:
+// {
+// clang::Type *clang_type = (clang::Type *)m_data.GetMaxU64(&offset, sizeof(void*));
+// s->Printf("DW_OP_APPLE_clang_cast(%p)", clang_type);
+// }
+// break;
+// case DW_OP_APPLE_clear:
+// s->PutCString("DW_OP_APPLE_clear");
+// break;
+// case DW_OP_APPLE_error: // 0xFF - Stops expression evaluation and returns an error (no args)
+// s->PutCString("DW_OP_APPLE_error");
+// break;
+ }
+ }
+}
+
+void
+DWARFExpression::SetLocationListSlide (addr_t slide)
+{
+ m_loclist_slide = slide;
+}
+
+int
+DWARFExpression::GetRegisterKind ()
+{
+ return m_reg_kind;
+}
+
+void
+DWARFExpression::SetRegisterKind (RegisterKind reg_kind)
+{
+ m_reg_kind = reg_kind;
+}
+
+bool
+DWARFExpression::IsLocationList() const
+{
+ return m_loclist_slide != LLDB_INVALID_ADDRESS;
+}
+
+void
+DWARFExpression::GetDescription (Stream *s, lldb::DescriptionLevel level, addr_t location_list_base_addr, ABI *abi) const
+{
+ if (IsLocationList())
+ {
+ // We have a location list
+ lldb::offset_t offset = 0;
+ uint32_t count = 0;
+ addr_t curr_base_addr = location_list_base_addr;
+ while (m_data.ValidOffset(offset))
+ {
+ lldb::addr_t begin_addr_offset = m_data.GetAddress(&offset);
+ lldb::addr_t end_addr_offset = m_data.GetAddress(&offset);
+ if (begin_addr_offset < end_addr_offset)
+ {
+ if (count > 0)
+ s->PutCString(", ");
+ VMRange addr_range(curr_base_addr + begin_addr_offset, curr_base_addr + end_addr_offset);
+ addr_range.Dump(s, 0, 8);
+ s->PutChar('{');
+ lldb::offset_t location_length = m_data.GetU16(&offset);
+ DumpLocation (s, offset, location_length, level, abi);
+ s->PutChar('}');
+ offset += location_length;
+ }
+ else if (begin_addr_offset == 0 && end_addr_offset == 0)
+ {
+ // The end of the location list is marked by both the start and end offset being zero
+ break;
+ }
+ else
+ {
+ if ((m_data.GetAddressByteSize() == 4 && (begin_addr_offset == UINT32_MAX)) ||
+ (m_data.GetAddressByteSize() == 8 && (begin_addr_offset == UINT64_MAX)))
+ {
+ curr_base_addr = end_addr_offset + location_list_base_addr;
+ // We have a new base address
+ if (count > 0)
+ s->PutCString(", ");
+ *s << "base_addr = " << end_addr_offset;
+ }
+ }
+
+ count++;
+ }
+ }
+ else
+ {
+ // We have a normal location that contains DW_OP location opcodes
+ DumpLocation (s, 0, m_data.GetByteSize(), level, abi);
+ }
+}
+
+static bool
+ReadRegisterValueAsScalar
+(
+ RegisterContext *reg_ctx,
+ uint32_t reg_kind,
+ uint32_t reg_num,
+ Error *error_ptr,
+ Value &value
+)
+{
+ if (reg_ctx == NULL)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("No register context in frame.\n");
+ }
+ else
+ {
+ uint32_t native_reg = reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
+ if (native_reg == LLDB_INVALID_REGNUM)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Unable to convert register kind=%u reg_num=%u to a native register number.\n", reg_kind, reg_num);
+ }
+ else
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(native_reg);
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ if (reg_value.GetScalarValue(value.GetScalar()))
+ {
+ value.SetValueType (Value::eValueTypeScalar);
+ value.SetContext (Value::eContextTypeRegisterInfo,
+ const_cast<RegisterInfo *>(reg_info));
+ if (error_ptr)
+ error_ptr->Clear();
+ return true;
+ }
+ else
+ {
+ // If we get this error, then we need to implement a value
+ // buffer in the dwarf expression evaluation function...
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("register %s can't be converted to a scalar value",
+ reg_info->name);
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("register %s is not available", reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+//bool
+//DWARFExpression::LocationListContainsLoadAddress (Process* process, const Address &addr) const
+//{
+// return LocationListContainsLoadAddress(process, addr.GetLoadAddress(process));
+//}
+//
+//bool
+//DWARFExpression::LocationListContainsLoadAddress (Process* process, addr_t load_addr) const
+//{
+// if (load_addr == LLDB_INVALID_ADDRESS)
+// return false;
+//
+// if (IsLocationList())
+// {
+// lldb::offset_t offset = 0;
+//
+// addr_t loc_list_base_addr = m_loclist_slide.GetLoadAddress(process);
+//
+// if (loc_list_base_addr == LLDB_INVALID_ADDRESS)
+// return false;
+//
+// while (m_data.ValidOffset(offset))
+// {
+// // We need to figure out what the value is for the location.
+// addr_t lo_pc = m_data.GetAddress(&offset);
+// addr_t hi_pc = m_data.GetAddress(&offset);
+// if (lo_pc == 0 && hi_pc == 0)
+// break;
+// else
+// {
+// lo_pc += loc_list_base_addr;
+// hi_pc += loc_list_base_addr;
+//
+// if (lo_pc <= load_addr && load_addr < hi_pc)
+// return true;
+//
+// offset += m_data.GetU16(&offset);
+// }
+// }
+// }
+// return false;
+//}
+
+static offset_t
+GetOpcodeDataSize (const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op)
+{
+ lldb::offset_t offset = data_offset;
+ switch (op)
+ {
+ case DW_OP_addr:
+ case DW_OP_call_ref: // 0x9a 1 address sized offset of DIE (DWARF3)
+ return data.GetAddressByteSize();
+
+ // Opcodes with no arguments
+ case DW_OP_deref: // 0x06
+ case DW_OP_dup: // 0x12
+ case DW_OP_drop: // 0x13
+ case DW_OP_over: // 0x14
+ case DW_OP_swap: // 0x16
+ case DW_OP_rot: // 0x17
+ case DW_OP_xderef: // 0x18
+ case DW_OP_abs: // 0x19
+ case DW_OP_and: // 0x1a
+ case DW_OP_div: // 0x1b
+ case DW_OP_minus: // 0x1c
+ case DW_OP_mod: // 0x1d
+ case DW_OP_mul: // 0x1e
+ case DW_OP_neg: // 0x1f
+ case DW_OP_not: // 0x20
+ case DW_OP_or: // 0x21
+ case DW_OP_plus: // 0x22
+ case DW_OP_shl: // 0x24
+ case DW_OP_shr: // 0x25
+ case DW_OP_shra: // 0x26
+ case DW_OP_xor: // 0x27
+ case DW_OP_eq: // 0x29
+ case DW_OP_ge: // 0x2a
+ case DW_OP_gt: // 0x2b
+ case DW_OP_le: // 0x2c
+ case DW_OP_lt: // 0x2d
+ case DW_OP_ne: // 0x2e
+ case DW_OP_lit0: // 0x30
+ case DW_OP_lit1: // 0x31
+ case DW_OP_lit2: // 0x32
+ case DW_OP_lit3: // 0x33
+ case DW_OP_lit4: // 0x34
+ case DW_OP_lit5: // 0x35
+ case DW_OP_lit6: // 0x36
+ case DW_OP_lit7: // 0x37
+ case DW_OP_lit8: // 0x38
+ case DW_OP_lit9: // 0x39
+ case DW_OP_lit10: // 0x3A
+ case DW_OP_lit11: // 0x3B
+ case DW_OP_lit12: // 0x3C
+ case DW_OP_lit13: // 0x3D
+ case DW_OP_lit14: // 0x3E
+ case DW_OP_lit15: // 0x3F
+ case DW_OP_lit16: // 0x40
+ case DW_OP_lit17: // 0x41
+ case DW_OP_lit18: // 0x42
+ case DW_OP_lit19: // 0x43
+ case DW_OP_lit20: // 0x44
+ case DW_OP_lit21: // 0x45
+ case DW_OP_lit22: // 0x46
+ case DW_OP_lit23: // 0x47
+ case DW_OP_lit24: // 0x48
+ case DW_OP_lit25: // 0x49
+ case DW_OP_lit26: // 0x4A
+ case DW_OP_lit27: // 0x4B
+ case DW_OP_lit28: // 0x4C
+ case DW_OP_lit29: // 0x4D
+ case DW_OP_lit30: // 0x4E
+ case DW_OP_lit31: // 0x4f
+ case DW_OP_reg0: // 0x50
+ case DW_OP_reg1: // 0x51
+ case DW_OP_reg2: // 0x52
+ case DW_OP_reg3: // 0x53
+ case DW_OP_reg4: // 0x54
+ case DW_OP_reg5: // 0x55
+ case DW_OP_reg6: // 0x56
+ case DW_OP_reg7: // 0x57
+ case DW_OP_reg8: // 0x58
+ case DW_OP_reg9: // 0x59
+ case DW_OP_reg10: // 0x5A
+ case DW_OP_reg11: // 0x5B
+ case DW_OP_reg12: // 0x5C
+ case DW_OP_reg13: // 0x5D
+ case DW_OP_reg14: // 0x5E
+ case DW_OP_reg15: // 0x5F
+ case DW_OP_reg16: // 0x60
+ case DW_OP_reg17: // 0x61
+ case DW_OP_reg18: // 0x62
+ case DW_OP_reg19: // 0x63
+ case DW_OP_reg20: // 0x64
+ case DW_OP_reg21: // 0x65
+ case DW_OP_reg22: // 0x66
+ case DW_OP_reg23: // 0x67
+ case DW_OP_reg24: // 0x68
+ case DW_OP_reg25: // 0x69
+ case DW_OP_reg26: // 0x6A
+ case DW_OP_reg27: // 0x6B
+ case DW_OP_reg28: // 0x6C
+ case DW_OP_reg29: // 0x6D
+ case DW_OP_reg30: // 0x6E
+ case DW_OP_reg31: // 0x6F
+ case DW_OP_nop: // 0x96
+ case DW_OP_push_object_address: // 0x97 DWARF3
+ case DW_OP_form_tls_address: // 0x9b DWARF3
+ case DW_OP_call_frame_cfa: // 0x9c DWARF3
+ case DW_OP_stack_value: // 0x9f DWARF4
+ return 0;
+
+ // Opcodes with a single 1 byte arguments
+ case DW_OP_const1u: // 0x08 1 1-byte constant
+ case DW_OP_const1s: // 0x09 1 1-byte constant
+ case DW_OP_pick: // 0x15 1 1-byte stack index
+ case DW_OP_deref_size: // 0x94 1 1-byte size of data retrieved
+ case DW_OP_xderef_size: // 0x95 1 1-byte size of data retrieved
+ return 1;
+
+ // Opcodes with a single 2 byte arguments
+ case DW_OP_const2u: // 0x0a 1 2-byte constant
+ case DW_OP_const2s: // 0x0b 1 2-byte constant
+ case DW_OP_skip: // 0x2f 1 signed 2-byte constant
+ case DW_OP_bra: // 0x28 1 signed 2-byte constant
+ case DW_OP_call2: // 0x98 1 2-byte offset of DIE (DWARF3)
+ return 2;
+
+ // Opcodes with a single 4 byte arguments
+ case DW_OP_const4u: // 0x0c 1 4-byte constant
+ case DW_OP_const4s: // 0x0d 1 4-byte constant
+ case DW_OP_call4: // 0x99 1 4-byte offset of DIE (DWARF3)
+ return 4;
+
+ // Opcodes with a single 8 byte arguments
+ case DW_OP_const8u: // 0x0e 1 8-byte constant
+ case DW_OP_const8s: // 0x0f 1 8-byte constant
+ return 8;
+
+ // All opcodes that have a single ULEB (signed or unsigned) argument
+ case DW_OP_constu: // 0x10 1 ULEB128 constant
+ case DW_OP_consts: // 0x11 1 SLEB128 constant
+ case DW_OP_plus_uconst: // 0x23 1 ULEB128 addend
+ case DW_OP_breg0: // 0x70 1 ULEB128 register
+ case DW_OP_breg1: // 0x71 1 ULEB128 register
+ case DW_OP_breg2: // 0x72 1 ULEB128 register
+ case DW_OP_breg3: // 0x73 1 ULEB128 register
+ case DW_OP_breg4: // 0x74 1 ULEB128 register
+ case DW_OP_breg5: // 0x75 1 ULEB128 register
+ case DW_OP_breg6: // 0x76 1 ULEB128 register
+ case DW_OP_breg7: // 0x77 1 ULEB128 register
+ case DW_OP_breg8: // 0x78 1 ULEB128 register
+ case DW_OP_breg9: // 0x79 1 ULEB128 register
+ case DW_OP_breg10: // 0x7a 1 ULEB128 register
+ case DW_OP_breg11: // 0x7b 1 ULEB128 register
+ case DW_OP_breg12: // 0x7c 1 ULEB128 register
+ case DW_OP_breg13: // 0x7d 1 ULEB128 register
+ case DW_OP_breg14: // 0x7e 1 ULEB128 register
+ case DW_OP_breg15: // 0x7f 1 ULEB128 register
+ case DW_OP_breg16: // 0x80 1 ULEB128 register
+ case DW_OP_breg17: // 0x81 1 ULEB128 register
+ case DW_OP_breg18: // 0x82 1 ULEB128 register
+ case DW_OP_breg19: // 0x83 1 ULEB128 register
+ case DW_OP_breg20: // 0x84 1 ULEB128 register
+ case DW_OP_breg21: // 0x85 1 ULEB128 register
+ case DW_OP_breg22: // 0x86 1 ULEB128 register
+ case DW_OP_breg23: // 0x87 1 ULEB128 register
+ case DW_OP_breg24: // 0x88 1 ULEB128 register
+ case DW_OP_breg25: // 0x89 1 ULEB128 register
+ case DW_OP_breg26: // 0x8a 1 ULEB128 register
+ case DW_OP_breg27: // 0x8b 1 ULEB128 register
+ case DW_OP_breg28: // 0x8c 1 ULEB128 register
+ case DW_OP_breg29: // 0x8d 1 ULEB128 register
+ case DW_OP_breg30: // 0x8e 1 ULEB128 register
+ case DW_OP_breg31: // 0x8f 1 ULEB128 register
+ case DW_OP_regx: // 0x90 1 ULEB128 register
+ case DW_OP_fbreg: // 0x91 1 SLEB128 offset
+ case DW_OP_piece: // 0x93 1 ULEB128 size of piece addressed
+ data.Skip_LEB128(&offset);
+ return offset - data_offset;
+
+ // All opcodes that have a 2 ULEB (signed or unsigned) arguments
+ case DW_OP_bregx: // 0x92 2 ULEB128 register followed by SLEB128 offset
+ case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
+ data.Skip_LEB128(&offset);
+ data.Skip_LEB128(&offset);
+ return offset - data_offset;
+
+ case DW_OP_implicit_value: // 0x9e ULEB128 size followed by block of that size (DWARF4)
+ {
+ uint64_t block_len = data.Skip_LEB128(&offset);
+ offset += block_len;
+ return offset - data_offset;
+ }
+
+ default:
+ break;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+lldb::addr_t
+DWARFExpression::GetLocation_DW_OP_addr (uint32_t op_addr_idx, bool &error) const
+{
+ error = false;
+ if (IsLocationList())
+ return LLDB_INVALID_ADDRESS;
+ lldb::offset_t offset = 0;
+ uint32_t curr_op_addr_idx = 0;
+ while (m_data.ValidOffset(offset))
+ {
+ const uint8_t op = m_data.GetU8(&offset);
+
+ if (op == DW_OP_addr)
+ {
+ const lldb::addr_t op_file_addr = m_data.GetAddress(&offset);
+ if (curr_op_addr_idx == op_addr_idx)
+ return op_file_addr;
+ else
+ ++curr_op_addr_idx;
+ }
+ else
+ {
+ const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
+ if (op_arg_size == LLDB_INVALID_OFFSET)
+ {
+ error = true;
+ break;
+ }
+ offset += op_arg_size;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+DWARFExpression::Update_DW_OP_addr (lldb::addr_t file_addr)
+{
+ if (IsLocationList())
+ return false;
+ lldb::offset_t offset = 0;
+ while (m_data.ValidOffset(offset))
+ {
+ const uint8_t op = m_data.GetU8(&offset);
+
+ if (op == DW_OP_addr)
+ {
+ const uint32_t addr_byte_size = m_data.GetAddressByteSize();
+ // We have to make a copy of the data as we don't know if this
+ // data is from a read only memory mapped buffer, so we duplicate
+ // all of the data first, then modify it, and if all goes well,
+ // we then replace the data for this expression
+
+ // So first we copy the data into a heap buffer
+ std::unique_ptr<DataBufferHeap> head_data_ap (new DataBufferHeap (m_data.GetDataStart(),
+ m_data.GetByteSize()));
+
+ // Make en encoder so we can write the address into the buffer using
+ // the correct byte order (endianness)
+ DataEncoder encoder (head_data_ap->GetBytes(),
+ head_data_ap->GetByteSize(),
+ m_data.GetByteOrder(),
+ addr_byte_size);
+
+ // Replace the address in the new buffer
+ if (encoder.PutMaxU64 (offset, addr_byte_size, file_addr) == UINT32_MAX)
+ return false;
+
+ // All went well, so now we can reset the data using a shared
+ // pointer to the heap data so "m_data" will now correctly
+ // manage the heap data.
+ m_data.SetData (DataBufferSP (head_data_ap.release()));
+ return true;
+ }
+ else
+ {
+ const offset_t op_arg_size = GetOpcodeDataSize (m_data, offset, op);
+ if (op_arg_size == LLDB_INVALID_OFFSET)
+ break;
+ offset += op_arg_size;
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::LocationListContainsAddress (lldb::addr_t loclist_base_addr, lldb::addr_t addr) const
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (IsLocationList())
+ {
+ lldb::offset_t offset = 0;
+
+ if (loclist_base_addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ break;
+ else
+ {
+ lo_pc += loclist_base_addr - m_loclist_slide;
+ hi_pc += loclist_base_addr - m_loclist_slide;
+
+ if (lo_pc <= addr && addr < hi_pc)
+ return true;
+
+ offset += m_data.GetU16(&offset);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::GetLocation (addr_t base_addr, addr_t pc, lldb::offset_t &offset, lldb::offset_t &length)
+{
+ offset = 0;
+ if (!IsLocationList())
+ {
+ length = m_data.GetByteSize();
+ return true;
+ }
+
+ if (base_addr != LLDB_INVALID_ADDRESS && pc != LLDB_INVALID_ADDRESS)
+ {
+ addr_t curr_base_addr = base_addr;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ {
+ break;
+ }
+ else
+ {
+ lo_pc += curr_base_addr - m_loclist_slide;
+ hi_pc += curr_base_addr - m_loclist_slide;
+
+ length = m_data.GetU16(&offset);
+
+ if (length > 0 && lo_pc <= pc && pc < hi_pc)
+ return true;
+
+ offset += length;
+ }
+ }
+ }
+ offset = LLDB_INVALID_OFFSET;
+ length = 0;
+ return false;
+}
+
+bool
+DWARFExpression::DumpLocationForAddress (Stream *s,
+ lldb::DescriptionLevel level,
+ addr_t base_addr,
+ addr_t address,
+ ABI *abi)
+{
+ lldb::offset_t offset = 0;
+ lldb::offset_t length = 0;
+
+ if (GetLocation (base_addr, address, offset, length))
+ {
+ if (length > 0)
+ {
+ DumpLocation(s, offset, length, level, abi);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContextScope *exe_scope,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ ExecutionContext exe_ctx (exe_scope);
+ return Evaluate(&exe_ctx, expr_locals, decl_map, NULL, loclist_base_load_addr, initial_value_ptr, result, error_ptr);
+}
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ lldb::addr_t loclist_base_load_addr,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+) const
+{
+ if (IsLocationList())
+ {
+ lldb::offset_t offset = 0;
+ addr_t pc;
+ StackFrame *frame = NULL;
+ if (reg_ctx)
+ pc = reg_ctx->GetPC();
+ else
+ {
+ frame = exe_ctx->GetFramePtr();
+ if (!frame)
+ return false;
+ RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
+ if (!reg_ctx_sp)
+ return false;
+ pc = reg_ctx_sp->GetPC();
+ }
+
+ if (loclist_base_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (pc == LLDB_INVALID_ADDRESS)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid PC in frame.");
+ return false;
+ }
+
+ addr_t curr_loclist_base_load_addr = loclist_base_load_addr;
+
+ while (m_data.ValidOffset(offset))
+ {
+ // We need to figure out what the value is for the location.
+ addr_t lo_pc = m_data.GetAddress(&offset);
+ addr_t hi_pc = m_data.GetAddress(&offset);
+ if (lo_pc == 0 && hi_pc == 0)
+ {
+ break;
+ }
+ else
+ {
+ lo_pc += curr_loclist_base_load_addr - m_loclist_slide;
+ hi_pc += curr_loclist_base_load_addr - m_loclist_slide;
+
+ uint16_t length = m_data.GetU16(&offset);
+
+ if (length > 0 && lo_pc <= pc && pc < hi_pc)
+ {
+ return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, offset, length, m_reg_kind, initial_value_ptr, result, error_ptr);
+ }
+ offset += length;
+ }
+ }
+ }
+ if (error_ptr)
+ error_ptr->SetErrorString ("variable not available");
+ return false;
+ }
+
+ // Not a location list, just a single expression.
+ return DWARFExpression::Evaluate (exe_ctx, expr_locals, decl_map, reg_ctx, m_data, 0, m_data.GetByteSize(), m_reg_kind, initial_value_ptr, result, error_ptr);
+}
+
+
+
+bool
+DWARFExpression::Evaluate
+(
+ ExecutionContext *exe_ctx,
+ ClangExpressionVariableList *expr_locals,
+ ClangExpressionDeclMap *decl_map,
+ RegisterContext *reg_ctx,
+ const DataExtractor& opcodes,
+ const lldb::offset_t opcodes_offset,
+ const lldb::offset_t opcodes_length,
+ const uint32_t reg_kind,
+ const Value* initial_value_ptr,
+ Value& result,
+ Error *error_ptr
+)
+{
+
+ if (opcodes_length == 0)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("no location, value may have been optimized out");
+ return false;
+ }
+ std::vector<Value> stack;
+
+ Process *process = NULL;
+ StackFrame *frame = NULL;
+
+ if (exe_ctx)
+ {
+ process = exe_ctx->GetProcessPtr();
+ frame = exe_ctx->GetFramePtr();
+ }
+ if (reg_ctx == NULL && frame)
+ reg_ctx = frame->GetRegisterContext().get();
+
+ if (initial_value_ptr)
+ stack.push_back(*initial_value_ptr);
+
+ lldb::offset_t offset = opcodes_offset;
+ const lldb::offset_t end_offset = opcodes_offset + opcodes_length;
+ Value tmp;
+ uint32_t reg_num;
+
+ // Make sure all of the data is available in opcodes.
+ if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length))
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("invalid offset and/or length for opcodes buffer.");
+ return false;
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+
+ while (opcodes.ValidOffset(offset) && offset < end_offset)
+ {
+ const lldb::offset_t op_offset = offset;
+ const uint8_t op = opcodes.GetU8(&offset);
+
+ if (log && log->GetVerbose())
+ {
+ size_t count = stack.size();
+ log->Printf("Stack before operation has %lu values:", count);
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ log->Printf(" %s", new_value.GetData());
+ }
+ log->Printf("0x%8.8" PRIx64 ": %s", op_offset, DW_OP_value_to_name(op));
+ }
+ switch (op)
+ {
+ //----------------------------------------------------------------------
+ // The DW_OP_addr operation has a single operand that encodes a machine
+ // address and whose size is the size of an address on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_addr:
+ stack.push_back(Scalar(opcodes.GetAddress(&offset)));
+ stack.back().SetValueType (Value::eValueTypeFileAddress);
+ break;
+
+ //----------------------------------------------------------------------
+ // The DW_OP_addr_sect_offset4 is used for any location expressions in
+ // shared libraries that have a location like:
+ // DW_OP_addr(0x1000)
+ // If this address resides in a shared library, then this virtual
+ // address won't make sense when it is evaluated in the context of a
+ // running process where shared libraries have been slid. To account for
+ // this, this new address type where we can store the section pointer
+ // and a 4 byte offset.
+ //----------------------------------------------------------------------
+// case DW_OP_addr_sect_offset4:
+// {
+// result_type = eResultTypeFileAddress;
+// lldb::Section *sect = (lldb::Section *)opcodes.GetMaxU64(&offset, sizeof(void *));
+// lldb::addr_t sect_offset = opcodes.GetU32(&offset);
+//
+// Address so_addr (sect, sect_offset);
+// lldb::addr_t load_addr = so_addr.GetLoadAddress();
+// if (load_addr != LLDB_INVALID_ADDRESS)
+// {
+// // We successfully resolve a file address to a load
+// // address.
+// stack.push_back(load_addr);
+// break;
+// }
+// else
+// {
+// // We were able
+// if (error_ptr)
+// error_ptr->SetErrorStringWithFormat ("Section %s in %s is not currently loaded.\n", sect->GetName().AsCString(), sect->GetModule()->GetFileSpec().GetFilename().AsCString());
+// return false;
+// }
+// }
+// break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_deref
+ // OPERANDS: none
+ // DESCRIPTION: Pops the top stack entry and treats it as an address.
+ // The value retrieved from that address is pushed. The size of the
+ // data retrieved from the dereferenced address is the size of an
+ // address on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_deref:
+ {
+ Value::ValueType value_type = stack.back().GetValueType();
+ switch (value_type)
+ {
+ case Value::eValueTypeHostAddress:
+ {
+ void *src = (void *)stack.back().GetScalar().ULongLong();
+ intptr_t ptr;
+ ::memcpy (&ptr, src, sizeof(void *));
+ stack.back().GetScalar() = ptr;
+ stack.back().ClearContext();
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ if (exe_ctx)
+ {
+ if (process)
+ {
+ lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ uint8_t addr_bytes[sizeof(lldb::addr_t)];
+ uint32_t addr_size = process->GetAddressByteSize();
+ Error error;
+ if (process->ReadMemory(pointer_addr, &addr_bytes, addr_size, error) == addr_size)
+ {
+ DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), addr_size);
+ lldb::offset_t addr_data_offset = 0;
+ stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
+ stack.back().ClearContext();
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
+ pointer_addr,
+ error.AsCString());
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_deref_size
+ // OPERANDS: 1
+ // 1 - uint8_t that specifies the size of the data to dereference.
+ // DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top
+ // stack entry and treats it as an address. The value retrieved from that
+ // address is pushed. In the DW_OP_deref_size operation, however, the
+ // size in bytes of the data retrieved from the dereferenced address is
+ // specified by the single operand. This operand is a 1-byte unsigned
+ // integral constant whose value may not be larger than the size of an
+ // address on the target machine. The data retrieved is zero extended
+ // to the size of an address on the target machine before being pushed
+ // on the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_deref_size:
+ {
+ uint8_t size = opcodes.GetU8(&offset);
+ Value::ValueType value_type = stack.back().GetValueType();
+ switch (value_type)
+ {
+ case Value::eValueTypeHostAddress:
+ {
+ void *src = (void *)stack.back().GetScalar().ULongLong();
+ intptr_t ptr;
+ ::memcpy (&ptr, src, sizeof(void *));
+ // I can't decide whether the size operand should apply to the bytes in their
+ // lldb-host endianness or the target endianness.. I doubt this'll ever come up
+ // but I'll opt for assuming big endian regardless.
+ switch (size)
+ {
+ case 1: ptr = ptr & 0xff; break;
+ case 2: ptr = ptr & 0xffff; break;
+ case 3: ptr = ptr & 0xffffff; break;
+ case 4: ptr = ptr & 0xffffffff; break;
+ // the casts are added to work around the case where intptr_t is a 32 bit quantity;
+ // presumably we won't hit the 5..7 cases if (void*) is 32-bits in this program.
+ case 5: ptr = (intptr_t) ptr & 0xffffffffffULL; break;
+ case 6: ptr = (intptr_t) ptr & 0xffffffffffffULL; break;
+ case 7: ptr = (intptr_t) ptr & 0xffffffffffffffULL; break;
+ default: break;
+ }
+ stack.back().GetScalar() = ptr;
+ stack.back().ClearContext();
+ }
+ break;
+ case Value::eValueTypeLoadAddress:
+ if (exe_ctx)
+ {
+ if (process)
+ {
+ lldb::addr_t pointer_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+ uint8_t addr_bytes[sizeof(lldb::addr_t)];
+ Error error;
+ if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) == size)
+ {
+ DataExtractor addr_data(addr_bytes, sizeof(addr_bytes), process->GetByteOrder(), size);
+ lldb::offset_t addr_data_offset = 0;
+ switch (size)
+ {
+ case 1: stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset); break;
+ case 2: stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset); break;
+ case 4: stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset); break;
+ case 8: stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset); break;
+ default: stack.back().GetScalar() = addr_data.GetPointer(&addr_data_offset);
+ }
+ stack.back().ClearContext();
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("Failed to dereference pointer from 0x%" PRIx64 " for DW_OP_deref: %s\n",
+ pointer_addr,
+ error.AsCString());
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL process for DW_OP_deref.\n");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_deref.\n");
+ return false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xderef_size
+ // OPERANDS: 1
+ // 1 - uint8_t that specifies the size of the data to dereference.
+ // DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at
+ // the top of the stack is treated as an address. The second stack
+ // entry is treated as an "address space identifier" for those
+ // architectures that support multiple address spaces. The top two
+ // stack elements are popped, a data item is retrieved through an
+ // implementation-defined address calculation and pushed as the new
+ // stack top. In the DW_OP_xderef_size operation, however, the size in
+ // bytes of the data retrieved from the dereferenced address is
+ // specified by the single operand. This operand is a 1-byte unsigned
+ // integral constant whose value may not be larger than the size of an
+ // address on the target machine. The data retrieved is zero extended
+ // to the size of an address on the target machine before being pushed
+ // on the expression stack.
+ //----------------------------------------------------------------------
+ case DW_OP_xderef_size:
+ if (error_ptr)
+ error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
+ return false;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xderef
+ // OPERANDS: none
+ // DESCRIPTION: Provides an extended dereference mechanism. The entry at
+ // the top of the stack is treated as an address. The second stack entry
+ // is treated as an "address space identifier" for those architectures
+ // that support multiple address spaces. The top two stack elements are
+ // popped, a data item is retrieved through an implementation-defined
+ // address calculation and pushed as the new stack top. The size of the
+ // data retrieved from the dereferenced address is the size of an address
+ // on the target machine.
+ //----------------------------------------------------------------------
+ case DW_OP_xderef:
+ if (error_ptr)
+ error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // All DW_OP_constXXX opcodes have a single operand as noted below:
+ //
+ // Opcode Operand 1
+ // --------------- ----------------------------------------------------
+ // DW_OP_const1u 1-byte unsigned integer constant
+ // DW_OP_const1s 1-byte signed integer constant
+ // DW_OP_const2u 2-byte unsigned integer constant
+ // DW_OP_const2s 2-byte signed integer constant
+ // DW_OP_const4u 4-byte unsigned integer constant
+ // DW_OP_const4s 4-byte signed integer constant
+ // DW_OP_const8u 8-byte unsigned integer constant
+ // DW_OP_const8s 8-byte signed integer constant
+ // DW_OP_constu unsigned LEB128 integer constant
+ // DW_OP_consts signed LEB128 integer constant
+ //----------------------------------------------------------------------
+ case DW_OP_const1u : stack.push_back(Scalar(( uint8_t)opcodes.GetU8 (&offset))); break;
+ case DW_OP_const1s : stack.push_back(Scalar(( int8_t)opcodes.GetU8 (&offset))); break;
+ case DW_OP_const2u : stack.push_back(Scalar((uint16_t)opcodes.GetU16 (&offset))); break;
+ case DW_OP_const2s : stack.push_back(Scalar(( int16_t)opcodes.GetU16 (&offset))); break;
+ case DW_OP_const4u : stack.push_back(Scalar((uint32_t)opcodes.GetU32 (&offset))); break;
+ case DW_OP_const4s : stack.push_back(Scalar(( int32_t)opcodes.GetU32 (&offset))); break;
+ case DW_OP_const8u : stack.push_back(Scalar((uint64_t)opcodes.GetU64 (&offset))); break;
+ case DW_OP_const8s : stack.push_back(Scalar(( int64_t)opcodes.GetU64 (&offset))); break;
+ case DW_OP_constu : stack.push_back(Scalar(opcodes.GetULEB128 (&offset))); break;
+ case DW_OP_consts : stack.push_back(Scalar(opcodes.GetSLEB128 (&offset))); break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_dup
+ // OPERANDS: none
+ // DESCRIPTION: duplicates the value at the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_dup:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack empty for DW_OP_dup.");
+ return false;
+ }
+ else
+ stack.push_back(stack.back());
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_drop
+ // OPERANDS: none
+ // DESCRIPTION: pops the value at the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_drop:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack empty for DW_OP_drop.");
+ return false;
+ }
+ else
+ stack.pop_back();
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_over
+ // OPERANDS: none
+ // DESCRIPTION: Duplicates the entry currently second in the stack at
+ // the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_over:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_over.");
+ return false;
+ }
+ else
+ stack.push_back(stack[stack.size() - 2]);
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_pick
+ // OPERANDS: uint8_t index into the current stack
+ // DESCRIPTION: The stack entry with the specified index (0 through 255,
+ // inclusive) is pushed on the stack
+ //----------------------------------------------------------------------
+ case DW_OP_pick:
+ {
+ uint8_t pick_idx = opcodes.GetU8(&offset);
+ if (pick_idx < stack.size())
+ stack.push_back(stack[pick_idx]);
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat("Index %u out of range for DW_OP_pick.\n", pick_idx);
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_swap
+ // OPERANDS: none
+ // DESCRIPTION: swaps the top two stack entries. The entry at the top
+ // of the stack becomes the second stack entry, and the second entry
+ // becomes the top of the stack
+ //----------------------------------------------------------------------
+ case DW_OP_swap:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_swap.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.back() = stack[stack.size() - 2];
+ stack[stack.size() - 2] = tmp;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_rot
+ // OPERANDS: none
+ // DESCRIPTION: Rotates the first three stack entries. The entry at
+ // the top of the stack becomes the third stack entry, the second
+ // entry becomes the top of the stack, and the third entry becomes
+ // the second entry.
+ //----------------------------------------------------------------------
+ case DW_OP_rot:
+ if (stack.size() < 3)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 3 items for DW_OP_rot.");
+ return false;
+ }
+ else
+ {
+ size_t last_idx = stack.size() - 1;
+ Value old_top = stack[last_idx];
+ stack[last_idx] = stack[last_idx - 1];
+ stack[last_idx - 1] = stack[last_idx - 2];
+ stack[last_idx - 2] = old_top;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_abs
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, interprets it as a signed
+ // value and pushes its absolute value. If the absolute value can not be
+ // represented, the result is undefined.
+ //----------------------------------------------------------------------
+ case DW_OP_abs:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_abs.");
+ return false;
+ }
+ else if (stack.back().ResolveValue(exe_ctx).AbsoluteValue() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Failed to take the absolute value of the first stack item.");
+ return false;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_and
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, performs a bitwise and
+ // operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_and:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_and.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_div
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, divides the former second
+ // entry by the former top of the stack using signed division, and
+ // pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_div:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_div.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ if (tmp.ResolveValue(exe_ctx).IsZero())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Divide by zero.");
+ return false;
+ }
+ else
+ {
+ stack.pop_back();
+ stack.back() = stack.back().ResolveValue(exe_ctx) / tmp.ResolveValue(exe_ctx);
+ if (!stack.back().ResolveValue(exe_ctx).IsValid())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Divide failed.");
+ return false;
+ }
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_minus
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, subtracts the former top
+ // of the stack from the former second entry, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_minus:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_minus.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_mod
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values and pushes the result of
+ // the calculation: former second stack entry modulo the former top of
+ // the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_mod:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mod.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_mul
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, multiplies them
+ // together, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_mul:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_mul.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_neg
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, and pushes its negation.
+ //----------------------------------------------------------------------
+ case DW_OP_neg:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_neg.");
+ return false;
+ }
+ else
+ {
+ if (stack.back().ResolveValue(exe_ctx).UnaryNegate() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Unary negate failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_not
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, and pushes its bitwise
+ // complement
+ //----------------------------------------------------------------------
+ case DW_OP_not:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_not.");
+ return false;
+ }
+ else
+ {
+ if (stack.back().ResolveValue(exe_ctx).OnesComplement() == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Logical NOT failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_or
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, performs a bitwise or
+ // operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_or:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_or.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_plus
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, adds them together, and
+ // pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_plus:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_plus.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) + tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_plus_uconst
+ // OPERANDS: none
+ // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128
+ // constant operand and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_plus_uconst:
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 1 item for DW_OP_plus_uconst.");
+ return false;
+ }
+ else
+ {
+ const uint64_t uconst_value = opcodes.GetULEB128(&offset);
+ // Implicit conversion from a UINT to a Scalar...
+ stack.back().ResolveValue(exe_ctx) += uconst_value;
+ if (!stack.back().ResolveValue(exe_ctx).IsValid())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shl
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former
+ // second entry left by the number of bits specified by the former top
+ // of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shl:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shl.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shr
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former second
+ // entry right logically (filling with zero bits) by the number of bits
+ // specified by the former top of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shr:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shr.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ if (stack.back().ResolveValue(exe_ctx).ShiftRightLogical(tmp.ResolveValue(exe_ctx)) == false)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("DW_OP_shr failed.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_shra
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, shifts the former second
+ // entry right arithmetically (divide the magnitude by 2, keep the same
+ // sign for the result) by the number of bits specified by the former
+ // top of the stack, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_shra:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_shra.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_xor
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack entries, performs the bitwise
+ // exclusive-or operation on the two, and pushes the result.
+ //----------------------------------------------------------------------
+ case DW_OP_xor:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_xor.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_skip
+ // OPERANDS: int16_t
+ // DESCRIPTION: An unconditional branch. Its single operand is a 2-byte
+ // signed integer constant. The 2-byte constant is the number of bytes
+ // of the DWARF expression to skip forward or backward from the current
+ // operation, beginning after the 2-byte constant.
+ //----------------------------------------------------------------------
+ case DW_OP_skip:
+ {
+ int16_t skip_offset = (int16_t)opcodes.GetU16(&offset);
+ lldb::offset_t new_offset = offset + skip_offset;
+ if (new_offset >= opcodes_offset && new_offset < end_offset)
+ offset = new_offset;
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip.");
+ return false;
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bra
+ // OPERANDS: int16_t
+ // DESCRIPTION: A conditional branch. Its single operand is a 2-byte
+ // signed integer constant. This operation pops the top of stack. If
+ // the value popped is not the constant 0, the 2-byte constant operand
+ // is the number of bytes of the DWARF expression to skip forward or
+ // backward from the current operation, beginning after the 2-byte
+ // constant.
+ //----------------------------------------------------------------------
+ case DW_OP_bra:
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ int16_t bra_offset = (int16_t)opcodes.GetU16(&offset);
+ Scalar zero(0);
+ if (tmp.ResolveValue(exe_ctx) != zero)
+ {
+ lldb::offset_t new_offset = offset + bra_offset;
+ if (new_offset >= opcodes_offset && new_offset < end_offset)
+ offset = new_offset;
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra.");
+ return false;
+ }
+ }
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_eq
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // equals (==) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_eq:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_eq.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_ge
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // greater than or equal to (>=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_ge:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ge.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_gt
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // greater than (>) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_gt:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_gt.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_le
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // less than or equal to (<=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_le:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_le.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_lt
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // less than (<) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_lt:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_lt.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_ne
+ // OPERANDS: none
+ // DESCRIPTION: pops the top two stack values, compares using the
+ // not equal (!=) operator.
+ // STACK RESULT: push the constant value 1 onto the stack if the result
+ // of the operation is true or the constant value 0 if the result of the
+ // operation is false.
+ //----------------------------------------------------------------------
+ case DW_OP_ne:
+ if (stack.size() < 2)
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString("Expression stack needs at least 2 items for DW_OP_ne.");
+ return false;
+ }
+ else
+ {
+ tmp = stack.back();
+ stack.pop_back();
+ stack.back().ResolveValue(exe_ctx) = stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx);
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_litn
+ // OPERANDS: none
+ // DESCRIPTION: encode the unsigned literal values from 0 through 31.
+ // STACK RESULT: push the unsigned literal constant value onto the top
+ // of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ stack.push_back(Scalar(op - DW_OP_lit0));
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_regN
+ // OPERANDS: none
+ // DESCRIPTION: Push the value in register n on the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ {
+ reg_num = op - DW_OP_reg0;
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ stack.push_back(tmp);
+ else
+ return false;
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_regx
+ // OPERANDS:
+ // ULEB128 literal operand that encodes the register.
+ // DESCRIPTION: Push the value in register on the top of the stack.
+ //----------------------------------------------------------------------
+ case DW_OP_regx:
+ {
+ reg_num = opcodes.GetULEB128(&offset);
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ stack.push_back(tmp);
+ else
+ return false;
+ }
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bregN
+ // OPERANDS:
+ // SLEB128 offset from register N
+ // DESCRIPTION: Value is in memory at the address specified by register
+ // N plus an offset.
+ //----------------------------------------------------------------------
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ {
+ reg_num = op - DW_OP_breg0;
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
+ tmp.ClearContext();
+ stack.push_back(tmp);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ break;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_bregx
+ // OPERANDS: 2
+ // ULEB128 literal operand that encodes the register.
+ // SLEB128 offset from register N
+ // DESCRIPTION: Value is in memory at the address specified by register
+ // N plus an offset.
+ //----------------------------------------------------------------------
+ case DW_OP_bregx:
+ {
+ reg_num = opcodes.GetULEB128(&offset);
+
+ if (ReadRegisterValueAsScalar (reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ {
+ int64_t breg_offset = opcodes.GetSLEB128(&offset);
+ tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
+ tmp.ClearContext();
+ stack.push_back(tmp);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ break;
+
+ case DW_OP_fbreg:
+ if (exe_ctx)
+ {
+ if (frame)
+ {
+ Scalar value;
+ if (frame->GetFrameBaseValue(value, error_ptr))
+ {
+ int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
+ value += fbreg_offset;
+ stack.push_back(value);
+ stack.back().SetValueType (Value::eValueTypeLoadAddress);
+ }
+ else
+ return false;
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_fbreg opcode.");
+ return false;
+ }
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorStringWithFormat ("NULL execution context for DW_OP_fbreg.\n");
+ return false;
+ }
+
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_nop
+ // OPERANDS: none
+ // DESCRIPTION: A place holder. It has no effect on the location stack
+ // or any of its values.
+ //----------------------------------------------------------------------
+ case DW_OP_nop:
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_piece
+ // OPERANDS: 1
+ // ULEB128: byte size of the piece
+ // DESCRIPTION: The operand describes the size in bytes of the piece of
+ // the object referenced by the DWARF expression whose result is at the
+ // top of the stack. If the piece is located in a register, but does not
+ // occupy the entire register, the placement of the piece within that
+ // register is defined by the ABI.
+ //
+ // Many compilers store a single variable in sets of registers, or store
+ // a variable partially in memory and partially in registers.
+ // DW_OP_piece provides a way of describing how large a part of a
+ // variable a particular DWARF expression refers to.
+ //----------------------------------------------------------------------
+ case DW_OP_piece:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_piece.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_push_object_address
+ // OPERANDS: none
+ // DESCRIPTION: Pushes the address of the object currently being
+ // evaluated as part of evaluation of a user presented expression.
+ // This object may correspond to an independent variable described by
+ // its own DIE or it may be a component of an array, structure, or class
+ // whose address has been dynamically determined by an earlier step
+ // during user expression evaluation.
+ //----------------------------------------------------------------------
+ case DW_OP_push_object_address:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_push_object_address.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call2
+ // OPERANDS:
+ // uint16_t compile unit relative offset of a DIE
+ // DESCRIPTION: Performs subroutine calls during evaluation
+ // of a DWARF expression. The operand is the 2-byte unsigned offset
+ // of a debugging information entry in the current compilation unit.
+ //
+ // Operand interpretation is exactly like that for DW_FORM_ref2.
+ //
+ // This operation transfers control of DWARF expression evaluation
+ // to the DW_AT_location attribute of the referenced DIE. If there is
+ // no such attribute, then there is no effect. Execution of the DWARF
+ // expression of a DW_AT_location attribute may add to and/or remove from
+ // values on the stack. Execution returns to the point following the call
+ // when the end of the attribute is reached. Values on the stack at the
+ // time of the call may be used as parameters by the called expression
+ // and values left on the stack by the called expression may be used as
+ // return values by prior agreement between the calling and called
+ // expressions.
+ //----------------------------------------------------------------------
+ case DW_OP_call2:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call2.");
+ return false;
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call4
+ // OPERANDS: 1
+ // uint32_t compile unit relative offset of a DIE
+ // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
+ // expression. For DW_OP_call4, the operand is a 4-byte unsigned offset
+ // of a debugging information entry in the current compilation unit.
+ //
+ // Operand interpretation DW_OP_call4 is exactly like that for
+ // DW_FORM_ref4.
+ //
+ // This operation transfers control of DWARF expression evaluation
+ // to the DW_AT_location attribute of the referenced DIE. If there is
+ // no such attribute, then there is no effect. Execution of the DWARF
+ // expression of a DW_AT_location attribute may add to and/or remove from
+ // values on the stack. Execution returns to the point following the call
+ // when the end of the attribute is reached. Values on the stack at the
+ // time of the call may be used as parameters by the called expression
+ // and values left on the stack by the called expression may be used as
+ // return values by prior agreement between the calling and called
+ // expressions.
+ //----------------------------------------------------------------------
+ case DW_OP_call4:
+ if (error_ptr)
+ error_ptr->SetErrorString ("Unimplemented opcode DW_OP_call4.");
+ return false;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_stack_value
+ // OPERANDS: None
+ // DESCRIPTION: Specifies that the object does not exist in memory but
+ // rather is a constant value. The value from the top of the stack is
+ // the value to be used. This is the actual object value and not the
+ // location.
+ //----------------------------------------------------------------------
+ case DW_OP_stack_value:
+ stack.back().SetValueType(Value::eValueTypeScalar);
+ break;
+
+ //----------------------------------------------------------------------
+ // OPCODE: DW_OP_call_frame_cfa
+ // OPERANDS: None
+ // DESCRIPTION: Specifies a DWARF expression that pushes the value of
+ // the canonical frame address consistent with the call frame information
+ // located in .debug_frame (or in the FDEs of the eh_frame section).
+ //----------------------------------------------------------------------
+ case DW_OP_call_frame_cfa:
+ if (frame)
+ {
+ // Note that we don't have to parse FDEs because this DWARF expression
+ // is commonly evaluated with a valid stack frame.
+ StackID id = frame->GetStackID();
+ addr_t cfa = id.GetCallFrameAddress();
+ if (cfa != LLDB_INVALID_ADDRESS)
+ {
+ stack.push_back(Scalar(cfa));
+ stack.back().SetValueType (Value::eValueTypeHostAddress);
+ }
+ else
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack frame does not include a canonical frame address for DW_OP_call_frame_cfa opcode.");
+ }
+ else
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Invalid stack frame in context for DW_OP_call_frame_cfa opcode.");
+ return false;
+ }
+ break;
+ default:
+ if (log)
+ log->Printf("Unhandled opcode %s in DWARFExpression.", DW_OP_value_to_name(op));
+ break;
+ }
+ }
+
+ if (stack.empty())
+ {
+ if (error_ptr)
+ error_ptr->SetErrorString ("Stack empty after evaluation.");
+ return false;
+ }
+ else if (log && log->GetVerbose())
+ {
+ size_t count = stack.size();
+ log->Printf("Stack after operation has %lu values:", count);
+ for (size_t i=0; i<count; ++i)
+ {
+ StreamString new_value;
+ new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+ stack[i].Dump(&new_value);
+ log->Printf(" %s", new_value.GetData());
+ }
+ }
+
+ result = stack.back();
+ return true; // Return true on success
+}
+
diff --git a/source/Expression/ExpressionSourceCode.cpp b/source/Expression/ExpressionSourceCode.cpp
new file mode 100644
index 000000000000..aef3b9e301e5
--- /dev/null
+++ b/source/Expression/ExpressionSourceCode.cpp
@@ -0,0 +1,142 @@
+//===-- ExpressionSourceCode.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/Expression/ExpressionSourceCode.h"
+
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb_private;
+
+const char *
+ExpressionSourceCode::g_expression_prefix = R"(
+#undef NULL
+#undef Nil
+#undef nil
+#undef YES
+#undef NO
+#define NULL (__null)
+#define Nil (__null)
+#define nil (__null)
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+typedef signed char BOOL;
+typedef signed __INT8_TYPE__ int8_t;
+typedef unsigned __INT8_TYPE__ uint8_t;
+typedef signed __INT16_TYPE__ int16_t;
+typedef unsigned __INT16_TYPE__ uint16_t;
+typedef signed __INT32_TYPE__ int32_t;
+typedef unsigned __INT32_TYPE__ uint32_t;
+typedef signed __INT64_TYPE__ int64_t;
+typedef unsigned __INT64_TYPE__ uint64_t;
+typedef signed __INTPTR_TYPE__ intptr_t;
+typedef unsigned __INTPTR_TYPE__ uintptr_t;
+typedef __SIZE_TYPE__ size_t;
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef unsigned short unichar;
+)";
+
+
+bool ExpressionSourceCode::GetText (std::string &text, lldb::LanguageType wrapping_language, bool const_object, bool static_method) const
+{
+ if (m_wrap)
+ {
+ switch (wrapping_language)
+ {
+ default:
+ return false;
+ case lldb::eLanguageTypeC:
+ case lldb::eLanguageTypeC_plus_plus:
+ case lldb::eLanguageTypeObjC:
+ break;
+ }
+
+ StreamString wrap_stream;
+
+ switch (wrapping_language)
+ {
+ default:
+ break;
+ case lldb::eLanguageTypeC:
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "void \n"
+ "%s(void *$__lldb_arg) \n"
+ "{ \n"
+ " %s; \n"
+ "} \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ break;
+ case lldb::eLanguageTypeC_plus_plus:
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "void \n"
+ "$__lldb_class::%s(void *$__lldb_arg) %s\n"
+ "{ \n"
+ " %s; \n"
+ "} \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ (const_object ? "const" : ""),
+ m_body.c_str());
+ break;
+ case lldb::eLanguageTypeObjC:
+ if (static_method)
+ {
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "@interface $__lldb_objc_class ($__lldb_category) \n"
+ "+(void)%s:(void *)$__lldb_arg; \n"
+ "@end \n"
+ "@implementation $__lldb_objc_class ($__lldb_category) \n"
+ "+(void)%s:(void *)$__lldb_arg \n"
+ "{ \n"
+ " %s; \n"
+ "} \n"
+ "@end \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ }
+ else
+ {
+ wrap_stream.Printf("%s \n"
+ "%s \n"
+ "@interface $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg; \n"
+ "@end \n"
+ "@implementation $__lldb_objc_class ($__lldb_category) \n"
+ "-(void)%s:(void *)$__lldb_arg \n"
+ "{ \n"
+ " %s; \n"
+ "} \n"
+ "@end \n",
+ g_expression_prefix,
+ m_prefix.c_str(),
+ m_name.c_str(),
+ m_name.c_str(),
+ m_body.c_str());
+ }
+ break;
+ }
+
+ text = wrap_stream.GetString();
+ }
+ else
+ {
+ text.append(m_body);
+ }
+
+ return true;
+}
diff --git a/source/Expression/IRDynamicChecks.cpp b/source/Expression/IRDynamicChecks.cpp
new file mode 100644
index 000000000000..4030f149ab2d
--- /dev/null
+++ b/source/Expression/IRDynamicChecks.cpp
@@ -0,0 +1,659 @@
+//===-- IRDynamicChecks.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/Expression/IRDynamicChecks.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/ClangUtilityFunction.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/Value.h"
+
+using namespace llvm;
+using namespace lldb_private;
+
+static char ID;
+
+#define VALID_POINTER_CHECK_NAME "$__lldb_valid_pointer_check"
+#define VALID_OBJC_OBJECT_CHECK_NAME "$__lldb_objc_object_check"
+
+static const char g_valid_pointer_check_text[] =
+"extern \"C\" void\n"
+"$__lldb_valid_pointer_check (unsigned char *$__lldb_arg_ptr)\n"
+"{\n"
+" unsigned char $__lldb_local_val = *$__lldb_arg_ptr;\n"
+"}";
+
+DynamicCheckerFunctions::DynamicCheckerFunctions ()
+{
+}
+
+DynamicCheckerFunctions::~DynamicCheckerFunctions ()
+{
+}
+
+bool
+DynamicCheckerFunctions::Install(Stream &error_stream,
+ ExecutionContext &exe_ctx)
+{
+ m_valid_pointer_check.reset(new ClangUtilityFunction(g_valid_pointer_check_text,
+ VALID_POINTER_CHECK_NAME));
+ if (!m_valid_pointer_check->Install(error_stream, exe_ctx))
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ if (process)
+ {
+ ObjCLanguageRuntime *objc_language_runtime = process->GetObjCLanguageRuntime();
+
+ if (objc_language_runtime)
+ {
+ m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker(VALID_OBJC_OBJECT_CHECK_NAME));
+
+ if (!m_objc_object_check->Install(error_stream, exe_ctx))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+DynamicCheckerFunctions::DoCheckersExplainStop (lldb::addr_t addr, Stream &message)
+{
+ // FIXME: We have to get the checkers to know why they scotched the call in more detail,
+ // so we can print a better message here.
+ if (m_valid_pointer_check.get() != NULL && m_valid_pointer_check->ContainsAddress(addr))
+ {
+ message.Printf ("Attempted to dereference an invalid pointer.");
+ return true;
+ }
+ else if (m_objc_object_check.get() != NULL && m_objc_object_check->ContainsAddress(addr))
+ {
+ message.Printf ("Attempted to dereference an invalid ObjC Object or send it an unrecognized selector");
+ return true;
+ }
+ return false;
+}
+
+
+static std::string
+PrintValue(llvm::Value *V, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ V->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+//----------------------------------------------------------------------
+/// @class Instrumenter IRDynamicChecks.cpp
+/// @brief Finds and instruments individual LLVM IR instructions
+///
+/// When instrumenting LLVM IR, it is frequently desirable to first search
+/// for instructions, and then later modify them. This way iterators
+/// remain intact, and multiple passes can look at the same code base without
+/// treading on each other's toes.
+///
+/// The Instrumenter class implements this functionality. A client first
+/// calls Inspect on a function, which populates a list of instructions to
+/// be instrumented. Then, later, when all passes' Inspect functions have
+/// been called, the client calls Instrument, which adds the desired
+/// instrumentation.
+///
+/// A subclass of Instrumenter must override InstrumentInstruction, which
+/// is responsible for adding whatever instrumentation is necessary.
+///
+/// A subclass of Instrumenter may override:
+///
+/// - InspectInstruction [default: does nothing]
+///
+/// - InspectBasicBlock [default: iterates through the instructions in a
+/// basic block calling InspectInstruction]
+///
+/// - InspectFunction [default: iterates through the basic blocks in a
+/// function calling InspectBasicBlock]
+//----------------------------------------------------------------------
+class Instrumenter {
+public:
+ //------------------------------------------------------------------
+ /// Constructor
+ ///
+ /// @param[in] module
+ /// The module being instrumented.
+ //------------------------------------------------------------------
+ Instrumenter (llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ m_module(module),
+ m_checker_functions(checker_functions),
+ m_i8ptr_ty(NULL)
+ {
+ }
+
+ virtual~Instrumenter ()
+ {
+ }
+
+ //------------------------------------------------------------------
+ /// Inspect a function to find instructions to instrument
+ ///
+ /// @param[in] function
+ /// The function to inspect.
+ ///
+ /// @return
+ /// True on success; false on error.
+ //------------------------------------------------------------------
+ bool Inspect (llvm::Function &function)
+ {
+ return InspectFunction(function);
+ }
+
+ //------------------------------------------------------------------
+ /// Instrument all the instructions found by Inspect()
+ ///
+ /// @return
+ /// True on success; false on error.
+ //------------------------------------------------------------------
+ bool Instrument ()
+ {
+ for (InstIterator ii = m_to_instrument.begin(), last_ii = m_to_instrument.end();
+ ii != last_ii;
+ ++ii)
+ {
+ if (!InstrumentInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+protected:
+ //------------------------------------------------------------------
+ /// Add instrumentation to a single instruction
+ ///
+ /// @param[in] inst
+ /// The instruction to be instrumented.
+ ///
+ /// @return
+ /// True on success; false otherwise.
+ //------------------------------------------------------------------
+ virtual bool InstrumentInstruction(llvm::Instruction *inst) = 0;
+
+ //------------------------------------------------------------------
+ /// Register a single instruction to be instrumented
+ ///
+ /// @param[in] inst
+ /// The instruction to be instrumented.
+ //------------------------------------------------------------------
+ void RegisterInstruction(llvm::Instruction &i)
+ {
+ m_to_instrument.push_back(&i);
+ }
+
+ //------------------------------------------------------------------
+ /// Determine whether a single instruction is interesting to
+ /// instrument, and, if so, call RegisterInstruction
+ ///
+ /// @param[in] i
+ /// The instruction to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectInstruction(llvm::Instruction &i)
+ {
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Scan a basic block to see if any instructions are interesting
+ ///
+ /// @param[in] bb
+ /// The basic block to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectBasicBlock(llvm::BasicBlock &bb)
+ {
+ for (llvm::BasicBlock::iterator ii = bb.begin(), last_ii = bb.end();
+ ii != last_ii;
+ ++ii)
+ {
+ if (!InspectInstruction(*ii))
+ return false;
+ }
+
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Scan a function to see if any instructions are interesting
+ ///
+ /// @param[in] f
+ /// The function to be inspected.
+ ///
+ /// @return
+ /// False if there was an error scanning; true otherwise.
+ //------------------------------------------------------------------
+ virtual bool InspectFunction(llvm::Function &f)
+ {
+ for (llvm::Function::iterator bbi = f.begin(), last_bbi = f.end();
+ bbi != last_bbi;
+ ++bbi)
+ {
+ if (!InspectBasicBlock(*bbi))
+ return false;
+ }
+
+ return true;
+ }
+
+ //------------------------------------------------------------------
+ /// Build a function pointer for a function with signature
+ /// void (*)(uint8_t*) with a given address
+ ///
+ /// @param[in] start_address
+ /// The address of the function.
+ ///
+ /// @return
+ /// The function pointer, for use in a CallInst.
+ //------------------------------------------------------------------
+ llvm::Value *BuildPointerValidatorFunc(lldb::addr_t start_address)
+ {
+ IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
+ (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32);
+
+ llvm::Type *param_array[1];
+
+ param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type*> params(param_array, 1);
+
+ FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+ }
+
+ //------------------------------------------------------------------
+ /// Build a function pointer for a function with signature
+ /// void (*)(uint8_t*, uint8_t*) with a given address
+ ///
+ /// @param[in] start_address
+ /// The address of the function.
+ ///
+ /// @return
+ /// The function pointer, for use in a CallInst.
+ //------------------------------------------------------------------
+ llvm::Value *BuildObjectCheckerFunc(lldb::addr_t start_address)
+ {
+ IntegerType *intptr_ty = llvm::Type::getIntNTy(m_module.getContext(),
+ (m_module.getPointerSize() == llvm::Module::Pointer64) ? 64 : 32);
+
+ llvm::Type *param_array[2];
+
+ param_array[0] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+ param_array[1] = const_cast<llvm::PointerType*>(GetI8PtrTy());
+
+ ArrayRef<llvm::Type*> params(param_array, 2);
+
+ FunctionType *fun_ty = FunctionType::get(llvm::Type::getVoidTy(m_module.getContext()), params, true);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(fun_ty);
+ Constant *fun_addr_int = ConstantInt::get(intptr_ty, start_address, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+ }
+
+ PointerType *GetI8PtrTy()
+ {
+ if (!m_i8ptr_ty)
+ m_i8ptr_ty = llvm::Type::getInt8PtrTy(m_module.getContext());
+
+ return m_i8ptr_ty;
+ }
+
+ typedef std::vector <llvm::Instruction *> InstVector;
+ typedef InstVector::iterator InstIterator;
+
+ InstVector m_to_instrument; ///< List of instructions the inspector found
+ llvm::Module &m_module; ///< The module which is being instrumented
+ DynamicCheckerFunctions &m_checker_functions; ///< The dynamic checker functions for the process
+private:
+ PointerType *m_i8ptr_ty;
+};
+
+class ValidPointerChecker : public Instrumenter
+{
+public:
+ ValidPointerChecker (llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ Instrumenter(module, checker_functions),
+ m_valid_pointer_check_func(NULL)
+ {
+ }
+
+ virtual ~ValidPointerChecker ()
+ {
+ }
+private:
+ bool InstrumentInstruction(llvm::Instruction *inst)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("Instrumenting load/store instruction: %s\n",
+ PrintValue(inst).c_str());
+
+ if (!m_valid_pointer_check_func)
+ m_valid_pointer_check_func = BuildPointerValidatorFunc(m_checker_functions.m_valid_pointer_check->StartAddress());
+
+ llvm::Value *dereferenced_ptr = NULL;
+
+ if (llvm::LoadInst *li = dyn_cast<llvm::LoadInst> (inst))
+ dereferenced_ptr = li->getPointerOperand();
+ else if (llvm::StoreInst *si = dyn_cast<llvm::StoreInst> (inst))
+ dereferenced_ptr = si->getPointerOperand();
+ else
+ return false;
+
+ // Insert an instruction to cast the loaded value to int8_t*
+
+ BitCastInst *bit_cast = new BitCastInst(dereferenced_ptr,
+ GetI8PtrTy(),
+ "",
+ inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[1];
+
+ arg_array[0] = bit_cast;
+
+ llvm::ArrayRef<llvm::Value *> args(arg_array, 1);
+
+ CallInst::Create(m_valid_pointer_check_func,
+ args,
+ "",
+ inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i)
+ {
+ if (dyn_cast<llvm::LoadInst> (&i) ||
+ dyn_cast<llvm::StoreInst> (&i))
+ RegisterInstruction(i);
+
+ return true;
+ }
+
+ llvm::Value *m_valid_pointer_check_func;
+};
+
+class ObjcObjectChecker : public Instrumenter
+{
+public:
+ ObjcObjectChecker(llvm::Module &module,
+ DynamicCheckerFunctions &checker_functions) :
+ Instrumenter(module, checker_functions),
+ m_objc_object_check_func(NULL)
+ {
+ }
+
+ virtual
+ ~ObjcObjectChecker ()
+ {
+ }
+
+ enum msgSend_type
+ {
+ eMsgSend = 0,
+ eMsgSendSuper,
+ eMsgSendSuper_stret,
+ eMsgSend_fpret,
+ eMsgSend_stret
+ };
+
+ std::map <llvm::Instruction *, msgSend_type> msgSend_types;
+
+private:
+ bool InstrumentInstruction(llvm::Instruction *inst)
+ {
+ CallInst *call_inst = dyn_cast<CallInst>(inst);
+
+ if (!call_inst)
+ return false; // call_inst really shouldn't be NULL, because otherwise InspectInstruction wouldn't have registered it
+
+ if (!m_objc_object_check_func)
+ m_objc_object_check_func = BuildObjectCheckerFunc(m_checker_functions.m_objc_object_check->StartAddress());
+
+ // id objc_msgSend(id theReceiver, SEL theSelector, ...)
+
+ llvm::Value *target_object;
+ llvm::Value *selector;
+
+ switch (msgSend_types[inst])
+ {
+ case eMsgSend:
+ case eMsgSend_fpret:
+ target_object = call_inst->getArgOperand(0);
+ selector = call_inst->getArgOperand(1);
+ break;
+ case eMsgSend_stret:
+ target_object = call_inst->getArgOperand(1);
+ selector = call_inst->getArgOperand(2);
+ break;
+ case eMsgSendSuper:
+ case eMsgSendSuper_stret:
+ return true;
+ }
+
+ // These objects should always be valid according to Sean Calannan
+ assert (target_object);
+ assert (selector);
+
+ // Insert an instruction to cast the receiver id to int8_t*
+
+ BitCastInst *bit_cast = new BitCastInst(target_object,
+ GetI8PtrTy(),
+ "",
+ inst);
+
+ // Insert an instruction to call the helper with the result
+
+ llvm::Value *arg_array[2];
+
+ arg_array[0] = bit_cast;
+ arg_array[1] = selector;
+
+ ArrayRef<llvm::Value*> args(arg_array, 2);
+
+ CallInst::Create(m_objc_object_check_func,
+ args,
+ "",
+ inst);
+
+ return true;
+ }
+
+ bool InspectInstruction(llvm::Instruction &i)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ CallInst *call_inst = dyn_cast<CallInst>(&i);
+
+ if (call_inst)
+ {
+ // This metadata is set by IRForTarget::MaybeHandleCall().
+
+ MDNode *metadata = call_inst->getMetadata("lldb.call.realName");
+
+ if (!metadata)
+ return true;
+
+ if (metadata->getNumOperands() != 1)
+ {
+ if (log)
+ log->Printf("Function call metadata has %d operands for [%p] %s", metadata->getNumOperands(), call_inst, PrintValue(call_inst).c_str());
+ return false;
+ }
+
+ MDString *real_name = dyn_cast<MDString>(metadata->getOperand(0));
+
+ if (!real_name)
+ {
+ if (log)
+ log->Printf("Function call metadata is not an MDString for [%p] %s", call_inst, PrintValue(call_inst).c_str());
+ return false;
+ }
+
+ std::string name_str = real_name->getString();
+ const char* name_cstr = name_str.c_str();
+
+ if (log)
+ log->Printf("Found call to %s: %s\n", name_cstr, PrintValue(call_inst).c_str());
+
+ if (name_str.find("objc_msgSend") == std::string::npos)
+ return true;
+
+ if (!strcmp(name_cstr, "objc_msgSend"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_stret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_stret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSend_fpret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSend_fpret;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper;
+ return true;
+ }
+
+ if (!strcmp(name_cstr, "objc_msgSendSuper_stret"))
+ {
+ RegisterInstruction(i);
+ msgSend_types[&i] = eMsgSendSuper_stret;
+ return true;
+ }
+
+ if (log)
+ log->Printf("Function name '%s' contains 'objc_msgSend' but is not handled", name_str.c_str());
+
+ return true;
+ }
+
+ return true;
+ }
+
+ llvm::Value *m_objc_object_check_func;
+};
+
+IRDynamicChecks::IRDynamicChecks(DynamicCheckerFunctions &checker_functions,
+ const char *func_name) :
+ ModulePass(ID),
+ m_func_name(func_name),
+ m_checker_functions(checker_functions)
+{
+}
+
+IRDynamicChecks::~IRDynamicChecks()
+{
+}
+
+bool
+IRDynamicChecks::runOnModule(llvm::Module &M)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ llvm::Function* function = M.getFunction(StringRef(m_func_name.c_str()));
+
+ if (!function)
+ {
+ if (log)
+ log->Printf("Couldn't find %s() in the module", m_func_name.c_str());
+
+ return false;
+ }
+
+ if (m_checker_functions.m_valid_pointer_check.get())
+ {
+ ValidPointerChecker vpc(M, m_checker_functions);
+
+ if (!vpc.Inspect(*function))
+ return false;
+
+ if (!vpc.Instrument())
+ return false;
+ }
+
+ if (m_checker_functions.m_objc_object_check.get())
+ {
+ ObjcObjectChecker ooc(M, m_checker_functions);
+
+ if (!ooc.Inspect(*function))
+ return false;
+
+ if (!ooc.Instrument())
+ return false;
+ }
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ M.print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf ("Module after dynamic checks: \n%s", s.c_str());
+ }
+
+ return true;
+}
+
+void
+IRDynamicChecks::assignPassManager(PMStack &PMS,
+ PassManagerType T)
+{
+}
+
+PassManagerType
+IRDynamicChecks::getPotentialPassManagerType() const
+{
+ return PMT_ModulePassManager;
+}
diff --git a/source/Expression/IRExecutionUnit.cpp b/source/Expression/IRExecutionUnit.cpp
new file mode 100644
index 000000000000..16ef6e5d54e1
--- /dev/null
+++ b/source/Expression/IRExecutionUnit.cpp
@@ -0,0 +1,704 @@
+//===-- IRExecutionUnit.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/SourceMgr.h"
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+IRExecutionUnit::IRExecutionUnit (std::unique_ptr<llvm::LLVMContext> &context_ap,
+ std::unique_ptr<llvm::Module> &module_ap,
+ ConstString &name,
+ const lldb::TargetSP &target_sp,
+ std::vector<std::string> &cpu_features) :
+ IRMemoryMap(target_sp),
+ m_context_ap(context_ap.release()),
+ m_module_ap(module_ap.release()),
+ m_module(m_module_ap.get()),
+ m_cpu_features(cpu_features),
+ m_name(name),
+ m_did_jit(false),
+ m_function_load_addr(LLDB_INVALID_ADDRESS),
+ m_function_end_load_addr(LLDB_INVALID_ADDRESS)
+{
+}
+
+lldb::addr_t
+IRExecutionUnit::WriteNow (const uint8_t *bytes,
+ size_t size,
+ Error &error)
+{
+ lldb::addr_t allocation_process_addr = Malloc (size,
+ 8,
+ lldb::ePermissionsWritable | lldb::ePermissionsReadable,
+ eAllocationPolicyMirror,
+ error);
+
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+
+ WriteMemory(allocation_process_addr, bytes, size, error);
+
+ if (!error.Success())
+ {
+ Error err;
+ Free (allocation_process_addr, err);
+
+ return LLDB_INVALID_ADDRESS;
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ DataBufferHeap my_buffer(size, 0);
+ Error err;
+ ReadMemory(my_buffer.GetBytes(), allocation_process_addr, size, err);
+
+ if (err.Success())
+ {
+ DataExtractor my_extractor(my_buffer.GetBytes(), my_buffer.GetByteSize(), lldb::eByteOrderBig, 8);
+
+ StreamString ss;
+
+ my_extractor.Dump(&ss, 0, lldb::eFormatBytesWithASCII, 1, my_buffer.GetByteSize(), 32, allocation_process_addr, 0, 0);
+
+ log->PutCString(ss.GetData());
+ }
+ }
+
+ return allocation_process_addr;
+}
+
+void
+IRExecutionUnit::FreeNow (lldb::addr_t allocation)
+{
+ if (allocation == LLDB_INVALID_ADDRESS)
+ return;
+
+ Error err;
+
+ Free(allocation, err);
+}
+
+Error
+IRExecutionUnit::DisassembleFunction (Stream &stream,
+ lldb::ProcessSP &process_wp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ExecutionContext exe_ctx(process_wp);
+
+ Error ret;
+
+ ret.Clear();
+
+ lldb::addr_t func_local_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t func_remote_addr = LLDB_INVALID_ADDRESS;
+
+ for (JittedFunction &function : m_jitted_functions)
+ {
+ if (strstr(function.m_name.c_str(), m_name.AsCString()))
+ {
+ func_local_addr = function.m_local_addr;
+ func_remote_addr = function.m_remote_addr;
+ }
+ }
+
+ if (func_local_addr == LLDB_INVALID_ADDRESS)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't find function %s for disassembly", m_name.AsCString());
+ return ret;
+ }
+
+ if (log)
+ log->Printf("Found function, has local address 0x%" PRIx64 " and remote address 0x%" PRIx64, (uint64_t)func_local_addr, (uint64_t)func_remote_addr);
+
+ std::pair <lldb::addr_t, lldb::addr_t> func_range;
+
+ func_range = GetRemoteRangeForLocal(func_local_addr);
+
+ if (func_range.first == 0 && func_range.second == 0)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't find code range for function %s", m_name.AsCString());
+ return ret;
+ }
+
+ if (log)
+ log->Printf("Function's code range is [0x%" PRIx64 "+0x%" PRIx64 "]", func_range.first, func_range.second);
+
+ Target *target = exe_ctx.GetTargetPtr();
+ if (!target)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorString("Couldn't find the target");
+ return ret;
+ }
+
+ lldb::DataBufferSP buffer_sp(new DataBufferHeap(func_range.second, 0));
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Error err;
+ process->ReadMemory(func_remote_addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), err);
+
+ if (!err.Success())
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Couldn't read from process: %s", err.AsCString("unknown error"));
+ return ret;
+ }
+
+ ArchSpec arch(target->GetArchitecture());
+
+ const char *plugin_name = NULL;
+ const char *flavor_string = NULL;
+ lldb::DisassemblerSP disassembler_sp = Disassembler::FindPlugin(arch, flavor_string, plugin_name);
+
+ if (!disassembler_sp)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorStringWithFormat("Unable to find disassembler plug-in for %s architecture.", arch.GetArchitectureName());
+ return ret;
+ }
+
+ if (!process)
+ {
+ ret.SetErrorToGenericError();
+ ret.SetErrorString("Couldn't find the process");
+ return ret;
+ }
+
+ DataExtractor extractor(buffer_sp,
+ process->GetByteOrder(),
+ target->GetArchitecture().GetAddressByteSize());
+
+ if (log)
+ {
+ log->Printf("Function data has contents:");
+ extractor.PutToLog (log,
+ 0,
+ extractor.GetByteSize(),
+ func_remote_addr,
+ 16,
+ DataExtractor::TypeUInt8);
+ }
+
+ disassembler_sp->DecodeInstructions (Address (func_remote_addr), extractor, 0, UINT32_MAX, false, false);
+
+ InstructionList &instruction_list = disassembler_sp->GetInstructionList();
+ const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
+
+ for (size_t instruction_index = 0, num_instructions = instruction_list.GetSize();
+ instruction_index < num_instructions;
+ ++instruction_index)
+ {
+ Instruction *instruction = instruction_list.GetInstructionAtIndex(instruction_index).get();
+ instruction->Dump (&stream,
+ max_opcode_byte_size,
+ true,
+ true,
+ &exe_ctx);
+ stream.PutChar('\n');
+ }
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disassembler_sp->GetInstructionList().Clear();
+ return ret;
+}
+
+static void ReportInlineAsmError(const llvm::SMDiagnostic &diagnostic, void *Context, unsigned LocCookie)
+{
+ Error *err = static_cast<Error*>(Context);
+
+ if (err && err->Success())
+ {
+ err->SetErrorToGenericError();
+ err->SetErrorStringWithFormat("Inline assembly error: %s", diagnostic.getMessage().str().c_str());
+ }
+}
+
+void
+IRExecutionUnit::GetRunnableInfo(Error &error,
+ lldb::addr_t &func_addr,
+ lldb::addr_t &func_end)
+{
+ lldb::ProcessSP process_sp(GetProcessWP().lock());
+
+ func_addr = LLDB_INVALID_ADDRESS;
+ func_end = LLDB_INVALID_ADDRESS;
+
+ if (!process_sp)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write the JIT compiled code into the process because the process is invalid");
+ return;
+ }
+
+ if (m_did_jit)
+ {
+ func_addr = m_function_load_addr;
+ func_end = m_function_end_load_addr;
+
+ return;
+ };
+
+ m_did_jit = true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ std::string error_string;
+
+ if (log)
+ {
+ std::string s;
+ llvm::raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf ("Module being sent to JIT: \n%s", s.c_str());
+ }
+
+ llvm::Triple triple(m_module->getTargetTriple());
+ llvm::Function *function = m_module->getFunction (m_name.AsCString());
+ llvm::Reloc::Model relocModel;
+ llvm::CodeModel::Model codeModel;
+
+ if (triple.isOSBinFormatELF())
+ {
+ relocModel = llvm::Reloc::Static;
+ // This will be small for 32-bit and large for 64-bit.
+ codeModel = llvm::CodeModel::JITDefault;
+ }
+ else
+ {
+ relocModel = llvm::Reloc::PIC_;
+ codeModel = llvm::CodeModel::Small;
+ }
+
+ m_module_ap->getContext().setInlineAsmDiagnosticHandler(ReportInlineAsmError, &error);
+
+ llvm::EngineBuilder builder(m_module_ap.get());
+
+ builder.setEngineKind(llvm::EngineKind::JIT)
+ .setErrorStr(&error_string)
+ .setRelocationModel(relocModel)
+ .setJITMemoryManager(new MemoryManager(*this))
+ .setOptLevel(llvm::CodeGenOpt::Less)
+ .setAllocateGVsWithCode(true)
+ .setCodeModel(codeModel)
+ .setUseMCJIT(true);
+
+ llvm::StringRef mArch;
+ llvm::StringRef mCPU;
+ llvm::SmallVector<std::string, 0> mAttrs;
+
+ for (std::string &feature : m_cpu_features)
+ mAttrs.push_back(feature);
+
+ llvm::TargetMachine *target_machine = builder.selectTarget(triple,
+ mArch,
+ mCPU,
+ mAttrs);
+
+ m_execution_engine_ap.reset(builder.create(target_machine));
+
+ if (!m_execution_engine_ap.get())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't JIT the function: %s", error_string.c_str());
+ return;
+ }
+ else
+ {
+ m_module_ap.release(); // ownership was transferred
+ }
+
+ m_execution_engine_ap->DisableLazyCompilation();
+
+ // We don't actually need the function pointer here, this just forces it to get resolved.
+
+ void *fun_ptr = m_execution_engine_ap->getPointerToFunction(function);
+
+ if (!error.Success())
+ {
+ // We got an error through our callback!
+ return;
+ }
+
+ if (!function)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't find '%s' in the JITted module", m_name.AsCString());
+ return;
+ }
+
+ if (!fun_ptr)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("'%s' was in the JITted module but wasn't lowered", m_name.AsCString());
+ return;
+ }
+
+ m_jitted_functions.push_back (JittedFunction(m_name.AsCString(), (lldb::addr_t)fun_ptr));
+
+ CommitAllocations(process_sp);
+ ReportAllocations(*m_execution_engine_ap);
+ WriteData(process_sp);
+
+ for (JittedFunction &jitted_function : m_jitted_functions)
+ {
+ jitted_function.m_remote_addr = GetRemoteAddressForLocal (jitted_function.m_local_addr);
+
+ if (!jitted_function.m_name.compare(m_name.AsCString()))
+ {
+ AddrRange func_range = GetRemoteRangeForLocal(jitted_function.m_local_addr);
+ m_function_end_load_addr = func_range.first + func_range.second;
+ m_function_load_addr = jitted_function.m_remote_addr;
+ }
+ }
+
+ if (log)
+ {
+ log->Printf("Code can be run in the target.");
+
+ StreamString disassembly_stream;
+
+ Error err = DisassembleFunction(disassembly_stream, process_sp);
+
+ if (!err.Success())
+ {
+ log->Printf("Couldn't disassemble function : %s", err.AsCString("unknown error"));
+ }
+ else
+ {
+ log->Printf("Function disassembly:\n%s", disassembly_stream.GetData());
+ }
+ }
+
+ func_addr = m_function_load_addr;
+ func_end = m_function_end_load_addr;
+
+ return;
+}
+
+IRExecutionUnit::~IRExecutionUnit ()
+{
+ m_module_ap.reset();
+ m_execution_engine_ap.reset();
+ m_context_ap.reset();
+}
+
+IRExecutionUnit::MemoryManager::MemoryManager (IRExecutionUnit &parent) :
+ m_default_mm_ap (llvm::JITMemoryManager::CreateDefaultMemManager()),
+ m_parent (parent)
+{
+}
+
+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,
+ StubSize,
+ Alignment));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateStub (F=%p, StubSize=%u, Alignment=%u) = %p",
+ F, StubSize, Alignment, 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);
+}
+
+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,
+ Size,
+ Alignment));
+
+ 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)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateCodeSection(Size, Alignment, SectionID);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsExecutable,
+ Size,
+ Alignment,
+ SectionID));
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateCodeSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
+ (uint64_t)Size, Alignment, SectionID, return_value);
+ }
+
+ return return_value;
+}
+
+uint8_t *
+IRExecutionUnit::MemoryManager::allocateDataSection(uintptr_t Size,
+ unsigned Alignment,
+ unsigned SectionID,
+ bool IsReadOnly)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ uint8_t *return_value = m_default_mm_ap->allocateDataSection(Size, Alignment, SectionID, IsReadOnly);
+
+ m_parent.m_records.push_back(AllocationRecord((uintptr_t)return_value,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ Size,
+ Alignment,
+ SectionID));
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::allocateDataSection(Size=0x%" PRIx64 ", Alignment=%u, SectionID=%u) = %p",
+ (uint64_t)Size, Alignment, SectionID, return_value);
+ }
+
+ 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,
+ Size,
+ Alignment));
+
+ 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)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (AllocationRecord &record : m_records)
+ {
+ if (local_address >= record.m_host_address &&
+ local_address < record.m_host_address + record.m_size)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t ret = record.m_process_address + (local_address - record.m_host_address);
+
+ if (log)
+ {
+ log->Printf("IRExecutionUnit::GetRemoteAddressForLocal() found 0x%" PRIx64 " in [0x%" PRIx64 "..0x%" PRIx64 "], and returned 0x%" PRIx64 " from [0x%" PRIx64 "..0x%" PRIx64 "].",
+ local_address,
+ (uint64_t)record.m_host_address,
+ (uint64_t)record.m_host_address + (uint64_t)record.m_size,
+ ret,
+ record.m_process_address,
+ record.m_process_address + record.m_size);
+ }
+
+ return ret;
+ }
+ }
+
+ return LLDB_INVALID_ADDRESS;
+}
+
+IRExecutionUnit::AddrRange
+IRExecutionUnit::GetRemoteRangeForLocal (lldb::addr_t local_address)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (local_address >= record.m_host_address &&
+ local_address < record.m_host_address + record.m_size)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return AddrRange(0, 0);
+
+ return AddrRange(record.m_process_address, record.m_size);
+ }
+ }
+
+ return AddrRange (0, 0);
+}
+
+bool
+IRExecutionUnit::CommitAllocations (lldb::ProcessSP &process_sp)
+{
+ bool ret = true;
+
+ lldb_private::Error err;
+
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address != LLDB_INVALID_ADDRESS)
+ continue;
+
+
+ record.m_process_address = Malloc(record.m_size,
+ record.m_alignment,
+ record.m_permissions,
+ eAllocationPolicyProcessOnly,
+ err);
+
+ if (!err.Success())
+ {
+ ret = false;
+ break;
+ }
+ }
+
+ if (!ret)
+ {
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address != LLDB_INVALID_ADDRESS)
+ {
+ Free(record.m_process_address, err);
+ record.m_process_address = LLDB_INVALID_ADDRESS;
+ }
+ }
+ }
+
+ return ret;
+}
+
+void
+IRExecutionUnit::ReportAllocations (llvm::ExecutionEngine &engine)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ continue;
+
+ if (record.m_section_id == eSectionIDInvalid)
+ continue;
+
+ engine.mapSectionAddress((void*)record.m_host_address, record.m_process_address);
+ }
+
+ // Trigger re-application of relocations.
+ engine.finalizeObject();
+}
+
+bool
+IRExecutionUnit::WriteData (lldb::ProcessSP &process_sp)
+{
+ for (AllocationRecord &record : m_records)
+ {
+ if (record.m_process_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Error err;
+
+ WriteMemory (record.m_process_address, (uint8_t*)record.m_host_address, record.m_size, err);
+ }
+
+ return true;
+}
+
+void
+IRExecutionUnit::AllocationRecord::dump (Log *log)
+{
+ if (!log)
+ return;
+
+ log->Printf("[0x%llx+0x%llx]->0x%llx (alignment %d, section ID %d)",
+ (unsigned long long)m_host_address,
+ (unsigned long long)m_size,
+ (unsigned long long)m_process_address,
+ (unsigned)m_alignment,
+ (unsigned)m_section_id);
+}
diff --git a/source/Expression/IRForTarget.cpp b/source/Expression/IRForTarget.cpp
new file mode 100644
index 000000000000..cac3fdf60dfa
--- /dev/null
+++ b/source/Expression/IRForTarget.cpp
@@ -0,0 +1,2879 @@
+//===-- IRForTarget.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/Expression/IRForTarget.h"
+
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/Module.h"
+#include "llvm/PassManager.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/IR/ValueSymbolTable.h"
+
+#include "clang/AST/ASTContext.h"
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangExpressionDeclMap.h"
+#include "lldb/Expression/IRExecutionUnit.h"
+#include "lldb/Expression/IRInterpreter.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTType.h"
+
+#include <map>
+
+using namespace llvm;
+
+static char ID;
+
+IRForTarget::StaticDataAllocator::StaticDataAllocator(lldb_private::IRExecutionUnit &execution_unit) :
+ m_execution_unit(execution_unit),
+ m_stream_string(lldb_private::Stream::eBinary, execution_unit.GetAddressByteSize(), execution_unit.GetByteOrder()),
+ m_allocation(LLDB_INVALID_ADDRESS)
+{
+}
+
+IRForTarget::FunctionValueCache::FunctionValueCache(Maker const &maker) :
+ m_maker(maker),
+ m_values()
+{
+}
+
+IRForTarget::FunctionValueCache::~FunctionValueCache()
+{
+}
+
+llvm::Value *IRForTarget::FunctionValueCache::GetValue(llvm::Function *function)
+{
+ if (!m_values.count(function))
+ {
+ llvm::Value *ret = m_maker(function);
+ m_values[function] = ret;
+ return ret;
+ }
+ return m_values[function];
+}
+
+lldb::addr_t IRForTarget::StaticDataAllocator::Allocate()
+{
+ lldb_private::Error err;
+
+ if (m_allocation != LLDB_INVALID_ADDRESS)
+ {
+ m_execution_unit.FreeNow(m_allocation);
+ m_allocation = LLDB_INVALID_ADDRESS;
+ }
+
+ m_allocation = m_execution_unit.WriteNow((const uint8_t*)m_stream_string.GetData(), m_stream_string.GetSize(), err);
+
+ return m_allocation;
+}
+
+static llvm::Value *FindEntryInstruction (llvm::Function *function)
+{
+ if (function->empty())
+ return NULL;
+
+ return function->getEntryBlock().getFirstNonPHIOrDbg();
+}
+
+IRForTarget::IRForTarget (lldb_private::ClangExpressionDeclMap *decl_map,
+ bool resolve_vars,
+ lldb_private::IRExecutionUnit &execution_unit,
+ lldb_private::Stream *error_stream,
+ const char *func_name) :
+ ModulePass(ID),
+ m_resolve_vars(resolve_vars),
+ m_func_name(func_name),
+ m_module(NULL),
+ m_decl_map(decl_map),
+ m_data_allocator(execution_unit),
+ m_CFStringCreateWithBytes(NULL),
+ m_sel_registerName(NULL),
+ m_error_stream(error_stream),
+ m_result_store(NULL),
+ m_result_is_pointer(false),
+ m_reloc_placeholder(NULL),
+ m_entry_instruction_finder (FindEntryInstruction)
+{
+}
+
+/* Handy utility functions used at several places in the code */
+
+static std::string
+PrintValue(const Value *value, bool truncate = false)
+{
+ std::string s;
+ if (value)
+ {
+ raw_string_ostream rso(s);
+ value->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ }
+ return s;
+}
+
+static std::string
+PrintType(const llvm::Type *type, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ type->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+IRForTarget::~IRForTarget()
+{
+}
+
+bool
+IRForTarget::FixFunctionLinkage(llvm::Function &llvm_function)
+{
+ llvm_function.setLinkage(GlobalValue::ExternalLinkage);
+
+ std::string name = llvm_function.getName().str();
+
+ return true;
+}
+
+bool
+IRForTarget::GetFunctionAddress (llvm::Function *fun,
+ uint64_t &fun_addr,
+ lldb_private::ConstString &name,
+ Constant **&value_ptr)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ fun_addr = LLDB_INVALID_ADDRESS;
+ name.Clear();
+ value_ptr = NULL;
+
+ if (fun->isIntrinsic())
+ {
+ Intrinsic::ID intrinsic_id = (Intrinsic::ID)fun->getIntrinsicID();
+
+ switch (intrinsic_id)
+ {
+ default:
+ if (log)
+ log->Printf("Unresolved intrinsic \"%s\"", Intrinsic::getName(intrinsic_id).c_str());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Call to unhandled compiler intrinsic '%s'\n", Intrinsic::getName(intrinsic_id).c_str());
+
+ return false;
+ case Intrinsic::memcpy:
+ {
+ static lldb_private::ConstString g_memcpy_str ("memcpy");
+ name = g_memcpy_str;
+ }
+ break;
+ case Intrinsic::memset:
+ {
+ static lldb_private::ConstString g_memset_str ("memset");
+ name = g_memset_str;
+ }
+ break;
+ }
+
+ if (log && name)
+ log->Printf("Resolved intrinsic name \"%s\"", name.GetCString());
+ }
+ else
+ {
+ name.SetCStringWithLength (fun->getName().data(), fun->getName().size());
+ }
+
+ // Find the address of the function.
+
+ clang::NamedDecl *fun_decl = DeclForGlobal (fun);
+
+ if (fun_decl)
+ {
+ if (!m_decl_map->GetFunctionInfo (fun_decl, fun_addr))
+ {
+ lldb_private::ConstString altnernate_name;
+ bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr);
+ if (!found_it)
+ {
+ // Check for an alternate mangling for "std::basic_string<char>"
+ // that is part of the itanium C++ name mangling scheme
+ const char *name_cstr = name.GetCString();
+ if (name_cstr && strncmp(name_cstr, "_ZNKSbIcE", strlen("_ZNKSbIcE")) == 0)
+ {
+ std::string alternate_mangling("_ZNKSs");
+ alternate_mangling.append (name_cstr + strlen("_ZNKSbIcE"));
+ altnernate_name.SetCString(alternate_mangling.c_str());
+ found_it = m_decl_map->GetFunctionAddress (altnernate_name, fun_addr);
+ }
+ }
+
+ if (!found_it)
+ {
+ lldb_private::Mangled mangled_name(name);
+ lldb_private::Mangled alt_mangled_name(altnernate_name);
+ if (log)
+ {
+ if (alt_mangled_name)
+ log->Printf("Function \"%s\" (alternate name \"%s\") has no address",
+ mangled_name.GetName().GetCString(),
+ alt_mangled_name.GetName().GetCString());
+ else
+ log->Printf("Function \"%s\" had no address",
+ mangled_name.GetName().GetCString());
+ }
+
+ if (m_error_stream)
+ {
+ if (alt_mangled_name)
+ m_error_stream->Printf("error: call to a function '%s' (alternate name '%s') that is not present in the target\n",
+ mangled_name.GetName().GetCString(),
+ alt_mangled_name.GetName().GetCString());
+ else if (mangled_name.GetMangledName())
+ m_error_stream->Printf("error: call to a function '%s' ('%s') that is not present in the target\n",
+ mangled_name.GetName().GetCString(),
+ mangled_name.GetMangledName().GetCString());
+ else
+ m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n",
+ mangled_name.GetName().GetCString());
+ }
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (!m_decl_map->GetFunctionAddress (name, fun_addr))
+ {
+ if (log)
+ log->Printf ("Metadataless function \"%s\" had no address", name.GetCString());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Call to a symbol-only function '%s' that is not present in the target\n", name.GetCString());
+
+ return false;
+ }
+ }
+
+ if (log)
+ log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), fun_addr);
+
+ return true;
+}
+
+llvm::Constant *
+IRForTarget::BuildFunctionPointer (llvm::Type *type,
+ uint64_t ptr)
+{
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+ PointerType *fun_ptr_ty = PointerType::getUnqual(type);
+ Constant *fun_addr_int = ConstantInt::get(intptr_ty, ptr, false);
+ return ConstantExpr::getIntToPtr(fun_addr_int, fun_ptr_ty);
+}
+
+void
+IRForTarget::RegisterFunctionMetadata(LLVMContext &context,
+ llvm::Value *function_ptr,
+ const char *name)
+{
+ for (Value::use_iterator i = function_ptr->use_begin(), e = function_ptr->use_end();
+ i != e;
+ ++i)
+ {
+ Value *user = *i;
+
+ if (Instruction *user_inst = dyn_cast<Instruction>(user))
+ {
+ MDString* md_name = MDString::get(context, StringRef(name));
+
+ MDNode *metadata = MDNode::get(context, md_name);
+
+ user_inst->setMetadata("lldb.call.realName", metadata);
+ }
+ else
+ {
+ RegisterFunctionMetadata (context, user, name);
+ }
+ }
+}
+
+bool
+IRForTarget::ResolveFunctionPointers(llvm::Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (llvm::Module::iterator fi = llvm_module.begin();
+ fi != llvm_module.end();
+ ++fi)
+ {
+ Function *fun = fi;
+
+ bool is_decl = fun->isDeclaration();
+
+ if (log)
+ log->Printf("Examining %s function %s", (is_decl ? "declaration" : "non-declaration"), fun->getName().str().c_str());
+
+ if (!is_decl)
+ continue;
+
+ if (fun->hasNUses(0))
+ continue; // ignore
+
+ uint64_t addr = LLDB_INVALID_ADDRESS;
+ lldb_private::ConstString name;
+ Constant **value_ptr = NULL;
+
+ if (!GetFunctionAddress(fun,
+ addr,
+ name,
+ value_ptr))
+ return false; // GetFunctionAddress reports its own errors
+
+ Constant *value = BuildFunctionPointer(fun->getFunctionType(), addr);
+
+ RegisterFunctionMetadata (llvm_module.getContext(), fun, name.AsCString());
+
+ if (value_ptr)
+ *value_ptr = value;
+
+ // If we are replacing a function with the nobuiltin attribute, it may
+ // be called with the builtin attribute on call sites. Remove any such
+ // attributes since it's illegal to have a builtin call to something
+ // other than a nobuiltin function.
+ if (fun->hasFnAttribute(Attribute::NoBuiltin)) {
+ Attribute builtin = Attribute::get(fun->getContext(), Attribute::Builtin);
+
+ for (auto u = fun->use_begin(), e = fun->use_end(); u != e; ++u) {
+ if (auto call = dyn_cast<CallInst>(*u)) {
+ call->removeAttribute(AttributeSet::FunctionIndex, builtin);
+ }
+ }
+ }
+
+ fun->replaceAllUsesWith(value);
+ }
+
+ return true;
+}
+
+
+clang::NamedDecl *
+IRForTarget::DeclForGlobal (const GlobalValue *global_val, Module *module)
+{
+ NamedMDNode *named_metadata = module->getNamedMetadata("clang.global.decl.ptrs");
+
+ if (!named_metadata)
+ return NULL;
+
+ unsigned num_nodes = named_metadata->getNumOperands();
+ unsigned node_index;
+
+ for (node_index = 0;
+ node_index < num_nodes;
+ ++node_index)
+ {
+ MDNode *metadata_node = named_metadata->getOperand(node_index);
+
+ if (!metadata_node)
+ return NULL;
+
+ if (metadata_node->getNumOperands() != 2)
+ continue;
+
+ if (metadata_node->getOperand(0) != global_val)
+ continue;
+
+ ConstantInt *constant_int = dyn_cast<ConstantInt>(metadata_node->getOperand(1));
+
+ if (!constant_int)
+ return NULL;
+
+ uintptr_t ptr = constant_int->getZExtValue();
+
+ return reinterpret_cast<clang::NamedDecl *>(ptr);
+ }
+
+ return NULL;
+}
+
+clang::NamedDecl *
+IRForTarget::DeclForGlobal (GlobalValue *global_val)
+{
+ return DeclForGlobal(global_val, m_module);
+}
+
+bool
+IRForTarget::CreateResultVariable (llvm::Function &llvm_function)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!m_resolve_vars)
+ return true;
+
+ // Find the result variable. If it doesn't exist, we can give up right here.
+
+ ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
+
+ std::string result_name_str;
+ const char *result_name = NULL;
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ result_name_str = vi->first().str();
+ const char *value_name = result_name_str.c_str();
+
+ if (strstr(value_name, "$__lldb_expr_result_ptr") &&
+ strncmp(value_name, "_ZGV", 4))
+ {
+ result_name = value_name;
+ m_result_is_pointer = true;
+ break;
+ }
+
+ if (strstr(value_name, "$__lldb_expr_result") &&
+ strncmp(value_name, "_ZGV", 4))
+ {
+ result_name = value_name;
+ m_result_is_pointer = false;
+ break;
+ }
+ }
+
+ if (!result_name)
+ {
+ if (log)
+ log->PutCString("Couldn't find result variable");
+
+ return true;
+ }
+
+ if (log)
+ log->Printf("Result name: \"%s\"", result_name);
+
+ Value *result_value = m_module->getNamedValue(result_name);
+
+ if (!result_value)
+ {
+ if (log)
+ log->PutCString("Result variable had no data");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable's name (%s) exists, but not its definition\n", result_name);
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found result in the IR: \"%s\"", PrintValue(result_value, false).c_str());
+
+ GlobalVariable *result_global = dyn_cast<GlobalVariable>(result_value);
+
+ if (!result_global)
+ {
+ if (log)
+ log->PutCString("Result variable isn't a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) is defined, but is not a global variable\n", result_name);
+
+ return false;
+ }
+
+ clang::NamedDecl *result_decl = DeclForGlobal (result_global);
+ if (!result_decl)
+ {
+ if (log)
+ log->PutCString("Result variable doesn't have a corresponding Decl");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) does not have a corresponding Clang entity\n", result_name);
+
+ return false;
+ }
+
+ if (log)
+ {
+ std::string decl_desc_str;
+ raw_string_ostream decl_desc_stream(decl_desc_str);
+ result_decl->print(decl_desc_stream);
+ decl_desc_stream.flush();
+
+ log->Printf("Found result decl: \"%s\"", decl_desc_str.c_str());
+ }
+
+ clang::VarDecl *result_var = dyn_cast<clang::VarDecl>(result_decl);
+ if (!result_var)
+ {
+ if (log)
+ log->PutCString("Result variable Decl isn't a VarDecl");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s)'s corresponding Clang entity isn't a variable\n", result_name);
+
+ return false;
+ }
+
+ // Get the next available result name from m_decl_map and create the persistent
+ // variable for it
+
+ // If the result is an Lvalue, it is emitted as a pointer; see
+ // ASTResultSynthesizer::SynthesizeBodyResult.
+ if (m_result_is_pointer)
+ {
+ clang::QualType pointer_qual_type = result_var->getType();
+ const clang::Type *pointer_type = pointer_qual_type.getTypePtr();
+
+ const clang::PointerType *pointer_pointertype = pointer_type->getAs<clang::PointerType>();
+ const clang::ObjCObjectPointerType *pointer_objcobjpointertype = pointer_type->getAs<clang::ObjCObjectPointerType>();
+
+ if (pointer_pointertype)
+ {
+ clang::QualType element_qual_type = pointer_pointertype->getPointeeType();
+
+ m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
+ &result_decl->getASTContext());
+ }
+ else if (pointer_objcobjpointertype)
+ {
+ clang::QualType element_qual_type = clang::QualType(pointer_objcobjpointertype->getObjectType(), 0);
+
+ m_result_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(),
+ &result_decl->getASTContext());
+ }
+ else
+ {
+ if (log)
+ log->PutCString("Expected result to have pointer type, but it did not");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Lvalue result (%s) is not a pointer variable\n", result_name);
+
+ return false;
+ }
+ }
+ else
+ {
+ m_result_type = lldb_private::TypeFromParser(result_var->getType().getAsOpaquePtr(),
+ &result_decl->getASTContext());
+ }
+
+ if (m_result_type.GetBitSize() == 0)
+ {
+ lldb_private::StreamString type_desc_stream;
+ m_result_type.DumpTypeDescription(&type_desc_stream);
+
+ if (log)
+ log->Printf("Result type has size 0");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Size of result type '%s' couldn't be determined\n",
+ type_desc_stream.GetData());
+ return false;
+ }
+
+ if (log)
+ {
+ lldb_private::StreamString type_desc_stream;
+ m_result_type.DumpTypeDescription(&type_desc_stream);
+
+ log->Printf("Result decl type: \"%s\"", type_desc_stream.GetData());
+ }
+
+ m_result_name = lldb_private::ConstString("$RESULT_NAME");
+
+ if (log)
+ log->Printf("Creating a new result global: \"%s\" with size 0x%" PRIx64,
+ m_result_name.GetCString(),
+ m_result_type.GetByteSize());
+
+ // Construct a new result global and set up its metadata
+
+ GlobalVariable *new_result_global = new GlobalVariable((*m_module),
+ result_global->getType()->getElementType(),
+ false, /* not constant */
+ GlobalValue::ExternalLinkage,
+ NULL, /* no initializer */
+ m_result_name.GetCString ());
+
+ // It's too late in compilation to create a new VarDecl for this, but we don't
+ // need to. We point the metadata at the old VarDecl. This creates an odd
+ // anomaly: a variable with a Value whose name is something like $0 and a
+ // Decl whose name is $__lldb_expr_result. This condition is handled in
+ // ClangExpressionDeclMap::DoMaterialize, and the name of the variable is
+ // fixed up.
+
+ ConstantInt *new_constant_int = ConstantInt::get(llvm::Type::getInt64Ty(m_module->getContext()),
+ reinterpret_cast<uint64_t>(result_decl),
+ false);
+
+ llvm::Value* values[2];
+ values[0] = new_result_global;
+ values[1] = new_constant_int;
+
+ ArrayRef<Value*> value_ref(values, 2);
+
+ MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
+ NamedMDNode *named_metadata = m_module->getNamedMetadata("clang.global.decl.ptrs");
+ named_metadata->addOperand(persistent_global_md);
+
+ if (log)
+ log->Printf("Replacing \"%s\" with \"%s\"",
+ PrintValue(result_global).c_str(),
+ PrintValue(new_result_global).c_str());
+
+ if (result_global->hasNUses(0))
+ {
+ // We need to synthesize a store for this variable, because otherwise
+ // there's nothing to put into its equivalent persistent variable.
+
+ BasicBlock &entry_block(llvm_function.getEntryBlock());
+ Instruction *first_entry_instruction(entry_block.getFirstNonPHIOrDbg());
+
+ if (!first_entry_instruction)
+ return false;
+
+ if (!result_global->hasInitializer())
+ {
+ if (log)
+ log->Printf("Couldn't find initializer for unused variable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Result variable (%s) has no writes and no initializer\n", result_name);
+
+ return false;
+ }
+
+ Constant *initializer = result_global->getInitializer();
+
+ StoreInst *synthesized_store = new StoreInst(initializer,
+ new_result_global,
+ first_entry_instruction);
+
+ if (log)
+ log->Printf("Synthesized result store \"%s\"\n", PrintValue(synthesized_store).c_str());
+ }
+ else
+ {
+ result_global->replaceAllUsesWith(new_result_global);
+ }
+
+ if (!m_decl_map->AddPersistentVariable(result_decl,
+ m_result_name,
+ m_result_type,
+ true,
+ m_result_is_pointer))
+ return false;
+
+ result_global->eraseFromParent();
+
+ return true;
+}
+
+#if 0
+static void DebugUsers(Log *log, Value *value, uint8_t depth)
+{
+ if (!depth)
+ return;
+
+ depth--;
+
+ if (log)
+ log->Printf(" <Begin %d users>", value->getNumUses());
+
+ for (Value::use_iterator ui = value->use_begin(), ue = value->use_end();
+ ui != ue;
+ ++ui)
+ {
+ if (log)
+ log->Printf(" <Use %p> %s", *ui, PrintValue(*ui).c_str());
+ DebugUsers(log, *ui, depth);
+ }
+
+ if (log)
+ log->Printf(" <End uses>");
+}
+#endif
+
+bool
+IRForTarget::RewriteObjCConstString (llvm::GlobalVariable *ns_str,
+ llvm::GlobalVariable *cstr)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Type *ns_str_ty = ns_str->getType();
+
+ Type *i8_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize()
+ == Module::Pointer64) ? 64 : 32);
+ Type *i32_ty = Type::getInt32Ty(m_module->getContext());
+ Type *i8_ty = Type::getInt8Ty(m_module->getContext());
+
+ if (!m_CFStringCreateWithBytes)
+ {
+ lldb::addr_t CFStringCreateWithBytes_addr;
+
+ static lldb_private::ConstString g_CFStringCreateWithBytes_str ("CFStringCreateWithBytes");
+
+ if (!m_decl_map->GetFunctionAddress (g_CFStringCreateWithBytes_str, CFStringCreateWithBytes_addr))
+ {
+ if (log)
+ log->PutCString("Couldn't find CFStringCreateWithBytes in the target");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Rewriting an Objective-C constant string requires CFStringCreateWithBytes\n");
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found CFStringCreateWithBytes at 0x%" PRIx64, CFStringCreateWithBytes_addr);
+
+ // Build the function type:
+ //
+ // CFStringRef CFStringCreateWithBytes (
+ // CFAllocatorRef alloc,
+ // const UInt8 *bytes,
+ // CFIndex numBytes,
+ // CFStringEncoding encoding,
+ // Boolean isExternalRepresentation
+ // );
+ //
+ // We make the following substitutions:
+ //
+ // CFStringRef -> i8*
+ // CFAllocatorRef -> i8*
+ // UInt8 * -> i8*
+ // CFIndex -> long (i32 or i64, as appropriate; we ask the module for its pointer size for now)
+ // CFStringEncoding -> i32
+ // Boolean -> i8
+
+ Type *arg_type_array[5];
+
+ arg_type_array[0] = i8_ptr_ty;
+ arg_type_array[1] = i8_ptr_ty;
+ arg_type_array[2] = intptr_ty;
+ arg_type_array[3] = i32_ty;
+ arg_type_array[4] = i8_ty;
+
+ ArrayRef<Type *> CFSCWB_arg_types(arg_type_array, 5);
+
+ llvm::Type *CFSCWB_ty = FunctionType::get(ns_str_ty, CFSCWB_arg_types, false);
+
+ // Build the constant containing the pointer to the function
+ PointerType *CFSCWB_ptr_ty = PointerType::getUnqual(CFSCWB_ty);
+ Constant *CFSCWB_addr_int = ConstantInt::get(intptr_ty, CFStringCreateWithBytes_addr, false);
+ m_CFStringCreateWithBytes = ConstantExpr::getIntToPtr(CFSCWB_addr_int, CFSCWB_ptr_ty);
+ }
+
+ ConstantDataSequential *string_array = NULL;
+
+ if (cstr)
+ string_array = dyn_cast<ConstantDataSequential>(cstr->getInitializer());
+
+ Constant *alloc_arg = Constant::getNullValue(i8_ptr_ty);
+ Constant *bytes_arg = cstr ? ConstantExpr::getBitCast(cstr, i8_ptr_ty) : Constant::getNullValue(i8_ptr_ty);
+ Constant *numBytes_arg = ConstantInt::get(intptr_ty, cstr ? string_array->getNumElements() - 1 : 0, false);
+ Constant *encoding_arg = ConstantInt::get(i32_ty, 0x0600, false); /* 0x0600 is kCFStringEncodingASCII */
+ Constant *isExternal_arg = ConstantInt::get(i8_ty, 0x0, false); /* 0x0 is false */
+
+ Value *argument_array[5];
+
+ argument_array[0] = alloc_arg;
+ argument_array[1] = bytes_arg;
+ argument_array[2] = numBytes_arg;
+ argument_array[3] = encoding_arg;
+ argument_array[4] = isExternal_arg;
+
+ ArrayRef <Value *> CFSCWB_arguments(argument_array, 5);
+
+ FunctionValueCache CFSCWB_Caller ([this, &CFSCWB_arguments] (llvm::Function *function)->llvm::Value * {
+ return CallInst::Create(m_CFStringCreateWithBytes,
+ CFSCWB_arguments,
+ "CFStringCreateWithBytes",
+ llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(ns_str, CFSCWB_Caller, m_entry_instruction_finder))
+ {
+ if (log)
+ log->PutCString("Couldn't replace the NSString with the result of the call");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Couldn't replace an Objective-C constant string with a dynamic string\n");
+
+ return false;
+ }
+
+ ns_str->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::RewriteObjCConstStrings()
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ ValueSymbolTable& value_symbol_table = m_module->getValueSymbolTable();
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ std::string value_name = vi->first().str();
+ const char *value_name_cstr = value_name.c_str();
+
+ if (strstr(value_name_cstr, "_unnamed_cfstring_"))
+ {
+ Value *nsstring_value = vi->second;
+
+ GlobalVariable *nsstring_global = dyn_cast<GlobalVariable>(nsstring_value);
+
+ if (!nsstring_global)
+ {
+ if (log)
+ log->PutCString("NSString variable is not a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a global variable\n");
+
+ return false;
+ }
+
+ if (!nsstring_global->hasInitializer())
+ {
+ if (log)
+ log->PutCString("NSString variable does not have an initializer");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have an initializer\n");
+
+ return false;
+ }
+
+ ConstantStruct *nsstring_struct = dyn_cast<ConstantStruct>(nsstring_global->getInitializer());
+
+ if (!nsstring_struct)
+ {
+ if (log)
+ log->PutCString("NSString variable's initializer is not a ConstantStruct");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string is not a structure constant\n");
+
+ return false;
+ }
+
+ // We expect the following structure:
+ //
+ // struct {
+ // int *isa;
+ // int flags;
+ // char *str;
+ // long length;
+ // };
+
+ if (nsstring_struct->getNumOperands() != 4)
+ {
+ if (log)
+ log->Printf("NSString variable's initializer structure has an unexpected number of members. Should be 4, is %d", nsstring_struct->getNumOperands());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: The struct for an Objective-C constant string is not as expected\n");
+
+ return false;
+ }
+
+ Constant *nsstring_member = nsstring_struct->getOperand(2);
+
+ if (!nsstring_member)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element was empty");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string does not have a string initializer\n");
+
+ return false;
+ }
+
+ ConstantExpr *nsstring_expr = dyn_cast<ConstantExpr>(nsstring_member);
+
+ if (!nsstring_expr)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a ConstantExpr");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not constant\n");
+
+ return false;
+ }
+
+ if (nsstring_expr->getOpcode() != Instruction::GetElementPtr)
+ {
+ if (log)
+ log->Printf("NSString initializer's str element is not a GetElementPtr expression, it's a %s", nsstring_expr->getOpcodeName());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer is not an array\n");
+
+ return false;
+ }
+
+ Constant *nsstring_cstr = nsstring_expr->getOperand(0);
+
+ GlobalVariable *cstr_global = dyn_cast<GlobalVariable>(nsstring_cstr);
+
+ if (!cstr_global)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a GlobalVariable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a global\n");
+
+ return false;
+ }
+
+ if (!cstr_global->hasInitializer())
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element does not have an initializer");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to initialized data\n");
+
+ return false;
+ }
+
+ /*
+ if (!cstr_array)
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a ConstantArray");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to an array\n");
+
+ return false;
+ }
+
+ if (!cstr_array->isCString())
+ {
+ if (log)
+ log->PutCString("NSString initializer's str element is not a C string array");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: An Objective-C constant string's string initializer doesn't point to a C string\n");
+
+ return false;
+ }
+ */
+
+ ConstantDataArray *cstr_array = dyn_cast<ConstantDataArray>(cstr_global->getInitializer());
+
+ if (log)
+ {
+ if (cstr_array)
+ log->Printf("Found NSString constant %s, which contains \"%s\"", value_name_cstr, cstr_array->getAsString().str().c_str());
+ else
+ log->Printf("Found NSString constant %s, which contains \"\"", value_name_cstr);
+ }
+
+ if (!cstr_array)
+ cstr_global = NULL;
+
+ if (!RewriteObjCConstString(nsstring_global, cstr_global))
+ {
+ if (log)
+ log->PutCString("Error rewriting the constant string");
+
+ // We don't print an error message here because RewriteObjCConstString has done so for us.
+
+ return false;
+ }
+ }
+ }
+
+ for (ValueSymbolTable::iterator vi = value_symbol_table.begin(), ve = value_symbol_table.end();
+ vi != ve;
+ ++vi)
+ {
+ std::string value_name = vi->first().str();
+ const char *value_name_cstr = value_name.c_str();
+
+ if (!strcmp(value_name_cstr, "__CFConstantStringClassReference"))
+ {
+ GlobalVariable *gv = dyn_cast<GlobalVariable>(vi->second);
+
+ if (!gv)
+ {
+ if (log)
+ log->PutCString("__CFConstantStringClassReference is not a global variable");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Found a CFConstantStringClassReference, but it is not a global object\n");
+
+ return false;
+ }
+
+ gv->eraseFromParent();
+
+ break;
+ }
+ }
+
+ return true;
+}
+
+static bool IsObjCSelectorRef (Value *value)
+{
+ GlobalVariable *global_variable = dyn_cast<GlobalVariable>(value);
+
+ if (!global_variable || !global_variable->hasName() || !global_variable->getName().startswith("\01L_OBJC_SELECTOR_REFERENCES_"))
+ return false;
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::RewriteObjCSelector (Instruction* selector_load)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ LoadInst *load = dyn_cast<LoadInst>(selector_load);
+
+ if (!load)
+ return false;
+
+ // Unpack the message name from the selector. In LLVM IR, an objc_msgSend gets represented as
+ //
+ // %tmp = load i8** @"\01L_OBJC_SELECTOR_REFERENCES_" ; <i8*>
+ // %call = call i8* (i8*, i8*, ...)* @objc_msgSend(i8* %obj, i8* %tmp, ...) ; <i8*>
+ //
+ // where %obj is the object pointer and %tmp is the selector.
+ //
+ // @"\01L_OBJC_SELECTOR_REFERENCES_" is a pointer to a character array called @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_".
+ // @"\01L_OBJC_llvm_moduleETH_VAR_NAllvm_moduleE_" contains the string.
+
+ // Find the pointer's initializer (a ConstantExpr with opcode GetElementPtr) and get the string from its target
+
+ GlobalVariable *_objc_selector_references_ = dyn_cast<GlobalVariable>(load->getPointerOperand());
+
+ if (!_objc_selector_references_ || !_objc_selector_references_->hasInitializer())
+ return false;
+
+ Constant *osr_initializer = _objc_selector_references_->getInitializer();
+
+ ConstantExpr *osr_initializer_expr = dyn_cast<ConstantExpr>(osr_initializer);
+
+ if (!osr_initializer_expr || osr_initializer_expr->getOpcode() != Instruction::GetElementPtr)
+ return false;
+
+ Value *osr_initializer_base = osr_initializer_expr->getOperand(0);
+
+ if (!osr_initializer_base)
+ return false;
+
+ // Find the string's initializer (a ConstantArray) and get the string from it
+
+ GlobalVariable *_objc_meth_var_name_ = dyn_cast<GlobalVariable>(osr_initializer_base);
+
+ if (!_objc_meth_var_name_ || !_objc_meth_var_name_->hasInitializer())
+ return false;
+
+ Constant *omvn_initializer = _objc_meth_var_name_->getInitializer();
+
+ ConstantDataArray *omvn_initializer_array = dyn_cast<ConstantDataArray>(omvn_initializer);
+
+ if (!omvn_initializer_array->isString())
+ return false;
+
+ std::string omvn_initializer_string = omvn_initializer_array->getAsString();
+
+ if (log)
+ log->Printf("Found Objective-C selector reference \"%s\"", omvn_initializer_string.c_str());
+
+ // Construct a call to sel_registerName
+
+ if (!m_sel_registerName)
+ {
+ lldb::addr_t sel_registerName_addr;
+
+ static lldb_private::ConstString g_sel_registerName_str ("sel_registerName");
+ if (!m_decl_map->GetFunctionAddress (g_sel_registerName_str, sel_registerName_addr))
+ return false;
+
+ if (log)
+ log->Printf("Found sel_registerName at 0x%" PRIx64, sel_registerName_addr);
+
+ // Build the function type: struct objc_selector *sel_registerName(uint8_t*)
+
+ // The below code would be "more correct," but in actuality what's required is uint8_t*
+ //Type *sel_type = StructType::get(m_module->getContext());
+ //Type *sel_ptr_type = PointerType::getUnqual(sel_type);
+ Type *sel_ptr_type = Type::getInt8PtrTy(m_module->getContext());
+
+ Type *type_array[1];
+
+ type_array[0] = llvm::Type::getInt8PtrTy(m_module->getContext());
+
+ ArrayRef<Type *> srN_arg_types(type_array, 1);
+
+ llvm::Type *srN_type = FunctionType::get(sel_ptr_type, srN_arg_types, false);
+
+ // Build the constant containing the pointer to the function
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+ PointerType *srN_ptr_ty = PointerType::getUnqual(srN_type);
+ Constant *srN_addr_int = ConstantInt::get(intptr_ty, sel_registerName_addr, false);
+ m_sel_registerName = ConstantExpr::getIntToPtr(srN_addr_int, srN_ptr_ty);
+ }
+
+ Value *argument_array[1];
+
+ Constant *omvn_pointer = ConstantExpr::getBitCast(_objc_meth_var_name_, Type::getInt8PtrTy(m_module->getContext()));
+
+ argument_array[0] = omvn_pointer;
+
+ ArrayRef<Value *> srN_arguments(argument_array, 1);
+
+ CallInst *srN_call = CallInst::Create(m_sel_registerName,
+ srN_arguments,
+ "sel_registerName",
+ selector_load);
+
+ // Replace the load with the call in all users
+
+ selector_load->replaceAllUsesWith(srN_call);
+
+ selector_load->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::RewriteObjCSelectors (BasicBlock &basic_block)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList selector_loads;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (IsObjCSelectorRef(load->getPointerOperand()))
+ selector_loads.push_back(&inst);
+ }
+
+ InstrIterator iter;
+
+ for (iter = selector_loads.begin();
+ iter != selector_loads.end();
+ ++iter)
+ {
+ if (!RewriteObjCSelector(*iter))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't change a static reference to an Objective-C selector to a dynamic reference\n");
+
+ if (log)
+ log->PutCString("Couldn't rewrite a reference to an Objective-C selector");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ AllocaInst *alloc = dyn_cast<AllocaInst>(persistent_alloc);
+
+ MDNode *alloc_md = alloc->getMetadata("clang.decl.ptr");
+
+ if (!alloc_md || !alloc_md->getNumOperands())
+ return false;
+
+ ConstantInt *constant_int = dyn_cast<ConstantInt>(alloc_md->getOperand(0));
+
+ if (!constant_int)
+ return false;
+
+ // We attempt to register this as a new persistent variable with the DeclMap.
+
+ uintptr_t ptr = constant_int->getZExtValue();
+
+ clang::VarDecl *decl = reinterpret_cast<clang::VarDecl *>(ptr);
+
+ lldb_private::TypeFromParser result_decl_type (decl->getType().getAsOpaquePtr(),
+ &decl->getASTContext());
+
+ StringRef decl_name (decl->getName());
+ lldb_private::ConstString persistent_variable_name (decl_name.data(), decl_name.size());
+ if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false))
+ return false;
+
+ GlobalVariable *persistent_global = new GlobalVariable((*m_module),
+ alloc->getType(),
+ false, /* not constant */
+ GlobalValue::ExternalLinkage,
+ NULL, /* no initializer */
+ alloc->getName().str().c_str());
+
+ // What we're going to do here is make believe this was a regular old external
+ // variable. That means we need to make the metadata valid.
+
+ NamedMDNode *named_metadata = m_module->getOrInsertNamedMetadata("clang.global.decl.ptrs");
+
+ llvm::Value* values[2];
+ values[0] = persistent_global;
+ values[1] = constant_int;
+
+ ArrayRef<llvm::Value*> value_ref(values, 2);
+
+ MDNode *persistent_global_md = MDNode::get(m_module->getContext(), value_ref);
+ named_metadata->addOperand(persistent_global_md);
+
+ // Now, since the variable is a pointer variable, we will drop in a load of that
+ // pointer variable.
+
+ LoadInst *persistent_load = new LoadInst (persistent_global, "", alloc);
+
+ if (log)
+ log->Printf("Replacing \"%s\" with \"%s\"",
+ PrintValue(alloc).c_str(),
+ PrintValue(persistent_load).c_str());
+
+ alloc->replaceAllUsesWith(persistent_load);
+ alloc->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::RewritePersistentAllocs(llvm::BasicBlock &basic_block)
+{
+ if (!m_resolve_vars)
+ return true;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList pvar_allocs;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (AllocaInst *alloc = dyn_cast<AllocaInst>(&inst))
+ {
+ llvm::StringRef alloc_name = alloc->getName();
+
+ if (alloc_name.startswith("$") &&
+ !alloc_name.startswith("$__lldb"))
+ {
+ if (alloc_name.find_first_of("0123456789") == 1)
+ {
+ if (log)
+ log->Printf("Rejecting a numeric persistent variable.");
+
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Names starting with $0, $1, ... are reserved for use as result names\n");
+
+ return false;
+ }
+
+ pvar_allocs.push_back(alloc);
+ }
+ }
+ }
+
+ InstrIterator iter;
+
+ for (iter = pvar_allocs.begin();
+ iter != pvar_allocs.end();
+ ++iter)
+ {
+ if (!RewritePersistentAlloc(*iter))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite the creation of a persistent variable\n");
+
+ if (log)
+ log->PutCString("Couldn't rewrite the creation of a persistent variable");
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::MaterializeInitializer (uint8_t *data, Constant *initializer)
+{
+ if (!initializer)
+ return true;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log && log->GetVerbose())
+ log->Printf(" MaterializeInitializer(%p, %s)", data, PrintValue(initializer).c_str());
+
+ Type *initializer_type = initializer->getType();
+
+ if (ConstantInt *int_initializer = dyn_cast<ConstantInt>(initializer))
+ {
+ memcpy (data, int_initializer->getValue().getRawData(), m_target_data->getTypeStoreSize(initializer_type));
+ return true;
+ }
+ else if (ConstantDataArray *array_initializer = dyn_cast<ConstantDataArray>(initializer))
+ {
+ if (array_initializer->isString())
+ {
+ std::string array_initializer_string = array_initializer->getAsString();
+ memcpy (data, array_initializer_string.c_str(), m_target_data->getTypeStoreSize(initializer_type));
+ }
+ else
+ {
+ ArrayType *array_initializer_type = array_initializer->getType();
+ Type *array_element_type = array_initializer_type->getElementType();
+
+ size_t element_size = m_target_data->getTypeAllocSize(array_element_type);
+
+ for (unsigned i = 0; i < array_initializer->getNumOperands(); ++i)
+ {
+ Value *operand_value = array_initializer->getOperand(i);
+ Constant *operand_constant = dyn_cast<Constant>(operand_value);
+
+ if (!operand_constant)
+ return false;
+
+ if (!MaterializeInitializer(data + (i * element_size), operand_constant))
+ return false;
+ }
+ }
+ return true;
+ }
+ else if (ConstantStruct *struct_initializer = dyn_cast<ConstantStruct>(initializer))
+ {
+ StructType *struct_initializer_type = struct_initializer->getType();
+ const StructLayout *struct_layout = m_target_data->getStructLayout(struct_initializer_type);
+
+ for (unsigned i = 0;
+ i < struct_initializer->getNumOperands();
+ ++i)
+ {
+ if (!MaterializeInitializer(data + struct_layout->getElementOffset(i), struct_initializer->getOperand(i)))
+ return false;
+ }
+ return true;
+ }
+ else if (isa<ConstantAggregateZero>(initializer))
+ {
+ memset(data, 0, m_target_data->getTypeStoreSize(initializer_type));
+ return true;
+ }
+ return false;
+}
+
+bool
+IRForTarget::MaterializeInternalVariable (GlobalVariable *global_variable)
+{
+ if (GlobalVariable::isExternalLinkage(global_variable->getLinkage()))
+ return false;
+
+ if (global_variable == m_reloc_placeholder)
+ return true;
+
+ uint64_t offset = m_data_allocator.GetStream().GetSize();
+
+ llvm::Type *variable_type = global_variable->getType();
+
+ Constant *initializer = global_variable->getInitializer();
+
+ llvm::Type *initializer_type = initializer->getType();
+
+ size_t size = m_target_data->getTypeAllocSize(initializer_type);
+ size_t align = m_target_data->getPrefTypeAlignment(initializer_type);
+
+ const size_t mask = (align - 1);
+ uint64_t aligned_offset = (offset + mask) & ~mask;
+ m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
+ offset = aligned_offset;
+
+ lldb_private::DataBufferHeap data(size, '\0');
+
+ if (initializer)
+ if (!MaterializeInitializer(data.GetBytes(), initializer))
+ return false;
+
+ m_data_allocator.GetStream().Write(data.GetBytes(), data.GetByteSize());
+
+ Constant *new_pointer = BuildRelocation(variable_type, offset);
+
+ global_variable->replaceAllUsesWith(new_pointer);
+
+ global_variable->eraseFromParent();
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::MaybeHandleVariable (Value *llvm_value_ptr)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("MaybeHandleVariable (%s)", PrintValue(llvm_value_ptr).c_str());
+
+ if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(llvm_value_ptr))
+ {
+ switch (constant_expr->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::GetElementPtr:
+ case Instruction::BitCast:
+ Value *s = constant_expr->getOperand(0);
+ if (!MaybeHandleVariable(s))
+ return false;
+ }
+ }
+ else if (GlobalVariable *global_variable = dyn_cast<GlobalVariable>(llvm_value_ptr))
+ {
+ if (!GlobalValue::isExternalLinkage(global_variable->getLinkage()))
+ return MaterializeInternalVariable(global_variable);
+
+ clang::NamedDecl *named_decl = DeclForGlobal(global_variable);
+
+ if (!named_decl)
+ {
+ if (IsObjCSelectorRef(llvm_value_ptr))
+ return true;
+
+ if (!global_variable->hasExternalLinkage())
+ return true;
+
+ if (log)
+ log->Printf("Found global variable \"%s\" without metadata", global_variable->getName().str().c_str());
+
+ return false;
+ }
+
+ std::string name (named_decl->getName().str());
+
+ clang::ValueDecl *value_decl = dyn_cast<clang::ValueDecl>(named_decl);
+ if (value_decl == NULL)
+ return false;
+
+ lldb_private::ClangASTType clang_type(&value_decl->getASTContext(), value_decl->getType());
+
+ const Type *value_type = NULL;
+
+ if (name[0] == '$')
+ {
+ // The $__lldb_expr_result name indicates the the return value has allocated as
+ // a static variable. Per the comment at ASTResultSynthesizer::SynthesizeBodyResult,
+ // accesses to this static variable need to be redirected to the result of dereferencing
+ // a pointer that is passed in as one of the arguments.
+ //
+ // Consequently, when reporting the size of the type, we report a pointer type pointing
+ // to the type of $__lldb_expr_result, not the type itself.
+ //
+ // We also do this for any user-declared persistent variables.
+ clang_type = clang_type.GetPointerType();
+ value_type = PointerType::get(global_variable->getType(), 0);
+ }
+ else
+ {
+ value_type = global_variable->getType();
+ }
+
+ const uint64_t value_size = clang_type.GetByteSize();
+ off_t value_alignment = (clang_type.GetTypeBitAlign() + 7ull) / 8ull;
+
+ if (log)
+ {
+ log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %" PRIu64 ", align %" PRId64 "]",
+ name.c_str(),
+ clang_type.GetQualType().getAsString().c_str(),
+ PrintType(value_type).c_str(),
+ value_size,
+ value_alignment);
+ }
+
+
+ if (named_decl && !m_decl_map->AddValueToStruct(named_decl,
+ lldb_private::ConstString (name.c_str()),
+ llvm_value_ptr,
+ value_size,
+ value_alignment))
+ {
+ if (!global_variable->hasExternalLinkage())
+ return true;
+ else if (HandleSymbol (global_variable))
+ return true;
+ else
+ return false;
+ }
+ }
+ else if (dyn_cast<llvm::Function>(llvm_value_ptr))
+ {
+ if (log)
+ log->Printf("Function pointers aren't handled right now");
+
+ return false;
+ }
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::HandleSymbol (Value *symbol)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ lldb_private::ConstString name(symbol->getName().str().c_str());
+
+ lldb::addr_t symbol_addr = m_decl_map->GetSymbolAddress (name, lldb::eSymbolTypeAny);
+
+ if (symbol_addr == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf ("Symbol \"%s\" had no address", name.GetCString());
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Found \"%s\" at 0x%" PRIx64, name.GetCString(), symbol_addr);
+
+ Type *symbol_type = symbol->getType();
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ Constant *symbol_addr_int = ConstantInt::get(intptr_ty, symbol_addr, false);
+
+ Value *symbol_addr_ptr = ConstantExpr::getIntToPtr(symbol_addr_int, symbol_type);
+
+ if (log)
+ log->Printf("Replacing %s with %s", PrintValue(symbol).c_str(), PrintValue(symbol_addr_ptr).c_str());
+
+ symbol->replaceAllUsesWith(symbol_addr_ptr);
+
+ return true;
+}
+
+bool
+IRForTarget::MaybeHandleCallArguments (CallInst *Old)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf("MaybeHandleCallArguments(%s)", PrintValue(Old).c_str());
+
+ for (unsigned op_index = 0, num_ops = Old->getNumArgOperands();
+ op_index < num_ops;
+ ++op_index)
+ if (!MaybeHandleVariable(Old->getArgOperand(op_index))) // conservatively believe that this is a store
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite one of the arguments of a function call.\n");
+
+ return false;
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::HandleObjCClass(Value *classlist_reference)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ GlobalVariable *global_variable = dyn_cast<GlobalVariable>(classlist_reference);
+
+ if (!global_variable)
+ return false;
+
+ Constant *initializer = global_variable->getInitializer();
+
+ if (!initializer)
+ return false;
+
+ if (!initializer->hasName())
+ return false;
+
+ StringRef name(initializer->getName());
+ lldb_private::ConstString name_cstr(name.str().c_str());
+ lldb::addr_t class_ptr = m_decl_map->GetSymbolAddress(name_cstr, lldb::eSymbolTypeObjCClass);
+
+ if (log)
+ log->Printf("Found reference to Objective-C class %s (0x%llx)", name_cstr.AsCString(), (unsigned long long)class_ptr);
+
+ if (class_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (global_variable->use_begin() == global_variable->use_end())
+ return false;
+
+ SmallVector<LoadInst *, 2> load_instructions;
+
+ for (Value::use_iterator i = global_variable->use_begin(), e = global_variable->use_end();
+ i != e;
+ ++i)
+ {
+ if (LoadInst *load_instruction = dyn_cast<LoadInst>(*i))
+ load_instructions.push_back(load_instruction);
+ }
+
+ if (load_instructions.empty())
+ return false;
+
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize()
+ == Module::Pointer64) ? 64 : 32);
+
+ Constant *class_addr = ConstantInt::get(intptr_ty, (uint64_t)class_ptr);
+
+ for (LoadInst *load_instruction : load_instructions)
+ {
+ Constant *class_bitcast = ConstantExpr::getIntToPtr(class_addr, load_instruction->getType());
+
+ load_instruction->replaceAllUsesWith(class_bitcast);
+
+ load_instruction->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::RemoveCXAAtExit (BasicBlock &basic_block)
+{
+ BasicBlock::iterator ii;
+
+ std::vector<CallInst *> calls_to_remove;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ CallInst *call = dyn_cast<CallInst>(&inst);
+
+ // MaybeHandleCallArguments handles error reporting; we are silent here
+ if (!call)
+ continue;
+
+ bool remove = false;
+
+ llvm::Function *func = call->getCalledFunction();
+
+ if (func && func->getName() == "__cxa_atexit")
+ remove = true;
+
+ llvm::Value *val = call->getCalledValue();
+
+ if (val && val->getName() == "__cxa_atexit")
+ remove = true;
+
+ if (remove)
+ calls_to_remove.push_back(call);
+ }
+
+ for (std::vector<CallInst *>::iterator ci = calls_to_remove.begin(), ce = calls_to_remove.end();
+ ci != ce;
+ ++ci)
+ {
+ (*ci)->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ResolveCalls(BasicBlock &basic_block)
+{
+ /////////////////////////////////////////////////////////////////////////
+ // Prepare the current basic block for execution in the remote process
+ //
+
+ BasicBlock::iterator ii;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ CallInst *call = dyn_cast<CallInst>(&inst);
+
+ // MaybeHandleCallArguments handles error reporting; we are silent here
+ if (call && !MaybeHandleCallArguments(call))
+ return false;
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ResolveExternals (Function &llvm_function)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ for (Module::global_iterator global = m_module->global_begin(), end = m_module->global_end();
+ global != end;
+ ++global)
+ {
+ if (!global)
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: global variable is NULL");
+
+ return false;
+ }
+
+ std::string global_name = (*global).getName().str();
+
+ if (log)
+ log->Printf("Examining %s, DeclForGlobalValue returns %p",
+ global_name.c_str(),
+ DeclForGlobal(global));
+
+ if (global_name.find("OBJC_IVAR") == 0)
+ {
+ if (!HandleSymbol(global))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Couldn't find Objective-C indirect ivar symbol %s\n", global_name.c_str());
+
+ return false;
+ }
+ }
+ else if (global_name.find("OBJC_CLASSLIST_REFERENCES_$") != global_name.npos)
+ {
+ if (!HandleObjCClass(global))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n");
+
+ return false;
+ }
+ }
+ else if (global_name.find("OBJC_CLASSLIST_SUP_REFS_$") != global_name.npos)
+ {
+ if (!HandleObjCClass(global))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Error [IRForTarget]: Couldn't resolve the class for an Objective-C static method call\n");
+
+ return false;
+ }
+ }
+ else if (DeclForGlobal(global))
+ {
+ if (!MaybeHandleVariable (global))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't rewrite external variable %s\n", global_name.c_str());
+
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ReplaceStrings ()
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ typedef std::map <GlobalVariable *, size_t> OffsetsTy;
+
+ OffsetsTy offsets;
+
+ for (Module::global_iterator gi = m_module->global_begin(), ge = m_module->global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *gv = gi;
+
+ if (!gv->hasInitializer())
+ continue;
+
+ Constant *gc = gv->getInitializer();
+
+ std::string str;
+
+ if (gc->isNullValue())
+ {
+ Type *gc_type = gc->getType();
+
+ ArrayType *gc_array_type = dyn_cast<ArrayType>(gc_type);
+
+ if (!gc_array_type)
+ continue;
+
+ Type *gc_element_type = gc_array_type->getElementType();
+
+ IntegerType *gc_integer_type = dyn_cast<IntegerType>(gc_element_type);
+
+ if (gc_integer_type->getBitWidth() != 8)
+ continue;
+
+ str = "";
+ }
+ else
+ {
+ ConstantDataArray *gc_array = dyn_cast<ConstantDataArray>(gc);
+
+ if (!gc_array)
+ continue;
+
+ if (!gc_array->isCString())
+ continue;
+
+ if (log)
+ log->Printf("Found a GlobalVariable with string initializer %s", PrintValue(gc).c_str());
+
+ str = gc_array->getAsString();
+ }
+
+ offsets[gv] = m_data_allocator.GetStream().GetSize();
+
+ m_data_allocator.GetStream().Write(str.c_str(), str.length() + 1);
+ }
+
+ Type *char_ptr_ty = Type::getInt8PtrTy(m_module->getContext());
+
+ for (OffsetsTy::iterator oi = offsets.begin(), oe = offsets.end();
+ oi != oe;
+ ++oi)
+ {
+ GlobalVariable *gv = oi->first;
+ size_t offset = oi->second;
+
+ Constant *new_initializer = BuildRelocation(char_ptr_ty, offset);
+
+ if (log)
+ log->Printf("Replacing GV %s with %s", PrintValue(gv).c_str(), PrintValue(new_initializer).c_str());
+
+ for (GlobalVariable::use_iterator ui = gv->use_begin(), ue = gv->use_end();
+ ui != ue;
+ ++ui)
+ {
+ if (log)
+ log->Printf("Found use %s", PrintValue(*ui).c_str());
+
+ ConstantExpr *const_expr = dyn_cast<ConstantExpr>(*ui);
+ StoreInst *store_inst = dyn_cast<StoreInst>(*ui);
+
+ if (const_expr)
+ {
+ if (const_expr->getOpcode() != Instruction::GetElementPtr)
+ {
+ if (log)
+ log->Printf("Use (%s) of string variable is not a GetElementPtr constant", PrintValue(const_expr).c_str());
+
+ return false;
+ }
+
+ Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, const_expr->getOperand(0)->getType());
+ Constant *new_gep = const_expr->getWithOperandReplaced(0, bit_cast);
+
+ const_expr->replaceAllUsesWith(new_gep);
+ }
+ else if (store_inst)
+ {
+ Constant *bit_cast = ConstantExpr::getBitCast(new_initializer, store_inst->getValueOperand()->getType());
+
+ store_inst->setOperand(0, bit_cast);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Use (%s) of string variable is neither a constant nor a store", PrintValue(const_expr).c_str());
+
+ return false;
+ }
+ }
+
+ gv->eraseFromParent();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ReplaceStaticLiterals (llvm::BasicBlock &basic_block)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ typedef SmallVector <Value*, 2> ConstantList;
+ typedef SmallVector <llvm::Instruction*, 2> UserList;
+ typedef ConstantList::iterator ConstantIterator;
+ typedef UserList::iterator UserIterator;
+
+ ConstantList static_constants;
+ UserList static_users;
+
+ for (BasicBlock::iterator ii = basic_block.begin(), ie = basic_block.end();
+ ii != ie;
+ ++ii)
+ {
+ llvm::Instruction &inst = *ii;
+
+ for (Instruction::op_iterator oi = inst.op_begin(), oe = inst.op_end();
+ oi != oe;
+ ++oi)
+ {
+ Value *operand_val = oi->get();
+
+ ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
+
+ if (operand_constant_fp/* && operand_constant_fp->getType()->isX86_FP80Ty()*/)
+ {
+ static_constants.push_back(operand_val);
+ static_users.push_back(ii);
+ }
+ }
+ }
+
+ ConstantIterator constant_iter;
+ UserIterator user_iter;
+
+ for (constant_iter = static_constants.begin(), user_iter = static_users.begin();
+ constant_iter != static_constants.end();
+ ++constant_iter, ++user_iter)
+ {
+ Value *operand_val = *constant_iter;
+ llvm::Instruction *inst = *user_iter;
+
+ ConstantFP *operand_constant_fp = dyn_cast<ConstantFP>(operand_val);
+
+ if (operand_constant_fp)
+ {
+ Type *operand_type = operand_constant_fp->getType();
+
+ APFloat operand_apfloat = operand_constant_fp->getValueAPF();
+ APInt operand_apint = operand_apfloat.bitcastToAPInt();
+
+ const uint8_t* operand_raw_data = (const uint8_t*)operand_apint.getRawData();
+ size_t operand_data_size = operand_apint.getBitWidth() / 8;
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream ss(s);
+ for (size_t index = 0;
+ index < operand_data_size;
+ ++index)
+ {
+ ss << (uint32_t)operand_raw_data[index];
+ ss << " ";
+ }
+ ss.flush();
+
+ log->Printf("Found ConstantFP with size %lu and raw data %s", operand_data_size, s.c_str());
+ }
+
+ lldb_private::DataBufferHeap data(operand_data_size, 0);
+
+ if (lldb::endian::InlHostByteOrder() != m_data_allocator.GetStream().GetByteOrder())
+ {
+ uint8_t *data_bytes = data.GetBytes();
+
+ for (size_t index = 0;
+ index < operand_data_size;
+ ++index)
+ {
+ data_bytes[index] = operand_raw_data[operand_data_size - (1 + index)];
+ }
+ }
+ else
+ {
+ memcpy(data.GetBytes(), operand_raw_data, operand_data_size);
+ }
+
+ uint64_t offset = m_data_allocator.GetStream().GetSize();
+
+ size_t align = m_target_data->getPrefTypeAlignment(operand_type);
+
+ const size_t mask = (align - 1);
+ uint64_t aligned_offset = (offset + mask) & ~mask;
+ m_data_allocator.GetStream().PutNHex8(aligned_offset - offset, 0);
+ offset = aligned_offset;
+
+ m_data_allocator.GetStream().Write(data.GetBytes(), operand_data_size);
+
+ llvm::Type *fp_ptr_ty = operand_constant_fp->getType()->getPointerTo();
+
+ Constant *new_pointer = BuildRelocation(fp_ptr_ty, aligned_offset);
+
+ llvm::LoadInst *fp_load = new llvm::LoadInst(new_pointer, "fp_load", inst);
+
+ operand_constant_fp->replaceAllUsesWith(fp_load);
+ }
+ }
+
+ return true;
+}
+
+static bool isGuardVariableRef(Value *V)
+{
+ Constant *Old = NULL;
+
+ if (!(Old = dyn_cast<Constant>(V)))
+ return false;
+
+ ConstantExpr *CE = NULL;
+
+ if ((CE = dyn_cast<ConstantExpr>(V)))
+ {
+ if (CE->getOpcode() != Instruction::BitCast)
+ return false;
+
+ Old = CE->getOperand(0);
+ }
+
+ GlobalVariable *GV = dyn_cast<GlobalVariable>(Old);
+
+ if (!GV || !GV->hasName() || !GV->getName().startswith("_ZGV"))
+ return false;
+
+ return true;
+}
+
+void
+IRForTarget::TurnGuardLoadIntoZero(llvm::Instruction* guard_load)
+{
+ Constant* zero(ConstantInt::get(Type::getInt8Ty(m_module->getContext()), 0, true));
+
+ Value::use_iterator ui;
+
+ for (ui = guard_load->use_begin();
+ ui != guard_load->use_end();
+ ++ui)
+ {
+ if (isa<Constant>(*ui))
+ {
+ // do nothing for the moment
+ }
+ else
+ {
+ ui->replaceUsesOfWith(guard_load, zero);
+ }
+ }
+
+ guard_load->eraseFromParent();
+}
+
+static void ExciseGuardStore(Instruction* guard_store)
+{
+ guard_store->eraseFromParent();
+}
+
+bool
+IRForTarget::RemoveGuards(BasicBlock &basic_block)
+{
+ ///////////////////////////////////////////////////////
+ // Eliminate any reference to guard variables found.
+ //
+
+ BasicBlock::iterator ii;
+
+ typedef SmallVector <Instruction*, 2> InstrList;
+ typedef InstrList::iterator InstrIterator;
+
+ InstrList guard_loads;
+ InstrList guard_stores;
+
+ for (ii = basic_block.begin();
+ ii != basic_block.end();
+ ++ii)
+ {
+ Instruction &inst = *ii;
+
+ if (LoadInst *load = dyn_cast<LoadInst>(&inst))
+ if (isGuardVariableRef(load->getPointerOperand()))
+ guard_loads.push_back(&inst);
+
+ if (StoreInst *store = dyn_cast<StoreInst>(&inst))
+ if (isGuardVariableRef(store->getPointerOperand()))
+ guard_stores.push_back(&inst);
+ }
+
+ InstrIterator iter;
+
+ for (iter = guard_loads.begin();
+ iter != guard_loads.end();
+ ++iter)
+ TurnGuardLoadIntoZero(*iter);
+
+ for (iter = guard_stores.begin();
+ iter != guard_stores.end();
+ ++iter)
+ ExciseGuardStore(*iter);
+
+ return true;
+}
+
+// This function does not report errors; its callers are responsible.
+bool
+IRForTarget::UnfoldConstant(Constant *old_constant,
+ FunctionValueCache &value_maker,
+ FunctionValueCache &entry_instruction_finder)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ Value::use_iterator ui;
+
+ SmallVector<User*, 16> users;
+
+ // We do this because the use list might change, invalidating our iterator.
+ // Much better to keep a work list ourselves.
+ for (ui = old_constant->use_begin();
+ ui != old_constant->use_end();
+ ++ui)
+ users.push_back(*ui);
+
+ for (size_t i = 0;
+ i < users.size();
+ ++i)
+ {
+ User *user = users[i];
+
+ if (Constant *constant = dyn_cast<Constant>(user))
+ {
+ // synthesize a new non-constant equivalent of the constant
+
+ if (ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
+ {
+ switch (constant_expr->getOpcode())
+ {
+ default:
+ if (log)
+ log->Printf("Unhandled constant expression type: \"%s\"", PrintValue(constant_expr).c_str());
+ return false;
+ case Instruction::BitCast:
+ {
+ FunctionValueCache bit_cast_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
+ // UnaryExpr
+ // OperandList[0] is value
+
+ if (constant_expr->getOperand(0) != old_constant)
+ return constant_expr;
+
+ return new BitCastInst(value_maker.GetValue(function),
+ constant_expr->getType(),
+ "",
+ llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(constant_expr, bit_cast_maker, entry_instruction_finder))
+ return false;
+ }
+ break;
+ case Instruction::GetElementPtr:
+ {
+ // GetElementPtrConstantExpr
+ // OperandList[0] is base
+ // OperandList[1]... are indices
+
+ FunctionValueCache get_element_pointer_maker ([&value_maker, &entry_instruction_finder, old_constant, constant_expr] (llvm::Function *function)->llvm::Value* {
+ Value *ptr = constant_expr->getOperand(0);
+
+ if (ptr == old_constant)
+ ptr = value_maker.GetValue(function);
+
+ std::vector<Value*> index_vector;
+
+ unsigned operand_index;
+ unsigned num_operands = constant_expr->getNumOperands();
+
+ for (operand_index = 1;
+ operand_index < num_operands;
+ ++operand_index)
+ {
+ Value *operand = constant_expr->getOperand(operand_index);
+
+ if (operand == old_constant)
+ operand = value_maker.GetValue(function);
+
+ index_vector.push_back(operand);
+ }
+
+ ArrayRef <Value*> indices(index_vector);
+
+ return GetElementPtrInst::Create(ptr, indices, "", llvm::cast<Instruction>(entry_instruction_finder.GetValue(function)));
+ });
+
+ if (!UnfoldConstant(constant_expr, get_element_pointer_maker, entry_instruction_finder))
+ return false;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Unhandled constant type: \"%s\"", PrintValue(constant).c_str());
+ return false;
+ }
+ }
+ else
+ {
+ if (Instruction *inst = llvm::dyn_cast<Instruction>(user))
+ {
+ inst->replaceUsesOfWith(old_constant, value_maker.GetValue(inst->getParent()->getParent()));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(user).c_str());
+ return false;
+ }
+ }
+ }
+
+ if (!isa<GlobalValue>(old_constant))
+ {
+ old_constant->destroyConstant();
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::ReplaceVariables (Function &llvm_function)
+{
+ if (!m_resolve_vars)
+ return true;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ m_decl_map->DoStructLayout();
+
+ if (log)
+ log->Printf("Element arrangement:");
+
+ uint32_t num_elements;
+ uint32_t element_index;
+
+ size_t size;
+ off_t alignment;
+
+ if (!m_decl_map->GetStructInfo (num_elements, size, alignment))
+ return false;
+
+ Function::arg_iterator iter(llvm_function.getArgumentList().begin());
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes no arguments (should take at least a struct pointer)");
+
+ return false;
+ }
+
+ Argument *argument = iter;
+
+ if (argument->getName().equals("this"))
+ {
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'this' argument (should take a struct pointer too)");
+
+ return false;
+ }
+
+ argument = iter;
+ }
+ else if (argument->getName().equals("self"))
+ {
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' argument (should take '_cmd' and a struct pointer too)");
+
+ return false;
+ }
+
+ if (!iter->getName().equals("_cmd"))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes '%s' after 'self' argument (should take '_cmd')", iter->getName().str().c_str());
+
+ return false;
+ }
+
+ ++iter;
+
+ if (iter == llvm_function.getArgumentList().end())
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes only 'self' and '_cmd' arguments (should take a struct pointer too)");
+
+ return false;
+ }
+
+ argument = iter;
+ }
+
+ if (!argument->getName().equals("$__lldb_arg"))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Wrapper takes an argument named '%s' instead of the struct pointer", argument->getName().str().c_str());
+
+ return false;
+ }
+
+ if (log)
+ log->Printf("Arg: \"%s\"", PrintValue(argument).c_str());
+
+ BasicBlock &entry_block(llvm_function.getEntryBlock());
+ Instruction *FirstEntryInstruction(entry_block.getFirstNonPHIOrDbg());
+
+ if (!FirstEntryInstruction)
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find the first instruction in the wrapper for use in rewriting");
+
+ return false;
+ }
+
+ LLVMContext &context(m_module->getContext());
+ IntegerType *offset_type(Type::getInt32Ty(context));
+
+ if (!offset_type)
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't produce an offset type");
+
+ return false;
+ }
+
+ for (element_index = 0; element_index < num_elements; ++element_index)
+ {
+ const clang::NamedDecl *decl = NULL;
+ Value *value = NULL;
+ off_t offset;
+ lldb_private::ConstString name;
+
+ if (!m_decl_map->GetStructElement (decl, value, offset, name, element_index))
+ {
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Structure information is incomplete");
+
+ return false;
+ }
+
+ if (log)
+ log->Printf(" \"%s\" (\"%s\") placed at %" PRId64,
+ name.GetCString(),
+ decl->getNameAsString().c_str(),
+ offset);
+
+ if (value)
+ {
+ if (log)
+ log->Printf(" Replacing [%s]", PrintValue(value).c_str());
+
+ FunctionValueCache body_result_maker ([this, name, offset_type, offset, argument, value] (llvm::Function *function)->llvm::Value * {
+ // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in cases where the result
+ // variable is an rvalue, we have to synthesize a dereference of the appropriate structure
+ // entry in order to produce the static variable that the AST thinks it is accessing.
+
+ llvm::Instruction *entry_instruction = llvm::cast<Instruction>(m_entry_instruction_finder.GetValue(function));
+
+ ConstantInt *offset_int(ConstantInt::get(offset_type, offset, true));
+ GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument,
+ offset_int,
+ "",
+ entry_instruction);
+
+ if (name == m_result_name && !m_result_is_pointer)
+ {
+ BitCastInst *bit_cast = new BitCastInst(get_element_ptr,
+ value->getType()->getPointerTo(),
+ "",
+ entry_instruction);
+
+ LoadInst *load = new LoadInst(bit_cast, "", entry_instruction);
+
+ return load;
+ }
+ else
+ {
+ BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", entry_instruction);
+
+ return bit_cast;
+ }
+ });
+
+ if (Constant *constant = dyn_cast<Constant>(value))
+ {
+ UnfoldConstant(constant, body_result_maker, m_entry_instruction_finder);
+ }
+ else if (Instruction *instruction = dyn_cast<Instruction>(value))
+ {
+ value->replaceAllUsesWith(body_result_maker.GetValue(instruction->getParent()->getParent()));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Unhandled non-constant type: \"%s\"", PrintValue(value).c_str());
+ return false;
+ }
+
+ if (GlobalVariable *var = dyn_cast<GlobalVariable>(value))
+ var->eraseFromParent();
+ }
+ }
+
+ if (log)
+ log->Printf("Total structure [align %" PRId64 ", size %lu]", alignment, size);
+
+ return true;
+}
+
+llvm::Constant *
+IRForTarget::BuildRelocation(llvm::Type *type, uint64_t offset)
+{
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ llvm::Constant *offset_int = ConstantInt::get(intptr_ty, offset);
+
+ llvm::Constant *offset_array[1];
+
+ offset_array[0] = offset_int;
+
+ llvm::ArrayRef<llvm::Constant *> offsets(offset_array, 1);
+
+ llvm::Constant *reloc_getelementptr = ConstantExpr::getGetElementPtr(m_reloc_placeholder, offsets);
+ llvm::Constant *reloc_getbitcast = ConstantExpr::getBitCast(reloc_getelementptr, type);
+
+ return reloc_getbitcast;
+}
+
+bool
+IRForTarget::CompleteDataAllocation ()
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (!m_data_allocator.GetStream().GetSize())
+ return true;
+
+ lldb::addr_t allocation = m_data_allocator.Allocate();
+
+ if (log)
+ {
+ if (allocation)
+ log->Printf("Allocated static data at 0x%llx", (unsigned long long)allocation);
+ else
+ log->Printf("Failed to allocate static data");
+ }
+
+ if (!allocation || allocation == LLDB_INVALID_ADDRESS)
+ return false;
+
+ IntegerType *intptr_ty = Type::getIntNTy(m_module->getContext(),
+ (m_module->getPointerSize() == Module::Pointer64) ? 64 : 32);
+
+ Constant *relocated_addr = ConstantInt::get(intptr_ty, (uint64_t)allocation);
+ Constant *relocated_bitcast = ConstantExpr::getIntToPtr(relocated_addr, llvm::Type::getInt8PtrTy(m_module->getContext()));
+
+ m_reloc_placeholder->replaceAllUsesWith(relocated_bitcast);
+
+ m_reloc_placeholder->eraseFromParent();
+
+ return true;
+}
+
+bool
+IRForTarget::StripAllGVs (Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+ std::vector<GlobalVariable *> global_vars;
+ std::set<GlobalVariable *>erased_vars;
+
+ bool erased = true;
+
+ while (erased)
+ {
+ erased = false;
+
+ for (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
+
+ global_var->removeDeadConstantUsers();
+
+ if (global_var->use_empty())
+ {
+ if (log)
+ log->Printf("Did remove %s",
+ PrintValue(global_var).c_str());
+ global_var->eraseFromParent();
+ erased = true;
+ break;
+ }
+ }
+ }
+
+ for (Module::global_iterator gi = llvm_module.global_begin(), ge = llvm_module.global_end();
+ gi != ge;
+ ++gi)
+ {
+ GlobalVariable *global_var = dyn_cast<GlobalVariable>(gi);
+
+ GlobalValue::use_iterator ui = global_var->use_begin();
+
+ if (log)
+ log->Printf("Couldn't remove %s because of %s",
+ PrintValue(global_var).c_str(),
+ PrintValue(*ui).c_str());
+ }
+
+ return true;
+}
+
+bool
+IRForTarget::runOnModule (Module &llvm_module)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ m_module = &llvm_module;
+ m_target_data.reset(new DataLayout(m_module));
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module as passed in to IRForTarget: \n\"%s\"", s.c_str());
+ }
+
+ Function* main_function = m_module->getFunction(StringRef(m_func_name.c_str()));
+
+ if (!main_function)
+ {
+ if (log)
+ log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str());
+
+ if (m_error_stream)
+ m_error_stream->Printf("Internal error [IRForTarget]: Couldn't find wrapper '%s' in the module", m_func_name.c_str());
+
+ return false;
+ }
+
+ if (!FixFunctionLinkage (*main_function))
+ {
+ if (log)
+ log->Printf("Couldn't fix the linkage for the function");
+
+ return false;
+ }
+
+ llvm::Type *intptr_ty = Type::getInt8Ty(m_module->getContext());
+
+ m_reloc_placeholder = new llvm::GlobalVariable((*m_module),
+ intptr_ty,
+ false /* IsConstant */,
+ GlobalVariable::InternalLinkage,
+ Constant::getNullValue(intptr_ty),
+ "reloc_placeholder",
+ NULL /* InsertBefore */,
+ GlobalVariable::NotThreadLocal /* ThreadLocal */,
+ 0 /* AddressSpace */);
+
+ ////////////////////////////////////////////////////////////
+ // Replace $__lldb_expr_result with a persistent variable
+ //
+
+ if (!CreateResultVariable(*main_function))
+ {
+ if (log)
+ log->Printf("CreateResultVariable() failed");
+
+ // CreateResultVariable() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module after creating the result variable: \n\"%s\"", s.c_str());
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = fi;
+
+ if (function->begin() == function->end())
+ continue;
+
+ Function::iterator bbi;
+
+ for (bbi = function->begin();
+ bbi != function->end();
+ ++bbi)
+ {
+ if (!RemoveGuards(*bbi))
+ {
+ if (log)
+ log->Printf("RemoveGuards() failed");
+
+ // RemoveGuards() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RewritePersistentAllocs(*bbi))
+ {
+ if (log)
+ log->Printf("RewritePersistentAllocs() failed");
+
+ // RewritePersistentAllocs() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!RemoveCXAAtExit(*bbi))
+ {
+ if (log)
+ log->Printf("RemoveCXAAtExit() failed");
+
+ // RemoveCXAAtExit() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Fix all Objective-C constant strings to use NSStringWithCString:encoding:
+ //
+
+ if (!RewriteObjCConstStrings())
+ {
+ if (log)
+ log->Printf("RewriteObjCConstStrings() failed");
+
+ // RewriteObjCConstStrings() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ ///////////////////////////////
+ // Resolve function pointers
+ //
+
+ if (!ResolveFunctionPointers(llvm_module))
+ {
+ if (log)
+ log->Printf("ResolveFunctionPointers() failed");
+
+ // ResolveFunctionPointers() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = fi;
+
+ for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
+ bbi != bbe;
+ ++bbi)
+ {
+ if (!RewriteObjCSelectors(*bbi))
+ {
+ if (log)
+ log->Printf("RewriteObjCSelectors() failed");
+
+ // RewriteObjCSelectors() reports its own errors, so we don't do so here
+
+ return false;
+ }
+ }
+ }
+
+ for (Module::iterator fi = m_module->begin(), fe = m_module->end();
+ fi != fe;
+ ++fi)
+ {
+ llvm::Function *function = fi;
+
+ for (llvm::Function::iterator bbi = function->begin(), bbe = function->end();
+ bbi != bbe;
+ ++bbi)
+ {
+ if (!ResolveCalls(*bbi))
+ {
+ if (log)
+ log->Printf("ResolveCalls() failed");
+
+ // ResolveCalls() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceStaticLiterals(*bbi))
+ {
+ if (log)
+ log->Printf("ReplaceStaticLiterals() failed");
+
+ return false;
+ }
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Run function-level passes that only make sense on the main function
+ //
+
+ if (!ResolveExternals(*main_function))
+ {
+ if (log)
+ log->Printf("ResolveExternals() failed");
+
+ // ResolveExternals() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceVariables(*main_function))
+ {
+ if (log)
+ log->Printf("ReplaceVariables() failed");
+
+ // ReplaceVariables() reports its own errors, so we don't do so here
+
+ return false;
+ }
+
+ if (!ReplaceStrings())
+ {
+ if (log)
+ log->Printf("ReplaceStrings() failed");
+
+ return false;
+ }
+
+ if (!CompleteDataAllocation())
+ {
+ if (log)
+ log->Printf("CompleteDataAllocation() failed");
+
+ return false;
+ }
+
+ if (!StripAllGVs(llvm_module))
+ {
+ if (log)
+ log->Printf("StripAllGVs() failed");
+ }
+
+ if (log && log->GetVerbose())
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ m_module->print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module after preparing for execution: \n\"%s\"", s.c_str());
+ }
+
+ return true;
+}
+
+void
+IRForTarget::assignPassManager (PMStack &pass_mgr_stack, PassManagerType pass_mgr_type)
+{
+}
+
+PassManagerType
+IRForTarget::getPotentialPassManagerType() const
+{
+ return PMT_ModulePassManager;
+}
diff --git a/source/Expression/IRInterpreter.cpp b/source/Expression/IRInterpreter.cpp
new file mode 100644
index 000000000000..dcbf584cfb63
--- /dev/null
+++ b/source/Expression/IRInterpreter.cpp
@@ -0,0 +1,1379 @@
+//===-- IRInterpreter.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/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Expression/IRInterpreter.h"
+
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <map>
+
+using namespace llvm;
+
+static std::string
+PrintValue(const Value *value, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ value->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+
+ size_t offset;
+ while ((offset = s.find('\n')) != s.npos)
+ s.erase(offset, 1);
+ while (s[0] == ' ' || s[0] == '\t')
+ s.erase(0, 1);
+
+ return s;
+}
+
+static std::string
+PrintType(const Type *type, bool truncate = false)
+{
+ std::string s;
+ raw_string_ostream rso(s);
+ type->print(rso);
+ rso.flush();
+ if (truncate)
+ s.resize(s.length() - 1);
+ return s;
+}
+
+class InterpreterStackFrame
+{
+public:
+ typedef std::map <const Value*, lldb::addr_t> ValueMap;
+
+ ValueMap m_values;
+ DataLayout &m_target_data;
+ lldb_private::IRMemoryMap &m_memory_map;
+ const BasicBlock *m_bb;
+ BasicBlock::const_iterator m_ii;
+ BasicBlock::const_iterator m_ie;
+
+ lldb::addr_t m_frame_process_address;
+ size_t m_frame_size;
+ lldb::addr_t m_stack_pointer;
+
+ lldb::ByteOrder m_byte_order;
+ size_t m_addr_byte_size;
+
+ InterpreterStackFrame (DataLayout &target_data,
+ lldb_private::IRMemoryMap &memory_map,
+ lldb::addr_t stack_frame_bottom,
+ lldb::addr_t stack_frame_top) :
+ m_target_data (target_data),
+ m_memory_map (memory_map)
+ {
+ m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
+ m_addr_byte_size = (target_data.getPointerSize(0));
+
+ m_frame_process_address = stack_frame_bottom;
+ m_frame_size = stack_frame_top - stack_frame_bottom;
+ m_stack_pointer = stack_frame_top;
+ }
+
+ ~InterpreterStackFrame ()
+ {
+ }
+
+ void Jump (const BasicBlock *bb)
+ {
+ m_bb = bb;
+ m_ii = m_bb->begin();
+ m_ie = m_bb->end();
+ }
+
+ std::string SummarizeValue (const Value *value)
+ {
+ lldb_private::StreamString ss;
+
+ ss.Printf("%s", PrintValue(value).c_str());
+
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ {
+ lldb::addr_t addr = i->second;
+
+ ss.Printf(" 0x%llx", (unsigned long long)addr);
+ }
+
+ return ss.GetString();
+ }
+
+ bool AssignToMatchType (lldb_private::Scalar &scalar, uint64_t u64value, Type *type)
+ {
+ size_t type_size = m_target_data.getTypeStoreSize(type);
+
+ switch (type_size)
+ {
+ case 1:
+ scalar = (uint8_t)u64value;
+ break;
+ case 2:
+ scalar = (uint16_t)u64value;
+ break;
+ case 4:
+ scalar = (uint32_t)u64value;
+ break;
+ case 8:
+ scalar = (uint64_t)u64value;
+ break;
+ default:
+ return false;
+ }
+
+ return true;
+ }
+
+ bool EvaluateValue (lldb_private::Scalar &scalar, const Value *value, Module &module)
+ {
+ const Constant *constant = dyn_cast<Constant>(value);
+
+ if (constant)
+ {
+ APInt value_apint;
+
+ if (!ResolveConstantValue(value_apint, constant))
+ return false;
+
+ return AssignToMatchType(scalar, value_apint.getLimitedValue(), value->getType());
+ }
+ else
+ {
+ lldb::addr_t process_address = ResolveValue(value, module);
+ size_t value_size = m_target_data.getTypeStoreSize(value->getType());
+
+ lldb_private::DataExtractor value_extractor;
+ lldb_private::Error extract_error;
+
+ m_memory_map.GetMemoryData(value_extractor, process_address, value_size, extract_error);
+
+ if (!extract_error.Success())
+ return false;
+
+ lldb::offset_t offset = 0;
+ if (value_size == 1 || value_size == 2 || value_size == 4 || value_size == 8)
+ {
+ uint64_t u64value = value_extractor.GetMaxU64(&offset, value_size);
+ return AssignToMatchType(scalar, u64value, value->getType());
+ }
+ }
+
+ return false;
+ }
+
+ bool AssignValue (const Value *value, lldb_private::Scalar &scalar, Module &module)
+ {
+ lldb::addr_t process_address = ResolveValue (value, module);
+
+ if (process_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Scalar cast_scalar;
+
+ if (!AssignToMatchType(cast_scalar, scalar.GetRawBits64(0), value->getType()))
+ return false;
+
+ size_t value_byte_size = m_target_data.getTypeStoreSize(value->getType());
+
+ lldb_private::DataBufferHeap buf(value_byte_size, 0);
+
+ lldb_private::Error get_data_error;
+
+ if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(), m_byte_order, get_data_error))
+ return false;
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WriteMemory(process_address, buf.GetBytes(), buf.GetByteSize(), write_error);
+
+ return write_error.Success();
+ }
+
+ bool ResolveConstantValue (APInt &value, const Constant *constant)
+ {
+ switch (constant->getValueID())
+ {
+ default:
+ break;
+ case Value::ConstantIntVal:
+ if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
+ {
+ value = constant_int->getValue();
+ return true;
+ }
+ break;
+ case Value::ConstantFPVal:
+ if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
+ {
+ value = constant_fp->getValueAPF().bitcastToAPInt();
+ return true;
+ }
+ break;
+ case Value::ConstantExprVal:
+ if (const ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
+ {
+ switch (constant_expr->getOpcode())
+ {
+ default:
+ return false;
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ case Instruction::BitCast:
+ return ResolveConstantValue(value, constant_expr->getOperand(0));
+ case Instruction::GetElementPtr:
+ {
+ ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
+ ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
+
+ Constant *base = dyn_cast<Constant>(*op_cursor);
+
+ if (!base)
+ return false;
+
+ if (!ResolveConstantValue(value, base))
+ return false;
+
+ op_cursor++;
+
+ if (op_cursor == op_end)
+ return true; // no offset to apply!
+
+ SmallVector <Value *, 8> indices (op_cursor, op_end);
+
+ uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
+
+ const bool is_signed = true;
+ value += APInt(value.getBitWidth(), offset, is_signed);
+
+ return true;
+ }
+ }
+ }
+ break;
+ case Value::ConstantPointerNullVal:
+ if (isa<ConstantPointerNull>(constant))
+ {
+ value = APInt(m_target_data.getPointerSizeInBits(), 0);
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ bool MakeArgument(const Argument *value, uint64_t address)
+ {
+ lldb::addr_t data_address = Malloc(value->getType());
+
+ if (data_address == LLDB_INVALID_ADDRESS)
+ return false;
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WritePointerToMemory(data_address, address, write_error);
+
+ if (!write_error.Success())
+ {
+ lldb_private::Error free_error;
+ m_memory_map.Free(data_address, free_error);
+ return false;
+ }
+
+ m_values[value] = data_address;
+
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ log->Printf("Made an allocation for argument %s", PrintValue(value).c_str());
+ log->Printf(" Data region : %llx", (unsigned long long)address);
+ log->Printf(" Ref region : %llx", (unsigned long long)data_address);
+ }
+
+ return true;
+ }
+
+ bool ResolveConstant (lldb::addr_t process_address, const Constant *constant)
+ {
+ APInt resolved_value;
+
+ if (!ResolveConstantValue(resolved_value, constant))
+ return false;
+
+ const uint64_t *raw_data = resolved_value.getRawData();
+
+ size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
+
+ lldb_private::Error write_error;
+
+ m_memory_map.WriteMemory(process_address, (uint8_t*)raw_data, constant_size, write_error);
+
+ return write_error.Success();
+ }
+
+ lldb::addr_t Malloc (size_t size, uint8_t byte_alignment)
+ {
+ lldb::addr_t ret = m_stack_pointer;
+
+ ret -= size;
+ ret -= (ret % byte_alignment);
+
+ if (ret < m_frame_process_address)
+ return LLDB_INVALID_ADDRESS;
+
+ m_stack_pointer = ret;
+ return ret;
+ }
+
+ lldb::addr_t MallocPointer ()
+ {
+ return Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment());
+ }
+
+ lldb::addr_t Malloc (llvm::Type *type)
+ {
+ lldb_private::Error alloc_error;
+
+ return Malloc(m_target_data.getTypeAllocSize(type), m_target_data.getPrefTypeAlignment(type));
+ }
+
+ std::string PrintData (lldb::addr_t addr, llvm::Type *type)
+ {
+ size_t length = m_target_data.getTypeStoreSize(type);
+
+ lldb_private::DataBufferHeap buf(length, 0);
+
+ lldb_private::Error read_error;
+
+ m_memory_map.ReadMemory(buf.GetBytes(), addr, length, read_error);
+
+ if (!read_error.Success())
+ return std::string("<couldn't read data>");
+
+ lldb_private::StreamString ss;
+
+ for (size_t i = 0; i < length; i++)
+ {
+ if ((!(i & 0xf)) && i)
+ ss.Printf("%02hhx - ", buf.GetBytes()[i]);
+ else
+ ss.Printf("%02hhx ", buf.GetBytes()[i]);
+ }
+
+ return ss.GetString();
+ }
+
+ lldb::addr_t ResolveValue (const Value *value, Module &module)
+ {
+ ValueMap::iterator i = m_values.find(value);
+
+ if (i != m_values.end())
+ return i->second;
+
+ // Fall back and allocate space [allocation type Alloca]
+
+ lldb::addr_t data_address = Malloc(value->getType());
+
+ if (const Constant *constant = dyn_cast<Constant>(value))
+ {
+ if (!ResolveConstant (data_address, constant))
+ {
+ lldb_private::Error free_error;
+ m_memory_map.Free(data_address, free_error);
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+
+ m_values[value] = data_address;
+ return data_address;
+ }
+};
+
+static const char *unsupported_opcode_error = "Interpreter doesn't handle one of the expression's opcodes";
+static const char *unsupported_operand_error = "Interpreter doesn't handle one of the expression's operands";
+//static const char *interpreter_initialization_error = "Interpreter couldn't be initialized";
+static const char *interpreter_internal_error = "Interpreter encountered an internal error";
+static const char *bad_value_error = "Interpreter couldn't resolve a value during execution";
+static const char *memory_allocation_error = "Interpreter couldn't allocate memory";
+static const char *memory_write_error = "Interpreter couldn't write to memory";
+static const char *memory_read_error = "Interpreter couldn't read from memory";
+static const char *infinite_loop_error = "Interpreter ran for too many cycles";
+//static const char *bad_result_error = "Result of expression is in bad memory";
+
+bool
+IRInterpreter::CanInterpret (llvm::Module &module,
+ llvm::Function &function,
+ lldb_private::Error &error)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ bool saw_function_with_body = false;
+
+ for (Module::iterator fi = module.begin(), fe = module.end();
+ fi != fe;
+ ++fi)
+ {
+ if (fi->begin() != fi->end())
+ {
+ if (saw_function_with_body)
+ return false;
+ saw_function_with_body = true;
+ }
+ }
+
+ for (Function::iterator bbi = function.begin(), bbe = function.end();
+ bbi != bbe;
+ ++bbi)
+ {
+ for (BasicBlock::iterator ii = bbi->begin(), ie = bbi->end();
+ ii != ie;
+ ++ii)
+ {
+ switch (ii->getOpcode())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+ case Instruction::Add:
+ case Instruction::Alloca:
+ case Instruction::BitCast:
+ case Instruction::Br:
+ case Instruction::GetElementPtr:
+ break;
+ case Instruction::ICmp:
+ {
+ ICmpInst *icmp_inst = dyn_cast<ICmpInst>(ii);
+
+ if (!icmp_inst)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ switch (icmp_inst->getPredicate())
+ {
+ default:
+ {
+ if (log)
+ log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str());
+
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+ case CmpInst::ICMP_EQ:
+ case CmpInst::ICMP_NE:
+ case CmpInst::ICMP_UGT:
+ case CmpInst::ICMP_UGE:
+ case CmpInst::ICMP_ULT:
+ case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_SGT:
+ case CmpInst::ICMP_SGE:
+ case CmpInst::ICMP_SLT:
+ case CmpInst::ICMP_SLE:
+ break;
+ }
+ }
+ break;
+ case Instruction::And:
+ case Instruction::AShr:
+ case Instruction::IntToPtr:
+ case Instruction::PtrToInt:
+ case Instruction::Load:
+ case Instruction::LShr:
+ case Instruction::Mul:
+ case Instruction::Or:
+ case Instruction::Ret:
+ case Instruction::SDiv:
+ case Instruction::SExt:
+ case Instruction::Shl:
+ case Instruction::SRem:
+ case Instruction::Store:
+ case Instruction::Sub:
+ case Instruction::UDiv:
+ case Instruction::URem:
+ case Instruction::Xor:
+ case Instruction::ZExt:
+ break;
+ }
+
+ for (int oi = 0, oe = ii->getNumOperands();
+ oi != oe;
+ ++oi)
+ {
+ Value *operand = ii->getOperand(oi);
+ Type *operand_type = operand->getType();
+
+ switch (operand_type->getTypeID())
+ {
+ default:
+ break;
+ case Type::VectorTyID:
+ {
+ if (log)
+ log->Printf("Unsupported operand type: %s", PrintType(operand_type).c_str());
+ error.SetErrorString(unsupported_operand_error);
+ return false;
+ }
+ }
+ }
+ }
+
+ }
+
+ return true;}
+
+bool
+IRInterpreter::Interpret (llvm::Module &module,
+ llvm::Function &function,
+ llvm::ArrayRef<lldb::addr_t> args,
+ lldb_private::IRMemoryMap &memory_map,
+ lldb_private::Error &error,
+ lldb::addr_t stack_frame_bottom,
+ lldb::addr_t stack_frame_top)
+{
+ lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ std::string s;
+ raw_string_ostream oss(s);
+
+ module.print(oss, NULL);
+
+ oss.flush();
+
+ log->Printf("Module as passed in to IRInterpreter::Interpret: \n\"%s\"", s.c_str());
+ }
+
+ DataLayout data_layout(&module);
+
+ InterpreterStackFrame frame(data_layout, memory_map, stack_frame_bottom, stack_frame_top);
+
+ if (frame.m_frame_process_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString("Couldn't allocate stack frame");
+ }
+
+ int arg_index = 0;
+
+ for (llvm::Function::arg_iterator ai = function.arg_begin(), ae = function.arg_end();
+ ai != ae;
+ ++ai, ++arg_index)
+ {
+ if (args.size() < arg_index)
+ {
+ error.SetErrorString ("Not enough arguments passed in to function");
+ return false;
+ }
+
+ lldb::addr_t ptr = args[arg_index];
+
+ frame.MakeArgument(ai, ptr);
+ }
+
+ uint32_t num_insts = 0;
+
+ frame.Jump(function.begin());
+
+ while (frame.m_ii != frame.m_ie && (++num_insts < 4096))
+ {
+ const Instruction *inst = frame.m_ii;
+
+ if (log)
+ log->Printf("Interpreting %s", PrintValue(inst).c_str());
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ case Instruction::Sub:
+ case Instruction::Mul:
+ case Instruction::SDiv:
+ case Instruction::UDiv:
+ case Instruction::SRem:
+ case Instruction::URem:
+ case Instruction::Shl:
+ case Instruction::LShr:
+ case Instruction::AShr:
+ case Instruction::And:
+ case Instruction::Or:
+ case Instruction::Xor:
+ {
+ const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
+
+ if (!bin_op)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BinaryOperator", inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (inst->getOpcode())
+ {
+ default:
+ break;
+ case Instruction::Add:
+ result = L + R;
+ break;
+ case Instruction::Mul:
+ result = L * R;
+ break;
+ case Instruction::Sub:
+ result = L - R;
+ break;
+ case Instruction::SDiv:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = L / R;
+ break;
+ case Instruction::UDiv:
+ result = L.GetRawBits64(0) / R.GetRawBits64(1);
+ break;
+ case Instruction::SRem:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = L % R;
+ break;
+ case Instruction::URem:
+ result = L.GetRawBits64(0) % R.GetRawBits64(1);
+ break;
+ case Instruction::Shl:
+ result = L << R;
+ break;
+ case Instruction::AShr:
+ result = L >> R;
+ break;
+ case Instruction::LShr:
+ result = L;
+ result.ShiftRightLogical(R);
+ break;
+ case Instruction::And:
+ result = L & R;
+ break;
+ case Instruction::Or:
+ result = L | R;
+ break;
+ case Instruction::Xor:
+ result = L ^ R;
+ break;
+ }
+
+ frame.AssignValue(inst, result, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a %s", inst->getOpcodeName());
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Alloca:
+ {
+ const AllocaInst *alloca_inst = dyn_cast<AllocaInst>(inst);
+
+ if (!alloca_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Alloca, but instruction is not an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (alloca_inst->isArrayAllocation())
+ {
+ if (log)
+ log->Printf("AllocaInsts are not handled if isArrayAllocation() is true");
+ error.SetErrorToGenericError();
+ error.SetErrorString(unsupported_opcode_error);
+ return false;
+ }
+
+ // The semantics of Alloca are:
+ // Create a region R of virtual memory of type T, backed by a data buffer
+ // Create a region P of virtual memory of type T*, backed by a data buffer
+ // Write the virtual address of R into P
+
+ Type *T = alloca_inst->getAllocatedType();
+ Type *Tptr = alloca_inst->getType();
+
+ lldb::addr_t R = frame.Malloc(T);
+
+ if (R == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("Couldn't allocate memory for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_allocation_error);
+ return false;
+ }
+
+ lldb::addr_t P = frame.Malloc(Tptr);
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("Couldn't allocate the result pointer for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_allocation_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+
+ memory_map.WritePointerToMemory(P, R, write_error);
+
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write the result pointer for an AllocaInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_write_error);
+ lldb_private::Error free_error;
+ memory_map.Free(P, free_error);
+ memory_map.Free(R, free_error);
+ return false;
+ }
+
+ frame.m_values[alloca_inst] = P;
+
+ if (log)
+ {
+ log->Printf("Interpreted an AllocaInst");
+ log->Printf(" R : 0x%" PRIx64, R);
+ log->Printf(" P : 0x%" PRIx64, P);
+ }
+ }
+ break;
+ case Instruction::BitCast:
+ case Instruction::ZExt:
+ {
+ const CastInst *cast_inst = dyn_cast<CastInst>(inst);
+
+ if (!cast_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BitCastInst", cast_inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *source = cast_inst->getOperand(0);
+
+ lldb_private::Scalar S;
+
+ if (!frame.EvaluateValue(S, source, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(source).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, S, module);
+ }
+ break;
+ case Instruction::SExt:
+ {
+ const CastInst *cast_inst = dyn_cast<CastInst>(inst);
+
+ if (!cast_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns %s, but instruction is not a BitCastInst", cast_inst->getOpcodeName());
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *source = cast_inst->getOperand(0);
+
+ lldb_private::Scalar S;
+
+ if (!frame.EvaluateValue(S, source, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(source).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ S.MakeSigned();
+
+ lldb_private::Scalar S_signextend(S.SLongLong());
+
+ frame.AssignValue(inst, S_signextend, module);
+ }
+ break;
+ case Instruction::Br:
+ {
+ const BranchInst *br_inst = dyn_cast<BranchInst>(inst);
+
+ if (!br_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Br, but instruction is not a BranchInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ if (br_inst->isConditional())
+ {
+ Value *condition = br_inst->getCondition();
+
+ lldb_private::Scalar C;
+
+ if (!frame.EvaluateValue(C, condition, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(condition).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (C.GetRawBits64(0))
+ frame.Jump(br_inst->getSuccessor(0));
+ else
+ frame.Jump(br_inst->getSuccessor(1));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with a condition");
+ log->Printf(" cond : %s", frame.SummarizeValue(condition).c_str());
+ }
+ }
+ else
+ {
+ frame.Jump(br_inst->getSuccessor(0));
+
+ if (log)
+ {
+ log->Printf("Interpreted a BrInst with no condition");
+ }
+ }
+ }
+ continue;
+ case Instruction::GetElementPtr:
+ {
+ const GetElementPtrInst *gep_inst = dyn_cast<GetElementPtrInst>(inst);
+
+ if (!gep_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns GetElementPtr, but instruction is not a GetElementPtrInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ const Value *pointer_operand = gep_inst->getPointerOperand();
+ Type *pointer_type = pointer_operand->getType();
+
+ lldb_private::Scalar P;
+
+ if (!frame.EvaluateValue(P, pointer_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(pointer_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ typedef SmallVector <Value *, 8> IndexVector;
+ typedef IndexVector::iterator IndexIterator;
+
+ SmallVector <Value *, 8> indices (gep_inst->idx_begin(),
+ gep_inst->idx_end());
+
+ SmallVector <Value *, 8> const_indices;
+
+ for (IndexIterator ii = indices.begin(), ie = indices.end();
+ ii != ie;
+ ++ii)
+ {
+ ConstantInt *constant_index = dyn_cast<ConstantInt>(*ii);
+
+ if (!constant_index)
+ {
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, *ii, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(*ii).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (log)
+ log->Printf("Evaluated constant index %s as %llu", PrintValue(*ii).c_str(), I.ULongLong(LLDB_INVALID_ADDRESS));
+
+ constant_index = cast<ConstantInt>(ConstantInt::get((*ii)->getType(), I.ULongLong(LLDB_INVALID_ADDRESS)));
+ }
+
+ const_indices.push_back(constant_index);
+ }
+
+ uint64_t offset = data_layout.getIndexedOffset(pointer_type, const_indices);
+
+ lldb_private::Scalar Poffset = P + offset;
+
+ frame.AssignValue(inst, Poffset, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a GetElementPtrInst");
+ log->Printf(" P : %s", frame.SummarizeValue(pointer_operand).c_str());
+ log->Printf(" Poffset : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::ICmp:
+ {
+ const ICmpInst *icmp_inst = dyn_cast<ICmpInst>(inst);
+
+ if (!icmp_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns ICmp, but instruction is not an ICmpInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ CmpInst::Predicate predicate = icmp_inst->getPredicate();
+
+ Value *lhs = inst->getOperand(0);
+ Value *rhs = inst->getOperand(1);
+
+ lldb_private::Scalar L;
+ lldb_private::Scalar R;
+
+ if (!frame.EvaluateValue(L, lhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (!frame.EvaluateValue(R, rhs, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb_private::Scalar result;
+
+ switch (predicate)
+ {
+ default:
+ return false;
+ case CmpInst::ICMP_EQ:
+ result = (L == R);
+ break;
+ case CmpInst::ICMP_NE:
+ result = (L != R);
+ break;
+ case CmpInst::ICMP_UGT:
+ result = (L.GetRawBits64(0) > R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_UGE:
+ result = (L.GetRawBits64(0) >= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULT:
+ result = (L.GetRawBits64(0) < R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_ULE:
+ result = (L.GetRawBits64(0) <= R.GetRawBits64(0));
+ break;
+ case CmpInst::ICMP_SGT:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L > R);
+ break;
+ case CmpInst::ICMP_SGE:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L >= R);
+ break;
+ case CmpInst::ICMP_SLT:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L < R);
+ break;
+ case CmpInst::ICMP_SLE:
+ L.MakeSigned();
+ R.MakeSigned();
+ result = (L <= R);
+ break;
+ }
+
+ frame.AssignValue(inst, result, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted an ICmpInst");
+ log->Printf(" L : %s", frame.SummarizeValue(lhs).c_str());
+ log->Printf(" R : %s", frame.SummarizeValue(rhs).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::IntToPtr:
+ {
+ const IntToPtrInst *int_to_ptr_inst = dyn_cast<IntToPtrInst>(inst);
+
+ if (!int_to_ptr_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns IntToPtr, but instruction is not an IntToPtrInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *src_operand = int_to_ptr_inst->getOperand(0);
+
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, src_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(src_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, I, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted an IntToPtr");
+ log->Printf(" Src : %s", frame.SummarizeValue(src_operand).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::PtrToInt:
+ {
+ const PtrToIntInst *ptr_to_int_inst = dyn_cast<PtrToIntInst>(inst);
+
+ if (!ptr_to_int_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns PtrToInt, but instruction is not an PtrToIntInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ Value *src_operand = ptr_to_int_inst->getOperand(0);
+
+ lldb_private::Scalar I;
+
+ if (!frame.EvaluateValue(I, src_operand, module))
+ {
+ if (log)
+ log->Printf("Couldn't evaluate %s", PrintValue(src_operand).c_str());
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ frame.AssignValue(inst, I, module);
+
+ if (log)
+ {
+ log->Printf("Interpreted a PtrToInt");
+ log->Printf(" Src : %s", frame.SummarizeValue(src_operand).c_str());
+ log->Printf(" = : %s", frame.SummarizeValue(inst).c_str());
+ }
+ }
+ break;
+ case Instruction::Load:
+ {
+ const LoadInst *load_inst = dyn_cast<LoadInst>(inst);
+
+ if (!load_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Load, but instruction is not a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ // The semantics of Load are:
+ // Create a region D that will contain the loaded data
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be loaded from
+ // Transfer a unit of type type(D) from R to D
+
+ const Value *pointer_operand = load_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ {
+ if (log)
+ log->Printf("getPointerOperand()->getType() is not a PointerType");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ lldb::addr_t D = frame.ResolveValue(load_inst, module);
+ lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
+
+ if (D == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("LoadInst's value doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("LoadInst's pointer doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb::addr_t R;
+ lldb_private::Error read_error;
+ memory_map.ReadPointerFromMemory(&R, P, read_error);
+
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read the address to be loaded for a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ size_t target_size = data_layout.getTypeStoreSize(target_ty);
+ lldb_private::DataBufferHeap buffer(target_size, 0);
+
+ read_error.Clear();
+ memory_map.ReadMemory(buffer.GetBytes(), R, buffer.GetByteSize(), read_error);
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read from a region on behalf of a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+ memory_map.WriteMemory(D, buffer.GetBytes(), buffer.GetByteSize(), write_error);
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write to a region on behalf of a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ if (log)
+ {
+ log->Printf("Interpreted a LoadInst");
+ log->Printf(" P : 0x%" PRIx64, P);
+ log->Printf(" R : 0x%" PRIx64, R);
+ log->Printf(" D : 0x%" PRIx64, D);
+ }
+ }
+ break;
+ case Instruction::Ret:
+ {
+ return true;
+ }
+ case Instruction::Store:
+ {
+ const StoreInst *store_inst = dyn_cast<StoreInst>(inst);
+
+ if (!store_inst)
+ {
+ if (log)
+ log->Printf("getOpcode() returns Store, but instruction is not a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(interpreter_internal_error);
+ return false;
+ }
+
+ // The semantics of Store are:
+ // Resolve the region D containing the data to be stored
+ // Resolve the region P containing a pointer
+ // Dereference P to get the region R that the data should be stored in
+ // Transfer a unit of type type(D) from D to R
+
+ const Value *value_operand = store_inst->getValueOperand();
+ const Value *pointer_operand = store_inst->getPointerOperand();
+
+ Type *pointer_ty = pointer_operand->getType();
+ PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
+ if (!pointer_ptr_ty)
+ return false;
+ Type *target_ty = pointer_ptr_ty->getElementType();
+
+ lldb::addr_t D = frame.ResolveValue(value_operand, module);
+ lldb::addr_t P = frame.ResolveValue(pointer_operand, module);
+
+ if (D == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("StoreInst's value doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ if (P == LLDB_INVALID_ADDRESS)
+ {
+ if (log)
+ log->Printf("StoreInst's pointer doesn't resolve to anything");
+ error.SetErrorToGenericError();
+ error.SetErrorString(bad_value_error);
+ return false;
+ }
+
+ lldb::addr_t R;
+ lldb_private::Error read_error;
+ memory_map.ReadPointerFromMemory(&R, P, read_error);
+
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read the address to be loaded for a LoadInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ size_t target_size = data_layout.getTypeStoreSize(target_ty);
+ lldb_private::DataBufferHeap buffer(target_size, 0);
+
+ read_error.Clear();
+ memory_map.ReadMemory(buffer.GetBytes(), D, buffer.GetByteSize(), read_error);
+ if (!read_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't read from a region on behalf of a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_read_error);
+ return false;
+ }
+
+ lldb_private::Error write_error;
+ memory_map.WriteMemory(R, buffer.GetBytes(), buffer.GetByteSize(), write_error);
+ if (!write_error.Success())
+ {
+ if (log)
+ log->Printf("Couldn't write to a region on behalf of a StoreInst");
+ error.SetErrorToGenericError();
+ error.SetErrorString(memory_write_error);
+ return false;
+ }
+
+ if (log)
+ {
+ log->Printf("Interpreted a StoreInst");
+ log->Printf(" D : 0x%" PRIx64, D);
+ log->Printf(" P : 0x%" PRIx64, P);
+ log->Printf(" R : 0x%" PRIx64, R);
+ }
+ }
+ break;
+ }
+
+ ++frame.m_ii;
+ }
+
+ if (num_insts >= 4096)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString(infinite_loop_error);
+ return false;
+ }
+
+ return false;
+}
diff --git a/source/Expression/IRMemoryMap.cpp b/source/Expression/IRMemoryMap.cpp
new file mode 100644
index 000000000000..ef362baff161
--- /dev/null
+++ b/source/Expression/IRMemoryMap.cpp
@@ -0,0 +1,758 @@
+//===-- IRMemoryMap.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Expression/IRMemoryMap.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+IRMemoryMap::IRMemoryMap (lldb::TargetSP target_sp) :
+ m_target_wp(target_sp)
+{
+ if (target_sp)
+ m_process_wp = target_sp->GetProcessSP();
+}
+
+IRMemoryMap::~IRMemoryMap ()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ AllocationMap::iterator iter;
+
+ Error err;
+
+ while ((iter = m_allocations.begin()) != m_allocations.end())
+ {
+ err.Clear();
+ if (iter->second.m_leak)
+ m_allocations.erase(iter);
+ else
+ Free(iter->first, err);
+ }
+ }
+}
+
+lldb::addr_t
+IRMemoryMap::FindSpace (size_t size)
+{
+ lldb::TargetSP target_sp = m_target_wp.lock();
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ lldb::addr_t ret = LLDB_INVALID_ADDRESS;
+
+ if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ Error alloc_error;
+
+ ret = process_sp->AllocateMemory(size, lldb::ePermissionsReadable | lldb::ePermissionsWritable, alloc_error);
+
+ if (!alloc_error.Success())
+ return LLDB_INVALID_ADDRESS;
+ else
+ return ret;
+ }
+
+ for (int iterations = 0; iterations < 16; ++iterations)
+ {
+ lldb::addr_t candidate = LLDB_INVALID_ADDRESS;
+
+ switch (target_sp->GetArchitecture().GetAddressByteSize())
+ {
+ case 4:
+ {
+ uint32_t random_data = random();
+ candidate = random_data;
+ candidate &= ~0xfffull;
+ break;
+ }
+ case 8:
+ {
+ uint32_t random_low = random();
+ uint32_t random_high = random();
+ candidate = random_high;
+ candidate <<= 32ull;
+ candidate |= random_low;
+ candidate &= ~0xfffull;
+ break;
+ }
+ }
+
+ if (IntersectsAllocation(candidate, size))
+ continue;
+
+ ret = candidate;
+
+ return ret;
+ }
+
+ return ret;
+}
+
+IRMemoryMap::AllocationMap::iterator
+IRMemoryMap::FindAllocation (lldb::addr_t addr, size_t size)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return m_allocations.end();
+
+ AllocationMap::iterator iter = m_allocations.lower_bound (addr);
+
+ if (iter == m_allocations.end() ||
+ iter->first > addr)
+ {
+ if (iter == m_allocations.begin())
+ return m_allocations.end();
+ iter--;
+ }
+
+ if (iter->first <= addr && iter->first + iter->second.m_size >= addr + size)
+ return iter;
+
+ return m_allocations.end();
+}
+
+bool
+IRMemoryMap::IntersectsAllocation (lldb::addr_t addr, size_t size)
+{
+ if (addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ AllocationMap::iterator iter = m_allocations.lower_bound (addr);
+
+ if (iter == m_allocations.end() ||
+ iter->first > addr)
+ {
+ if (iter == m_allocations.begin())
+ return false;
+
+ iter--;
+ }
+
+ while (iter != m_allocations.end() && iter->second.m_process_alloc < addr + size)
+ {
+ if (iter->second.m_process_start + iter->second.m_size > addr)
+ return true;
+
+ ++iter;
+ }
+
+ return false;
+}
+
+lldb::ByteOrder
+IRMemoryMap::GetByteOrder()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp->GetByteOrder();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp->GetArchitecture().GetByteOrder();
+
+ return lldb::eByteOrderInvalid;
+}
+
+uint32_t
+IRMemoryMap::GetAddressByteSize()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp->GetAddressByteSize();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp->GetArchitecture().GetAddressByteSize();
+
+ return UINT32_MAX;
+}
+
+ExecutionContextScope *
+IRMemoryMap::GetBestExecutionContextScope()
+{
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ return process_sp.get();
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ return target_sp.get();
+
+ return NULL;
+}
+
+IRMemoryMap::Allocation::Allocation (lldb::addr_t process_alloc,
+ lldb::addr_t process_start,
+ size_t size,
+ uint32_t permissions,
+ uint8_t alignment,
+ AllocationPolicy policy) :
+ m_process_alloc (process_alloc),
+ m_process_start (process_start),
+ m_size (size),
+ m_permissions (permissions),
+ m_alignment (alignment),
+ m_policy (policy),
+ m_leak (false)
+{
+ switch (policy)
+ {
+ default:
+ assert (0 && "We cannot reach this!");
+ case eAllocationPolicyHostOnly:
+ m_data.SetByteSize(size);
+ memset(m_data.GetBytes(), 0, size);
+ break;
+ case eAllocationPolicyProcessOnly:
+ break;
+ case eAllocationPolicyMirror:
+ m_data.SetByteSize(size);
+ memset(m_data.GetBytes(), 0, size);
+ break;
+ }
+}
+
+lldb::addr_t
+IRMemoryMap::Malloc (size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, Error &error)
+{
+ error.Clear();
+
+ lldb::ProcessSP process_sp;
+ lldb::addr_t allocation_address = LLDB_INVALID_ADDRESS;
+ lldb::addr_t aligned_address = LLDB_INVALID_ADDRESS;
+
+ size_t alignment_mask = alignment - 1;
+ size_t allocation_size;
+
+ if (size == 0)
+ allocation_size = alignment;
+ else
+ allocation_size = (size & alignment_mask) ? ((size + alignment) & (~alignment_mask)) : size;
+
+ switch (policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: invalid allocation policy");
+ return LLDB_INVALID_ADDRESS;
+ case eAllocationPolicyHostOnly:
+ allocation_address = FindSpace(allocation_size);
+ if (allocation_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: address space is full");
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
+ case eAllocationPolicyMirror:
+ process_sp = m_process_wp.lock();
+ if (process_sp && process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ }
+ else
+ {
+ policy = eAllocationPolicyHostOnly;
+ allocation_address = FindSpace(allocation_size);
+ if (allocation_address == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: address space is full");
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ if (process_sp->CanJIT() && process_sp->IsAlive())
+ {
+ allocation_address = process_sp->AllocateMemory(allocation_size, permissions, error);
+ if (!error.Success())
+ return LLDB_INVALID_ADDRESS;
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: process doesn't support allocating memory");
+ return LLDB_INVALID_ADDRESS;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't malloc: process doesn't exist, and this memory must be in the process");
+ return LLDB_INVALID_ADDRESS;
+ }
+ break;
+ }
+
+
+ lldb::addr_t mask = alignment - 1;
+ aligned_address = (allocation_address + mask) & (~mask);
+
+ m_allocations[aligned_address] = Allocation(allocation_address,
+ aligned_address,
+ allocation_size,
+ permissions,
+ alignment,
+ policy);
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ const char * policy_string;
+
+ switch (policy)
+ {
+ default:
+ policy_string = "<invalid policy>";
+ break;
+ case eAllocationPolicyHostOnly:
+ policy_string = "eAllocationPolicyHostOnly";
+ break;
+ case eAllocationPolicyProcessOnly:
+ policy_string = "eAllocationPolicyProcessOnly";
+ break;
+ case eAllocationPolicyMirror:
+ policy_string = "eAllocationPolicyMirror";
+ break;
+ }
+
+ log->Printf("IRMemoryMap::Malloc (%" PRIu64 ", 0x%" PRIx64 ", 0x%" PRIx64 ", %s) -> 0x%" PRIx64,
+ (uint64_t)allocation_size,
+ (uint64_t)alignment,
+ (uint64_t)permissions,
+ policy_string,
+ aligned_address);
+ }
+
+ return aligned_address;
+}
+
+void
+IRMemoryMap::Leak (lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = m_allocations.find(process_address);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't leak: allocation doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ allocation.m_leak = true;
+}
+
+void
+IRMemoryMap::Free (lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = m_allocations.find(process_address);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't free: allocation doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ case eAllocationPolicyHostOnly:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ if (process_sp->CanJIT() && process_sp->IsAlive())
+ process_sp->DeallocateMemory(allocation.m_process_alloc); // FindSpace allocated this for real
+ }
+
+ break;
+ }
+ case eAllocationPolicyMirror:
+ case eAllocationPolicyProcessOnly:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp)
+ process_sp->DeallocateMemory(allocation.m_process_alloc);
+ }
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::Free (0x%" PRIx64 ") freed [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ iter->second.m_process_start,
+ iter->second.m_process_start + iter->second.m_size);
+ }
+
+ m_allocations.erase(iter);
+}
+
+void
+IRMemoryMap::WriteMemory (lldb::addr_t process_address, const uint8_t *bytes, size_t size, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ return;
+ }
+
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: no allocation contains the target range and the process doesn't exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ uint64_t offset = process_address - allocation.m_process_start;
+
+ lldb::ProcessSP process_sp;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: invalid allocation policy");
+ return;
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: data buffer is empty");
+ return;
+ }
+ ::memcpy (allocation.m_data.GetBytes() + offset, bytes, size);
+ break;
+ case eAllocationPolicyMirror:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't write: data buffer is empty");
+ return;
+ }
+ ::memcpy (allocation.m_data.GetBytes() + offset, bytes, size);
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->WriteMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::WriteMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") went to [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ (uint64_t)bytes,
+ (uint64_t)size,
+ (uint64_t)allocation.m_process_start,
+ (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
+ }
+}
+
+void
+IRMemoryMap::WriteScalarToMemory (lldb::addr_t process_address, Scalar &scalar, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size == UINT32_MAX)
+ size = scalar.GetByteSize();
+
+ if (size > 0)
+ {
+ uint8_t buf[32];
+ const size_t mem_size = scalar.GetAsMemoryData (buf, size, GetByteOrder(), error);
+ if (mem_size > 0)
+ {
+ return WriteMemory(process_address, buf, mem_size, error);
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't write scalar: failed to get scalar as memory data");
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't write scalar: its size was zero");
+ }
+ return;
+}
+
+void
+IRMemoryMap::WritePointerToMemory (lldb::addr_t process_address, lldb::addr_t address, Error &error)
+{
+ error.Clear();
+
+ Scalar scalar(address);
+
+ WriteScalarToMemory(process_address, scalar, GetAddressByteSize(), error);
+}
+
+void
+IRMemoryMap::ReadMemory (uint8_t *bytes, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ return;
+ }
+
+ lldb::TargetSP target_sp = m_target_wp.lock();
+
+ if (target_sp)
+ {
+ Address absolute_address(process_address);
+ target_sp->ReadMemory(absolute_address, false, bytes, size, error);
+ return;
+ }
+
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: no allocation contains the target range, and neither the process nor the target exist");
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ uint64_t offset = process_address - allocation.m_process_start;
+
+ lldb::ProcessSP process_sp;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: invalid allocation policy");
+ return;
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: data buffer is empty");
+ return;
+ }
+ ::memcpy (bytes, allocation.m_data.GetBytes() + offset, size);
+ break;
+ case eAllocationPolicyMirror:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ else
+ {
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't read: data buffer is empty");
+ return;
+ }
+ ::memcpy (bytes, allocation.m_data.GetBytes() + offset, size);
+ }
+ break;
+ case eAllocationPolicyProcessOnly:
+ process_sp = m_process_wp.lock();
+ if (process_sp)
+ {
+ process_sp->ReadMemory(process_address, bytes, size, error);
+ if (!error.Success())
+ return;
+ }
+ break;
+ }
+
+ if (lldb_private::Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("IRMemoryMap::ReadMemory (0x%" PRIx64 ", 0x%" PRIx64 ", 0x%" PRId64 ") came from [0x%" PRIx64 "..0x%" PRIx64 ")",
+ (uint64_t)process_address,
+ (uint64_t)bytes,
+ (uint64_t)size,
+ (uint64_t)allocation.m_process_start,
+ (uint64_t)allocation.m_process_start + (uint64_t)allocation.m_size);
+ }
+}
+
+void
+IRMemoryMap::ReadScalarFromMemory (Scalar &scalar, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size > 0)
+ {
+ DataBufferHeap buf(size, 0);
+ ReadMemory(buf.GetBytes(), process_address, size, error);
+
+ if (!error.Success())
+ return;
+
+ DataExtractor extractor(buf.GetBytes(), buf.GetByteSize(), GetByteOrder(), GetAddressByteSize());
+
+ lldb::offset_t offset = 0;
+
+ switch (size)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't read scalar: unsupported size %" PRIu64, (uint64_t)size);
+ return;
+ case 1: scalar = extractor.GetU8(&offset); break;
+ case 2: scalar = extractor.GetU16(&offset); break;
+ case 4: scalar = extractor.GetU32(&offset); break;
+ case 8: scalar = extractor.GetU64(&offset); break;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't read scalar: its size was zero");
+ }
+ return;
+}
+
+void
+IRMemoryMap::ReadPointerFromMemory (lldb::addr_t *address, lldb::addr_t process_address, Error &error)
+{
+ error.Clear();
+
+ Scalar pointer_scalar;
+ ReadScalarFromMemory(pointer_scalar, process_address, GetAddressByteSize(), error);
+
+ if (!error.Success())
+ return;
+
+ *address = pointer_scalar.ULongLong();
+
+ return;
+}
+
+void
+IRMemoryMap::GetMemoryData (DataExtractor &extractor, lldb::addr_t process_address, size_t size, Error &error)
+{
+ error.Clear();
+
+ if (size > 0)
+ {
+ AllocationMap::iterator iter = FindAllocation(process_address, size);
+
+ if (iter == m_allocations.end())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorStringWithFormat("Couldn't find an allocation containing [0x%" PRIx64 "..0x%" PRIx64 ")", process_address, process_address + size);
+ return;
+ }
+
+ Allocation &allocation = iter->second;
+
+ switch (allocation.m_policy)
+ {
+ default:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: invalid allocation policy");
+ return;
+ case eAllocationPolicyProcessOnly:
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: memory is only in the target");
+ return;
+ case eAllocationPolicyMirror:
+ {
+ lldb::ProcessSP process_sp = m_process_wp.lock();
+
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: data buffer is empty");
+ return;
+ }
+ if (process_sp)
+ {
+ process_sp->ReadMemory(allocation.m_process_start, allocation.m_data.GetBytes(), allocation.m_data.GetByteSize(), error);
+ if (!error.Success())
+ return;
+ uint64_t offset = process_address - allocation.m_process_start;
+ extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
+ return;
+ }
+ }
+ case eAllocationPolicyHostOnly:
+ if (!allocation.m_data.GetByteSize())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't get memory data: data buffer is empty");
+ return;
+ }
+ uint64_t offset = process_address - allocation.m_process_start;
+ extractor = DataExtractor(allocation.m_data.GetBytes() + offset, size, GetByteOrder(), GetAddressByteSize());
+ return;
+ }
+ }
+ else
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString ("Couldn't get memory data: its size was zero");
+ return;
+ }
+}
+
+
diff --git a/source/Expression/Materializer.cpp b/source/Expression/Materializer.cpp
new file mode 100644
index 000000000000..8a1900ebb739
--- /dev/null
+++ b/source/Expression/Materializer.cpp
@@ -0,0 +1,1414 @@
+//===-- Materializer.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/Core/RegisterValue.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Expression/ClangExpressionVariable.h"
+#include "lldb/Expression/Materializer.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+uint32_t
+Materializer::AddStructMember (Entity &entity)
+{
+ uint32_t size = entity.GetSize();
+ uint32_t alignment = entity.GetAlignment();
+
+ uint32_t ret;
+
+ if (m_current_offset == 0)
+ m_struct_alignment = alignment;
+
+ if (m_current_offset % alignment)
+ m_current_offset += (alignment - (m_current_offset % alignment));
+
+ ret = m_current_offset;
+
+ m_current_offset += size;
+
+ return ret;
+}
+
+void
+Materializer::Entity::SetSizeAndAlignmentFromType (ClangASTType &type)
+{
+ m_size = type.GetByteSize();
+
+ uint32_t bit_alignment = type.GetTypeBitAlign();
+
+ if (bit_alignment % 8)
+ {
+ bit_alignment += 8;
+ bit_alignment &= ~((uint32_t)0x111u);
+ }
+
+ m_alignment = bit_alignment / 8;
+}
+
+class EntityPersistentVariable : public Materializer::Entity
+{
+public:
+ EntityPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp) :
+ Entity(),
+ m_persistent_variable_sp(persistent_variable_sp)
+ {
+ // Hard-coding to maximum size of a pointer since persistent variables are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void MakeAllocation (IRMemoryMap &map, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ // Allocate a spare memory area to store the persistent variable's contents.
+
+ Error allocate_error;
+
+ lldb::addr_t mem = map.Malloc(m_persistent_variable_sp->GetByteSize(),
+ 8,
+ lldb::ePermissionsReadable | lldb::ePermissionsWritable,
+ IRMemoryMap::eAllocationPolicyMirror,
+ allocate_error);
+
+ if (!allocate_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a memory area to store %s: %s", m_persistent_variable_sp->GetName().GetCString(), allocate_error.AsCString());
+ return;
+ }
+
+ if (log)
+ log->Printf("Allocated %s (0x%" PRIx64 ") sucessfully", m_persistent_variable_sp->GetName().GetCString(), mem);
+
+ // Put the location of the spare memory into the live data of the ValueObject.
+
+ m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create (map.GetBestExecutionContextScope(),
+ m_persistent_variable_sp->GetTypeFromUser(),
+ m_persistent_variable_sp->GetName(),
+ mem,
+ eAddressTypeLoad,
+ m_persistent_variable_sp->GetByteSize());
+
+ // Clear the flag if the variable will never be deallocated.
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget)
+ {
+ Error leak_error;
+ map.Leak(mem, leak_error);
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsAllocation;
+ }
+
+ // Write the contents of the variable to the area.
+
+ Error write_error;
+
+ map.WriteMemory (mem,
+ m_persistent_variable_sp->GetValueBytes(),
+ m_persistent_variable_sp->GetByteSize(),
+ write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't write %s to the target: %s", m_persistent_variable_sp->GetName().AsCString(),
+ write_error.AsCString());
+ return;
+ }
+ }
+
+ void DestroyAllocation (IRMemoryMap &map, Error &err)
+ {
+ Error deallocate_error;
+
+ map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue().GetScalar().ULongLong(), deallocate_error);
+
+ m_persistent_variable_sp->m_live_sp.reset();
+
+ if (!deallocate_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't deallocate memory for %s: %s", m_persistent_variable_sp->GetName().GetCString(), deallocate_error.AsCString());
+ }
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64 ", m_name = %s, m_flags = 0x%hx]",
+ (uint64_t)load_addr,
+ m_persistent_variable_sp->GetName().AsCString(),
+ m_persistent_variable_sp->m_flags);
+ }
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation)
+ {
+ MakeAllocation(map, err);
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+
+ if (!err.Success())
+ return;
+ }
+
+ if ((m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference && m_persistent_variable_sp->m_live_sp) ||
+ m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated)
+ {
+ Error write_error;
+
+ map.WriteScalarToMemory(load_addr,
+ m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
+ map.GetAddressByteSize(),
+ write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the location of %s to memory: %s", m_persistent_variable_sp->GetName().AsCString(), write_error.AsCString());
+ }
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("no materialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 ", m_name = %s, m_flags = 0x%hx]",
+ (uint64_t)process_address + m_offset,
+ m_persistent_variable_sp->GetName().AsCString(),
+ m_persistent_variable_sp->m_flags);
+ }
+
+ if ((m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated) ||
+ (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference))
+ {
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVIsProgramReference &&
+ !m_persistent_variable_sp->m_live_sp)
+ {
+ // If the reference comes from the program, then the ClangExpressionVariable's
+ // live variable data hasn't been set up yet. Do this now.
+
+ lldb::addr_t location;
+ Error read_error;
+
+ map.ReadPointerFromMemory(&location, load_addr, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't read the address of program-allocated variable %s: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString());
+ return;
+ }
+
+ m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create (map.GetBestExecutionContextScope (),
+ m_persistent_variable_sp->GetTypeFromUser(),
+ m_persistent_variable_sp->GetName(),
+ location,
+ eAddressTypeLoad,
+ m_persistent_variable_sp->GetByteSize());
+
+ if (frame_top != LLDB_INVALID_ADDRESS &&
+ frame_bottom != LLDB_INVALID_ADDRESS &&
+ location >= frame_bottom &&
+ location <= frame_top)
+ {
+ // If the variable is resident in the stack frame created by the expression,
+ // then it cannot be relied upon to stay around. We treat it as needing
+ // reallocation.
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry;
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVIsProgramReference;
+ }
+ }
+
+ lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue().GetScalar().ULongLong();
+
+ if (!m_persistent_variable_sp->m_live_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't find the memory area used to store %s", m_persistent_variable_sp->GetName().GetCString());
+ return;
+ }
+
+ if (m_persistent_variable_sp->m_live_sp->GetValue().GetValueAddressType() != eAddressTypeLoad)
+ {
+ err.SetErrorStringWithFormat("the address of the memory area for %s is in an incorrect format", m_persistent_variable_sp->GetName().GetCString());
+ return;
+ }
+
+ if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry ||
+ m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget)
+ {
+ if (log)
+ log->Printf("Dematerializing %s from 0x%" PRIx64 " (size = %llu)", m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, (unsigned long long)m_persistent_variable_sp->GetByteSize());
+
+ // Read the contents of the spare memory area
+
+ m_persistent_variable_sp->ValueUpdated ();
+
+ Error read_error;
+
+ map.ReadMemory(m_persistent_variable_sp->GetValueBytes(),
+ mem,
+ m_persistent_variable_sp->GetByteSize(),
+ read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorStringWithFormat ("couldn't read the contents of %s from memory: %s", m_persistent_variable_sp->GetName().GetCString(), read_error.AsCString());
+ return;
+ }
+
+ m_persistent_variable_sp->m_flags &= ~ClangExpressionVariable::EVNeedsFreezeDry;
+ }
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("no dematerialization happened for persistent variable %s", m_persistent_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess();
+ if (!process_sp ||
+ !process_sp->CanJIT())
+ {
+ // Allocations are not persistent so persistent variables cannot stay materialized.
+
+ m_persistent_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+
+ DestroyAllocation(map, err);
+ if (!err.Success())
+ return;
+ }
+ else if (m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation &&
+ !(m_persistent_variable_sp->m_flags & ClangExpressionVariable::EVKeepInTarget))
+ {
+ DestroyAllocation(map, err);
+ if (!err.Success())
+ return;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", load_addr, m_persistent_variable_sp->GetName().AsCString());
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ {
+ dump_stream.Printf("Target:\n");
+
+ lldb::addr_t target_address;
+
+ map.ReadPointerFromMemory (&target_address, load_addr, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_persistent_variable_sp->GetByteSize(), 0);
+
+ map.ReadMemory(data.GetBytes(), target_address, m_persistent_variable_sp->GetByteSize(), err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, target_address);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ lldb::ClangExpressionVariableSP m_persistent_variable_sp;
+};
+
+uint32_t
+Materializer::AddPersistentVariable (lldb::ClangExpressionVariableSP &persistent_variable_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityPersistentVariable (persistent_variable_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityVariable : public Materializer::Entity
+{
+public:
+ EntityVariable (lldb::VariableSP &variable_sp) :
+ Entity(),
+ m_variable_sp(variable_sp),
+ m_is_reference(false),
+ m_temporary_allocation(LLDB_INVALID_ADDRESS),
+ m_temporary_allocation_size(0)
+ {
+ // Hard-coding to maximum size of a pointer since all variables are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ m_is_reference = m_variable_sp->GetType()->GetClangForwardType().IsReferenceType();
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ if (log)
+ {
+ log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64 ", m_variable_sp = %s]",
+ (uint64_t)load_addr,
+ m_variable_sp->GetName().AsCString());
+ }
+
+ ExecutionContextScope *scope = frame_sp.get();
+
+ if (!scope)
+ scope = map.GetBestExecutionContextScope();
+
+ lldb::ValueObjectSP valobj_sp = ValueObjectVariable::Create(scope, m_variable_sp);
+
+ if (!valobj_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't get a value object for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ if (m_is_reference)
+ {
+ DataExtractor valobj_extractor;
+ valobj_sp->GetData(valobj_extractor);
+ lldb::offset_t offset = 0;
+ lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
+
+ Error write_error;
+ map.WritePointerToMemory(load_addr, reference_addr, write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the contents of reference variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+ }
+ else
+ {
+ Error get_address_error;
+ lldb::ValueObjectSP addr_of_valobj_sp = valobj_sp->AddressOf(get_address_error);
+ if (get_address_error.Success())
+ {
+ DataExtractor valobj_extractor;
+ addr_of_valobj_sp->GetData(valobj_extractor);
+ lldb::offset_t offset = 0;
+ lldb::addr_t addr_of_valobj_addr = valobj_extractor.GetAddress(&offset);
+
+ Error write_error;
+ map.WritePointerToMemory(load_addr, addr_of_valobj_addr, write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+ }
+ else
+ {
+ DataExtractor data;
+ valobj_sp->GetData(data);
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorStringWithFormat("trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ if (data.GetByteSize() != m_variable_sp->GetType()->GetByteSize())
+ {
+ if (data.GetByteSize() == 0 && m_variable_sp->LocationExpression().IsValid() == false)
+ {
+ err.SetErrorStringWithFormat("the variable '%s' has no location, it may have been optimized out", m_variable_sp->GetName().AsCString());
+ }
+ else
+ {
+ err.SetErrorStringWithFormat("size of variable %s disagrees with the ValueObject's size", m_variable_sp->GetName().AsCString());
+ }
+ return;
+ }
+
+ size_t bit_align = m_variable_sp->GetType()->GetClangLayoutType().GetTypeBitAlign();
+ size_t byte_align = (bit_align + 7) / 8;
+
+ Error alloc_error;
+
+ m_temporary_allocation = map.Malloc(data.GetByteSize(), byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
+ m_temporary_allocation_size = data.GetByteSize();
+
+ if (!alloc_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a temporary region for %s: %s", m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
+ return;
+ }
+
+ Error write_error;
+
+ map.WriteMemory(m_temporary_allocation, data.GetDataStart(), data.GetByteSize(), write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write to the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
+ return;
+ }
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), pointer_write_error.AsCString());
+ }
+ }
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ if (log)
+ {
+ log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 ", m_variable_sp = %s]",
+ (uint64_t)load_addr,
+ m_variable_sp->GetName().AsCString());
+ }
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ ExecutionContextScope *scope = frame_sp.get();
+
+ if (!scope)
+ scope = map.GetBestExecutionContextScope();
+
+ lldb::ValueObjectSP valobj_sp = ValueObjectVariable::Create(scope, m_variable_sp);
+
+ if (!valobj_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't get a value object for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ lldb_private::DataExtractor data;
+
+ Error extract_error;
+
+ map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), extract_error);
+
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for variable %s", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ Error set_error;
+
+ valobj_sp->SetData(data, set_error);
+
+ if (!set_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the new contents of %s back into the variable", m_variable_sp->GetName().AsCString());
+ return;
+ }
+
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+
+ if (!free_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't free the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString());
+ return;
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+ dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
+
+ Error err;
+
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ lldb::offset_t offset;
+
+ ptr = extractor.GetPointer(&offset);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf("Points to process memory:\n");
+ }
+ else
+ {
+ dump_stream.Printf("Temporary allocation:\n");
+ }
+
+ if (ptr == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf(" <could not be be found>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_temporary_allocation_size, 0);
+
+ map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+
+ }
+private:
+ lldb::VariableSP m_variable_sp;
+ bool m_is_reference;
+ lldb::addr_t m_temporary_allocation;
+ size_t m_temporary_allocation_size;
+};
+
+uint32_t
+Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityVariable (variable_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityResultVariable : public Materializer::Entity
+{
+public:
+ EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) :
+ Entity(),
+ m_type(type),
+ m_is_program_reference(is_program_reference),
+ m_keep_in_memory(keep_in_memory),
+ m_temporary_allocation(LLDB_INVALID_ADDRESS),
+ m_temporary_allocation_size(0)
+ {
+ // Hard-coding to maximum size of a pointer since all results are materialized by reference
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ if (!m_is_program_reference)
+ {
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ err.SetErrorString("Trying to create a temporary region for the result but one exists");
+ return;
+ }
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ size_t byte_size = m_type.GetByteSize();
+ size_t bit_align = m_type.GetTypeBitAlign();
+ size_t byte_align = (bit_align + 7) / 8;
+
+ Error alloc_error;
+
+ m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
+ m_temporary_allocation_size = byte_size;
+
+ if (!alloc_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't allocate a temporary region for the result: %s", alloc_error.AsCString());
+ return;
+ }
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of the temporary region for the result: %s", pointer_write_error.AsCString());
+ }
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ err.SetErrorString("Tried to detmaterialize a result variable with the normal Dematerialize method");
+ }
+
+ void Dematerialize (lldb::ClangExpressionVariableSP &result_variable_sp,
+ lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ err.Clear();
+
+ ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
+
+ if (!exe_scope)
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: invalid execution context scope");
+ return;
+ }
+
+ lldb::addr_t address;
+ Error read_error;
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ map.ReadPointerFromMemory (&address, load_addr, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its address");
+ return;
+ }
+
+ lldb::TargetSP target_sp = exe_scope->CalculateTarget();
+
+ if (!target_sp)
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: no target");
+ return;
+ }
+
+ ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName();
+
+ lldb::ClangExpressionVariableSP ret;
+
+ ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope,
+ name,
+ m_type,
+ map.GetByteOrder(),
+ map.GetAddressByteSize());
+
+ if (!ret)
+ {
+ err.SetErrorStringWithFormat("couldn't dematerialize a result variable: failed to make persistent variable %s", name.AsCString());
+ return;
+ }
+
+ lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess();
+
+ bool can_persist = (m_is_program_reference && process_sp && process_sp->CanJIT() && !(address >= frame_bottom && address < frame_top));
+
+ if (can_persist && m_keep_in_memory)
+ {
+ ret->m_live_sp = ValueObjectConstResult::Create(exe_scope,
+ m_type,
+ name,
+ address,
+ eAddressTypeLoad,
+ ret->GetByteSize());
+ }
+
+ ret->ValueUpdated();
+
+ const size_t pvar_byte_size = ret->GetByteSize();
+ uint8_t *pvar_data = ret->GetValueBytes();
+
+ map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
+
+ if (!read_error.Success())
+ {
+ err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its memory");
+ return;
+ }
+
+ result_variable_sp = ret;
+
+ if (!can_persist || !m_keep_in_memory)
+ {
+ ret->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+
+ if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+ map.Free(m_temporary_allocation, free_error);
+ }
+ }
+ else
+ {
+ ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
+
+ Error err;
+
+ lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ lldb::offset_t offset;
+
+ ptr = extractor.GetPointer(&offset);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf("Points to process memory:\n");
+ }
+ else
+ {
+ dump_stream.Printf("Temporary allocation:\n");
+ }
+
+ if (ptr == LLDB_INVALID_ADDRESS)
+ {
+ dump_stream.Printf(" <could not be be found>\n");
+ }
+ else
+ {
+ DataBufferHeap data (m_temporary_allocation_size, 0);
+
+ map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS)
+ {
+ Error free_error;
+
+ map.Free(m_temporary_allocation, free_error);
+ }
+
+ m_temporary_allocation = LLDB_INVALID_ADDRESS;
+ m_temporary_allocation_size = 0;
+ }
+private:
+ TypeFromUser m_type;
+ bool m_is_program_reference;
+ bool m_keep_in_memory;
+
+ lldb::addr_t m_temporary_allocation;
+ size_t m_temporary_allocation_size;
+};
+
+uint32_t
+Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ m_result_entity = iter->get();
+ return ret;
+}
+
+class EntitySymbol : public Materializer::Entity
+{
+public:
+ EntitySymbol (const Symbol &symbol) :
+ Entity(),
+ m_symbol(symbol)
+ {
+ // Hard-coding to maximum size of a symbol
+ m_size = 8;
+ m_alignment = 8;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 ", m_symbol = %s]",
+ (uint64_t)load_addr,
+ m_symbol.GetName().AsCString());
+ }
+
+ Address &sym_address = m_symbol.GetAddress();
+
+ ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
+
+ lldb::TargetSP target_sp;
+
+ if (exe_scope)
+ target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
+
+ if (!target_sp)
+ {
+ err.SetErrorStringWithFormat("couldn't resolve symbol %s because there is no target", m_symbol.GetName().AsCString());
+ return;
+ }
+
+ lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
+
+ if (resolved_address == LLDB_INVALID_ADDRESS)
+ resolved_address = sym_address.GetFileAddress();
+
+ Error pointer_write_error;
+
+ map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
+
+ if (!pointer_write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the address of symbol %s: %s", m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 ", m_symbol = %s]",
+ (uint64_t)load_addr,
+ m_symbol.GetName().AsCString());
+ }
+
+ // no work needs to be done
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, m_symbol.GetName().AsCString());
+
+ {
+ dump_stream.Printf("Pointer:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ Symbol m_symbol;
+};
+
+uint32_t
+Materializer::AddSymbol (const Symbol &symbol_sp, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntitySymbol (symbol_sp));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+class EntityRegister : public Materializer::Entity
+{
+public:
+ EntityRegister (const RegisterInfo &register_info) :
+ Entity(),
+ m_register_info(register_info)
+ {
+ // Hard-coding alignment conservatively
+ m_size = m_register_info.byte_size;
+ m_alignment = m_register_info.byte_size;
+ }
+
+ void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 ", m_register_info = %s]",
+ (uint64_t)load_addr,
+ m_register_info.name);
+ }
+
+ RegisterValue reg_value;
+
+ if (!frame_sp.get())
+ {
+ err.SetErrorStringWithFormat("couldn't materialize register %s without a stack frame", m_register_info.name);
+ return;
+ }
+
+ lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
+
+ if (!reg_context_sp->ReadRegister(&m_register_info, reg_value))
+ {
+ err.SetErrorStringWithFormat("couldn't read the value of register %s", m_register_info.name);
+ return;
+ }
+
+ DataExtractor register_data;
+
+ if (!reg_value.GetData(register_data))
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for register %s", m_register_info.name);
+ return;
+ }
+
+ if (register_data.GetByteSize() != m_register_info.byte_size)
+ {
+ err.SetErrorStringWithFormat("data for register %s had size %llu but we expected %llu", m_register_info.name, (unsigned long long)register_data.GetByteSize(), (unsigned long long)m_register_info.byte_size);
+ return;
+ }
+
+ m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(), register_data.GetByteSize()));
+
+ Error write_error;
+
+ map.WriteMemory(load_addr, register_data.GetDataStart(), register_data.GetByteSize(), write_error);
+
+ if (!write_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't write the contents of register %s: %s", m_register_info.name, write_error.AsCString());
+ return;
+ }
+ }
+
+ void Dematerialize (lldb::StackFrameSP &frame_sp,
+ IRMemoryMap &map,
+ lldb::addr_t process_address,
+ lldb::addr_t frame_top,
+ lldb::addr_t frame_bottom,
+ Error &err)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+ if (log)
+ {
+ log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 ", m_register_info = %s]",
+ (uint64_t)load_addr,
+ m_register_info.name);
+ }
+
+ Error extract_error;
+
+ DataExtractor register_data;
+
+ if (!frame_sp.get())
+ {
+ err.SetErrorStringWithFormat("couldn't dematerialize register %s without a stack frame", m_register_info.name);
+ return;
+ }
+
+ lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
+
+ map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, extract_error);
+
+ if (!extract_error.Success())
+ {
+ err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", m_register_info.name, extract_error.AsCString());
+ return;
+ }
+
+ if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), register_data.GetByteSize()))
+ {
+ // No write required, and in particular we avoid errors if the register wasn't writable
+
+ m_register_contents.reset();
+ return;
+ }
+
+ m_register_contents.reset();
+
+ RegisterValue register_value (const_cast<uint8_t*>(register_data.GetDataStart()), register_data.GetByteSize(), register_data.GetByteOrder());
+
+ if (!reg_context_sp->WriteRegister(&m_register_info, register_value))
+ {
+ err.SetErrorStringWithFormat("couldn't write the value of register %s", m_register_info.name);
+ return;
+ }
+ }
+
+ void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
+ {
+ StreamString dump_stream;
+
+ Error err;
+
+ const lldb::addr_t load_addr = process_address + m_offset;
+
+
+ dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, m_register_info.name);
+
+ {
+ dump_stream.Printf("Value:\n");
+
+ DataBufferHeap data (m_size, 0);
+
+ map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
+
+ if (!err.Success())
+ {
+ dump_stream.Printf(" <could not be read>\n");
+ }
+ else
+ {
+ DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
+
+ extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
+
+ dump_stream.PutChar('\n');
+ }
+ }
+
+ log->PutCString(dump_stream.GetData());
+ }
+
+ void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
+ {
+ }
+private:
+ RegisterInfo m_register_info;
+ lldb::DataBufferSP m_register_contents;
+};
+
+uint32_t
+Materializer::AddRegister (const RegisterInfo &register_info, Error &err)
+{
+ EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
+ iter->reset (new EntityRegister (register_info));
+ uint32_t ret = AddStructMember(**iter);
+ (*iter)->SetOffset(ret);
+ return ret;
+}
+
+Materializer::Materializer () :
+ m_dematerializer_wp(),
+ m_result_entity(NULL),
+ m_current_offset(0),
+ m_struct_alignment(8)
+{
+}
+
+Materializer::~Materializer ()
+{
+ DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
+
+ if (dematerializer_sp)
+ dematerializer_sp->Wipe();
+}
+
+Materializer::DematerializerSP
+Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
+{
+ ExecutionContextScope *exe_scope = frame_sp.get();
+
+ if (!exe_scope)
+ exe_scope = map.GetBestExecutionContextScope();
+
+ DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
+
+ if (dematerializer_sp)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't materialize: already materialized");
+ }
+
+ DematerializerSP ret(new Dematerializer(*this, frame_sp, map, process_address));
+
+ if (!exe_scope)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't materialize: target doesn't exist");
+ }
+
+ for (EntityUP &entity_up : m_entities)
+ {
+ entity_up->Materialize(frame_sp, map, process_address, error);
+
+ if (!error.Success())
+ return DematerializerSP();
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 ") materialized:", frame_sp.get(), process_address);
+ for (EntityUP &entity_up : m_entities)
+ entity_up->DumpToLog(map, process_address, log);
+ }
+
+ m_dematerializer_wp = ret;
+
+ return ret;
+}
+
+void
+Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_bottom, lldb::addr_t frame_top)
+{
+ lldb::StackFrameSP frame_sp;
+
+ lldb::ThreadSP thread_sp = m_thread_wp.lock();
+ if (thread_sp)
+ frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
+
+ ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
+
+ if (!IsValid())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
+ }
+
+ if (!exe_scope)
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Couldn't dematerialize: target is gone");
+ }
+ else
+ {
+ if (Log *log =lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
+ {
+ log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address = 0x%" PRIx64 ") about to dematerialize:", frame_sp.get(), m_process_address);
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ entity_up->DumpToLog(*m_map, m_process_address, log);
+ }
+
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ {
+ if (entity_up.get() == m_materializer->m_result_entity)
+ {
+ static_cast<EntityResultVariable*>(m_materializer->m_result_entity)->Dematerialize (result_sp, frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
+ }
+ else
+ {
+ entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
+ }
+
+ if (!error.Success())
+ break;
+ }
+ }
+
+ Wipe();
+}
+
+void
+Materializer::Dematerializer::Wipe ()
+{
+ if (!IsValid())
+ return;
+
+ for (EntityUP &entity_up : m_materializer->m_entities)
+ {
+ entity_up->Wipe (*m_map, m_process_address);
+ }
+
+ m_materializer = NULL;
+ m_map = NULL;
+ m_process_address = LLDB_INVALID_ADDRESS;
+}
diff --git a/source/Host/common/Condition.cpp b/source/Host/common/Condition.cpp
new file mode 100644
index 000000000000..daa729cadca5
--- /dev/null
+++ b/source/Host/common/Condition.cpp
@@ -0,0 +1,106 @@
+//===-- Condition.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <errno.h>
+
+#include "lldb/Host/Condition.h"
+#include "lldb/Host/TimeValue.h"
+
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor
+//
+// The default constructor will initialize a new pthread condition
+// and maintain the condition in the object state.
+//----------------------------------------------------------------------
+Condition::Condition () :
+ m_condition()
+{
+ ::pthread_cond_init (&m_condition, NULL);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Destroys the pthread condition that the object owns.
+//----------------------------------------------------------------------
+Condition::~Condition ()
+{
+ ::pthread_cond_destroy (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// Unblock all threads waiting for a condition variable
+//----------------------------------------------------------------------
+int
+Condition::Broadcast ()
+{
+ return ::pthread_cond_broadcast (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// Get accessor to the pthread condition object
+//----------------------------------------------------------------------
+pthread_cond_t *
+Condition::GetCondition ()
+{
+ return &m_condition;
+}
+
+//----------------------------------------------------------------------
+// Unblocks one thread waiting for the condition variable
+//----------------------------------------------------------------------
+int
+Condition::Signal ()
+{
+ return ::pthread_cond_signal (&m_condition);
+}
+
+//----------------------------------------------------------------------
+// The Wait() function atomically blocks the current thread
+// waiting on the owned condition variable, and unblocks the mutex
+// specified by "mutex". The waiting thread unblocks only after
+// another thread calls Signal(), or Broadcast() with the same
+// condition variable, or if "abstime" is valid (non-NULL) this
+// function will return when the system time reaches the time
+// specified in "abstime". If "abstime" is NULL this function will
+// wait for an infinite amount of time for the condition variable
+// to be signaled or broadcasted.
+//
+// The current thread re-acquires the lock on "mutex".
+//----------------------------------------------------------------------
+int
+Condition::Wait (Mutex &mutex, const TimeValue *abstime, bool *timed_out)
+{
+ int err = 0;
+ do
+ {
+ if (abstime && abstime->IsValid())
+ {
+ struct timespec abstime_ts = abstime->GetAsTimeSpec();
+ err = ::pthread_cond_timedwait (&m_condition, mutex.GetMutex(), &abstime_ts);
+ }
+ else
+ err = ::pthread_cond_wait (&m_condition, mutex.GetMutex());
+ } while (err == EINTR);
+
+ if (timed_out != NULL)
+ {
+ if (err == ETIMEDOUT)
+ *timed_out = true;
+ else
+ *timed_out = false;
+ }
+
+
+ return err;
+}
+
diff --git a/source/Host/common/DynamicLibrary.cpp b/source/Host/common/DynamicLibrary.cpp
new file mode 100644
index 000000000000..315a675895ff
--- /dev/null
+++ b/source/Host/common/DynamicLibrary.cpp
@@ -0,0 +1,33 @@
+//===-- DynamicLibrary.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Error.h"
+#include "lldb/Host/DynamicLibrary.h"
+
+using namespace lldb_private;
+
+DynamicLibrary::DynamicLibrary (const FileSpec& spec, uint32_t options) : m_filespec(spec)
+{
+ Error err;
+ m_handle = Host::DynamicLibraryOpen (spec,options,err);
+ if (err.Fail())
+ m_handle = NULL;
+}
+
+bool
+DynamicLibrary::IsValid ()
+{
+ return m_handle != NULL;
+}
+
+DynamicLibrary::~DynamicLibrary ()
+{
+ if (m_handle)
+ Host::DynamicLibraryClose (m_handle);
+}
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
new file mode 100644
index 000000000000..c0d3c290f4c7
--- /dev/null
+++ b/source/Host/common/File.cpp
@@ -0,0 +1,716 @@
+//===-- FileSpec.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/File.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Config.h"
+#include "lldb/Host/FileSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *
+GetStreamOpenModeFromOptions (uint32_t options)
+{
+ if (options & File::eOpenOptionAppend)
+ {
+ if (options & File::eOpenOptionRead)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "a+x";
+ else
+ return "a+";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "ax";
+ else
+ return "a";
+ }
+ }
+ else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite)
+ {
+ if (options & File::eOpenOptionCanCreate)
+ {
+ if (options & File::eOpenOptionCanCreateNewOnly)
+ return "w+x";
+ else
+ return "w+";
+ }
+ else
+ return "r+";
+ }
+ else if (options & File::eOpenOptionRead)
+ {
+ return "r";
+ }
+ else if (options & File::eOpenOptionWrite)
+ {
+ return "w";
+ }
+ return NULL;
+}
+
+int File::kInvalidDescriptor = -1;
+FILE * File::kInvalidStream = NULL;
+
+File::File(const char *path, uint32_t options, uint32_t permissions) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ Open (path, options, permissions);
+}
+
+File::File (const File &rhs) :
+ m_descriptor (kInvalidDescriptor),
+ m_stream (kInvalidStream),
+ m_options (0),
+ m_owned (false)
+{
+ Duplicate (rhs);
+}
+
+
+File &
+File::operator = (const File &rhs)
+{
+ if (this != &rhs)
+ Duplicate (rhs);
+ return *this;
+}
+
+File::~File()
+{
+ Close ();
+}
+
+
+int
+File::GetDescriptor() const
+{
+ if (DescriptorIsValid())
+ return m_descriptor;
+
+ // Don't open the file descriptor if we don't need to, just get it from the
+ // stream if we have one.
+ if (StreamIsValid())
+ return fileno (m_stream);
+
+ // Invalid descriptor and invalid stream, return invalid descriptor.
+ return kInvalidDescriptor;
+}
+
+void
+File::SetDescriptor (int fd, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_descriptor = fd;
+ m_owned = transfer_ownership;
+}
+
+
+FILE *
+File::GetStream ()
+{
+ if (!StreamIsValid())
+ {
+ if (DescriptorIsValid())
+ {
+ const char *mode = GetStreamOpenModeFromOptions (m_options);
+ if (mode)
+ {
+ do
+ {
+ m_stream = ::fdopen (m_descriptor, mode);
+ } while (m_stream == NULL && errno == EINTR);
+ }
+ }
+ }
+ return m_stream;
+}
+
+
+void
+File::SetStream (FILE *fh, bool transfer_ownership)
+{
+ if (IsValid())
+ Close();
+ m_stream = fh;
+ m_owned = transfer_ownership;
+}
+
+Error
+File::Duplicate (const File &rhs)
+{
+ Error error;
+ if (IsValid ())
+ Close();
+
+ if (rhs.DescriptorIsValid())
+ {
+ m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
+ if (!DescriptorIsValid())
+ error.SetErrorToErrno();
+ else
+ {
+ m_options = rhs.m_options;
+ m_owned = true;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid file to duplicate");
+ }
+ return error;
+}
+
+Error
+File::Open (const char *path, uint32_t options, uint32_t permissions)
+{
+ Error error;
+ if (IsValid())
+ Close ();
+
+ int oflag = 0;
+ const bool read = options & eOpenOptionRead;
+ const bool write = options & eOpenOptionWrite;
+ if (write)
+ {
+ if (read)
+ oflag |= O_RDWR;
+ else
+ oflag |= O_WRONLY;
+
+ if (options & eOpenOptionAppend)
+ oflag |= O_APPEND;
+
+ if (options & eOpenOptionTruncate)
+ oflag |= O_TRUNC;
+
+ if (options & eOpenOptionCanCreate)
+ oflag |= O_CREAT;
+
+ if (options & eOpenOptionCanCreateNewOnly)
+ oflag |= O_CREAT | O_EXCL;
+ }
+ else if (read)
+ {
+ oflag |= O_RDONLY;
+ }
+
+ if (options & eOpenOptionNonBlocking)
+ oflag |= O_NONBLOCK;
+
+ mode_t mode = 0;
+ if (oflag & O_CREAT)
+ {
+ if (permissions & ePermissionsUserRead) mode |= S_IRUSR;
+ if (permissions & ePermissionsUserWrite) mode |= S_IWUSR;
+ if (permissions & ePermissionsUserExecute) mode |= S_IXUSR;
+ if (permissions & ePermissionsGroupRead) mode |= S_IRGRP;
+ if (permissions & ePermissionsGroupWrite) mode |= S_IWGRP;
+ if (permissions & ePermissionsGroupExecute) mode |= S_IXGRP;
+ if (permissions & ePermissionsWorldRead) mode |= S_IROTH;
+ if (permissions & ePermissionsWorldWrite) mode |= S_IWOTH;
+ if (permissions & ePermissionsWorldExecute) mode |= S_IXOTH;
+ }
+
+ do
+ {
+ m_descriptor = ::open(path, oflag, mode);
+ } while (m_descriptor < 0 && errno == EINTR);
+
+ if (!DescriptorIsValid())
+ error.SetErrorToErrno();
+ else
+ m_owned = true;
+
+ return error;
+}
+
+Error
+File::Close ()
+{
+ Error error;
+ if (IsValid ())
+ {
+ if (m_owned)
+ {
+ if (StreamIsValid())
+ {
+ if (::fclose (m_stream) == EOF)
+ error.SetErrorToErrno();
+ }
+
+ if (DescriptorIsValid())
+ {
+ if (::close (m_descriptor) != 0)
+ error.SetErrorToErrno();
+ }
+ }
+ m_descriptor = kInvalidDescriptor;
+ m_stream = kInvalidStream;
+ m_options = 0;
+ m_owned = false;
+ }
+ return error;
+}
+
+
+Error
+File::GetFileSpec (FileSpec &file_spec) const
+{
+ Error error;
+#ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED
+ if (IsValid ())
+ {
+ char path[PATH_MAX];
+ if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1)
+ error.SetErrorToErrno();
+ else
+ file_spec.SetFile (path, false);
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+#elif defined(__linux__)
+ char proc[64];
+ char path[PATH_MAX];
+ if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0)
+ error.SetErrorString ("cannot resolve file descriptor");
+ else
+ {
+ ssize_t len;
+ if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1)
+ error.SetErrorToErrno();
+ else
+ {
+ path[len] = '\0';
+ file_spec.SetFile (path, false);
+ }
+ }
+#else
+ error.SetErrorString ("File::GetFileSpec is not supported on this platform");
+#endif
+
+ if (error.Fail())
+ file_spec.Clear();
+ return error;
+}
+
+off_t
+File::SeekFromStart (off_t offset, Error *error_ptr)
+{
+ off_t result = 0;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_SET);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromCurrent (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_CUR);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+off_t
+File::SeekFromEnd (off_t offset, Error *error_ptr)
+{
+ off_t result = -1;
+ if (DescriptorIsValid())
+ {
+ result = ::lseek (m_descriptor, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (StreamIsValid ())
+ {
+ result = ::fseek(m_stream, offset, SEEK_END);
+
+ if (error_ptr)
+ {
+ if (result == -1)
+ error_ptr->SetErrorToErrno();
+ else
+ error_ptr->Clear();
+ }
+ }
+ else if (error_ptr)
+ {
+ error_ptr->SetErrorString("invalid file handle");
+ }
+ return result;
+}
+
+Error
+File::Flush ()
+{
+ Error error;
+ if (StreamIsValid())
+ {
+ int err = 0;
+ do
+ {
+ err = ::fflush (m_stream);
+ } while (err == EOF && errno == EINTR);
+
+ if (err == EOF)
+ error.SetErrorToErrno();
+ }
+ else if (!DescriptorIsValid())
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+
+Error
+File::Sync ()
+{
+ Error error;
+ if (DescriptorIsValid())
+ {
+ int err = 0;
+ do
+ {
+ err = ::fsync (m_descriptor);
+ } while (err == -1 && errno == EINTR);
+
+ if (err == -1)
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Read (void *buf, size_t &num_bytes)
+{
+ Error error;
+ ssize_t bytes_read = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_read = ::read (m_descriptor, buf, num_bytes);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_read = ::fread (buf, 1, num_bytes, m_stream);
+
+ if (bytes_read == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_read;
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes)
+{
+ Error error;
+ ssize_t bytes_written = -1;
+ if (DescriptorIsValid())
+ {
+ do
+ {
+ bytes_written = ::write (m_descriptor, buf, num_bytes);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written == -1)
+ {
+ error.SetErrorToErrno();
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+ }
+ else if (StreamIsValid())
+ {
+ bytes_written = ::fwrite (buf, 1, num_bytes, m_stream);
+
+ if (bytes_written == 0)
+ {
+ if (::feof(m_stream))
+ error.SetErrorString ("feof");
+ else if (::ferror (m_stream))
+ error.SetErrorString ("ferror");
+ num_bytes = 0;
+ }
+ else
+ num_bytes = bytes_written;
+
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+
+Error
+File::Read (void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ ssize_t bytes_read = -1;
+ do
+ {
+ bytes_read = ::pread (fd, buf, num_bytes, offset);
+ } while (bytes_read < 0 && errno == EINTR);
+
+ if (bytes_read < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_read;
+ num_bytes = bytes_read;
+ }
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+Error
+File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp)
+{
+ Error error;
+
+ if (num_bytes > 0)
+ {
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ struct stat file_stats;
+ if (::fstat (fd, &file_stats) == 0)
+ {
+ if (file_stats.st_size > offset)
+ {
+ const size_t bytes_left = file_stats.st_size - offset;
+ if (num_bytes > bytes_left)
+ num_bytes = bytes_left;
+
+ std::unique_ptr<DataBufferHeap> data_heap_ap;
+ data_heap_ap.reset(new DataBufferHeap(num_bytes + (null_terminate ? 1 : 0), '\0'));
+
+ if (data_heap_ap.get())
+ {
+ error = Read (data_heap_ap->GetBytes(), num_bytes, offset);
+ if (error.Success())
+ {
+ // Make sure we read exactly what we asked for and if we got
+ // less, adjust the array
+ if (num_bytes < data_heap_ap->GetByteSize())
+ data_heap_ap->SetByteSize(num_bytes);
+ data_buffer_sp.reset(data_heap_ap.release());
+ return error;
+ }
+ }
+ }
+ else
+ error.SetErrorString("file is empty");
+ }
+ else
+ error.SetErrorToErrno();
+ }
+ else
+ error.SetErrorString("invalid file handle");
+ }
+ else
+ error.SetErrorString("invalid file handle");
+
+ num_bytes = 0;
+ data_buffer_sp.reset();
+ return error;
+}
+
+Error
+File::Write (const void *buf, size_t &num_bytes, off_t &offset)
+{
+ Error error;
+ int fd = GetDescriptor();
+ if (fd != kInvalidDescriptor)
+ {
+ ssize_t bytes_written = -1;
+ do
+ {
+ bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset);
+ } while (bytes_written < 0 && errno == EINTR);
+
+ if (bytes_written < 0)
+ {
+ num_bytes = 0;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ offset += bytes_written;
+ num_bytes = bytes_written;
+ }
+ }
+ else
+ {
+ num_bytes = 0;
+ error.SetErrorString("invalid file handle");
+ }
+ return error;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::Printf (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ size_t result = PrintfVarArg (format, args);
+ va_end (args);
+ return result;
+}
+
+//------------------------------------------------------------------
+// Print some formatted output to the stream.
+//------------------------------------------------------------------
+size_t
+File::PrintfVarArg (const char *format, va_list args)
+{
+ size_t result = 0;
+ if (DescriptorIsValid())
+ {
+ char *s = NULL;
+ result = vasprintf(&s, format, args);
+ if (s != NULL)
+ {
+ if (result > 0)
+ {
+ size_t s_len = result;
+ Write (s, s_len);
+ result = s_len;
+ }
+ free (s);
+ }
+ }
+ else if (StreamIsValid())
+ {
+ result = ::vfprintf (m_stream, format, args);
+ }
+ return result;
+}
diff --git a/source/Host/common/FileSpec.cpp b/source/Host/common/FileSpec.cpp
new file mode 100644
index 000000000000..08d626e836a1
--- /dev/null
+++ b/source/Host/common/FileSpec.cpp
@@ -0,0 +1,1059 @@
+//===-- FileSpec.cpp --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <sys/stat.h>
+#include <set>
+#include <string.h>
+#include <fstream>
+
+#include "lldb/Host/Config.h" // Have to include this before we test the define...
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+#include <pwd.h>
+#endif
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Program.h"
+
+#include "lldb/Host/File.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataBufferMemoryMap.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Utility/CleanUp.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+GetFileStats (const FileSpec *file_spec, struct stat *stats_ptr)
+{
+ char resolved_path[PATH_MAX];
+ if (file_spec->GetPath (resolved_path, sizeof(resolved_path)))
+ return ::stat (resolved_path, stats_ptr) == 0;
+ return false;
+}
+
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+
+static const char*
+GetCachedGlobTildeSlash()
+{
+ static std::string g_tilde;
+ if (g_tilde.empty())
+ {
+ struct passwd *user_entry;
+ user_entry = getpwuid(geteuid());
+ if (user_entry != NULL)
+ g_tilde = user_entry->pw_dir;
+
+ if (g_tilde.empty())
+ return NULL;
+ }
+ return g_tilde.c_str();
+}
+
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+
+// Resolves the username part of a path of the form ~user/other/directories, and
+// writes the result into dst_path.
+// Returns 0 if there WAS a ~ in the path but the username couldn't be resolved.
+// Otherwise returns the number of characters copied into dst_path. If the return
+// is >= dst_len, then the resolved path is too long...
+size_t
+FileSpec::ResolveUsername (const char *src_path, char *dst_path, size_t dst_len)
+{
+ if (src_path == NULL || src_path[0] == '\0')
+ return 0;
+
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+
+ char user_home[PATH_MAX];
+ const char *user_name;
+
+
+ // If there's no ~, then just copy src_path straight to dst_path (they may be the same string...)
+ if (src_path[0] != '~')
+ {
+ size_t len = strlen (src_path);
+ if (len >= dst_len)
+ {
+ ::bcopy (src_path, dst_path, dst_len - 1);
+ dst_path[dst_len] = '\0';
+ }
+ else
+ ::bcopy (src_path, dst_path, len + 1);
+
+ return len;
+ }
+
+ const char *first_slash = ::strchr (src_path, '/');
+ char remainder[PATH_MAX];
+
+ if (first_slash == NULL)
+ {
+ // The whole name is the username (minus the ~):
+ user_name = src_path + 1;
+ remainder[0] = '\0';
+ }
+ else
+ {
+ size_t user_name_len = first_slash - src_path - 1;
+ ::memcpy (user_home, src_path + 1, user_name_len);
+ user_home[user_name_len] = '\0';
+ user_name = user_home;
+
+ ::strcpy (remainder, first_slash);
+ }
+
+ if (user_name == NULL)
+ return 0;
+ // User name of "" means the current user...
+
+ struct passwd *user_entry;
+ const char *home_dir = NULL;
+
+ if (user_name[0] == '\0')
+ {
+ home_dir = GetCachedGlobTildeSlash();
+ }
+ else
+ {
+ user_entry = ::getpwnam (user_name);
+ if (user_entry != NULL)
+ home_dir = user_entry->pw_dir;
+ }
+
+ if (home_dir == NULL)
+ return 0;
+ else
+ return ::snprintf (dst_path, dst_len, "%s%s", home_dir, remainder);
+#else
+ // Resolving home directories is not supported, just copy the path...
+ return ::snprintf (dst_path, dst_len, "%s", src_path);
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+}
+
+size_t
+FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches)
+{
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ size_t extant_entries = matches.GetSize();
+
+ setpwent();
+ struct passwd *user_entry;
+ const char *name_start = partial_name + 1;
+ std::set<std::string> name_list;
+
+ while ((user_entry = getpwent()) != NULL)
+ {
+ if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name)
+ {
+ std::string tmp_buf("~");
+ tmp_buf.append(user_entry->pw_name);
+ tmp_buf.push_back('/');
+ name_list.insert(tmp_buf);
+ }
+ }
+ std::set<std::string>::iterator pos, end = name_list.end();
+ for (pos = name_list.begin(); pos != end; pos++)
+ {
+ matches.AppendString((*pos).c_str());
+ }
+ return matches.GetSize() - extant_entries;
+#else
+ // Resolving home directories is not supported, just copy the path...
+ return 0;
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+}
+
+
+
+size_t
+FileSpec::Resolve (const char *src_path, char *dst_path, size_t dst_len)
+{
+ if (src_path == NULL || src_path[0] == '\0')
+ return 0;
+
+ // Glob if needed for ~/, otherwise copy in case src_path is same as dst_path...
+ char unglobbed_path[PATH_MAX];
+#ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ if (src_path[0] == '~')
+ {
+ size_t return_count = ResolveUsername(src_path, unglobbed_path, sizeof(unglobbed_path));
+
+ // If we couldn't find the user referred to, or the resultant path was too long,
+ // then just copy over the src_path.
+ if (return_count == 0 || return_count >= sizeof(unglobbed_path))
+ ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
+ }
+ else
+#endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER
+ {
+ ::snprintf(unglobbed_path, sizeof(unglobbed_path), "%s", src_path);
+ }
+
+ // Now resolve the path if needed
+ char resolved_path[PATH_MAX];
+ if (::realpath (unglobbed_path, resolved_path))
+ {
+ // Success, copy the resolved path
+ return ::snprintf(dst_path, dst_len, "%s", resolved_path);
+ }
+ else
+ {
+ // Failed, just copy the unglobbed path
+ return ::snprintf(dst_path, dst_len, "%s", unglobbed_path);
+ }
+}
+
+FileSpec::FileSpec() :
+ m_directory(),
+ m_filename()
+{
+}
+
+//------------------------------------------------------------------
+// Default constructor that can take an optional full path to a
+// file on disk.
+//------------------------------------------------------------------
+FileSpec::FileSpec(const char *pathname, bool resolve_path) :
+ m_directory(),
+ m_filename(),
+ m_is_resolved(false)
+{
+ if (pathname && pathname[0])
+ SetFile(pathname, resolve_path);
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec& rhs) :
+ m_directory (rhs.m_directory),
+ m_filename (rhs.m_filename),
+ m_is_resolved (rhs.m_is_resolved)
+{
+}
+
+//------------------------------------------------------------------
+// Copy constructor
+//------------------------------------------------------------------
+FileSpec::FileSpec(const FileSpec* rhs) :
+ m_directory(),
+ m_filename()
+{
+ if (rhs)
+ *this = *rhs;
+}
+
+//------------------------------------------------------------------
+// Virtual destrcuctor in case anyone inherits from this class.
+//------------------------------------------------------------------
+FileSpec::~FileSpec()
+{
+}
+
+//------------------------------------------------------------------
+// Assignment operator.
+//------------------------------------------------------------------
+const FileSpec&
+FileSpec::operator= (const FileSpec& rhs)
+{
+ if (this != &rhs)
+ {
+ m_directory = rhs.m_directory;
+ m_filename = rhs.m_filename;
+ m_is_resolved = rhs.m_is_resolved;
+ }
+ return *this;
+}
+
+//------------------------------------------------------------------
+// Update the contents of this object with a new path. The path will
+// be split up into a directory and filename and stored as uniqued
+// string values for quick comparison and efficient memory usage.
+//------------------------------------------------------------------
+void
+FileSpec::SetFile (const char *pathname, bool resolve)
+{
+ m_filename.Clear();
+ m_directory.Clear();
+ m_is_resolved = false;
+ if (pathname == NULL || pathname[0] == '\0')
+ return;
+
+ char resolved_path[PATH_MAX];
+ bool path_fit = true;
+
+ if (resolve)
+ {
+ path_fit = (FileSpec::Resolve (pathname, resolved_path, sizeof(resolved_path)) < sizeof(resolved_path) - 1);
+ m_is_resolved = path_fit;
+ }
+ else
+ {
+ // Copy the path because "basename" and "dirname" want to muck with the
+ // path buffer
+ if (::strlen (pathname) > sizeof(resolved_path) - 1)
+ path_fit = false;
+ else
+ ::strcpy (resolved_path, pathname);
+ }
+
+
+ if (path_fit)
+ {
+ char *filename = ::basename (resolved_path);
+ if (filename)
+ {
+ m_filename.SetCString (filename);
+ // Truncate the basename off the end of the resolved path
+
+ // Only attempt to get the dirname if it looks like we have a path
+ if (strchr(resolved_path, '/'))
+ {
+ char *directory = ::dirname (resolved_path);
+
+ // Make sure we didn't get our directory resolved to "." without having
+ // specified
+ if (directory)
+ m_directory.SetCString(directory);
+ else
+ {
+ char *last_resolved_path_slash = strrchr(resolved_path, '/');
+ if (last_resolved_path_slash)
+ {
+ *last_resolved_path_slash = '\0';
+ m_directory.SetCString(resolved_path);
+ }
+ }
+ }
+ }
+ else
+ m_directory.SetCString(resolved_path);
+ }
+}
+
+//----------------------------------------------------------------------
+// Convert to pointer operator. This allows code to check any FileSpec
+// objects to see if they contain anything valid using code such as:
+//
+// if (file_spec)
+// {}
+//----------------------------------------------------------------------
+FileSpec::operator bool() const
+{
+ return m_filename || m_directory;
+}
+
+//----------------------------------------------------------------------
+// Logical NOT operator. This allows code to check any FileSpec
+// objects to see if they are invalid using code such as:
+//
+// if (!file_spec)
+// {}
+//----------------------------------------------------------------------
+bool
+FileSpec::operator!() const
+{
+ return !m_directory && !m_filename;
+}
+
+//------------------------------------------------------------------
+// Equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator== (const FileSpec& rhs) const
+{
+ if (m_filename == rhs.m_filename)
+ {
+ if (m_directory == rhs.m_directory)
+ return true;
+
+ // TODO: determine if we want to keep this code in here.
+ // The code below was added to handle a case where we were
+ // trying to set a file and line breakpoint and one path
+ // was resolved, and the other not and the directory was
+ // in a mount point that resolved to a more complete path:
+ // "/tmp/a.c" == "/private/tmp/a.c". I might end up pulling
+ // this out...
+ if (IsResolved() && rhs.IsResolved())
+ {
+ // Both paths are resolved, no need to look further...
+ return false;
+ }
+
+ FileSpec resolved_lhs(*this);
+
+ // If "this" isn't resolved, resolve it
+ if (!IsResolved())
+ {
+ if (resolved_lhs.ResolvePath())
+ {
+ // This path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as our unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ m_is_resolved = (m_directory == resolved_lhs.m_directory);
+ }
+ else
+ return false;
+ }
+
+ FileSpec resolved_rhs(rhs);
+ if (!rhs.IsResolved())
+ {
+ if (resolved_rhs.ResolvePath())
+ {
+ // rhs's path wasn't resolved but now it is. Check if the resolved
+ // directory is the same as rhs's unresolved directory, and if so,
+ // we can mark this object as resolved to avoid more future resolves
+ rhs.m_is_resolved = (rhs.m_directory == resolved_rhs.m_directory);
+ }
+ else
+ return false;
+ }
+
+ // If we reach this point in the code we were able to resolve both paths
+ // and since we only resolve the paths if the basenames are equal, then
+ // we can just check if both directories are equal...
+ return resolved_lhs.GetDirectory() == resolved_rhs.GetDirectory();
+ }
+ return false;
+}
+
+//------------------------------------------------------------------
+// Not equal to operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator!= (const FileSpec& rhs) const
+{
+ return !(*this == rhs);
+}
+
+//------------------------------------------------------------------
+// Less than operator
+//------------------------------------------------------------------
+bool
+FileSpec::operator< (const FileSpec& rhs) const
+{
+ return FileSpec::Compare(*this, rhs, true) < 0;
+}
+
+//------------------------------------------------------------------
+// Dump a FileSpec object to a stream
+//------------------------------------------------------------------
+Stream&
+lldb_private::operator << (Stream &s, const FileSpec& f)
+{
+ f.Dump(&s);
+ return s;
+}
+
+//------------------------------------------------------------------
+// Clear this object by releasing both the directory and filename
+// string values and making them both the empty string.
+//------------------------------------------------------------------
+void
+FileSpec::Clear()
+{
+ m_directory.Clear();
+ m_filename.Clear();
+}
+
+//------------------------------------------------------------------
+// Compare two FileSpec objects. If "full" is true, then both
+// the directory and the filename must match. If "full" is false,
+// then the directory names for "a" and "b" are only compared if
+// they are both non-empty. This allows a FileSpec object to only
+// contain a filename and it can match FileSpec objects that have
+// matching filenames with different paths.
+//
+// Return -1 if the "a" is less than "b", 0 if "a" is equal to "b"
+// and "1" if "a" is greater than "b".
+//------------------------------------------------------------------
+int
+FileSpec::Compare(const FileSpec& a, const FileSpec& b, bool full)
+{
+ int result = 0;
+
+ // If full is true, then we must compare both the directory and filename.
+
+ // If full is false, then if either directory is empty, then we match on
+ // the basename only, and if both directories have valid values, we still
+ // do a full compare. This allows for matching when we just have a filename
+ // in one of the FileSpec objects.
+
+ if (full || (a.m_directory && b.m_directory))
+ {
+ result = ConstString::Compare(a.m_directory, b.m_directory);
+ if (result)
+ return result;
+ }
+ return ConstString::Compare (a.m_filename, b.m_filename);
+}
+
+bool
+FileSpec::Equal (const FileSpec& a, const FileSpec& b, bool full)
+{
+ if (!full && (a.GetDirectory().IsEmpty() || b.GetDirectory().IsEmpty()))
+ return a.m_filename == b.m_filename;
+ else
+ return a == b;
+}
+
+
+
+//------------------------------------------------------------------
+// Dump the object to the supplied stream. If the object contains
+// a valid directory name, it will be displayed followed by a
+// directory delimiter, and the filename.
+//------------------------------------------------------------------
+void
+FileSpec::Dump(Stream *s) const
+{
+ static ConstString g_slash_only ("/");
+ if (s)
+ {
+ m_directory.Dump(s);
+ if (m_directory && m_directory != g_slash_only)
+ s->PutChar('/');
+ m_filename.Dump(s);
+ }
+}
+
+//------------------------------------------------------------------
+// Returns true if the file exists.
+//------------------------------------------------------------------
+bool
+FileSpec::Exists () const
+{
+ struct stat file_stats;
+ return GetFileStats (this, &file_stats);
+}
+
+bool
+FileSpec::ResolveExecutableLocation ()
+{
+ if (!m_directory)
+ {
+ const char *file_cstr = m_filename.GetCString();
+ if (file_cstr)
+ {
+ const std::string file_str (file_cstr);
+ std::string path = llvm::sys::FindProgramByName (file_str);
+ llvm::StringRef dir_ref = llvm::sys::path::parent_path(path);
+ //llvm::StringRef dir_ref = path.getDirname();
+ if (! dir_ref.empty())
+ {
+ // FindProgramByName returns "." if it can't find the file.
+ if (strcmp (".", dir_ref.data()) == 0)
+ return false;
+
+ m_directory.SetCString (dir_ref.data());
+ if (Exists())
+ return true;
+ else
+ {
+ // If FindProgramByName found the file, it returns the directory + filename in its return results.
+ // We need to separate them.
+ FileSpec tmp_file (dir_ref.data(), false);
+ if (tmp_file.Exists())
+ {
+ m_directory = tmp_file.m_directory;
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool
+FileSpec::ResolvePath ()
+{
+ if (m_is_resolved)
+ return true; // We have already resolved this path
+
+ char path_buf[PATH_MAX];
+ if (!GetPath (path_buf, PATH_MAX))
+ return false;
+ // SetFile(...) will set m_is_resolved correctly if it can resolve the path
+ SetFile (path_buf, true);
+ return m_is_resolved;
+}
+
+uint64_t
+FileSpec::GetByteSize() const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ return file_stats.st_size;
+ return 0;
+}
+
+FileSpec::FileType
+FileSpec::GetFileType () const
+{
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ {
+ mode_t file_type = file_stats.st_mode & S_IFMT;
+ switch (file_type)
+ {
+ case S_IFDIR: return eFileTypeDirectory;
+ case S_IFIFO: return eFileTypePipe;
+ case S_IFREG: return eFileTypeRegular;
+ case S_IFSOCK: return eFileTypeSocket;
+ case S_IFLNK: return eFileTypeSymbolicLink;
+ default:
+ break;
+ }
+ return eFileTypeUnknown;
+ }
+ return eFileTypeInvalid;
+}
+
+TimeValue
+FileSpec::GetModificationTime () const
+{
+ TimeValue mod_time;
+ struct stat file_stats;
+ if (GetFileStats (this, &file_stats))
+ mod_time.OffsetWithSeconds(file_stats.st_mtime);
+ return mod_time;
+}
+
+//------------------------------------------------------------------
+// Directory string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetDirectory()
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Directory string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetDirectory() const
+{
+ return m_directory;
+}
+
+//------------------------------------------------------------------
+// Filename string get accessor.
+//------------------------------------------------------------------
+ConstString &
+FileSpec::GetFilename()
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Filename string const get accessor.
+//------------------------------------------------------------------
+const ConstString &
+FileSpec::GetFilename() const
+{
+ return m_filename;
+}
+
+//------------------------------------------------------------------
+// Extract the directory and path into a fixed buffer. This is
+// needed as the directory and path are stored in separate string
+// values.
+//------------------------------------------------------------------
+size_t
+FileSpec::GetPath(char *path, size_t path_max_len) const
+{
+ if (path_max_len)
+ {
+ const char *dirname = m_directory.GetCString();
+ const char *filename = m_filename.GetCString();
+ if (dirname)
+ {
+ if (filename)
+ return ::snprintf (path, path_max_len, "%s/%s", dirname, filename);
+ else
+ return ::snprintf (path, path_max_len, "%s", dirname);
+ }
+ else if (filename)
+ {
+ return ::snprintf (path, path_max_len, "%s", filename);
+ }
+ }
+ if (path)
+ path[0] = '\0';
+ return 0;
+}
+
+std::string
+FileSpec::GetPath (void) const
+{
+ static ConstString g_slash_only ("/");
+ std::string path;
+ const char *dirname = m_directory.GetCString();
+ const char *filename = m_filename.GetCString();
+ if (dirname)
+ {
+ path.append (dirname);
+ if (filename && m_directory != g_slash_only)
+ path.append ("/");
+ }
+ if (filename)
+ path.append (filename);
+ return path;
+}
+
+ConstString
+FileSpec::GetFileNameExtension () const
+{
+ if (m_filename)
+ {
+ const char *filename = m_filename.GetCString();
+ const char* dot_pos = strrchr(filename, '.');
+ if (dot_pos && dot_pos[1] != '\0')
+ return ConstString(dot_pos+1);
+ }
+ return ConstString();
+}
+
+ConstString
+FileSpec::GetFileNameStrippingExtension () const
+{
+ const char *filename = m_filename.GetCString();
+ if (filename == NULL)
+ return ConstString();
+
+ const char* dot_pos = strrchr(filename, '.');
+ if (dot_pos == NULL)
+ return m_filename;
+
+ return ConstString(filename, dot_pos-filename);
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data is memory mapped and
+// will lazily page in data from the file as memory is accessed.
+// The data that is mappped will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const
+{
+ DataBufferSP data_sp;
+ std::unique_ptr<DataBufferMemoryMap> mmap_data(new DataBufferMemoryMap());
+ if (mmap_data.get())
+ {
+ const size_t mapped_length = mmap_data->MemoryMapFromFileSpec (this, file_offset, file_size);
+ if (((file_size == SIZE_MAX) && (mapped_length > 0)) || (mapped_length >= file_size))
+ data_sp.reset(mmap_data.release());
+ }
+ return data_sp;
+}
+
+
+//------------------------------------------------------------------
+// Return the size in bytes that this object takes in memory. This
+// returns the size in bytes of this object, not any shared string
+// values it may refer to.
+//------------------------------------------------------------------
+size_t
+FileSpec::MemorySize() const
+{
+ return m_filename.MemorySize() + m_directory.MemorySize();
+}
+
+
+size_t
+FileSpec::ReadFileContents (off_t file_offset, void *dst, size_t dst_len, Error *error_ptr) const
+{
+ Error error;
+ size_t bytes_read = 0;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ off_t file_offset_after_seek = file_offset;
+ bytes_read = dst_len;
+ error = file.Read(dst, bytes_read, file_offset_after_seek);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return bytes_read;
+}
+
+//------------------------------------------------------------------
+// Returns a shared pointer to a data buffer that contains all or
+// part of the contents of a file. The data copies into a heap based
+// buffer that lives in the DataBuffer shared pointer object returned.
+// The data that is cached will start "file_offset" bytes into the
+// file, and "file_size" bytes will be mapped. If "file_size" is
+// greater than the number of bytes available in the file starting
+// at "file_offset", the number of bytes will be appropriately
+// truncated. The final number of bytes that get mapped can be
+// verified using the DataBuffer::GetByteSize() function.
+//------------------------------------------------------------------
+DataBufferSP
+FileSpec::ReadFileContents (off_t file_offset, size_t file_size, Error *error_ptr) const
+{
+ Error error;
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ const bool null_terminate = false;
+ error = file.Read (file_size, file_offset, null_terminate, data_sp);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return data_sp;
+}
+
+DataBufferSP
+FileSpec::ReadFileContentsAsCString(Error *error_ptr)
+{
+ Error error;
+ DataBufferSP data_sp;
+ char resolved_path[PATH_MAX];
+ if (GetPath(resolved_path, sizeof(resolved_path)))
+ {
+ File file;
+ error = file.Open(resolved_path, File::eOpenOptionRead);
+ if (error.Success())
+ {
+ off_t offset = 0;
+ size_t length = SIZE_MAX;
+ const bool null_terminate = true;
+ error = file.Read (length, offset, null_terminate, data_sp);
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid file specification");
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return data_sp;
+}
+
+size_t
+FileSpec::ReadFileLines (STLStringArray &lines)
+{
+ lines.clear();
+ char path[PATH_MAX];
+ if (GetPath(path, sizeof(path)))
+ {
+ std::ifstream file_stream (path);
+
+ if (file_stream)
+ {
+ std::string line;
+ while (getline (file_stream, line))
+ lines.push_back (line);
+ }
+ }
+ return lines.size();
+}
+
+FileSpec::EnumerateDirectoryResult
+FileSpec::EnumerateDirectory
+(
+ const char *dir_path,
+ bool find_directories,
+ bool find_files,
+ bool find_other,
+ EnumerateDirectoryCallbackType callback,
+ void *callback_baton
+)
+{
+ if (dir_path && dir_path[0])
+ {
+ lldb_utility::CleanUp <DIR *, int> dir_path_dir (opendir(dir_path), NULL, closedir);
+ if (dir_path_dir.is_valid())
+ {
+ long path_max = fpathconf (dirfd (dir_path_dir.get()), _PC_NAME_MAX);
+#if defined (__APPLE_) && defined (__DARWIN_MAXPATHLEN)
+ if (path_max < __DARWIN_MAXPATHLEN)
+ path_max = __DARWIN_MAXPATHLEN;
+#endif
+ struct dirent *buf, *dp;
+ buf = (struct dirent *) malloc (offsetof (struct dirent, d_name) + path_max + 1);
+
+ while (buf && readdir_r(dir_path_dir.get(), buf, &dp) == 0 && dp)
+ {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN)
+ {
+ size_t len = strlen(dp->d_name);
+
+ if (len == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (len == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ bool call_callback = false;
+ FileSpec::FileType file_type = eFileTypeUnknown;
+
+ switch (dp->d_type)
+ {
+ default:
+ case DT_UNKNOWN: file_type = eFileTypeUnknown; call_callback = true; break;
+ case DT_FIFO: file_type = eFileTypePipe; call_callback = find_other; break;
+ case DT_CHR: file_type = eFileTypeOther; call_callback = find_other; break;
+ case DT_DIR: file_type = eFileTypeDirectory; call_callback = find_directories; break;
+ case DT_BLK: file_type = eFileTypeOther; call_callback = find_other; break;
+ case DT_REG: file_type = eFileTypeRegular; call_callback = find_files; break;
+ case DT_LNK: file_type = eFileTypeSymbolicLink; call_callback = find_other; break;
+ case DT_SOCK: file_type = eFileTypeSocket; call_callback = find_other; break;
+#if !defined(__OpenBSD__)
+ case DT_WHT: file_type = eFileTypeOther; call_callback = find_other; break;
+#endif
+ }
+
+ 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);
+ if (child_path_len < (int)(sizeof(child_path) - 1))
+ {
+ // Don't resolve the file type or path
+ FileSpec child_path_spec (child_path, false);
+
+ EnumerateDirectoryResult result = callback (callback_baton, file_type, child_path_spec);
+
+ switch (result)
+ {
+ case eEnumerateDirectoryResultNext:
+ // Enumerate next entry in the current directory. We just
+ // exit this switch and will continue enumerating the
+ // current directory as we currently are...
+ break;
+
+ case eEnumerateDirectoryResultEnter: // Recurse into the current entry if it is a directory or symlink, or next if not
+ if (FileSpec::EnumerateDirectory (child_path,
+ find_directories,
+ find_files,
+ find_other,
+ callback,
+ callback_baton) == eEnumerateDirectoryResultQuit)
+ {
+ // The subdirectory returned Quit, which means to
+ // stop all directory enumerations at all levels.
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultQuit;
+ }
+ break;
+
+ case eEnumerateDirectoryResultExit: // Exit from the current directory at the current level.
+ // Exit from this directory level and tell parent to
+ // keep enumerating.
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultNext;
+
+ case eEnumerateDirectoryResultQuit: // Stop directory enumerations at any level
+ if (buf)
+ free (buf);
+ return eEnumerateDirectoryResultQuit;
+ }
+ }
+ }
+ }
+ if (buf)
+ {
+ free (buf);
+ }
+ }
+ }
+ // By default when exiting a directory, we tell the parent enumeration
+ // to continue enumerating.
+ return eEnumerateDirectoryResultNext;
+}
+
+//------------------------------------------------------------------
+/// Returns true if the filespec represents an implementation source
+/// file (files with a ".c", ".cpp", ".m", ".mm" (many more)
+/// extension).
+///
+/// @return
+/// \b true if the filespec represents an implementation source
+/// file, \b false otherwise.
+//------------------------------------------------------------------
+bool
+FileSpec::IsSourceImplementationFile () const
+{
+ ConstString extension (GetFileNameExtension());
+ if (extension)
+ {
+ static RegularExpression g_source_file_regex ("^(c|m|mm|cpp|c\\+\\+|cxx|cc|cp|s|asm|f|f77|f90|f95|f03|for|ftn|fpp|ada|adb|ads)$",
+ REG_EXTENDED | REG_ICASE);
+ return g_source_file_regex.Execute (extension.GetCString());
+ }
+ return false;
+}
+
+bool
+FileSpec::IsRelativeToCurrentWorkingDirectory () const
+{
+ const char *directory = m_directory.GetCString();
+ if (directory && directory[0])
+ {
+ // If the path doesn't start with '/' or '~', return true
+ switch (directory[0])
+ {
+ case '/':
+ case '~':
+ return false;
+ default:
+ return true;
+ }
+ }
+ else if (m_filename)
+ {
+ // No directory, just a basename, return true
+ return true;
+ }
+ return false;
+}
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
new file mode 100644
index 000000000000..a7bad0063efd
--- /dev/null
+++ b/source/Host/common/Host.cpp
@@ -0,0 +1,1568 @@
+//===-- Host.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"
+
+// C includes
+#include <dlfcn.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#if defined (__APPLE__)
+
+#include <dispatch/dispatch.h>
+#include <libproc.h>
+#include <mach-o/dyld.h>
+#include <mach/mach_port.h>
+
+#endif
+
+#if defined (__linux__) || defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+#include <sys/wait.h>
+#include <sys/syscall.h>
+#endif
+
+#if defined (__FreeBSD__)
+#include <pthread_np.h>
+#endif
+
+#include "lldb/Host/Host.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/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/Mutex.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MachO.h"
+#include "llvm/Support/raw_ostream.h"
+
+
+
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+#if !defined (__APPLE__)
+struct MonitorInfo
+{
+ lldb::pid_t pid; // The process ID to monitor
+ Host::MonitorChildProcessCallback callback; // The callback function to call when "pid" exits or signals
+ void *callback_baton; // The callback baton for the callback function
+ bool monitor_signals; // If true, call the callback when "pid" gets signaled.
+};
+
+static void *
+MonitorChildProcessThreadFunction (void *arg);
+
+lldb::thread_t
+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;
+ info_ptr->callback = callback;
+ info_ptr->callback_baton = callback_baton;
+ info_ptr->monitor_signals = monitor_signals;
+
+ char thread_name[256];
+ ::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%" PRIu64 ")>", pid);
+ thread = ThreadCreate (thread_name,
+ MonitorChildProcessThreadFunction,
+ info_ptr,
+ NULL);
+
+ return thread;
+}
+
+//------------------------------------------------------------------
+// Scoped class that will disable thread canceling when it is
+// constructed, and exception safely restore the previous value it
+// when it goes out of scope.
+//------------------------------------------------------------------
+class ScopedPThreadCancelDisabler
+{
+public:
+ ScopedPThreadCancelDisabler()
+ {
+ // Disable the ability for this thread to be cancelled
+ int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state);
+ if (err != 0)
+ m_old_state = -1;
+
+ }
+
+ ~ScopedPThreadCancelDisabler()
+ {
+ // Restore the ability for this thread to be cancelled to what it
+ // previously was.
+ if (m_old_state != -1)
+ ::pthread_setcancelstate (m_old_state, 0);
+ }
+private:
+ int m_old_state; // Save the old cancelability state.
+};
+
+static void *
+MonitorChildProcessThreadFunction (void *arg)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ const char *function = __FUNCTION__;
+ if (log)
+ log->Printf ("%s (arg = %p) thread starting...", function, arg);
+
+ MonitorInfo *info = (MonitorInfo *)arg;
+
+ const Host::MonitorChildProcessCallback callback = info->callback;
+ void * const callback_baton = info->callback_baton;
+ const lldb::pid_t pid = info->pid;
+ const bool monitor_signals = info->monitor_signals;
+
+ delete info;
+
+ int status = -1;
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+ #define __WALL 0
+#endif
+ const int options = __WALL;
+
+ while (1)
+ {
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf("%s ::wait_pid (pid = %" PRIu64 ", &status, options = %i)...", function, pid, options);
+
+ // Wait for all child processes
+ ::pthread_testcancel ();
+ // Get signals from all children with same process group of pid
+ const lldb::pid_t wait_pid = ::waitpid (-1*pid, &status, options);
+ ::pthread_testcancel ();
+
+ if (wait_pid == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because waitpid failed (%s)...", __FUNCTION__, arg, strerror(errno));
+ break;
+ }
+ }
+ else if (wait_pid > 0)
+ {
+ bool exited = false;
+ int signal = 0;
+ int exit_status = 0;
+ const char *status_cstr = NULL;
+ if (WIFSTOPPED(status))
+ {
+ signal = WSTOPSIG(status);
+ status_cstr = "STOPPED";
+ }
+ else if (WIFEXITED(status))
+ {
+ exit_status = WEXITSTATUS(status);
+ status_cstr = "EXITED";
+ exited = true;
+ }
+ else if (WIFSIGNALED(status))
+ {
+ signal = WTERMSIG(status);
+ status_cstr = "SIGNALED";
+ if (wait_pid == pid) {
+ exited = true;
+ exit_status = -1;
+ }
+ }
+ else
+ {
+ status_cstr = "(\?\?\?)";
+ }
+
+ // Scope for pthread_cancel_disabler
+ {
+ ScopedPThreadCancelDisabler pthread_cancel_disabler;
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s ::waitpid (pid = %" PRIu64 ", &status, options = %i) => pid = %" PRIu64 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i",
+ function,
+ wait_pid,
+ options,
+ pid,
+ status,
+ status_cstr,
+ signal,
+ exit_status);
+
+ if (exited || (signal != 0 && monitor_signals))
+ {
+ bool callback_return = false;
+ if (callback)
+ callback_return = callback (callback_baton, wait_pid, exited, signal, exit_status);
+
+ // If our process exited, then this thread should exit
+ if (exited && wait_pid == pid)
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because pid received exit signal...", __FUNCTION__, arg);
+ break;
+ }
+ // If the callback returns true, it means this process should
+ // exit
+ if (callback_return)
+ {
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting because callback returned true...", __FUNCTION__, arg);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
+ if (log)
+ log->Printf ("%s (arg = %p) thread exiting...", __FUNCTION__, arg);
+
+ return NULL;
+}
+
+
+void
+Host::SystemLog (SystemLogType type, const char *format, va_list args)
+{
+ vfprintf (stderr, format, args);
+}
+
+#endif // #if !defined (__APPLE__)
+
+void
+Host::SystemLog (SystemLogType type, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ SystemLog (type, format, args);
+ va_end (args);
+}
+
+size_t
+Host::GetPageSize()
+{
+ return ::getpagesize();
+}
+
+const ArchSpec &
+Host::GetArchitecture (SystemDefaultArchitecture arch_kind)
+{
+ static bool g_supports_32 = false;
+ static bool g_supports_64 = false;
+ static ArchSpec g_host_arch_32;
+ static ArchSpec g_host_arch_64;
+
+#if defined (__APPLE__)
+
+ // Apple is different in that it can support both 32 and 64 bit executables
+ // in the same operating system running concurrently. Here we detect the
+ // correct host architectures for both 32 and 64 bit including if 64 bit
+ // executables are supported on the system.
+
+ if (g_supports_32 == false && g_supports_64 == false)
+ {
+ // All apple systems support 32 bit execution.
+ g_supports_32 = true;
+ uint32_t cputype, cpusubtype;
+ uint32_t is_64_bit_capable = false;
+ size_t len = sizeof(cputype);
+ ArchSpec host_arch;
+ // These will tell us about the kernel architecture, which even on a 64
+ // bit machine can be 32 bit...
+ if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
+ {
+ len = sizeof (cpusubtype);
+ if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) != 0)
+ cpusubtype = CPU_TYPE_ANY;
+
+ len = sizeof (is_64_bit_capable);
+ if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
+ {
+ if (is_64_bit_capable)
+ g_supports_64 = true;
+ }
+
+ if (is_64_bit_capable)
+ {
+#if defined (__i386__) || defined (__x86_64__)
+ if (cpusubtype == CPU_SUBTYPE_486)
+ cpusubtype = CPU_SUBTYPE_I386_ALL;
+#endif
+ if (cputype & CPU_ARCH_ABI64)
+ {
+ // We have a 64 bit kernel on a 64 bit system
+ g_host_arch_32.SetArchitecture (eArchTypeMachO, ~(CPU_ARCH_MASK) & cputype, cpusubtype);
+ g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
+ }
+ else
+ {
+ // We have a 32 bit kernel on a 64 bit system
+ g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
+ cputype |= CPU_ARCH_ABI64;
+ g_host_arch_64.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
+ }
+ }
+ else
+ {
+ g_host_arch_32.SetArchitecture (eArchTypeMachO, cputype, cpusubtype);
+ g_host_arch_64.Clear();
+ }
+ }
+ }
+
+#else // #if defined (__APPLE__)
+
+ if (g_supports_32 == false && g_supports_64 == false)
+ {
+ llvm::Triple triple(llvm::sys::getDefaultTargetTriple());
+
+ g_host_arch_32.Clear();
+ g_host_arch_64.Clear();
+
+ // If the OS is Linux, "unknown" in the vendor slot isn't what we want
+ // for the default triple. It's probably an artifact of config.guess.
+ if (triple.getOS() == llvm::Triple::Linux && triple.getVendor() == llvm::Triple::UnknownVendor)
+ triple.setVendorName("");
+
+ switch (triple.getArch())
+ {
+ default:
+ g_host_arch_32.SetTriple(triple);
+ g_supports_32 = true;
+ break;
+
+ case llvm::Triple::x86_64:
+ g_host_arch_64.SetTriple(triple);
+ g_supports_64 = true;
+ g_host_arch_32.SetTriple(triple.get32BitArchVariant());
+ g_supports_32 = true;
+ break;
+
+ case llvm::Triple::sparcv9:
+ case llvm::Triple::ppc64:
+ g_host_arch_64.SetTriple(triple);
+ g_supports_64 = true;
+ break;
+ }
+
+ g_supports_32 = g_host_arch_32.IsValid();
+ g_supports_64 = g_host_arch_64.IsValid();
+ }
+
+#endif // #else for #if defined (__APPLE__)
+
+ if (arch_kind == eSystemDefaultArchitecture32)
+ return g_host_arch_32;
+ else if (arch_kind == eSystemDefaultArchitecture64)
+ return g_host_arch_64;
+
+ if (g_supports_64)
+ return g_host_arch_64;
+
+ return g_host_arch_32;
+}
+
+const ConstString &
+Host::GetVendorString()
+{
+ static ConstString g_vendor;
+ if (!g_vendor)
+ {
+ const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getVendorName();
+ g_vendor.SetCStringWithLength(str_ref.data(), str_ref.size());
+ }
+ return g_vendor;
+}
+
+const ConstString &
+Host::GetOSString()
+{
+ static ConstString g_os_string;
+ if (!g_os_string)
+ {
+ const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
+ const llvm::StringRef &str_ref = host_arch.GetTriple().getOSName();
+ g_os_string.SetCStringWithLength(str_ref.data(), str_ref.size());
+ }
+ return g_os_string;
+}
+
+const ConstString &
+Host::GetTargetTriple()
+{
+ static ConstString g_host_triple;
+ if (!(g_host_triple))
+ {
+ const ArchSpec &host_arch = GetArchitecture (eSystemDefaultArchitecture);
+ g_host_triple.SetCString(host_arch.GetTriple().getTriple().c_str());
+ }
+ return g_host_triple;
+}
+
+lldb::pid_t
+Host::GetCurrentProcessID()
+{
+ return ::getpid();
+}
+
+lldb::tid_t
+Host::GetCurrentThreadID()
+{
+#if defined (__APPLE__)
+ // Calling "mach_port_deallocate()" bumps the reference count on the thread
+ // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
+ // count.
+ thread_port_t thread_self = mach_thread_self();
+ mach_port_deallocate(mach_task_self(), thread_self);
+ return thread_self;
+#elif defined(__FreeBSD__)
+ return lldb::tid_t(pthread_getthreadid_np());
+#elif defined(__linux__)
+ return lldb::tid_t(syscall(SYS_gettid));
+#else
+ return lldb::tid_t(pthread_self());
+#endif
+}
+
+lldb::thread_t
+Host::GetCurrentThread ()
+{
+ return lldb::thread_t(pthread_self());
+}
+
+const char *
+Host::GetSignalAsCString (int signo)
+{
+ switch (signo)
+ {
+ case SIGHUP: return "SIGHUP"; // 1 hangup
+ case SIGINT: return "SIGINT"; // 2 interrupt
+ case SIGQUIT: return "SIGQUIT"; // 3 quit
+ case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught)
+ case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught)
+ case SIGABRT: return "SIGABRT"; // 6 abort()
+#if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
+ case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
+#endif
+#if !defined(_POSIX_C_SOURCE)
+ case SIGEMT: return "SIGEMT"; // 7 EMT instruction
+#endif
+ case SIGFPE: return "SIGFPE"; // 8 floating point exception
+ case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored)
+ case SIGBUS: return "SIGBUS"; // 10 bus error
+ case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation
+ case SIGSYS: return "SIGSYS"; // 12 bad argument to system call
+ case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it
+ case SIGALRM: return "SIGALRM"; // 14 alarm clock
+ case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill
+ case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel
+ case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty
+ case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty
+ case SIGCONT: return "SIGCONT"; // 19 continue a stopped process
+ case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit
+ case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read
+ case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local&LTOSTOP)
+#if !defined(_POSIX_C_SOURCE)
+ case SIGIO: return "SIGIO"; // 23 input/output possible signal
+#endif
+ case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit
+ case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit
+ case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm
+ case SIGPROF: return "SIGPROF"; // 27 profiling time alarm
+#if !defined(_POSIX_C_SOURCE)
+ case SIGWINCH: return "SIGWINCH"; // 28 window size changes
+ case SIGINFO: return "SIGINFO"; // 29 information request
+#endif
+ case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1
+ case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2
+ default:
+ break;
+ }
+ return NULL;
+}
+
+void
+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?
+}
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ // TODO: Is there a way to the host environment for this process on other systems?
+ return 0;
+}
+
+#endif // #if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined (__linux__)
+
+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
+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);
+
+ int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr);
+ if (err == 0)
+ {
+ if (error)
+ error->Clear();
+ return thread;
+ }
+
+ if (error)
+ error->SetError (err, eErrorTypePOSIX);
+
+ return LLDB_INVALID_HOST_THREAD;
+}
+
+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;
+}
+
+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)
+{
+ char *namebuf = (char *)::malloc (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, thread_name, len);
+ namebuf[len] = 0;
+
+ int namebuflen = strlen(namebuf);
+ 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);
+ }
+ return false;
+}
+
+FileSpec
+Host::GetProgramFileSpec ()
+{
+ static FileSpec g_program_filespec;
+ if (!g_program_filespec)
+ {
+#if defined (__APPLE__)
+ char program_fullpath[PATH_MAX];
+ // If DST is NULL, then return the number of bytes needed.
+ uint32_t len = sizeof(program_fullpath);
+ int err = _NSGetExecutablePath (program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile (program_fullpath, false);
+ else if (err == -1)
+ {
+ char *large_program_fullpath = (char *)::malloc (len + 1);
+
+ err = _NSGetExecutablePath (large_program_fullpath, &len);
+ if (err == 0)
+ g_program_filespec.SetFile (large_program_fullpath, false);
+
+ ::free (large_program_fullpath);
+ }
+#elif defined (__linux__)
+ char exe_path[PATH_MAX];
+ ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
+ if (len > 0) {
+ exe_path[len] = 0;
+ g_program_filespec.SetFile(exe_path, false);
+ }
+#elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+ int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() };
+ size_t exe_path_size;
+ if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0)
+ {
+ char *exe_path = new char[exe_path_size];
+ if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0)
+ g_program_filespec.SetFile(exe_path, false);
+ delete[] exe_path;
+ }
+#endif
+ }
+ return g_program_filespec;
+}
+
+FileSpec
+Host::GetModuleFileSpecForHostAddress (const void *host_addr)
+{
+ FileSpec module_filespec;
+ Dl_info info;
+ if (::dladdr (host_addr, &info))
+ {
+ if (info.dli_fname)
+ module_filespec.SetFile(info.dli_fname, true);
+ }
+ return module_filespec;
+}
+
+#if !defined (__APPLE__) // see Host.mm
+
+bool
+Host::GetBundleDirectory (const FileSpec &file, FileSpec &bundle)
+{
+ bundle.Clear();
+ return false;
+}
+
+bool
+Host::ResolveExecutableInBundle (FileSpec &file)
+{
+ return false;
+}
+#endif
+
+// Opaque info that tracks a dynamic library that was loaded
+struct DynamicLibraryInfo
+{
+ DynamicLibraryInfo (const FileSpec &fs, int o, void *h) :
+ file_spec (fs),
+ open_options (o),
+ handle (h)
+ {
+ }
+
+ const FileSpec file_spec;
+ uint32_t open_options;
+ void * handle;
+};
+
+void *
+Host::DynamicLibraryOpen (const FileSpec &file_spec, uint32_t options, Error &error)
+{
+ char path[PATH_MAX];
+ if (file_spec.GetPath(path, sizeof(path)))
+ {
+ int mode = 0;
+
+ if (options & eDynamicLibraryOpenOptionLazy)
+ mode |= RTLD_LAZY;
+ else
+ mode |= RTLD_NOW;
+
+
+ if (options & eDynamicLibraryOpenOptionLocal)
+ mode |= RTLD_LOCAL;
+ else
+ mode |= RTLD_GLOBAL;
+
+#ifdef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
+ if (options & eDynamicLibraryOpenOptionLimitGetSymbol)
+ mode |= RTLD_FIRST;
+#endif
+
+ void * opaque = ::dlopen (path, mode);
+
+ if (opaque)
+ {
+ error.Clear();
+ return new DynamicLibraryInfo (file_spec, options, opaque);
+ }
+ else
+ {
+ error.SetErrorString(::dlerror());
+ }
+ }
+ else
+ {
+ error.SetErrorString("failed to extract path");
+ }
+ return NULL;
+}
+
+Error
+Host::DynamicLibraryClose (void *opaque)
+{
+ Error error;
+ if (opaque == NULL)
+ {
+ error.SetErrorString ("invalid dynamic library handle");
+ }
+ else
+ {
+ DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
+ if (::dlclose (dylib_info->handle) != 0)
+ {
+ error.SetErrorString(::dlerror());
+ }
+
+ dylib_info->open_options = 0;
+ dylib_info->handle = 0;
+ delete dylib_info;
+ }
+ return error;
+}
+
+void *
+Host::DynamicLibraryGetSymbol (void *opaque, const char *symbol_name, Error &error)
+{
+ if (opaque == NULL)
+ {
+ error.SetErrorString ("invalid dynamic library handle");
+ }
+ else
+ {
+ DynamicLibraryInfo *dylib_info = (DynamicLibraryInfo *) opaque;
+
+ void *symbol_addr = ::dlsym (dylib_info->handle, symbol_name);
+ if (symbol_addr)
+ {
+#ifndef LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED
+ // This host doesn't support limiting searches to this shared library
+ // so we need to verify that the match came from this shared library
+ // if it was requested in the Host::DynamicLibraryOpen() function.
+ if (dylib_info->open_options & eDynamicLibraryOpenOptionLimitGetSymbol)
+ {
+ FileSpec match_dylib_spec (Host::GetModuleFileSpecForHostAddress (symbol_addr));
+ if (match_dylib_spec != dylib_info->file_spec)
+ {
+ char dylib_path[PATH_MAX];
+ if (dylib_info->file_spec.GetPath (dylib_path, sizeof(dylib_path)))
+ error.SetErrorStringWithFormat ("symbol not found in \"%s\"", dylib_path);
+ else
+ error.SetErrorString ("symbol not found");
+ return NULL;
+ }
+ }
+#endif
+ error.Clear();
+ return symbol_addr;
+ }
+ else
+ {
+ error.SetErrorString(::dlerror());
+ }
+ }
+ return NULL;
+}
+
+bool
+Host::GetLLDBPath (PathType path_type, FileSpec &file_spec)
+{
+ // To get paths related to LLDB we get the path to the executable that
+ // contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
+ // on linux this is assumed to be the "lldb" main executable. If LLDB on
+ // linux is actually in a shared library (liblldb.so) then this function will
+ // need to be modified to "do the right thing".
+
+ switch (path_type)
+ {
+ case ePathTypeLLDBShlibDir:
+ {
+ static ConstString g_lldb_so_dir;
+ if (!g_lldb_so_dir)
+ {
+ FileSpec lldb_file_spec (Host::GetModuleFileSpecForHostAddress ((void *)Host::GetLLDBPath));
+ g_lldb_so_dir = lldb_file_spec.GetDirectory();
+ }
+ file_spec.GetDirectory() = g_lldb_so_dir;
+ return file_spec.GetDirectory();
+ }
+ break;
+
+ case ePathTypeSupportExecutableDir:
+ {
+ static ConstString g_lldb_support_exe_dir;
+ if (!g_lldb_support_exe_dir)
+ {
+ FileSpec lldb_file_spec;
+ if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
+ {
+ char raw_path[PATH_MAX];
+ char resolved_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+#if defined (__APPLE__)
+ char *framework_pos = ::strstr (raw_path, "LLDB.framework");
+ if (framework_pos)
+ {
+ framework_pos += strlen("LLDB.framework");
+#if !defined (__arm__)
+ ::strncpy (framework_pos, "/Resources", PATH_MAX - (framework_pos - raw_path));
+#endif
+ }
+#endif
+ FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
+ g_lldb_support_exe_dir.SetCString(resolved_path);
+ }
+ }
+ file_spec.GetDirectory() = g_lldb_support_exe_dir;
+ return file_spec.GetDirectory();
+ }
+ break;
+
+ case ePathTypeHeaderDir:
+ {
+ static ConstString g_lldb_headers_dir;
+ if (!g_lldb_headers_dir)
+ {
+#if defined (__APPLE__)
+ FileSpec lldb_file_spec;
+ if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
+ {
+ char raw_path[PATH_MAX];
+ char resolved_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+ char *framework_pos = ::strstr (raw_path, "LLDB.framework");
+ if (framework_pos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ ::strncpy (framework_pos, "/Headers", PATH_MAX - (framework_pos - raw_path));
+ }
+ FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
+ g_lldb_headers_dir.SetCString(resolved_path);
+ }
+#else
+ // TODO: Anyone know how we can determine this for linux? Other systems??
+ g_lldb_headers_dir.SetCString ("/opt/local/include/lldb");
+#endif
+ }
+ file_spec.GetDirectory() = g_lldb_headers_dir;
+ return file_spec.GetDirectory();
+ }
+ break;
+
+#ifndef LLDB_DISABLE_PYTHON
+ case ePathTypePythonDir:
+ {
+ static ConstString g_lldb_python_dir;
+ if (!g_lldb_python_dir)
+ {
+ FileSpec lldb_file_spec;
+ if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
+ {
+ char raw_path[PATH_MAX];
+ char resolved_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+#if defined (__APPLE__)
+ char *framework_pos = ::strstr (raw_path, "LLDB.framework");
+ if (framework_pos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ ::strncpy (framework_pos, "/Resources/Python", PATH_MAX - (framework_pos - raw_path));
+ }
+#else
+ llvm::SmallString<256> python_version_dir;
+ llvm::raw_svector_ostream os(python_version_dir);
+ os << "/python" << PY_MAJOR_VERSION << '.' << PY_MINOR_VERSION << "/site-packages";
+ os.flush();
+
+ // We may get our string truncated. Should we protect
+ // this with an assert?
+
+ ::strncat(raw_path, python_version_dir.c_str(),
+ sizeof(raw_path) - strlen(raw_path) - 1);
+
+#endif
+ FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
+ g_lldb_python_dir.SetCString(resolved_path);
+ }
+ }
+ file_spec.GetDirectory() = g_lldb_python_dir;
+ return file_spec.GetDirectory();
+ }
+ break;
+#endif
+
+ case ePathTypeLLDBSystemPlugins: // System plug-ins directory
+ {
+#if defined (__APPLE__) || defined(__linux__)
+ static ConstString g_lldb_system_plugin_dir;
+ static bool g_lldb_system_plugin_dir_located = false;
+ if (!g_lldb_system_plugin_dir_located)
+ {
+ g_lldb_system_plugin_dir_located = true;
+#if defined (__APPLE__)
+ FileSpec lldb_file_spec;
+ if (GetLLDBPath (ePathTypeLLDBShlibDir, lldb_file_spec))
+ {
+ char raw_path[PATH_MAX];
+ char resolved_path[PATH_MAX];
+ lldb_file_spec.GetPath(raw_path, sizeof(raw_path));
+
+ char *framework_pos = ::strstr (raw_path, "LLDB.framework");
+ if (framework_pos)
+ {
+ framework_pos += strlen("LLDB.framework");
+ ::strncpy (framework_pos, "/Resources/PlugIns", PATH_MAX - (framework_pos - raw_path));
+ FileSpec::Resolve (raw_path, resolved_path, sizeof(resolved_path));
+ g_lldb_system_plugin_dir.SetCString(resolved_path);
+ }
+ return false;
+ }
+#elif defined (__linux__)
+ FileSpec lldb_file_spec("/usr/lib/lldb", true);
+ if (lldb_file_spec.Exists())
+ {
+ g_lldb_system_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
+ }
+#endif // __APPLE__ || __linux__
+ }
+
+ if (g_lldb_system_plugin_dir)
+ {
+ file_spec.GetDirectory() = g_lldb_system_plugin_dir;
+ return true;
+ }
+#else
+ // TODO: where would system LLDB plug-ins be located on other systems?
+ return false;
+#endif
+ }
+ break;
+
+ case ePathTypeLLDBUserPlugins: // User plug-ins directory
+ {
+#if defined (__APPLE__)
+ static ConstString g_lldb_user_plugin_dir;
+ if (!g_lldb_user_plugin_dir)
+ {
+ char user_plugin_path[PATH_MAX];
+ if (FileSpec::Resolve ("~/Library/Application Support/LLDB/PlugIns",
+ user_plugin_path,
+ sizeof(user_plugin_path)))
+ {
+ g_lldb_user_plugin_dir.SetCString(user_plugin_path);
+ }
+ }
+ file_spec.GetDirectory() = g_lldb_user_plugin_dir;
+ return file_spec.GetDirectory();
+#elif defined (__linux__)
+ static ConstString g_lldb_user_plugin_dir;
+ if (!g_lldb_user_plugin_dir)
+ {
+ // XDG Base Directory Specification
+ // http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
+ // If XDG_DATA_HOME exists, use that, otherwise use ~/.local/share/lldb.
+ FileSpec lldb_file_spec;
+ const char *xdg_data_home = getenv("XDG_DATA_HOME");
+ if (xdg_data_home && xdg_data_home[0])
+ {
+ std::string user_plugin_dir (xdg_data_home);
+ user_plugin_dir += "/lldb";
+ lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
+ }
+ else
+ {
+ const char *home_dir = getenv("HOME");
+ if (home_dir && home_dir[0])
+ {
+ std::string user_plugin_dir (home_dir);
+ user_plugin_dir += "/.local/share/lldb";
+ lldb_file_spec.SetFile (user_plugin_dir.c_str(), true);
+ }
+ }
+
+ if (lldb_file_spec.Exists())
+ g_lldb_user_plugin_dir.SetCString(lldb_file_spec.GetPath().c_str());
+ }
+ file_spec.GetDirectory() = g_lldb_user_plugin_dir;
+ return file_spec.GetDirectory();
+#endif
+ // TODO: where would user LLDB plug-ins be located on other systems?
+ return false;
+ }
+ }
+
+ return false;
+}
+
+
+bool
+Host::GetHostname (std::string &s)
+{
+ char hostname[PATH_MAX];
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (::gethostname (hostname, sizeof(hostname) - 1) == 0)
+ {
+ struct hostent* h = ::gethostbyname (hostname);
+ if (h)
+ s.assign (h->h_name);
+ else
+ s.assign (hostname);
+ return true;
+ }
+ return false;
+}
+
+const char *
+Host::GetUserName (uint32_t uid, std::string &user_name)
+{
+ struct passwd user_info;
+ struct passwd *user_info_ptr = &user_info;
+ char user_buffer[PATH_MAX];
+ size_t user_buffer_size = sizeof(user_buffer);
+ if (::getpwuid_r (uid,
+ &user_info,
+ user_buffer,
+ user_buffer_size,
+ &user_info_ptr) == 0)
+ {
+ if (user_info_ptr)
+ {
+ user_name.assign (user_info_ptr->pw_name);
+ return user_name.c_str();
+ }
+ }
+ user_name.clear();
+ return NULL;
+}
+
+const char *
+Host::GetGroupName (uint32_t gid, std::string &group_name)
+{
+ char group_buffer[PATH_MAX];
+ size_t group_buffer_size = sizeof(group_buffer);
+ struct group group_info;
+ struct group *group_info_ptr = &group_info;
+ // Try the threadsafe version first
+ if (::getgrgid_r (gid,
+ &group_info,
+ group_buffer,
+ group_buffer_size,
+ &group_info_ptr) == 0)
+ {
+ if (group_info_ptr)
+ {
+ group_name.assign (group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ else
+ {
+ // The threadsafe version isn't currently working
+ // for me on darwin, but the non-threadsafe version
+ // is, so I am calling it below.
+ group_info_ptr = ::getgrgid (gid);
+ if (group_info_ptr)
+ {
+ group_name.assign (group_info_ptr->gr_name);
+ return group_name.c_str();
+ }
+ }
+ group_name.clear();
+ return NULL;
+}
+
+#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) // see macosx/Host.mm
+bool
+Host::GetOSBuildString (std::string &s)
+{
+ s.clear();
+ return false;
+}
+
+bool
+Host::GetOSKernelDescription (std::string &s)
+{
+ s.clear();
+ return false;
+}
+#endif
+
+uint32_t
+Host::GetUserID ()
+{
+ return getuid();
+}
+
+uint32_t
+Host::GetGroupID ()
+{
+ return getgid();
+}
+
+uint32_t
+Host::GetEffectiveUserID ()
+{
+ return geteuid();
+}
+
+uint32_t
+Host::GetEffectiveGroupID ()
+{
+ return getegid();
+}
+
+#if !defined (__APPLE__) && !defined(__linux__)
+uint32_t
+Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+ return process_infos.GetSize();
+}
+#endif // #if !defined (__APPLE__) && !defined(__linux__)
+
+#if !defined (__APPLE__) && !defined (__FreeBSD__) && !defined (__FreeBSD_kernel__) && !defined(__linux__)
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+ return false;
+}
+#endif
+
+#if !defined(__linux__)
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+ return false;
+}
+#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 = Host::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 () :
+ process_reaped (false),
+ can_delete (false),
+ pid (LLDB_INVALID_PROCESS_ID),
+ signo(-1),
+ status(-1)
+ {
+ }
+
+ lldb_private::Predicate<bool> process_reaped;
+ lldb_private::Predicate<bool> can_delete;
+ lldb::pid_t pid;
+ int signo;
+ int status;
+};
+
+static bool
+MonitorShellCommand (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited, // True if the process did exit
+ int signo, // Zero for no signal
+ int status) // Exit value of process if signal is zero
+{
+ ShellInfo *shell_info = (ShellInfo *)callback_baton;
+ shell_info->pid = pid;
+ shell_info->signo = signo;
+ shell_info->status = status;
+ // Let the thread running Host::RunShellCommand() know that the process
+ // exited and that ShellInfo has been filled in by broadcasting to it
+ shell_info->process_reaped.SetValue(1, eBroadcastAlways);
+ // Now wait for a handshake back from that thread running Host::RunShellCommand
+ // so we know that we can delete shell_info_ptr
+ shell_info->can_delete.WaitForValueEqualTo(true);
+ // Sleep a bit to allow the shell_info->can_delete.SetValue() to complete...
+ usleep(1000);
+ // Now delete the shell info that was passed into this function
+ delete shell_info;
+ return true;
+}
+
+Error
+Host::RunShellCommand (const char *command,
+ const char *working_dir,
+ int *status_ptr,
+ int *signo_ptr,
+ std::string *command_output_ptr,
+ uint32_t timeout_sec,
+ const char *shell)
+{
+ Error error;
+ ProcessLaunchInfo launch_info;
+ if (shell && shell[0])
+ {
+ // Run the command in a shell
+ launch_info.SetShell(shell);
+ launch_info.GetArguments().AppendArgument(command);
+ const bool localhost = true;
+ const bool will_debug = false;
+ const bool first_arg_is_full_shell_command = true;
+ launch_info.ConvertArgumentsForLaunchingInShell (error,
+ localhost,
+ will_debug,
+ first_arg_is_full_shell_command);
+ }
+ else
+ {
+ // No shell, just run it
+ Args args (command);
+ const bool first_arg_is_executable = true;
+ launch_info.SetArguments(args, first_arg_is_executable);
+ }
+
+ if (working_dir)
+ launch_info.SetWorkingDirectory(working_dir);
+ char output_file_path_buffer[L_tmpnam];
+ const char *output_file_path = NULL;
+ if (command_output_ptr)
+ {
+ // Create a temporary file to get the stdout/stderr and redirect the
+ // output of the command into this file. We will later read this file
+ // if all goes well and fill the data into "command_output_ptr"
+ output_file_path = ::tmpnam(output_file_path_buffer);
+ launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
+ launch_info.AppendOpenFileAction(STDOUT_FILENO, output_file_path, false, true);
+ launch_info.AppendDuplicateFileAction(STDOUT_FILENO, STDERR_FILENO);
+ }
+ else
+ {
+ launch_info.AppendSuppressFileAction (STDIN_FILENO, true, false);
+ launch_info.AppendSuppressFileAction (STDOUT_FILENO, false, true);
+ launch_info.AppendSuppressFileAction (STDERR_FILENO, false, true);
+ }
+
+ // The process monitor callback will delete the 'shell_info_ptr' below...
+ std::unique_ptr<ShellInfo> shell_info_ap (new ShellInfo());
+
+ const bool monitor_signals = false;
+ launch_info.SetMonitorProcessCallback(MonitorShellCommand, shell_info_ap.get(), monitor_signals);
+
+ error = LaunchProcess (launch_info);
+ const lldb::pid_t pid = launch_info.GetProcessID();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // The process successfully launched, so we can defer ownership of
+ // "shell_info" to the MonitorShellCommand callback function that will
+ // get called when the process dies. We release the unique pointer as it
+ // doesn't need to delete the ShellInfo anymore.
+ ShellInfo *shell_info = shell_info_ap.release();
+ TimeValue timeout_time(TimeValue::Now());
+ timeout_time.OffsetWithSeconds(timeout_sec);
+ bool timed_out = false;
+ shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out);
+ if (timed_out)
+ {
+ error.SetErrorString("timed out waiting for shell command to complete");
+
+ // Kill the process since it didn't complete withint the timeout specified
+ ::kill (pid, SIGKILL);
+ // Wait for the monitor callback to get the message
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(1);
+ timed_out = false;
+ shell_info->process_reaped.WaitForValueEqualTo(true, &timeout_time, &timed_out);
+ }
+ else
+ {
+ if (status_ptr)
+ *status_ptr = shell_info->status;
+
+ if (signo_ptr)
+ *signo_ptr = shell_info->signo;
+
+ if (command_output_ptr)
+ {
+ command_output_ptr->clear();
+ FileSpec file_spec(output_file_path, File::eOpenOptionRead);
+ uint64_t file_size = file_spec.GetByteSize();
+ if (file_size > 0)
+ {
+ if (file_size > command_output_ptr->max_size())
+ {
+ error.SetErrorStringWithFormat("shell command output is too large to fit into a std::string");
+ }
+ else
+ {
+ command_output_ptr->resize(file_size);
+ file_spec.ReadFileContents(0, &((*command_output_ptr)[0]), command_output_ptr->size(), &error);
+ }
+ }
+ }
+ }
+ shell_info->can_delete.SetValue(true, eBroadcastAlways);
+ }
+ else
+ {
+ error.SetErrorString("failed to get process ID");
+ }
+
+ if (output_file_path)
+ ::unlink (output_file_path);
+ // Handshake with the monitor thread, or just let it know in advance that
+ // it can delete "shell_info" in case we timed out and were not able to kill
+ // the process...
+ return error;
+}
+
+
+uint32_t
+Host::GetNumberCPUS ()
+{
+ static uint32_t g_num_cores = UINT32_MAX;
+ if (g_num_cores == UINT32_MAX)
+ {
+#if defined(__APPLE__) or defined (__linux__) or defined (__FreeBSD__) or defined (__FreeBSD_kernel__)
+
+ g_num_cores = ::sysconf(_SC_NPROCESSORS_ONLN);
+
+#elif defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+
+ // Header file for this might need to be included at the top of this file
+ SYSTEM_INFO system_info;
+ ::GetSystemInfo (&system_info);
+ g_num_cores = system_info.dwNumberOfProcessors;
+
+#else
+
+ // Assume POSIX support if a host specific case has not been supplied above
+ g_num_cores = 0;
+ int num_cores = 0;
+ size_t num_cores_len = sizeof(num_cores);
+#ifdef HW_AVAILCPU
+ int mib[] = { CTL_HW, HW_AVAILCPU };
+#else
+ int mib[] = { CTL_HW, HW_NCPU };
+#endif
+
+ /* get the number of CPUs from the system */
+ if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
+ {
+ g_num_cores = num_cores;
+ }
+ else
+ {
+ mib[1] = HW_NCPU;
+ num_cores_len = sizeof(num_cores);
+ if (sysctl(mib, sizeof(mib)/sizeof(int), &num_cores, &num_cores_len, NULL, 0) == 0 && (num_cores > 0))
+ {
+ if (num_cores > 0)
+ g_num_cores = num_cores;
+ }
+ }
+#endif
+ }
+ return g_num_cores;
+}
+
+
+
+#if !defined (__APPLE__)
+bool
+Host::OpenFileInExternalEditor (const FileSpec &file_spec, uint32_t line_no)
+{
+ return false;
+}
+
+void
+Host::SetCrashDescriptionWithFormat (const char *format, ...)
+{
+}
+
+void
+Host::SetCrashDescription (const char *description)
+{
+}
+
+lldb::pid_t
+LaunchApplication (const FileSpec &app_file_spec)
+{
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+#endif
diff --git a/source/Host/common/Mutex.cpp b/source/Host/common/Mutex.cpp
new file mode 100644
index 000000000000..39cd8c6adb4e
--- /dev/null
+++ b/source/Host/common/Mutex.cpp
@@ -0,0 +1,390 @@
+//===-- Mutex.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/Mutex.h"
+#include "lldb/Host/Host.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if 0
+// This logging is way too verbose to enable even for a log channel.
+// This logging can be enabled by changing the "#if 0", but should be
+// reverted prior to checking in.
+#include <cstdio>
+#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_LOG(fmt, ...)
+#endif
+
+// Enable extra mutex error checking
+#ifdef LLDB_CONFIGURATION_DEBUG
+#define ENABLE_MUTEX_ERROR_CHECKING 1
+#include <inttypes.h>
+#endif
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+#include <set>
+
+enum MutexAction
+{
+ eMutexActionInitialized,
+ eMutexActionDestroyed,
+ eMutexActionAssertInitialized
+};
+
+static bool
+error_check_mutex (pthread_mutex_t *m, MutexAction action)
+{
+ typedef std::set<pthread_mutex_t *> mutex_set;
+ static pthread_mutex_t g_mutex_set_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static mutex_set g_initialized_mutex_set;
+ static mutex_set g_destroyed_mutex_set;
+
+ bool success = true;
+ int err;
+ // Manually call lock so we don't to any of this error checking
+ err = ::pthread_mutex_lock (&g_mutex_set_mutex);
+ assert(err == 0);
+ switch (action)
+ {
+ case eMutexActionInitialized:
+ // Make sure this isn't already in our initialized mutex set...
+ assert (g_initialized_mutex_set.find(m) == g_initialized_mutex_set.end());
+ // Remove this from the destroyed set in case it was ever in there
+ g_destroyed_mutex_set.erase(m);
+ // Add the mutex to the initialized set
+ g_initialized_mutex_set.insert(m);
+ break;
+
+ case eMutexActionDestroyed:
+ // Make sure this isn't already in our destroyed mutex set...
+ assert (g_destroyed_mutex_set.find(m) == g_destroyed_mutex_set.end());
+ // Remove this from the initialized so we can put it into the destroyed set
+ g_initialized_mutex_set.erase(m);
+ // Add the mutex to the destroyed set
+ g_destroyed_mutex_set.insert(m);
+ break;
+ case eMutexActionAssertInitialized:
+ // This function will return true if "m" is in the initialized mutex set
+ success = g_initialized_mutex_set.find(m) != g_initialized_mutex_set.end();
+ assert (success);
+ break;
+ }
+ // Manually call unlock so we don't to any of this error checking
+ err = ::pthread_mutex_unlock (&g_mutex_set_mutex);
+ assert(err == 0);
+ return success;
+}
+
+#endif
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// This will create a scoped mutex locking object that doesn't have
+// a mutex to lock. One will need to be provided using the Reset()
+// method.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker () :
+ m_mutex_ptr(NULL)
+{
+}
+
+//----------------------------------------------------------------------
+// Constructor with a Mutex object.
+//
+// This will create a scoped mutex locking object that extracts the
+// mutex owned by "m" and locks it.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker (Mutex& m) :
+ m_mutex_ptr(NULL)
+{
+ Lock (m);
+}
+
+//----------------------------------------------------------------------
+// Constructor with a Mutex object pointer.
+//
+// This will create a scoped mutex locking object that extracts the
+// mutex owned by "m" and locks it.
+//----------------------------------------------------------------------
+Mutex::Locker::Locker (Mutex* m) :
+ m_mutex_ptr(NULL)
+{
+ if (m)
+ Lock (m);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// Unlocks any owned mutex object (if it is valid).
+//----------------------------------------------------------------------
+Mutex::Locker::~Locker ()
+{
+ Unlock();
+}
+
+//----------------------------------------------------------------------
+// Unlock the current mutex in this object (if this owns a valid
+// mutex) and lock the new "mutex" object if it is non-NULL.
+//----------------------------------------------------------------------
+void
+Mutex::Locker::Lock (Mutex &mutex)
+{
+ // We already have this mutex locked or both are NULL...
+ if (m_mutex_ptr == &mutex)
+ return;
+
+ Unlock ();
+
+ m_mutex_ptr = &mutex;
+ m_mutex_ptr->Lock();
+}
+
+void
+Mutex::Locker::Unlock ()
+{
+ if (m_mutex_ptr)
+ {
+ m_mutex_ptr->Unlock ();
+ m_mutex_ptr = NULL;
+ }
+}
+
+bool
+Mutex::Locker::TryLock (Mutex &mutex, const char *failure_message)
+{
+ // We already have this mutex locked!
+ if (m_mutex_ptr == &mutex)
+ return true;
+
+ Unlock ();
+
+ if (mutex.TryLock(failure_message) == 0)
+ m_mutex_ptr = &mutex;
+
+ return m_mutex_ptr != NULL;
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with no attributes.
+//----------------------------------------------------------------------
+Mutex::Mutex () :
+ m_mutex()
+{
+ int err;
+ err = ::pthread_mutex_init (&m_mutex, NULL);
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionInitialized);
+#endif
+ assert(err == 0);
+}
+
+//----------------------------------------------------------------------
+// Default constructor.
+//
+// Creates a pthread mutex with "type" as the mutex type.
+//----------------------------------------------------------------------
+Mutex::Mutex (Mutex::Type type) :
+ m_mutex()
+{
+ int err;
+ ::pthread_mutexattr_t attr;
+ err = ::pthread_mutexattr_init (&attr);
+ assert(err == 0);
+ switch (type)
+ {
+ case eMutexTypeNormal:
+#if ENABLE_MUTEX_ERROR_CHECKING
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK);
+#else
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_NORMAL);
+#endif
+ break;
+
+ case eMutexTypeRecursive:
+ err = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ break;
+ }
+ assert(err == 0);
+ err = ::pthread_mutex_init (&m_mutex, &attr);
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionInitialized);
+#endif
+ assert(err == 0);
+ err = ::pthread_mutexattr_destroy (&attr);
+ assert(err == 0);
+}
+
+//----------------------------------------------------------------------
+// Destructor.
+//
+// Destroys the mutex owned by this object.
+//----------------------------------------------------------------------
+Mutex::~Mutex()
+{
+ int err = ::pthread_mutex_destroy (&m_mutex);
+ assert(err == 0);
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err == 0)
+ error_check_mutex (&m_mutex, eMutexActionDestroyed);
+ else
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_destroy() => err = %i (%s)", __PRETTY_FUNCTION__, err, strerror(err));
+ assert(err == 0);
+ }
+ memset (&m_mutex, '\xba', sizeof(m_mutex));
+#endif
+}
+
+//----------------------------------------------------------------------
+// Mutex get accessor.
+//----------------------------------------------------------------------
+pthread_mutex_t *
+Mutex::GetMutex()
+{
+ return &m_mutex;
+}
+
+//----------------------------------------------------------------------
+// Locks the mutex owned by this object, if the mutex is already
+// locked, the calling thread will block until the mutex becomes
+// available.
+//
+// RETURNS
+// The error code from the pthread_mutex_lock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Lock()
+{
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p)...\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex);
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_lock (&m_mutex);
+
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err)
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_lock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
+ assert(err == 0);
+ }
+#endif
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_lock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+//----------------------------------------------------------------------
+// Attempts to lock the mutex owned by this object without blocking.
+// If the mutex is already locked, TryLock() will not block waiting
+// for the mutex, but will return an error condition.
+//
+// RETURNS
+// The error code from the pthread_mutex_trylock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::TryLock(const char *failure_message)
+{
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_trylock (&m_mutex);
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_trylock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+//----------------------------------------------------------------------
+// If the current thread holds the lock on the owned mutex, then
+// Unlock() will unlock the mutex. Calling Unlock() on this object
+// that the calling thread does not hold will result in undefined
+// behavior.
+//
+// RETURNS
+// The error code from the pthread_mutex_unlock() function call.
+//----------------------------------------------------------------------
+int
+Mutex::Unlock()
+{
+#if ENABLE_MUTEX_ERROR_CHECKING
+ error_check_mutex (&m_mutex, eMutexActionAssertInitialized);
+#endif
+
+ int err = ::pthread_mutex_unlock (&m_mutex);
+
+#if ENABLE_MUTEX_ERROR_CHECKING
+ if (err)
+ {
+ Host::SetCrashDescriptionWithFormat ("%s error: pthread_mutex_unlock(%p) => err = %i (%s)", __PRETTY_FUNCTION__, &m_mutex, err, strerror(err));
+ assert(err == 0);
+ }
+#endif
+ DEBUG_LOG ("[%4.4" PRIx64 "/%4.4" PRIx64 "] pthread_mutex_unlock (%p) => %i\n", Host::GetCurrentProcessID(), Host::GetCurrentThreadID(), &m_mutex, err);
+ return err;
+}
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+int
+TrackingMutex::Unlock ()
+{
+ if (!m_failure_message.empty())
+ Host::SetCrashDescriptionWithFormat ("Unlocking lock (on thread %p) that thread: %p failed to get: %s",
+ pthread_self(),
+ m_thread_that_tried,
+ m_failure_message.c_str());
+ assert (m_failure_message.empty());
+ return Mutex::Unlock();
+}
+
+int
+LoggingMutex::Lock ()
+{
+ printf("locking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::Lock();
+ m_locked = true;
+ printf("%d\n",x);
+ return x;
+}
+
+int
+LoggingMutex::Unlock ()
+{
+ printf("unlocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::Unlock();
+ m_locked = false;
+ printf("%d\n",x);
+ return x;
+}
+
+int
+LoggingMutex::TryLock (const char *failure_message)
+{
+ printf("trylocking mutex %p by [%4.4" PRIx64 "/%4.4" PRIx64 "]...", this, Host::GetCurrentProcessID(), Host::GetCurrentThreadID());
+ int x = Mutex::TryLock(failure_message);
+ if (x == 0)
+ m_locked = true;
+ printf("%d\n",x);
+ return x;
+}
+
+#endif
+
+
diff --git a/source/Host/common/SocketAddress.cpp b/source/Host/common/SocketAddress.cpp
new file mode 100644
index 000000000000..a22dc7a01c15
--- /dev/null
+++ b/source/Host/common/SocketAddress.cpp
@@ -0,0 +1,260 @@
+//===-- SocketAddress.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/SocketAddress.h"
+#include <stddef.h>
+
+// C Includes
+#include <assert.h>
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SocketAddress constructor
+//----------------------------------------------------------------------
+SocketAddress::SocketAddress ()
+{
+ Clear ();
+}
+
+SocketAddress::SocketAddress (const struct sockaddr &s)
+{
+ m_socket_addr.sa = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_in &s)
+{
+ m_socket_addr.sa_ipv4 = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_in6 &s)
+{
+ m_socket_addr.sa_ipv6 = s;
+}
+
+
+SocketAddress::SocketAddress (const struct sockaddr_storage &s)
+{
+ m_socket_addr.sa_storage = s;
+}
+
+//----------------------------------------------------------------------
+// SocketAddress copy constructor
+//----------------------------------------------------------------------
+SocketAddress::SocketAddress (const SocketAddress& rhs) :
+ m_socket_addr (rhs.m_socket_addr)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SocketAddress::~SocketAddress()
+{
+}
+
+void
+SocketAddress::Clear ()
+{
+ memset (&m_socket_addr, 0, sizeof(m_socket_addr));
+}
+
+bool
+SocketAddress::IsValid () const
+{
+ return GetLength () != 0;
+}
+
+static socklen_t
+GetFamilyLength (sa_family_t family)
+{
+ switch (family)
+ {
+ case AF_INET: return sizeof(struct sockaddr_in);
+ case AF_INET6: return sizeof(struct sockaddr_in6);
+ }
+ assert(0 && "Unsupported address family");
+}
+
+socklen_t
+SocketAddress::GetLength () const
+{
+#if defined(__APPLE__)
+ return m_socket_addr.sa.sa_len;
+#else
+ return GetFamilyLength (GetFamily());
+#endif
+}
+
+socklen_t
+SocketAddress::GetMaxLength ()
+{
+ return sizeof (sockaddr_t);
+}
+
+sa_family_t
+SocketAddress::GetFamily () const
+{
+ return m_socket_addr.sa.sa_family;
+}
+
+void
+SocketAddress::SetFamily (sa_family_t family)
+{
+ m_socket_addr.sa.sa_family = family;
+#if defined(__APPLE__)
+ m_socket_addr.sa.sa_len = GetFamilyLength (family);
+#endif
+}
+
+in_port_t
+SocketAddress::GetPort () const
+{
+ switch (GetFamily())
+ {
+ case AF_INET: return m_socket_addr.sa_ipv4.sin_port;
+ case AF_INET6: return m_socket_addr.sa_ipv6.sin6_port;
+ }
+ return 0;
+}
+
+bool
+SocketAddress::SetPort (in_port_t port)
+{
+ switch (GetFamily())
+ {
+ case AF_INET:
+ m_socket_addr.sa_ipv4.sin_port = htons(port);
+ return true;
+
+ case AF_INET6:
+ m_socket_addr.sa_ipv6.sin6_port = htons(port);
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// SocketAddress assignment operator
+//----------------------------------------------------------------------
+const SocketAddress&
+SocketAddress::operator=(const SocketAddress& rhs)
+{
+ if (this != &rhs)
+ m_socket_addr = rhs.m_socket_addr;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct addrinfo *addr_info)
+{
+ Clear();
+ if (addr_info &&
+ addr_info->ai_addr &&
+ addr_info->ai_addrlen > 0&&
+ addr_info->ai_addrlen <= sizeof m_socket_addr)
+ {
+ ::memcpy (&m_socket_addr,
+ addr_info->ai_addr,
+ addr_info->ai_addrlen);
+ }
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr &s)
+{
+ m_socket_addr.sa = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_in &s)
+{
+ m_socket_addr.sa_ipv4 = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_in6 &s)
+{
+ m_socket_addr.sa_ipv6 = s;
+ return *this;
+}
+
+const SocketAddress&
+SocketAddress::operator=(const struct sockaddr_storage &s)
+{
+ m_socket_addr.sa_storage = s;
+ return *this;
+}
+
+bool
+SocketAddress::SetAddress (const struct addrinfo *hints_ptr,
+ const char *host,
+ const char *service,
+ struct addrinfo *addr_info_ptr)
+{
+ struct addrinfo *service_info_list = NULL;
+ int err = ::getaddrinfo (host, service, hints_ptr, &service_info_list);
+ if (err == 0 && service_info_list)
+ {
+ if (addr_info_ptr)
+ *addr_info_ptr = *service_info_list;
+ *this = service_info_list;
+ }
+ else
+ Clear();
+
+ :: freeaddrinfo (service_info_list);
+
+ const bool is_valid = IsValid();
+ if (!is_valid)
+ {
+ if (addr_info_ptr)
+ ::memset (addr_info_ptr, 0, sizeof(struct addrinfo));
+ }
+ return is_valid;
+}
+
+
+bool
+SocketAddress::SetToLocalhost (sa_family_t family, in_port_t port)
+{
+ switch (family)
+ {
+ case AF_INET:
+ SetFamily (AF_INET);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv4.sin_addr.s_addr = htonl (INADDR_ANY);
+ return true;
+ }
+ break;
+
+ case AF_INET6:
+ SetFamily (AF_INET6);
+ if (SetPort (port))
+ {
+ m_socket_addr.sa_ipv6.sin6_addr = in6addr_any;
+ return true;
+ }
+ break;
+
+ }
+ Clear();
+ return false;
+}
diff --git a/source/Host/common/Symbols.cpp b/source/Host/common/Symbols.cpp
new file mode 100644
index 000000000000..7189269677d9
--- /dev/null
+++ b/source/Host/common/Symbols.cpp
@@ -0,0 +1,163 @@
+//===-- Symbols.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/Symbols.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#if defined (__linux__) || defined (__FreeBSD__)
+
+FileSpec
+Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
+{
+ // FIXME
+ return FileSpec();
+}
+
+FileSpec
+Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
+{
+ const char *symbol_filename = module_spec.GetSymbolFileSpec().GetFilename().AsCString();
+ if (!symbol_filename || !symbol_filename[0])
+ return FileSpec();
+
+ FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
+
+ // Add module directory.
+ const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
+ debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
+
+ // Add current working directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
+
+ // Add /usr/lib/debug directory.
+ debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
+
+ std::string uuid_str;
+ const UUID &module_uuid = module_spec.GetUUID();
+ if (module_uuid.IsValid())
+ {
+ // Some debug files are stored in the .build-id directory like this:
+ // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
+ uuid_str = module_uuid.GetAsString("");
+ uuid_str.insert (2, 1, '/');
+ uuid_str = uuid_str + ".debug";
+ }
+
+ // Get full path to our module. Needed to check debug files like this:
+ // /usr/lib/debug/usr/lib/libboost_date_time.so.1.46.1
+ std::string module_filename = module_spec.GetFileSpec().GetPath();
+
+ size_t num_directories = debug_file_search_paths.GetSize();
+ for (size_t idx = 0; idx < num_directories; ++idx)
+ {
+ FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
+ dirspec.ResolvePath();
+ if (!dirspec.Exists() || !dirspec.IsDirectory())
+ continue;
+
+ std::vector<std::string> files;
+ std::string dirname = dirspec.GetPath();
+
+ files.push_back (dirname + "/" + symbol_filename);
+ files.push_back (dirname + "/.debug/" + symbol_filename);
+ files.push_back (dirname + "/.build-id/" + uuid_str);
+ files.push_back (dirname + module_filename);
+
+ const uint32_t num_files = files.size();
+ for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
+ {
+ const std::string &filename = files[idx_file];
+ FileSpec file_spec (filename.c_str(), true);
+
+ if (file_spec == module_spec.GetFileSpec())
+ continue;
+
+ if (file_spec.Exists())
+ {
+ lldb_private::ModuleSpecList specs;
+ const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
+ assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
+ if (num_specs == 1)
+ {
+ ModuleSpec mspec;
+ if (specs.GetModuleSpecAtIndex (0, mspec))
+ {
+ if (mspec.GetUUID() == module_uuid)
+ return file_spec;
+ }
+ }
+ }
+ }
+ }
+
+ return FileSpec();
+}
+
+FileSpec
+Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch)
+{
+ // FIXME
+ return FileSpec();
+}
+
+bool
+Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
+{
+ // Fill in the module_spec.GetFileSpec() for the object file and/or the
+ // module_spec.GetSymbolFileSpec() for the debug symbols file.
+ return false;
+}
+
+#elif !defined (__APPLE__)
+
+FileSpec
+Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
+{
+ // FIXME
+ return FileSpec();
+}
+
+FileSpec
+Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
+{
+ // FIXME
+ return FileSpec();
+}
+
+FileSpec
+Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
+ const lldb_private::UUID *uuid,
+ const ArchSpec *arch)
+{
+ return FileSpec();
+}
+
+bool
+Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
+{
+ // Fill in the module_spec.GetFileSpec() for the object file and/or the
+ // module_spec.GetSymbolFileSpec() for the debug symbols file.
+ return false;
+}
+
+#endif
diff --git a/source/Host/common/Terminal.cpp b/source/Host/common/Terminal.cpp
new file mode 100644
index 000000000000..89d21cf0bf6c
--- /dev/null
+++ b/source/Host/common/Terminal.cpp
@@ -0,0 +1,307 @@
+//===-- Terminal.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/Terminal.h"
+#include "lldb/Host/Config.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+#include <termios.h>
+#endif
+
+
+using namespace lldb_private;
+
+bool
+Terminal::IsATerminal () const
+{
+ return m_fd >= 0 && ::isatty (m_fd);
+}
+
+
+bool
+Terminal::SetEcho (bool enabled)
+{
+ if (FileDescriptorIsValid())
+ {
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (IsATerminal ())
+ {
+ struct termios fd_termios;
+ if (::tcgetattr(m_fd, &fd_termios) == 0)
+ {
+ bool set_corectly = false;
+ if (enabled)
+ {
+ if (fd_termios.c_lflag & ECHO)
+ set_corectly = true;
+ else
+ fd_termios.c_lflag |= ECHO;
+ }
+ else
+ {
+ if (fd_termios.c_lflag & ECHO)
+ fd_termios.c_lflag &= ~ECHO;
+ else
+ set_corectly = true;
+ }
+
+ if (set_corectly)
+ return true;
+ return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
+ }
+ }
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ }
+ return false;
+}
+
+bool
+Terminal::SetCanonical (bool enabled)
+{
+ if (FileDescriptorIsValid())
+ {
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (IsATerminal ())
+ {
+ struct termios fd_termios;
+ if (::tcgetattr(m_fd, &fd_termios) == 0)
+ {
+ bool set_corectly = false;
+ if (enabled)
+ {
+ if (fd_termios.c_lflag & ICANON)
+ set_corectly = true;
+ else
+ fd_termios.c_lflag |= ICANON;
+ }
+ else
+ {
+ if (fd_termios.c_lflag & ICANON)
+ fd_termios.c_lflag &= ~ICANON;
+ else
+ set_corectly = true;
+ }
+
+ if (set_corectly)
+ return true;
+ return ::tcsetattr (m_fd, TCSANOW, &fd_termios) == 0;
+ }
+ }
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Default constructor
+//----------------------------------------------------------------------
+TerminalState::TerminalState() :
+ m_tty(),
+ m_tflags(-1),
+ m_termios_ap(),
+ m_process_group(-1)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TerminalState::~TerminalState()
+{
+}
+
+void
+TerminalState::Clear ()
+{
+ m_tty.Clear();
+ m_tflags = -1;
+ m_termios_ap.reset();
+ m_process_group = -1;
+}
+
+//----------------------------------------------------------------------
+// Save the current state of the TTY for the file descriptor "fd"
+// and if "save_process_group" is true, attempt to save the process
+// group info for the TTY.
+//----------------------------------------------------------------------
+bool
+TerminalState::Save (int fd, bool save_process_group)
+{
+ m_tty.SetFileDescriptor(fd);
+ if (m_tty.IsATerminal())
+ {
+ m_tflags = ::fcntl (fd, F_GETFL, 0);
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (m_termios_ap.get() == NULL)
+ m_termios_ap.reset (new struct termios);
+ int err = ::tcgetattr (fd, m_termios_ap.get());
+ if (err != 0)
+ m_termios_ap.reset();
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (save_process_group)
+ m_process_group = ::tcgetpgrp (0);
+ else
+ m_process_group = -1;
+ }
+ else
+ {
+ m_tty.Clear();
+ m_tflags = -1;
+ m_termios_ap.reset();
+ m_process_group = -1;
+ }
+ return IsValid();
+}
+
+//----------------------------------------------------------------------
+// Restore the state of the TTY using the cached values from a
+// previous call to Save().
+//----------------------------------------------------------------------
+bool
+TerminalState::Restore () const
+{
+ if (IsValid())
+ {
+ const int fd = m_tty.GetFileDescriptor();
+ if (TFlagsIsValid())
+ fcntl (fd, F_SETFL, m_tflags);
+
+#ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+ if (TTYStateIsValid())
+ tcsetattr (fd, TCSANOW, m_termios_ap.get());
+#endif // #ifdef LLDB_CONFIG_TERMIOS_SUPPORTED
+
+ if (ProcessGroupIsValid())
+ {
+ // Save the original signal handler.
+ void (*saved_sigttou_callback) (int) = NULL;
+ saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN);
+ // Set the process group
+ tcsetpgrp (fd, m_process_group);
+ // Restore the original signal handler.
+ signal (SIGTTOU, saved_sigttou_callback);
+ }
+ return true;
+ }
+ return false;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Returns true if this object has valid saved TTY state settings
+// that can be used to restore a previous state.
+//----------------------------------------------------------------------
+bool
+TerminalState::IsValid() const
+{
+ return m_tty.FileDescriptorIsValid () && (TFlagsIsValid() || TTYStateIsValid());
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_tflags is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::TFlagsIsValid() const
+{
+ return m_tflags != -1;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_ttystate is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::TTYStateIsValid() const
+{
+ return m_termios_ap.get() != 0;
+}
+
+//----------------------------------------------------------------------
+// Returns true if m_process_group is valid
+//----------------------------------------------------------------------
+bool
+TerminalState::ProcessGroupIsValid() const
+{
+ return m_process_group != -1;
+}
+
+//------------------------------------------------------------------
+// Constructor
+//------------------------------------------------------------------
+TerminalStateSwitcher::TerminalStateSwitcher () :
+ m_currentState(UINT32_MAX)
+{
+}
+
+//------------------------------------------------------------------
+// Destructor
+//------------------------------------------------------------------
+TerminalStateSwitcher::~TerminalStateSwitcher ()
+{
+}
+
+//------------------------------------------------------------------
+// Returns the number of states that this switcher contains
+//------------------------------------------------------------------
+uint32_t
+TerminalStateSwitcher::GetNumberOfStates() const
+{
+ return sizeof(m_ttystates)/sizeof(TerminalState);
+}
+
+//------------------------------------------------------------------
+// Restore the state at index "idx".
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TerminalStateSwitcher::Restore (uint32_t idx) const
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx >= num_states)
+ return false;
+
+ // See if we already are in this state?
+ if (m_currentState < num_states && (idx == m_currentState) && m_ttystates[idx].IsValid())
+ return true;
+
+ // Set the state to match the index passed in and only update the
+ // current state if there are no errors.
+ if (m_ttystates[idx].Restore())
+ {
+ m_currentState = idx;
+ return true;
+ }
+
+ // We failed to set the state. The tty state was invalid or not
+ // initialized.
+ return false;
+}
+
+//------------------------------------------------------------------
+// Save the state at index "idx" for file descriptor "fd" and
+// save the process group if requested.
+//
+// Returns true if the restore was successful, false otherwise.
+//------------------------------------------------------------------
+bool
+TerminalStateSwitcher::Save (uint32_t idx, int fd, bool save_process_group)
+{
+ const uint32_t num_states = GetNumberOfStates();
+ if (idx < num_states)
+ return m_ttystates[idx].Save(fd, save_process_group);
+ return false;
+}
+
+
diff --git a/source/Host/common/TimeValue.cpp b/source/Host/common/TimeValue.cpp
new file mode 100644
index 000000000000..303ac94058b0
--- /dev/null
+++ b/source/Host/common/TimeValue.cpp
@@ -0,0 +1,210 @@
+//===-- TimeValue.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/TimeValue.h"
+
+// C Includes
+#include <stddef.h>
+#include <time.h>
+#include <cstring>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// TimeValue constructor
+//----------------------------------------------------------------------
+TimeValue::TimeValue() :
+ m_nano_seconds (0)
+{
+}
+
+//----------------------------------------------------------------------
+// TimeValue copy constructor
+//----------------------------------------------------------------------
+TimeValue::TimeValue(const TimeValue& rhs) :
+ m_nano_seconds (rhs.m_nano_seconds)
+{
+}
+
+TimeValue::TimeValue(const struct timespec& ts) :
+ m_nano_seconds ((uint64_t) ts.tv_sec * NanoSecPerSec + ts.tv_nsec)
+{
+}
+
+TimeValue::TimeValue(const struct timeval& tv) :
+ m_nano_seconds ((uint64_t) tv.tv_sec * NanoSecPerSec + (uint64_t) tv.tv_usec * NanoSecPerMicroSec)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TimeValue::~TimeValue()
+{
+}
+
+
+uint64_t
+TimeValue::GetAsNanoSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds;
+}
+
+uint64_t
+TimeValue::GetAsMicroSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds / NanoSecPerMicroSec;
+}
+
+uint64_t
+TimeValue::GetAsSecondsSinceJan1_1970() const
+{
+ return m_nano_seconds / NanoSecPerSec;
+}
+
+
+
+struct timespec
+TimeValue::GetAsTimeSpec () const
+{
+ struct timespec ts;
+ ts.tv_sec = m_nano_seconds / NanoSecPerSec;
+ ts.tv_nsec = m_nano_seconds % NanoSecPerSec;
+ return ts;
+}
+
+struct timeval
+TimeValue::GetAsTimeVal () const
+{
+ struct timeval tv;
+ tv.tv_sec = m_nano_seconds / NanoSecPerSec;
+ tv.tv_usec = (m_nano_seconds % NanoSecPerSec) / NanoSecPerMicroSec;
+ return tv;
+}
+
+void
+TimeValue::Clear ()
+{
+ m_nano_seconds = 0;
+}
+
+bool
+TimeValue::IsValid () const
+{
+ return m_nano_seconds != 0;
+}
+
+void
+TimeValue::OffsetWithSeconds (uint64_t sec)
+{
+ m_nano_seconds += sec * NanoSecPerSec;
+}
+
+void
+TimeValue::OffsetWithMicroSeconds (uint64_t usec)
+{
+ m_nano_seconds += usec * NanoSecPerMicroSec;
+}
+
+void
+TimeValue::OffsetWithNanoSeconds (uint64_t nsec)
+{
+ m_nano_seconds += nsec;
+}
+
+TimeValue
+TimeValue::Now()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ TimeValue now(tv);
+ return now;
+}
+
+//----------------------------------------------------------------------
+// TimeValue assignment operator
+//----------------------------------------------------------------------
+const TimeValue&
+TimeValue::operator=(const TimeValue& rhs)
+{
+ m_nano_seconds = rhs.m_nano_seconds;
+ return *this;
+}
+
+void
+TimeValue::Dump (Stream *s, uint32_t width) const
+{
+ if (s == NULL)
+ return;
+
+ char time_buf[32];
+ time_t time = GetAsSecondsSinceJan1_1970();
+ char *time_cstr = ::ctime_r(&time, time_buf);
+ if (time_cstr)
+ {
+ char *newline = ::strpbrk(time_cstr, "\n\r");
+ if (newline)
+ *newline = '\0';
+ if (width > 0)
+ s->Printf("%-*s", width, time_cstr);
+ else
+ s->PutCString(time_cstr);
+ }
+ else if (width > 0)
+ s->Printf("%-*s", width, "");
+}
+
+bool
+lldb_private::operator == (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() == rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator != (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() != rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator < (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() < rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator <= (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() <= rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator > (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() > rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+bool
+lldb_private::operator >= (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() >= rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+uint64_t
+lldb_private::operator - (const TimeValue &lhs, const TimeValue &rhs)
+{
+ return lhs.GetAsNanoSecondsSinceJan1_1970() - rhs.GetAsNanoSecondsSinceJan1_1970();
+}
+
+
diff --git a/source/Host/freebsd/Host.cpp b/source/Host/freebsd/Host.cpp
new file mode 100644
index 000000000000..405e7eacf5a9
--- /dev/null
+++ b/source/Host/freebsd/Host.cpp
@@ -0,0 +1,337 @@
+//===-- source/Host/freebsd/Host.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdio.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/utsname.h>
+#include <sys/sysctl.h>
+
+#include <sys/ptrace.h>
+#include <sys/exec.h>
+#include <machine/elf.h>
+
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Process.h"
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "llvm/Support/Host.h"
+
+
+extern "C" {
+ extern char **environ;
+}
+
+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)
+{
+ std::string thread_name;
+ return thread_name;
+}
+
+void
+Host::Backtrace (Stream &strm, uint32_t max_frames)
+{
+ char backtrace_path[] = "/tmp/lldb-backtrace-tmp-XXXXXX";
+ int backtrace_fd = ::mkstemp (backtrace_path);
+ if (backtrace_fd != -1)
+ {
+ std::vector<void *> frame_buffer (max_frames, NULL);
+ int count = ::backtrace (&frame_buffer[0], frame_buffer.size());
+ ::backtrace_symbols_fd (&frame_buffer[0], count, backtrace_fd);
+
+ const off_t buffer_size = ::lseek(backtrace_fd, 0, SEEK_CUR);
+
+ if (::lseek(backtrace_fd, 0, SEEK_SET) == 0)
+ {
+ char *buffer = (char *)::malloc (buffer_size);
+ if (buffer)
+ {
+ ssize_t bytes_read = ::read (backtrace_fd, buffer, buffer_size);
+ if (bytes_read > 0)
+ strm.Write(buffer, bytes_read);
+ ::free (buffer);
+ }
+ }
+ ::close (backtrace_fd);
+ ::unlink (backtrace_path);
+ }
+}
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+ char *v;
+ char **var = environ;
+ for (; var != NULL && *var != NULL; ++var) {
+ v = strchr(*var, (int)'-');
+ if (v == NULL)
+ continue;
+ env.AppendString(v);
+ }
+ return env.GetSize();
+}
+
+bool
+Host::GetOSVersion(uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update)
+{
+ struct utsname un;
+ int status;
+
+ if (uname(&un) < 0)
+ return false;
+
+ status = sscanf(un.release, "%u.%u", &major, &minor);
+ return status == 2;
+}
+
+Error
+Host::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ assert(!"Not implemented yet!!!");
+ return error;
+}
+
+bool
+Host::GetOSBuildString (std::string &s)
+{
+ int mib[2] = { CTL_KERN, KERN_OSREV };
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign (cstr, cstr_len);
+ return true;
+ }
+ s.clear();
+ return false;
+}
+
+bool
+Host::GetOSKernelDescription (std::string &s)
+{
+ int mib[2] = { CTL_KERN, KERN_VERSION };
+ char cstr[PATH_MAX];
+ size_t cstr_len = sizeof(cstr);
+ if (::sysctl (mib, 2, cstr, &cstr_len, NULL, 0) == 0)
+ {
+ s.assign (cstr, cstr_len);
+ return true;
+ }
+ s.clear();
+ return false;
+}
+
+static bool
+GetFreeBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr,
+ ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid()) {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, (int)process_info.GetProcessID() };
+
+ char arg_data[8192];
+ size_t arg_data_size = sizeof(arg_data);
+ if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) == 0)
+ {
+ DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *));
+ lldb::offset_t offset = 0;
+ const char *cstr;
+
+ cstr = data.GetCStr (&offset);
+ if (cstr)
+ {
+ process_info.GetExecutableFile().SetFile(cstr, false);
+
+ if (!(match_info_ptr == NULL ||
+ NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(),
+ match_info_ptr->GetNameMatchType(),
+ match_info_ptr->GetProcessInfo().GetName())))
+ return false;
+
+ Args &proc_args = process_info.GetArguments();
+ while (1)
+ {
+ const uint8_t *p = data.PeekData(offset, 1);
+ while ((p != NULL) && (*p == '\0') && offset < arg_data_size)
+ {
+ ++offset;
+ p = data.PeekData(offset, 1);
+ }
+ if (p == NULL || offset >= arg_data_size)
+ return true;
+
+ cstr = data.GetCStr(&offset);
+ if (cstr)
+ proc_args.AppendArgument(cstr);
+ else
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+static bool
+GetFreeBSDProcessCPUType (ProcessInstanceInfo &process_info)
+{
+ if (process_info.ProcessIDIsValid()) {
+ process_info.GetArchitecture() = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ return true;
+ }
+ process_info.GetArchitecture().Clear();
+ return false;
+}
+
+static bool
+GetFreeBSDProcessUserAndGroup(ProcessInstanceInfo &process_info)
+{
+ struct kinfo_proc proc_kinfo;
+ size_t proc_kinfo_size;
+
+ if (process_info.ProcessIDIsValid())
+ {
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
+ (int)process_info.GetProcessID() };
+ proc_kinfo_size = sizeof(struct kinfo_proc);
+
+ if (::sysctl (mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0)
+ {
+ if (proc_kinfo_size > 0)
+ {
+ process_info.SetParentProcessID (proc_kinfo.ki_ppid);
+ process_info.SetUserID (proc_kinfo.ki_ruid);
+ process_info.SetGroupID (proc_kinfo.ki_rgid);
+ process_info.SetEffectiveUserID (proc_kinfo.ki_uid);
+ if (proc_kinfo.ki_ngroups > 0)
+ process_info.SetEffectiveGroupID (proc_kinfo.ki_groups[0]);
+ else
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID);
+ process_info.SetUserID (UINT32_MAX);
+ process_info.SetGroupID (UINT32_MAX);
+ process_info.SetEffectiveUserID (UINT32_MAX);
+ process_info.SetEffectiveGroupID (UINT32_MAX);
+ return false;
+}
+
+bool
+Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.SetProcessID(pid);
+ if (GetFreeBSDProcessArgs(NULL, process_info)) {
+ // should use libprocstat instead of going right into sysctl?
+ GetFreeBSDProcessCPUType(process_info);
+ GetFreeBSDProcessUserAndGroup(process_info);
+ return true;
+ }
+ process_info.Clear();
+ return false;
+}
+
+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;
+ 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);
+ buf_sp.reset(buf_ap.release());
+ } else {
+ perror("sysctl failed on ps_strings");
+ }
+
+ done:
+ return buf_sp;
+}
diff --git a/source/Interpreter/Args.cpp b/source/Interpreter/Args.cpp
new file mode 100644
index 000000000000..e6d20435803f
--- /dev/null
+++ b/source/Interpreter/Args.cpp
@@ -0,0 +1,1789 @@
+//===-- Args.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"
+
+// C Includes
+#include <getopt.h>
+#include <cstdlib>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Process.h"
+//#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+//#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Args constructor
+//----------------------------------------------------------------------
+Args::Args (const char *command) :
+ m_args(),
+ m_argv(),
+ m_args_quote_char()
+{
+ if (command)
+ SetCommandString (command);
+}
+
+
+Args::Args (const char *command, size_t len) :
+ m_args(),
+ m_argv(),
+ m_args_quote_char()
+{
+ if (command && len)
+ SetCommandString (command, len);
+}
+
+//----------------------------------------------------------------------
+// We have to be very careful on the copy constructor of this class
+// to make sure we copy all of the string values, but we can't copy the
+// rhs.m_argv into m_argv since it will point to the "const char *" c
+// strings in rhs.m_args. We need to copy the string list and update our
+// own m_argv appropriately.
+//----------------------------------------------------------------------
+Args::Args (const Args &rhs) :
+ m_args (rhs.m_args),
+ m_argv (),
+ m_args_quote_char(rhs.m_args_quote_char)
+{
+ UpdateArgvFromArgs();
+}
+
+//----------------------------------------------------------------------
+// We have to be very careful on the copy constructor of this class
+// to make sure we copy all of the string values, but we can't copy the
+// rhs.m_argv into m_argv since it will point to the "const char *" c
+// strings in rhs.m_args. We need to copy the string list and update our
+// own m_argv appropriately.
+//----------------------------------------------------------------------
+const Args &
+Args::operator= (const Args &rhs)
+{
+ // Make sure we aren't assigning to self
+ if (this != &rhs)
+ {
+ m_args = rhs.m_args;
+ m_args_quote_char = rhs.m_args_quote_char;
+ UpdateArgvFromArgs();
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Args::~Args ()
+{
+}
+
+void
+Args::Dump (Stream *s)
+{
+ const size_t argc = m_argv.size();
+ for (size_t i=0; i<argc; ++i)
+ {
+ s->Indent();
+ const char *arg_cstr = m_argv[i];
+ if (arg_cstr)
+ s->Printf("argv[%zi]=\"%s\"\n", i, arg_cstr);
+ else
+ s->Printf("argv[%zi]=NULL\n", i);
+ }
+ s->EOL();
+}
+
+bool
+Args::GetCommandString (std::string &command) const
+{
+ command.clear();
+ const size_t argc = GetArgumentCount();
+ for (size_t i=0; i<argc; ++i)
+ {
+ if (i > 0)
+ command += ' ';
+ command += m_argv[i];
+ }
+ return argc > 0;
+}
+
+bool
+Args::GetQuotedCommandString (std::string &command) const
+{
+ command.clear ();
+ const size_t argc = GetArgumentCount();
+ for (size_t i = 0; i < argc; ++i)
+ {
+ if (i > 0)
+ command.append (1, ' ');
+ char quote_char = GetArgumentQuoteCharAtIndex(i);
+ if (quote_char)
+ {
+ command.append (1, quote_char);
+ command.append (m_argv[i]);
+ command.append (1, quote_char);
+ }
+ else
+ command.append (m_argv[i]);
+ }
+ return argc > 0;
+}
+
+void
+Args::SetCommandString (const char *command, size_t len)
+{
+ // Use std::string to make sure we get a NULL terminated string we can use
+ // as "command" could point to a string within a large string....
+ std::string null_terminated_command(command, len);
+ SetCommandString(null_terminated_command.c_str());
+}
+
+void
+Args::SetCommandString (const char *command)
+{
+ m_args.clear();
+ m_argv.clear();
+ m_args_quote_char.clear();
+
+ if (command && command[0])
+ {
+ static const char *k_space_separators = " \t";
+ static const char *k_space_separators_with_slash_and_quotes = " \t \\'\"";
+ const char *arg_end = NULL;
+ const char *arg_pos;
+ for (arg_pos = command;
+ arg_pos && arg_pos[0];
+ arg_pos = arg_end)
+ {
+ // Skip any leading space separators
+ const char *arg_start = ::strspn (arg_pos, k_space_separators) + arg_pos;
+
+ // If there were only space separators to the end of the line, then
+ // we're done.
+ if (*arg_start == '\0')
+ break;
+
+ // Arguments can be split into multiple discontiguous pieces,
+ // for example:
+ // "Hello ""World"
+ // this would result in a single argument "Hello World" (without/
+ // the quotes) since the quotes would be removed and there is
+ // not space between the strings. So we need to keep track of the
+ // current start of each argument piece in "arg_piece_start"
+ const char *arg_piece_start = arg_start;
+ arg_pos = arg_piece_start;
+
+ std::string arg;
+ // Since we can have multiple quotes that form a single command
+ // in a command like: "Hello "world'!' (which will make a single
+ // argument "Hello world!") we remember the first quote character
+ // we encounter and use that for the quote character.
+ char first_quote_char = '\0';
+ char quote_char = '\0';
+ bool arg_complete = false;
+
+ do
+ {
+ arg_end = ::strcspn (arg_pos, k_space_separators_with_slash_and_quotes) + arg_pos;
+
+ switch (arg_end[0])
+ {
+ default:
+ assert (!"Unhandled case statement, we must handle this...");
+ break;
+
+ case '\0':
+ // End of C string
+ if (arg_piece_start && arg_piece_start[0])
+ arg.append (arg_piece_start);
+ arg_complete = true;
+ break;
+
+ case '\\':
+ // Backslash character
+ switch (arg_end[1])
+ {
+ case '\0':
+ arg.append (arg_piece_start);
+ ++arg_end;
+ arg_complete = true;
+ break;
+
+ default:
+ if (quote_char == '\0')
+ {
+ arg.append (arg_piece_start, arg_end - arg_piece_start);
+ if (arg_end[1] != '\0')
+ {
+ arg.append (arg_end + 1, 1);
+ arg_pos = arg_end + 2;
+ arg_piece_start = arg_pos;
+ }
+ }
+ else
+ arg_pos = arg_end + 2;
+ break;
+ }
+ break;
+
+ case '"':
+ case '\'':
+ case '`':
+ // Quote characters
+ if (quote_char)
+ {
+ // We found a quote character while inside a quoted
+ // character argument. If it matches our current quote
+ // character, this ends the effect of the quotes. If it
+ // doesn't we ignore it.
+ if (quote_char == arg_end[0])
+ {
+ arg.append (arg_piece_start, arg_end - arg_piece_start);
+ // Clear the quote character and let parsing
+ // continue (we need to watch for things like:
+ // "Hello ""World"
+ // "Hello "World
+ // "Hello "'World'
+ // All of which will result in a single argument "Hello World"
+ quote_char = '\0'; // Note that we are no longer inside quotes
+ arg_pos = arg_end + 1; // Skip the quote character
+ arg_piece_start = arg_pos; // Note we are starting from later in the string
+ }
+ else
+ {
+ // different quote, skip it and keep going
+ arg_pos = arg_end + 1;
+ }
+ }
+ else
+ {
+ // We found the start of a quote scope.
+ // Make sure there isn't a string that precedes
+ // the start of a quote scope like:
+ // Hello" World"
+ // If so, then add the "Hello" to the arg
+ if (arg_end > arg_piece_start)
+ arg.append (arg_piece_start, arg_end - arg_piece_start);
+
+ // Enter into a quote scope
+ quote_char = arg_end[0];
+
+ if (first_quote_char == '\0')
+ first_quote_char = quote_char;
+
+ arg_pos = arg_end;
+ ++arg_pos; // Skip the quote character
+ arg_piece_start = arg_pos; // Note we are starting from later in the string
+
+ // Skip till the next quote character
+ const char *end_quote = ::strchr (arg_piece_start, quote_char);
+ while (end_quote && end_quote[-1] == '\\')
+ {
+ // Don't skip the quote character if it is
+ // preceded by a '\' character
+ end_quote = ::strchr (end_quote + 1, quote_char);
+ }
+
+ if (end_quote)
+ {
+ if (end_quote > arg_piece_start)
+ arg.append (arg_piece_start, end_quote - arg_piece_start);
+
+ // If the next character is a space or the end of
+ // string, this argument is complete...
+ if (end_quote[1] == ' ' || end_quote[1] == '\t' || end_quote[1] == '\0')
+ {
+ arg_complete = true;
+ arg_end = end_quote + 1;
+ }
+ else
+ {
+ arg_pos = end_quote + 1;
+ arg_piece_start = arg_pos;
+ }
+ quote_char = '\0';
+ }
+ else
+ {
+ // Consume the rest of the string as there was no terminating quote
+ arg.append(arg_piece_start);
+ arg_end = arg_piece_start + strlen(arg_piece_start);
+ arg_complete = true;
+ }
+ }
+ break;
+
+ case ' ':
+ case '\t':
+ if (quote_char)
+ {
+ // We are currently processing a quoted character and found
+ // a space character, skip any spaces and keep trying to find
+ // the end of the argument.
+ arg_pos = ::strspn (arg_end, k_space_separators) + arg_end;
+ }
+ else
+ {
+ // We are not inside any quotes, we just found a space after an
+ // argument
+ if (arg_end > arg_piece_start)
+ arg.append (arg_piece_start, arg_end - arg_piece_start);
+ arg_complete = true;
+ }
+ break;
+ }
+ } while (!arg_complete);
+
+ m_args.push_back(arg);
+ m_args_quote_char.push_back (first_quote_char);
+ }
+ UpdateArgvFromArgs();
+ }
+}
+
+void
+Args::UpdateArgsAfterOptionParsing()
+{
+ // Now m_argv might be out of date with m_args, so we need to fix that
+ arg_cstr_collection::const_iterator argv_pos, argv_end = m_argv.end();
+ arg_sstr_collection::iterator args_pos;
+ arg_quote_char_collection::iterator quotes_pos;
+
+ for (argv_pos = m_argv.begin(), args_pos = m_args.begin(), quotes_pos = m_args_quote_char.begin();
+ argv_pos != argv_end && args_pos != m_args.end();
+ ++argv_pos)
+ {
+ const char *argv_cstr = *argv_pos;
+ if (argv_cstr == NULL)
+ break;
+
+ while (args_pos != m_args.end())
+ {
+ const char *args_cstr = args_pos->c_str();
+ if (args_cstr == argv_cstr)
+ {
+ // We found the argument that matches the C string in the
+ // vector, so we can now look for the next one
+ ++args_pos;
+ ++quotes_pos;
+ break;
+ }
+ else
+ {
+ quotes_pos = m_args_quote_char.erase (quotes_pos);
+ args_pos = m_args.erase (args_pos);
+ }
+ }
+ }
+
+ if (args_pos != m_args.end())
+ m_args.erase (args_pos, m_args.end());
+
+ if (quotes_pos != m_args_quote_char.end())
+ m_args_quote_char.erase (quotes_pos, m_args_quote_char.end());
+}
+
+void
+Args::UpdateArgvFromArgs()
+{
+ m_argv.clear();
+ arg_sstr_collection::const_iterator pos, end = m_args.end();
+ for (pos = m_args.begin(); pos != end; ++pos)
+ m_argv.push_back(pos->c_str());
+ m_argv.push_back(NULL);
+ // Make sure we have enough arg quote chars in the array
+ if (m_args_quote_char.size() < m_args.size())
+ m_args_quote_char.resize (m_argv.size());
+}
+
+size_t
+Args::GetArgumentCount() const
+{
+ if (m_argv.empty())
+ return 0;
+ return m_argv.size() - 1;
+}
+
+const char *
+Args::GetArgumentAtIndex (size_t idx) const
+{
+ if (idx < m_argv.size())
+ return m_argv[idx];
+ return NULL;
+}
+
+char
+Args::GetArgumentQuoteCharAtIndex (size_t idx) const
+{
+ if (idx < m_args_quote_char.size())
+ return m_args_quote_char[idx];
+ return '\0';
+}
+
+char **
+Args::GetArgumentVector()
+{
+ if (!m_argv.empty())
+ return (char **)&m_argv[0];
+ return NULL;
+}
+
+const char **
+Args::GetConstArgumentVector() const
+{
+ if (!m_argv.empty())
+ return (const char **)&m_argv[0];
+ return NULL;
+}
+
+void
+Args::Shift ()
+{
+ // Don't pop the last NULL terminator from the argv array
+ if (m_argv.size() > 1)
+ {
+ m_argv.erase(m_argv.begin());
+ m_args.pop_front();
+ if (!m_args_quote_char.empty())
+ m_args_quote_char.erase(m_args_quote_char.begin());
+ }
+}
+
+const char *
+Args::Unshift (const char *arg_cstr, char quote_char)
+{
+ m_args.push_front(arg_cstr);
+ m_argv.insert(m_argv.begin(), m_args.front().c_str());
+ m_args_quote_char.insert(m_args_quote_char.begin(), quote_char);
+ return GetArgumentAtIndex (0);
+}
+
+void
+Args::AppendArguments (const Args &rhs)
+{
+ const size_t rhs_argc = rhs.GetArgumentCount();
+ for (size_t i=0; i<rhs_argc; ++i)
+ AppendArgument(rhs.GetArgumentAtIndex(i));
+}
+
+void
+Args::AppendArguments (const char **argv)
+{
+ if (argv)
+ {
+ for (uint32_t i=0; argv[i]; ++i)
+ AppendArgument(argv[i]);
+ }
+}
+
+const char *
+Args::AppendArgument (const char *arg_cstr, char quote_char)
+{
+ return InsertArgumentAtIndex (GetArgumentCount(), arg_cstr, quote_char);
+}
+
+const char *
+Args::InsertArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ pos = m_args.insert(pos, arg_cstr);
+
+ if (idx >= m_args_quote_char.size())
+ {
+ m_args_quote_char.resize(idx + 1);
+ m_args_quote_char[idx] = quote_char;
+ }
+ else
+ m_args_quote_char.insert(m_args_quote_char.begin() + idx, quote_char);
+
+ UpdateArgvFromArgs();
+ return GetArgumentAtIndex(idx);
+}
+
+const char *
+Args::ReplaceArgumentAtIndex (size_t idx, const char *arg_cstr, char quote_char)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ if (pos != end)
+ {
+ pos->assign(arg_cstr);
+ assert(idx < m_argv.size() - 1);
+ m_argv[idx] = pos->c_str();
+ if (idx >= m_args_quote_char.size())
+ m_args_quote_char.resize(idx + 1);
+ m_args_quote_char[idx] = quote_char;
+ return GetArgumentAtIndex(idx);
+ }
+ return NULL;
+}
+
+void
+Args::DeleteArgumentAtIndex (size_t idx)
+{
+ // Since we are using a std::list to hold onto the copied C string and
+ // we don't have direct access to the elements, we have to iterate to
+ // find the value.
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ size_t i = idx;
+ for (pos = m_args.begin(); i > 0 && pos != end; ++pos)
+ --i;
+
+ if (pos != end)
+ {
+ m_args.erase (pos);
+ assert(idx < m_argv.size() - 1);
+ m_argv.erase(m_argv.begin() + idx);
+ if (idx < m_args_quote_char.size())
+ m_args_quote_char.erase(m_args_quote_char.begin() + idx);
+ }
+}
+
+void
+Args::SetArguments (size_t argc, const char **argv)
+{
+ // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
+ // no need to clear it here.
+ m_args.clear();
+ m_args_quote_char.clear();
+
+ // First copy each string
+ for (size_t i=0; i<argc; ++i)
+ {
+ m_args.push_back (argv[i]);
+ if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
+ m_args_quote_char.push_back (argv[i][0]);
+ else
+ m_args_quote_char.push_back ('\0');
+ }
+
+ UpdateArgvFromArgs();
+}
+
+void
+Args::SetArguments (const char **argv)
+{
+ // m_argv will be rebuilt in UpdateArgvFromArgs() below, so there is
+ // no need to clear it here.
+ m_args.clear();
+ m_args_quote_char.clear();
+
+ if (argv)
+ {
+ // First copy each string
+ for (size_t i=0; argv[i]; ++i)
+ {
+ m_args.push_back (argv[i]);
+ if ((argv[i][0] == '\'') || (argv[i][0] == '"') || (argv[i][0] == '`'))
+ m_args_quote_char.push_back (argv[i][0]);
+ else
+ m_args_quote_char.push_back ('\0');
+ }
+ }
+
+ UpdateArgvFromArgs();
+}
+
+
+Error
+Args::ParseOptions (Options &options)
+{
+ StreamString sstr;
+ Error error;
+ struct option *long_options = options.GetLongOptions();
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat("invalid long options");
+ return error;
+ }
+
+ for (int i=0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ if (isprint8(long_options[i].val))
+ {
+ sstr << (char)long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument: break;
+ case required_argument: sstr << ':'; break;
+ case optional_argument: sstr << "::"; break;
+ }
+ }
+ }
+ }
+#ifdef __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long_only(GetArgumentCount(),
+ GetArgumentVector(),
+ sstr.GetData(),
+ long_options,
+ &long_options_index);
+ if (val == -1)
+ break;
+
+ // Did we get an error?
+ if (val == '?')
+ {
+ error.SetErrorStringWithFormat("unknown or ambiguous option");
+ break;
+ }
+ // The option auto-set itself
+ if (val == 0)
+ continue;
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Lookup the long option index
+ if (long_options_index == -1)
+ {
+ for (int i=0;
+ long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+ ++i)
+ {
+ if (long_options[i].val == val)
+ {
+ long_options_index = i;
+ break;
+ }
+ }
+ }
+ // Call the callback with the option
+ if (long_options_index >= 0)
+ {
+ error = options.SetOptionValue(long_options_index,
+ long_options[long_options_index].has_arg == no_argument ? NULL : optarg);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid option with value '%i'", val);
+ }
+ if (error.Fail())
+ break;
+ }
+
+ // Update our ARGV now that get options has consumed all the options
+ m_argv.erase(m_argv.begin(), m_argv.begin() + optind);
+ UpdateArgsAfterOptionParsing ();
+ return error;
+}
+
+void
+Args::Clear ()
+{
+ m_args.clear ();
+ m_argv.clear ();
+ m_args_quote_char.clear();
+}
+
+int32_t
+Args::StringToSInt32 (const char *s, int32_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ const long sval = ::strtol (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = ((sval <= INT32_MAX) && (sval >= INT32_MIN));
+ return (int32_t)sval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+uint32_t
+Args::StringToUInt32 (const char *s, uint32_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ const unsigned long uval = ::strtoul (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr)
+ *success_ptr = (uval <= UINT32_MAX);
+ return (uint32_t)uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+
+int64_t
+Args::StringToSInt64 (const char *s, int64_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ int64_t uval = ::strtoll (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+uint64_t
+Args::StringToUInt64 (const char *s, uint64_t fail_value, int base, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ char *end = NULL;
+ uint64_t uval = ::strtoull (s, &end, base);
+ if (*end == '\0')
+ {
+ if (success_ptr) *success_ptr = true;
+ return uval; // All characters were used, return the result
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+lldb::addr_t
+Args::StringToAddress (const ExecutionContext *exe_ctx, const char *s, lldb::addr_t fail_value, Error *error_ptr)
+{
+ bool error_set = false;
+ if (s && s[0])
+ {
+ char *end = NULL;
+ lldb::addr_t addr = ::strtoull (s, &end, 0);
+ if (*end == '\0')
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return addr; // All characters were used, return the result
+ }
+ // Try base 16 with no prefix...
+ addr = ::strtoull (s, &end, 16);
+ if (*end == '\0')
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return addr; // All characters were used, return the result
+ }
+
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ lldb::ValueObjectSP valobj_sp;
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false);
+ options.SetUnwindOnError(true);
+ options.SetKeepInMemory(false);
+ options.SetRunOthers(true);
+
+ ExecutionResults expr_result = target->EvaluateExpression(s,
+ exe_ctx->GetFramePtr(),
+ valobj_sp,
+ options);
+
+ bool success = false;
+ if (expr_result == eExecutionCompleted)
+ {
+ // Get the address to watch.
+ addr = valobj_sp->GetValueAsUnsigned(fail_value, &success);
+ if (success)
+ {
+ if (error_ptr)
+ error_ptr->Clear();
+ return addr;
+ }
+ else
+ {
+ if (error_ptr)
+ {
+ error_set = true;
+ error_ptr->SetErrorStringWithFormat("address expression \"%s\" resulted in a value whose type can't be converted to an address: %s", s, valobj_sp->GetTypeName().GetCString());
+ }
+ }
+
+ }
+ else
+ {
+ // Since the compiler can't handle things like "main + 12" we should
+ // try to do this for now. The compliler doesn't like adding offsets
+ // to function pointer types.
+ static RegularExpression g_symbol_plus_offset_regex("^(.*)([-\\+])[[:space:]]*(0x[0-9A-Fa-f]+|[0-9]+)[[:space:]]*$");
+ RegularExpression::Match regex_match(3);
+ if (g_symbol_plus_offset_regex.Execute(s, &regex_match))
+ {
+ uint64_t offset = 0;
+ bool add = true;
+ std::string name;
+ std::string str;
+ if (regex_match.GetMatchAtIndex(s, 1, name))
+ {
+ if (regex_match.GetMatchAtIndex(s, 2, str))
+ {
+ add = str[0] == '+';
+
+ if (regex_match.GetMatchAtIndex(s, 3, str))
+ {
+ offset = Args::StringToUInt64(str.c_str(), 0, 0, &success);
+
+ if (success)
+ {
+ Error error;
+ addr = StringToAddress (exe_ctx, name.c_str(), LLDB_INVALID_ADDRESS, &error);
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ if (add)
+ return addr + offset;
+ else
+ return addr - offset;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (error_ptr)
+ {
+ error_set = true;
+ error_ptr->SetErrorStringWithFormat("address expression \"%s\" evaluation failed", s);
+ }
+ }
+ }
+ }
+ }
+ if (error_ptr)
+ {
+ if (!error_set)
+ error_ptr->SetErrorStringWithFormat("invalid address expression \"%s\"", s);
+ }
+ return fail_value;
+}
+
+const char *
+Args::StripSpaces (std::string &s, bool leading, bool trailing, bool return_null_if_empty)
+{
+ static const char *k_white_space = " \t\v";
+ if (!s.empty())
+ {
+ if (leading)
+ {
+ size_t pos = s.find_first_not_of (k_white_space);
+ if (pos == std::string::npos)
+ s.clear();
+ else if (pos > 0)
+ s.erase(0, pos);
+ }
+
+ if (trailing)
+ {
+ size_t rpos = s.find_last_not_of(k_white_space);
+ if (rpos != std::string::npos && rpos + 1 < s.size())
+ s.erase(rpos + 1);
+ }
+ }
+ if (return_null_if_empty && s.empty())
+ return NULL;
+ return s.c_str();
+}
+
+bool
+Args::StringToBoolean (const char *s, bool fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ if (::strcasecmp (s, "false") == 0 ||
+ ::strcasecmp (s, "off") == 0 ||
+ ::strcasecmp (s, "no") == 0 ||
+ ::strcmp (s, "0") == 0)
+ {
+ if (success_ptr)
+ *success_ptr = true;
+ return false;
+ }
+ else
+ if (::strcasecmp (s, "true") == 0 ||
+ ::strcasecmp (s, "on") == 0 ||
+ ::strcasecmp (s, "yes") == 0 ||
+ ::strcmp (s, "1") == 0)
+ {
+ if (success_ptr) *success_ptr = true;
+ return true;
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+const char *
+Args::StringToVersion (const char *s, uint32_t &major, uint32_t &minor, uint32_t &update)
+{
+ major = UINT32_MAX;
+ minor = UINT32_MAX;
+ update = UINT32_MAX;
+
+ if (s && s[0])
+ {
+ char *pos = NULL;
+ unsigned long uval32 = ::strtoul (s, &pos, 0);
+ if (pos == s)
+ return s;
+ major = uval32;
+ if (*pos == '\0')
+ {
+ return pos; // Decoded major and got end of string
+ }
+ else if (*pos == '.')
+ {
+ const char *minor_cstr = pos + 1;
+ uval32 = ::strtoul (minor_cstr, &pos, 0);
+ if (pos == minor_cstr)
+ return pos; // Didn't get any digits for the minor version...
+ minor = uval32;
+ if (*pos == '.')
+ {
+ const char *update_cstr = pos + 1;
+ uval32 = ::strtoul (update_cstr, &pos, 0);
+ if (pos == update_cstr)
+ return pos;
+ update = uval32;
+ }
+ return pos;
+ }
+ }
+ return 0;
+}
+
+const char *
+Args::GetShellSafeArgument (const char *unsafe_arg, std::string &safe_arg)
+{
+ safe_arg.assign (unsafe_arg);
+ size_t prev_pos = 0;
+ while (prev_pos < safe_arg.size())
+ {
+ // Escape spaces and quotes
+ size_t pos = safe_arg.find_first_of(" '\"", prev_pos);
+ if (pos != std::string::npos)
+ {
+ safe_arg.insert (pos, 1, '\\');
+ prev_pos = pos + 2;
+ }
+ else
+ break;
+ }
+ return safe_arg.c_str();
+}
+
+
+int64_t
+Args::StringToOptionEnum (const char *s, OptionEnumValueElement *enum_values, int32_t fail_value, Error &error)
+{
+ if (enum_values)
+ {
+ if (s && s[0])
+ {
+ for (int i = 0; enum_values[i].string_value != NULL ; i++)
+ {
+ if (strstr(enum_values[i].string_value, s) == enum_values[i].string_value)
+ {
+ error.Clear();
+ return enum_values[i].value;
+ }
+ }
+ }
+
+ StreamString strm;
+ strm.PutCString ("invalid enumeration value, valid values are: ");
+ for (int i = 0; enum_values[i].string_value != NULL; i++)
+ {
+ strm.Printf ("%s\"%s\"",
+ i > 0 ? ", " : "",
+ enum_values[i].string_value);
+ }
+ error.SetErrorString(strm.GetData());
+ }
+ else
+ {
+ error.SetErrorString ("invalid enumeration argument");
+ }
+ return fail_value;
+}
+
+ScriptLanguage
+Args::StringToScriptLanguage (const char *s, ScriptLanguage fail_value, bool *success_ptr)
+{
+ if (s && s[0])
+ {
+ if ((::strcasecmp (s, "python") == 0) ||
+ (::strcasecmp (s, "default") == 0 && eScriptLanguagePython == eScriptLanguageDefault))
+ {
+ if (success_ptr) *success_ptr = true;
+ return eScriptLanguagePython;
+ }
+ if (::strcasecmp (s, "none"))
+ {
+ if (success_ptr) *success_ptr = true;
+ return eScriptLanguageNone;
+ }
+ }
+ if (success_ptr) *success_ptr = false;
+ return fail_value;
+}
+
+Error
+Args::StringToFormat
+(
+ const char *s,
+ lldb::Format &format,
+ size_t *byte_size_ptr
+)
+{
+ format = eFormatInvalid;
+ Error error;
+
+ if (s && s[0])
+ {
+ if (byte_size_ptr)
+ {
+ if (isdigit (s[0]))
+ {
+ char *format_char = NULL;
+ unsigned long byte_size = ::strtoul (s, &format_char, 0);
+ if (byte_size != ULONG_MAX)
+ *byte_size_ptr = byte_size;
+ s = format_char;
+ }
+ else
+ *byte_size_ptr = 0;
+ }
+
+ const bool partial_match_ok = true;
+ if (!FormatManager::GetFormatFromCString (s, partial_match_ok, format))
+ {
+ StreamString error_strm;
+ error_strm.Printf ("Invalid format character or name '%s'. Valid values are:\n", s);
+ for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
+ {
+ char format_char = FormatManager::GetFormatAsFormatChar(f);
+ if (format_char)
+ error_strm.Printf ("'%c' or ", format_char);
+
+ error_strm.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
+ error_strm.EOL();
+ }
+
+ if (byte_size_ptr)
+ error_strm.PutCString ("An optional byte size can precede the format character.\n");
+ error.SetErrorString(error_strm.GetString().c_str());
+ }
+
+ if (error.Fail())
+ return error;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("%s option string", s ? "empty" : "invalid");
+ }
+ return error;
+}
+
+lldb::Encoding
+Args::StringToEncoding (const char *s, lldb::Encoding fail_value)
+{
+ if (s && s[0])
+ {
+ if (strcmp(s, "uint") == 0)
+ return eEncodingUint;
+ else if (strcmp(s, "sint") == 0)
+ return eEncodingSint;
+ else if (strcmp(s, "ieee754") == 0)
+ return eEncodingIEEE754;
+ else if (strcmp(s, "vector") == 0)
+ return eEncodingVector;
+ }
+ return fail_value;
+}
+
+uint32_t
+Args::StringToGenericRegister (const char *s)
+{
+ if (s && s[0])
+ {
+ if (strcmp(s, "pc") == 0)
+ return LLDB_REGNUM_GENERIC_PC;
+ else if (strcmp(s, "sp") == 0)
+ return LLDB_REGNUM_GENERIC_SP;
+ else if (strcmp(s, "fp") == 0)
+ return LLDB_REGNUM_GENERIC_FP;
+ else if (strcmp(s, "ra") == 0)
+ return LLDB_REGNUM_GENERIC_RA;
+ else if (strcmp(s, "flags") == 0)
+ return LLDB_REGNUM_GENERIC_FLAGS;
+ else if (strncmp(s, "arg", 3) == 0)
+ {
+ if (s[3] && s[4] == '\0')
+ {
+ switch (s[3])
+ {
+ case '1': return LLDB_REGNUM_GENERIC_ARG1;
+ case '2': return LLDB_REGNUM_GENERIC_ARG2;
+ case '3': return LLDB_REGNUM_GENERIC_ARG3;
+ case '4': return LLDB_REGNUM_GENERIC_ARG4;
+ case '5': return LLDB_REGNUM_GENERIC_ARG5;
+ case '6': return LLDB_REGNUM_GENERIC_ARG6;
+ case '7': return LLDB_REGNUM_GENERIC_ARG7;
+ case '8': return LLDB_REGNUM_GENERIC_ARG8;
+ }
+ }
+ }
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+void
+Args::LongestCommonPrefix (std::string &common_prefix)
+{
+ arg_sstr_collection::iterator pos, end = m_args.end();
+ pos = m_args.begin();
+ if (pos == end)
+ common_prefix.clear();
+ else
+ common_prefix = (*pos);
+
+ for (++pos; pos != end; ++pos)
+ {
+ size_t new_size = (*pos).size();
+
+ // First trim common_prefix if it is longer than the current element:
+ if (common_prefix.size() > new_size)
+ common_prefix.erase (new_size);
+
+ // Then trim it at the first disparity:
+
+ for (size_t i = 0; i < common_prefix.size(); i++)
+ {
+ if ((*pos)[i] != common_prefix[i])
+ {
+ common_prefix.erase(i);
+ break;
+ }
+ }
+
+ // If we've emptied the common prefix, we're done.
+ if (common_prefix.empty())
+ break;
+ }
+}
+
+size_t
+Args::FindArgumentIndexForOption (struct option *long_options, int long_options_index)
+{
+ char short_buffer[3];
+ char long_buffer[255];
+ ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val);
+ ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].name);
+ size_t end = GetArgumentCount ();
+ size_t idx = 0;
+ while (idx < end)
+ {
+ if ((::strncmp (GetArgumentAtIndex (idx), short_buffer, strlen (short_buffer)) == 0)
+ || (::strncmp (GetArgumentAtIndex (idx), long_buffer, strlen (long_buffer)) == 0))
+ {
+ return idx;
+ }
+ ++idx;
+ }
+
+ return end;
+}
+
+bool
+Args::IsPositionalArgument (const char *arg)
+{
+ if (arg == NULL)
+ return false;
+
+ bool is_positional = true;
+ char *cptr = (char *) arg;
+
+ if (cptr[0] == '%')
+ {
+ ++cptr;
+ while (isdigit (cptr[0]))
+ ++cptr;
+ if (cptr[0] != '\0')
+ is_positional = false;
+ }
+ else
+ is_positional = false;
+
+ return is_positional;
+}
+
+void
+Args::ParseAliasOptions (Options &options,
+ CommandReturnObject &result,
+ OptionArgVector *option_arg_vector,
+ std::string &raw_input_string)
+{
+ StreamString sstr;
+ int i;
+ struct option *long_options = options.GetLongOptions();
+
+ if (long_options == NULL)
+ {
+ result.AppendError ("invalid long options");
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+
+ for (i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ sstr << (char) long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ sstr << ":";
+ break;
+ case optional_argument:
+ sstr << "::";
+ break;
+ }
+ }
+ }
+
+#ifdef __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long_only (GetArgumentCount(),
+ GetArgumentVector(),
+ sstr.GetData(),
+ long_options,
+ &long_options_index);
+
+ if (val == -1)
+ break;
+
+ if (val == '?')
+ {
+ result.AppendError ("unknown or ambiguous option");
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+
+ if (val == 0)
+ continue;
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Look up the long option index
+ if (long_options_index == -1)
+ {
+ for (int j = 0;
+ long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ ++j)
+ {
+ if (long_options[j].val == val)
+ {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index >= 0)
+ {
+ StreamString option_str;
+ option_str.Printf ("-%c", val);
+
+ switch (long_options[long_options_index].has_arg)
+ {
+ case no_argument:
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ OptionArgValue (no_argument, "<no-argument>")));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ OptionArgValue (required_argument,
+ std::string (optarg))));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Option '%s' is missing argument specifier.\n",
+ option_str.GetData());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ break;
+ case optional_argument:
+ if (optarg != NULL)
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ OptionArgValue (optional_argument,
+ std::string (optarg))));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()),
+ OptionArgValue (optional_argument, "<no-argument>")));
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ break;
+ default:
+ result.AppendErrorWithFormat ("error with options table; invalid value in has_arg field for option '%c'.\n", val);
+ result.SetStatus (eReturnStatusFailed);
+ break;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Invalid option with value '%c'.\n", val);
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ if (long_options_index >= 0)
+ {
+ // Find option in the argument list; also see if it was supposed to take an argument and if one was
+ // supplied. Remove option (and argument, if given) from the argument list. Also remove them from
+ // the raw_input_string, if one was passed in.
+ size_t idx = FindArgumentIndexForOption (long_options, long_options_index);
+ if (idx < GetArgumentCount())
+ {
+ if (raw_input_string.size() > 0)
+ {
+ const char *tmp_arg = GetArgumentAtIndex (idx);
+ size_t pos = raw_input_string.find (tmp_arg);
+ if (pos != std::string::npos)
+ raw_input_string.erase (pos, strlen (tmp_arg));
+ }
+ ReplaceArgumentAtIndex (idx, "");
+ if ((long_options[long_options_index].has_arg != no_argument)
+ && (optarg != NULL)
+ && (idx+1 < GetArgumentCount())
+ && (strcmp (optarg, GetArgumentAtIndex(idx+1)) == 0))
+ {
+ if (raw_input_string.size() > 0)
+ {
+ const char *tmp_arg = GetArgumentAtIndex (idx+1);
+ size_t pos = raw_input_string.find (tmp_arg);
+ if (pos != std::string::npos)
+ raw_input_string.erase (pos, strlen (tmp_arg));
+ }
+ ReplaceArgumentAtIndex (idx+1, "");
+ }
+ }
+ }
+
+ if (!result.Succeeded())
+ break;
+ }
+}
+
+void
+Args::ParseArgsForCompletion
+(
+ Options &options,
+ OptionElementVector &option_element_vector,
+ uint32_t cursor_index
+)
+{
+ StreamString sstr;
+ struct option *long_options = options.GetLongOptions();
+ option_element_vector.clear();
+
+ if (long_options == NULL)
+ {
+ return;
+ }
+
+ // Leading : tells getopt to return a : for a missing option argument AND
+ // to suppress error messages.
+
+ sstr << ":";
+ for (int i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ sstr << (char) long_options[i].val;
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ sstr << ":";
+ break;
+ case optional_argument:
+ sstr << "::";
+ break;
+ }
+ }
+ }
+
+#ifdef __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+ opterr = 0;
+
+ int val;
+ const OptionDefinition *opt_defs = options.GetDefinitions();
+
+ // Fooey... getopt_long_only permutes the GetArgumentVector to move the options to the front.
+ // So we have to build another Arg and pass that to getopt_long_only so it doesn't
+ // change the one we have.
+
+ std::vector<const char *> dummy_vec (GetArgumentVector(), GetArgumentVector() + GetArgumentCount() + 1);
+
+ bool failed_once = false;
+ uint32_t dash_dash_pos = -1;
+
+ while (1)
+ {
+ bool missing_argument = false;
+ int long_options_index = -1;
+
+ val = ::getopt_long_only (dummy_vec.size() - 1,
+ (char *const *) &dummy_vec.front(),
+ sstr.GetData(),
+ long_options,
+ &long_options_index);
+
+ if (val == -1)
+ {
+ // When we're completing a "--" which is the last option on line,
+ if (failed_once)
+ break;
+
+ failed_once = true;
+
+ // If this is a bare "--" we mark it as such so we can complete it successfully later.
+ // Handling the "--" is a little tricky, since that may mean end of options or arguments, or the
+ // user might want to complete options by long name. I make this work by checking whether the
+ // cursor is in the "--" argument, and if so I assume we're completing the long option, otherwise
+ // I let it pass to getopt_long_only which will terminate the option parsing.
+ // Note, in either case we continue parsing the line so we can figure out what other options
+ // were passed. This will be useful when we come to restricting completions based on what other
+ // options we've seen on the line.
+
+ if (optind < dummy_vec.size() - 1
+ && (strcmp (dummy_vec[optind-1], "--") == 0))
+ {
+ dash_dash_pos = optind - 1;
+ if (optind - 1 == cursor_index)
+ {
+ option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDoubleDash, optind - 1,
+ OptionArgElement::eBareDoubleDash));
+ continue;
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ else if (val == '?')
+ {
+ option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1,
+ OptionArgElement::eUnrecognizedArg));
+ continue;
+ }
+ else if (val == 0)
+ {
+ continue;
+ }
+ else if (val == ':')
+ {
+ // This is a missing argument.
+ val = optopt;
+ missing_argument = true;
+ }
+
+ ((Options *) &options)->OptionSeen (val);
+
+ // Look up the long option index
+ if (long_options_index == -1)
+ {
+ for (int j = 0;
+ long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val;
+ ++j)
+ {
+ if (long_options[j].val == val)
+ {
+ long_options_index = j;
+ break;
+ }
+ }
+ }
+
+ // See if the option takes an argument, and see if one was supplied.
+ if (long_options_index >= 0)
+ {
+ int opt_defs_index = -1;
+ for (int i = 0; ; i++)
+ {
+ if (opt_defs[i].short_option == 0)
+ break;
+ else if (opt_defs[i].short_option == val)
+ {
+ opt_defs_index = i;
+ break;
+ }
+ }
+
+ switch (long_options[long_options_index].has_arg)
+ {
+ case no_argument:
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, 0));
+ break;
+ case required_argument:
+ if (optarg != NULL)
+ {
+ int arg_index;
+ if (missing_argument)
+ arg_index = -1;
+ else
+ arg_index = optind - 1;
+
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, arg_index));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 1, -1));
+ }
+ break;
+ case optional_argument:
+ if (optarg != NULL)
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1));
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (opt_defs_index, optind - 2, optind - 1));
+ }
+ break;
+ default:
+ // The options table is messed up. Here we'll just continue
+ option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1,
+ OptionArgElement::eUnrecognizedArg));
+ break;
+ }
+ }
+ else
+ {
+ option_element_vector.push_back (OptionArgElement (OptionArgElement::eUnrecognizedArg, optind - 1,
+ OptionArgElement::eUnrecognizedArg));
+ }
+ }
+
+ // Finally we have to handle the case where the cursor index points at a single "-". We want to mark that in
+ // the option_element_vector, but only if it is not after the "--". But it turns out that getopt_long_only just ignores
+ // an isolated "-". So we have to look it up by hand here. We only care if it is AT the cursor position.
+
+ if ((dash_dash_pos == -1 || cursor_index < dash_dash_pos)
+ && strcmp (GetArgumentAtIndex(cursor_index), "-") == 0)
+ {
+ option_element_vector.push_back (OptionArgElement (OptionArgElement::eBareDash, cursor_index,
+ OptionArgElement::eBareDash));
+
+ }
+}
+
+void
+Args::EncodeEscapeSequences (const char *src, std::string &dst)
+{
+ dst.clear();
+ if (src)
+ {
+ for (const char *p = src; *p != '\0'; ++p)
+ {
+ size_t non_special_chars = ::strcspn (p, "\\");
+ if (non_special_chars > 0)
+ {
+ dst.append(p, non_special_chars);
+ p += non_special_chars;
+ if (*p == '\0')
+ break;
+ }
+
+ if (*p == '\\')
+ {
+ ++p; // skip the slash
+ switch (*p)
+ {
+ case 'a' : dst.append(1, '\a'); break;
+ case 'b' : dst.append(1, '\b'); break;
+ case 'f' : dst.append(1, '\f'); break;
+ case 'n' : dst.append(1, '\n'); break;
+ case 'r' : dst.append(1, '\r'); break;
+ case 't' : dst.append(1, '\t'); break;
+ case 'v' : dst.append(1, '\v'); break;
+ case '\\': dst.append(1, '\\'); break;
+ case '\'': dst.append(1, '\''); break;
+ case '"' : dst.append(1, '"'); break;
+ case '0' :
+ // 1 to 3 octal chars
+ {
+ // Make a string that can hold onto the initial zero char,
+ // up to 3 octal digits, and a terminating NULL.
+ char oct_str[5] = { '\0', '\0', '\0', '\0', '\0' };
+
+ int i;
+ for (i=0; (p[i] >= '0' && p[i] <= '7') && i<4; ++i)
+ oct_str[i] = p[i];
+
+ // We don't want to consume the last octal character since
+ // the main for loop will do this for us, so we advance p by
+ // one less than i (even if i is zero)
+ p += i - 1;
+ unsigned long octal_value = ::strtoul (oct_str, NULL, 8);
+ if (octal_value <= UINT8_MAX)
+ {
+ dst.append(1, (char)octal_value);
+ }
+ }
+ break;
+
+ case 'x':
+ // hex number in the format
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the 'x'
+
+ // Make a string that can hold onto two hex chars plus a
+ // NULL terminator
+ char hex_str[3] = { *p, '\0', '\0' };
+ if (isxdigit(p[1]))
+ {
+ ++p; // Skip the first of the two hex chars
+ hex_str[1] = *p;
+ }
+
+ unsigned long hex_value = strtoul (hex_str, NULL, 16);
+ if (hex_value <= UINT8_MAX)
+ dst.append (1, (char)hex_value);
+ }
+ else
+ {
+ dst.append(1, 'x');
+ }
+ break;
+
+ default:
+ // Just desensitize any other character by just printing what
+ // came after the '\'
+ dst.append(1, *p);
+ break;
+
+ }
+ }
+ }
+ }
+}
+
+
+void
+Args::ExpandEscapedCharacters (const char *src, std::string &dst)
+{
+ dst.clear();
+ if (src)
+ {
+ for (const char *p = src; *p != '\0'; ++p)
+ {
+ if (isprint8(*p))
+ dst.append(1, *p);
+ else
+ {
+ switch (*p)
+ {
+ case '\a': dst.append("\\a"); break;
+ case '\b': dst.append("\\b"); break;
+ case '\f': dst.append("\\f"); break;
+ case '\n': dst.append("\\n"); break;
+ case '\r': dst.append("\\r"); break;
+ case '\t': dst.append("\\t"); break;
+ case '\v': dst.append("\\v"); break;
+ case '\'': dst.append("\\'"); break;
+ case '"': dst.append("\\\""); break;
+ case '\\': dst.append("\\\\"); break;
+ default:
+ {
+ // Just encode as octal
+ dst.append("\\0");
+ char octal_str[32];
+ snprintf(octal_str, sizeof(octal_str), "%o", *p);
+ dst.append(octal_str);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
+
diff --git a/source/Interpreter/CommandHistory.cpp b/source/Interpreter/CommandHistory.cpp
new file mode 100644
index 000000000000..33971e3959c6
--- /dev/null
+++ b/source/Interpreter/CommandHistory.cpp
@@ -0,0 +1,143 @@
+//===-- CommandHistory.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/CommandHistory.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+CommandHistory::CommandHistory () :
+ m_mutex(Mutex::eMutexTypeRecursive),
+ m_history()
+{}
+
+CommandHistory::~CommandHistory ()
+{}
+
+size_t
+CommandHistory::GetSize () const
+{
+ Mutex::Locker locker(m_mutex);
+ return m_history.size();
+}
+
+bool
+CommandHistory::IsEmpty () const
+{
+ Mutex::Locker locker(m_mutex);
+ return m_history.empty();
+}
+
+const char*
+CommandHistory::FindString (const char* input_str) const
+{
+ Mutex::Locker locker(m_mutex);
+ if (!input_str)
+ return NULL;
+ if (input_str[0] != g_repeat_char)
+ return NULL;
+ if (input_str[1] == '-')
+ {
+ bool success;
+ size_t idx = Args::StringToUInt32 (input_str+2, 0, 0, &success);
+ if (!success)
+ return NULL;
+ if (idx > m_history.size())
+ return NULL;
+ idx = m_history.size() - idx;
+ return m_history[idx].c_str();
+
+ }
+ else if (input_str[1] == g_repeat_char)
+ {
+ if (m_history.empty())
+ return NULL;
+ else
+ return m_history.back().c_str();
+ }
+ else
+ {
+ bool success;
+ uint32_t idx = Args::StringToUInt32 (input_str+1, 0, 0, &success);
+ if (!success)
+ return NULL;
+ if (idx >= m_history.size())
+ return NULL;
+ return m_history[idx].c_str();
+ }
+}
+
+const char*
+CommandHistory::GetStringAtIndex (size_t idx) const
+{
+ Mutex::Locker locker(m_mutex);
+ if (idx < m_history.size())
+ return m_history[idx].c_str();
+ return NULL;
+}
+
+const char*
+CommandHistory::operator [] (size_t idx) const
+{
+ return GetStringAtIndex(idx);
+}
+
+const char*
+CommandHistory::GetRecentmostString () const
+{
+ Mutex::Locker locker(m_mutex);
+ if (m_history.empty())
+ return NULL;
+ return m_history.back().c_str();
+}
+
+void
+CommandHistory::AppendString (const std::string& str,
+ bool reject_if_dupe)
+{
+ Mutex::Locker locker(m_mutex);
+ if (reject_if_dupe)
+ {
+ if (!m_history.empty())
+ {
+ if (str == m_history.back())
+ return;
+ }
+ }
+ m_history.push_back(std::string(str));
+}
+
+void
+CommandHistory::Clear ()
+{
+ Mutex::Locker locker(m_mutex);
+ m_history.clear();
+}
+
+void
+CommandHistory::Dump (Stream& stream,
+ size_t start_idx,
+ size_t stop_idx) const
+{
+ Mutex::Locker locker(m_mutex);
+ stop_idx = std::min(stop_idx, m_history.size() - 1);
+ for (size_t counter = start_idx;
+ counter <= stop_idx;
+ counter++)
+ {
+ const std::string hist_item = m_history[counter];
+ if (!hist_item.empty())
+ {
+ stream.Indent();
+ stream.Printf ("%4zu: %s\n", counter, hist_item.c_str());
+ }
+ }
+}
diff --git a/source/Interpreter/CommandInterpreter.cpp b/source/Interpreter/CommandInterpreter.cpp
new file mode 100644
index 000000000000..db2f2fafbef1
--- /dev/null
+++ b/source/Interpreter/CommandInterpreter.cpp
@@ -0,0 +1,2882 @@
+//===-- CommandInterpreter.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 <string>
+#include <vector>
+
+#include <getopt.h>
+#include <stdlib.h>
+
+#include "CommandObjectScript.h"
+#include "lldb/Interpreter/CommandObjectRegexCommand.h"
+
+#include "../Commands/CommandObjectApropos.h"
+#include "../Commands/CommandObjectArgs.h"
+#include "../Commands/CommandObjectBreakpoint.h"
+#include "../Commands/CommandObjectDisassemble.h"
+#include "../Commands/CommandObjectExpression.h"
+#include "../Commands/CommandObjectFrame.h"
+#include "../Commands/CommandObjectHelp.h"
+#include "../Commands/CommandObjectLog.h"
+#include "../Commands/CommandObjectMemory.h"
+#include "../Commands/CommandObjectPlatform.h"
+#include "../Commands/CommandObjectPlugin.h"
+#include "../Commands/CommandObjectProcess.h"
+#include "../Commands/CommandObjectQuit.h"
+#include "../Commands/CommandObjectRegister.h"
+#include "../Commands/CommandObjectSettings.h"
+#include "../Commands/CommandObjectSource.h"
+#include "../Commands/CommandObjectCommands.h"
+#include "../Commands/CommandObjectSyntax.h"
+#include "../Commands/CommandObjectTarget.h"
+#include "../Commands/CommandObjectThread.h"
+#include "../Commands/CommandObjectType.h"
+#include "../Commands/CommandObjectVersion.h"
+#include "../Commands/CommandObjectWatchpoint.h"
+
+
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/Options.h"
+#include "lldb/Interpreter/ScriptInterpreterNone.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/TargetList.h"
+
+#include "lldb/Utility/CleanUp.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static PropertyDefinition
+g_properties[] =
+{
+ { "expand-regex-aliases", OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, regular expression alias commands will show the expanded command that will be executed. This can be used to debug new regular expression alias commands." },
+ { "prompt-on-quit", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will prompt you before quitting if there are any live processes being debugged. If false, LLDB will quit without asking in any case." },
+ { "stop-command-source-on-error", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, LLDB will stop running a 'command source' script upon encountering an error." },
+ { NULL , OptionValue::eTypeInvalid, true, 0 , NULL, NULL, NULL }
+};
+
+enum
+{
+ ePropertyExpandRegexAliases = 0,
+ ePropertyPromptOnQuit = 1,
+ ePropertyStopCmdSourceOnError = 2
+};
+
+ConstString &
+CommandInterpreter::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.commandInterpreter");
+ return class_name;
+}
+
+CommandInterpreter::CommandInterpreter
+(
+ Debugger &debugger,
+ ScriptLanguage script_language,
+ bool synchronous_execution
+) :
+ Broadcaster (&debugger, "lldb.command-interpreter"),
+ Properties(OptionValuePropertiesSP(new OptionValueProperties(ConstString("interpreter")))),
+ m_debugger (debugger),
+ m_synchronous_execution (synchronous_execution),
+ m_skip_lldbinit_files (false),
+ m_skip_app_init_files (false),
+ m_script_interpreter_ap (),
+ m_comment_char ('#'),
+ m_batch_command_mode (false),
+ m_truncation_warning(eNoTruncation),
+ m_command_source_depth (0)
+{
+ debugger.SetScriptLanguage (script_language);
+ SetEventName (eBroadcastBitThreadShouldExit, "thread-should-exit");
+ SetEventName (eBroadcastBitResetPrompt, "reset-prompt");
+ SetEventName (eBroadcastBitQuitCommandReceived, "quit");
+ CheckInWithManager ();
+ m_collection_sp->Initialize (g_properties);
+}
+
+bool
+CommandInterpreter::GetExpandRegexAliases () const
+{
+ const uint32_t idx = ePropertyExpandRegexAliases;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+CommandInterpreter::GetPromptOnQuit () const
+{
+ const uint32_t idx = ePropertyPromptOnQuit;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+CommandInterpreter::GetStopCmdSourceOnError () const
+{
+ const uint32_t idx = ePropertyStopCmdSourceOnError;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+CommandInterpreter::Initialize ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ CommandReturnObject result;
+
+ LoadCommandDictionary ();
+
+ // Set up some initial aliases.
+ CommandObjectSP cmd_obj_sp = GetCommandSPExact ("quit", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("q", cmd_obj_sp);
+ AddAlias ("exit", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-attach",false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("attach", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("process detach",false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("detach", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("process continue", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("c", cmd_obj_sp);
+ AddAlias ("continue", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-break",false);
+ if (cmd_obj_sp)
+ AddAlias ("b", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-tbreak",false);
+ if (cmd_obj_sp)
+ AddAlias ("tbreak", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("thread step-inst", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("stepi", cmd_obj_sp);
+ AddAlias ("si", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("thread step-inst-over", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("nexti", cmd_obj_sp);
+ AddAlias ("ni", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("thread step-in", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("s", cmd_obj_sp);
+ AddAlias ("step", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("thread step-over", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("n", cmd_obj_sp);
+ AddAlias ("next", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("thread step-out", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("finish", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("frame select", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("f", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("thread select", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("t", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-list", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("l", cmd_obj_sp);
+ AddAlias ("list", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-env", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("env", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("memory read", false);
+ if (cmd_obj_sp)
+ AddAlias ("x", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-up", false);
+ if (cmd_obj_sp)
+ AddAlias ("up", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-down", false);
+ if (cmd_obj_sp)
+ AddAlias ("down", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-display", false);
+ if (cmd_obj_sp)
+ AddAlias ("display", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("disassemble", false);
+ if (cmd_obj_sp)
+ AddAlias ("dis", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("disassemble", false);
+ if (cmd_obj_sp)
+ AddAlias ("di", cmd_obj_sp);
+
+
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-undisplay", false);
+ if (cmd_obj_sp)
+ AddAlias ("undisplay", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("_regexp-bt", false);
+ if (cmd_obj_sp)
+ AddAlias ("bt", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("target create", false);
+ if (cmd_obj_sp)
+ AddAlias ("file", cmd_obj_sp);
+
+ cmd_obj_sp = GetCommandSPExact ("target modules", false);
+ if (cmd_obj_sp)
+ AddAlias ("image", cmd_obj_sp);
+
+
+ OptionArgVectorSP alias_arguments_vector_sp (new OptionArgVector);
+
+ cmd_obj_sp = GetCommandSPExact ("expression", false);
+ if (cmd_obj_sp)
+ {
+ ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp);
+ AddAlias ("p", cmd_obj_sp);
+ AddAlias ("print", cmd_obj_sp);
+ AddAlias ("call", cmd_obj_sp);
+ AddOrReplaceAliasOptions ("p", alias_arguments_vector_sp);
+ AddOrReplaceAliasOptions ("print", alias_arguments_vector_sp);
+ AddOrReplaceAliasOptions ("call", alias_arguments_vector_sp);
+
+ alias_arguments_vector_sp.reset (new OptionArgVector);
+ ProcessAliasOptionsArgs (cmd_obj_sp, "-O -- ", alias_arguments_vector_sp);
+ AddAlias ("po", cmd_obj_sp);
+ AddOrReplaceAliasOptions ("po", alias_arguments_vector_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("process kill", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("kill", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("process launch", false);
+ if (cmd_obj_sp)
+ {
+ alias_arguments_vector_sp.reset (new OptionArgVector);
+#if defined (__arm__)
+ ProcessAliasOptionsArgs (cmd_obj_sp, "--", alias_arguments_vector_sp);
+#else
+ ProcessAliasOptionsArgs (cmd_obj_sp, "--shell=/bin/bash --", alias_arguments_vector_sp);
+#endif
+ AddAlias ("r", cmd_obj_sp);
+ AddAlias ("run", cmd_obj_sp);
+ AddOrReplaceAliasOptions ("r", alias_arguments_vector_sp);
+ AddOrReplaceAliasOptions ("run", alias_arguments_vector_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("target symbols add", false);
+ if (cmd_obj_sp)
+ {
+ AddAlias ("add-dsym", cmd_obj_sp);
+ }
+
+ cmd_obj_sp = GetCommandSPExact ("breakpoint set", false);
+ if (cmd_obj_sp)
+ {
+ alias_arguments_vector_sp.reset (new OptionArgVector);
+ ProcessAliasOptionsArgs (cmd_obj_sp, "--func-regex %1", alias_arguments_vector_sp);
+ AddAlias ("rbreak", cmd_obj_sp);
+ AddOrReplaceAliasOptions("rbreak", alias_arguments_vector_sp);
+ }
+}
+
+const char *
+CommandInterpreter::ProcessEmbeddedScriptCommands (const char *arg)
+{
+ // This function has not yet been implemented.
+
+ // Look for any embedded script command
+ // If found,
+ // get interpreter object from the command dictionary,
+ // call execute_one_command on it,
+ // get the results as a string,
+ // substitute that string for current stuff.
+
+ return arg;
+}
+
+
+void
+CommandInterpreter::LoadCommandDictionary ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ lldb::ScriptLanguage script_language = m_debugger.GetScriptLanguage();
+
+ m_command_dict["apropos"] = CommandObjectSP (new CommandObjectApropos (*this));
+ m_command_dict["breakpoint"]= CommandObjectSP (new CommandObjectMultiwordBreakpoint (*this));
+ m_command_dict["command"] = CommandObjectSP (new CommandObjectMultiwordCommands (*this));
+ m_command_dict["disassemble"] = CommandObjectSP (new CommandObjectDisassemble (*this));
+ m_command_dict["expression"]= CommandObjectSP (new CommandObjectExpression (*this));
+ m_command_dict["frame"] = CommandObjectSP (new CommandObjectMultiwordFrame (*this));
+ m_command_dict["help"] = CommandObjectSP (new CommandObjectHelp (*this));
+ m_command_dict["log"] = CommandObjectSP (new CommandObjectLog (*this));
+ m_command_dict["memory"] = CommandObjectSP (new CommandObjectMemory (*this));
+ m_command_dict["platform"] = CommandObjectSP (new CommandObjectPlatform (*this));
+ m_command_dict["plugin"] = CommandObjectSP (new CommandObjectPlugin (*this));
+ m_command_dict["process"] = CommandObjectSP (new CommandObjectMultiwordProcess (*this));
+ m_command_dict["quit"] = CommandObjectSP (new CommandObjectQuit (*this));
+ m_command_dict["register"] = CommandObjectSP (new CommandObjectRegister (*this));
+ m_command_dict["script"] = CommandObjectSP (new CommandObjectScript (*this, script_language));
+ m_command_dict["settings"] = CommandObjectSP (new CommandObjectMultiwordSettings (*this));
+ m_command_dict["source"] = CommandObjectSP (new CommandObjectMultiwordSource (*this));
+ m_command_dict["target"] = CommandObjectSP (new CommandObjectMultiwordTarget (*this));
+ m_command_dict["thread"] = CommandObjectSP (new CommandObjectMultiwordThread (*this));
+ m_command_dict["type"] = CommandObjectSP (new CommandObjectType (*this));
+ m_command_dict["version"] = CommandObjectSP (new CommandObjectVersion (*this));
+ m_command_dict["watchpoint"]= CommandObjectSP (new CommandObjectMultiwordWatchpoint (*this));
+
+ const char *break_regexes[][2] = {{"^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "breakpoint set --file '%1' --line %2"},
+ {"^([[:digit:]]+)[[:space:]]*$", "breakpoint set --line %1"},
+ {"^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "breakpoint set --address %1"},
+ {"^[\"']?([-+]?\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'"},
+ {"^(-.*)$", "breakpoint set %1"},
+ {"^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'"},
+ {"^\\&(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1' --skip-prologue=0"},
+ {"^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'"}};
+
+ size_t num_regexes = sizeof break_regexes/sizeof(char *[2]);
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ break_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-break",
+ "Set a breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.",
+ "_regexp-break [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>",
+ 2,
+ CommandCompletions::eSymbolCompletion |
+ CommandCompletions::eSourceFileCompletion));
+
+ if (break_regex_cmd_ap.get())
+ {
+ bool success = true;
+ for (size_t i = 0; i < num_regexes; i++)
+ {
+ success = break_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], break_regexes[i][1]);
+ if (!success)
+ break;
+ }
+ success = break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full");
+
+ if (success)
+ {
+ CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release());
+ m_command_dict[break_regex_cmd_sp->GetCommandName ()] = break_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ tbreak_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-tbreak",
+ "Set a one shot breakpoint using a regular expression to specify the location, where <linenum> is in decimal and <address> is in hex.",
+ "_regexp-tbreak [<filename>:<linenum>]\n_regexp-break [<linenum>]\n_regexp-break [<address>]\n_regexp-break <...>",
+ 2,
+ CommandCompletions::eSymbolCompletion |
+ CommandCompletions::eSourceFileCompletion));
+
+ if (tbreak_regex_cmd_ap.get())
+ {
+ bool success = true;
+ for (size_t i = 0; i < num_regexes; i++)
+ {
+ // If you add a resultant command string longer than 1024 characters be sure to increase the size of this buffer.
+ char buffer[1024];
+ int num_printed = snprintf(buffer, 1024, "%s %s", break_regexes[i][1], "-o");
+ assert (num_printed < 1024);
+ success = tbreak_regex_cmd_ap->AddRegexCommand (break_regexes[i][0], buffer);
+ if (!success)
+ break;
+ }
+ success = tbreak_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list --full");
+
+ if (success)
+ {
+ CommandObjectSP tbreak_regex_cmd_sp(tbreak_regex_cmd_ap.release());
+ m_command_dict[tbreak_regex_cmd_sp->GetCommandName ()] = tbreak_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ attach_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_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));
+ if (attach_regex_cmd_ap.get())
+ {
+ if (attach_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "process attach --pid %1") &&
+ attach_regex_cmd_ap->AddRegexCommand("^(-.*|.* -.*)$", "process attach %1") && // Any options that are specified get passed to 'process attach'
+ attach_regex_cmd_ap->AddRegexCommand("^(.+)$", "process attach --name '%1'") &&
+ attach_regex_cmd_ap->AddRegexCommand("^$", "process attach"))
+ {
+ CommandObjectSP attach_regex_cmd_sp(attach_regex_cmd_ap.release());
+ m_command_dict[attach_regex_cmd_sp->GetCommandName ()] = attach_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ down_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-down",
+ "Go down \"n\" frames in the stack (1 frame by default).",
+ "_regexp-down [n]", 2));
+ if (down_regex_cmd_ap.get())
+ {
+ if (down_regex_cmd_ap->AddRegexCommand("^$", "frame select -r -1") &&
+ down_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "frame select -r -%1"))
+ {
+ CommandObjectSP down_regex_cmd_sp(down_regex_cmd_ap.release());
+ m_command_dict[down_regex_cmd_sp->GetCommandName ()] = down_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ up_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-up",
+ "Go up \"n\" frames in the stack (1 frame by default).",
+ "_regexp-up [n]", 2));
+ if (up_regex_cmd_ap.get())
+ {
+ if (up_regex_cmd_ap->AddRegexCommand("^$", "frame select -r 1") &&
+ up_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "frame select -r %1"))
+ {
+ CommandObjectSP up_regex_cmd_sp(up_regex_cmd_ap.release());
+ m_command_dict[up_regex_cmd_sp->GetCommandName ()] = up_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ display_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-display",
+ "Add an expression evaluation stop-hook.",
+ "_regexp-display expression", 2));
+ if (display_regex_cmd_ap.get())
+ {
+ if (display_regex_cmd_ap->AddRegexCommand("^(.+)$", "target stop-hook add -o \"expr -- %1\""))
+ {
+ CommandObjectSP display_regex_cmd_sp(display_regex_cmd_ap.release());
+ m_command_dict[display_regex_cmd_sp->GetCommandName ()] = display_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ undisplay_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-undisplay",
+ "Remove an expression evaluation stop-hook.",
+ "_regexp-undisplay stop-hook-number", 2));
+ if (undisplay_regex_cmd_ap.get())
+ {
+ if (undisplay_regex_cmd_ap->AddRegexCommand("^([0-9]+)$", "target stop-hook delete %1"))
+ {
+ CommandObjectSP undisplay_regex_cmd_sp(undisplay_regex_cmd_ap.release());
+ m_command_dict[undisplay_regex_cmd_sp->GetCommandName ()] = undisplay_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ 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));
+ if (connect_gdb_remote_cmd_ap.get())
+ {
+ if (connect_gdb_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin gdb-remote connect://%1") &&
+ connect_gdb_remote_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", "process connect --plugin gdb-remote connect://localhost:%1"))
+ {
+ CommandObjectSP command_sp(connect_gdb_remote_cmd_ap.release());
+ m_command_dict[command_sp->GetCommandName ()] = command_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ 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));
+ if (connect_kdp_remote_cmd_ap.get())
+ {
+ if (connect_kdp_remote_cmd_ap->AddRegexCommand("^([^:]+:[[:digit:]]+)$", "process connect --plugin kdp-remote udp://%1") &&
+ connect_kdp_remote_cmd_ap->AddRegexCommand("^(.+)$", "process connect --plugin kdp-remote udp://%1:41139"))
+ {
+ CommandObjectSP command_sp(connect_kdp_remote_cmd_ap.release());
+ m_command_dict[command_sp->GetCommandName ()] = command_sp;
+ }
+ }
+
+ 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));
+ 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
+ // three frames you would do "bt -c 3" but the intention is to have this emulate the gdb "bt" command and
+ // so now "bt 3" is the preferred form, in line with gdb.
+ if (bt_regex_cmd_ap->AddRegexCommand("^([[:digit:]]+)$", "thread backtrace -c %1") &&
+ bt_regex_cmd_ap->AddRegexCommand("^-c ([[:digit:]]+)$", "thread backtrace -c %1") &&
+ bt_regex_cmd_ap->AddRegexCommand("^all$", "thread backtrace all") &&
+ bt_regex_cmd_ap->AddRegexCommand("^$", "thread backtrace"))
+ {
+ CommandObjectSP command_sp(bt_regex_cmd_ap.release());
+ m_command_dict[command_sp->GetCommandName ()] = command_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ list_regex_cmd_ap(new CommandObjectRegexCommand (*this,
+ "_regexp-list",
+ "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-attach [<file>:<line>]\n_regexp-attach [<file>:<line>]",
+ 2,
+ CommandCompletions::eSourceFileCompletion));
+ if (list_regex_cmd_ap.get())
+ {
+ if (list_regex_cmd_ap->AddRegexCommand("^([0-9]+)[[:space:]]*$", "source list --line %1") &&
+ list_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*:[[:space:]]*([[:digit:]]+)[[:space:]]*$", "source list --file '%1' --line %2") &&
+ list_regex_cmd_ap->AddRegexCommand("^\\*?(0x[[:xdigit:]]+)[[:space:]]*$", "source list --address %1") &&
+ list_regex_cmd_ap->AddRegexCommand("^-[[:space:]]*$", "source list --reverse") &&
+ list_regex_cmd_ap->AddRegexCommand("^-([[:digit:]]+)[[:space:]]*$", "source list --reverse --count %1") &&
+ list_regex_cmd_ap->AddRegexCommand("^(.+)$", "source list --name \"%1\"") &&
+ list_regex_cmd_ap->AddRegexCommand("^$", "source list"))
+ {
+ CommandObjectSP list_regex_cmd_sp(list_regex_cmd_ap.release());
+ m_command_dict[list_regex_cmd_sp->GetCommandName ()] = list_regex_cmd_sp;
+ }
+ }
+
+ std::unique_ptr<CommandObjectRegexCommand>
+ 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));
+ if (env_regex_cmd_ap.get())
+ {
+ if (env_regex_cmd_ap->AddRegexCommand("^$", "settings show target.env-vars") &&
+ env_regex_cmd_ap->AddRegexCommand("^([A-Za-z_][A-Za-z_0-9]*=.*)$", "settings set target.env-vars %1"))
+ {
+ CommandObjectSP env_regex_cmd_sp(env_regex_cmd_ap.release());
+ m_command_dict[env_regex_cmd_sp->GetCommandName ()] = env_regex_cmd_sp;
+ }
+ }
+
+}
+
+int
+CommandInterpreter::GetCommandNamesMatchingPartialString (const char *cmd_str, bool include_aliases,
+ StringList &matches)
+{
+ CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_str, matches);
+
+ if (include_aliases)
+ {
+ CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_str, matches);
+ }
+
+ return matches.GetSize();
+}
+
+CommandObjectSP
+CommandInterpreter::GetCommandSP (const char *cmd_cstr, bool include_aliases, bool exact, StringList *matches)
+{
+ CommandObject::CommandMap::iterator pos;
+ CommandObjectSP command_sp;
+
+ std::string cmd(cmd_cstr);
+
+ if (HasCommands())
+ {
+ pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (include_aliases && HasAliases())
+ {
+ pos = m_alias_dict.find(cmd);
+ if (pos != m_alias_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (HasUserCommands())
+ {
+ pos = m_user_dict.find(cmd);
+ if (pos != m_user_dict.end())
+ command_sp = pos->second;
+ }
+
+ if (!exact && !command_sp)
+ {
+ // We will only get into here if we didn't find any exact matches.
+
+ CommandObjectSP user_match_sp, alias_match_sp, real_match_sp;
+
+ StringList local_matches;
+ if (matches == NULL)
+ matches = &local_matches;
+
+ unsigned int num_cmd_matches = 0;
+ unsigned int num_alias_matches = 0;
+ unsigned int num_user_matches = 0;
+
+ // Look through the command dictionaries one by one, and if we get only one match from any of
+ // them in toto, then return that, otherwise return an empty CommandObjectSP and the list of matches.
+
+ if (HasCommands())
+ {
+ num_cmd_matches = CommandObject::AddNamesMatchingPartialString (m_command_dict, cmd_cstr, *matches);
+ }
+
+ if (num_cmd_matches == 1)
+ {
+ cmd.assign(matches->GetStringAtIndex(0));
+ pos = m_command_dict.find(cmd);
+ if (pos != m_command_dict.end())
+ real_match_sp = pos->second;
+ }
+
+ if (include_aliases && HasAliases())
+ {
+ num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd_cstr, *matches);
+
+ }
+
+ if (num_alias_matches == 1)
+ {
+ cmd.assign(matches->GetStringAtIndex (num_cmd_matches));
+ pos = m_alias_dict.find(cmd);
+ if (pos != m_alias_dict.end())
+ alias_match_sp = pos->second;
+ }
+
+ if (HasUserCommands())
+ {
+ num_user_matches = CommandObject::AddNamesMatchingPartialString (m_user_dict, cmd_cstr, *matches);
+ }
+
+ if (num_user_matches == 1)
+ {
+ cmd.assign (matches->GetStringAtIndex (num_cmd_matches + num_alias_matches));
+
+ pos = m_user_dict.find (cmd);
+ if (pos != m_user_dict.end())
+ user_match_sp = pos->second;
+ }
+
+ // If we got exactly one match, return that, otherwise return the match list.
+
+ if (num_user_matches + num_cmd_matches + num_alias_matches == 1)
+ {
+ if (num_cmd_matches)
+ return real_match_sp;
+ else if (num_alias_matches)
+ return alias_match_sp;
+ else
+ return user_match_sp;
+ }
+ }
+ else if (matches && command_sp)
+ {
+ matches->AppendString (cmd_cstr);
+ }
+
+
+ return command_sp;
+}
+
+bool
+CommandInterpreter::AddCommand (const char *name, const lldb::CommandObjectSP &cmd_sp, bool can_replace)
+{
+ if (name && name[0])
+ {
+ std::string name_sstr(name);
+ bool found = (m_command_dict.find (name_sstr) != m_command_dict.end());
+ if (found && !can_replace)
+ return false;
+ if (found && m_command_dict[name_sstr]->IsRemovable() == false)
+ return false;
+ m_command_dict[name_sstr] = cmd_sp;
+ return true;
+ }
+ return false;
+}
+
+bool
+CommandInterpreter::AddUserCommand (std::string name,
+ const lldb::CommandObjectSP &cmd_sp,
+ bool can_replace)
+{
+ if (!name.empty())
+ {
+
+ const char* name_cstr = name.c_str();
+
+ // do not allow replacement of internal commands
+ if (CommandExists(name_cstr))
+ {
+ if (can_replace == false)
+ return false;
+ if (m_command_dict[name]->IsRemovable() == false)
+ return false;
+ }
+
+ if (UserCommandExists(name_cstr))
+ {
+ if (can_replace == false)
+ return false;
+ if (m_user_dict[name]->IsRemovable() == false)
+ return false;
+ }
+
+ m_user_dict[name] = cmd_sp;
+ return true;
+ }
+ return false;
+}
+
+CommandObjectSP
+CommandInterpreter::GetCommandSPExact (const char *cmd_cstr, bool include_aliases)
+{
+ Args cmd_words (cmd_cstr); // Break up the command string into words, in case it's a multi-word command.
+ CommandObjectSP ret_val; // Possibly empty return value.
+
+ if (cmd_cstr == NULL)
+ return ret_val;
+
+ if (cmd_words.GetArgumentCount() == 1)
+ return GetCommandSP(cmd_cstr, include_aliases, true, NULL);
+ else
+ {
+ // We have a multi-word command (seemingly), so we need to do more work.
+ // First, get the cmd_obj_sp for the first word in the command.
+ CommandObjectSP cmd_obj_sp = GetCommandSP (cmd_words.GetArgumentAtIndex (0), include_aliases, true, NULL);
+ if (cmd_obj_sp.get() != NULL)
+ {
+ // Loop through the rest of the words in the command (everything passed in was supposed to be part of a
+ // command name), and find the appropriate sub-command SP for each command word....
+ size_t end = cmd_words.GetArgumentCount();
+ for (size_t j= 1; j < end; ++j)
+ {
+ if (cmd_obj_sp->IsMultiwordObject())
+ {
+ cmd_obj_sp = cmd_obj_sp->GetSubcommandSP (cmd_words.GetArgumentAtIndex (j));
+ if (cmd_obj_sp.get() == NULL)
+ // The sub-command name was invalid. Fail and return the empty 'ret_val'.
+ return ret_val;
+ }
+ else
+ // We have more words in the command name, but we don't have a multiword object. Fail and return
+ // empty 'ret_val'.
+ return ret_val;
+ }
+ // We successfully looped through all the command words and got valid command objects for them. Assign the
+ // last object retrieved to 'ret_val'.
+ ret_val = cmd_obj_sp;
+ }
+ }
+ return ret_val;
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObjectExact (const char *cmd_cstr, bool include_aliases)
+{
+ return GetCommandSPExact (cmd_cstr, include_aliases).get();
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObject (const char *cmd_cstr, StringList *matches)
+{
+ CommandObject *command_obj = GetCommandSP (cmd_cstr, false, true, matches).get();
+
+ // If we didn't find an exact match to the command string in the commands, look in
+ // the aliases.
+
+ if (command_obj)
+ return command_obj;
+
+ command_obj = GetCommandSP (cmd_cstr, true, true, matches).get();
+
+ if (command_obj)
+ return command_obj;
+
+ // If there wasn't an exact match then look for an inexact one in just the commands
+ command_obj = GetCommandSP(cmd_cstr, false, false, NULL).get();
+
+ // Finally, if there wasn't an inexact match among the commands, look for an inexact
+ // match in both the commands and aliases.
+
+ if (command_obj)
+ {
+ if (matches)
+ matches->AppendString(command_obj->GetCommandName());
+ return command_obj;
+ }
+
+ return GetCommandSP(cmd_cstr, true, false, matches).get();
+}
+
+bool
+CommandInterpreter::CommandExists (const char *cmd)
+{
+ return m_command_dict.find(cmd) != m_command_dict.end();
+}
+
+bool
+CommandInterpreter::ProcessAliasOptionsArgs (lldb::CommandObjectSP &cmd_obj_sp,
+ const char *options_args,
+ OptionArgVectorSP &option_arg_vector_sp)
+{
+ bool success = true;
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ if (!options_args || (strlen (options_args) < 1))
+ return true;
+
+ std::string options_string (options_args);
+ Args args (options_args);
+ CommandReturnObject result;
+ // Check to see if the command being aliased can take any command options.
+ Options *options = cmd_obj_sp->GetOptions ();
+ if (options)
+ {
+ // See if any options were specified as part of the alias; if so, handle them appropriately.
+ options->NotifyOptionParsingStarting ();
+ args.Unshift ("dummy_arg");
+ args.ParseAliasOptions (*options, result, option_arg_vector, options_string);
+ args.Shift ();
+ if (result.Succeeded())
+ options->VerifyPartialOptions (result);
+ if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
+ {
+ result.AppendError ("Unable to create requested alias.\n");
+ return false;
+ }
+ }
+
+ if (!options_string.empty())
+ {
+ if (cmd_obj_sp->WantsRawCommandString ())
+ option_arg_vector->push_back (OptionArgPair ("<argument>",
+ OptionArgValue (-1,
+ options_string)));
+ else
+ {
+ const size_t argc = args.GetArgumentCount();
+ for (size_t i = 0; i < argc; ++i)
+ if (strcmp (args.GetArgumentAtIndex (i), "") != 0)
+ option_arg_vector->push_back
+ (OptionArgPair ("<argument>",
+ OptionArgValue (-1,
+ std::string (args.GetArgumentAtIndex (i)))));
+ }
+ }
+
+ return success;
+}
+
+bool
+CommandInterpreter::GetAliasFullName (const char *cmd, std::string &full_name)
+{
+ bool exact_match = (m_alias_dict.find(cmd) != m_alias_dict.end());
+ if (exact_match)
+ {
+ full_name.assign(cmd);
+ return exact_match;
+ }
+ else
+ {
+ StringList matches;
+ size_t num_alias_matches;
+ num_alias_matches = CommandObject::AddNamesMatchingPartialString (m_alias_dict, cmd, matches);
+ if (num_alias_matches == 1)
+ {
+ // Make sure this isn't shadowing a command in the regular command space:
+ StringList regular_matches;
+ const bool include_aliases = false;
+ const bool exact = false;
+ CommandObjectSP cmd_obj_sp(GetCommandSP (cmd, include_aliases, exact, &regular_matches));
+ if (cmd_obj_sp || regular_matches.GetSize() > 0)
+ return false;
+ else
+ {
+ full_name.assign (matches.GetStringAtIndex(0));
+ return true;
+ }
+ }
+ else
+ return false;
+ }
+}
+
+bool
+CommandInterpreter::AliasExists (const char *cmd)
+{
+ return m_alias_dict.find(cmd) != m_alias_dict.end();
+}
+
+bool
+CommandInterpreter::UserCommandExists (const char *cmd)
+{
+ return m_user_dict.find(cmd) != m_user_dict.end();
+}
+
+void
+CommandInterpreter::AddAlias (const char *alias_name, CommandObjectSP& command_obj_sp)
+{
+ command_obj_sp->SetIsAlias (true);
+ m_alias_dict[alias_name] = command_obj_sp;
+}
+
+bool
+CommandInterpreter::RemoveAlias (const char *alias_name)
+{
+ CommandObject::CommandMap::iterator pos = m_alias_dict.find(alias_name);
+ if (pos != m_alias_dict.end())
+ {
+ m_alias_dict.erase(pos);
+ return true;
+ }
+ return false;
+}
+bool
+CommandInterpreter::RemoveUser (const char *alias_name)
+{
+ CommandObject::CommandMap::iterator pos = m_user_dict.find(alias_name);
+ if (pos != m_user_dict.end())
+ {
+ m_user_dict.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+void
+CommandInterpreter::GetAliasHelp (const char *alias_name, const char *command_name, StreamString &help_string)
+{
+ help_string.Printf ("'%s", command_name);
+ OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name);
+
+ if (option_arg_vector_sp)
+ {
+ OptionArgVector *options = option_arg_vector_sp.get();
+ for (size_t i = 0; i < options->size(); ++i)
+ {
+ OptionArgPair cur_option = (*options)[i];
+ std::string opt = cur_option.first;
+ OptionArgValue value_pair = cur_option.second;
+ std::string value = value_pair.second;
+ if (opt.compare("<argument>") == 0)
+ {
+ help_string.Printf (" %s", value.c_str());
+ }
+ else
+ {
+ help_string.Printf (" %s", opt.c_str());
+ if ((value.compare ("<no-argument>") != 0)
+ && (value.compare ("<need-argument") != 0))
+ {
+ help_string.Printf (" %s", value.c_str());
+ }
+ }
+ }
+ }
+
+ help_string.Printf ("'");
+}
+
+size_t
+CommandInterpreter::FindLongestCommandWord (CommandObject::CommandMap &dict)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ CommandObject::CommandMap::const_iterator end = dict.end();
+ size_t max_len = 0;
+
+ for (pos = dict.begin(); pos != end; ++pos)
+ {
+ size_t len = pos->first.size();
+ if (max_len < len)
+ max_len = len;
+ }
+ return max_len;
+}
+
+void
+CommandInterpreter::GetHelp (CommandReturnObject &result,
+ uint32_t cmd_types)
+{
+ CommandObject::CommandMap::const_iterator pos;
+ size_t max_len = FindLongestCommandWord (m_command_dict);
+
+ if ( (cmd_types & eCommandTypesBuiltin) == eCommandTypesBuiltin )
+ {
+
+ result.AppendMessage("The following is a list of built-in, permanent debugger commands:");
+ result.AppendMessage("");
+
+ for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos)
+ {
+ OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(),
+ max_len);
+ }
+ result.AppendMessage("");
+
+ }
+
+ if (!m_alias_dict.empty() && ( (cmd_types & eCommandTypesAliases) == eCommandTypesAliases ))
+ {
+ result.AppendMessage("The following is a list of your current command abbreviations "
+ "(see 'help command alias' for more info):");
+ result.AppendMessage("");
+ max_len = FindLongestCommandWord (m_alias_dict);
+
+ for (pos = m_alias_dict.begin(); pos != m_alias_dict.end(); ++pos)
+ {
+ StreamString sstr;
+ StreamString translation_and_help;
+ std::string entry_name = pos->first;
+ std::string second_entry = pos->second.get()->GetCommandName();
+ GetAliasHelp (pos->first.c_str(), pos->second->GetCommandName(), sstr);
+
+ translation_and_help.Printf ("(%s) %s", sstr.GetData(), pos->second->GetHelp());
+ OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--",
+ translation_and_help.GetData(), max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ if (!m_user_dict.empty() && ( (cmd_types & eCommandTypesUserDef) == eCommandTypesUserDef ))
+ {
+ result.AppendMessage ("The following is a list of your current user-defined commands:");
+ result.AppendMessage("");
+ max_len = FindLongestCommandWord (m_user_dict);
+ for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos)
+ {
+ OutputFormattedHelpText (result.GetOutputStream(), pos->first.c_str(), "--", pos->second->GetHelp(),
+ max_len);
+ }
+ result.AppendMessage("");
+ }
+
+ result.AppendMessage("For more information on any particular command, try 'help <command-name>'.");
+}
+
+CommandObject *
+CommandInterpreter::GetCommandObjectForCommand (std::string &command_string)
+{
+ // This function finds the final, lowest-level, alias-resolved command object whose 'Execute' function will
+ // eventually be invoked by the given command line.
+
+ CommandObject *cmd_obj = NULL;
+ std::string white_space (" \t\v");
+ size_t start = command_string.find_first_not_of (white_space);
+ size_t end = 0;
+ bool done = false;
+ while (!done)
+ {
+ if (start != std::string::npos)
+ {
+ // Get the next word from command_string.
+ end = command_string.find_first_of (white_space, start);
+ if (end == std::string::npos)
+ end = command_string.size();
+ std::string cmd_word = command_string.substr (start, end - start);
+
+ if (cmd_obj == NULL)
+ // Since cmd_obj is NULL we are on our first time through this loop. Check to see if cmd_word is a valid
+ // command or alias.
+ cmd_obj = GetCommandObject (cmd_word.c_str());
+ else if (cmd_obj->IsMultiwordObject ())
+ {
+ // Our current object is a multi-word object; see if the cmd_word is a valid sub-command for our object.
+ CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (cmd_word.c_str());
+ if (sub_cmd_obj)
+ cmd_obj = sub_cmd_obj;
+ else // cmd_word was not a valid sub-command word, so we are donee
+ done = true;
+ }
+ else
+ // We have a cmd_obj and it is not a multi-word object, so we are done.
+ done = true;
+
+ // If we didn't find a valid command object, or our command object is not a multi-word object, or
+ // we are at the end of the command_string, then we are done. Otherwise, find the start of the
+ // next word.
+
+ if (!cmd_obj || !cmd_obj->IsMultiwordObject() || end >= command_string.size())
+ done = true;
+ else
+ start = command_string.find_first_not_of (white_space, end);
+ }
+ else
+ // Unable to find any more words.
+ done = true;
+ }
+
+ if (end == command_string.size())
+ command_string.clear();
+ else
+ command_string = command_string.substr(end);
+
+ return cmd_obj;
+}
+
+static const char *k_white_space = " \t\v";
+static const char *k_valid_command_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
+static void
+StripLeadingSpaces (std::string &s)
+{
+ if (!s.empty())
+ {
+ size_t pos = s.find_first_not_of (k_white_space);
+ if (pos == std::string::npos)
+ s.clear();
+ else if (pos == 0)
+ return;
+ s.erase (0, pos);
+ }
+}
+
+static size_t
+FindArgumentTerminator (const std::string &s)
+{
+ const size_t s_len = s.size();
+ size_t offset = 0;
+ while (offset < s_len)
+ {
+ size_t pos = s.find ("--", offset);
+ if (pos == std::string::npos)
+ break;
+ if (pos > 0)
+ {
+ if (isspace(s[pos-1]))
+ {
+ // Check if the string ends "\s--" (where \s is a space character)
+ // or if we have "\s--\s".
+ if ((pos + 2 >= s_len) || isspace(s[pos+2]))
+ {
+ return pos;
+ }
+ }
+ }
+ offset = pos + 2;
+ }
+ return std::string::npos;
+}
+
+static bool
+ExtractCommand (std::string &command_string, std::string &command, std::string &suffix, char &quote_char)
+{
+ command.clear();
+ suffix.clear();
+ StripLeadingSpaces (command_string);
+
+ bool result = false;
+ quote_char = '\0';
+
+ if (!command_string.empty())
+ {
+ const char first_char = command_string[0];
+ if (first_char == '\'' || first_char == '"')
+ {
+ quote_char = first_char;
+ const size_t end_quote_pos = command_string.find (quote_char, 1);
+ if (end_quote_pos == std::string::npos)
+ {
+ command.swap (command_string);
+ command_string.erase ();
+ }
+ else
+ {
+ command.assign (command_string, 1, end_quote_pos - 1);
+ if (end_quote_pos + 1 < command_string.size())
+ command_string.erase (0, command_string.find_first_not_of (k_white_space, end_quote_pos + 1));
+ else
+ command_string.erase ();
+ }
+ }
+ else
+ {
+ const size_t first_space_pos = command_string.find_first_of (k_white_space);
+ if (first_space_pos == std::string::npos)
+ {
+ command.swap (command_string);
+ command_string.erase();
+ }
+ else
+ {
+ command.assign (command_string, 0, first_space_pos);
+ command_string.erase(0, command_string.find_first_not_of (k_white_space, first_space_pos));
+ }
+ }
+ result = true;
+ }
+
+
+ if (!command.empty())
+ {
+ // actual commands can't start with '-' or '_'
+ if (command[0] != '-' && command[0] != '_')
+ {
+ size_t pos = command.find_first_not_of(k_valid_command_chars);
+ if (pos > 0 && pos != std::string::npos)
+ {
+ suffix.assign (command.begin() + pos, command.end());
+ command.erase (pos);
+ }
+ }
+ }
+
+ return result;
+}
+
+CommandObject *
+CommandInterpreter::BuildAliasResult (const char *alias_name,
+ std::string &raw_input_string,
+ std::string &alias_result,
+ CommandReturnObject &result)
+{
+ CommandObject *alias_cmd_obj = NULL;
+ Args cmd_args (raw_input_string.c_str());
+ alias_cmd_obj = GetCommandObject (alias_name);
+ StreamString result_str;
+
+ if (alias_cmd_obj)
+ {
+ std::string alias_name_str = alias_name;
+ if ((cmd_args.GetArgumentCount() == 0)
+ || (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0))
+ cmd_args.Unshift (alias_name);
+
+ result_str.Printf ("%s", alias_cmd_obj->GetCommandName ());
+ OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name);
+
+ if (option_arg_vector_sp.get())
+ {
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+
+ for (size_t i = 0; i < option_arg_vector->size(); ++i)
+ {
+ OptionArgPair option_pair = (*option_arg_vector)[i];
+ OptionArgValue value_pair = option_pair.second;
+ int value_type = value_pair.first;
+ std::string option = option_pair.first;
+ std::string value = value_pair.second;
+ if (option.compare ("<argument>") == 0)
+ result_str.Printf (" %s", value.c_str());
+ else
+ {
+ result_str.Printf (" %s", option.c_str());
+ if (value_type != optional_argument)
+ result_str.Printf (" ");
+ if (value.compare ("<no_argument>") != 0)
+ {
+ int index = GetOptionArgumentPosition (value.c_str());
+ if (index == 0)
+ result_str.Printf ("%s", value.c_str());
+ else if (index >= cmd_args.GetArgumentCount())
+ {
+
+ result.AppendErrorWithFormat
+ ("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
+ index);
+ result.SetStatus (eReturnStatusFailed);
+ return alias_cmd_obj;
+ }
+ else
+ {
+ size_t strpos = raw_input_string.find (cmd_args.GetArgumentAtIndex (index));
+ if (strpos != std::string::npos)
+ raw_input_string = raw_input_string.erase (strpos,
+ strlen (cmd_args.GetArgumentAtIndex (index)));
+ result_str.Printf ("%s", cmd_args.GetArgumentAtIndex (index));
+ }
+ }
+ }
+ }
+ }
+
+ alias_result = result_str.GetData();
+ }
+ return alias_cmd_obj;
+}
+
+Error
+CommandInterpreter::PreprocessCommand (std::string &command)
+{
+ // The command preprocessor needs to do things to the command
+ // line before any parsing of arguments or anything else is done.
+ // The only current stuff that gets proprocessed is anyting enclosed
+ // in backtick ('`') characters is evaluated as an expression and
+ // the result of the expression must be a scalar that can be substituted
+ // into the command. An example would be:
+ // (lldb) memory read `$rsp + 20`
+ Error error; // Error for any expressions that might not evaluate
+ size_t start_backtick;
+ size_t pos = 0;
+ while ((start_backtick = command.find ('`', pos)) != std::string::npos)
+ {
+ if (start_backtick > 0 && command[start_backtick-1] == '\\')
+ {
+ // The backtick was preceeded by a '\' character, remove the slash
+ // and don't treat the backtick as the start of an expression
+ command.erase(start_backtick-1, 1);
+ // No need to add one to start_backtick since we just deleted a char
+ pos = start_backtick;
+ }
+ else
+ {
+ const size_t expr_content_start = start_backtick + 1;
+ const size_t end_backtick = command.find ('`', expr_content_start);
+ if (end_backtick == std::string::npos)
+ return error;
+ else if (end_backtick == expr_content_start)
+ {
+ // Empty expression (two backticks in a row)
+ command.erase (start_backtick, 2);
+ }
+ else
+ {
+ std::string expr_str (command, expr_content_start, end_backtick - expr_content_start);
+
+ ExecutionContext exe_ctx(GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ // 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();
+ if (target)
+ {
+ ValueObjectSP expr_result_valobj_sp;
+
+ EvaluateExpressionOptions options;
+ options.SetCoerceToId(false)
+ .SetUnwindOnError(true)
+ .SetIgnoreBreakpoints(true)
+ .SetKeepInMemory(false)
+ .SetRunOthers(true)
+ .SetTimeoutUsec(0);
+
+ ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(),
+ exe_ctx.GetFramePtr(),
+ expr_result_valobj_sp,
+ options);
+
+ if (expr_result == eExecutionCompleted)
+ {
+ Scalar scalar;
+ if (expr_result_valobj_sp->ResolveValue (scalar))
+ {
+ command.erase (start_backtick, end_backtick - start_backtick + 1);
+ StreamString value_strm;
+ const bool show_type = false;
+ scalar.GetValue (&value_strm, show_type);
+ size_t value_string_size = value_strm.GetSize();
+ if (value_string_size)
+ {
+ command.insert (start_backtick, value_strm.GetData(), value_string_size);
+ pos = start_backtick + value_string_size;
+ continue;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("expression value didn't result in a scalar value for the expression '%s'", expr_str.c_str());
+ }
+ }
+ else
+ {
+ if (expr_result_valobj_sp)
+ error = expr_result_valobj_sp->GetError();
+ if (error.Success())
+ {
+
+ switch (expr_result)
+ {
+ case eExecutionSetupError:
+ error.SetErrorStringWithFormat("expression setup error for the expression '%s'", expr_str.c_str());
+ break;
+ case eExecutionCompleted:
+ break;
+ case eExecutionDiscarded:
+ error.SetErrorStringWithFormat("expression discarded for the expression '%s'", expr_str.c_str());
+ break;
+ case eExecutionInterrupted:
+ error.SetErrorStringWithFormat("expression interrupted for the expression '%s'", expr_str.c_str());
+ break;
+ case eExecutionHitBreakpoint:
+ error.SetErrorStringWithFormat("expression hit breakpoint for the expression '%s'", expr_str.c_str());
+ break;
+ case eExecutionTimedOut:
+ error.SetErrorStringWithFormat("expression timed out for the expression '%s'", expr_str.c_str());
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (error.Fail())
+ break;
+ }
+ }
+ return error;
+}
+
+
+bool
+CommandInterpreter::HandleCommand (const char *command_line,
+ LazyBool lazy_add_to_history,
+ CommandReturnObject &result,
+ ExecutionContext *override_context,
+ bool repeat_on_empty_command,
+ bool no_context_switching)
+
+{
+
+ bool done = false;
+ CommandObject *cmd_obj = NULL;
+ bool wants_raw_input = false;
+ std::string command_string (command_line);
+ std::string original_command_string (command_line);
+
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS));
+ Host::SetCrashDescriptionWithFormat ("HandleCommand(command = \"%s\")", command_line);
+
+ // Make a scoped cleanup object that will clear the crash description string
+ // on exit of this function.
+ lldb_utility::CleanUp <const char *> crash_description_cleanup(NULL, Host::SetCrashDescription);
+
+ if (log)
+ log->Printf ("Processing command: %s", command_line);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "Handling command: %s.", command_line);
+
+ if (!no_context_switching)
+ UpdateExecutionContext (override_context);
+
+ bool add_to_history;
+ if (lazy_add_to_history == eLazyBoolCalculate)
+ add_to_history = (m_command_source_depth == 0);
+ else
+ add_to_history = (lazy_add_to_history == eLazyBoolYes);
+
+ bool empty_command = false;
+ bool comment_command = false;
+ if (command_string.empty())
+ empty_command = true;
+ else
+ {
+ const char *k_space_characters = "\t\n\v\f\r ";
+
+ size_t non_space = command_string.find_first_not_of (k_space_characters);
+ // Check for empty line or comment line (lines whose first
+ // non-space character is the comment character for this interpreter)
+ if (non_space == std::string::npos)
+ empty_command = true;
+ else if (command_string[non_space] == m_comment_char)
+ comment_command = true;
+ else if (command_string[non_space] == CommandHistory::g_repeat_char)
+ {
+ const char *history_string = m_command_history.FindString(command_string.c_str() + non_space);
+ if (history_string == NULL)
+ {
+ result.AppendErrorWithFormat ("Could not find entry: %s in history", command_string.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ add_to_history = false;
+ command_string = history_string;
+ original_command_string = history_string;
+ }
+ }
+
+ if (empty_command)
+ {
+ if (repeat_on_empty_command)
+ {
+ if (m_command_history.IsEmpty())
+ {
+ result.AppendError ("empty command");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ else
+ {
+ command_line = m_repeat_command.c_str();
+ command_string = command_line;
+ original_command_string = command_line;
+ if (m_repeat_command.empty())
+ {
+ result.AppendErrorWithFormat("No auto repeat.\n");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ add_to_history = false;
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+ }
+ else if (comment_command)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return true;
+ }
+
+
+ Error error (PreprocessCommand (command_string));
+
+ if (error.Fail())
+ {
+ result.AppendError (error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ // Phase 1.
+
+ // Before we do ANY kind of argument processing, etc. we need to figure out what the real/final command object
+ // is for the specified command, and whether or not it wants raw input. This gets complicated by the fact that
+ // the user could have specified an alias, and in translating the alias there may also be command options and/or
+ // even data (including raw text strings) that need to be found and inserted into the command line as part of
+ // the translation. So this first step is plain look-up & replacement, resulting in three things: 1). the command
+ // object whose Execute method will actually be called; 2). a revised command string, with all substitutions &
+ // replacements taken care of; 3). whether or not the Execute function wants raw input or not.
+
+ StreamString revised_command_line;
+ size_t actual_cmd_name_len = 0;
+ std::string next_word;
+ StringList matches;
+ while (!done)
+ {
+ char quote_char = '\0';
+ std::string suffix;
+ ExtractCommand (command_string, next_word, suffix, quote_char);
+ if (cmd_obj == NULL)
+ {
+ std::string full_name;
+ if (GetAliasFullName(next_word.c_str(), full_name))
+ {
+ std::string alias_result;
+ cmd_obj = BuildAliasResult (full_name.c_str(), command_string, alias_result, result);
+ revised_command_line.Printf ("%s", alias_result.c_str());
+ if (cmd_obj)
+ {
+ wants_raw_input = cmd_obj->WantsRawCommandString ();
+ actual_cmd_name_len = strlen (cmd_obj->GetCommandName());
+ }
+ }
+ else
+ {
+ cmd_obj = GetCommandObject (next_word.c_str(), &matches);
+ if (cmd_obj)
+ {
+ actual_cmd_name_len += next_word.length();
+ revised_command_line.Printf ("%s", next_word.c_str());
+ wants_raw_input = cmd_obj->WantsRawCommandString ();
+ }
+ else
+ {
+ revised_command_line.Printf ("%s", next_word.c_str());
+ }
+ }
+ }
+ else
+ {
+ if (cmd_obj->IsMultiwordObject ())
+ {
+ CommandObject *sub_cmd_obj = cmd_obj->GetSubcommandObject (next_word.c_str());
+ if (sub_cmd_obj)
+ {
+ actual_cmd_name_len += next_word.length() + 1;
+ revised_command_line.Printf (" %s", next_word.c_str());
+ cmd_obj = sub_cmd_obj;
+ wants_raw_input = cmd_obj->WantsRawCommandString ();
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+ else
+ {
+ if (quote_char)
+ revised_command_line.Printf (" %c%s%s%c", quote_char, next_word.c_str(), suffix.c_str(), quote_char);
+ else
+ revised_command_line.Printf (" %s%s", next_word.c_str(), suffix.c_str());
+ done = true;
+ }
+ }
+
+ if (cmd_obj == NULL)
+ {
+ const size_t num_matches = matches.GetSize();
+ if (matches.GetSize() > 1) {
+ StreamString error_msg;
+ error_msg.Printf ("Ambiguous command '%s'. Possible matches:\n", next_word.c_str());
+
+ for (uint32_t i = 0; i < num_matches; ++i) {
+ error_msg.Printf ("\t%s\n", matches.GetStringAtIndex(i));
+ }
+ result.AppendRawError (error_msg.GetString().c_str());
+ } else {
+ // We didn't have only one match, otherwise we wouldn't get here.
+ assert(num_matches == 0);
+ result.AppendErrorWithFormat ("'%s' is not a valid command.\n", next_word.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ if (cmd_obj->IsMultiwordObject ())
+ {
+ if (!suffix.empty())
+ {
+
+ result.AppendErrorWithFormat ("command '%s' did not recognize '%s%s%s' as valid (subcommand might be invalid).\n",
+ cmd_obj->GetCommandName(),
+ next_word.empty() ? "" : next_word.c_str(),
+ next_word.empty() ? " -- " : " ",
+ suffix.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ // If we found a normal command, we are done
+ done = true;
+ if (!suffix.empty())
+ {
+ switch (suffix[0])
+ {
+ case '/':
+ // GDB format suffixes
+ {
+ Options *command_options = cmd_obj->GetOptions();
+ if (command_options && command_options->SupportsLongOption("gdb-format"))
+ {
+ std::string gdb_format_option ("--gdb-format=");
+ gdb_format_option += (suffix.c_str() + 1);
+
+ bool inserted = false;
+ std::string &cmd = revised_command_line.GetString();
+ size_t arg_terminator_idx = FindArgumentTerminator (cmd);
+ if (arg_terminator_idx != std::string::npos)
+ {
+ // Insert the gdb format option before the "--" that terminates options
+ gdb_format_option.append(1,' ');
+ cmd.insert(arg_terminator_idx, gdb_format_option);
+ inserted = true;
+ }
+
+ if (!inserted)
+ revised_command_line.Printf (" %s", gdb_format_option.c_str());
+
+ if (wants_raw_input && FindArgumentTerminator(cmd) == std::string::npos)
+ revised_command_line.PutCString (" --");
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("the '%s' command doesn't support the --gdb-format option\n",
+ cmd_obj->GetCommandName());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ break;
+
+ default:
+ result.AppendErrorWithFormat ("unknown command shorthand suffix: '%s'\n",
+ suffix.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+
+ }
+ }
+ }
+ if (command_string.length() == 0)
+ done = true;
+
+ }
+
+ if (!command_string.empty())
+ revised_command_line.Printf (" %s", command_string.c_str());
+
+ // End of Phase 1.
+ // At this point cmd_obj should contain the CommandObject whose Execute method will be called, if the command
+ // specified was valid; revised_command_line contains the complete command line (including command name(s)),
+ // fully translated with all substitutions & translations taken care of (still in raw text format); and
+ // wants_raw_input specifies whether the Execute method expects raw input or not.
+
+
+ if (log)
+ {
+ log->Printf ("HandleCommand, cmd_obj : '%s'", cmd_obj ? cmd_obj->GetCommandName() : "<not found>");
+ log->Printf ("HandleCommand, revised_command_line: '%s'", revised_command_line.GetData());
+ log->Printf ("HandleCommand, wants_raw_input:'%s'", wants_raw_input ? "True" : "False");
+ }
+
+ // Phase 2.
+ // Take care of things like setting up the history command & calling the appropriate Execute method on the
+ // CommandObject, with the appropriate arguments.
+
+ if (cmd_obj != NULL)
+ {
+ if (add_to_history)
+ {
+ Args command_args (revised_command_line.GetData());
+ const char *repeat_command = cmd_obj->GetRepeatCommand(command_args, 0);
+ if (repeat_command != NULL)
+ m_repeat_command.assign(repeat_command);
+ else
+ m_repeat_command.assign(original_command_string.c_str());
+
+ m_command_history.AppendString (original_command_string);
+ }
+
+ command_string = revised_command_line.GetData();
+ std::string command_name (cmd_obj->GetCommandName());
+ std::string remainder;
+ if (actual_cmd_name_len < command_string.length())
+ remainder = command_string.substr (actual_cmd_name_len); // Note: 'actual_cmd_name_len' may be considerably shorter
+ // than cmd_obj->GetCommandName(), because name completion
+ // allows users to enter short versions of the names,
+ // e.g. 'br s' for 'breakpoint set'.
+
+ // Remove any initial spaces
+ std::string white_space (" \t\v");
+ size_t pos = remainder.find_first_not_of (white_space);
+ if (pos != 0 && pos != std::string::npos)
+ remainder.erase(0, pos);
+
+ if (log)
+ log->Printf ("HandleCommand, command line after removing command name(s): '%s'", remainder.c_str());
+
+ cmd_obj->Execute (remainder.c_str(), result);
+ }
+ else
+ {
+ // We didn't find the first command object, so complete the first argument.
+ Args command_args (revised_command_line.GetData());
+ StringList matches;
+ int num_matches;
+ int cursor_index = 0;
+ int cursor_char_position = strlen (command_args.GetArgumentAtIndex(0));
+ bool word_complete;
+ num_matches = HandleCompletionMatches (command_args,
+ cursor_index,
+ cursor_char_position,
+ 0,
+ -1,
+ word_complete,
+ matches);
+
+ if (num_matches > 0)
+ {
+ std::string error_msg;
+ error_msg.assign ("ambiguous command '");
+ error_msg.append(command_args.GetArgumentAtIndex(0));
+ error_msg.append ("'.");
+
+ error_msg.append (" Possible completions:");
+ for (int i = 0; i < num_matches; i++)
+ {
+ error_msg.append ("\n\t");
+ error_msg.append (matches.GetStringAtIndex (i));
+ }
+ error_msg.append ("\n");
+ result.AppendRawError (error_msg.c_str());
+ }
+ else
+ result.AppendErrorWithFormat ("Unrecognized command '%s'.\n", command_args.GetArgumentAtIndex (0));
+
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ if (log)
+ log->Printf ("HandleCommand, command %s", (result.Succeeded() ? "succeeded" : "did not succeed"));
+
+ return result.Succeeded();
+}
+
+int
+CommandInterpreter::HandleCompletionMatches (Args &parsed_line,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ int num_command_matches = 0;
+ bool look_for_subcommand = false;
+
+ // For any of the command completions a unique match will be a complete word.
+ word_complete = true;
+
+ if (cursor_index == -1)
+ {
+ // We got nothing on the command line, so return the list of commands
+ bool include_aliases = true;
+ num_command_matches = GetCommandNamesMatchingPartialString ("", include_aliases, matches);
+ }
+ else if (cursor_index == 0)
+ {
+ // The cursor is in the first argument, so just do a lookup in the dictionary.
+ CommandObject *cmd_obj = GetCommandObject (parsed_line.GetArgumentAtIndex(0), &matches);
+ num_command_matches = matches.GetSize();
+
+ if (num_command_matches == 1
+ && cmd_obj && cmd_obj->IsMultiwordObject()
+ && matches.GetStringAtIndex(0) != NULL
+ && strcmp (parsed_line.GetArgumentAtIndex(0), matches.GetStringAtIndex(0)) == 0)
+ {
+ look_for_subcommand = true;
+ num_command_matches = 0;
+ matches.DeleteStringAtIndex(0);
+ parsed_line.AppendArgument ("");
+ cursor_index++;
+ cursor_char_position = 0;
+ }
+ }
+
+ if (cursor_index > 0 || look_for_subcommand)
+ {
+ // We are completing further on into a commands arguments, so find the command and tell it
+ // to complete the command.
+ // First see if there is a matching initial command:
+ CommandObject *command_object = GetCommandObject (parsed_line.GetArgumentAtIndex(0));
+ if (command_object == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ parsed_line.Shift();
+ cursor_index--;
+ num_command_matches = command_object->HandleCompletion (parsed_line,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+ }
+
+ return num_command_matches;
+
+}
+
+int
+CommandInterpreter::HandleCompletion (const char *current_line,
+ const char *cursor,
+ const char *last_char,
+ int match_start_point,
+ int max_return_elements,
+ StringList &matches)
+{
+ // We parse the argument up to the cursor, so the last argument in parsed_line is
+ // the one containing the cursor, and the cursor is after the last character.
+
+ Args parsed_line(current_line, last_char - current_line);
+ Args partial_parsed_line(current_line, cursor - current_line);
+
+ // Don't complete comments, and if the line we are completing is just the history repeat character,
+ // substitute the appropriate history line.
+ const char *first_arg = parsed_line.GetArgumentAtIndex(0);
+ if (first_arg)
+ {
+ if (first_arg[0] == m_comment_char)
+ return 0;
+ else if (first_arg[0] == CommandHistory::g_repeat_char)
+ {
+ const char *history_string = m_command_history.FindString (first_arg);
+ if (history_string != NULL)
+ {
+ matches.Clear();
+ matches.InsertStringAtIndex(0, history_string);
+ return -2;
+ }
+ else
+ return 0;
+
+ }
+ }
+
+
+ int num_args = partial_parsed_line.GetArgumentCount();
+ int cursor_index = partial_parsed_line.GetArgumentCount() - 1;
+ int cursor_char_position;
+
+ if (cursor_index == -1)
+ cursor_char_position = 0;
+ else
+ cursor_char_position = strlen (partial_parsed_line.GetArgumentAtIndex(cursor_index));
+
+ if (cursor > current_line && cursor[-1] == ' ')
+ {
+ // We are just after a space. If we are in an argument, then we will continue
+ // parsing, but if we are between arguments, then we have to complete whatever the next
+ // element would be.
+ // We can distinguish the two cases because if we are in an argument (e.g. because the space is
+ // protected by a quote) then the space will also be in the parsed argument...
+
+ const char *current_elem = partial_parsed_line.GetArgumentAtIndex(cursor_index);
+ if (cursor_char_position == 0 || current_elem[cursor_char_position - 1] != ' ')
+ {
+ parsed_line.InsertArgumentAtIndex(cursor_index + 1, "", '"');
+ cursor_index++;
+ cursor_char_position = 0;
+ }
+ }
+
+ int num_command_matches;
+
+ matches.Clear();
+
+ // Only max_return_elements == -1 is supported at present:
+ assert (max_return_elements == -1);
+ bool word_complete;
+ num_command_matches = HandleCompletionMatches (parsed_line,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+
+ if (num_command_matches <= 0)
+ return num_command_matches;
+
+ if (num_args == 0)
+ {
+ // If we got an empty string, insert nothing.
+ matches.InsertStringAtIndex(0, "");
+ }
+ else
+ {
+ // Now figure out if there is a common substring, and if so put that in element 0, otherwise
+ // put an empty string in element 0.
+ std::string command_partial_str;
+ if (cursor_index >= 0)
+ command_partial_str.assign(parsed_line.GetArgumentAtIndex(cursor_index),
+ parsed_line.GetArgumentAtIndex(cursor_index) + cursor_char_position);
+
+ std::string common_prefix;
+ matches.LongestCommonPrefix (common_prefix);
+ const size_t partial_name_len = command_partial_str.size();
+
+ // If we matched a unique single command, add a space...
+ // Only do this if the completer told us this was a complete word, however...
+ if (num_command_matches == 1 && word_complete)
+ {
+ char quote_char = parsed_line.GetArgumentQuoteCharAtIndex(cursor_index);
+ if (quote_char != '\0')
+ common_prefix.push_back(quote_char);
+
+ common_prefix.push_back(' ');
+ }
+ common_prefix.erase (0, partial_name_len);
+ matches.InsertStringAtIndex(0, common_prefix.c_str());
+ }
+ return num_command_matches;
+}
+
+
+CommandInterpreter::~CommandInterpreter ()
+{
+}
+
+const char *
+CommandInterpreter::GetPrompt ()
+{
+ return m_debugger.GetPrompt();
+}
+
+void
+CommandInterpreter::SetPrompt (const char *new_prompt)
+{
+ m_debugger.SetPrompt (new_prompt);
+}
+
+size_t
+CommandInterpreter::GetConfirmationInputReaderCallback
+(
+ void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction action,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ File &out_file = reader.GetDebugger().GetOutputFile();
+ bool *response_ptr = (bool *) baton;
+
+ switch (action)
+ {
+ case eInputReaderActivate:
+ if (out_file.IsValid())
+ {
+ if (reader.GetPrompt())
+ {
+ out_file.Printf ("%s", reader.GetPrompt());
+ out_file.Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (out_file.IsValid() && reader.GetPrompt())
+ {
+ out_file.Printf ("%s", reader.GetPrompt());
+ out_file.Flush ();
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ if (bytes_len == 0)
+ {
+ reader.SetIsDone(true);
+ }
+ else if (bytes[0] == 'y' || bytes[0] == 'Y')
+ {
+ *response_ptr = true;
+ reader.SetIsDone(true);
+ }
+ else if (bytes[0] == 'n' || bytes[0] == 'N')
+ {
+ *response_ptr = false;
+ reader.SetIsDone(true);
+ }
+ else
+ {
+ if (out_file.IsValid() && !reader.IsDone() && reader.GetPrompt())
+ {
+ out_file.Printf ("Please answer \"y\" or \"n\".\n%s", reader.GetPrompt());
+ out_file.Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ case eInputReaderEndOfFile:
+ *response_ptr = false; // Assume ^C or ^D means cancel the proposed action
+ reader.SetIsDone (true);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+
+ return bytes_len;
+
+}
+
+bool
+CommandInterpreter::Confirm (const char *message, bool default_answer)
+{
+ // Check AutoConfirm first:
+ if (m_debugger.GetAutoConfirm())
+ return default_answer;
+
+ InputReaderSP reader_sp (new InputReader(GetDebugger()));
+ bool response = default_answer;
+ if (reader_sp)
+ {
+ std::string prompt(message);
+ prompt.append(": [");
+ if (default_answer)
+ prompt.append ("Y/n] ");
+ else
+ prompt.append ("y/N] ");
+
+ Error err (reader_sp->Initialize (CommandInterpreter::GetConfirmationInputReaderCallback,
+ &response, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ prompt.c_str(), // prompt
+ true)); // echo input
+ if (err.Success())
+ {
+ GetDebugger().PushInputReader (reader_sp);
+ }
+ reader_sp->WaitOnReaderIsDone();
+ }
+ return response;
+}
+
+OptionArgVectorSP
+CommandInterpreter::GetAliasOptions (const char *alias_name)
+{
+ OptionArgMap::iterator pos;
+ OptionArgVectorSP ret_val;
+
+ std::string alias (alias_name);
+
+ if (HasAliasOptions())
+ {
+ pos = m_alias_options.find (alias);
+ if (pos != m_alias_options.end())
+ ret_val = pos->second;
+ }
+
+ return ret_val;
+}
+
+void
+CommandInterpreter::RemoveAliasOptions (const char *alias_name)
+{
+ OptionArgMap::iterator pos = m_alias_options.find(alias_name);
+ if (pos != m_alias_options.end())
+ {
+ m_alias_options.erase (pos);
+ }
+}
+
+void
+CommandInterpreter::AddOrReplaceAliasOptions (const char *alias_name, OptionArgVectorSP &option_arg_vector_sp)
+{
+ m_alias_options[alias_name] = option_arg_vector_sp;
+}
+
+bool
+CommandInterpreter::HasCommands ()
+{
+ return (!m_command_dict.empty());
+}
+
+bool
+CommandInterpreter::HasAliases ()
+{
+ return (!m_alias_dict.empty());
+}
+
+bool
+CommandInterpreter::HasUserCommands ()
+{
+ return (!m_user_dict.empty());
+}
+
+bool
+CommandInterpreter::HasAliasOptions ()
+{
+ return (!m_alias_options.empty());
+}
+
+void
+CommandInterpreter::BuildAliasCommandArgs (CommandObject *alias_cmd_obj,
+ const char *alias_name,
+ Args &cmd_args,
+ std::string &raw_input_string,
+ CommandReturnObject &result)
+{
+ OptionArgVectorSP option_arg_vector_sp = GetAliasOptions (alias_name);
+
+ bool wants_raw_input = alias_cmd_obj->WantsRawCommandString();
+
+ // Make sure that the alias name is the 0th element in cmd_args
+ std::string alias_name_str = alias_name;
+ if (alias_name_str.compare (cmd_args.GetArgumentAtIndex(0)) != 0)
+ cmd_args.Unshift (alias_name);
+
+ Args new_args (alias_cmd_obj->GetCommandName());
+ if (new_args.GetArgumentCount() == 2)
+ new_args.Shift();
+
+ if (option_arg_vector_sp.get())
+ {
+ if (wants_raw_input)
+ {
+ // We have a command that both has command options and takes raw input. Make *sure* it has a
+ // " -- " in the right place in the raw_input_string.
+ size_t pos = raw_input_string.find(" -- ");
+ if (pos == std::string::npos)
+ {
+ // None found; assume it goes at the beginning of the raw input string
+ raw_input_string.insert (0, " -- ");
+ }
+ }
+
+ OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
+ const size_t old_size = cmd_args.GetArgumentCount();
+ std::vector<bool> used (old_size + 1, false);
+
+ used[0] = true;
+
+ for (size_t i = 0; i < option_arg_vector->size(); ++i)
+ {
+ OptionArgPair option_pair = (*option_arg_vector)[i];
+ OptionArgValue value_pair = option_pair.second;
+ int value_type = value_pair.first;
+ std::string option = option_pair.first;
+ std::string value = value_pair.second;
+ if (option.compare ("<argument>") == 0)
+ {
+ if (!wants_raw_input
+ || (value.compare("--") != 0)) // Since we inserted this above, make sure we don't insert it twice
+ new_args.AppendArgument (value.c_str());
+ }
+ else
+ {
+ if (value_type != optional_argument)
+ new_args.AppendArgument (option.c_str());
+ if (value.compare ("<no-argument>") != 0)
+ {
+ int index = GetOptionArgumentPosition (value.c_str());
+ if (index == 0)
+ {
+ // value was NOT a positional argument; must be a real value
+ if (value_type != optional_argument)
+ new_args.AppendArgument (value.c_str());
+ else
+ {
+ char buffer[255];
+ ::snprintf (buffer, sizeof (buffer), "%s%s", option.c_str(), value.c_str());
+ new_args.AppendArgument (buffer);
+ }
+
+ }
+ else if (index >= cmd_args.GetArgumentCount())
+ {
+ result.AppendErrorWithFormat
+ ("Not enough arguments provided; you need at least %d arguments to use this alias.\n",
+ index);
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ else
+ {
+ // Find and remove cmd_args.GetArgumentAtIndex(i) from raw_input_string
+ size_t strpos = raw_input_string.find (cmd_args.GetArgumentAtIndex (index));
+ if (strpos != std::string::npos)
+ {
+ raw_input_string = raw_input_string.erase (strpos, strlen (cmd_args.GetArgumentAtIndex (index)));
+ }
+
+ if (value_type != optional_argument)
+ new_args.AppendArgument (cmd_args.GetArgumentAtIndex (index));
+ else
+ {
+ char buffer[255];
+ ::snprintf (buffer, sizeof(buffer), "%s%s", option.c_str(),
+ cmd_args.GetArgumentAtIndex (index));
+ new_args.AppendArgument (buffer);
+ }
+ used[index] = true;
+ }
+ }
+ }
+ }
+
+ for (size_t j = 0; j < cmd_args.GetArgumentCount(); ++j)
+ {
+ if (!used[j] && !wants_raw_input)
+ new_args.AppendArgument (cmd_args.GetArgumentAtIndex (j));
+ }
+
+ cmd_args.Clear();
+ cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector());
+ }
+ else
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ // This alias was not created with any options; nothing further needs to be done, unless it is a command that
+ // wants raw input, in which case we need to clear the rest of the data from cmd_args, since its in the raw
+ // input string.
+ if (wants_raw_input)
+ {
+ cmd_args.Clear();
+ cmd_args.SetArguments (new_args.GetArgumentCount(), (const char **) new_args.GetArgumentVector());
+ }
+ return;
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return;
+}
+
+
+int
+CommandInterpreter::GetOptionArgumentPosition (const char *in_string)
+{
+ int position = 0; // Any string that isn't an argument position, i.e. '%' followed by an integer, gets a position
+ // of zero.
+
+ char *cptr = (char *) in_string;
+
+ // Does it start with '%'
+ if (cptr[0] == '%')
+ {
+ ++cptr;
+
+ // Is the rest of it entirely digits?
+ if (isdigit (cptr[0]))
+ {
+ const char *start = cptr;
+ while (isdigit (cptr[0]))
+ ++cptr;
+
+ // We've gotten to the end of the digits; are we at the end of the string?
+ if (cptr[0] == '\0')
+ position = atoi (start);
+ }
+ }
+
+ return position;
+}
+
+void
+CommandInterpreter::SourceInitFile (bool in_cwd, CommandReturnObject &result)
+{
+ FileSpec init_file;
+ if (in_cwd)
+ {
+ // In the current working directory we don't load any program specific
+ // .lldbinit files, we only look for a "./.lldbinit" file.
+ if (m_skip_lldbinit_files)
+ return;
+
+ init_file.SetFile ("./.lldbinit", true);
+ }
+ else
+ {
+ // If we aren't looking in the current working directory we are looking
+ // in the home directory. We will first see if there is an application
+ // specific ".lldbinit" file whose name is "~/.lldbinit" followed by a
+ // "-" and the name of the program. If this file doesn't exist, we fall
+ // back to just the "~/.lldbinit" file. We also obey any requests to not
+ // load the init files.
+ const char *init_file_path = "~/.lldbinit";
+
+ if (m_skip_app_init_files == false)
+ {
+ FileSpec program_file_spec (Host::GetProgramFileSpec());
+ const char *program_name = program_file_spec.GetFilename().AsCString();
+
+ if (program_name)
+ {
+ char program_init_file_name[PATH_MAX];
+ ::snprintf (program_init_file_name, sizeof(program_init_file_name), "%s-%s", init_file_path, program_name);
+ init_file.SetFile (program_init_file_name, true);
+ if (!init_file.Exists())
+ init_file.Clear();
+ }
+ }
+
+ if (!init_file && !m_skip_lldbinit_files)
+ init_file.SetFile (init_file_path, true);
+ }
+
+ // If the file exists, tell HandleCommand to 'source' it; this will do the actual broadcasting
+ // of the commands back to any appropriate listener (see CommandObjectSource::Execute for more details).
+
+ if (init_file.Exists())
+ {
+ ExecutionContext *exe_ctx = NULL; // We don't have any context yet.
+ bool stop_on_continue = true;
+ bool stop_on_error = false;
+ bool echo_commands = false;
+ bool print_results = false;
+
+ HandleCommandsFromFile (init_file, exe_ctx, stop_on_continue, stop_on_error, echo_commands, print_results, eLazyBoolNo, result);
+ }
+ else
+ {
+ // nothing to be done if the file doesn't exist
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ }
+}
+
+PlatformSP
+CommandInterpreter::GetPlatform (bool prefer_target_platform)
+{
+ PlatformSP platform_sp;
+ if (prefer_target_platform)
+ {
+ ExecutionContext exe_ctx(GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ platform_sp = target->GetPlatform();
+ }
+
+ if (!platform_sp)
+ platform_sp = m_debugger.GetPlatformList().GetSelectedPlatform();
+ return platform_sp;
+}
+
+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,
+ CommandReturnObject &result)
+{
+ size_t num_lines = commands.GetSize();
+
+ // If we are going to continue past a "continue" then we need to run the commands synchronously.
+ // Make sure you reset this value anywhere you return from the function.
+
+ bool old_async_execution = m_debugger.GetAsyncExecution();
+
+ // If we've been given an execution context, set it at the start, but don't keep resetting it or we will
+ // cause series of commands that change the context, then do an operation that relies on that context to fail.
+
+ if (override_context != NULL)
+ UpdateExecutionContext (override_context);
+
+ if (!stop_on_continue)
+ {
+ m_debugger.SetAsyncExecution (false);
+ }
+
+ for (size_t idx = 0; idx < num_lines; idx++)
+ {
+ const char *cmd = commands.GetStringAtIndex(idx);
+ if (cmd[0] == '\0')
+ continue;
+
+ if (echo_commands)
+ {
+ result.AppendMessageWithFormat ("%s %s\n",
+ GetPrompt(),
+ cmd);
+ }
+
+ CommandReturnObject tmp_result;
+ // If override_context is not NULL, pass no_context_switching = true for
+ // HandleCommand() since we updated our context already.
+
+ // 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)
+ m_command_source_depth++;
+ bool success = HandleCommand(cmd, add_to_history, tmp_result,
+ NULL, /* override_context */
+ true, /* repeat_on_empty_command */
+ override_context != NULL /* no_context_switching */);
+ if (!add_to_history)
+ m_command_source_depth--;
+
+ if (print_results)
+ {
+ if (tmp_result.Succeeded())
+ result.AppendMessageWithFormat("%s", tmp_result.GetOutputData());
+ }
+
+ if (!success || !tmp_result.Succeeded())
+ {
+ const char *error_msg = tmp_result.GetErrorData();
+ if (error_msg == NULL || error_msg[0] == '\0')
+ error_msg = "<unknown error>.\n";
+ if (stop_on_error)
+ {
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' failed with %s",
+ idx, cmd, error_msg);
+ result.SetStatus (eReturnStatusFailed);
+ m_debugger.SetAsyncExecution (old_async_execution);
+ return;
+ }
+ else if (print_results)
+ {
+ result.AppendMessageWithFormat ("Command #%zu '%s' failed with %s",
+ idx + 1,
+ cmd,
+ error_msg);
+ }
+ }
+
+ if (result.GetImmediateOutputStream())
+ result.GetImmediateOutputStream()->Flush();
+
+ if (result.GetImmediateErrorStream())
+ result.GetImmediateErrorStream()->Flush();
+
+ // N.B. Can't depend on DidChangeProcessState, because the state coming into the command execution
+ // could be running (for instance in Breakpoint Commands.
+ // So we check the return value to see if it is has running in it.
+ if ((tmp_result.GetStatus() == eReturnStatusSuccessContinuingNoResult)
+ || (tmp_result.GetStatus() == eReturnStatusSuccessContinuingResult))
+ {
+ if (stop_on_continue)
+ {
+ // 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
+ // last command in the set of commands to be run.
+ if (idx != num_lines - 1)
+ result.AppendErrorWithFormat("Aborting reading of commands after command #%zu: '%s' continued the target.\n",
+ idx + 1, cmd);
+ else
+ result.AppendMessageWithFormat ("Command #%zu '%s' continued the target.\n", idx + 1, cmd);
+
+ result.SetStatus(tmp_result.GetStatus());
+ m_debugger.SetAsyncExecution (old_async_execution);
+
+ return;
+ }
+ }
+
+ }
+
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ m_debugger.SetAsyncExecution (old_async_execution);
+
+ return;
+}
+
+void
+CommandInterpreter::HandleCommandsFromFile (FileSpec &cmd_file,
+ ExecutionContext *context,
+ bool stop_on_continue,
+ bool stop_on_error,
+ bool echo_command,
+ bool print_result,
+ LazyBool add_to_history,
+ CommandReturnObject &result)
+{
+ if (cmd_file.Exists())
+ {
+ bool success;
+ StringList commands;
+ success = commands.ReadFileLines(cmd_file);
+ if (!success)
+ {
+ result.AppendErrorWithFormat ("Error reading commands from file: %s.\n", cmd_file.GetFilename().AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+ m_command_source_depth++;
+ HandleCommands (commands, context, stop_on_continue, stop_on_error, echo_command, print_result, add_to_history, result);
+ m_command_source_depth--;
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("Error reading commands from file %s - file not found.\n",
+ cmd_file.GetFilename().AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ return;
+ }
+}
+
+ScriptInterpreter *
+CommandInterpreter::GetScriptInterpreter (bool can_create)
+{
+ if (m_script_interpreter_ap.get() != NULL)
+ return m_script_interpreter_ap.get();
+
+ if (!can_create)
+ return NULL;
+
+ // <rdar://problem/11751427>
+ // we need to protect the initialization of the script interpreter
+ // otherwise we could end up with two threads both trying to create
+ // their instance of it, and for some languages (e.g. Python)
+ // this is a bulletproof recipe for disaster!
+ // this needs to be a function-level static because multiple Debugger instances living in the same process
+ // still need to be isolated and not try to initialize Python concurrently
+ static Mutex g_interpreter_mutex(Mutex::eMutexTypeRecursive);
+ Mutex::Locker interpreter_lock(g_interpreter_mutex);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf("Initializing the ScriptInterpreter now\n");
+
+ lldb::ScriptLanguage script_lang = GetDebugger().GetScriptLanguage();
+ switch (script_lang)
+ {
+ case eScriptLanguagePython:
+#ifndef LLDB_DISABLE_PYTHON
+ m_script_interpreter_ap.reset (new ScriptInterpreterPython (*this));
+ break;
+#else
+ // Fall through to the None case when python is disabled
+#endif
+ case eScriptLanguageNone:
+ m_script_interpreter_ap.reset (new ScriptInterpreterNone (*this));
+ break;
+ };
+
+ return m_script_interpreter_ap.get();
+}
+
+
+
+bool
+CommandInterpreter::GetSynchronous ()
+{
+ return m_synchronous_execution;
+}
+
+void
+CommandInterpreter::SetSynchronous (bool value)
+{
+ m_synchronous_execution = value;
+}
+
+void
+CommandInterpreter::OutputFormattedHelpText (Stream &strm,
+ const char *word_text,
+ const char *separator,
+ const char *help_text,
+ size_t max_word_len)
+{
+ const uint32_t max_columns = m_debugger.GetTerminalWidth();
+
+ int indent_size = max_word_len + strlen (separator) + 2;
+
+ strm.IndentMore (indent_size);
+
+ StreamString text_strm;
+ text_strm.Printf ("%-*s %s %s", (int)max_word_len, word_text, separator, help_text);
+
+ size_t len = text_strm.GetSize();
+ const char *text = text_strm.GetData();
+ if (text[len - 1] == '\n')
+ {
+ text_strm.EOL();
+ len = text_strm.GetSize();
+ }
+
+ if (len < max_columns)
+ {
+ // Output it as a single line.
+ strm.Printf ("%s", text);
+ }
+ else
+ {
+ // We need to break it up into multiple lines.
+ bool first_line = true;
+ int text_width;
+ size_t start = 0;
+ size_t end = start;
+ const size_t final_end = strlen (text);
+
+ while (end < final_end)
+ {
+ if (first_line)
+ text_width = max_columns - 1;
+ else
+ text_width = max_columns - indent_size - 1;
+
+ // Don't start the 'text' on a space, since we're already outputting the indentation.
+ if (!first_line)
+ {
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+ }
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ assert (end > 0);
+ }
+
+ const size_t sub_len = end - start;
+ if (start != 0)
+ strm.EOL();
+ if (!first_line)
+ strm.Indent();
+ else
+ first_line = false;
+ assert (start <= final_end);
+ assert (start + sub_len <= final_end);
+ if (sub_len > 0)
+ strm.Write (text + start, sub_len);
+ start = end + 1;
+ }
+ }
+ strm.EOL();
+ strm.IndentLess(indent_size);
+}
+
+void
+CommandInterpreter::OutputHelpText (Stream &strm,
+ const char *word_text,
+ const char *separator,
+ const char *help_text,
+ uint32_t max_word_len)
+{
+ int indent_size = max_word_len + strlen (separator) + 2;
+
+ strm.IndentMore (indent_size);
+
+ StreamString text_strm;
+ text_strm.Printf ("%-*s %s %s", max_word_len, word_text, separator, help_text);
+
+ const uint32_t max_columns = m_debugger.GetTerminalWidth();
+
+ size_t len = text_strm.GetSize();
+ const char *text = text_strm.GetData();
+
+ uint32_t chars_left = max_columns;
+
+ for (uint32_t i = 0; i < len; i++)
+ {
+ if ((text[i] == ' ' && ::strchr((text+i+1), ' ') && chars_left < ::strchr((text+i+1), ' ')-(text+i)) || text[i] == '\n')
+ {
+ chars_left = max_columns - indent_size;
+ strm.EOL();
+ strm.Indent();
+ }
+ else
+ {
+ strm.PutChar(text[i]);
+ chars_left--;
+ }
+
+ }
+
+ strm.EOL();
+ strm.IndentLess(indent_size);
+}
+
+void
+CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found,
+ StringList &commands_help, bool search_builtin_commands, bool search_user_commands)
+{
+ CommandObject::CommandMap::const_iterator pos;
+
+ if (search_builtin_commands)
+ {
+ for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos)
+ {
+ const char *command_name = pos->first.c_str();
+ CommandObject *cmd_obj = pos->second.get();
+
+ if (cmd_obj->HelpTextContainsWord (search_word))
+ {
+ commands_found.AppendString (command_name);
+ commands_help.AppendString (cmd_obj->GetHelp());
+ }
+
+ if (cmd_obj->IsMultiwordObject())
+ cmd_obj->AproposAllSubCommands (command_name,
+ search_word,
+ commands_found,
+ commands_help);
+
+ }
+ }
+
+ if (search_user_commands)
+ {
+ for (pos = m_user_dict.begin(); pos != m_user_dict.end(); ++pos)
+ {
+ const char *command_name = pos->first.c_str();
+ CommandObject *cmd_obj = pos->second.get();
+
+ if (cmd_obj->HelpTextContainsWord (search_word))
+ {
+ commands_found.AppendString (command_name);
+ commands_help.AppendString (cmd_obj->GetHelp());
+ }
+
+ if (cmd_obj->IsMultiwordObject())
+ cmd_obj->AproposAllSubCommands (command_name,
+ search_word,
+ commands_found,
+ commands_help);
+
+ }
+ }
+}
+
+
+void
+CommandInterpreter::UpdateExecutionContext (ExecutionContext *override_context)
+{
+ if (override_context != NULL)
+ {
+ m_exe_ctx_ref = *override_context;
+ }
+ else
+ {
+ const bool adopt_selected = true;
+ m_exe_ctx_ref.SetTargetPtr (m_debugger.GetSelectedTarget().get(), adopt_selected);
+ }
+}
diff --git a/source/Interpreter/CommandObject.cpp b/source/Interpreter/CommandObject.cpp
new file mode 100644
index 000000000000..291dc4013573
--- /dev/null
+++ b/source/Interpreter/CommandObject.cpp
@@ -0,0 +1,1174 @@
+//===-- CommandObject.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/Interpreter/CommandObject.h"
+
+#include <string>
+#include <map>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/Options.h"
+
+// These are for the Sourcename completers.
+// FIXME: Make a separate file for the completers.
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObject
+//-------------------------------------------------------------------------
+
+CommandObject::CommandObject
+(
+ CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t flags
+) :
+ m_interpreter (interpreter),
+ m_cmd_name (name),
+ m_cmd_help_short (),
+ m_cmd_help_long (),
+ m_cmd_syntax (),
+ m_is_alias (false),
+ m_flags (flags),
+ m_arguments(),
+ m_command_override_callback (NULL),
+ m_command_override_baton (NULL)
+{
+ if (help && help[0])
+ m_cmd_help_short = help;
+ if (syntax && syntax[0])
+ m_cmd_syntax = syntax;
+}
+
+CommandObject::~CommandObject ()
+{
+}
+
+const char *
+CommandObject::GetHelp ()
+{
+ return m_cmd_help_short.c_str();
+}
+
+const char *
+CommandObject::GetHelpLong ()
+{
+ return m_cmd_help_long.c_str();
+}
+
+const char *
+CommandObject::GetSyntax ()
+{
+ if (m_cmd_syntax.length() == 0)
+ {
+ StreamString syntax_str;
+ syntax_str.Printf ("%s", GetCommandName());
+ if (GetOptions() != NULL)
+ syntax_str.Printf (" <cmd-options>");
+ if (m_arguments.size() > 0)
+ {
+ syntax_str.Printf (" ");
+ if (WantsRawCommandString() && GetOptions() && GetOptions()->NumCommandOptions())
+ syntax_str.Printf("-- ");
+ GetFormattedCommandArguments (syntax_str);
+ }
+ m_cmd_syntax = syntax_str.GetData ();
+ }
+
+ return m_cmd_syntax.c_str();
+}
+
+const char *
+CommandObject::GetCommandName ()
+{
+ return m_cmd_name.c_str();
+}
+
+void
+CommandObject::SetCommandName (const char *name)
+{
+ m_cmd_name = name;
+}
+
+void
+CommandObject::SetHelp (const char *cstr)
+{
+ m_cmd_help_short = cstr;
+}
+
+void
+CommandObject::SetHelpLong (const char *cstr)
+{
+ m_cmd_help_long = cstr;
+}
+
+void
+CommandObject::SetHelpLong (std::string str)
+{
+ m_cmd_help_long = str;
+}
+
+void
+CommandObject::SetSyntax (const char *cstr)
+{
+ m_cmd_syntax = cstr;
+}
+
+Options *
+CommandObject::GetOptions ()
+{
+ // By default commands don't have options unless this virtual function
+ // is overridden by base classes.
+ return NULL;
+}
+
+bool
+CommandObject::ParseOptions
+(
+ Args& args,
+ CommandReturnObject &result
+)
+{
+ // See if the subclass has options?
+ Options *options = GetOptions();
+ if (options != NULL)
+ {
+ Error error;
+ options->NotifyOptionParsingStarting();
+
+ // ParseOptions calls getopt_long_only, which always skips the zero'th item in the array and starts at position 1,
+ // so we need to push a dummy value into position zero.
+ args.Unshift("dummy_string");
+ error = args.ParseOptions (*options);
+
+ // The "dummy_string" will have already been removed by ParseOptions,
+ // so no need to remove it.
+
+ if (error.Success())
+ error = options->NotifyOptionParsingFinished();
+
+ if (error.Success())
+ {
+ if (options->VerifyOptions (result))
+ return true;
+ }
+ else
+ {
+ const char *error_cstr = error.AsCString();
+ if (error_cstr)
+ {
+ // We got an error string, lets use that
+ result.AppendError(error_cstr);
+ }
+ else
+ {
+ // No error string, output the usage information into result
+ options->GenerateOptionUsage (result.GetErrorStream(), this);
+ }
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ return true;
+}
+
+
+
+bool
+CommandObject::CheckRequirements (CommandReturnObject &result)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // Nothing should be stored in m_exe_ctx between running commands as m_exe_ctx
+ // has shared pointers to the target, process, thread and frame and we don't
+ // want any CommandObject instances to keep any of these objects around
+ // longer than for a single command. Every command should call
+ // CommandObject::Cleanup() after it has completed
+ assert (m_exe_ctx.GetTargetPtr() == NULL);
+ assert (m_exe_ctx.GetProcessPtr() == NULL);
+ assert (m_exe_ctx.GetThreadPtr() == NULL);
+ assert (m_exe_ctx.GetFramePtr() == NULL);
+#endif
+
+ // Lock down the interpreter's execution context prior to running the
+ // command so we guarantee the selected target, process, thread and frame
+ // can't go away during the execution
+ m_exe_ctx = m_interpreter.GetExecutionContext();
+
+ const uint32_t flags = GetFlags().Get();
+ if (flags & (eFlagRequiresTarget |
+ eFlagRequiresProcess |
+ eFlagRequiresThread |
+ eFlagRequiresFrame |
+ eFlagTryTargetAPILock ))
+ {
+
+ if ((flags & eFlagRequiresTarget) && !m_exe_ctx.HasTargetScope())
+ {
+ result.AppendError (GetInvalidTargetDescription());
+ return false;
+ }
+
+ if ((flags & eFlagRequiresProcess) && !m_exe_ctx.HasProcessScope())
+ {
+ result.AppendError (GetInvalidProcessDescription());
+ return false;
+ }
+
+ if ((flags & eFlagRequiresThread) && !m_exe_ctx.HasThreadScope())
+ {
+ result.AppendError (GetInvalidThreadDescription());
+ return false;
+ }
+
+ if ((flags & eFlagRequiresFrame) && !m_exe_ctx.HasFrameScope())
+ {
+ result.AppendError (GetInvalidFrameDescription());
+ return false;
+ }
+
+ if ((flags & eFlagRequiresRegContext) && (m_exe_ctx.GetRegisterContext() == NULL))
+ {
+ result.AppendError (GetInvalidRegContextDescription());
+ return false;
+ }
+
+ if (flags & eFlagTryTargetAPILock)
+ {
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ if (m_api_locker.TryLock (target->GetAPIMutex(), NULL) == false)
+ {
+ result.AppendError ("failed to get API lock");
+ return false;
+ }
+ }
+ }
+ }
+
+ if (GetFlags().AnySet (CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused))
+ {
+ Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process == NULL)
+ {
+ // A process that is not running is considered paused.
+ if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched))
+ {
+ result.AppendError ("Process must exist.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ else
+ {
+ StateType state = process->GetState();
+ switch (state)
+ {
+ case eStateInvalid:
+ case eStateSuspended:
+ case eStateCrashed:
+ case eStateStopped:
+ break;
+
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ if (GetFlags().Test(CommandObject::eFlagProcessMustBeLaunched))
+ {
+ result.AppendError ("Process must be launched.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ break;
+
+ case eStateRunning:
+ case eStateStepping:
+ if (GetFlags().Test(CommandObject::eFlagProcessMustBePaused))
+ {
+ result.AppendError ("Process is running. Use 'process interrupt' to pause execution.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+void
+CommandObject::Cleanup ()
+{
+ m_exe_ctx.Clear();
+ m_api_locker.Unlock();
+}
+
+
+class CommandDictCommandPartialMatch
+{
+ public:
+ CommandDictCommandPartialMatch (const char *match_str)
+ {
+ m_match_str = match_str;
+ }
+ bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const
+ {
+ // A NULL or empty string matches everything.
+ if (m_match_str == NULL || *m_match_str == '\0')
+ return true;
+
+ return map_element.first.find (m_match_str, 0) == 0;
+ }
+
+ private:
+ const char *m_match_str;
+};
+
+int
+CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str,
+ StringList &matches)
+{
+ int number_added = 0;
+ CommandDictCommandPartialMatch matcher(cmd_str);
+
+ CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher);
+
+ while (matching_cmds != in_map.end())
+ {
+ ++number_added;
+ matches.AppendString((*matching_cmds).first.c_str());
+ matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);;
+ }
+ return number_added;
+}
+
+int
+CommandObject::HandleCompletion
+(
+ Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches
+)
+{
+ // Default implmentation of WantsCompletion() is !WantsRawCommandString().
+ // Subclasses who want raw command string but desire, for example,
+ // argument completion should override WantsCompletion() to return true,
+ // instead.
+ if (WantsRawCommandString() && !WantsCompletion())
+ {
+ // FIXME: Abstract telling the completion to insert the completion character.
+ matches.Clear();
+ return -1;
+ }
+ else
+ {
+ // Can we do anything generic with the options?
+ Options *cur_options = GetOptions();
+ CommandReturnObject result;
+ OptionElementVector opt_element_vector;
+
+ if (cur_options != NULL)
+ {
+ // Re-insert the dummy command name string which will have been
+ // stripped off:
+ input.Unshift ("dummy-string");
+ cursor_index++;
+
+
+ // I stick an element on the end of the input, because if the last element is
+ // option that requires an argument, getopt_long_only will freak out.
+
+ input.AppendArgument ("<FAKE-VALUE>");
+
+ input.ParseArgsForCompletion (*cur_options, opt_element_vector, cursor_index);
+
+ input.DeleteArgumentAtIndex(input.GetArgumentCount() - 1);
+
+ bool handled_by_options;
+ handled_by_options = cur_options->HandleOptionCompletion (input,
+ opt_element_vector,
+ cursor_index,
+ cursor_char_position,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ if (handled_by_options)
+ return matches.GetSize();
+ }
+
+ // If we got here, the last word is not an option or an option argument.
+ return HandleArgumentCompletion (input,
+ cursor_index,
+ cursor_char_position,
+ opt_element_vector,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ }
+}
+
+bool
+CommandObject::HelpTextContainsWord (const char *search_word)
+{
+ std::string options_usage_help;
+
+ bool found_word = false;
+
+ const char *short_help = GetHelp();
+ const char *long_help = GetHelpLong();
+ const char *syntax_help = GetSyntax();
+
+ if (short_help && strcasestr (short_help, search_word))
+ found_word = true;
+ else if (long_help && strcasestr (long_help, search_word))
+ found_word = true;
+ else if (syntax_help && strcasestr (syntax_help, search_word))
+ found_word = true;
+
+ if (!found_word
+ && GetOptions() != NULL)
+ {
+ StreamString usage_help;
+ GetOptions()->GenerateOptionUsage (usage_help, this);
+ if (usage_help.GetSize() > 0)
+ {
+ const char *usage_text = usage_help.GetData();
+ if (strcasestr (usage_text, search_word))
+ found_word = true;
+ }
+ }
+
+ return found_word;
+}
+
+int
+CommandObject::GetNumArgumentEntries ()
+{
+ return m_arguments.size();
+}
+
+CommandObject::CommandArgumentEntry *
+CommandObject::GetArgumentEntryAtIndex (int idx)
+{
+ if (idx < m_arguments.size())
+ return &(m_arguments[idx]);
+
+ return NULL;
+}
+
+CommandObject::ArgumentTableEntry *
+CommandObject::FindArgumentDataByType (CommandArgumentType arg_type)
+{
+ const ArgumentTableEntry *table = CommandObject::GetArgumentTable();
+
+ for (int i = 0; i < eArgTypeLastArg; ++i)
+ if (table[i].arg_type == arg_type)
+ return (ArgumentTableEntry *) &(table[i]);
+
+ return NULL;
+}
+
+void
+CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, CommandInterpreter &interpreter)
+{
+ const ArgumentTableEntry* table = CommandObject::GetArgumentTable();
+ ArgumentTableEntry *entry = (ArgumentTableEntry *) &(table[arg_type]);
+
+ // The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up...
+
+ if (entry->arg_type != arg_type)
+ entry = CommandObject::FindArgumentDataByType (arg_type);
+
+ if (!entry)
+ return;
+
+ StreamString name_str;
+ name_str.Printf ("<%s>", entry->arg_name);
+
+ if (entry->help_function)
+ {
+ const char* help_text = entry->help_function();
+ if (!entry->help_function.self_formatting)
+ {
+ interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", help_text,
+ name_str.GetSize());
+ }
+ else
+ {
+ interpreter.OutputHelpText(str, name_str.GetData(), "--", help_text,
+ name_str.GetSize());
+ }
+ }
+ else
+ interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", entry->help_text, name_str.GetSize());
+}
+
+const char *
+CommandObject::GetArgumentName (CommandArgumentType arg_type)
+{
+ ArgumentTableEntry *entry = (ArgumentTableEntry *) &(CommandObject::GetArgumentTable()[arg_type]);
+
+ // The table is *supposed* to be kept in arg_type order, but someone *could* have messed it up...
+
+ if (entry->arg_type != arg_type)
+ entry = CommandObject::FindArgumentDataByType (arg_type);
+
+ if (entry)
+ return entry->arg_name;
+
+ StreamString str;
+ str << "Arg name for type (" << arg_type << ") not in arg table!";
+ return str.GetData();
+}
+
+bool
+CommandObject::IsPairType (ArgumentRepetitionType arg_repeat_type)
+{
+ if ((arg_repeat_type == eArgRepeatPairPlain)
+ || (arg_repeat_type == eArgRepeatPairOptional)
+ || (arg_repeat_type == eArgRepeatPairPlus)
+ || (arg_repeat_type == eArgRepeatPairStar)
+ || (arg_repeat_type == eArgRepeatPairRange)
+ || (arg_repeat_type == eArgRepeatPairRangeOptional))
+ return true;
+
+ return false;
+}
+
+static CommandObject::CommandArgumentEntry
+OptSetFiltered(uint32_t opt_set_mask, CommandObject::CommandArgumentEntry &cmd_arg_entry)
+{
+ CommandObject::CommandArgumentEntry ret_val;
+ for (unsigned i = 0; i < cmd_arg_entry.size(); ++i)
+ if (opt_set_mask & cmd_arg_entry[i].arg_opt_set_association)
+ ret_val.push_back(cmd_arg_entry[i]);
+ return ret_val;
+}
+
+// Default parameter value of opt_set_mask is LLDB_OPT_SET_ALL, which means take
+// all the argument data into account. On rare cases where some argument sticks
+// with certain option sets, this function returns the option set filtered args.
+void
+CommandObject::GetFormattedCommandArguments (Stream &str, uint32_t opt_set_mask)
+{
+ int num_args = m_arguments.size();
+ for (int i = 0; i < num_args; ++i)
+ {
+ if (i > 0)
+ str.Printf (" ");
+ CommandArgumentEntry arg_entry =
+ opt_set_mask == LLDB_OPT_SET_ALL ? m_arguments[i]
+ : OptSetFiltered(opt_set_mask, m_arguments[i]);
+ int num_alternatives = arg_entry.size();
+
+ if ((num_alternatives == 2)
+ && IsPairType (arg_entry[0].arg_repetition))
+ {
+ const char *first_name = GetArgumentName (arg_entry[0].arg_type);
+ const char *second_name = GetArgumentName (arg_entry[1].arg_type);
+ switch (arg_entry[0].arg_repetition)
+ {
+ case eArgRepeatPairPlain:
+ str.Printf ("<%s> <%s>", first_name, second_name);
+ break;
+ case eArgRepeatPairOptional:
+ str.Printf ("[<%s> <%s>]", first_name, second_name);
+ break;
+ case eArgRepeatPairPlus:
+ str.Printf ("<%s> <%s> [<%s> <%s> [...]]", first_name, second_name, first_name, second_name);
+ break;
+ case eArgRepeatPairStar:
+ str.Printf ("[<%s> <%s> [<%s> <%s> [...]]]", first_name, second_name, first_name, second_name);
+ break;
+ case eArgRepeatPairRange:
+ str.Printf ("<%s_1> <%s_1> ... <%s_n> <%s_n>", first_name, second_name, first_name, second_name);
+ break;
+ case eArgRepeatPairRangeOptional:
+ str.Printf ("[<%s_1> <%s_1> ... <%s_n> <%s_n>]", first_name, second_name, first_name, second_name);
+ break;
+ // Explicitly test for all the rest of the cases, so if new types get added we will notice the
+ // missing case statement(s).
+ case eArgRepeatPlain:
+ case eArgRepeatOptional:
+ case eArgRepeatPlus:
+ case eArgRepeatStar:
+ case eArgRepeatRange:
+ // These should not be reached, as they should fail the IsPairType test above.
+ break;
+ }
+ }
+ else
+ {
+ StreamString names;
+ for (int j = 0; j < num_alternatives; ++j)
+ {
+ if (j > 0)
+ names.Printf (" | ");
+ names.Printf ("%s", GetArgumentName (arg_entry[j].arg_type));
+ }
+ switch (arg_entry[0].arg_repetition)
+ {
+ case eArgRepeatPlain:
+ str.Printf ("<%s>", names.GetData());
+ break;
+ case eArgRepeatPlus:
+ str.Printf ("<%s> [<%s> [...]]", names.GetData(), names.GetData());
+ break;
+ case eArgRepeatStar:
+ str.Printf ("[<%s> [<%s> [...]]]", names.GetData(), names.GetData());
+ break;
+ case eArgRepeatOptional:
+ str.Printf ("[<%s>]", names.GetData());
+ break;
+ case eArgRepeatRange:
+ str.Printf ("<%s_1> .. <%s_n>", names.GetData(), names.GetData());
+ break;
+ // Explicitly test for all the rest of the cases, so if new types get added we will notice the
+ // missing case statement(s).
+ case eArgRepeatPairPlain:
+ case eArgRepeatPairOptional:
+ case eArgRepeatPairPlus:
+ case eArgRepeatPairStar:
+ case eArgRepeatPairRange:
+ case eArgRepeatPairRangeOptional:
+ // These should not be hit, as they should pass the IsPairType test above, and control should
+ // have gone into the other branch of the if statement.
+ break;
+ }
+ }
+ }
+}
+
+CommandArgumentType
+CommandObject::LookupArgumentName (const char *arg_name)
+{
+ CommandArgumentType return_type = eArgTypeLastArg;
+
+ std::string arg_name_str (arg_name);
+ size_t len = arg_name_str.length();
+ if (arg_name[0] == '<'
+ && arg_name[len-1] == '>')
+ arg_name_str = arg_name_str.substr (1, len-2);
+
+ const ArgumentTableEntry *table = GetArgumentTable();
+ for (int i = 0; i < eArgTypeLastArg; ++i)
+ if (arg_name_str.compare (table[i].arg_name) == 0)
+ return_type = g_arguments_data[i].arg_type;
+
+ return return_type;
+}
+
+static const char *
+RegisterNameHelpTextCallback ()
+{
+ return "Register names can be specified using the architecture specific names. "
+ "They can also be specified using generic names. Not all generic entities have "
+ "registers backing them on all architectures. When they don't the generic name "
+ "will return an error.\n"
+ "The generic names defined in lldb are:\n"
+ "\n"
+ "pc - program counter register\n"
+ "ra - return address register\n"
+ "fp - frame pointer register\n"
+ "sp - stack pointer register\n"
+ "flags - the flags register\n"
+ "arg{1-6} - integer argument passing registers.\n";
+}
+
+static const char *
+BreakpointIDHelpTextCallback ()
+{
+ return "Breakpoint ID's consist major and minor numbers; the major number "
+ "corresponds to the single entity that was created with a 'breakpoint set' "
+ "command; the minor numbers correspond to all the locations that were actually "
+ "found/set based on the major breakpoint. A full breakpoint ID might look like "
+ "3.14, meaning the 14th location set for the 3rd breakpoint. You can specify "
+ "all the locations of a breakpoint by just indicating the major breakpoint "
+ "number. A valid breakpoint id consists either of just the major id number, "
+ "or the major number, a dot, and the location number (e.g. 3 or 3.2 could "
+ "both be valid breakpoint ids).";
+}
+
+static const char *
+BreakpointIDRangeHelpTextCallback ()
+{
+ return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. "
+ "This can be done through several mechanisms. The easiest way is to just "
+ "enter a space-separated list of breakpoint ids. To specify all the "
+ "breakpoint locations under a major breakpoint, you can use the major "
+ "breakpoint number followed by '.*', eg. '5.*' means all the locations under "
+ "breakpoint 5. You can also indicate a range of breakpoints by using "
+ "<start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can "
+ "be any valid breakpoint ids. It is not legal, however, to specify a range "
+ "using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7"
+ " is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal.";
+}
+
+static const char *
+GDBFormatHelpTextCallback ()
+{
+ return "A GDB format consists of a repeat count, a format letter and a size letter. "
+ "The repeat count is optional and defaults to 1. The format letter is optional "
+ "and defaults to the previous format that was used. The size letter is optional "
+ "and defaults to the previous size that was used.\n"
+ "\n"
+ "Format letters include:\n"
+ "o - octal\n"
+ "x - hexadecimal\n"
+ "d - decimal\n"
+ "u - unsigned decimal\n"
+ "t - binary\n"
+ "f - float\n"
+ "a - address\n"
+ "i - instruction\n"
+ "c - char\n"
+ "s - string\n"
+ "T - OSType\n"
+ "A - float as hex\n"
+ "\n"
+ "Size letters include:\n"
+ "b - 1 byte (byte)\n"
+ "h - 2 bytes (halfword)\n"
+ "w - 4 bytes (word)\n"
+ "g - 8 bytes (giant)\n"
+ "\n"
+ "Example formats:\n"
+ "32xb - show 32 1 byte hexadecimal integer values\n"
+ "16xh - show 16 2 byte hexadecimal integer values\n"
+ "64 - show 64 2 byte hexadecimal integer values (format and size from the last format)\n"
+ "dw - show 1 4 byte decimal integer value\n"
+ ;
+}
+
+static const char *
+FormatHelpTextCallback ()
+{
+
+ static char* help_text_ptr = NULL;
+
+ if (help_text_ptr)
+ return help_text_ptr;
+
+ StreamString sstr;
+ sstr << "One of the format names (or one-character names) that can be used to show a variable's value:\n";
+ for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
+ {
+ if (f != eFormatDefault)
+ sstr.PutChar('\n');
+
+ char format_char = FormatManager::GetFormatAsFormatChar(f);
+ if (format_char)
+ sstr.Printf("'%c' or ", format_char);
+
+ sstr.Printf ("\"%s\"", FormatManager::GetFormatAsCString(f));
+ }
+
+ sstr.Flush();
+
+ std::string data = sstr.GetString();
+
+ help_text_ptr = new char[data.length()+1];
+
+ data.copy(help_text_ptr, data.length());
+
+ return help_text_ptr;
+}
+
+static const char *
+LanguageTypeHelpTextCallback ()
+{
+ static char* help_text_ptr = NULL;
+
+ if (help_text_ptr)
+ return help_text_ptr;
+
+ StreamString sstr;
+ sstr << "One of the following languages:\n";
+
+ for (unsigned int l = eLanguageTypeUnknown; l < eNumLanguageTypes; ++l)
+ {
+ sstr << " " << LanguageRuntime::GetNameForLanguageType(static_cast<LanguageType>(l)) << "\n";
+ }
+
+ sstr.Flush();
+
+ std::string data = sstr.GetString();
+
+ help_text_ptr = new char[data.length()+1];
+
+ data.copy(help_text_ptr, data.length());
+
+ return help_text_ptr;
+}
+
+static const char *
+SummaryStringHelpTextCallback()
+{
+ return
+ "A summary string is a way to extract information from variables in order to present them using a summary.\n"
+ "Summary strings contain static text, variables, scopes and control sequences:\n"
+ " - Static text can be any sequence of non-special characters, i.e. anything but '{', '}', '$', or '\\'.\n"
+ " - Variables are sequences of characters beginning with ${, ending with } and that contain symbols in the format described below.\n"
+ " - Scopes are any sequence of text between { and }. Anything included in a scope will only appear in the output summary if there were no errors.\n"
+ " - Control sequences are the usual C/C++ '\\a', '\\n', ..., plus '\\$', '\\{' and '\\}'.\n"
+ "A summary string works by copying static text verbatim, turning control sequences into their character counterpart, expanding variables and trying to expand scopes.\n"
+ "A variable is expanded by giving it a value other than its textual representation, and the way this is done depends on what comes after the ${ marker.\n"
+ "The most common sequence if ${var followed by an expression path, which is the text one would type to access a member of an aggregate types, given a variable of that type"
+ " (e.g. if type T has a member named x, which has a member named y, and if t is of type T, the expression path would be .x.y and the way to fit that into a summary string would be"
+ " ${var.x.y}). You can also use ${*var followed by an expression path and in that case the object referred by the path will be dereferenced before being displayed."
+ " If the object is not a pointer, doing so will cause an error. For additional details on expression paths, you can type 'help expr-path'. \n"
+ "By default, summary strings attempt to display the summary for any variable they reference, and if that fails the value. If neither can be shown, nothing is displayed."
+ "In a summary string, you can also use an array index [n], or a slice-like range [n-m]. This can have two different meanings depending on what kind of object the expression"
+ " path refers to:\n"
+ " - if it is a scalar type (any basic type like int, float, ...) the expression is a bitfield, i.e. the bits indicated by the indexing operator are extracted out of the number"
+ " and displayed as an individual variable\n"
+ " - if it is an array or pointer the array items indicated by the indexing operator are shown as the result of the variable. if the expression is an array, real array items are"
+ " printed; if it is a pointer, the pointer-as-array syntax is used to obtain the values (this means, the latter case can have no range checking)\n"
+ "If you are trying to display an array for which the size is known, you can also use [] instead of giving an exact range. This has the effect of showing items 0 thru size - 1.\n"
+ "Additionally, a variable can contain an (optional) format code, as in ${var.x.y%code}, where code can be any of the valid formats described in 'help format', or one of the"
+ " special symbols only allowed as part of a variable:\n"
+ " %V: show the value of the object by default\n"
+ " %S: show the summary of the object by default\n"
+ " %@: show the runtime-provided object description (for Objective-C, it calls NSPrintForDebugger; for C/C++ it does nothing)\n"
+ " %L: show the location of the object (memory address or a register name)\n"
+ " %#: show the number of children of the object\n"
+ " %T: show the type of the object\n"
+ "Another variable that you can use in summary strings is ${svar . This sequence works exactly like ${var, including the fact that ${*svar is an allowed sequence, but uses"
+ " the object's synthetic children provider instead of the actual objects. For instance, if you are using STL synthetic children providers, the following summary string would"
+ " count the number of actual elements stored in an std::list:\n"
+ "type summary add -s \"${svar%#}\" -x \"std::list<\"";
+}
+
+static const char *
+ExprPathHelpTextCallback()
+{
+ return
+ "An expression path is the sequence of symbols that is used in C/C++ to access a member variable of an aggregate object (class).\n"
+ "For instance, given a class:\n"
+ " class foo {\n"
+ " int a;\n"
+ " int b; .\n"
+ " foo* next;\n"
+ " };\n"
+ "the expression to read item b in the item pointed to by next for foo aFoo would be aFoo.next->b.\n"
+ "Given that aFoo could just be any object of type foo, the string '.next->b' is the expression path, because it can be attached to any foo instance to achieve the effect.\n"
+ "Expression paths in LLDB include dot (.) and arrow (->) operators, and most commands using expression paths have ways to also accept the star (*) operator.\n"
+ "The meaning of these operators is the same as the usual one given to them by the C/C++ standards.\n"
+ "LLDB also has support for indexing ([ ]) in expression paths, and extends the traditional meaning of the square brackets operator to allow bitfield extraction:\n"
+ "for objects of native types (int, float, char, ...) saying '[n-m]' as an expression path (where n and m are any positive integers, e.g. [3-5]) causes LLDB to extract"
+ " bits n thru m from the value of the variable. If n == m, [n] is also allowed as a shortcut syntax. For arrays and pointers, expression paths can only contain one index"
+ " and the meaning of the operation is the same as the one defined by C/C++ (item extraction). Some commands extend bitfield-like syntax for arrays and pointers with the"
+ " meaning of array slicing (taking elements n thru m inside the array or pointed-to memory).";
+}
+
+void
+CommandObject::GenerateHelpText (CommandReturnObject &result)
+{
+ GenerateHelpText(result.GetOutputStream());
+
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+}
+
+void
+CommandObject::GenerateHelpText (Stream &output_strm)
+{
+ CommandInterpreter& interpreter = GetCommandInterpreter();
+ if (GetOptions() != NULL)
+ {
+ if (WantsRawCommandString())
+ {
+ std::string help_text (GetHelp());
+ help_text.append (" This command takes 'raw' input (no need to quote stuff).");
+ interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
+ }
+ else
+ interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1);
+ output_strm.Printf ("\nSyntax: %s\n", GetSyntax());
+ GetOptions()->GenerateOptionUsage (output_strm, this);
+ const char *long_help = GetHelpLong();
+ if ((long_help != NULL)
+ && (strlen (long_help) > 0))
+ output_strm.Printf ("\n%s", long_help);
+ if (WantsRawCommandString() && !WantsCompletion())
+ {
+ // Emit the message about using ' -- ' between the end of the command options and the raw input
+ // conditionally, i.e., only if the command object does not want completion.
+ interpreter.OutputFormattedHelpText (output_strm, "", "",
+ "\nIMPORTANT NOTE: Because this command takes 'raw' input, if you use any command options"
+ " you must use ' -- ' between the end of the command options and the beginning of the raw input.", 1);
+ }
+ else if (GetNumArgumentEntries() > 0
+ && GetOptions()
+ && GetOptions()->NumCommandOptions() > 0)
+ {
+ // Also emit a warning about using "--" in case you are using a command that takes options and arguments.
+ interpreter.OutputFormattedHelpText (output_strm, "", "",
+ "\nThis command takes options and free-form arguments. If your arguments resemble"
+ " option specifiers (i.e., they start with a - or --), you must use ' -- ' between"
+ " the end of the command options and the beginning of the arguments.", 1);
+ }
+ }
+ else if (IsMultiwordObject())
+ {
+ if (WantsRawCommandString())
+ {
+ std::string help_text (GetHelp());
+ help_text.append (" This command takes 'raw' input (no need to quote stuff).");
+ interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
+ }
+ else
+ interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1);
+ GenerateHelpText (output_strm);
+ }
+ else
+ {
+ const char *long_help = GetHelpLong();
+ if ((long_help != NULL)
+ && (strlen (long_help) > 0))
+ output_strm.Printf ("%s", long_help);
+ else if (WantsRawCommandString())
+ {
+ std::string help_text (GetHelp());
+ help_text.append (" This command takes 'raw' input (no need to quote stuff).");
+ interpreter.OutputFormattedHelpText (output_strm, "", "", help_text.c_str(), 1);
+ }
+ else
+ interpreter.OutputFormattedHelpText (output_strm, "", "", GetHelp(), 1);
+ output_strm.Printf ("\nSyntax: %s\n", GetSyntax());
+ }
+}
+
+void
+CommandObject::AddIDsArgumentData(CommandArgumentEntry &arg, CommandArgumentType ID, CommandArgumentType IDRange)
+{
+ CommandArgumentData id_arg;
+ CommandArgumentData id_range_arg;
+
+ // Create the first variant for the first (and only) argument for this command.
+ id_arg.arg_type = ID;
+ id_arg.arg_repetition = eArgRepeatOptional;
+
+ // Create the second variant for the first (and only) argument for this command.
+ id_range_arg.arg_type = IDRange;
+ id_range_arg.arg_repetition = eArgRepeatOptional;
+
+ // The first (and only) argument for this command could be either an id or an id_range.
+ // Push both variants into the entry for the first argument for this command.
+ arg.push_back(id_arg);
+ arg.push_back(id_range_arg);
+}
+
+const char *
+CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
+{
+ if (arg_type >=0 && arg_type < eArgTypeLastArg)
+ return g_arguments_data[arg_type].arg_name;
+ return NULL;
+
+}
+
+const char *
+CommandObject::GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type)
+{
+ if (arg_type >=0 && arg_type < eArgTypeLastArg)
+ return g_arguments_data[arg_type].help_text;
+ return NULL;
+}
+
+bool
+CommandObjectParsed::Execute (const char *args_string, CommandReturnObject &result)
+{
+ CommandOverrideCallback command_callback = GetOverrideCallback();
+ bool handled = false;
+ Args cmd_args (args_string);
+ if (command_callback)
+ {
+ Args full_args (GetCommandName ());
+ full_args.AppendArguments(cmd_args);
+ handled = command_callback (GetOverrideCallbackBaton(), full_args.GetConstArgumentVector());
+ }
+ if (!handled)
+ {
+ for (size_t i = 0; i < cmd_args.GetArgumentCount(); ++i)
+ {
+ const char *tmp_str = cmd_args.GetArgumentAtIndex (i);
+ if (tmp_str[0] == '`') // back-quote
+ cmd_args.ReplaceArgumentAtIndex (i, m_interpreter.ProcessEmbeddedScriptCommands (tmp_str));
+ }
+
+ if (CheckRequirements(result))
+ {
+ if (ParseOptions (cmd_args, result))
+ {
+ // Call the command-specific version of 'Execute', passing it the already processed arguments.
+ handled = DoExecute (cmd_args, result);
+ }
+ }
+
+ Cleanup();
+ }
+ return handled;
+}
+
+bool
+CommandObjectRaw::Execute (const char *args_string, CommandReturnObject &result)
+{
+ CommandOverrideCallback command_callback = GetOverrideCallback();
+ bool handled = false;
+ if (command_callback)
+ {
+ std::string full_command (GetCommandName ());
+ full_command += ' ';
+ full_command += args_string;
+ const char *argv[2] = { NULL, NULL };
+ argv[0] = full_command.c_str();
+ handled = command_callback (GetOverrideCallbackBaton(), argv);
+ }
+ if (!handled)
+ {
+ if (CheckRequirements(result))
+ handled = DoExecute (args_string, result);
+
+ Cleanup();
+ }
+ return handled;
+}
+
+static
+const char *arch_helper()
+{
+ static StreamString g_archs_help;
+ if (g_archs_help.Empty())
+ {
+ StringList archs;
+ ArchSpec::AutoComplete(NULL, archs);
+ g_archs_help.Printf("These are the supported architecture names:\n");
+ archs.Join("\n", g_archs_help);
+ }
+ return g_archs_help.GetData();
+}
+
+CommandObject::ArgumentTableEntry
+CommandObject::g_arguments_data[] =
+{
+ { eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { NULL, false }, "A valid address in the target program's execution space." },
+ { eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { NULL, false }, "An expression that resolves to an address." },
+ { eArgTypeAliasName, "alias-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of an abbreviation (alias) for a debugger command." },
+ { eArgTypeAliasOptions, "options-for-aliased-command", CommandCompletions::eNoCompletion, { NULL, false }, "Command options to be used as part of an alias (abbreviation) definition. (See 'help commands alias' for more information.)" },
+ { eArgTypeArchitecture, "arch", CommandCompletions::eArchitectureCompletion, { arch_helper, true }, "The architecture name, e.g. i386 or x86_64." },
+ { eArgTypeBoolean, "boolean", CommandCompletions::eNoCompletion, { NULL, false }, "A Boolean value: 'true' or 'false'" },
+ { eArgTypeBreakpointID, "breakpt-id", CommandCompletions::eNoCompletion, { BreakpointIDHelpTextCallback, false }, NULL },
+ { eArgTypeBreakpointIDRange, "breakpt-id-list", CommandCompletions::eNoCompletion, { BreakpointIDRangeHelpTextCallback, false }, NULL },
+ { eArgTypeByteSize, "byte-size", CommandCompletions::eNoCompletion, { NULL, false }, "Number of bytes to use." },
+ { eArgTypeClassName, "class-name", CommandCompletions::eNoCompletion, { NULL, false }, "Then name of a class from the debug information in the program." },
+ { eArgTypeCommandName, "cmd-name", CommandCompletions::eNoCompletion, { NULL, false }, "A debugger command (may be multiple words), without any options or arguments." },
+ { eArgTypeCount, "count", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." },
+ { eArgTypeDirectoryName, "directory", CommandCompletions::eDiskDirectoryCompletion, { NULL, false }, "A directory name." },
+ { eArgTypeDisassemblyFlavor, "disassembly-flavor", CommandCompletions::eNoCompletion, { NULL, false }, "A disassembly flavor recognized by your disassembly plugin. Currently the only valid options are \"att\" and \"intel\" for Intel targets" },
+ { eArgTypeEndAddress, "end-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeExpressionPath, "expr-path", CommandCompletions::eNoCompletion, { ExprPathHelpTextCallback, true }, NULL },
+ { eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, { NULL, false }, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
+ { eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, { NULL, false }, "The name of a file (can include path)." },
+ { eArgTypeFormat, "format", CommandCompletions::eNoCompletion, { FormatHelpTextCallback, true }, NULL },
+ { eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into a thread's list of frames." },
+ { eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function." },
+ { eArgTypeFunctionOrSymbol, "function-or-symbol", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a function or symbol." },
+ { eArgTypeGDBFormat, "gdb-format", CommandCompletions::eNoCompletion, { GDBFormatHelpTextCallback, true }, NULL },
+ { eArgTypeIndex, "index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a list." },
+ { eArgTypeLanguage, "language", CommandCompletions::eNoCompletion, { LanguageTypeHelpTextCallback, true }, NULL },
+ { eArgTypeLineNum, "linenum", CommandCompletions::eNoCompletion, { NULL, false }, "Line number in a source file." },
+ { eArgTypeLogCategory, "log-category", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a category within a log channel, e.g. all (try \"log list\" to see a list of all channels and their categories." },
+ { eArgTypeLogChannel, "log-channel", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a log channel, e.g. process.gdb-remote (try \"log list\" to see a list of all channels and their categories)." },
+ { eArgTypeMethod, "method", CommandCompletions::eNoCompletion, { NULL, false }, "A C++ method name." },
+ { eArgTypeName, "name", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeNewPathPrefix, "new-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeNumLines, "num-lines", CommandCompletions::eNoCompletion, { NULL, false }, "The number of lines to use." },
+ { eArgTypeNumberPerLine, "number-per-line", CommandCompletions::eNoCompletion, { NULL, false }, "The number of items per line to display." },
+ { eArgTypeOffset, "offset", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeOldPathPrefix, "old-path-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeOneLiner, "one-line-command", CommandCompletions::eNoCompletion, { NULL, false }, "A command that is entered as a single line of text." },
+ { eArgTypePid, "pid", CommandCompletions::eNoCompletion, { NULL, false }, "The process ID number." },
+ { eArgTypePlugin, "plugin", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeProcessName, "process-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the process." },
+ { eArgTypePythonClass, "python-class", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python class." },
+ { eArgTypePythonFunction, "python-function", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a Python function." },
+ { eArgTypePythonScript, "python-script", CommandCompletions::eNoCompletion, { NULL, false }, "Source code written in Python." },
+ { eArgTypeQueueName, "queue-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of the thread queue." },
+ { eArgTypeRegisterName, "register-name", CommandCompletions::eNoCompletion, { RegisterNameHelpTextCallback, true }, NULL },
+ { eArgTypeRegularExpression, "regular-expression", CommandCompletions::eNoCompletion, { NULL, false }, "A regular expression." },
+ { eArgTypeRunArgs, "run-args", CommandCompletions::eNoCompletion, { NULL, false }, "Arguments to be passed to the target program when it starts executing." },
+ { eArgTypeRunMode, "run-mode", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeScriptedCommandSynchronicity, "script-cmd-synchronicity", CommandCompletions::eNoCompletion, { NULL, false }, "The synchronicity to use to run scripted commands with regard to LLDB event system." },
+ { eArgTypeScriptLang, "script-language", CommandCompletions::eNoCompletion, { NULL, false }, "The scripting language to be used for script-based commands. Currently only Python is valid." },
+ { eArgTypeSearchWord, "search-word", CommandCompletions::eNoCompletion, { NULL, false }, "The word for which you wish to search for information about." },
+ { eArgTypeSelector, "selector", CommandCompletions::eNoCompletion, { NULL, false }, "An Objective-C selector name." },
+ { eArgTypeSettingIndex, "setting-index", CommandCompletions::eNoCompletion, { NULL, false }, "An index into a settings variable that is an array (try 'settings list' to see all the possible settings variables and their types)." },
+ { eArgTypeSettingKey, "setting-key", CommandCompletions::eNoCompletion, { NULL, false }, "A key into a settings variables that is a dictionary (try 'settings list' to see all the possible settings variables and their types)." },
+ { eArgTypeSettingPrefix, "setting-prefix", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable up to a dot ('.'), e.g. 'target.process.'" },
+ { eArgTypeSettingVariableName, "setting-variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a settable internal debugger variable. Type 'settings list' to see a complete list of such variables." },
+ { eArgTypeShlibName, "shlib-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a shared library." },
+ { eArgTypeSourceFile, "source-file", CommandCompletions::eSourceFileCompletion, { NULL, false }, "The name of a source file.." },
+ { eArgTypeSortOrder, "sort-order", CommandCompletions::eNoCompletion, { NULL, false }, "Specify a sort order when dumping lists." },
+ { eArgTypeStartAddress, "start-address", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeSummaryString, "summary-string", CommandCompletions::eNoCompletion, { SummaryStringHelpTextCallback, true }, NULL },
+ { eArgTypeSymbol, "symbol", CommandCompletions::eSymbolCompletion, { NULL, false }, "Any symbol name (function name, variable, argument, etc.)" },
+ { eArgTypeThreadID, "thread-id", CommandCompletions::eNoCompletion, { NULL, false }, "Thread ID number." },
+ { eArgTypeThreadIndex, "thread-index", CommandCompletions::eNoCompletion, { NULL, false }, "Index into the process' list of threads." },
+ { eArgTypeThreadName, "thread-name", CommandCompletions::eNoCompletion, { NULL, false }, "The thread's name." },
+ { eArgTypeUnsignedInteger, "unsigned-integer", CommandCompletions::eNoCompletion, { NULL, false }, "An unsigned integer." },
+ { eArgTypeUnixSignal, "unix-signal", CommandCompletions::eNoCompletion, { NULL, false }, "A valid Unix signal name or number (e.g. SIGKILL, KILL or 9)." },
+ { eArgTypeVarName, "variable-name", CommandCompletions::eNoCompletion, { NULL, false }, "The name of a variable in your program." },
+ { eArgTypeValue, "value", CommandCompletions::eNoCompletion, { NULL, false }, "A value could be anything, depending on where and how it is used." },
+ { eArgTypeWidth, "width", CommandCompletions::eNoCompletion, { NULL, false }, "Help text goes here." },
+ { eArgTypeNone, "none", CommandCompletions::eNoCompletion, { NULL, false }, "No help available for this." },
+ { eArgTypePlatform, "platform-name", CommandCompletions::ePlatformPluginCompletion, { NULL, false }, "The name of an installed platform plug-in . Type 'platform list' to see a complete list of installed platforms." },
+ { eArgTypeWatchpointID, "watchpt-id", CommandCompletions::eNoCompletion, { NULL, false }, "Watchpoint IDs are positive integers." },
+ { eArgTypeWatchpointIDRange, "watchpt-id-list", CommandCompletions::eNoCompletion, { NULL, false }, "For example, '1-3' or '1 to 3'." },
+ { eArgTypeWatchType, "watch-type", CommandCompletions::eNoCompletion, { NULL, false }, "Specify the type for a watchpoint." }
+};
+
+const CommandObject::ArgumentTableEntry*
+CommandObject::GetArgumentTable ()
+{
+ // If this assertion fires, then the table above is out of date with the CommandArgumentType enumeration
+ assert ((sizeof (CommandObject::g_arguments_data) / sizeof (CommandObject::ArgumentTableEntry)) == eArgTypeLastArg);
+ return CommandObject::g_arguments_data;
+}
+
+
diff --git a/source/Interpreter/CommandObjectRegexCommand.cpp b/source/Interpreter/CommandObjectRegexCommand.cpp
new file mode 100644
index 000000000000..59cf1f05fb65
--- /dev/null
+++ b/source/Interpreter/CommandObjectRegexCommand.cpp
@@ -0,0 +1,150 @@
+//===-- CommandObjectRegexCommand.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/Interpreter/CommandObjectRegexCommand.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// CommandObjectRegexCommand constructor
+//----------------------------------------------------------------------
+CommandObjectRegexCommand::CommandObjectRegexCommand
+(
+ CommandInterpreter &interpreter,
+ const char *name,
+ const char *help,
+ const char *syntax,
+ uint32_t max_matches,
+ uint32_t completion_type_mask
+) :
+ CommandObjectRaw (interpreter, name, help, syntax),
+ m_max_matches (max_matches),
+ m_completion_type_mask (completion_type_mask),
+ m_entries ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CommandObjectRegexCommand::~CommandObjectRegexCommand()
+{
+}
+
+
+bool
+CommandObjectRegexCommand::DoExecute
+(
+ const char *command,
+ CommandReturnObject &result
+)
+{
+ if (command)
+ {
+ EntryCollection::const_iterator pos, end = m_entries.end();
+ for (pos = m_entries.begin(); pos != end; ++pos)
+ {
+ RegularExpression::Match regex_match(m_max_matches);
+
+ if (pos->regex.Execute (command, &regex_match))
+ {
+ std::string new_command(pos->command);
+ std::string match_str;
+ char percent_var[8];
+ size_t idx, percent_var_idx;
+ for (uint32_t match_idx=1; match_idx <= m_max_matches; ++match_idx)
+ {
+ if (regex_match.GetMatchAtIndex (command, match_idx, match_str))
+ {
+ const int percent_var_len = ::snprintf (percent_var, sizeof(percent_var), "%%%u", match_idx);
+ for (idx = 0; (percent_var_idx = new_command.find(percent_var, idx)) != std::string::npos; )
+ {
+ new_command.erase(percent_var_idx, percent_var_len);
+ new_command.insert(percent_var_idx, match_str);
+ idx += percent_var_idx + match_str.size();
+ }
+ }
+ }
+ // Interpret the new command and return this as the result!
+ if (m_interpreter.GetExpandRegexAliases())
+ result.GetOutputStream().Printf("%s\n", new_command.c_str());
+ // Pass in true for "no context switching". The command that called us should have set up the context
+ // appropriately, we shouldn't have to redo that.
+ return m_interpreter.HandleCommand(new_command.c_str(), eLazyBoolCalculate, result, NULL, true, true);
+ }
+ }
+ result.SetStatus(eReturnStatusFailed);
+ if (GetSyntax() != NULL)
+ result.AppendError (GetSyntax());
+ else
+ result.AppendErrorWithFormat ("Command contents '%s' failed to match any regular expression in the '%s' regex command.\n",
+ command,
+ m_cmd_name.c_str());
+ return false;
+ }
+ result.AppendError("empty command passed to regular expression command");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+}
+
+
+bool
+CommandObjectRegexCommand::AddRegexCommand (const char *re_cstr, const char *command_cstr)
+{
+ m_entries.resize(m_entries.size() + 1);
+ // Only add the regular expression if it compiles
+ if (m_entries.back().regex.Compile (re_cstr, REG_EXTENDED))
+ {
+ m_entries.back().command.assign (command_cstr);
+ return true;
+ }
+ // The regex didn't compile...
+ m_entries.pop_back();
+ return false;
+}
+
+int
+CommandObjectRegexCommand::HandleCompletion (Args &input,
+ int &cursor_index,
+ int &cursor_char_position,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ if (m_completion_type_mask)
+ {
+ std::string completion_str (input.GetArgumentAtIndex (cursor_index), cursor_char_position);
+ CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ m_completion_type_mask,
+ completion_str.c_str(),
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+ }
+ else
+ {
+ matches.Clear();
+ word_complete = false;
+ }
+ return 0;
+}
diff --git a/source/Interpreter/CommandObjectScript.cpp b/source/Interpreter/CommandObjectScript.cpp
new file mode 100644
index 000000000000..aff507d98580
--- /dev/null
+++ b/source/Interpreter/CommandObjectScript.cpp
@@ -0,0 +1,93 @@
+//===-- CommandObjectScript.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 "CommandObjectScript.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/Core/Debugger.h"
+
+#include "lldb/DataFormatters/DataVisualization.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// CommandObjectScript
+//-------------------------------------------------------------------------
+
+CommandObjectScript::CommandObjectScript (CommandInterpreter &interpreter, ScriptLanguage script_lang) :
+ CommandObjectRaw (interpreter,
+ "script",
+ "Pass an expression to the script interpreter for evaluation and return the results. Drop into the interactive interpreter if no expression is given.",
+ "script [<script-expression-for-evaluation>]")
+{
+}
+
+CommandObjectScript::~CommandObjectScript ()
+{
+}
+
+bool
+CommandObjectScript::DoExecute
+(
+ const char *command,
+ CommandReturnObject &result
+)
+{
+#ifdef LLDB_DISABLE_PYTHON
+ // if we ever support languages other than Python this simple #ifdef won't work
+ result.AppendError("your copy of LLDB does not support scripting.");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+#else
+ if (m_interpreter.GetDebugger().GetScriptLanguage() == lldb::eScriptLanguageNone)
+ {
+ result.AppendError("the script-lang setting is set to none - scripting not available");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter ();
+
+ if (script_interpreter == NULL)
+ {
+ result.AppendError("no script interpreter");
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ DataVisualization::ForceUpdate(); // script might change Python code we use for formatting.. make sure we keep up to date with it
+
+ if (command == NULL || command[0] == '\0')
+ {
+ script_interpreter->ExecuteInterpreterLoop ();
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+ // We can do better when reporting the status of one-liner script execution.
+ if (script_interpreter->ExecuteOneLine (command, &result))
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ else
+ result.SetStatus(eReturnStatusFailed);
+
+ return result.Succeeded();
+#endif
+}
diff --git a/source/Interpreter/CommandObjectScript.h b/source/Interpreter/CommandObjectScript.h
new file mode 100644
index 000000000000..fd55fc44a46a
--- /dev/null
+++ b/source/Interpreter/CommandObjectScript.h
@@ -0,0 +1,42 @@
+//===-- CommandObjectScript.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_CommandObjectScript_h_
+#define liblldb_CommandObjectScript_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+
+namespace lldb_private {
+
+//-------------------------------------------------------------------------
+// CommandObjectScript
+//-------------------------------------------------------------------------
+
+class CommandObjectScript : public CommandObjectRaw
+{
+public:
+
+ CommandObjectScript (CommandInterpreter &interpreter,
+ lldb::ScriptLanguage script_lang);
+
+ virtual
+ ~CommandObjectScript ();
+
+protected:
+ virtual bool
+ DoExecute (const char *command, CommandReturnObject &result);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_CommandObjectScript_h_
diff --git a/source/Interpreter/CommandReturnObject.cpp b/source/Interpreter/CommandReturnObject.cpp
new file mode 100644
index 000000000000..9c63753a23ff
--- /dev/null
+++ b/source/Interpreter/CommandReturnObject.cpp
@@ -0,0 +1,219 @@
+//===-- CommandReturnObject.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/CommandReturnObject.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static void
+DumpStringToStreamWithNewline (Stream &strm, const std::string &s, bool add_newline_if_empty)
+{
+ bool add_newline = false;
+ if (s.empty())
+ {
+ add_newline = add_newline_if_empty;
+ }
+ else
+ {
+ // We already checked for empty above, now make sure there is a newline
+ // in the error, and if there isn't one, add one.
+ strm.Write(s.c_str(), s.size());
+
+ const char last_char = *s.rbegin();
+ add_newline = last_char != '\n' && last_char != '\r';
+
+ }
+ if (add_newline)
+ strm.EOL();
+}
+
+
+CommandReturnObject::CommandReturnObject () :
+ m_out_stream (),
+ m_err_stream (),
+ m_status (eReturnStatusStarted),
+ m_did_change_process_state (false)
+{
+}
+
+CommandReturnObject::~CommandReturnObject ()
+{
+}
+
+void
+CommandReturnObject::AppendErrorWithFormat (const char *format, ...)
+{
+ if (!format)
+ return;
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+
+ const std::string &s = sstrm.GetString();
+ if (!s.empty())
+ {
+ Stream &error_strm = GetErrorStream();
+ error_strm.PutCString ("error: ");
+ DumpStringToStreamWithNewline (error_strm, s, false);
+ }
+}
+
+void
+CommandReturnObject::AppendMessageWithFormat (const char *format, ...)
+{
+ if (!format)
+ return;
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+ GetOutputStream().Printf("%s", sstrm.GetData());
+}
+
+void
+CommandReturnObject::AppendWarningWithFormat (const char *format, ...)
+{
+ if (!format)
+ return;
+ va_list args;
+ va_start (args, format);
+ StreamString sstrm;
+ sstrm.PrintfVarArg(format, args);
+ va_end (args);
+
+ GetErrorStream().Printf("warning: %s", sstrm.GetData());
+}
+
+void
+CommandReturnObject::AppendMessage (const char *in_string)
+{
+ if (!in_string)
+ return;
+ GetOutputStream().Printf("%s\n", in_string);
+}
+
+void
+CommandReturnObject::AppendWarning (const char *in_string)
+{
+ if (!in_string || *in_string == '\0')
+ return;
+ GetErrorStream().Printf("warning: %s\n", in_string);
+}
+
+// Similar to AppendWarning, but do not prepend 'warning: ' to message, and
+// don't append "\n" to the end of it.
+
+void
+CommandReturnObject::AppendRawWarning (const char *in_string)
+{
+ if (in_string && in_string[0])
+ GetErrorStream().PutCString(in_string);
+}
+
+void
+CommandReturnObject::AppendError (const char *in_string)
+{
+ if (!in_string || *in_string == '\0')
+ return;
+ GetErrorStream().Printf ("error: %s\n", in_string);
+}
+
+void
+CommandReturnObject::SetError (const Error &error, const char *fallback_error_cstr)
+{
+ const char *error_cstr = error.AsCString();
+ if (error_cstr == NULL)
+ error_cstr = fallback_error_cstr;
+ SetError(error_cstr);
+}
+
+void
+CommandReturnObject::SetError (const char *error_cstr)
+{
+ if (error_cstr)
+ {
+ AppendError (error_cstr);
+ SetStatus (eReturnStatusFailed);
+ }
+}
+
+// Similar to AppendError, but do not prepend 'Error: ' to message, and
+// don't append "\n" to the end of it.
+
+void
+CommandReturnObject::AppendRawError (const char *in_string)
+{
+ if (in_string && in_string[0])
+ GetErrorStream().PutCString(in_string);
+}
+
+void
+CommandReturnObject::SetStatus (ReturnStatus status)
+{
+ m_status = status;
+}
+
+ReturnStatus
+CommandReturnObject::GetStatus ()
+{
+ return m_status;
+}
+
+bool
+CommandReturnObject::Succeeded ()
+{
+ return m_status <= eReturnStatusSuccessContinuingResult;
+}
+
+bool
+CommandReturnObject::HasResult ()
+{
+ return (m_status == eReturnStatusSuccessFinishResult ||
+ m_status == eReturnStatusSuccessContinuingResult);
+}
+
+void
+CommandReturnObject::Clear()
+{
+ lldb::StreamSP stream_sp;
+ stream_sp = m_out_stream.GetStreamAtIndex (eStreamStringIndex);
+ if (stream_sp)
+ static_cast<StreamString *>(stream_sp.get())->Clear();
+ stream_sp = m_err_stream.GetStreamAtIndex (eStreamStringIndex);
+ if (stream_sp)
+ static_cast<StreamString *>(stream_sp.get())->Clear();
+ m_status = eReturnStatusStarted;
+ m_did_change_process_state = false;
+}
+
+bool
+CommandReturnObject::GetDidChangeProcessState ()
+{
+ return m_did_change_process_state;
+}
+
+void
+CommandReturnObject::SetDidChangeProcessState (bool b)
+{
+ m_did_change_process_state = b;
+}
+
diff --git a/source/Interpreter/OptionGroupArchitecture.cpp b/source/Interpreter/OptionGroupArchitecture.cpp
new file mode 100644
index 000000000000..af103bb0bd9d
--- /dev/null
+++ b/source/Interpreter/OptionGroupArchitecture.cpp
@@ -0,0 +1,86 @@
+//===-- OptionGroupArchitecture.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/OptionGroupArchitecture.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupArchitecture::OptionGroupArchitecture() :
+ m_arch_str ()
+{
+}
+
+OptionGroupArchitecture::~OptionGroupArchitecture ()
+{
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1 , false, "arch" , 'a', required_argument, NULL, 0, eArgTypeArchitecture , "Specify the architecture for the target."},
+};
+
+uint32_t
+OptionGroupArchitecture::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_option_table);
+}
+
+const OptionDefinition *
+OptionGroupArchitecture::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+bool
+OptionGroupArchitecture::GetArchitecture (Platform *platform, ArchSpec &arch)
+{
+ if (m_arch_str.empty())
+ arch.Clear();
+ else
+ arch.SetTriple(m_arch_str.c_str(), platform);
+ return arch.IsValid();
+}
+
+
+Error
+OptionGroupArchitecture::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'a':
+ m_arch_str.assign (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupArchitecture::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_arch_str.clear();
+}
+
diff --git a/source/Interpreter/OptionGroupBoolean.cpp b/source/Interpreter/OptionGroupBoolean.cpp
new file mode 100644
index 000000000000..5b5b38478b02
--- /dev/null
+++ b/source/Interpreter/OptionGroupBoolean.cpp
@@ -0,0 +1,67 @@
+//===-- OptionGroupBoolean.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/OptionGroupBoolean.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupBoolean::OptionGroupBoolean (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ const char *usage_text,
+ bool default_value,
+ bool no_argument_toggle_default) :
+ m_value (default_value, default_value)
+{
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.option_has_arg = no_argument_toggle_default ? no_argument : required_argument;
+ m_option_definition.enum_values = NULL;
+ m_option_definition.completion_type = 0;
+ m_option_definition.argument_type = eArgTypeBoolean;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupBoolean::~OptionGroupBoolean ()
+{
+}
+
+Error
+OptionGroupBoolean::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ if (m_option_definition.option_has_arg == no_argument)
+ {
+ // Not argument, toggle the default value and mark the option as having been set
+ m_value.SetCurrentValue (!m_value.GetDefaultValue());
+ m_value.SetOptionWasSet ();
+ }
+ else
+ {
+ error = m_value.SetValueFromCString (option_arg);
+ }
+ return error;
+}
+
+void
+OptionGroupBoolean::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_value.Clear();
+}
diff --git a/source/Interpreter/OptionGroupFile.cpp b/source/Interpreter/OptionGroupFile.cpp
new file mode 100644
index 000000000000..6867395789c7
--- /dev/null
+++ b/source/Interpreter/OptionGroupFile.cpp
@@ -0,0 +1,97 @@
+//===-- OptionGroupFile.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/OptionGroupFile.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupFile::OptionGroupFile (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text) :
+ m_file ()
+{
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.option_has_arg = required_argument;
+ m_option_definition.enum_values = NULL;
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupFile::~OptionGroupFile ()
+{
+}
+
+Error
+OptionGroupFile::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error (m_file.SetValueFromCString (option_arg));
+ return error;
+}
+
+void
+OptionGroupFile::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_file.Clear();
+}
+
+
+OptionGroupFileList::OptionGroupFileList (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text) :
+ m_file_list ()
+{
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.option_has_arg = required_argument;
+ m_option_definition.enum_values = NULL;
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupFileList::~OptionGroupFileList ()
+{
+}
+
+Error
+OptionGroupFileList::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error (m_file_list.SetValueFromCString (option_arg));
+ return error;
+}
+
+void
+OptionGroupFileList::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_file_list.Clear();
+}
diff --git a/source/Interpreter/OptionGroupFormat.cpp b/source/Interpreter/OptionGroupFormat.cpp
new file mode 100644
index 000000000000..790cbb668fa1
--- /dev/null
+++ b/source/Interpreter/OptionGroupFormat.cpp
@@ -0,0 +1,249 @@
+//===-- OptionGroupFormat.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/Interpreter/OptionGroupFormat.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupFormat::OptionGroupFormat (lldb::Format default_format,
+ uint64_t default_byte_size,
+ uint64_t default_count) :
+ m_format (default_format, default_format),
+ m_byte_size (default_byte_size, default_byte_size),
+ m_count (default_count, default_count),
+ m_prev_gdb_format('x'),
+ m_prev_gdb_size('w')
+{
+}
+
+OptionGroupFormat::~OptionGroupFormat ()
+{
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+{ LLDB_OPT_SET_1, false, "format" ,'f', required_argument, NULL, 0, eArgTypeFormat , "Specify a format to be used for display."},
+{ LLDB_OPT_SET_2, false, "gdb-format",'G', required_argument, NULL, 0, eArgTypeGDBFormat, "Specify a format using a GDB format specifier string."},
+{ LLDB_OPT_SET_3, false, "size" ,'s', required_argument, NULL, 0, eArgTypeByteSize , "The size in bytes to use when displaying with the selected format."},
+{ LLDB_OPT_SET_4, false, "count" ,'c', required_argument, NULL, 0, eArgTypeCount , "The number of total items to display."},
+};
+
+uint32_t
+OptionGroupFormat::GetNumDefinitions ()
+{
+ if (m_byte_size.GetDefaultValue() < UINT64_MAX)
+ {
+ if (m_count.GetDefaultValue() < UINT64_MAX)
+ return 4;
+ else
+ return 3;
+ }
+ return 2;
+}
+
+const OptionDefinition *
+OptionGroupFormat::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+OptionGroupFormat::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'f':
+ error = m_format.SetValueFromCString (option_arg);
+ break;
+
+ case 'c':
+ if (m_count.GetDefaultValue() == 0)
+ {
+ error.SetErrorString ("--count option is disabled");
+ }
+ else
+ {
+ error = m_count.SetValueFromCString (option_arg);
+ if (m_count.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid --count option value '%s'", option_arg);
+ }
+ break;
+
+ case 's':
+ if (m_byte_size.GetDefaultValue() == 0)
+ {
+ error.SetErrorString ("--size option is disabled");
+ }
+ else
+ {
+ error = m_byte_size.SetValueFromCString (option_arg);
+ if (m_byte_size.GetCurrentValue() == 0)
+ error.SetErrorStringWithFormat("invalid --size option value '%s'", option_arg);
+ }
+ break;
+
+ case 'G':
+ {
+ char *end = NULL;
+ const char *gdb_format_cstr = option_arg;
+ uint64_t count = 0;
+ if (::isdigit (gdb_format_cstr[0]))
+ {
+ count = strtoull (gdb_format_cstr, &end, 0);
+
+ if (option_arg != end)
+ gdb_format_cstr = end; // We have a valid count, advance the string position
+ else
+ count = 0;
+ }
+
+ Format format = eFormatDefault;
+ uint32_t byte_size = 0;
+
+ while (ParserGDBFormatLetter (interpreter, gdb_format_cstr[0], format, byte_size))
+ {
+ ++gdb_format_cstr;
+ }
+
+ // We the first character of the "gdb_format_cstr" is not the
+ // NULL terminator, we didn't consume the entire string and
+ // something is wrong. Also, if none of the format, size or count
+ // was specified correctly, then abort.
+ if (gdb_format_cstr[0] || (format == eFormatInvalid && byte_size == 0 && count == 0))
+ {
+ // Nothing got set correctly
+ error.SetErrorStringWithFormat ("invalid gdb format string '%s'", option_arg);
+ return error;
+ }
+
+ // At least one of the format, size or count was set correctly.
+ // Anything that wasn't set correctly should be set to the
+ // previous default
+ if (format == eFormatInvalid)
+ ParserGDBFormatLetter (interpreter, m_prev_gdb_format, format, byte_size);
+
+ const bool byte_size_enabled = m_byte_size.GetDefaultValue() < UINT64_MAX;
+ const bool count_enabled = m_count.GetDefaultValue() < UINT64_MAX;
+ if (byte_size_enabled)
+ {
+ // Byte size is enabled
+ if (byte_size == 0)
+ ParserGDBFormatLetter (interpreter, m_prev_gdb_size, format, byte_size);
+ }
+ else
+ {
+ // Byte size is disabled, make sure it wasn't specified
+ if (byte_size > 0)
+ {
+ error.SetErrorString ("this command doesn't support specifying a byte size");
+ return error;
+ }
+ }
+
+ if (count_enabled)
+ {
+ // Count is enabled and was not set, set it to the default for gdb format statements (which is 1).
+ if (count == 0)
+ count = 1;
+ }
+ else
+ {
+ // Count is disabled, make sure it wasn't specified
+ if (count > 0)
+ {
+ error.SetErrorString ("this command doesn't support specifying a count");
+ return error;
+ }
+ }
+
+ m_format.SetCurrentValue (format);
+ m_format.SetOptionWasSet ();
+ if (byte_size_enabled)
+ {
+ m_byte_size.SetCurrentValue (byte_size);
+ m_byte_size.SetOptionWasSet ();
+ }
+ if (count_enabled)
+ {
+ m_count.SetCurrentValue(count);
+ m_count.SetOptionWasSet ();
+ }
+ }
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+bool
+OptionGroupFormat::ParserGDBFormatLetter (CommandInterpreter &interpreter, char format_letter, Format &format, uint32_t &byte_size)
+{
+ m_has_gdb_format = true;
+ switch (format_letter)
+ {
+ case 'o': format = eFormatOctal; m_prev_gdb_format = format_letter; return true;
+ case 'x': format = eFormatHex; m_prev_gdb_format = format_letter; return true;
+ case 'd': format = eFormatDecimal; m_prev_gdb_format = format_letter; return true;
+ case 'u': format = eFormatUnsigned; m_prev_gdb_format = format_letter; return true;
+ case 't': format = eFormatBinary; m_prev_gdb_format = format_letter; return true;
+ case 'f': format = eFormatFloat; m_prev_gdb_format = format_letter; return true;
+ case 'a': format = eFormatAddressInfo;
+ {
+ ExecutionContext exe_ctx(interpreter.GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ byte_size = target->GetArchitecture().GetAddressByteSize();
+ m_prev_gdb_format = format_letter;
+ return true;
+ }
+ case 'i': format = eFormatInstruction; m_prev_gdb_format = format_letter; return true;
+ case 'c': format = eFormatChar; m_prev_gdb_format = format_letter; return true;
+ case 's': format = eFormatCString; m_prev_gdb_format = format_letter; return true;
+ case 'T': format = eFormatOSType; m_prev_gdb_format = format_letter; return true;
+ case 'A': format = eFormatHexFloat; m_prev_gdb_format = format_letter; return true;
+ case 'b': byte_size = 1; m_prev_gdb_size = format_letter; return true;
+ case 'h': byte_size = 2; m_prev_gdb_size = format_letter; return true;
+ case 'w': byte_size = 4; m_prev_gdb_size = format_letter; return true;
+ case 'g': byte_size = 8; m_prev_gdb_size = format_letter; return true;
+ default: break;
+ }
+ return false;
+}
+
+void
+OptionGroupFormat::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_format.Clear();
+ m_byte_size.Clear();
+ m_count.Clear();
+ m_has_gdb_format = false;
+}
diff --git a/source/Interpreter/OptionGroupOutputFile.cpp b/source/Interpreter/OptionGroupOutputFile.cpp
new file mode 100644
index 000000000000..aa01bf54964f
--- /dev/null
+++ b/source/Interpreter/OptionGroupOutputFile.cpp
@@ -0,0 +1,81 @@
+//===-- OptionGroupOutputFile.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/OptionGroupOutputFile.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupOutputFile::OptionGroupOutputFile() :
+ m_file (),
+ m_append (false, false)
+{
+}
+
+OptionGroupOutputFile::~OptionGroupOutputFile ()
+{
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1 , false, "outfile", 'o', required_argument, NULL, 0, eArgTypeFilename , "Specify a path for capturing command output."},
+ { LLDB_OPT_SET_1 , false, "append-outfile" , 'apnd', no_argument, NULL, 0, eArgTypeNone , "Append to the the file specified with '--outfile <path>'."},
+};
+
+uint32_t
+OptionGroupOutputFile::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_option_table);
+}
+
+const OptionDefinition *
+OptionGroupOutputFile::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+OptionGroupOutputFile::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'o':
+ error = m_file.SetValueFromCString (option_arg);
+ break;
+
+ case 'apnd':
+ m_append.SetCurrentValue(true);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupOutputFile::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_file.Clear();
+ m_append.Clear();
+}
diff --git a/source/Interpreter/OptionGroupPlatform.cpp b/source/Interpreter/OptionGroupPlatform.cpp
new file mode 100644
index 000000000000..a54edafd0196
--- /dev/null
+++ b/source/Interpreter/OptionGroupPlatform.cpp
@@ -0,0 +1,149 @@
+//===-- OptionGroupPlatform.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/Interpreter/OptionGroupPlatform.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+PlatformSP
+OptionGroupPlatform::CreatePlatformWithOptions (CommandInterpreter &interpreter,
+ const ArchSpec &arch,
+ bool make_selected,
+ Error& error,
+ ArchSpec &platform_arch) const
+{
+ PlatformSP platform_sp;
+
+ if (!m_platform_name.empty())
+ {
+ platform_sp = Platform::Create (m_platform_name.c_str(), error);
+ if (platform_sp)
+ {
+ if (platform_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ {
+ error.SetErrorStringWithFormat ("platform '%s' doesn't support '%s'",
+ platform_sp->GetName().GetCString(),
+ arch.GetTriple().getTriple().c_str());
+ platform_sp.reset();
+ return platform_sp;
+ }
+ }
+ }
+ else if (arch.IsValid())
+ {
+ platform_sp = Platform::Create (arch, &platform_arch, error);
+ }
+
+ if (platform_sp)
+ {
+ interpreter.GetDebugger().GetPlatformList().Append (platform_sp, make_selected);
+ if (m_os_version_major != UINT32_MAX)
+ {
+ platform_sp->SetOSVersion (m_os_version_major,
+ m_os_version_minor,
+ m_os_version_update);
+ }
+
+ if (m_sdk_sysroot)
+ platform_sp->SetSDKRootDirectory (m_sdk_sysroot);
+
+ if (m_sdk_build)
+ platform_sp->SetSDKBuild (m_sdk_build);
+ }
+
+ return platform_sp;
+}
+
+void
+OptionGroupPlatform::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_platform_name.clear();
+ m_sdk_sysroot.Clear();
+ m_sdk_build.Clear();
+ m_os_version_major = UINT32_MAX;
+ m_os_version_minor = UINT32_MAX;
+ m_os_version_update = UINT32_MAX;
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_ALL, false, "platform", 'p', required_argument, NULL, 0, eArgTypePlatform, "Specify name of the platform to use for this target, creating the platform if necessary."},
+ { LLDB_OPT_SET_ALL, false, "version" , 'v', required_argument, NULL, 0, eArgTypeNone, "Specify the initial SDK version to use prior to connecting." },
+ { LLDB_OPT_SET_ALL, false, "build" , 'b', required_argument, NULL, 0, eArgTypeNone, "Specify the initial SDK build number." },
+ { LLDB_OPT_SET_ALL, false, "sysroot" , 'S', required_argument, NULL, 0, eArgTypeFilename, "Specify the SDK root directory that contains a root of all remote system files." }
+};
+
+const OptionDefinition*
+OptionGroupPlatform::GetDefinitions ()
+{
+ if (m_include_platform_option)
+ return g_option_table;
+ return g_option_table + 1;
+}
+
+uint32_t
+OptionGroupPlatform::GetNumDefinitions ()
+{
+ if (m_include_platform_option)
+ return llvm::array_lengthof(g_option_table);
+ return llvm::array_lengthof(g_option_table) - 1;
+}
+
+
+Error
+OptionGroupPlatform::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ if (!m_include_platform_option)
+ ++option_idx;
+
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'p':
+ m_platform_name.assign (option_arg);
+ break;
+
+ case 'v':
+ if (Args::StringToVersion (option_arg,
+ m_os_version_major,
+ m_os_version_minor,
+ m_os_version_update) == option_arg)
+ error.SetErrorStringWithFormat ("invalid version string '%s'", option_arg);
+ break;
+
+ case 'b':
+ m_sdk_build.SetCString (option_arg);
+ break;
+
+ case 'S':
+ m_sdk_sysroot.SetCString (option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+ return error;
+}
diff --git a/source/Interpreter/OptionGroupString.cpp b/source/Interpreter/OptionGroupString.cpp
new file mode 100644
index 000000000000..ee9623967c60
--- /dev/null
+++ b/source/Interpreter/OptionGroupString.cpp
@@ -0,0 +1,58 @@
+//===-- OptionGroupString.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/OptionGroupString.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupString::OptionGroupString (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ const char *default_value) :
+ m_value (default_value, default_value)
+{
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.option_has_arg = required_argument;
+ m_option_definition.enum_values = NULL;
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupString::~OptionGroupString ()
+{
+}
+
+Error
+OptionGroupString::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error (m_value.SetValueFromCString (option_arg));
+ return error;
+}
+
+void
+OptionGroupString::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_value.Clear();
+}
diff --git a/source/Interpreter/OptionGroupUInt64.cpp b/source/Interpreter/OptionGroupUInt64.cpp
new file mode 100644
index 000000000000..e6996f702558
--- /dev/null
+++ b/source/Interpreter/OptionGroupUInt64.cpp
@@ -0,0 +1,58 @@
+//===-- OptionGroupUInt64.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/OptionGroupUInt64.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupUInt64::OptionGroupUInt64 (uint32_t usage_mask,
+ bool required,
+ const char *long_option,
+ int short_option,
+ uint32_t completion_type,
+ lldb::CommandArgumentType argument_type,
+ const char *usage_text,
+ uint64_t default_value) :
+ m_value (default_value, default_value)
+{
+ m_option_definition.usage_mask = usage_mask;
+ m_option_definition.required = required;
+ m_option_definition.long_option = long_option;
+ m_option_definition.short_option = short_option;
+ m_option_definition.option_has_arg = required_argument;
+ m_option_definition.enum_values = NULL;
+ m_option_definition.completion_type = completion_type;
+ m_option_definition.argument_type = argument_type;
+ m_option_definition.usage_text = usage_text;
+}
+
+OptionGroupUInt64::~OptionGroupUInt64 ()
+{
+}
+
+Error
+OptionGroupUInt64::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error (m_value.SetValueFromCString (option_arg));
+ return error;
+}
+
+void
+OptionGroupUInt64::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_value.Clear();
+}
diff --git a/source/Interpreter/OptionGroupUUID.cpp b/source/Interpreter/OptionGroupUUID.cpp
new file mode 100644
index 000000000000..14bdc8494e45
--- /dev/null
+++ b/source/Interpreter/OptionGroupUUID.cpp
@@ -0,0 +1,76 @@
+//===-- OptionGroupUUID.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/OptionGroupUUID.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupUUID::OptionGroupUUID() :
+ m_uuid ()
+{
+}
+
+OptionGroupUUID::~OptionGroupUUID ()
+{
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1 , false, "uuid", 'u', required_argument, NULL, 0, eArgTypeNone, "A module UUID value."},
+};
+
+uint32_t
+OptionGroupUUID::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_option_table);
+}
+
+const OptionDefinition *
+OptionGroupUUID::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+Error
+OptionGroupUUID::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+
+ switch (short_option)
+ {
+ case 'u':
+ error = m_uuid.SetValueFromCString (option_arg);
+ if (error.Success())
+ m_uuid.SetOptionWasSet();
+ break;
+
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupUUID::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ m_uuid.Clear();
+}
diff --git a/source/Interpreter/OptionGroupValueObjectDisplay.cpp b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
new file mode 100644
index 000000000000..22a7f37740d5
--- /dev/null
+++ b/source/Interpreter/OptionGroupValueObjectDisplay.cpp
@@ -0,0 +1,181 @@
+//===-- OptionGroupValueObjectDisplay.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/Interpreter/OptionGroupValueObjectDisplay.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Target.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionGroupValueObjectDisplay::OptionGroupValueObjectDisplay()
+{
+}
+
+OptionGroupValueObjectDisplay::~OptionGroupValueObjectDisplay ()
+{
+}
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, g_dynamic_value_types, 0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
+ { LLDB_OPT_SET_1, false, "synthetic-type", 'S', required_argument, NULL, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."},
+ { LLDB_OPT_SET_1, false, "depth", 'D', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
+ { LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
+ { LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
+ { LLDB_OPT_SET_1, false, "object-description", 'O', no_argument, NULL, 0, eArgTypeNone, "Print as an Objective-C object."},
+ { LLDB_OPT_SET_1, false, "ptr-depth", 'P', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
+ { LLDB_OPT_SET_1, false, "show-types", 'T', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
+ { LLDB_OPT_SET_1, false, "no-summary-depth", 'Y', optional_argument, NULL, 0, eArgTypeCount, "Set the depth at which omitting summary information stops (default is 1)."},
+ { LLDB_OPT_SET_1, false, "raw-output", 'R', no_argument, NULL, 0, eArgTypeNone, "Don't use formatting options."},
+ { LLDB_OPT_SET_1, false, "show-all-children", 'A', no_argument, NULL, 0, eArgTypeNone, "Ignore the upper bound on the number of children to show."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+uint32_t
+OptionGroupValueObjectDisplay::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_option_table);
+}
+
+const OptionDefinition *
+OptionGroupValueObjectDisplay::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+
+Error
+OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ bool success = false;
+
+ switch (short_option)
+ {
+ case 'd':
+ {
+ int32_t result;
+ result = Args::StringToOptionEnum (option_arg, g_dynamic_value_types, 2, error);
+ if (error.Success())
+ use_dynamic = (lldb::DynamicValueType) result;
+ }
+ break;
+ case 'T': show_types = true; break;
+ case 'L': show_location= true; break;
+ case 'F': flat_output = true; break;
+ case 'O': use_objc = true; break;
+ case 'R': be_raw = true; break;
+ case 'A': ignore_cap = true; break;
+
+ case 'D':
+ max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid max depth '%s'", option_arg);
+ break;
+
+ case 'P':
+ ptr_depth = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg);
+ break;
+
+ case 'Y':
+ if (option_arg)
+ {
+ no_summary_depth = Args::StringToUInt32 (option_arg, 0, 0, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid pointer depth '%s'", option_arg);
+ }
+ else
+ no_summary_depth = 1;
+ break;
+
+ case 'S':
+ use_synth = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("invalid synthetic-type '%s'", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ // If these defaults change, be sure to modify AnyOptionWasSet().
+ show_types = false;
+ no_summary_depth = 0;
+ show_location = false;
+ flat_output = false;
+ use_objc = false;
+ max_depth = UINT32_MAX;
+ ptr_depth = 0;
+ use_synth = true;
+ be_raw = false;
+ ignore_cap = false;
+
+ Target *target = interpreter.GetExecutionContext().GetTargetPtr();
+ if (target != NULL)
+ use_dynamic = target->GetPreferDynamicValue();
+ else
+ {
+ // If we don't have any targets, then dynamic values won't do us much good.
+ use_dynamic = lldb::eNoDynamicValues;
+ }
+}
+
+ValueObject::DumpValueObjectOptions
+OptionGroupValueObjectDisplay::GetAsDumpOptions (bool objc_is_compact,
+ lldb::Format format,
+ lldb::TypeSummaryImplSP summary_sp)
+{
+ ValueObject::DumpValueObjectOptions options;
+ options.SetMaximumPointerDepth(ptr_depth);
+ if (use_objc)
+ options.SetShowSummary(false);
+ else
+ options.SetOmitSummaryDepth(no_summary_depth);
+ options.SetMaximumDepth(max_depth)
+ .SetShowTypes(show_types)
+ .SetShowLocation(show_location)
+ .SetUseObjectiveC(use_objc)
+ .SetUseDynamicType(use_dynamic)
+ .SetUseSyntheticValue(use_synth)
+ .SetFlatOutput(flat_output)
+ .SetIgnoreCap(ignore_cap)
+ .SetFormat(format)
+ .SetSummary(summary_sp);
+
+ if (objc_is_compact)
+ options.SetHideRootType(use_objc)
+ .SetHideName(use_objc)
+ .SetHideValue(use_objc);
+
+ if (be_raw)
+ options.SetRawDisplay(true);
+
+ return options;
+}
diff --git a/source/Interpreter/OptionGroupVariable.cpp b/source/Interpreter/OptionGroupVariable.cpp
new file mode 100644
index 000000000000..316747eff036
--- /dev/null
+++ b/source/Interpreter/OptionGroupVariable.cpp
@@ -0,0 +1,144 @@
+//===-- OptionGroupVariable.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/Interpreter/OptionGroupVariable.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/DataFormatters/DataVisualization.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// if you add any options here, remember to update the counters in OptionGroupVariable::GetNumDefinitions()
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-globals", 'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "show-declaration",'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
+ { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
+ { LLDB_OPT_SET_1, false, "summary", 'y', required_argument, NULL, 0, eArgTypeName, "Specify the summary that the variable output should use."},
+ { LLDB_OPT_SET_2, false, "summary-string", 'z', required_argument, NULL, 0, eArgTypeName, "Specify a summary string to use to format the variable output."},
+};
+
+static Error
+ValidateNamedSummary (const char* str, void*)
+{
+ if (!str || !str[0])
+ return Error("must specify a valid named summary");
+ TypeSummaryImplSP summary_sp;
+ if (DataVisualization::NamedSummaryFormats::GetSummaryFormat(ConstString(str), summary_sp) == false)
+ return Error("must specify a valid named summary");
+ return Error();
+}
+
+static Error
+ValidateSummaryString (const char* str, void*)
+{
+ if (!str || !str[0])
+ return Error("must specify a non-empty summary string");
+ return Error();
+}
+
+OptionGroupVariable::OptionGroupVariable (bool show_frame_options) :
+ OptionGroup(),
+ include_frame_options (show_frame_options),
+ summary(ValidateNamedSummary),
+ summary_string(ValidateSummaryString)
+{
+}
+
+OptionGroupVariable::~OptionGroupVariable ()
+{
+}
+
+Error
+OptionGroupVariable::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ if (!include_frame_options)
+ option_idx += 3;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'r': use_regex = true; break;
+ case 'a': show_args = false; break;
+ case 'l': show_locals = false; break;
+ case 'g': show_globals = true; break;
+ case 'c': show_decl = true; break;
+ case 's':
+ show_scope = true;
+ break;
+ case 'y':
+ error = summary.SetCurrentValue(option_arg);
+ break;
+ case 'z':
+ error = summary_string.SetCurrentValue(option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupVariable::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ show_args = true; // Frame option only
+ show_locals = true; // Frame option only
+ show_globals = false; // Frame option only
+ show_decl = false;
+ use_regex = false;
+ show_scope = false;
+ summary.Clear();
+ summary_string.Clear();
+}
+
+#define NUM_FRAME_OPTS 3
+
+const OptionDefinition*
+OptionGroupVariable::GetDefinitions ()
+{
+ // Show the "--no-args", "--no-locals" and "--show-globals"
+ // options if we are showing frame specific options
+ if (include_frame_options)
+ return g_option_table;
+
+ // Skip the "--no-args", "--no-locals" and "--show-globals"
+ // options if we are not showing frame specific options (globals only)
+ return &g_option_table[NUM_FRAME_OPTS];
+}
+
+uint32_t
+OptionGroupVariable::GetNumDefinitions ()
+{
+ // Count the "--no-args", "--no-locals" and "--show-globals"
+ // options if we are showing frame specific options.
+ if (include_frame_options)
+ return llvm::array_lengthof(g_option_table);
+ else
+ return llvm::array_lengthof(g_option_table) - NUM_FRAME_OPTS;
+}
+
+
diff --git a/source/Interpreter/OptionGroupWatchpoint.cpp b/source/Interpreter/OptionGroupWatchpoint.cpp
new file mode 100644
index 000000000000..9eef37a3ae6e
--- /dev/null
+++ b/source/Interpreter/OptionGroupWatchpoint.cpp
@@ -0,0 +1,121 @@
+//===-- OptionGroupWatchpoint.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/OptionGroupWatchpoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Utility/Utils.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static OptionEnumValueElement g_watch_type[] =
+{
+ { OptionGroupWatchpoint::eWatchRead, "read", "Watch for read"},
+ { OptionGroupWatchpoint::eWatchWrite, "write", "Watch for write"},
+ { OptionGroupWatchpoint::eWatchReadWrite, "read_write", "Watch for read/write"},
+ { 0, NULL, NULL }
+};
+
+static OptionEnumValueElement g_watch_size[] =
+{
+ { 1, "1", "Watch for byte size of 1"},
+ { 2, "2", "Watch for byte size of 2"},
+ { 4, "4", "Watch for byte size of 4"},
+ { 8, "8", "Watch for byte size of 8"},
+ { 0, NULL, NULL }
+};
+
+static OptionDefinition
+g_option_table[] =
+{
+ { LLDB_OPT_SET_1, false, "watch", 'w', required_argument, g_watch_type, 0, eArgTypeWatchType, "Specify the type of watching to perform."},
+ { LLDB_OPT_SET_1, false, "xsize", 'x', required_argument, g_watch_size, 0, eArgTypeByteSize, "Number of bytes to use to watch a region."}
+};
+
+
+bool
+OptionGroupWatchpoint::IsWatchSizeSupported(uint32_t watch_size)
+{
+ for (uint32_t i = 0; i < llvm::array_lengthof(g_watch_size); ++i)
+ {
+ if (g_watch_size[i].value == 0)
+ break;
+ if (watch_size == g_watch_size[i].value)
+ return true;
+ }
+ return false;
+}
+
+OptionGroupWatchpoint::OptionGroupWatchpoint () :
+ OptionGroup()
+{
+}
+
+OptionGroupWatchpoint::~OptionGroupWatchpoint ()
+{
+}
+
+Error
+OptionGroupWatchpoint::SetOptionValue (CommandInterpreter &interpreter,
+ uint32_t option_idx,
+ const char *option_arg)
+{
+ Error error;
+ const int short_option = g_option_table[option_idx].short_option;
+ switch (short_option)
+ {
+ case 'w':
+ {
+ WatchType tmp_watch_type;
+ tmp_watch_type = (WatchType) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
+ if (error.Success())
+ {
+ watch_type = tmp_watch_type;
+ watch_type_specified = true;
+ }
+ break;
+ }
+ case 'x':
+ watch_size = (uint32_t) Args::StringToOptionEnum(option_arg, g_option_table[option_idx].enum_values, 0, error);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionGroupWatchpoint::OptionParsingStarting (CommandInterpreter &interpreter)
+{
+ watch_type_specified = false;
+ watch_type = eWatchInvalid;
+ watch_size = 0;
+}
+
+
+const OptionDefinition*
+OptionGroupWatchpoint::GetDefinitions ()
+{
+ return g_option_table;
+}
+
+uint32_t
+OptionGroupWatchpoint::GetNumDefinitions ()
+{
+ return llvm::array_lengthof(g_option_table);
+}
diff --git a/source/Interpreter/OptionValue.cpp b/source/Interpreter/OptionValue.cpp
new file mode 100644
index 000000000000..1f6b03ddac1a
--- /dev/null
+++ b/source/Interpreter/OptionValue.cpp
@@ -0,0 +1,633 @@
+//===-- OptionValue.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/OptionValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/OptionValues.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//-------------------------------------------------------------------------
+// Get this value as a uint64_t value if it is encoded as a boolean,
+// uint64_t or int64_t. Other types will cause "fail_value" to be
+// returned
+//-------------------------------------------------------------------------
+uint64_t
+OptionValue::GetUInt64Value (uint64_t fail_value, bool *success_ptr)
+{
+ if (success_ptr)
+ *success_ptr = true;
+ switch (GetType())
+ {
+ case OptionValue::eTypeBoolean: return static_cast<OptionValueBoolean *>(this)->GetCurrentValue();
+ case OptionValue::eTypeSInt64: return static_cast<OptionValueSInt64 *>(this)->GetCurrentValue();
+ case OptionValue::eTypeUInt64: return static_cast<OptionValueUInt64 *>(this)->GetCurrentValue();
+ default:
+ break;
+ }
+ if (success_ptr)
+ *success_ptr = false;
+ return fail_value;
+}
+
+Error
+OptionValue::SetSubValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *name,
+ const char *value)
+{
+ Error error;
+ error.SetErrorStringWithFormat("SetSubValue is not supported");
+ return error;
+}
+
+
+OptionValueBoolean *
+OptionValue::GetAsBoolean ()
+{
+ if (GetType () == OptionValue::eTypeBoolean)
+ return static_cast<OptionValueBoolean *>(this);
+ return NULL;
+}
+
+const OptionValueBoolean *
+OptionValue::GetAsBoolean () const
+{
+ if (GetType () == OptionValue::eTypeBoolean)
+ return static_cast<const OptionValueBoolean *>(this);
+ return NULL;
+}
+
+
+OptionValueFileSpec *
+OptionValue::GetAsFileSpec ()
+{
+ if (GetType () == OptionValue::eTypeFileSpec)
+ return static_cast<OptionValueFileSpec *>(this);
+ return NULL;
+
+}
+
+const OptionValueFileSpec *
+OptionValue::GetAsFileSpec () const
+{
+ if (GetType () == OptionValue::eTypeFileSpec)
+ return static_cast<const OptionValueFileSpec *>(this);
+ return NULL;
+
+}
+
+OptionValueFileSpecList *
+OptionValue::GetAsFileSpecList ()
+{
+ if (GetType () == OptionValue::eTypeFileSpecList)
+ return static_cast<OptionValueFileSpecList *>(this);
+ return NULL;
+
+}
+
+const OptionValueFileSpecList *
+OptionValue::GetAsFileSpecList () const
+{
+ if (GetType () == OptionValue::eTypeFileSpecList)
+ return static_cast<const OptionValueFileSpecList *>(this);
+ return NULL;
+
+}
+
+OptionValueArch *
+OptionValue::GetAsArch ()
+{
+ if (GetType () == OptionValue::eTypeArch)
+ return static_cast<OptionValueArch *>(this);
+ return NULL;
+}
+
+
+const OptionValueArch *
+OptionValue::GetAsArch () const
+{
+ if (GetType () == OptionValue::eTypeArch)
+ return static_cast<const OptionValueArch *>(this);
+ return NULL;
+}
+
+OptionValueArray *
+OptionValue::GetAsArray ()
+{
+ if (GetType () == OptionValue::eTypeArray)
+ return static_cast<OptionValueArray *>(this);
+ return NULL;
+}
+
+
+const OptionValueArray *
+OptionValue::GetAsArray () const
+{
+ if (GetType () == OptionValue::eTypeArray)
+ return static_cast<const OptionValueArray *>(this);
+ return NULL;
+}
+
+OptionValueArgs *
+OptionValue::GetAsArgs ()
+{
+ if (GetType () == OptionValue::eTypeArgs)
+ return static_cast<OptionValueArgs *>(this);
+ return NULL;
+}
+
+
+const OptionValueArgs *
+OptionValue::GetAsArgs () const
+{
+ if (GetType () == OptionValue::eTypeArgs)
+ return static_cast<const OptionValueArgs *>(this);
+ return NULL;
+}
+
+OptionValueDictionary *
+OptionValue::GetAsDictionary ()
+{
+ if (GetType () == OptionValue::eTypeDictionary)
+ return static_cast<OptionValueDictionary *>(this);
+ return NULL;
+}
+
+const OptionValueDictionary *
+OptionValue::GetAsDictionary () const
+{
+ if (GetType () == OptionValue::eTypeDictionary)
+ return static_cast<const OptionValueDictionary *>(this);
+ return NULL;
+}
+
+OptionValueEnumeration *
+OptionValue::GetAsEnumeration ()
+{
+ if (GetType () == OptionValue::eTypeEnum)
+ return static_cast<OptionValueEnumeration *>(this);
+ return NULL;
+}
+
+const OptionValueEnumeration *
+OptionValue::GetAsEnumeration () const
+{
+ if (GetType () == OptionValue::eTypeEnum)
+ return static_cast<const OptionValueEnumeration *>(this);
+ return NULL;
+}
+
+OptionValueFormat *
+OptionValue::GetAsFormat ()
+{
+ if (GetType () == OptionValue::eTypeFormat)
+ return static_cast<OptionValueFormat *>(this);
+ return NULL;
+}
+
+const OptionValueFormat *
+OptionValue::GetAsFormat () const
+{
+ if (GetType () == OptionValue::eTypeFormat)
+ return static_cast<const OptionValueFormat *>(this);
+ return NULL;
+}
+
+OptionValuePathMappings *
+OptionValue::GetAsPathMappings ()
+{
+ if (GetType () == OptionValue::eTypePathMap)
+ return static_cast<OptionValuePathMappings *>(this);
+ return NULL;
+}
+
+const OptionValuePathMappings *
+OptionValue::GetAsPathMappings () const
+{
+ if (GetType () == OptionValue::eTypePathMap)
+ return static_cast<const OptionValuePathMappings *>(this);
+ return NULL;
+}
+
+OptionValueProperties *
+OptionValue::GetAsProperties ()
+{
+ if (GetType () == OptionValue::eTypeProperties)
+ return static_cast<OptionValueProperties *>(this);
+ return NULL;
+}
+
+const OptionValueProperties *
+OptionValue::GetAsProperties () const
+{
+ if (GetType () == OptionValue::eTypeProperties)
+ return static_cast<const OptionValueProperties *>(this);
+ return NULL;
+}
+
+OptionValueRegex *
+OptionValue::GetAsRegex ()
+{
+ if (GetType () == OptionValue::eTypeRegex)
+ return static_cast<OptionValueRegex *>(this);
+ return NULL;
+}
+
+const OptionValueRegex *
+OptionValue::GetAsRegex () const
+{
+ if (GetType () == OptionValue::eTypeRegex)
+ return static_cast<const OptionValueRegex *>(this);
+ return NULL;
+}
+
+OptionValueSInt64 *
+OptionValue::GetAsSInt64 ()
+{
+ if (GetType () == OptionValue::eTypeSInt64)
+ return static_cast<OptionValueSInt64 *>(this);
+ return NULL;
+}
+
+const OptionValueSInt64 *
+OptionValue::GetAsSInt64 () const
+{
+ if (GetType () == OptionValue::eTypeSInt64)
+ return static_cast<const OptionValueSInt64 *>(this);
+ return NULL;
+}
+
+OptionValueString *
+OptionValue::GetAsString ()
+{
+ if (GetType () == OptionValue::eTypeString)
+ return static_cast<OptionValueString *>(this);
+ return NULL;
+}
+
+const OptionValueString *
+OptionValue::GetAsString () const
+{
+ if (GetType () == OptionValue::eTypeString)
+ return static_cast<const OptionValueString *>(this);
+ return NULL;
+}
+
+OptionValueUInt64 *
+OptionValue::GetAsUInt64 ()
+{
+ if (GetType () == OptionValue::eTypeUInt64)
+ return static_cast<OptionValueUInt64 *>(this);
+ return NULL;
+}
+
+const OptionValueUInt64 *
+OptionValue::GetAsUInt64 () const
+{
+ if (GetType () == OptionValue::eTypeUInt64)
+ return static_cast<const OptionValueUInt64 *>(this);
+ return NULL;
+}
+
+OptionValueUUID *
+OptionValue::GetAsUUID ()
+{
+ if (GetType () == OptionValue::eTypeUUID)
+ return static_cast<OptionValueUUID *>(this);
+ return NULL;
+
+}
+
+const OptionValueUUID *
+OptionValue::GetAsUUID () const
+{
+ if (GetType () == OptionValue::eTypeUUID)
+ return static_cast<const OptionValueUUID *>(this);
+ return NULL;
+
+}
+
+bool
+OptionValue::GetBooleanValue (bool fail_value) const
+{
+ const OptionValueBoolean *option_value = GetAsBoolean ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetBooleanValue (bool new_value)
+{
+ OptionValueBoolean *option_value = GetAsBoolean ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+int64_t
+OptionValue::GetEnumerationValue (int64_t fail_value) const
+{
+ const OptionValueEnumeration *option_value = GetAsEnumeration();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetEnumerationValue (int64_t value)
+{
+ OptionValueEnumeration *option_value = GetAsEnumeration();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(value);
+ return true;
+ }
+ return false;
+}
+
+FileSpec
+OptionValue::GetFileSpecValue () const
+{
+ const OptionValueFileSpec *option_value = GetAsFileSpec ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return FileSpec();
+}
+
+
+bool
+OptionValue::SetFileSpecValue (const FileSpec &file_spec)
+{
+ OptionValueFileSpec *option_value = GetAsFileSpec ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(file_spec, false);
+ return true;
+ }
+ return false;
+}
+
+FileSpecList
+OptionValue::GetFileSpecListValue () const
+{
+ const OptionValueFileSpecList *option_value = GetAsFileSpecList ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return FileSpecList();
+}
+
+
+lldb::Format
+OptionValue::GetFormatValue (lldb::Format fail_value) const
+{
+ const OptionValueFormat *option_value = GetAsFormat ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetFormatValue (lldb::Format new_value)
+{
+ OptionValueFormat *option_value = GetAsFormat ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+const RegularExpression *
+OptionValue::GetRegexValue () const
+{
+ const OptionValueRegex *option_value = GetAsRegex ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return NULL;
+}
+
+
+int64_t
+OptionValue::GetSInt64Value (int64_t fail_value) const
+{
+ const OptionValueSInt64 *option_value = GetAsSInt64 ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetSInt64Value (int64_t new_value)
+{
+ OptionValueSInt64 *option_value = GetAsSInt64 ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+const char *
+OptionValue::GetStringValue (const char *fail_value) const
+{
+ const OptionValueString *option_value = GetAsString ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetStringValue (const char *new_value)
+{
+ OptionValueString *option_value = GetAsString ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+uint64_t
+OptionValue::GetUInt64Value (uint64_t fail_value) const
+{
+ const OptionValueUInt64 *option_value = GetAsUInt64 ();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return fail_value;
+}
+
+bool
+OptionValue::SetUInt64Value (uint64_t new_value)
+{
+ OptionValueUInt64 *option_value = GetAsUInt64 ();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(new_value);
+ return true;
+ }
+ return false;
+}
+
+UUID
+OptionValue::GetUUIDValue () const
+{
+ const OptionValueUUID *option_value = GetAsUUID();
+ if (option_value)
+ return option_value->GetCurrentValue();
+ return UUID();
+}
+
+bool
+OptionValue::SetUUIDValue (const UUID &uuid)
+{
+ OptionValueUUID *option_value = GetAsUUID();
+ if (option_value)
+ {
+ option_value->SetCurrentValue(uuid);
+ return true;
+ }
+ return false;
+}
+
+const char *
+OptionValue::GetBuiltinTypeAsCString (Type t)
+{
+ switch (t)
+ {
+ case eTypeInvalid: return "invalid";
+ case eTypeArch: return "arch";
+ case eTypeArgs: return "arguments";
+ case eTypeArray: return "array";
+ case eTypeBoolean: return "boolean";
+ case eTypeDictionary: return "dictionary";
+ case eTypeEnum: return "enum";
+ case eTypeFileSpec: return "file";
+ case eTypeFileSpecList: return "file-list";
+ case eTypeFormat: return "format";
+ case eTypePathMap: return "path-map";
+ case eTypeProperties: return "properties";
+ case eTypeRegex: return "regex";
+ case eTypeSInt64: return "int";
+ case eTypeString: return "string";
+ case eTypeUInt64: return "unsigned";
+ case eTypeUUID: return "uuid";
+ }
+ return NULL;
+}
+
+
+lldb::OptionValueSP
+OptionValue::CreateValueFromCStringForTypeMask (const char *value_cstr, uint32_t type_mask, Error &error)
+{
+ // If only 1 bit is set in the type mask for a dictionary or array
+ // then we know how to decode a value from a cstring
+ lldb::OptionValueSP value_sp;
+ switch (type_mask)
+ {
+ case 1u << eTypeArch: value_sp.reset(new OptionValueArch()); break;
+ case 1u << eTypeBoolean: value_sp.reset(new OptionValueBoolean(false)); 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;
+ case 1u << eTypeString: value_sp.reset(new OptionValueString()); break;
+ case 1u << eTypeUInt64: value_sp.reset(new OptionValueUInt64()); break;
+ case 1u << eTypeUUID: value_sp.reset(new OptionValueUUID()); break;
+ }
+
+ if (value_sp)
+ error = value_sp->SetValueFromCString (value_cstr, eVarSetOperationAssign);
+ else
+ error.SetErrorString("unsupported type mask");
+ return value_sp;
+}
+
+bool
+OptionValue::DumpQualifiedName (Stream &strm) const
+{
+ bool dumped_something = false;
+ lldb::OptionValueSP m_parent_sp(m_parent_wp.lock());
+ if (m_parent_sp)
+ {
+ if (m_parent_sp->DumpQualifiedName(strm))
+ dumped_something = true;
+ }
+ ConstString name (GetName());
+ if (name)
+ {
+ if (dumped_something)
+ strm.PutChar('.');
+ else
+ dumped_something = true;
+ strm << name;
+ }
+ return dumped_something;
+}
+
+size_t
+OptionValue::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+ return matches.GetSize();
+}
+
+Error
+OptionValue::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationReplace:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'replace' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationInsertBefore:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'insert-before' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationInsertAfter:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'insert-after' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationRemove:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'remove' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationAppend:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'append' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationClear:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'clear' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationAssign:
+ error.SetErrorStringWithFormat ("%s objects do not support the 'assign' operation", GetTypeAsCString());
+ break;
+ case eVarSetOperationInvalid:
+ error.SetErrorStringWithFormat ("invalid operation performed on a %s object", GetTypeAsCString());
+ break;
+ }
+ return error;
+}
+
diff --git a/source/Interpreter/OptionValueArch.cpp b/source/Interpreter/OptionValueArch.cpp
new file mode 100644
index 000000000000..92fedffe75ea
--- /dev/null
+++ b/source/Interpreter/OptionValueArch.cpp
@@ -0,0 +1,111 @@
+//===-- OptionValueArch.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/Interpreter/OptionValueArch.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/State.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueArch::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.IsValid())
+ {
+ const char *arch_name = m_current_value.GetArchitectureName();
+ if (arch_name)
+ strm.PutCString (arch_name);
+ }
+ }
+}
+
+Error
+OptionValueArch::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (value_cstr && value_cstr[0])
+ {
+ if (m_current_value.SetTriple (value_cstr))
+ m_value_was_set = true;
+ else
+ error.SetErrorStringWithFormat("unsupported architecture '%s'", value_cstr);
+ }
+ else
+ {
+ error.SetErrorString("invalid value string");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueArch::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueArch(*this));
+}
+
+
+size_t
+OptionValueArch::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+ CommandCompletions::InvokeCommonCompletionCallbacks (interpreter,
+ CommandCompletions::eArchitectureCompletion,
+ s,
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+}
+
+
+
+
diff --git a/source/Interpreter/OptionValueArgs.cpp b/source/Interpreter/OptionValueArgs.cpp
new file mode 100644
index 000000000000..e28d884581fa
--- /dev/null
+++ b/source/Interpreter/OptionValueArgs.cpp
@@ -0,0 +1,38 @@
+//===-- OptionValueArgs.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/OptionValueArgs.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+size_t
+OptionValueArgs::GetArgs (Args &args)
+{
+ const uint32_t size = m_values.size();
+ std::vector<const char *> argv;
+ for (uint32_t i = 0; i<size; ++i)
+ {
+ const char *string_value = m_values[i]->GetStringValue ();
+ if (string_value)
+ argv.push_back(string_value);
+ }
+
+ if (argv.empty())
+ args.Clear();
+ else
+ args.SetArguments(argv.size(), &argv[0]);
+ return args.GetArgumentCount();
+}
diff --git a/source/Interpreter/OptionValueArray.cpp b/source/Interpreter/OptionValueArray.cpp
new file mode 100644
index 000000000000..9a015580bd6c
--- /dev/null
+++ b/source/Interpreter/OptionValueArray.cpp
@@ -0,0 +1,350 @@
+//===-- OptionValueArray.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/OptionValueArray.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueArray::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ const Type array_element_type = ConvertTypeMaskToType (m_type_mask);
+ if (dump_mask & eDumpOptionType)
+ {
+ if ((GetType() == eTypeArray) && (m_type_mask != eTypeInvalid))
+ strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(array_element_type));
+ else
+ strm.Printf ("(%s)", GetTypeAsCString());
+ }
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.Printf (" =%s", (m_values.size() > 0) ? "\n" : "");
+ strm.IndentMore();
+ const uint32_t size = m_values.size();
+ for (uint32_t i = 0; i<size; ++i)
+ {
+ strm.Indent();
+ strm.Printf("[%u]: ", i);
+ const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
+ switch (array_element_type)
+ {
+ default:
+ case eTypeArray:
+ case eTypeDictionary:
+ case eTypeProperties:
+ case eTypeFileSpecList:
+ case eTypePathMap:
+ m_values[i]->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
+ break;
+
+ case eTypeBoolean:
+ case eTypeEnum:
+ case eTypeFileSpec:
+ case eTypeFormat:
+ case eTypeSInt64:
+ case eTypeString:
+ case eTypeUInt64:
+ case eTypeUUID:
+ // No need to show the type for dictionaries of simple items
+ m_values[i]->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options);
+ break;
+ }
+ if (i < (size - 1))
+ strm.EOL();
+ }
+ strm.IndentLess();
+ }
+}
+
+Error
+OptionValueArray::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Args args(value);
+ return SetArgs (args, op);
+}
+
+
+lldb::OptionValueSP
+OptionValueArray::GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool will_modify,
+ Error &error) const
+{
+ if (name && name[0] == '[')
+ {
+ const char *end_bracket = strchr (name+1, ']');
+ if (end_bracket)
+ {
+ const char *sub_value = NULL;
+ if (end_bracket[1])
+ sub_value = end_bracket + 1;
+ std::string index_str (name+1, end_bracket);
+ const size_t array_count = m_values.size();
+ int32_t idx = Args::StringToSInt32(index_str.c_str(), INT32_MAX, 0, NULL);
+ if (idx != INT32_MAX)
+ {
+ ;
+ uint32_t new_idx = UINT32_MAX;
+ if (idx < 0)
+ {
+ // Access from the end of the array if the index is negative
+ new_idx = array_count - idx;
+ }
+ else
+ {
+ // Just a standard index
+ new_idx = idx;
+ }
+
+ if (new_idx < array_count)
+ {
+ if (m_values[new_idx])
+ {
+ if (sub_value)
+ return m_values[new_idx]->GetSubValue (exe_ctx, sub_value, will_modify, error);
+ else
+ return m_values[new_idx];
+ }
+ }
+ else
+ {
+ if (array_count == 0)
+ error.SetErrorStringWithFormat("index %i is not valid for an empty array", idx);
+ else if (idx > 0)
+ error.SetErrorStringWithFormat("index %i out of range, valid values are 0 through %" PRIu64, idx, (uint64_t)(array_count - 1));
+ else
+ error.SetErrorStringWithFormat("negative index %i out of range, valid values are -1 through -%" PRIu64, idx, (uint64_t)array_count);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid value path '%s', %s values only support '[<index>]' subvalues where <index> is a positive or negative array index", name, GetTypeAsCString());
+ }
+ return OptionValueSP();
+}
+
+
+size_t
+OptionValueArray::GetArgs (Args &args) const
+{
+ const uint32_t size = m_values.size();
+ std::vector<const char *> argv;
+ for (uint32_t i = 0; i<size; ++i)
+ {
+ const char *string_value = m_values[i]->GetStringValue ();
+ if (string_value)
+ argv.push_back(string_value);
+ }
+
+ if (argv.empty())
+ args.Clear();
+ else
+ args.SetArguments(argv.size(), &argv[0]);
+ return args.GetArgumentCount();
+}
+
+Error
+OptionValueArray::SetArgs (const Args &args, VarSetOperationType op)
+{
+ Error error;
+ const size_t argc = args.GetArgumentCount();
+ switch (op)
+ {
+ case eVarSetOperationInvalid:
+ error.SetErrorString("unsupported operation");
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ if (argc > 1)
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid insert array index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i=1; i<argc; ++i, ++idx)
+ {
+ lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
+ m_type_mask,
+ error));
+ if (value_sp)
+ {
+ if (error.Fail())
+ return error;
+ if (idx >= m_values.size())
+ m_values.push_back(value_sp);
+ else
+ m_values.insert(m_values.begin() + idx, value_sp);
+ }
+ else
+ {
+ error.SetErrorString("array of complex types must subclass OptionValueArray");
+ return error;
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("insert operation takes an array index followed by one or more values");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0)
+ {
+ const uint32_t size = m_values.size();
+ std::vector<int> remove_indexes;
+ bool all_indexes_valid = true;
+ size_t i;
+ for (i=0; i<argc; ++i)
+ {
+ const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
+ if (idx >= size)
+ {
+ all_indexes_valid = false;
+ break;
+ }
+ else
+ remove_indexes.push_back(idx);
+ }
+
+ if (all_indexes_valid)
+ {
+ size_t num_remove_indexes = remove_indexes.size();
+ if (num_remove_indexes)
+ {
+ // Sort and then erase in reverse so indexes are always valid
+ if (num_remove_indexes > 1)
+ {
+ std::sort(remove_indexes.begin(), remove_indexes.end());
+ for (std::vector<int>::const_reverse_iterator pos = remove_indexes.rbegin(), end = remove_indexes.rend(); pos != end; ++pos)
+ {
+ m_values.erase(m_values.begin() + *pos);
+ }
+ }
+ else
+ {
+ // Only one index
+ m_values.erase(m_values.begin() + remove_indexes.front());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i));
+ }
+ }
+ else
+ {
+ error.SetErrorString("remove operation takes one or more array indices");
+ }
+ break;
+
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ if (argc > 1)
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid replace array index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ for (size_t i=1; i<argc; ++i, ++idx)
+ {
+ lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
+ m_type_mask,
+ error));
+ if (value_sp)
+ {
+ if (error.Fail())
+ return error;
+ if (idx < count)
+ m_values[idx] = value_sp;
+ else
+ m_values.push_back(value_sp);
+ }
+ else
+ {
+ error.SetErrorString("array of complex types must subclass OptionValueArray");
+ return error;
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("replace operation takes an array index followed by one or more values");
+ }
+ break;
+
+ case eVarSetOperationAssign:
+ m_values.clear();
+ // Fall through to append case
+ case eVarSetOperationAppend:
+ for (size_t i=0; i<argc; ++i)
+ {
+ lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (args.GetArgumentAtIndex(i),
+ m_type_mask,
+ error));
+ if (value_sp)
+ {
+ if (error.Fail())
+ return error;
+ m_value_was_set = true;
+ AppendValue(value_sp);
+ }
+ else
+ {
+ error.SetErrorString("array of complex types must subclass OptionValueArray");
+ }
+ }
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueArray::DeepCopy () const
+{
+ OptionValueArray *copied_array = new OptionValueArray (m_type_mask, m_raw_value_dump);
+ lldb::OptionValueSP copied_value_sp(copied_array);
+ const uint32_t size = m_values.size();
+ for (uint32_t i = 0; i<size; ++i)
+ {
+ copied_array->AppendValue (m_values[i]->DeepCopy());
+ }
+ return copied_value_sp;
+}
+
+
+
diff --git a/source/Interpreter/OptionValueBoolean.cpp b/source/Interpreter/OptionValueBoolean.cpp
new file mode 100644
index 000000000000..6471943ee5dc
--- /dev/null
+++ b/source/Interpreter/OptionValueBoolean.cpp
@@ -0,0 +1,135 @@
+//===-- OptionValueBoolean.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/OptionValueBoolean.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"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueBoolean::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ if (dump_mask & eDumpOptionType)
+ strm.Printf ("(%s)", GetTypeAsCString ());
+// if (dump_mask & eDumpOptionName)
+// DumpQualifiedName (strm);
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" = ");
+ strm.PutCString (m_current_value ? "true" : "false");
+ }
+}
+
+Error
+OptionValueBoolean::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ bool success = false;
+ bool value = Args::StringToBoolean(value_cstr, false, &success);
+ if (success)
+ {
+ m_value_was_set = true;
+ m_current_value = value;
+ }
+ else
+ {
+ if (value_cstr == NULL)
+ error.SetErrorString ("invalid boolean string value: NULL");
+ else if (value_cstr[0] == '\0')
+ error.SetErrorString ("invalid boolean string value <empty>");
+ else
+ error.SetErrorStringWithFormat ("invalid boolean string value: '%s'", value_cstr);
+ }
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueBoolean::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueBoolean(*this));
+}
+
+size_t
+OptionValueBoolean::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+ struct StringEntry {
+ const char *string;
+ const size_t length;
+ };
+ static const StringEntry g_autocomplete_entries[] =
+ {
+ { "true" , 4 },
+ { "false", 5 },
+ { "on" , 2 },
+ { "off" , 3 },
+ { "yes" , 3 },
+ { "no" , 2 },
+ { "1" , 1 },
+ { "0" , 1 },
+ };
+ const size_t k_num_autocomplete_entries = sizeof(g_autocomplete_entries)/sizeof(StringEntry);
+
+ if (s && s[0])
+ {
+ const size_t s_len = strlen(s);
+ for (size_t i=0; i<k_num_autocomplete_entries; ++i)
+ {
+ if (s_len <= g_autocomplete_entries[i].length)
+ if (::strncasecmp(s, g_autocomplete_entries[i].string, s_len) == 0)
+ matches.AppendString(g_autocomplete_entries[i].string);
+ }
+ }
+ else
+ {
+ // only suggest "true" or "false" by default
+ for (size_t i=0; i<2; ++i)
+ matches.AppendString(g_autocomplete_entries[i].string);
+ }
+ return matches.GetSize();
+}
+
+
+
diff --git a/source/Interpreter/OptionValueDictionary.cpp b/source/Interpreter/OptionValueDictionary.cpp
new file mode 100644
index 000000000000..61f8aba431ac
--- /dev/null
+++ b/source/Interpreter/OptionValueDictionary.cpp
@@ -0,0 +1,436 @@
+//===-- OptionValueDictionary.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/Interpreter/OptionValueDictionary.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/StringRef.h"
+// Project includes
+#include "lldb/Core/State.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/OptionValueString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueDictionary::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ const Type dict_type = ConvertTypeMaskToType (m_type_mask);
+ if (dump_mask & eDumpOptionType)
+ {
+ if (m_type_mask != eTypeInvalid)
+ strm.Printf ("(%s of %ss)", GetTypeAsCString(), GetBuiltinTypeAsCString(dict_type));
+ else
+ strm.Printf ("(%s)", GetTypeAsCString());
+ }
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" =");
+
+ collection::iterator pos, end = m_values.end();
+
+ strm.IndentMore();
+
+ for (pos = m_values.begin(); pos != end; ++pos)
+ {
+ OptionValue *option_value = pos->second.get();
+ strm.EOL();
+ strm.Indent(pos->first.GetCString());
+
+ const uint32_t extra_dump_options = m_raw_value_dump ? eDumpOptionRaw : 0;
+ switch (dict_type)
+ {
+ default:
+ case eTypeArray:
+ case eTypeDictionary:
+ case eTypeProperties:
+ case eTypeFileSpecList:
+ case eTypePathMap:
+ strm.PutChar (' ');
+ option_value->DumpValue(exe_ctx, strm, dump_mask | extra_dump_options);
+ break;
+
+ case eTypeBoolean:
+ case eTypeEnum:
+ case eTypeFileSpec:
+ case eTypeFormat:
+ case eTypeSInt64:
+ case eTypeString:
+ case eTypeUInt64:
+ case eTypeUUID:
+ // No need to show the type for dictionaries of simple items
+ strm.PutCString("=");
+ option_value->DumpValue(exe_ctx, strm, (dump_mask & (~eDumpOptionType)) | extra_dump_options);
+ break;
+ }
+ }
+ strm.IndentLess();
+ }
+
+}
+
+size_t
+OptionValueDictionary::GetArgs (Args &args) const
+{
+ args.Clear();
+ collection::const_iterator pos, end = m_values.end();
+ for (pos = m_values.begin(); pos != end; ++pos)
+ {
+ StreamString strm;
+ strm.Printf("%s=", pos->first.GetCString());
+ pos->second->DumpValue(NULL, strm, eDumpOptionValue|eDumpOptionRaw);
+ args.AppendArgument(strm.GetString().c_str());
+ }
+ return args.GetArgumentCount();
+}
+
+Error
+OptionValueDictionary::SetArgs (const Args &args, VarSetOperationType op)
+{
+ Error error;
+ const size_t argc = args.GetArgumentCount();
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationAppend:
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (argc > 0)
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ llvm::StringRef key_and_value(args.GetArgumentAtIndex(i));
+ if (!key_and_value.empty())
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> kvp(key_and_value.split('='));
+ llvm::StringRef key = kvp.first;
+ bool key_valid = false;
+ if (!key.empty())
+ {
+ if (key.front() == '[')
+ {
+ // Key name starts with '[', so the the key value must be in single or double quotes like:
+ // ['<key>']
+ // ["<key>"]
+ if ((key.size() > 2) && (key.back() == ']'))
+ {
+ // Strip leading '[' and trailing ']'
+ key = key.substr(1, key.size()-2);
+ const char quote_char = key.front();
+ if ((quote_char == '\'') || (quote_char == '"'))
+ {
+ if ((key.size() > 2) && (key.back() == quote_char))
+ {
+ // Strip the quotes
+ key = key.substr(1, key.size()-2);
+ key_valid = true;
+ }
+ }
+ else
+ {
+ // square brackets, no quotes
+ key_valid = true;
+ }
+ }
+ }
+ else
+ {
+ // No square brackets or quotes
+ key_valid = true;
+ }
+ }
+ if (!key_valid)
+ {
+ error.SetErrorStringWithFormat("invalid key \"%s\", the key must be a bare string or surrounded by brackets with optional quotes: [<key>] or ['<key>'] or [\"<key>\"]", kvp.first.str().c_str());
+ return error;
+ }
+
+ lldb::OptionValueSP value_sp (CreateValueFromCStringForTypeMask (kvp.second.data(),
+ m_type_mask,
+ error));
+ if (value_sp)
+ {
+ if (error.Fail())
+ return error;
+ m_value_was_set = true;
+ SetValueForKey (ConstString(key), value_sp, true);
+ }
+ else
+ {
+ error.SetErrorString("dictionaries that can contain multiple types must subclass OptionValueArray");
+ }
+ }
+ else
+ {
+ error.SetErrorString("empty argument");
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("assign operation takes one or more key=value arguments");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0)
+ {
+ for (size_t i=0; i<argc; ++i)
+ {
+ ConstString key(args.GetArgumentAtIndex(i));
+ if (!DeleteValueForKey(key))
+ {
+ error.SetErrorStringWithFormat("no value found named '%s', aborting remove operation", key.GetCString());
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("remove operation takes one or more key arguments");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (NULL, op);
+ break;
+ }
+ return error;
+}
+
+Error
+OptionValueDictionary::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+{
+ Args args(value_cstr);
+ return SetArgs (args, op);
+}
+
+lldb::OptionValueSP
+OptionValueDictionary::GetSubValue (const ExecutionContext *exe_ctx, const char *name, bool will_modify, Error &error) const
+{
+ lldb::OptionValueSP value_sp;
+
+ if (name && name[0])
+ {
+ const char *sub_name = NULL;
+ ConstString key;
+ const char *open_bracket = ::strchr (name, '[');
+
+ if (open_bracket)
+ {
+ const char *key_start = open_bracket + 1;
+ const char *key_end = NULL;
+ switch (open_bracket[1])
+ {
+ case '\'':
+ ++key_start;
+ key_end = strchr(key_start, '\'');
+ if (key_end)
+ {
+ if (key_end[1] == ']')
+ {
+ if (key_end[2])
+ sub_name = key_end + 2;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid value path '%s', single quoted key names must be formatted as ['<key>'] where <key> is a string that doesn't contain quotes", name);
+ return value_sp;
+ }
+ }
+ else
+ {
+ error.SetErrorString ("missing '] key name terminator, key name started with ['");
+ return value_sp;
+ }
+ break;
+ case '"':
+ ++key_start;
+ key_end = strchr(key_start, '"');
+ if (key_end)
+ {
+ if (key_end[1] == ']')
+ {
+ if (key_end[2])
+ sub_name = key_end + 2;
+ break;
+ }
+ error.SetErrorStringWithFormat ("invalid value path '%s', double quoted key names must be formatted as [\"<key>\"] where <key> is a string that doesn't contain quotes", name);
+ return value_sp;
+ }
+ else
+ {
+ error.SetErrorString ("missing \"] key name terminator, key name started with [\"");
+ return value_sp;
+ }
+ break;
+
+ default:
+ key_end = strchr(key_start, ']');
+ if (key_end)
+ {
+ if (key_end[1])
+ sub_name = key_end + 1;
+ }
+ else
+ {
+ error.SetErrorString ("missing ] key name terminator, key name started with [");
+ return value_sp;
+ }
+ break;
+ }
+
+ if (key_start && key_end)
+ {
+ key.SetCStringWithLength (key_start, key_end - key_start);
+
+ value_sp = GetValueForKey (key);
+ if (value_sp)
+ {
+ if (sub_name)
+ return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("dictionary does not contain a value for the key name '%s'", key.GetCString());
+ }
+ }
+ }
+ if (!value_sp && error.AsCString() == NULL)
+ {
+ error.SetErrorStringWithFormat ("invalid value path '%s', %s values only support '[<key>]' subvalues where <key> a string value optionally delimitted by single or double quotes",
+ name,
+ GetTypeAsCString());
+ }
+ }
+ return value_sp;
+}
+
+Error
+OptionValueDictionary::SetSubValue (const ExecutionContext *exe_ctx, VarSetOperationType op, const char *name, const char *value)
+{
+ Error error;
+ const bool will_modify = true;
+ lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
+ if (value_sp)
+ error = value_sp->SetValueFromCString(value, op);
+ else
+ {
+ if (error.AsCString() == NULL)
+ error.SetErrorStringWithFormat("invalid value path '%s'", name);
+ }
+ return error;
+}
+
+
+lldb::OptionValueSP
+OptionValueDictionary::GetValueForKey (const ConstString &key) const
+{
+ lldb::OptionValueSP value_sp;
+ collection::const_iterator pos = m_values.find (key);
+ if (pos != m_values.end())
+ value_sp = pos->second;
+ return value_sp;
+}
+
+const char *
+OptionValueDictionary::GetStringValueForKey (const ConstString &key)
+{
+ collection::const_iterator pos = m_values.find (key);
+ if (pos != m_values.end())
+ {
+ OptionValueString *string_value = pos->second->GetAsString();
+ if (string_value)
+ return string_value->GetCurrentValue();
+ }
+ return NULL;
+}
+
+
+bool
+OptionValueDictionary::SetStringValueForKey (const ConstString &key,
+ const char *value,
+ bool can_replace)
+{
+ collection::const_iterator pos = m_values.find (key);
+ if (pos != m_values.end())
+ {
+ if (!can_replace)
+ return false;
+ if (pos->second->GetType() == OptionValue::eTypeString)
+ {
+ pos->second->SetValueFromCString(value);
+ return true;
+ }
+ }
+ m_values[key] = OptionValueSP (new OptionValueString (value));
+ return true;
+
+}
+
+bool
+OptionValueDictionary::SetValueForKey (const ConstString &key,
+ const lldb::OptionValueSP &value_sp,
+ bool can_replace)
+{
+ // Make sure the value_sp object is allowed to contain
+ // values of the type passed in...
+ if (value_sp && (m_type_mask & value_sp->GetTypeAsMask()))
+ {
+ if (!can_replace)
+ {
+ collection::const_iterator pos = m_values.find (key);
+ if (pos != m_values.end())
+ return false;
+ }
+ m_values[key] = value_sp;
+ return true;
+ }
+ return false;
+}
+
+bool
+OptionValueDictionary::DeleteValueForKey (const ConstString &key)
+{
+ collection::iterator pos = m_values.find (key);
+ if (pos != m_values.end())
+ {
+ m_values.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+lldb::OptionValueSP
+OptionValueDictionary::DeepCopy () const
+{
+ OptionValueDictionary *copied_dict = new OptionValueDictionary (m_type_mask, m_raw_value_dump);
+ lldb::OptionValueSP copied_value_sp(copied_dict);
+ collection::const_iterator pos, end = m_values.end();
+ for (pos = m_values.begin(); pos != end; ++pos)
+ {
+ StreamString strm;
+ strm.Printf("%s=", pos->first.GetCString());
+ copied_dict->SetValueForKey (pos->first, pos->second->DeepCopy(), true);
+ }
+ return copied_value_sp;
+}
+
diff --git a/source/Interpreter/OptionValueEnumeration.cpp b/source/Interpreter/OptionValueEnumeration.cpp
new file mode 100644
index 000000000000..f282235d58e3
--- /dev/null
+++ b/source/Interpreter/OptionValueEnumeration.cpp
@@ -0,0 +1,166 @@
+//===-- OptionValueEnumeration.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/OptionValueEnumeration.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/StringList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+OptionValueEnumeration::OptionValueEnumeration (const OptionEnumValueElement *enumerators,
+ enum_type value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value),
+ m_enumerations ()
+{
+ SetEnumerations(enumerators);
+}
+
+OptionValueEnumeration::~OptionValueEnumeration()
+{
+}
+
+void
+OptionValueEnumeration::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 (" = ");
+ const size_t count = m_enumerations.GetSize ();
+ for (size_t i=0; i<count; ++i)
+ {
+ if (m_enumerations.GetValueAtIndexUnchecked(i).value == m_current_value)
+ {
+ strm.PutCString(m_enumerations.GetCStringAtIndex(i));
+ return;
+ }
+ }
+ strm.Printf("%" PRIu64, (uint64_t)m_current_value);
+ }
+}
+
+Error
+OptionValueEnumeration::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (value && value[0])
+ {
+ ConstString const_enumerator_name(value);
+ const EnumerationMapEntry *enumerator_entry = m_enumerations.FindFirstValueForName (const_enumerator_name.GetCString());
+ if (enumerator_entry)
+ {
+ m_current_value = enumerator_entry->value.value;
+ }
+ else
+ {
+ StreamString error_strm;
+ error_strm.Printf("invalid enumeration value '%s'", value);
+ const size_t count = m_enumerations.GetSize ();
+ if (count)
+ {
+ error_strm.Printf(", valid values are: %s", m_enumerations.GetCStringAtIndex(0));
+ for (size_t i=1; i<count; ++i)
+ {
+ error_strm.Printf (", %s", m_enumerations.GetCStringAtIndex(i));
+ }
+ }
+ error.SetErrorString(error_strm.GetData());
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid enumeration value");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value, op);
+ break;
+ }
+ return error;
+}
+
+void
+OptionValueEnumeration::SetEnumerations (const OptionEnumValueElement *enumerators)
+{
+ m_enumerations.Clear();
+ if (enumerators)
+ {
+ for (size_t i=0; enumerators[i].string_value != NULL; ++i)
+ {
+ ConstString const_enumerator_name(enumerators[i].string_value);
+ EnumeratorInfo enumerator_info = { enumerators[i].value, enumerators[i].usage };
+ m_enumerations.Append (const_enumerator_name.GetCString(), enumerator_info);
+ }
+ m_enumerations.Sort();
+ }
+}
+
+
+lldb::OptionValueSP
+OptionValueEnumeration::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueEnumeration(*this));
+}
+
+size_t
+OptionValueEnumeration::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+
+ const uint32_t num_enumerators = m_enumerations.GetSize();
+ if (s && s[0])
+ {
+ const size_t s_len = strlen(s);
+ for (size_t i=0; i<num_enumerators; ++i)
+ {
+ const char *name = m_enumerations.GetCStringAtIndex(i);
+ if (::strncmp(s, name, s_len) == 0)
+ matches.AppendString(name);
+ }
+ }
+ else
+ {
+ // only suggest "true" or "false" by default
+ for (size_t i=0; i<num_enumerators; ++i)
+ matches.AppendString(m_enumerations.GetCStringAtIndex(i));
+ }
+ return matches.GetSize();
+}
+
+
+
+
diff --git a/source/Interpreter/OptionValueFileSpec.cpp b/source/Interpreter/OptionValueFileSpec.cpp
new file mode 100644
index 000000000000..e56b48b5579d
--- /dev/null
+++ b/source/Interpreter/OptionValueFileSpec.cpp
@@ -0,0 +1,159 @@
+//===-- OptionValueFileSpec.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/Interpreter/OptionValueFileSpec.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/State.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+OptionValueFileSpec::OptionValueFileSpec () :
+ OptionValue(),
+ m_current_value (),
+ m_default_value (),
+ m_data_sp(),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion)
+{
+}
+
+OptionValueFileSpec::OptionValueFileSpec (const FileSpec &value) :
+ OptionValue(),
+ m_current_value (value),
+ m_default_value (value),
+ m_data_sp(),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion)
+{
+}
+
+OptionValueFileSpec::OptionValueFileSpec (const FileSpec &current_value,
+ const FileSpec &default_value) :
+ OptionValue(),
+ m_current_value (current_value),
+ m_default_value (default_value),
+ m_data_sp(),
+ m_completion_mask (CommandCompletions::eDiskFileCompletion)
+{
+}
+
+void
+OptionValueFileSpec::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)
+ {
+ strm << '"' << m_current_value.GetPath().c_str() << '"';
+ }
+ }
+}
+
+Error
+OptionValueFileSpec::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (value_cstr && value_cstr[0])
+ {
+ Args args(value_cstr);
+ if (args.GetArgumentCount() == 1)
+ {
+ const char *path = args.GetArgumentAtIndex(0);
+ m_value_was_set = true;
+ m_current_value.SetFile(path, true);
+ }
+ else
+ {
+ error.SetErrorString("please supply a single path argument for this file or quote the path if it contains spaces");
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid value string");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueFileSpec::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueFileSpec(*this));
+}
+
+
+size_t
+OptionValueFileSpec::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+ CommandCompletions::InvokeCommonCompletionCallbacks (interpreter,
+ m_completion_mask,
+ s,
+ match_start_point,
+ max_return_elements,
+ NULL,
+ word_complete,
+ matches);
+ return matches.GetSize();
+}
+
+
+
+const lldb::DataBufferSP &
+OptionValueFileSpec::GetFileContents(bool null_terminate)
+{
+ if (!m_data_sp && m_current_value)
+ {
+ if (null_terminate)
+ m_data_sp = m_current_value.ReadFileContentsAsCString();
+ else
+ m_data_sp = m_current_value.ReadFileContents();
+ }
+ return m_data_sp;
+}
+
+
diff --git a/source/Interpreter/OptionValueFileSpecLIst.cpp b/source/Interpreter/OptionValueFileSpecLIst.cpp
new file mode 100644
index 000000000000..e493c70d5a55
--- /dev/null
+++ b/source/Interpreter/OptionValueFileSpecLIst.cpp
@@ -0,0 +1,186 @@
+//===-- OptionValueFileSpecList.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/OptionValueFileSpecList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueFileSpecList::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.Printf (" =%s", m_current_value.GetSize() > 0 ? "\n" : "");
+ strm.IndentMore();
+ const uint32_t size = m_current_value.GetSize();
+ for (uint32_t i = 0; i<size; ++i)
+ {
+ strm.Indent();
+ strm.Printf("[%u]: ", i);
+ m_current_value.GetFileSpecAtIndex(i).Dump(&strm);
+ }
+ strm.IndentLess();
+ }
+}
+
+Error
+OptionValueFileSpecList::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Error error;
+ Args args(value);
+ const size_t argc = args.GetArgumentCount();
+
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ if (argc > 1)
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = m_current_value.GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ for (size_t i=1; i<argc; ++i, ++idx)
+ {
+ FileSpec file (args.GetArgumentAtIndex(i), false);
+ if (idx < count)
+ m_current_value.Replace(idx, file);
+ else
+ m_current_value.Append(file);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("replace operation takes an array index followed by one or more values");
+ }
+ break;
+
+
+
+ case eVarSetOperationAssign:
+ m_current_value.Clear();
+ // Fall through to append case
+ case eVarSetOperationAppend:
+ if (argc > 0)
+ {
+ m_value_was_set = true;
+ for (size_t i=0; i<argc; ++i)
+ {
+ FileSpec file (args.GetArgumentAtIndex(i), false);
+ m_current_value.Append(file);
+ }
+ }
+ else
+ {
+ error.SetErrorString("assign operation takes at least one file path argument");
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ if (argc > 1)
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = m_current_value.GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid insert file list index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i=1; i<argc; ++i, ++idx)
+ {
+ FileSpec file (args.GetArgumentAtIndex(i), false);
+ m_current_value.Insert (idx, file);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("insert operation takes an array index followed by one or more values");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0)
+ {
+ std::vector<int> remove_indexes;
+ bool all_indexes_valid = true;
+ size_t i;
+ for (i=0; all_indexes_valid && i<argc; ++i)
+ {
+ const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
+ if (idx == INT32_MAX)
+ all_indexes_valid = false;
+ else
+ remove_indexes.push_back(idx);
+ }
+
+ if (all_indexes_valid)
+ {
+ size_t num_remove_indexes = remove_indexes.size();
+ if (num_remove_indexes)
+ {
+ // Sort and then erase in reverse so indexes are always valid
+ std::sort(remove_indexes.begin(), remove_indexes.end());
+ for (size_t j=num_remove_indexes-1; j<num_remove_indexes; ++j)
+ {
+ m_current_value.Remove (j);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i));
+ }
+ }
+ else
+ {
+ error.SetErrorString("remove operation takes one or more array index");
+ }
+ break;
+
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value, op);
+ break;
+ }
+ return error;
+
+ m_value_was_set = true;
+ return Error();
+}
+
+lldb::OptionValueSP
+OptionValueFileSpecList::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueFileSpecList(*this));
+}
+
+
diff --git a/source/Interpreter/OptionValueFormat.cpp b/source/Interpreter/OptionValueFormat.cpp
new file mode 100644
index 000000000000..34d36725fbbe
--- /dev/null
+++ b/source/Interpreter/OptionValueFormat.cpp
@@ -0,0 +1,78 @@
+//===-- OptionValueFormat.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "lldb/Interpreter/OptionValueFormat.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/DataFormatters/FormatManager.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueFormat::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ if (dump_mask & eDumpOptionType)
+ strm.Printf ("(%s)", GetTypeAsCString ());
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" = ");
+ strm.PutCString (FormatManager::GetFormatAsCString (m_current_value));
+ }
+}
+
+Error
+OptionValueFormat::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ Format new_format;
+ error = Args::StringToFormat (value_cstr, new_format, NULL);
+ if (error.Success())
+ {
+ m_value_was_set = true;
+ m_current_value = new_format;
+ }
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+
+lldb::OptionValueSP
+OptionValueFormat::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueFormat(*this));
+}
+
diff --git a/source/Interpreter/OptionValuePathMappings.cpp b/source/Interpreter/OptionValuePathMappings.cpp
new file mode 100644
index 000000000000..88a0eb7d6a3b
--- /dev/null
+++ b/source/Interpreter/OptionValuePathMappings.cpp
@@ -0,0 +1,185 @@
+//===-- OptionValuePathMappings.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/OptionValuePathMappings.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValuePathMappings::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.Printf (" =%s", (m_path_mappings.GetSize() > 0) ? "\n" : "");
+ m_path_mappings.Dump(&strm);
+ }
+}
+
+Error
+OptionValuePathMappings::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Error error;
+ Args args(value);
+ const size_t argc = args.GetArgumentCount();
+
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ // Must be at least one index + 1 pair of paths, and the pair count must be even
+ if (argc >= 3 && (((argc - 1) & 1) == 0))
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = m_path_mappings.GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ for (size_t i=1; i<argc; i += 2, ++idx)
+ {
+ ConstString a(args.GetArgumentAtIndex(i));
+ ConstString b(args.GetArgumentAtIndex(i+1));
+ if (!m_path_mappings.Replace (a, b, idx, m_notify_changes))
+ m_path_mappings.Append(a, b, m_notify_changes);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("replace operation takes an array index followed by one or more path pairs");
+ }
+ break;
+
+
+
+ case eVarSetOperationAssign:
+ if (argc < 2 || (argc & 1))
+ {
+ error.SetErrorString("assign operation takes one or more path pairs");
+ break;
+ }
+ m_path_mappings.Clear(m_notify_changes);
+ // Fall through to append case
+ case eVarSetOperationAppend:
+ if (argc < 2 || (argc & 1))
+ {
+ error.SetErrorString("append operation takes one or more path pairs");
+ break;
+ }
+ else
+ {
+ for (size_t i=0; i<argc; i += 2)
+ {
+ ConstString a(args.GetArgumentAtIndex(i));
+ ConstString b(args.GetArgumentAtIndex(i+1));
+ m_path_mappings.Append(a, b, m_notify_changes);
+ m_value_was_set = true;
+ }
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ // Must be at least one index + 1 pair of paths, and the pair count must be even
+ if (argc >= 3 && (((argc - 1) & 1) == 0))
+ {
+ uint32_t idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), UINT32_MAX);
+ const uint32_t count = m_path_mappings.GetSize();
+ if (idx > count)
+ {
+ error.SetErrorStringWithFormat("invalid file list index %u, index must be 0 through %u", idx, count);
+ }
+ else
+ {
+ if (op == eVarSetOperationInsertAfter)
+ ++idx;
+ for (size_t i=1; i<argc; i += 2, ++idx)
+ {
+ ConstString a(args.GetArgumentAtIndex(i));
+ ConstString b(args.GetArgumentAtIndex(i+1));
+ m_path_mappings.Insert (a, b, idx, m_notify_changes);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("insert operation takes an array index followed by one or more path pairs");
+ }
+ break;
+
+ case eVarSetOperationRemove:
+ if (argc > 0)
+ {
+ std::vector<int> remove_indexes;
+ bool all_indexes_valid = true;
+ size_t i;
+ for (i=0; all_indexes_valid && i<argc; ++i)
+ {
+ const int idx = Args::StringToSInt32(args.GetArgumentAtIndex(i), INT32_MAX);
+ if (idx == INT32_MAX)
+ all_indexes_valid = false;
+ else
+ remove_indexes.push_back(idx);
+ }
+
+ if (all_indexes_valid)
+ {
+ size_t num_remove_indexes = remove_indexes.size();
+ if (num_remove_indexes)
+ {
+ // Sort and then erase in reverse so indexes are always valid
+ std::sort(remove_indexes.begin(), remove_indexes.end());
+ for (size_t j=num_remove_indexes-1; j<num_remove_indexes; ++j)
+ {
+ m_path_mappings.Remove (j, m_notify_changes);
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid array index '%s', aborting remove operation", args.GetArgumentAtIndex(i));
+ }
+ }
+ else
+ {
+ error.SetErrorString("remove operation takes one or more array index");
+ }
+ break;
+
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value, op);
+ break;
+ }
+ return error;
+
+ m_value_was_set = true;
+ return Error();
+}
+
+lldb::OptionValueSP
+OptionValuePathMappings::DeepCopy () const
+{
+ return OptionValueSP(new OptionValuePathMappings(*this));
+}
diff --git a/source/Interpreter/OptionValueProperties.cpp b/source/Interpreter/OptionValueProperties.cpp
new file mode 100644
index 000000000000..0df378235cfa
--- /dev/null
+++ b/source/Interpreter/OptionValueProperties.cpp
@@ -0,0 +1,762 @@
+//===-- OptionValueProperties.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/OptionValueProperties.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Interpreter/Property.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+OptionValueProperties::OptionValueProperties (const ConstString &name) :
+ OptionValue (),
+ m_name (name),
+ m_properties (),
+ m_name_to_index ()
+{
+}
+
+OptionValueProperties::OptionValueProperties (const OptionValueProperties &global_properties) :
+ OptionValue (global_properties),
+ m_name (global_properties.m_name),
+ m_properties (global_properties.m_properties),
+ m_name_to_index (global_properties.m_name_to_index)
+{
+ // We now have an exact copy of "global_properties". We need to now
+ // find all non-global settings and copy the property values so that
+ // all non-global settings get new OptionValue instances created for
+ // them.
+ const size_t num_properties = m_properties.size();
+ for (size_t i=0; i<num_properties; ++i)
+ {
+ // Duplicate any values that are not global when contructing properties from
+ // a global copy
+ if (m_properties[i].IsGlobal() == false)
+ {
+ lldb::OptionValueSP new_value_sp (m_properties[i].GetValue()->DeepCopy());
+ m_properties[i].SetOptionValue(new_value_sp);
+ }
+ }
+}
+
+
+
+size_t
+OptionValueProperties::GetNumProperties() const
+{
+ return m_properties.size();
+}
+
+
+void
+OptionValueProperties::Initialize (const PropertyDefinition *defs)
+{
+ for (size_t i=0; defs[i].name; ++i)
+ {
+ Property property(defs[i]);
+ assert(property.IsValid());
+ m_name_to_index.Append(property.GetName().GetCString(),m_properties.size());
+ property.GetValue()->SetParent(shared_from_this());
+ m_properties.push_back(property);
+ }
+ m_name_to_index.Sort();
+}
+
+void
+OptionValueProperties::AppendProperty(const ConstString &name,
+ const ConstString &desc,
+ bool is_global,
+ const OptionValueSP &value_sp)
+{
+ Property property(name, desc, is_global, value_sp);
+ m_name_to_index.Append(name.GetCString(),m_properties.size());
+ m_properties.push_back(property);
+ value_sp->SetParent (shared_from_this());
+ m_name_to_index.Sort();
+}
+
+
+
+//bool
+//OptionValueProperties::GetQualifiedName (Stream &strm)
+//{
+// bool dumped_something = false;
+//// lldb::OptionValuePropertiesSP parent_sp(GetParent ());
+//// if (parent_sp)
+//// {
+//// parent_sp->GetQualifiedName (strm);
+//// strm.PutChar('.');
+//// dumped_something = true;
+//// }
+// if (m_name)
+// {
+// strm << m_name;
+// dumped_something = true;
+// }
+// return dumped_something;
+//}
+//
+lldb::OptionValueSP
+OptionValueProperties::GetValueForKey (const ExecutionContext *exe_ctx,
+ const ConstString &key,
+ bool will_modify) const
+{
+ lldb::OptionValueSP value_sp;
+ size_t idx = m_name_to_index.Find (key.GetCString(), SIZE_MAX);
+ if (idx < m_properties.size())
+ value_sp = GetPropertyAtIndex(exe_ctx, will_modify, idx)->GetValue();
+ return value_sp;
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetSubValue (const ExecutionContext *exe_ctx,
+ const char *name,
+ bool will_modify,
+ Error &error) const
+{
+ lldb::OptionValueSP value_sp;
+
+ if (name && name[0])
+ {
+ const char *sub_name = NULL;
+ ConstString key;
+ size_t key_len = ::strcspn (name, ".[{");
+
+ if (name[key_len])
+ {
+ key.SetCStringWithLength (name, key_len);
+ sub_name = name + key_len;
+ }
+ else
+ key.SetCString (name);
+
+ value_sp = GetValueForKey (exe_ctx, key, will_modify);
+ if (sub_name && value_sp)
+ {
+ switch (sub_name[0])
+ {
+ case '.':
+ return value_sp->GetSubValue (exe_ctx, sub_name + 1, will_modify, error);
+
+ case '{':
+ // Predicate matching for predicates like
+ // "<setting-name>{<predicate>}"
+ // strings are parsed by the current OptionValueProperties subclass
+ // to mean whatever they want to. For instance a subclass of
+ // OptionValueProperties for a lldb_private::Target might implement:
+ // "target.run-args{arch==i386}" -- only set run args if the arch is i386
+ // "target.run-args{path=/tmp/a/b/c/a.out}" -- only set run args if the path matches
+ // "target.run-args{basename==test&&arch==x86_64}" -- only set run args if exectable basename is "test" and arch is "x86_64"
+ if (sub_name[1])
+ {
+ const char *predicate_start = sub_name + 1;
+ const char *predicate_end = strchr(predicate_start, '}');
+ if (predicate_end)
+ {
+ std::string predicate(predicate_start, predicate_end);
+ if (PredicateMatches(exe_ctx, predicate.c_str()))
+ {
+ if (predicate_end[1])
+ {
+ // Still more subvalue string to evaluate
+ return value_sp->GetSubValue (exe_ctx, predicate_end + 1, will_modify, error);
+ }
+ else
+ {
+ // We have a match!
+ break;
+ }
+ }
+ }
+ }
+ // Predicate didn't match or wasn't correctly formed
+ value_sp.reset();
+ break;
+
+ case '[':
+ // Array or dictionary access for subvalues like:
+ // "[12]" -- access 12th array element
+ // "['hello']" -- dictionary access of key named hello
+ return value_sp->GetSubValue (exe_ctx, sub_name, will_modify, error);
+
+ default:
+ value_sp.reset();
+ break;
+ }
+ }
+ }
+ return value_sp;
+}
+
+Error
+OptionValueProperties::SetSubValue (const ExecutionContext *exe_ctx,
+ VarSetOperationType op,
+ const char *name,
+ const char *value)
+{
+ Error error;
+ const bool will_modify = true;
+ lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, name, will_modify, error));
+ if (value_sp)
+ error = value_sp->SetValueFromCString(value, op);
+ else
+ {
+ if (error.AsCString() == NULL)
+ error.SetErrorStringWithFormat("invalid value path '%s'", name);
+ }
+ return error;
+}
+
+
+ConstString
+OptionValueProperties::GetPropertyNameAtIndex (uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex(NULL, false, idx);
+ if (property)
+ return property->GetName();
+ return ConstString();
+
+}
+
+const char *
+OptionValueProperties::GetPropertyDescriptionAtIndex (uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex(NULL, false, idx);
+ if (property)
+ return property->GetDescription();
+ return NULL;
+}
+
+uint32_t
+OptionValueProperties::GetPropertyIndex (const ConstString &name) const
+{
+ return m_name_to_index.Find (name.GetCString(), SIZE_MAX);
+}
+
+const Property *
+OptionValueProperties::GetProperty (const ExecutionContext *exe_ctx, bool will_modify, const ConstString &name) const
+{
+ return GetPropertyAtIndex (exe_ctx, will_modify, m_name_to_index.Find (name.GetCString(), SIZE_MAX));
+}
+
+const Property *
+OptionValueProperties::GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+ return ProtectedGetPropertyAtIndex (idx);
+}
+
+lldb::OptionValueSP
+OptionValueProperties::GetPropertyValueAtIndex (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ uint32_t idx) const
+{
+ const Property *setting = GetPropertyAtIndex (exe_ctx, will_modify, idx);
+ if (setting)
+ return setting->GetValue();
+ return OptionValueSP();
+}
+
+OptionValuePathMappings *
+OptionValueProperties::GetPropertyAtIndexAsOptionValuePathMappings (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+ OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
+ if (value_sp)
+ return value_sp->GetAsPathMappings();
+ return NULL;
+}
+
+OptionValueFileSpecList *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpecList (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+ OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
+ if (value_sp)
+ return value_sp->GetAsFileSpecList();
+ return NULL;
+}
+
+OptionValueArch *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueArch (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ return property->GetValue()->GetAsArch();
+ return NULL;
+}
+
+bool
+OptionValueProperties::GetPropertyAtIndexAsArgs (const ExecutionContext *exe_ctx, uint32_t idx, Args &args) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ {
+ const OptionValueArray *array = value->GetAsArray();
+ if (array)
+ return array->GetArgs(args);
+ else
+ {
+ const OptionValueDictionary *dict = value->GetAsDictionary();
+ if (dict)
+ return dict->GetArgs(args);
+ }
+ }
+ }
+ return false;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexFromArgs (const ExecutionContext *exe_ctx, uint32_t idx, const Args &args)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ {
+ OptionValueArray *array = value->GetAsArray();
+ if (array)
+ return array->SetArgs(args, eVarSetOperationAssign).Success();
+ else
+ {
+ OptionValueDictionary *dict = value->GetAsDictionary();
+ if (dict)
+ return dict->SetArgs(args, eVarSetOperationAssign).Success();
+ }
+ }
+ }
+ return false;
+}
+
+bool
+OptionValueProperties::GetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool fail_value) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetBooleanValue(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsBoolean (const ExecutionContext *exe_ctx, uint32_t idx, bool new_value)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ {
+ value->SetBooleanValue(new_value);
+ return true;
+ }
+ }
+ return false;
+}
+
+OptionValueDictionary *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueDictionary (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ return property->GetValue()->GetAsDictionary();
+ return NULL;
+}
+
+int64_t
+OptionValueProperties::GetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetEnumerationValue(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsEnumeration (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->SetEnumerationValue(new_value);
+ }
+ return false;
+}
+
+
+OptionValueFileSpec *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueFileSpec (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetAsFileSpec();
+ }
+ return NULL;
+}
+
+
+FileSpec
+OptionValueProperties::GetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetFileSpecValue();
+ }
+ return FileSpec();
+}
+
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsFileSpec (const ExecutionContext *exe_ctx, uint32_t idx, const FileSpec &new_file_spec)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->SetFileSpecValue(new_file_spec);
+ }
+ return false;
+}
+
+const RegularExpression *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueRegex (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetRegexValue();
+ }
+ return NULL;
+}
+
+OptionValueSInt64 *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueSInt64 (const ExecutionContext *exe_ctx, uint32_t idx) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetAsSInt64();
+ }
+ return NULL;
+}
+
+int64_t
+OptionValueProperties::GetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t fail_value) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetSInt64Value(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsSInt64 (const ExecutionContext *exe_ctx, uint32_t idx, int64_t new_value)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->SetSInt64Value(new_value);
+ }
+ return false;
+}
+
+const char *
+OptionValueProperties::GetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *fail_value) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetStringValue(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsString (const ExecutionContext *exe_ctx, uint32_t idx, const char *new_value)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->SetStringValue(new_value);
+ }
+ return false;
+}
+
+OptionValueString *
+OptionValueProperties::GetPropertyAtIndexAsOptionValueString (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+{
+ OptionValueSP value_sp(GetPropertyValueAtIndex (exe_ctx, will_modify, idx));
+ if (value_sp)
+ return value_sp->GetAsString();
+ return NULL;
+}
+
+
+uint64_t
+OptionValueProperties::GetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t fail_value) const
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, false, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->GetUInt64Value(fail_value);
+ }
+ return fail_value;
+}
+
+bool
+OptionValueProperties::SetPropertyAtIndexAsUInt64 (const ExecutionContext *exe_ctx, uint32_t idx, uint64_t new_value)
+{
+ const Property *property = GetPropertyAtIndex (exe_ctx, true, idx);
+ if (property)
+ {
+ OptionValue *value = property->GetValue().get();
+ if (value)
+ return value->SetUInt64Value(new_value);
+ }
+ return false;
+}
+
+bool
+OptionValueProperties::Clear ()
+{
+ const size_t num_properties = m_properties.size();
+ for (size_t i=0; i<num_properties; ++i)
+ m_properties[i].GetValue()->Clear();
+ return true;
+}
+
+
+Error
+OptionValueProperties::SetValueFromCString (const char *value, VarSetOperationType op)
+{
+ Error error;
+
+// Args args(value_cstr);
+// const size_t argc = args.GetArgumentCount();
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ case eVarSetOperationRemove:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value, op);
+ break;
+ }
+
+ return error;
+}
+
+void
+OptionValueProperties::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ const size_t num_properties = m_properties.size();
+ for (size_t i=0; i<num_properties; ++i)
+ {
+ const Property *property = GetPropertyAtIndex(exe_ctx, false, i);
+ if (property)
+ {
+ OptionValue *option_value = property->GetValue().get();
+ assert (option_value);
+ const bool transparent_value = option_value->ValueIsTransparent ();
+ property->Dump (exe_ctx,
+ strm,
+ dump_mask);
+ if (!transparent_value)
+ strm.EOL();
+ }
+ }
+}
+
+Error
+OptionValueProperties::DumpPropertyValue (const ExecutionContext *exe_ctx,
+ Stream &strm,
+ const char *property_path,
+ uint32_t dump_mask)
+{
+ Error error;
+ const bool will_modify = false;
+ lldb::OptionValueSP value_sp (GetSubValue (exe_ctx, property_path, will_modify, error));
+ if (value_sp)
+ {
+ if (!value_sp->ValueIsTransparent ())
+ {
+ if (dump_mask & eDumpOptionName)
+ strm.PutCString (property_path);
+ if (dump_mask & ~eDumpOptionName)
+ strm.PutChar (' ');
+ }
+ value_sp->DumpValue (exe_ctx, strm, dump_mask);
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueProperties::DeepCopy () const
+{
+ assert(!"this shouldn't happen");
+}
+
+const Property *
+OptionValueProperties::GetPropertyAtPath (const ExecutionContext *exe_ctx,
+ bool will_modify,
+ const char *name) const
+{
+ const Property *property = NULL;
+ if (name && name[0])
+ {
+ const char *sub_name = NULL;
+ ConstString key;
+ size_t key_len = ::strcspn (name, ".[{");
+
+ if (name[key_len])
+ {
+ key.SetCStringWithLength (name, key_len);
+ sub_name = name + key_len;
+ }
+ else
+ key.SetCString (name);
+
+ property = GetProperty (exe_ctx, will_modify, key);
+ if (sub_name && property)
+ {
+ if (sub_name[0] == '.')
+ {
+ OptionValueProperties *sub_properties = property->GetValue()->GetAsProperties();
+ if (sub_properties)
+ return sub_properties->GetPropertyAtPath(exe_ctx, will_modify, sub_name + 1);
+ }
+ property = NULL;
+ }
+ }
+ return property;
+}
+
+void
+OptionValueProperties::DumpAllDescriptions (CommandInterpreter &interpreter,
+ Stream &strm) const
+{
+ size_t max_name_len = 0;
+ const size_t num_properties = m_properties.size();
+ for (size_t i=0; i<num_properties; ++i)
+ {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property)
+ max_name_len = std::max<size_t>(property->GetName().GetLength(), max_name_len);
+ }
+ for (size_t i=0; i<num_properties; ++i)
+ {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property)
+ property->DumpDescription (interpreter, strm, max_name_len, false);
+ }
+}
+
+void
+OptionValueProperties::Apropos (const char *keyword, std::vector<const Property *> &matching_properties) const
+{
+ const size_t num_properties = m_properties.size();
+ StreamString strm;
+ for (size_t i=0; i<num_properties; ++i)
+ {
+ const Property *property = ProtectedGetPropertyAtIndex(i);
+ if (property)
+ {
+ const OptionValueProperties *properties = property->GetValue()->GetAsProperties();
+ if (properties)
+ {
+ properties->Apropos (keyword, matching_properties);
+ }
+ else
+ {
+ bool match = false;
+ const char *name = property->GetName().GetCString();
+ if (name && ::strcasestr(name, keyword))
+ match = true;
+ else
+ {
+ const char *desc = property->GetDescription();
+ if (desc && ::strcasestr(desc, keyword))
+ match = true;
+ }
+ if (match)
+ {
+ matching_properties.push_back (property);
+ }
+ }
+ }
+ }
+}
+
+lldb::OptionValuePropertiesSP
+OptionValueProperties::GetSubProperty (const ExecutionContext *exe_ctx,
+ const ConstString &name)
+{
+ lldb::OptionValueSP option_value_sp(GetValueForKey(exe_ctx, name, false));
+ if (option_value_sp)
+ {
+ OptionValueProperties *ov_properties = option_value_sp->GetAsProperties ();
+ if (ov_properties)
+ return ov_properties->shared_from_this();
+ }
+ return lldb::OptionValuePropertiesSP();
+}
+
+
+
diff --git a/source/Interpreter/OptionValueRegex.cpp b/source/Interpreter/OptionValueRegex.cpp
new file mode 100644
index 000000000000..f1ba0ed04d6c
--- /dev/null
+++ b/source/Interpreter/OptionValueRegex.cpp
@@ -0,0 +1,86 @@
+//===-- OptionValueRegex.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/OptionValueRegex.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueRegex::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_regex.IsValid())
+ {
+ const char *regex_text = m_regex.GetText();
+ if (regex_text && regex_text[0])
+ strm.Printf ("%s", regex_text);
+ }
+ else
+ {
+
+ }
+ }
+}
+
+Error
+OptionValueRegex::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationInvalid:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (m_regex.Compile (value_cstr, m_regex.GetCompileFlags()))
+ {
+ m_value_was_set = true;
+ }
+ else
+ {
+ char regex_error[1024];
+ if (m_regex.GetErrorAsCString(regex_error, sizeof(regex_error)))
+ error.SetErrorString (regex_error);
+ else
+ error.SetErrorStringWithFormat ("regex error %u", m_regex.GetErrorCode());
+ }
+ break;
+ }
+ return error;
+}
+
+
+lldb::OptionValueSP
+OptionValueRegex::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueRegex(m_regex.GetText(), m_regex.GetCompileFlags()));
+}
diff --git a/source/Interpreter/OptionValueSInt64.cpp b/source/Interpreter/OptionValueSInt64.cpp
new file mode 100644
index 000000000000..04bf9306ade6
--- /dev/null
+++ b/source/Interpreter/OptionValueSInt64.cpp
@@ -0,0 +1,89 @@
+//===-- OptionValueSInt64.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/OptionValueSInt64.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueSInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ //printf ("%p: DumpValue (exe_ctx=%p, strm, mask) m_current_value = %" PRIi64 "\n", this, exe_ctx, m_current_value);
+ if (dump_mask & eDumpOptionType)
+ strm.Printf ("(%s)", GetTypeAsCString ());
+// if (dump_mask & eDumpOptionName)
+// DumpQualifiedName (strm);
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" = ");
+ strm.Printf ("%" PRIi64, m_current_value);
+ }
+}
+
+Error
+OptionValueSInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+{
+ //printf ("%p: SetValueFromCString (s=\"%s\", op=%i)\n", this, value_cstr, op);
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ bool success = false;
+ int64_t value = Args::StringToSInt64 (value_cstr, 0, 0, &success);
+ if (success)
+ {
+ if (value >= m_min_value && value <= m_max_value)
+ {
+ m_value_was_set = true;
+ m_current_value = value;
+ }
+ else
+ error.SetErrorStringWithFormat ("%" PRIi64 " is out of range, valid values must be between %" PRIi64 " and %" PRIi64 ".",
+ value,
+ m_min_value,
+ m_max_value);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid int64_t string value: '%s'", value_cstr);
+ }
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueSInt64::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueSInt64(*this));
+}
diff --git a/source/Interpreter/OptionValueString.cpp b/source/Interpreter/OptionValueString.cpp
new file mode 100644
index 000000000000..df047bd98996
--- /dev/null
+++ b/source/Interpreter/OptionValueString.cpp
@@ -0,0 +1,186 @@
+//===-- OptionValueString.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/OptionValueString.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueString::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.empty() || m_value_was_set)
+ {
+ if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
+ {
+ std::string expanded_escape_value;
+ Args::ExpandEscapedCharacters(m_current_value.c_str(), expanded_escape_value);
+ if (dump_mask & eDumpOptionRaw)
+ strm.Printf ("%s", expanded_escape_value.c_str());
+ else
+ strm.Printf ("\"%s\"", expanded_escape_value.c_str());
+ }
+ else
+ {
+ if (dump_mask & eDumpOptionRaw)
+ strm.Printf ("%s", m_current_value.c_str());
+ else
+ strm.Printf ("\"%s\"", m_current_value.c_str());
+ }
+ }
+ }
+}
+
+Error
+OptionValueString::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+
+ std::string value_str_no_quotes;
+ if (value_cstr)
+ {
+ switch (value_cstr[0])
+ {
+ case '"':
+ case '\'':
+ {
+ size_t len = strlen(value_cstr);
+ if (len <= 1 || value_cstr[len-1] != value_cstr[0])
+ {
+ error.SetErrorString("mismatched quotes");
+ return error;
+ }
+ value_str_no_quotes.assign (value_cstr + 1, len - 2);
+ value_cstr = value_str_no_quotes.c_str();
+ }
+ break;
+ }
+ }
+
+ switch (op)
+ {
+ case eVarSetOperationInvalid:
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ if (m_validator)
+ {
+ error = m_validator(value_cstr,m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+
+ case eVarSetOperationAppend:
+ {
+ std::string new_value(m_current_value);
+ if (value_cstr && value_cstr[0])
+ {
+ if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
+ {
+ std::string str;
+ Args::EncodeEscapeSequences (value_cstr, str);
+ new_value.append(str);
+ }
+ 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);
+ }
+ break;
+
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ if (m_validator)
+ {
+ error = m_validator(value_cstr,m_validator_baton);
+ if (error.Fail())
+ return error;
+ }
+ m_value_was_set = true;
+ if (m_options.Test (eOptionEncodeCharacterEscapeSequences))
+ {
+ Args::EncodeEscapeSequences (value_cstr, m_current_value);
+ }
+ else
+ {
+ SetCurrentValue (value_cstr);
+ }
+ break;
+ }
+ return error;
+}
+
+
+lldb::OptionValueSP
+OptionValueString::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueString(*this));
+}
+
+Error
+OptionValueString::SetCurrentValue (const char *value)
+{
+ if (m_validator)
+ {
+ Error error(m_validator(value,m_validator_baton));
+ if (error.Fail())
+ return error;
+ }
+ if (value && value[0])
+ m_current_value.assign (value);
+ else
+ m_current_value.clear();
+ return Error();
+}
+
+Error
+OptionValueString::AppendToCurrentValue (const char *value)
+{
+ if (value && value[0])
+ {
+ if (m_validator)
+ {
+ std::string new_value(m_current_value);
+ new_value.append(value);
+ Error error(m_validator(value,m_validator_baton));
+ if (error.Fail())
+ return error;
+ m_current_value.assign(new_value);
+ }
+ else
+ m_current_value.append (value);
+ }
+ return Error();
+}
diff --git a/source/Interpreter/OptionValueUInt64.cpp b/source/Interpreter/OptionValueUInt64.cpp
new file mode 100644
index 000000000000..56b3a1c74702
--- /dev/null
+++ b/source/Interpreter/OptionValueUInt64.cpp
@@ -0,0 +1,89 @@
+//===-- OptionValueUInt64.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/OptionValueUInt64.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::OptionValueSP
+OptionValueUInt64::Create (const char *value_cstr, Error &error)
+{
+ lldb::OptionValueSP value_sp (new OptionValueUInt64());
+ error = value_sp->SetValueFromCString (value_cstr);
+ if (error.Fail())
+ value_sp.reset();
+ return value_sp;
+}
+
+
+void
+OptionValueUInt64::DumpValue (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask)
+{
+ if (dump_mask & eDumpOptionType)
+ strm.Printf ("(%s)", GetTypeAsCString ());
+ if (dump_mask & eDumpOptionValue)
+ {
+ if (dump_mask & eDumpOptionType)
+ strm.PutCString (" = ");
+ strm.Printf ("%" PRIu64, m_current_value);
+ }
+}
+
+Error
+OptionValueUInt64::SetValueFromCString (const char *value_cstr, VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear ();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ bool success = false;
+ uint64_t value = Args::StringToUInt64 (value_cstr, 0, 0, &success);
+ if (success)
+ {
+ m_value_was_set = true;
+ m_current_value = value;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid uint64_t string value: '%s'", value_cstr);
+ }
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueUInt64::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueUInt64(*this));
+}
+
diff --git a/source/Interpreter/OptionValueUUID.cpp b/source/Interpreter/OptionValueUUID.cpp
new file mode 100644
index 000000000000..340f1e5e9986
--- /dev/null
+++ b/source/Interpreter/OptionValueUUID.cpp
@@ -0,0 +1,123 @@
+//===-- OptionValueUUID.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/Interpreter/OptionValueUUID.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OptionValueUUID::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 (" = ");
+ m_uuid.Dump (&strm);
+ }
+}
+
+Error
+OptionValueUUID::SetValueFromCString (const char *value_cstr,
+ VarSetOperationType op)
+{
+ Error error;
+ switch (op)
+ {
+ case eVarSetOperationClear:
+ Clear();
+ break;
+
+ case eVarSetOperationReplace:
+ case eVarSetOperationAssign:
+ {
+ if (m_uuid.SetFromCString(value_cstr) == 0)
+ error.SetErrorStringWithFormat ("invalid uuid string value '%s'", value_cstr);
+ else
+ m_value_was_set = true;
+ }
+ break;
+
+ case eVarSetOperationInsertBefore:
+ case eVarSetOperationInsertAfter:
+ case eVarSetOperationRemove:
+ case eVarSetOperationAppend:
+ case eVarSetOperationInvalid:
+ error = OptionValue::SetValueFromCString (value_cstr, op);
+ break;
+ }
+ return error;
+}
+
+lldb::OptionValueSP
+OptionValueUUID::DeepCopy () const
+{
+ return OptionValueSP(new OptionValueUUID(*this));
+}
+
+size_t
+OptionValueUUID::AutoComplete (CommandInterpreter &interpreter,
+ const char *s,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ StringList &matches)
+{
+ word_complete = false;
+ matches.Clear();
+ ExecutionContext exe_ctx(interpreter.GetExecutionContext());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const size_t num_modules = target->GetImages().GetSize();
+ if (num_modules > 0)
+ {
+ UUID::ValueType uuid_bytes;
+ const size_t num_bytes_decoded = UUID::DecodeUUIDBytesFromCString(s, uuid_bytes, NULL);
+ for (size_t i=0; i<num_modules; ++i)
+ {
+ ModuleSP module_sp (target->GetImages().GetModuleAtIndex(i));
+ if (module_sp)
+ {
+ const UUID &module_uuid = module_sp->GetUUID();
+ if (module_uuid.IsValid())
+ {
+ bool add_uuid = false;
+ if (num_bytes_decoded == 0)
+ add_uuid = true;
+ else
+ add_uuid = ::memcmp(module_uuid.GetBytes(), uuid_bytes, num_bytes_decoded) == 0;
+ if (add_uuid)
+ {
+ std::string uuid_str;
+ uuid_str = module_uuid.GetAsString();
+ if (!uuid_str.empty())
+ matches.AppendString(uuid_str.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ return matches.GetSize();
+}
+
diff --git a/source/Interpreter/Options.cpp b/source/Interpreter/Options.cpp
new file mode 100644
index 000000000000..293d75356630
--- /dev/null
+++ b/source/Interpreter/Options.cpp
@@ -0,0 +1,1077 @@
+//===-- Options.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/Interpreter/Options.h"
+
+// C Includes
+// C++ Includes
+#include <algorithm>
+#include <bitset>
+#include <map>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandCompletions.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//-------------------------------------------------------------------------
+// Options
+//-------------------------------------------------------------------------
+Options::Options (CommandInterpreter &interpreter) :
+ m_interpreter (interpreter),
+ m_getopt_table ()
+{
+ BuildValidOptionSets();
+}
+
+Options::~Options ()
+{
+}
+
+void
+Options::NotifyOptionParsingStarting ()
+{
+ m_seen_options.clear();
+ // Let the subclass reset its option values
+ OptionParsingStarting ();
+}
+
+Error
+Options::NotifyOptionParsingFinished ()
+{
+ return OptionParsingFinished ();
+}
+
+void
+Options::OptionSeen (int option_idx)
+{
+ m_seen_options.insert (option_idx);
+}
+
+// Returns true is set_a is a subset of set_b; Otherwise returns false.
+
+bool
+Options::IsASubset (const OptionSet& set_a, const OptionSet& set_b)
+{
+ bool is_a_subset = true;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ // set_a is a subset of set_b if every member of set_a is also a member of set_b
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a)
+ {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end())
+ is_a_subset = false;
+ }
+
+ return is_a_subset;
+}
+
+// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) && !ElementOf (x, set_b) }
+
+size_t
+Options::OptionsSetDiff (const OptionSet& set_a, const OptionSet& set_b, OptionSet& diffs)
+{
+ size_t num_diffs = 0;
+ OptionSet::const_iterator pos_a;
+ OptionSet::const_iterator pos_b;
+
+ for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a)
+ {
+ pos_b = set_b.find(*pos_a);
+ if (pos_b == set_b.end())
+ {
+ ++num_diffs;
+ diffs.insert(*pos_a);
+ }
+ }
+
+ return num_diffs;
+}
+
+// Returns the union of set_a and set_b. Does not put duplicate members into the union.
+
+void
+Options::OptionsSetUnion (const OptionSet &set_a, const OptionSet &set_b, OptionSet &union_set)
+{
+ OptionSet::const_iterator pos;
+ OptionSet::iterator pos_union;
+
+ // Put all the elements of set_a into the union.
+
+ for (pos = set_a.begin(); pos != set_a.end(); ++pos)
+ union_set.insert(*pos);
+
+ // Put all the elements of set_b that are not already there into the union.
+ for (pos = set_b.begin(); pos != set_b.end(); ++pos)
+ {
+ pos_union = union_set.find(*pos);
+ if (pos_union == union_set.end())
+ union_set.insert(*pos);
+ }
+}
+
+bool
+Options::VerifyOptions (CommandReturnObject &result)
+{
+ bool options_are_valid = false;
+
+ int num_levels = GetRequiredOptions().size();
+ if (num_levels)
+ {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i)
+ {
+ // This is the correct set of options if: 1). m_seen_options contains all of m_required_options[i]
+ // (i.e. all the required options at this level are a subset of m_seen_options); AND
+ // 2). { m_seen_options - m_required_options[i] is a subset of m_options_options[i] (i.e. all the rest of
+ // m_seen_options are in the set of optional options at this level.
+
+ // Check to see if all of m_required_options[i] are a subset of m_seen_options
+ if (IsASubset (GetRequiredOptions()[i], m_seen_options))
+ {
+ // Construct the set difference: remaining_options = {m_seen_options} - {m_required_options[i]}
+ OptionSet remaining_options;
+ OptionsSetDiff (m_seen_options, GetRequiredOptions()[i], remaining_options);
+ // Check to see if remaining_options is a subset of m_optional_options[i]
+ if (IsASubset (remaining_options, GetOptionalOptions()[i]))
+ options_are_valid = true;
+ }
+ }
+ }
+ else
+ {
+ options_are_valid = true;
+ }
+
+ if (options_are_valid)
+ {
+ result.SetStatus (eReturnStatusSuccessFinishNoResult);
+ }
+ else
+ {
+ result.AppendError ("invalid combination of options for the given command");
+ result.SetStatus (eReturnStatusFailed);
+ }
+
+ return options_are_valid;
+}
+
+// This is called in the Options constructor, though we could call it lazily if that ends up being
+// a performance problem.
+
+void
+Options::BuildValidOptionSets ()
+{
+ // Check to see if we already did this.
+ if (m_required_options.size() != 0)
+ return;
+
+ // Check to see if there are any options.
+ int num_options = NumCommandOptions ();
+ if (num_options == 0)
+ return;
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+ m_required_options.resize(1);
+ m_optional_options.resize(1);
+
+ // First count the number of option sets we've got. Ignore LLDB_ALL_OPTION_SETS...
+
+ uint32_t num_option_sets = 0;
+
+ for (int i = 0; i < num_options; i++)
+ {
+ uint32_t this_usage_mask = opt_defs[i].usage_mask;
+ if (this_usage_mask == LLDB_OPT_SET_ALL)
+ {
+ if (num_option_sets == 0)
+ num_option_sets = 1;
+ }
+ else
+ {
+ for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
+ {
+ if (this_usage_mask & (1 << j))
+ {
+ if (num_option_sets <= j)
+ num_option_sets = j + 1;
+ }
+ }
+ }
+ }
+
+ if (num_option_sets > 0)
+ {
+ m_required_options.resize(num_option_sets);
+ m_optional_options.resize(num_option_sets);
+
+ for (int i = 0; i < num_options; ++i)
+ {
+ for (uint32_t j = 0; j < num_option_sets; j++)
+ {
+ if (opt_defs[i].usage_mask & 1 << j)
+ {
+ if (opt_defs[i].required)
+ m_required_options[j].insert(opt_defs[i].short_option);
+ else
+ m_optional_options[j].insert(opt_defs[i].short_option);
+ }
+ }
+ }
+ }
+}
+
+uint32_t
+Options::NumCommandOptions ()
+{
+ const OptionDefinition *opt_defs = GetDefinitions ();
+ if (opt_defs == NULL)
+ return 0;
+
+ int i = 0;
+
+ if (opt_defs != NULL)
+ {
+ while (opt_defs[i].long_option != NULL)
+ ++i;
+ }
+
+ return i;
+}
+
+struct option *
+Options::GetLongOptions ()
+{
+ // Check to see if this has already been done.
+ if (m_getopt_table.empty())
+ {
+ // Check to see if there are any options.
+ const uint32_t num_options = NumCommandOptions();
+ if (num_options == 0)
+ return NULL;
+
+ uint32_t i;
+ const OptionDefinition *opt_defs = GetDefinitions();
+
+ std::map<int, uint32_t> option_seen;
+
+ m_getopt_table.resize(num_options + 1);
+ for (i = 0; i < num_options; ++i)
+ {
+ const int short_opt = opt_defs[i].short_option;
+
+ m_getopt_table[i].name = opt_defs[i].long_option;
+ m_getopt_table[i].has_arg = opt_defs[i].option_has_arg;
+ m_getopt_table[i].flag = NULL;
+ m_getopt_table[i].val = short_opt;
+
+ if (option_seen.find(short_opt) == option_seen.end())
+ {
+ option_seen[short_opt] = i;
+ }
+ else if (short_opt)
+ {
+ m_getopt_table[i].val = 0;
+ std::map<int, uint32_t>::const_iterator pos = option_seen.find(short_opt);
+ StreamString strm;
+ if (isprint8(short_opt))
+ Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option -%c that conflicts with option[%u] --%s, short option won't be used for --%s\n",
+ i,
+ opt_defs[i].long_option,
+ short_opt,
+ pos->second,
+ m_getopt_table[pos->second].name,
+ opt_defs[i].long_option);
+ else
+ Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option 0x%x that conflicts with option[%u] --%s, short option won't be used for --%s\n",
+ i,
+ opt_defs[i].long_option,
+ short_opt,
+ pos->second,
+ m_getopt_table[pos->second].name,
+ opt_defs[i].long_option);
+ }
+ }
+
+ //getopt_long_only requires a NULL final entry in the table:
+
+ m_getopt_table[i].name = NULL;
+ m_getopt_table[i].has_arg = 0;
+ m_getopt_table[i].flag = NULL;
+ m_getopt_table[i].val = 0;
+ }
+
+ if (m_getopt_table.empty())
+ return NULL;
+
+ return &m_getopt_table.front();
+}
+
+
+// This function takes INDENT, which tells how many spaces to output at the front of each line; SPACES, which is
+// a string containing 80 spaces; and TEXT, which is the text that is to be output. It outputs the text, on
+// multiple lines if necessary, to RESULT, with INDENT spaces at the front of each line. It breaks lines on spaces,
+// tabs or newlines, shortening the line if necessary to not break in the middle of a word. It assumes that each
+// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
+
+
+void
+Options::OutputFormattedUsageText
+(
+ Stream &strm,
+ const char *text,
+ uint32_t output_max_columns
+)
+{
+ int len = strlen (text);
+
+ // Will it all fit on one line?
+
+ if ((len + strm.GetIndentLevel()) < output_max_columns)
+ {
+ // Output it as a single line.
+ strm.Indent (text);
+ strm.EOL();
+ }
+ else
+ {
+ // We need to break it up into multiple lines.
+
+ int text_width = output_max_columns - strm.GetIndentLevel() - 1;
+ int start = 0;
+ int end = start;
+ int final_end = strlen (text);
+ int sub_len;
+
+ while (end < final_end)
+ {
+ // Don't start the 'text' on a space, since we're already outputting the indentation.
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ }
+
+ sub_len = end - start;
+ if (start != 0)
+ strm.EOL();
+ strm.Indent();
+ assert (start < final_end);
+ assert (start + sub_len <= final_end);
+ strm.Write(text + start, sub_len);
+ start = end + 1;
+ }
+ strm.EOL();
+ }
+}
+
+bool
+Options::SupportsLongOption (const char *long_option)
+{
+ if (long_option && long_option[0])
+ {
+ const OptionDefinition *opt_defs = GetDefinitions ();
+ if (opt_defs)
+ {
+ const char *long_option_name = long_option;
+ if (long_option[0] == '-' && long_option[1] == '-')
+ long_option_name += 2;
+
+ for (uint32_t i = 0; opt_defs[i].long_option; ++i)
+ {
+ if (strcmp(opt_defs[i].long_option, long_option_name) == 0)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+enum OptionDisplayType
+{
+ eDisplayBestOption,
+ eDisplayShortOption,
+ eDisplayLongOption
+};
+
+static bool
+PrintOption (const OptionDefinition &opt_def,
+ OptionDisplayType display_type,
+ const char *header,
+ const char *footer,
+ bool show_optional,
+ Stream &strm)
+{
+ const bool has_short_option = isprint8(opt_def.short_option) != 0;
+
+ if (display_type == eDisplayShortOption && !has_short_option)
+ return false;
+
+ if (header && header[0])
+ strm.PutCString(header);
+
+ if (show_optional && !opt_def.required)
+ strm.PutChar('[');
+ const bool show_short_option = has_short_option && display_type != eDisplayLongOption;
+ if (show_short_option)
+ strm.Printf ("-%c", opt_def.short_option);
+ else
+ strm.Printf ("--%s", opt_def.long_option);
+ switch (opt_def.option_has_arg)
+ {
+ case no_argument:
+ break;
+ case required_argument:
+ strm.Printf (" <%s>", CommandObject::GetArgumentName (opt_def.argument_type));
+ break;
+
+ case optional_argument:
+ strm.Printf ("%s[<%s>]",
+ show_short_option ? "" : "=",
+ CommandObject::GetArgumentName (opt_def.argument_type));
+ break;
+ }
+ if (show_optional && !opt_def.required)
+ strm.PutChar(']');
+ if (footer && footer[0])
+ strm.PutCString(footer);
+ return true;
+}
+
+void
+Options::GenerateOptionUsage
+(
+ Stream &strm,
+ CommandObject *cmd
+)
+{
+ const uint32_t screen_width = m_interpreter.GetDebugger().GetTerminalWidth();
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+ const uint32_t save_indent_level = strm.GetIndentLevel();
+ const char *name;
+
+ StreamString arguments_str;
+
+ if (cmd)
+ {
+ name = cmd->GetCommandName();
+ cmd->GetFormattedCommandArguments (arguments_str);
+ }
+ else
+ name = "";
+
+ strm.PutCString ("\nCommand Options Usage:\n");
+
+ strm.IndentMore(2);
+
+ // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
+ // <cmd> [options-for-level-1]
+ // etc.
+
+ const uint32_t num_options = NumCommandOptions();
+ if (num_options == 0)
+ return;
+
+ uint32_t num_option_sets = GetRequiredOptions().size();
+
+ uint32_t i;
+
+ for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set)
+ {
+ uint32_t opt_set_mask;
+
+ opt_set_mask = 1 << opt_set;
+ if (opt_set > 0)
+ strm.Printf ("\n");
+ strm.Indent (name);
+
+ // Different option sets may require different args.
+ StreamString args_str;
+ if (cmd)
+ cmd->GetFormattedCommandArguments(args_str, opt_set_mask);
+
+ // First go through and print all options that take no arguments as
+ // a single string. If a command has "-a" "-b" and "-c", this will show
+ // up as [-abc]
+
+ std::set<int> options;
+ std::set<int>::const_iterator options_pos, options_end;
+ for (i = 0; i < num_options; ++i)
+ {
+ if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option))
+ {
+ // Add current option to the end of out_stream.
+
+ if (opt_defs[i].required == true &&
+ opt_defs[i].option_has_arg == no_argument)
+ {
+ options.insert (opt_defs[i].short_option);
+ }
+ }
+ }
+
+ if (options.empty() == false)
+ {
+ // We have some required options with no arguments
+ strm.PutCString(" -");
+ for (i=0; i<2; ++i)
+ for (options_pos = options.begin(), options_end = options.end();
+ options_pos != options_end;
+ ++options_pos)
+ {
+ if (i==0 && ::islower (*options_pos))
+ continue;
+ if (i==1 && ::isupper (*options_pos))
+ continue;
+ strm << (char)*options_pos;
+ }
+ }
+
+ for (i = 0, options.clear(); i < num_options; ++i)
+ {
+ if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option))
+ {
+ // Add current option to the end of out_stream.
+
+ if (opt_defs[i].required == false &&
+ opt_defs[i].option_has_arg == no_argument)
+ {
+ options.insert (opt_defs[i].short_option);
+ }
+ }
+ }
+
+ if (options.empty() == false)
+ {
+ // We have some required options with no arguments
+ strm.PutCString(" [-");
+ for (i=0; i<2; ++i)
+ for (options_pos = options.begin(), options_end = options.end();
+ options_pos != options_end;
+ ++options_pos)
+ {
+ if (i==0 && ::islower (*options_pos))
+ continue;
+ if (i==1 && ::isupper (*options_pos))
+ continue;
+ strm << (char)*options_pos;
+ }
+ strm.PutChar(']');
+ }
+
+ // First go through and print the required options (list them up front).
+
+ for (i = 0; i < num_options; ++i)
+ {
+ if (opt_defs[i].usage_mask & opt_set_mask && isprint8(opt_defs[i].short_option))
+ {
+ if (opt_defs[i].required && opt_defs[i].option_has_arg != no_argument)
+ PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm);
+ }
+ }
+
+ // Now go through again, and this time only print the optional options.
+
+ for (i = 0; i < num_options; ++i)
+ {
+ if (opt_defs[i].usage_mask & opt_set_mask)
+ {
+ // Add current option to the end of out_stream.
+
+ if (!opt_defs[i].required && opt_defs[i].option_has_arg != no_argument)
+ PrintOption (opt_defs[i], eDisplayBestOption, " ", NULL, true, strm);
+ }
+ }
+
+ if (args_str.GetSize() > 0)
+ {
+ if (cmd->WantsRawCommandString())
+ strm.Printf(" --");
+
+ strm.Printf (" %s", args_str.GetData());
+ }
+ }
+
+ if (cmd &&
+ cmd->WantsRawCommandString() &&
+ arguments_str.GetSize() > 0)
+ {
+ strm.PutChar('\n');
+ strm.Indent(name);
+ strm.Printf(" %s", arguments_str.GetData());
+ }
+
+ strm.Printf ("\n\n");
+
+ // Now print out all the detailed information about the various options: long form, short form and help text:
+ // --long_name <argument> ( -short <argument> )
+ // help text
+
+ // This variable is used to keep track of which options' info we've printed out, because some options can be in
+ // more than one usage level, but we only want to print the long form of its information once.
+
+ std::multimap<int, uint32_t> options_seen;
+ strm.IndentMore (5);
+
+ // Put the unique command options in a vector & sort it, so we can output them alphabetically (by short_option)
+ // when writing out detailed help for each option.
+
+ for (i = 0; i < num_options; ++i)
+ options_seen.insert(std::make_pair(opt_defs[i].short_option, i));
+
+ // Go through the unique'd and alphabetically sorted vector of options, find the table entry for each option
+ // and write out the detailed help information for that option.
+
+ bool first_option_printed = false;;
+
+ for (auto pos : options_seen)
+ {
+ i = pos.second;
+ //Print out the help information for this option.
+
+ // Put a newline separation between arguments
+ if (first_option_printed)
+ strm.EOL();
+ else
+ first_option_printed = true;
+
+ CommandArgumentType arg_type = opt_defs[i].argument_type;
+
+ StreamString arg_name_str;
+ arg_name_str.Printf ("<%s>", CommandObject::GetArgumentName (arg_type));
+
+ strm.Indent ();
+ if (opt_defs[i].short_option && isprint8(opt_defs[i].short_option))
+ {
+ PrintOption (opt_defs[i], eDisplayShortOption, NULL, NULL, false, strm);
+ PrintOption (opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm);
+ }
+ else
+ {
+ // Short option is not printable, just print long option
+ PrintOption (opt_defs[i], eDisplayLongOption, NULL, NULL, false, strm);
+ }
+ strm.EOL();
+
+ strm.IndentMore (5);
+
+ if (opt_defs[i].usage_text)
+ OutputFormattedUsageText (strm,
+ opt_defs[i].usage_text,
+ screen_width);
+ if (opt_defs[i].enum_values != NULL)
+ {
+ strm.Indent ();
+ strm.Printf("Values: ");
+ for (int k = 0; opt_defs[i].enum_values[k].string_value != NULL; k++)
+ {
+ if (k == 0)
+ strm.Printf("%s", opt_defs[i].enum_values[k].string_value);
+ else
+ strm.Printf(" | %s", opt_defs[i].enum_values[k].string_value);
+ }
+ strm.EOL();
+ }
+ strm.IndentLess (5);
+ }
+
+ // Restore the indent level
+ strm.SetIndentLevel (save_indent_level);
+}
+
+// This function is called when we have been given a potentially incomplete set of
+// options, such as when an alias has been defined (more options might be added at
+// at the time the alias is invoked). We need to verify that the options in the set
+// m_seen_options are all part of a set that may be used together, but m_seen_options
+// may be missing some of the "required" options.
+
+bool
+Options::VerifyPartialOptions (CommandReturnObject &result)
+{
+ bool options_are_valid = false;
+
+ int num_levels = GetRequiredOptions().size();
+ if (num_levels)
+ {
+ for (int i = 0; i < num_levels && !options_are_valid; ++i)
+ {
+ // In this case we are treating all options as optional rather than required.
+ // Therefore a set of options is correct if m_seen_options is a subset of the
+ // union of m_required_options and m_optional_options.
+ OptionSet union_set;
+ OptionsSetUnion (GetRequiredOptions()[i], GetOptionalOptions()[i], union_set);
+ if (IsASubset (m_seen_options, union_set))
+ options_are_valid = true;
+ }
+ }
+
+ return options_are_valid;
+}
+
+bool
+Options::HandleOptionCompletion
+(
+ Args &input,
+ OptionElementVector &opt_element_vector,
+ int cursor_index,
+ int char_pos,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ lldb_private::StringList &matches
+)
+{
+ word_complete = true;
+
+ // For now we just scan the completions to see if the cursor position is in
+ // an option or its argument. Otherwise we'll call HandleArgumentCompletion.
+ // In the future we can use completion to validate options as well if we want.
+
+ const OptionDefinition *opt_defs = GetDefinitions();
+
+ std::string cur_opt_std_str (input.GetArgumentAtIndex(cursor_index));
+ cur_opt_std_str.erase(char_pos);
+ const char *cur_opt_str = cur_opt_std_str.c_str();
+
+ for (size_t i = 0; i < opt_element_vector.size(); i++)
+ {
+ int opt_pos = opt_element_vector[i].opt_pos;
+ int opt_arg_pos = opt_element_vector[i].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[i].opt_defs_index;
+ if (opt_pos == cursor_index)
+ {
+ // We're completing the option itself.
+
+ if (opt_defs_index == OptionArgElement::eBareDash)
+ {
+ // We're completing a bare dash. That means all options are open.
+ // FIXME: We should scan the other options provided and only complete options
+ // within the option group they belong to.
+ char opt_str[3] = {'-', 'a', '\0'};
+
+ for (int j = 0 ; opt_defs[j].short_option != 0 ; j++)
+ {
+ opt_str[1] = opt_defs[j].short_option;
+ matches.AppendString (opt_str);
+ }
+ return true;
+ }
+ else if (opt_defs_index == OptionArgElement::eBareDoubleDash)
+ {
+ std::string full_name ("--");
+ for (int j = 0 ; opt_defs[j].short_option != 0 ; j++)
+ {
+ full_name.erase(full_name.begin() + 2, full_name.end());
+ full_name.append (opt_defs[j].long_option);
+ matches.AppendString (full_name.c_str());
+ }
+ return true;
+ }
+ else if (opt_defs_index != OptionArgElement::eUnrecognizedArg)
+ {
+ // We recognized it, if it an incomplete long option, complete it anyway (getopt_long_only is
+ // happy with shortest unique string, but it's still a nice thing to do.) Otherwise return
+ // The string so the upper level code will know this is a full match and add the " ".
+ if (cur_opt_str && strlen (cur_opt_str) > 2
+ && cur_opt_str[0] == '-' && cur_opt_str[1] == '-'
+ && strcmp (opt_defs[opt_defs_index].long_option, cur_opt_str) != 0)
+ {
+ std::string full_name ("--");
+ full_name.append (opt_defs[opt_defs_index].long_option);
+ matches.AppendString(full_name.c_str());
+ return true;
+ }
+ else
+ {
+ matches.AppendString(input.GetArgumentAtIndex(cursor_index));
+ return true;
+ }
+ }
+ else
+ {
+ // FIXME - not handling wrong options yet:
+ // Check to see if they are writing a long option & complete it.
+ // I think we will only get in here if the long option table has two elements
+ // that are not unique up to this point. getopt_long_only does shortest unique match
+ // for long options already.
+
+ if (cur_opt_str && strlen (cur_opt_str) > 2
+ && cur_opt_str[0] == '-' && cur_opt_str[1] == '-')
+ {
+ for (int j = 0 ; opt_defs[j].short_option != 0 ; j++)
+ {
+ if (strstr(opt_defs[j].long_option, cur_opt_str + 2) == opt_defs[j].long_option)
+ {
+ std::string full_name ("--");
+ full_name.append (opt_defs[j].long_option);
+ // The options definitions table has duplicates because of the
+ // way the grouping information is stored, so only add once.
+ bool duplicate = false;
+ for (size_t k = 0; k < matches.GetSize(); k++)
+ {
+ if (matches.GetStringAtIndex(k) == full_name)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate)
+ matches.AppendString(full_name.c_str());
+ }
+ }
+ }
+ return true;
+ }
+
+
+ }
+ else if (opt_arg_pos == cursor_index)
+ {
+ // Okay the cursor is on the completion of an argument.
+ // See if it has a completion, otherwise return no matches.
+
+ if (opt_defs_index != -1)
+ {
+ HandleOptionArgumentCompletion (input,
+ cursor_index,
+ strlen (input.GetArgumentAtIndex(cursor_index)),
+ opt_element_vector,
+ i,
+ match_start_point,
+ max_return_elements,
+ word_complete,
+ matches);
+ return true;
+ }
+ else
+ {
+ // No completion callback means no completions...
+ return true;
+ }
+
+ }
+ else
+ {
+ // Not the last element, keep going.
+ continue;
+ }
+ }
+ return false;
+}
+
+bool
+Options::HandleOptionArgumentCompletion
+(
+ Args &input,
+ int cursor_index,
+ int char_pos,
+ OptionElementVector &opt_element_vector,
+ int opt_element_index,
+ int match_start_point,
+ int max_return_elements,
+ bool &word_complete,
+ lldb_private::StringList &matches
+)
+{
+ const OptionDefinition *opt_defs = GetDefinitions();
+ std::unique_ptr<SearchFilter> filter_ap;
+
+ int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
+ int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
+
+ // See if this is an enumeration type option, and if so complete it here:
+
+ OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values;
+ if (enum_values != NULL)
+ {
+ bool return_value = false;
+ std::string match_string(input.GetArgumentAtIndex (opt_arg_pos), input.GetArgumentAtIndex (opt_arg_pos) + char_pos);
+ for (int i = 0; enum_values[i].string_value != NULL; i++)
+ {
+ if (strstr(enum_values[i].string_value, match_string.c_str()) == enum_values[i].string_value)
+ {
+ matches.AppendString (enum_values[i].string_value);
+ return_value = true;
+ }
+ }
+ return return_value;
+ }
+
+ // If this is a source file or symbol type completion, and there is a
+ // -shlib option somewhere in the supplied arguments, then make a search filter
+ // for that shared library.
+ // FIXME: Do we want to also have an "OptionType" so we don't have to match string names?
+
+ uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;
+
+ if (completion_mask == 0)
+ {
+ lldb::CommandArgumentType option_arg_type = opt_defs[opt_defs_index].argument_type;
+ if (option_arg_type != eArgTypeNone)
+ {
+ CommandObject::ArgumentTableEntry *arg_entry = CommandObject::FindArgumentDataByType (opt_defs[opt_defs_index].argument_type);
+ if (arg_entry)
+ completion_mask = arg_entry->completion_type;
+ }
+ }
+
+ if (completion_mask & CommandCompletions::eSourceFileCompletion
+ || completion_mask & CommandCompletions::eSymbolCompletion)
+ {
+ for (size_t i = 0; i < opt_element_vector.size(); i++)
+ {
+ int cur_defs_index = opt_element_vector[i].opt_defs_index;
+ int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
+ const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
+
+ // If this is the "shlib" option and there was an argument provided,
+ // restrict it to that shared library.
+ if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1)
+ {
+ const char *module_name = input.GetArgumentAtIndex(cur_arg_pos);
+ if (module_name)
+ {
+ FileSpec module_spec(module_name, false);
+ lldb::TargetSP target_sp = m_interpreter.GetDebugger().GetSelectedTarget();
+ // Search filters require a target...
+ if (target_sp)
+ filter_ap.reset (new SearchFilterByModule (target_sp, module_spec));
+ }
+ break;
+ }
+ }
+ }
+
+ return CommandCompletions::InvokeCommonCompletionCallbacks (m_interpreter,
+ completion_mask,
+ input.GetArgumentAtIndex (opt_arg_pos),
+ match_start_point,
+ max_return_elements,
+ filter_ap.get(),
+ word_complete,
+ matches);
+
+}
+
+
+void
+OptionGroupOptions::Append (OptionGroup* group)
+{
+ const OptionDefinition* group_option_defs = group->GetDefinitions ();
+ const uint32_t group_option_count = group->GetNumDefinitions();
+ for (uint32_t i=0; i<group_option_count; ++i)
+ {
+ m_option_infos.push_back (OptionInfo (group, i));
+ m_option_defs.push_back (group_option_defs[i]);
+ }
+}
+
+void
+OptionGroupOptions::Append (OptionGroup* group,
+ uint32_t src_mask,
+ uint32_t dst_mask)
+{
+ const OptionDefinition* group_option_defs = group->GetDefinitions ();
+ const uint32_t group_option_count = group->GetNumDefinitions();
+ for (uint32_t i=0; i<group_option_count; ++i)
+ {
+ if (group_option_defs[i].usage_mask & src_mask)
+ {
+ m_option_infos.push_back (OptionInfo (group, i));
+ m_option_defs.push_back (group_option_defs[i]);
+ m_option_defs.back().usage_mask = dst_mask;
+ }
+ }
+}
+
+void
+OptionGroupOptions::Finalize ()
+{
+ m_did_finalize = true;
+ OptionDefinition empty_option_def = { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL };
+ m_option_defs.push_back (empty_option_def);
+}
+
+Error
+OptionGroupOptions::SetOptionValue (uint32_t option_idx,
+ const char *option_value)
+{
+ // After calling OptionGroupOptions::Append(...), you must finalize the groups
+ // by calling OptionGroupOptions::Finlize()
+ assert (m_did_finalize);
+ assert (m_option_infos.size() + 1 == m_option_defs.size());
+ Error error;
+ if (option_idx < m_option_infos.size())
+ {
+ error = m_option_infos[option_idx].option_group->SetOptionValue (m_interpreter,
+ m_option_infos[option_idx].option_index,
+ option_value);
+
+ }
+ else
+ {
+ error.SetErrorString ("invalid option index"); // Shouldn't happen...
+ }
+ return error;
+}
+
+void
+OptionGroupOptions::OptionParsingStarting ()
+{
+ std::set<OptionGroup*> group_set;
+ OptionInfos::iterator pos, end = m_option_infos.end();
+ for (pos = m_option_infos.begin(); pos != end; ++pos)
+ {
+ OptionGroup* group = pos->option_group;
+ if (group_set.find(group) == group_set.end())
+ {
+ group->OptionParsingStarting (m_interpreter);
+ group_set.insert(group);
+ }
+ }
+}
+Error
+OptionGroupOptions::OptionParsingFinished ()
+{
+ std::set<OptionGroup*> group_set;
+ Error error;
+ OptionInfos::iterator pos, end = m_option_infos.end();
+ for (pos = m_option_infos.begin(); pos != end; ++pos)
+ {
+ OptionGroup* group = pos->option_group;
+ if (group_set.find(group) == group_set.end())
+ {
+ error = group->OptionParsingFinished (m_interpreter);
+ group_set.insert(group);
+ if (error.Fail())
+ return error;
+ }
+ }
+ return error;
+}
diff --git a/source/Interpreter/Property.cpp b/source/Interpreter/Property.cpp
new file mode 100644
index 000000000000..e5cf63ada882
--- /dev/null
+++ b/source/Interpreter/Property.cpp
@@ -0,0 +1,275 @@
+//===-- Property.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/Interpreter/Property.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValues.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Property::Property (const PropertyDefinition &definition) :
+ m_name (definition.name),
+ m_description (definition.description),
+ m_value_sp (),
+ m_is_global (definition.global)
+{
+ switch (definition.type)
+ {
+ case OptionValue::eTypeInvalid:
+ case OptionValue::eTypeProperties:
+ break;
+ case OptionValue::eTypeArch:
+ // "definition.default_uint_value" is not used
+ // "definition.default_cstr_value" as a string value that represents the default string value for the architecture/triple
+ m_value_sp.reset (new OptionValueArch(definition.default_cstr_value));
+ break;
+
+ case OptionValue::eTypeArgs:
+ // "definition.default_uint_value" is always a OptionValue::Type
+ m_value_sp.reset (new OptionValueArgs());
+ break;
+
+ case OptionValue::eTypeArray:
+ // "definition.default_uint_value" is always a OptionValue::Type
+ m_value_sp.reset (new OptionValueArray(OptionValue::ConvertTypeToMask((OptionValue::Type)definition.default_uint_value)));
+ break;
+
+ case OptionValue::eTypeBoolean:
+ // "definition.default_uint_value" is the default boolean value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ if (definition.default_cstr_value)
+ m_value_sp.reset (new OptionValueBoolean(Args::StringToBoolean (definition.default_cstr_value, false, NULL)));
+ else
+ m_value_sp.reset (new OptionValueBoolean(definition.default_uint_value != 0));
+ 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)));
+ break;
+
+ case OptionValue::eTypeEnum:
+ // "definition.default_uint_value" is the default enumeration value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ {
+ OptionValueEnumeration *enum_value = new OptionValueEnumeration(definition.enum_values, definition.default_uint_value);
+ m_value_sp.reset (enum_value);
+ if (definition.default_cstr_value)
+ {
+ if (enum_value->SetValueFromCString(definition.default_cstr_value).Success())
+ {
+ enum_value->SetDefaultValue(enum_value->GetCurrentValue());
+ // Call Clear() since we don't want the value to appear as
+ // having been set since we called SetValueFromCString() above.
+ // Clear will set the current value to the default and clear
+ // the boolean that says that the value has been set.
+ enum_value->Clear();
+ }
+ }
+ }
+ break;
+
+ case OptionValue::eTypeFileSpec:
+ // "definition.default_uint_value" represents if the "definition.default_cstr_value" should
+ // be resolved or not
+ m_value_sp.reset (new OptionValueFileSpec(FileSpec(definition.default_cstr_value, definition.default_uint_value != 0)));
+ break;
+
+ case OptionValue::eTypeFileSpecList:
+ // "definition.default_uint_value" is not used for a OptionValue::eTypeFileSpecList
+ m_value_sp.reset (new OptionValueFileSpecList());
+ break;
+
+ case OptionValue::eTypeFormat:
+ // "definition.default_uint_value" is the default format enumeration value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ {
+ Format new_format = eFormatInvalid;
+ if (definition.default_cstr_value)
+ Args::StringToFormat (definition.default_cstr_value, new_format, NULL);
+ else
+ new_format = (Format)definition.default_uint_value;
+ m_value_sp.reset (new OptionValueFormat(new_format));
+ }
+ break;
+
+ case OptionValue::eTypePathMap:
+ // "definition.default_uint_value" tells us if notifications should occur for
+ // path mappings
+ m_value_sp.reset (new OptionValuePathMappings(definition.default_uint_value != 0));
+ break;
+
+ case OptionValue::eTypeRegex:
+ // "definition.default_uint_value" is used to the regular expression flags
+ // "definition.default_cstr_value" the default regular expression value
+ // value.
+ m_value_sp.reset (new OptionValueRegex(definition.default_cstr_value, definition.default_uint_value));
+ break;
+
+ case OptionValue::eTypeSInt64:
+ // "definition.default_uint_value" is the default integer value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ m_value_sp.reset (new OptionValueSInt64(definition.default_cstr_value ? Args::StringToSInt64 (definition.default_cstr_value) : definition.default_uint_value));
+ break;
+
+ case OptionValue::eTypeUInt64:
+ // "definition.default_uint_value" is the default unsigned integer value if
+ // "definition.default_cstr_value" is NULL, otherwise interpret
+ // "definition.default_cstr_value" as a string value that represents the default
+ // value.
+ m_value_sp.reset (new OptionValueUInt64(definition.default_cstr_value ? Args::StringToUInt64 (definition.default_cstr_value) : definition.default_uint_value));
+ break;
+
+ case OptionValue::eTypeUUID:
+ // "definition.default_uint_value" is not used for a OptionValue::eTypeUUID
+ // "definition.default_cstr_value" can contain a default UUID value
+ {
+ UUID uuid;
+ if (definition.default_cstr_value)
+ uuid.SetFromCString (definition.default_cstr_value);
+ m_value_sp.reset (new OptionValueUUID(uuid));
+ }
+ break;
+
+ case OptionValue::eTypeString:
+ // "definition.default_uint_value" can contain the string option flags OR'ed together
+ // "definition.default_cstr_value" can contain a default string value
+ {
+ OptionValueString *string_value = new OptionValueString(definition.default_cstr_value);
+ if (definition.default_uint_value != 0)
+ string_value->GetOptions().Reset(definition.default_uint_value);
+ m_value_sp.reset (string_value);
+ }
+ break;
+ }
+}
+
+Property::Property (const ConstString &name,
+ const ConstString &desc,
+ bool is_global,
+ const lldb::OptionValueSP &value_sp) :
+ m_name (name),
+ m_description (desc),
+ m_value_sp (value_sp),
+ m_is_global (is_global)
+{
+}
+
+bool
+Property::DumpQualifiedName(Stream &strm) const
+{
+ if (m_name)
+ {
+ if (m_value_sp->DumpQualifiedName(strm))
+ strm.PutChar('.');
+ strm << m_name;
+ return true;
+ }
+ return false;
+}
+
+
+void
+Property::Dump (const ExecutionContext *exe_ctx, Stream &strm, uint32_t dump_mask) const
+{
+ if (m_value_sp)
+ {
+ const bool dump_desc = dump_mask & OptionValue::eDumpOptionDescription;
+ const bool transparent = m_value_sp->ValueIsTransparent ();
+ if (dump_desc || !transparent)
+ {
+ if ((dump_mask & OptionValue::eDumpOptionName) && m_name)
+ {
+ DumpQualifiedName(strm);
+ if (dump_mask & ~OptionValue::eDumpOptionName)
+ strm.PutChar(' ');
+ }
+ }
+ if (dump_desc)
+ {
+ const char *desc = GetDescription();
+ if (desc)
+ strm.Printf ("-- %s", desc);
+
+ if (transparent && (dump_mask == (OptionValue::eDumpOptionName | OptionValue::eDumpOptionDescription)))
+ strm.EOL();
+ }
+ m_value_sp->DumpValue(exe_ctx, strm, dump_mask);
+ }
+}
+
+
+void
+Property::DumpDescription (CommandInterpreter &interpreter,
+ Stream &strm,
+ uint32_t output_width,
+ bool display_qualified_name) const
+{
+ if (m_value_sp)
+ {
+ const char *desc = GetDescription();
+
+ if (desc)
+ {
+ StreamString qualified_name;
+ const OptionValueProperties *sub_properties = m_value_sp->GetAsProperties();
+ if (sub_properties)
+ {
+ strm.EOL();
+
+ if (m_value_sp->DumpQualifiedName(qualified_name))
+ strm.Printf("'%s' variables:\n\n", qualified_name.GetString().c_str());
+ sub_properties->DumpAllDescriptions(interpreter, strm);
+ }
+ else
+ {
+ if (desc)
+ {
+ if (display_qualified_name)
+ {
+ StreamString qualified_name;
+ DumpQualifiedName(qualified_name);
+ interpreter.OutputFormattedHelpText (strm,
+ qualified_name.GetString().c_str(),
+ "--",
+ desc,
+ output_width);
+ }
+ else
+ {
+ interpreter.OutputFormattedHelpText (strm,
+ m_name.GetCString(),
+ "--",
+ desc,
+ output_width);
+ }
+ }
+ }
+ }
+ }
+}
+
diff --git a/source/Interpreter/PythonDataObjects.cpp b/source/Interpreter/PythonDataObjects.cpp
new file mode 100644
index 000000000000..2a1f348e14b7
--- /dev/null
+++ b/source/Interpreter/PythonDataObjects.cpp
@@ -0,0 +1,430 @@
+//===-- PythonDataObjects.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// In order to guarantee correct working with Python, Python.h *MUST* be
+// the *FIRST* header file included here.
+#ifdef LLDB_DISABLE_PYTHON
+
+// Python is disabled in this build
+
+#else
+
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+#include <stdio.h>
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/File.h"
+#include "lldb/Interpreter/PythonDataObjects.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+//----------------------------------------------------------------------
+// PythonObject
+//----------------------------------------------------------------------
+PythonObject::PythonObject (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
+ m_py_obj (NULL)
+{
+ if (script_object_sp)
+ Reset ((PyObject *)script_object_sp->GetObject());
+}
+
+void
+PythonObject::Dump (Stream &strm) const
+{
+ if (m_py_obj)
+ {
+ FILE *file = ::tmpfile();
+ if (file)
+ {
+ ::PyObject_Print (m_py_obj, file, 0);
+ const long length = ftell (file);
+ if (length)
+ {
+ ::rewind(file);
+ std::vector<char> file_contents (length,'\0');
+ const size_t length_read = ::fread (file_contents.data(), 1, file_contents.size(), file);
+ if (length_read > 0)
+ strm.Write (file_contents.data(), length_read);
+ }
+ ::fclose (file);
+ }
+ }
+ else
+ strm.PutCString ("NULL");
+}
+
+PythonString
+PythonObject::Repr ()
+{
+ if (!m_py_obj)
+ return PythonString ();
+ PyObject *repr = PyObject_Repr(m_py_obj);
+ if (!repr)
+ return PythonString ();
+ return PythonString(repr);
+}
+
+PythonString
+PythonObject::Str ()
+{
+ if (!m_py_obj)
+ return PythonString ();
+ PyObject *str = PyObject_Str(m_py_obj);
+ if (!str)
+ return PythonString ();
+ return PythonString(str);
+}
+
+//----------------------------------------------------------------------
+// PythonString
+//----------------------------------------------------------------------
+
+PythonString::PythonString (PyObject *py_obj) :
+ PythonObject(py_obj)
+{
+}
+
+PythonString::PythonString (const PythonObject &object) :
+ PythonObject(object.GetPythonObject())
+{
+}
+
+PythonString::PythonString (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
+ PythonObject (script_object_sp)
+{
+}
+
+PythonString::PythonString (const char* string) :
+ PythonObject(PyString_FromString(string))
+{
+}
+
+PythonString::PythonString () :
+ PythonObject()
+{
+}
+
+PythonString::~PythonString ()
+{
+}
+
+bool
+PythonString::Reset (PyObject *py_obj)
+{
+ if (py_obj && PyString_Check(py_obj))
+ return PythonObject::Reset(py_obj);
+
+ PythonObject::Reset(NULL);
+ return py_obj == NULL;
+}
+
+const char*
+PythonString::GetString() const
+{
+ if (m_py_obj)
+ return PyString_AsString(m_py_obj);
+ return NULL;
+}
+
+size_t
+PythonString::GetSize() const
+{
+ if (m_py_obj)
+ return PyString_Size(m_py_obj);
+ return 0;
+}
+
+void
+PythonString::SetString (const char* string)
+{
+ PythonObject::Reset(PyString_FromString(string));
+}
+
+//----------------------------------------------------------------------
+// PythonInteger
+//----------------------------------------------------------------------
+
+PythonInteger::PythonInteger (PyObject *py_obj) :
+ PythonObject(py_obj)
+{
+}
+
+PythonInteger::PythonInteger (const PythonObject &object) :
+ PythonObject(object.GetPythonObject())
+{
+}
+
+PythonInteger::PythonInteger (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
+ PythonObject (script_object_sp)
+{
+}
+
+PythonInteger::PythonInteger (int64_t value) :
+ PythonObject(PyInt_FromLong(value))
+{
+}
+
+
+PythonInteger::~PythonInteger ()
+{
+}
+
+bool
+PythonInteger::Reset (PyObject *py_obj)
+{
+ if (py_obj && PyInt_Check(py_obj))
+ return PythonObject::Reset(py_obj);
+
+ PythonObject::Reset(NULL);
+ return py_obj == NULL;
+}
+
+int64_t
+PythonInteger::GetInteger()
+{
+ if (m_py_obj)
+ return PyInt_AsLong(m_py_obj);
+ else
+ return UINT64_MAX;
+}
+
+void
+PythonInteger::SetInteger (int64_t value)
+{
+ PythonObject::Reset(PyInt_FromLong(value));
+}
+
+//----------------------------------------------------------------------
+// PythonList
+//----------------------------------------------------------------------
+
+PythonList::PythonList () :
+ PythonObject(PyList_New(0))
+{
+}
+
+PythonList::PythonList (uint32_t count) :
+ PythonObject(PyList_New(count))
+{
+}
+
+PythonList::PythonList (PyObject *py_obj) :
+ PythonObject(py_obj)
+{
+}
+
+
+PythonList::PythonList (const PythonObject &object) :
+ PythonObject(object.GetPythonObject())
+{
+}
+
+PythonList::PythonList (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
+ PythonObject (script_object_sp)
+{
+}
+
+PythonList::~PythonList ()
+{
+}
+
+bool
+PythonList::Reset (PyObject *py_obj)
+{
+ if (py_obj && PyList_Check(py_obj))
+ return PythonObject::Reset(py_obj);
+
+ PythonObject::Reset(NULL);
+ return py_obj == NULL;
+}
+
+uint32_t
+PythonList::GetSize()
+{
+ if (m_py_obj)
+ return PyList_GET_SIZE(m_py_obj);
+ return 0;
+}
+
+PythonObject
+PythonList::GetItemAtIndex (uint32_t index)
+{
+ if (m_py_obj)
+ return PythonObject(PyList_GetItem(m_py_obj, index));
+ return NULL;
+}
+
+void
+PythonList::SetItemAtIndex (uint32_t index, const PythonObject & object)
+{
+ if (m_py_obj && object)
+ PyList_SetItem(m_py_obj, index, object.GetPythonObject());
+}
+
+void
+PythonList::AppendItem (const PythonObject &object)
+{
+ if (m_py_obj && object)
+ PyList_Append(m_py_obj, object.GetPythonObject());
+}
+
+//----------------------------------------------------------------------
+// PythonDictionary
+//----------------------------------------------------------------------
+
+PythonDictionary::PythonDictionary () :
+ PythonObject(PyDict_New())
+{
+}
+
+PythonDictionary::PythonDictionary (PyObject *py_obj) :
+ PythonObject(py_obj)
+{
+}
+
+
+PythonDictionary::PythonDictionary (const PythonObject &object) :
+ PythonObject(object.GetPythonObject())
+{
+}
+
+PythonDictionary::PythonDictionary (const lldb::ScriptInterpreterObjectSP &script_object_sp) :
+ PythonObject (script_object_sp)
+{
+}
+
+PythonDictionary::~PythonDictionary ()
+{
+}
+
+bool
+PythonDictionary::Reset (PyObject *py_obj)
+{
+ if (py_obj && PyDict_Check(py_obj))
+ return PythonObject::Reset(py_obj);
+
+ PythonObject::Reset(NULL);
+ return py_obj == NULL;
+}
+
+uint32_t
+PythonDictionary::GetSize()
+{
+ if (m_py_obj)
+ return PyDict_Size(m_py_obj);
+ return 0;
+}
+
+PythonObject
+PythonDictionary::GetItemForKey (const char *key) const
+{
+ if (key && key[0])
+ {
+ PythonString python_key(key);
+ return GetItemForKey(python_key);
+ }
+ return NULL;
+}
+
+
+PythonObject
+PythonDictionary::GetItemForKey (const PythonString &key) const
+{
+ if (m_py_obj && key)
+ return PythonObject(PyDict_GetItem(m_py_obj, key.GetPythonObject()));
+ return PythonObject();
+}
+
+
+const char *
+PythonDictionary::GetItemForKeyAsString (const PythonString &key, const char *fail_value) const
+{
+ if (m_py_obj && key)
+ {
+ PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject());
+ if (py_obj && PyString_Check(py_obj))
+ return PyString_AsString(py_obj);
+ }
+ return fail_value;
+}
+
+int64_t
+PythonDictionary::GetItemForKeyAsInteger (const PythonString &key, int64_t fail_value) const
+{
+ if (m_py_obj && key)
+ {
+ PyObject *py_obj = PyDict_GetItem(m_py_obj, key.GetPythonObject());
+ if (py_obj)
+ {
+ if (PyInt_Check(py_obj))
+ return PyInt_AsLong(py_obj);
+
+ if (PyLong_Check(py_obj))
+ return PyLong_AsLong(py_obj);
+ }
+ }
+ return fail_value;
+}
+
+PythonList
+PythonDictionary::GetKeys () const
+{
+ if (m_py_obj)
+ return PythonList(PyDict_Keys(m_py_obj));
+ return PythonList();
+}
+
+PythonString
+PythonDictionary::GetKeyAtPosition (uint32_t pos) const
+{
+ PyObject *key, *value;
+ Py_ssize_t pos_iter = 0;
+
+ if (m_py_obj)
+ {
+ while (PyDict_Next(m_py_obj, &pos_iter, &key, &value))
+ {
+ if (pos-- == 0)
+ return PythonString(key);
+ }
+ }
+ return PythonString();
+}
+
+PythonObject
+PythonDictionary::GetValueAtPosition (uint32_t pos) const
+{
+ PyObject *key, *value;
+ Py_ssize_t pos_iter = 0;
+
+ if (!m_py_obj)
+ return NULL;
+
+ while (PyDict_Next(m_py_obj, &pos_iter, &key, &value)) {
+ if (pos-- == 0)
+ return PythonObject(value);
+ }
+ return PythonObject();
+}
+
+void
+PythonDictionary::SetItemForKey (const PythonString &key, const PythonObject &value)
+{
+ if (m_py_obj && key && value)
+ PyDict_SetItem(m_py_obj, key.GetPythonObject(), value.GetPythonObject());
+}
+
+#endif
diff --git a/source/Interpreter/ScriptInterpreter.cpp b/source/Interpreter/ScriptInterpreter.cpp
new file mode 100644
index 000000000000..67314731df2a
--- /dev/null
+++ b/source/Interpreter/ScriptInterpreter.cpp
@@ -0,0 +1,105 @@
+//===-- ScriptInterpreter.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/Interpreter/ScriptInterpreter.h"
+
+#include <string>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) :
+ m_interpreter (interpreter),
+ m_script_lang (script_lang)
+{
+}
+
+ScriptInterpreter::~ScriptInterpreter ()
+{
+}
+
+CommandInterpreter &
+ScriptInterpreter::GetCommandInterpreter ()
+{
+ return m_interpreter;
+}
+
+void
+ScriptInterpreter::CollectDataForBreakpointCommandCallback
+(
+ BreakpointOptions *bp_options,
+ CommandReturnObject &result
+)
+{
+ result.SetStatus (eReturnStatusFailed);
+ result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented.");
+}
+
+void
+ScriptInterpreter::CollectDataForWatchpointCommandCallback
+(
+ WatchpointOptions *bp_options,
+ CommandReturnObject &result
+)
+{
+ result.SetStatus (eReturnStatusFailed);
+ result.AppendError ("ScriptInterpreter::GetScriptCommands(StringList &) is not implemented.");
+}
+
+std::string
+ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
+{
+ std::string return_value;
+
+ switch (language)
+ {
+ case eScriptLanguageNone:
+ return_value = "None";
+ break;
+ case eScriptLanguagePython:
+ return_value = "Python";
+ break;
+ }
+
+ return return_value;
+}
+
+std::unique_ptr<ScriptInterpreterLocker>
+ScriptInterpreter::AcquireInterpreterLock ()
+{
+ return std::unique_ptr<ScriptInterpreterLocker>(new ScriptInterpreterLocker());
+}
+
+void
+ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback);
+#endif // #ifndef LLDB_DISABLE_PYTHON
+}
+
+void
+ScriptInterpreter::TerminateInterpreter ()
+{
+#ifndef LLDB_DISABLE_PYTHON
+ ScriptInterpreterPython::TerminateInterpreter ();
+#endif // #ifndef LLDB_DISABLE_PYTHON
+}
+
diff --git a/source/Interpreter/ScriptInterpreterNone.cpp b/source/Interpreter/ScriptInterpreterNone.cpp
new file mode 100644
index 000000000000..6a4411494c43
--- /dev/null
+++ b/source/Interpreter/ScriptInterpreterNone.cpp
@@ -0,0 +1,43 @@
+//===-- ScriptInterpreterNone.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/Interpreter/ScriptInterpreterNone.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ScriptInterpreterNone::ScriptInterpreterNone (CommandInterpreter &interpreter) :
+ ScriptInterpreter (interpreter, eScriptLanguageNone)
+{
+}
+
+ScriptInterpreterNone::~ScriptInterpreterNone ()
+{
+}
+
+bool
+ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, const ExecuteScriptOptions&)
+{
+ m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n");
+ return false;
+}
+
+void
+ScriptInterpreterNone::ExecuteInterpreterLoop ()
+{
+ m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n");
+}
+
+
diff --git a/source/Interpreter/ScriptInterpreterPython.cpp b/source/Interpreter/ScriptInterpreterPython.cpp
new file mode 100644
index 000000000000..9d9b8d93fb4d
--- /dev/null
+++ b/source/Interpreter/ScriptInterpreterPython.cpp
@@ -0,0 +1,3166 @@
+//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// In order to guarantee correct working with Python, Python.h *MUST* be
+// the *FIRST* header file included here.
+#ifdef LLDB_DISABLE_PYTHON
+
+// Python is disabled in this build
+
+#else
+
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "lldb/API/SBValue.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/WatchpointOptions.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
+static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
+static ScriptInterpreter::SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = NULL;
+static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
+static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL;
+static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = NULL;
+static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL;
+static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
+static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL;
+static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
+static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL;
+static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
+static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL;
+static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = NULL;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = NULL;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = NULL;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = NULL;
+static ScriptInterpreter::SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = NULL;
+
+// these are the Pythonic implementations of the required callbacks
+// these are scripting-language specific, which is why they belong here
+// we still need to use function pointers to them instead of relying
+// on linkage-time resolution because the SWIG stuff and this file
+// get built at different times
+extern "C" bool
+LLDBSwigPythonBreakpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::BreakpointLocationSP& sb_bp_loc);
+
+extern "C" bool
+LLDBSwigPythonWatchpointCallbackFunction (const char *python_function_name,
+ const char *session_dictionary_name,
+ const lldb::StackFrameSP& sb_frame,
+ const lldb::WatchpointSP& sb_wp);
+
+extern "C" bool
+LLDBSwigPythonCallTypeScript (const char *python_function_name,
+ void *session_dictionary,
+ const lldb::ValueObjectSP& valobj_sp,
+ void** pyfunct_wrapper,
+ std::string& retval);
+
+extern "C" void*
+LLDBSwigPythonCreateSyntheticProvider (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ValueObjectSP& valobj_sp);
+
+
+extern "C" uint32_t
+LLDBSwigPython_CalculateNumChildren (void *implementor);
+
+extern "C" void *
+LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
+
+extern "C" int
+LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
+
+extern "C" void *
+LLDBSWIGPython_CastPyObjectToSBValue (void* data);
+
+extern "C" bool
+LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
+
+extern "C" bool
+LLDBSwigPython_MightHaveChildrenSynthProviderInstance (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);
+
+extern "C" bool
+LLDBSwigPythonCallModuleInit (const char *python_module_name,
+ const char *session_dictionary_name,
+ lldb::DebuggerSP& debugger);
+
+extern "C" void*
+LLDBSWIGPythonCreateOSPlugin (const char *python_class_name,
+ const char *session_dictionary_name,
+ const lldb::ProcessSP& process_sp);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordProcess (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ProcessSP& process,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordThread (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::ThreadSP& thread,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordTarget (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::TargetSP& target,
+ std::string& output);
+
+extern "C" bool
+LLDBSWIGPythonRunScriptKeywordFrame (const char* python_function_name,
+ const char* session_dictionary_name,
+ lldb::StackFrameSP& frame,
+ std::string& output);
+
+static int
+_check_and_flush (FILE *stream)
+{
+ int prev_fail = ferror (stream);
+ return fflush (stream) || prev_fail ? EOF : 0;
+}
+
+ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter,
+ uint16_t on_entry,
+ uint16_t on_leave,
+ FILE* wait_msg_handle) :
+ ScriptInterpreterLocker (),
+ m_teardown_session( (on_leave & TearDownSession) == TearDownSession ),
+ m_python_interpreter(py_interpreter),
+ m_tmp_fh(wait_msg_handle)
+{
+ if (m_python_interpreter && !m_tmp_fh)
+ m_tmp_fh = (m_python_interpreter->m_dbg_stdout ? m_python_interpreter->m_dbg_stdout : stdout);
+
+ DoAcquireLock();
+ if ((on_entry & InitSession) == InitSession)
+ {
+ if (DoInitSession((on_entry & InitGlobals) == InitGlobals) == false)
+ {
+ // Don't teardown the session if we didn't init it.
+ m_teardown_session = false;
+ }
+ }
+}
+
+bool
+ScriptInterpreterPython::Locker::DoAcquireLock()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
+ m_GILState = PyGILState_Ensure();
+ if (log)
+ log->Printf("Ensured PyGILState. Previous state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : "");
+ return true;
+}
+
+bool
+ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals)
+{
+ if (!m_python_interpreter)
+ return false;
+ return m_python_interpreter->EnterSession (init_lldb_globals);
+}
+
+bool
+ScriptInterpreterPython::Locker::DoFreeLock()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
+ if (log)
+ log->Printf("Releasing PyGILState. Returning to state = %slocked\n", m_GILState == PyGILState_UNLOCKED ? "un" : "");
+ PyGILState_Release(m_GILState);
+ return true;
+}
+
+bool
+ScriptInterpreterPython::Locker::DoTearDownSession()
+{
+ if (!m_python_interpreter)
+ return false;
+ m_python_interpreter->LeaveSession ();
+ return true;
+}
+
+ScriptInterpreterPython::Locker::~Locker()
+{
+ if (m_teardown_session)
+ DoTearDownSession();
+ DoFreeLock();
+}
+
+ScriptInterpreterPython::PythonInputReaderManager::PythonInputReaderManager (ScriptInterpreterPython *interpreter) :
+m_interpreter(interpreter),
+m_debugger_sp(),
+m_reader_sp(),
+m_error(false)
+{
+ if (m_interpreter == NULL)
+ {
+ m_error = true;
+ return;
+ }
+
+ m_debugger_sp = m_interpreter->GetCommandInterpreter().GetDebugger().shared_from_this();
+
+ if (!m_debugger_sp)
+ {
+ m_error = true;
+ return;
+ }
+
+ m_reader_sp = InputReaderSP(new InputReader(*m_debugger_sp.get()));
+
+ if (!m_reader_sp)
+ {
+ m_error = true;
+ return;
+ }
+
+ Error error (m_reader_sp->Initialize (ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback,
+ m_interpreter, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ NULL, // prompt
+ true)); // echo input
+ if (error.Fail())
+ m_error = true;
+ else
+ {
+ m_debugger_sp->PushInputReader (m_reader_sp);
+ m_interpreter->m_embedded_thread_input_reader_sp = m_reader_sp;
+ }
+}
+
+ScriptInterpreterPython::PythonInputReaderManager::~PythonInputReaderManager()
+{
+ // Nothing to do if either m_interpreter or m_reader_sp is invalid.
+ if (!m_interpreter || !m_reader_sp)
+ return;
+
+ m_reader_sp->SetIsDone (true);
+ if (m_debugger_sp)
+ m_debugger_sp->PopInputReader(m_reader_sp);
+
+ // Only mess with m_interpreter's counterpart if, indeed, they are the same object.
+ if (m_reader_sp.get() == m_interpreter->m_embedded_thread_input_reader_sp.get())
+ {
+ m_interpreter->m_embedded_thread_pty.CloseSlaveFileDescriptor();
+ m_interpreter->m_embedded_thread_input_reader_sp.reset();
+ }
+}
+
+size_t
+ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback (void *baton,
+ InputReader &reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+{
+ lldb::thread_t embedded_interpreter_thread;
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+
+ if (baton == NULL)
+ return 0;
+
+ ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+
+ if (script_interpreter->m_script_lang != eScriptLanguagePython)
+ return 0;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+ // Save terminal settings if we can
+ int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor();
+ if (input_fd == File::kInvalidDescriptor)
+ input_fd = STDIN_FILENO;
+
+ script_interpreter->SaveTerminalState(input_fd);
+
+ char error_str[1024];
+ if (script_interpreter->m_embedded_thread_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str,
+ sizeof(error_str)))
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in opening master pty (fd = %d).",
+ script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor());
+ {
+ StreamString run_string;
+ char error_str[1024];
+ const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
+ if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
+ {
+ ScriptInterpreterPython::Locker locker(script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(),
+ pty_slave_name);
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+ }
+ }
+ embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.noninteractive-python>",
+ ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader,
+ script_interpreter, NULL);
+ if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread))
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread);
+ Error detach_error;
+ Host::ThreadDetach (embedded_interpreter_thread, &detach_error);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed in creating thread");
+ reader.SetIsDone (true);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed to open master pty ");
+ reader.SetIsDone (true);
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ // When another input reader is pushed, don't leave the session...
+ //script_interpreter->LeaveSession ();
+ break;
+
+ case eInputReaderReactivate:
+// {
+// ScriptInterpreterPython::Locker locker(script_interpreter,
+// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
+// ScriptInterpreterPython::Locker::FreeAcquiredLock);
+// }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderInterrupt:
+ {
+ PyThreadState* state = _PyThreadState_Current;
+ if (!state)
+ state = script_interpreter->m_command_thread_state;
+ if (state)
+ {
+ long tid = state->thread_id;
+ _PyThreadState_Current = state;
+ int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt);
+ if (log)
+ log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p",
+ tid,num_threads,state);
+ }
+ else if (log)
+ log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL");
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ reader.SetIsDone(true);
+ break;
+
+ case eInputReaderGotToken:
+ if (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor() != -1)
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %lu", bytes,
+ bytes_len);
+ if (bytes && bytes_len)
+ ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), bytes, bytes_len);
+ ::write (script_interpreter->m_embedded_thread_pty.GetMasterFileDescriptor(), "\n", 1);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %lu, Master File Descriptor is bad.",
+ bytes,
+ bytes_len);
+ reader.SetIsDone (true);
+ }
+ break;
+
+ case eInputReaderDone:
+ {
+ StreamString run_string;
+ char error_str[1024];
+ const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
+ if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
+ {
+ ScriptInterpreterPython::Locker locker(script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin; sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear();
+ }
+ // Restore terminal settings if they were validly saved
+ if (log)
+ log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader.");
+
+ script_interpreter->RestoreTerminalState ();
+
+ script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor();
+ }
+ break;
+ }
+
+ return bytes_len;
+}
+
+ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
+ ScriptInterpreter (interpreter, eScriptLanguagePython),
+ m_embedded_thread_pty (),
+ m_embedded_python_pty (),
+ m_embedded_thread_input_reader_sp (),
+ m_embedded_python_input_reader_sp (),
+ m_dbg_stdout (interpreter.GetDebugger().GetOutputFile().GetStream()),
+ m_new_sysout (NULL),
+ m_old_sysout (NULL),
+ m_old_syserr (NULL),
+ m_run_one_line (NULL),
+ m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()),
+ m_terminal_state (),
+ m_session_is_active (false),
+ m_valid_session (true),
+ m_command_thread_state (NULL)
+{
+
+ static int g_initialized = false;
+
+ if (!g_initialized)
+ {
+ g_initialized = true;
+ ScriptInterpreterPython::InitializePrivate ();
+ }
+
+ m_dictionary_name.append("_dict");
+ StreamString run_string;
+ run_string.Printf ("%s = dict()", m_dictionary_name.c_str());
+
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ PyRun_SimpleString (run_string.GetData());
+
+ run_string.Clear();
+
+ // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a
+ // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the
+ // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final
+ // call to Debugger::Terminate is made, the ref-count has the correct value.
+ //
+ // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in
+ // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed.
+
+ int old_count = Debugger::TestDebuggerRefCount();
+
+ run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb')", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ // WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set
+ // and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc')", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ int new_count = Debugger::TestDebuggerRefCount();
+
+ if (new_count > old_count)
+ Debugger::Terminate();
+
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64 "; pydoc.pager = pydoc.plainpager')", m_dictionary_name.c_str(),
+ interpreter.GetDebugger().GetID());
+ PyRun_SimpleString (run_string.GetData());
+
+ if (m_dbg_stdout != NULL)
+ {
+ m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
+ }
+
+ // get the output file handle from the debugger (if any)
+ File& out_file = interpreter.GetDebugger().GetOutputFile();
+ if (out_file.IsValid())
+ ResetOutputFileHandle(out_file.GetStream());
+}
+
+ScriptInterpreterPython::~ScriptInterpreterPython ()
+{
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+
+ if (m_embedded_thread_input_reader_sp.get() != NULL)
+ {
+ m_embedded_thread_input_reader_sp->SetIsDone (true);
+ m_embedded_thread_pty.CloseSlaveFileDescriptor();
+ const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp;
+ debugger.PopInputReader (reader_sp);
+ m_embedded_thread_input_reader_sp.reset();
+ }
+
+ if (m_embedded_python_input_reader_sp.get() != NULL)
+ {
+ m_embedded_python_input_reader_sp->SetIsDone (true);
+ m_embedded_python_pty.CloseSlaveFileDescriptor();
+ const InputReaderSP reader_sp = m_embedded_python_input_reader_sp;
+ debugger.PopInputReader (reader_sp);
+ m_embedded_python_input_reader_sp.reset();
+ }
+
+ if (m_new_sysout)
+ {
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeLock);
+ Py_XDECREF ((PyObject*)m_new_sysout);
+ }
+}
+
+void
+ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh)
+{
+ if (fh == NULL)
+ return;
+
+ m_dbg_stdout = fh;
+
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+
+ m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
+}
+
+void
+ScriptInterpreterPython::SaveTerminalState (int fd)
+{
+ // Python mucks with the terminal state of STDIN. If we can possibly avoid
+ // this by setting the file handles up correctly prior to entering the
+ // interpreter we should. For now we save and restore the terminal state
+ // on the input file handle.
+ m_terminal_state.Save (fd, false);
+}
+
+void
+ScriptInterpreterPython::RestoreTerminalState ()
+{
+ // Python mucks with the terminal state of STDIN. If we can possibly avoid
+ // this by setting the file handles up correctly prior to entering the
+ // interpreter we should. For now we save and restore the terminal state
+ // on the input file handle.
+ m_terminal_state.Restore();
+}
+
+void
+ScriptInterpreterPython::LeaveSession ()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+ if (log)
+ log->PutCString("ScriptInterpreterPython::LeaveSession()");
+
+ // checking that we have a valid thread state - since we use our own threading and locking
+ // in some (rare) cases during cleanup Python may end up believing we have no thread state
+ // and PyImport_AddModule will crash if that is the case - since that seems to only happen
+ // when destroying the SBDebugger, we can make do without clearing up stdout and stderr
+
+ // rdar://problem/11292882
+ // When the current thread state is NULL, PyThreadState_Get() issues a fatal error.
+ if (PyThreadState_GetDict())
+ {
+ PyObject *sysmod = PyImport_AddModule ("sys");
+ PyObject *sysdict = PyModule_GetDict (sysmod);
+
+ if (m_new_sysout && sysmod && sysdict)
+ {
+ if (m_old_sysout)
+ PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_old_sysout);
+ if (m_old_syserr)
+ PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_old_syserr);
+ }
+ }
+
+ m_session_is_active = false;
+}
+
+bool
+ScriptInterpreterPython::EnterSession (bool init_lldb_globals)
+{
+ // If we have already entered the session, without having officially 'left' it, then there is no need to
+ // 'enter' it again.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+ if (m_session_is_active)
+ {
+ if (log)
+ log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i) session is already active, returning without doing anything", init_lldb_globals);
+ return false;
+ }
+
+ if (log)
+ log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i)", init_lldb_globals);
+
+
+ m_session_is_active = true;
+
+ StreamString run_string;
+
+ if (init_lldb_globals)
+ {
+ run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID());
+ run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID());
+ run_string.PutCString ("; lldb.target = lldb.debugger.GetSelectedTarget()");
+ run_string.PutCString ("; lldb.process = lldb.target.GetProcess()");
+ run_string.PutCString ("; lldb.thread = lldb.process.GetSelectedThread ()");
+ run_string.PutCString ("; lldb.frame = lldb.thread.GetSelectedFrame ()");
+ run_string.PutCString ("')");
+ }
+ else
+ {
+ // If we aren't initing the globals, we should still always set the debugger (since that is always unique.)
+ run_string.Printf ( "run_one_line (%s, \"lldb.debugger_unique_id = %" PRIu64, m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID());
+ run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%" PRIu64 ")", GetCommandInterpreter().GetDebugger().GetID());
+ run_string.PutCString ("\")");
+ }
+
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear();
+
+ PyObject *sysmod = PyImport_AddModule ("sys");
+ PyObject *sysdict = PyModule_GetDict (sysmod);
+
+ if (m_new_sysout && sysmod && sysdict)
+ {
+ m_old_sysout = PyDict_GetItemString(sysdict, "stdout");
+ m_old_syserr = PyDict_GetItemString(sysdict, "stderr");
+ if (m_new_sysout)
+ {
+ PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_new_sysout);
+ PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_new_sysout);
+ }
+ }
+
+ if (PyErr_Occurred())
+ PyErr_Clear ();
+
+ return true;
+}
+
+static PyObject*
+FindSessionDictionary (const char* dict_name)
+{
+ static std::map<ConstString,PyObject*> g_dict_map;
+
+ ConstString dict(dict_name);
+
+ std::map<ConstString,PyObject*>::iterator iter = g_dict_map.find(dict);
+
+ if (iter != g_dict_map.end())
+ return iter->second;
+
+ PyObject *main_mod = PyImport_AddModule ("__main__");
+ if (main_mod != NULL)
+ {
+ PyObject *main_dict = PyModule_GetDict (main_mod);
+ if ((main_dict != NULL)
+ && PyDict_Check (main_dict))
+ {
+ // Go through the main dictionary looking for the correct python script interpreter dictionary
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next (main_dict, &pos, &key, &value))
+ {
+ // We have stolen references to the key and value objects in the dictionary; we need to increment
+ // them now so that Python's garbage collector doesn't collect them out from under us.
+ Py_INCREF (key);
+ Py_INCREF (value);
+ if (strcmp (PyString_AsString (key), dict_name) == 0)
+ {
+ g_dict_map[dict] = value;
+ return value;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+static std::string
+GenerateUniqueName (const char* base_name_wanted,
+ uint32_t& functions_counter,
+ void* name_token = NULL)
+{
+ StreamString sstr;
+
+ if (!base_name_wanted)
+ return std::string();
+
+ if (!name_token)
+ sstr.Printf ("%s_%d", base_name_wanted, functions_counter++);
+ else
+ sstr.Printf ("%s_%p", base_name_wanted, name_token);
+
+ return sstr.GetString();
+}
+
+bool
+ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, const ExecuteScriptOptions &options)
+{
+ if (!m_valid_session)
+ return false;
+
+ // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through
+ // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside
+ // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated
+ // method to pass the command string directly down to Python.
+
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
+
+ bool success = false;
+
+ if (command)
+ {
+ // Find the correct script interpreter dictionary in the main module.
+ PyObject *script_interpreter_dict = FindSessionDictionary(m_dictionary_name.c_str());
+ if (script_interpreter_dict != NULL)
+ {
+ PyObject *pfunc = (PyObject*)m_run_one_line;
+ PyObject *pmod = PyImport_AddModule ("lldb.embedded_interpreter");
+ if (pmod != NULL)
+ {
+ PyObject *pmod_dict = PyModule_GetDict (pmod);
+ if ((pmod_dict != NULL)
+ && PyDict_Check (pmod_dict))
+ {
+ if (!pfunc)
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next (pmod_dict, &pos, &key, &value))
+ {
+ Py_INCREF (key);
+ Py_INCREF (value);
+ if (strcmp (PyString_AsString (key), "run_one_line") == 0)
+ {
+ pfunc = value;
+ break;
+ }
+ }
+ m_run_one_line = pfunc;
+ }
+
+ if (pfunc && PyCallable_Check (pfunc))
+ {
+ PyObject *pargs = Py_BuildValue("(Os)",script_interpreter_dict,command);
+ if (pargs != NULL)
+ {
+ PyObject *pvalue = NULL;
+ { // scope for PythonInputReaderManager
+ PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
+ pvalue = PyObject_CallObject (pfunc, pargs);
+ }
+ Py_XDECREF (pargs);
+ if (pvalue != NULL)
+ {
+ Py_XDECREF (pvalue);
+ success = true;
+ }
+ else if (options.GetMaskoutErrors() && PyErr_Occurred ())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+ }
+ }
+ }
+ }
+ Py_INCREF (script_interpreter_dict);
+ }
+
+ if (success)
+ return true;
+
+ // The one-liner failed. Append the error message.
+ if (result)
+ result->AppendErrorWithFormat ("python failed attempting to evaluate '%s'\n", command);
+ return false;
+ }
+
+ if (result)
+ result->AppendError ("empty command passed to python\n");
+ return false;
+}
+
+size_t
+ScriptInterpreterPython::InputReaderCallback
+(
+ void *baton,
+ InputReader &reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ lldb::thread_t embedded_interpreter_thread;
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+
+ if (baton == NULL)
+ return 0;
+
+ ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+
+ if (script_interpreter->m_script_lang != eScriptLanguagePython)
+ return 0;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n");
+ out_stream->Flush();
+ }
+
+ // Save terminal settings if we can
+ int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor();
+ if (input_fd == File::kInvalidDescriptor)
+ input_fd = STDIN_FILENO;
+
+ script_interpreter->SaveTerminalState(input_fd);
+
+ {
+ ScriptInterpreterPython::Locker locker(script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ }
+
+ char error_str[1024];
+ if (script_interpreter->m_embedded_python_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str,
+ sizeof(error_str)))
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in opening master pty (fd = %d).",
+ script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor());
+ embedded_interpreter_thread = Host::ThreadCreate ("<lldb.script-interpreter.embedded-python-loop>",
+ ScriptInterpreterPython::RunEmbeddedPythonInterpreter,
+ script_interpreter, NULL);
+ if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread))
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", (void *)embedded_interpreter_thread);
+ Error detach_error;
+ Host::ThreadDetach (embedded_interpreter_thread, &detach_error);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed in creating thread");
+ reader.SetIsDone (true);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty ");
+ reader.SetIsDone (true);
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ // When another input reader is pushed, don't leave the session...
+ //script_interpreter->LeaveSession ();
+ break;
+
+ case eInputReaderReactivate:
+ {
+ ScriptInterpreterPython::Locker locker (script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderInterrupt:
+ ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24);
+ break;
+
+ case eInputReaderEndOfFile:
+ ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()\n", 7);
+ break;
+
+ case eInputReaderGotToken:
+ if (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor() != -1)
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu", bytes,
+ bytes_len);
+ if (bytes && bytes_len)
+ {
+ if ((int) bytes[0] == 4)
+ ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "quit()", 6);
+ else
+ ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), bytes, bytes_len);
+ }
+ ::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "\n", 1);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu, Master File Descriptor is bad.",
+ bytes,
+ bytes_len);
+ reader.SetIsDone (true);
+ }
+
+ break;
+
+ case eInputReaderDone:
+ {
+ Locker locker(script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock);
+ script_interpreter->LeaveSession ();
+ }
+
+ // Restore terminal settings if they were validly saved
+ if (log)
+ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader.");
+
+ script_interpreter->RestoreTerminalState ();
+
+ script_interpreter->m_embedded_python_pty.CloseMasterFileDescriptor();
+ break;
+ }
+
+ return bytes_len;
+}
+
+
+void
+ScriptInterpreterPython::ExecuteInterpreterLoop ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+
+ // At the moment, the only time the debugger does not have an input file handle is when this is called
+ // directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to
+ // try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't
+ // do it.
+
+ if (!debugger.GetInputFile().IsValid())
+ return;
+
+ InputReaderSP reader_sp (new InputReader(debugger));
+ if (reader_sp)
+ {
+ Error error (reader_sp->Initialize (ScriptInterpreterPython::InputReaderCallback,
+ this, // baton
+ eInputReaderGranularityLine, // token size, to pass to callback function
+ NULL, // end token
+ NULL, // prompt
+ true)); // echo input
+
+ if (error.Success())
+ {
+ debugger.PushInputReader (reader_sp);
+ m_embedded_python_input_reader_sp = reader_sp;
+ }
+ }
+}
+
+bool
+ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
+ ScriptInterpreter::ScriptReturnType return_type,
+ void *ret_value,
+ const ExecuteScriptOptions &options)
+{
+
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
+
+ PyObject *py_return = NULL;
+ PyObject *mainmod = PyImport_AddModule ("__main__");
+ PyObject *globals = PyModule_GetDict (mainmod);
+ PyObject *locals = NULL;
+ PyObject *py_error = NULL;
+ bool ret_success = false;
+ bool should_decrement_locals = false;
+ int success;
+
+ locals = FindSessionDictionary(m_dictionary_name.c_str());
+
+ if (locals == NULL)
+ {
+ locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str());
+ should_decrement_locals = true;
+ }
+
+ if (locals == NULL)
+ {
+ locals = globals;
+ should_decrement_locals = false;
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ PyErr_Clear();
+
+ if (in_string != NULL)
+ {
+ { // scope for PythonInputReaderManager
+ PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
+ py_return = PyRun_String (in_string, Py_eval_input, globals, locals);
+ if (py_return == NULL)
+ {
+ py_error = PyErr_Occurred ();
+ if (py_error != NULL)
+ PyErr_Clear ();
+
+ py_return = PyRun_String (in_string, Py_single_input, globals, locals);
+ }
+ }
+
+ if (locals != NULL
+ && should_decrement_locals)
+ Py_XDECREF (locals);
+
+ if (py_return != NULL)
+ {
+ switch (return_type)
+ {
+ case eScriptReturnTypeCharPtr: // "char *"
+ {
+ const char format[3] = "s#";
+ success = PyArg_Parse (py_return, format, (char **) ret_value);
+ break;
+ }
+ case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None
+ {
+ const char format[3] = "z";
+ success = PyArg_Parse (py_return, format, (char **) ret_value);
+ break;
+ }
+ case eScriptReturnTypeBool:
+ {
+ const char format[2] = "b";
+ success = PyArg_Parse (py_return, format, (bool *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeShortInt:
+ {
+ const char format[2] = "h";
+ success = PyArg_Parse (py_return, format, (short *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeShortIntUnsigned:
+ {
+ const char format[2] = "H";
+ success = PyArg_Parse (py_return, format, (unsigned short *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeInt:
+ {
+ const char format[2] = "i";
+ success = PyArg_Parse (py_return, format, (int *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeIntUnsigned:
+ {
+ const char format[2] = "I";
+ success = PyArg_Parse (py_return, format, (unsigned int *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeLongInt:
+ {
+ const char format[2] = "l";
+ success = PyArg_Parse (py_return, format, (long *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeLongIntUnsigned:
+ {
+ const char format[2] = "k";
+ success = PyArg_Parse (py_return, format, (unsigned long *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeLongLong:
+ {
+ const char format[2] = "L";
+ success = PyArg_Parse (py_return, format, (long long *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeLongLongUnsigned:
+ {
+ const char format[2] = "K";
+ success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeFloat:
+ {
+ const char format[2] = "f";
+ success = PyArg_Parse (py_return, format, (float *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeDouble:
+ {
+ const char format[2] = "d";
+ success = PyArg_Parse (py_return, format, (double *) ret_value);
+ break;
+ }
+ case eScriptReturnTypeChar:
+ {
+ const char format[2] = "c";
+ success = PyArg_Parse (py_return, format, (char *) ret_value);
+ break;
+ }
+ }
+ Py_XDECREF (py_return);
+ if (success)
+ ret_success = true;
+ else
+ ret_success = false;
+ }
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ {
+ ret_success = false;
+ if (options.GetMaskoutErrors())
+ {
+ if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
+ PyErr_Print ();
+ PyErr_Clear();
+ }
+ }
+
+ return ret_success;
+}
+
+bool
+ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options)
+{
+
+
+ Locker locker(this,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
+ ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
+
+ bool success = false;
+ PyObject *py_return = NULL;
+ PyObject *mainmod = PyImport_AddModule ("__main__");
+ PyObject *globals = PyModule_GetDict (mainmod);
+ PyObject *locals = NULL;
+ PyObject *py_error = NULL;
+ bool should_decrement_locals = false;
+
+ locals = FindSessionDictionary(m_dictionary_name.c_str());
+
+ if (locals == NULL)
+ {
+ locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str());
+ should_decrement_locals = true;
+ }
+
+ if (locals == NULL)
+ {
+ locals = globals;
+ should_decrement_locals = false;
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ PyErr_Clear();
+
+ if (in_string != NULL)
+ {
+ struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input);
+ if (compiled_node)
+ {
+ PyCodeObject *compiled_code = PyNode_Compile (compiled_node, "temp.py");
+ if (compiled_code)
+ {
+ { // scope for PythonInputReaderManager
+ PythonInputReaderManager py_input(options.GetEnableIO() ? this : NULL);
+ py_return = PyEval_EvalCode (compiled_code, globals, locals);
+ }
+ if (py_return != NULL)
+ {
+ success = true;
+ Py_XDECREF (py_return);
+ }
+ if (locals && should_decrement_locals)
+ Py_XDECREF (locals);
+ }
+ }
+ }
+
+ py_error = PyErr_Occurred ();
+ if (py_error != NULL)
+ {
+ success = false;
+ if (options.GetMaskoutErrors())
+ {
+ if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
+ PyErr_Print ();
+ PyErr_Clear();
+ }
+ }
+
+ return success;
+}
+
+static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.";
+
+static const char *g_bkpt_command_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
+ "def function(frame,bp_loc,internal_dict):\n"
+ " \"\"\"frame: the SBFrame for the location at which you stopped\n"
+ " bp_loc: an SBBreakpointLocation for the breakpoint location information\n"
+ " internal_dict: an LLDB support object not to be used\"\"\"";
+
+size_t
+ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
+(
+ void *baton,
+ InputReader &reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ static StringList commands_in_progress;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ commands_in_progress.Clear();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_bkpt_command_reader_instructions);
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ std::string temp_string (bytes, bytes_len);
+ commands_in_progress.AppendString (temp_string.c_str());
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ case eInputReaderInterrupt:
+ // Control-c (SIGINT) & control-d both mean finish & exit.
+ reader.SetIsDone(true);
+
+ // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command.
+ if (notification == eInputReaderInterrupt)
+ commands_in_progress.Clear();
+
+ // Fall through here...
+
+ case eInputReaderDone:
+ {
+ bool batch_mode = notification == eInputReaderDone ?
+ reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() :
+ true;
+ BreakpointOptions *bp_options = (BreakpointOptions *)baton;
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+ data_ap->user_source.AppendList (commands_in_progress);
+ if (data_ap.get())
+ {
+ ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (interpreter)
+ {
+ if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source,
+ data_ap->script_source))
+ {
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+ }
+ else if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ else
+ {
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ }
+ }
+ break;
+
+ }
+
+ return bytes_len;
+}
+
+size_t
+ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback
+(
+ void *baton,
+ InputReader &reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ static StringList commands_in_progress;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+
+ commands_in_progress.Clear();
+ if (!batch_mode)
+ {
+ out_stream->Printf ("%s\n", g_reader_instructions);
+ if (reader.GetPrompt())
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ if (reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
+ std::string temp_string (bytes, bytes_len);
+ commands_in_progress.AppendString (temp_string.c_str());
+ if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
+ {
+ out_stream->Printf ("%s", reader.GetPrompt());
+ out_stream->Flush ();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ case eInputReaderInterrupt:
+ // Control-c (SIGINT) & control-d both mean finish & exit.
+ reader.SetIsDone(true);
+
+ // Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command.
+ if (notification == eInputReaderInterrupt)
+ commands_in_progress.Clear();
+
+ // Fall through here...
+
+ case eInputReaderDone:
+ {
+ bool batch_mode = notification == eInputReaderDone ?
+ reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode() :
+ true;
+ WatchpointOptions *wp_options = (WatchpointOptions *)baton;
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+ data_ap->user_source.AppendList (commands_in_progress);
+ if (data_ap.get())
+ {
+ ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (interpreter)
+ {
+ if (interpreter->GenerateWatchpointCommandCallbackData (data_ap->user_source,
+ data_ap->script_source))
+ {
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp);
+ }
+ else if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf ("Warning: No command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ else
+ {
+ if (!batch_mode)
+ {
+ StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
+ out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n");
+ out_stream->Flush();
+ }
+ }
+ }
+ }
+ break;
+
+ }
+
+ return bytes_len;
+}
+
+void
+ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
+ CommandReturnObject &result)
+{
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+
+ InputReaderSP reader_sp (new InputReader (debugger));
+
+ if (reader_sp)
+ {
+ Error err = reader_sp->Initialize (
+ ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback,
+ bp_options, // baton
+ eInputReaderGranularityLine, // token size, for feeding data to callback function
+ "DONE", // end token
+ " ", // prompt
+ true); // echo input
+
+ if (err.Success())
+ debugger.PushInputReader (reader_sp);
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+void
+ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options,
+ CommandReturnObject &result)
+{
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+
+ InputReaderSP reader_sp (new InputReader (debugger));
+
+ if (reader_sp)
+ {
+ Error err = reader_sp->Initialize (
+ ScriptInterpreterPython::GenerateWatchpointOptionsCommandCallback,
+ wp_options, // baton
+ eInputReaderGranularityLine, // token size, for feeding data to callback function
+ "DONE", // end token
+ "> ", // prompt
+ true); // echo input
+
+ if (err.Success())
+ debugger.PushInputReader (reader_sp);
+ else
+ {
+ result.AppendError (err.AsCString());
+ result.SetStatus (eReturnStatusFailed);
+ }
+ }
+ else
+ {
+ result.AppendError("out of memory");
+ result.SetStatus (eReturnStatusFailed);
+ }
+}
+
+// Set a Python one-liner as the callback for the breakpoint.
+void
+ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
+ const char *oneliner)
+{
+ std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
+
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in breakpoint command list)
+ // while the latter is used for Python to interpret during the actual callback.
+
+ data_ap->user_source.AppendString (oneliner);
+ data_ap->script_source.assign (oneliner);
+
+ if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
+ {
+ BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
+ bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
+ }
+
+ return;
+}
+
+// Set a Python one-liner as the callback for the watchpoint.
+void
+ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_options,
+ const char *oneliner)
+{
+ std::unique_ptr<WatchpointOptions::CommandData> data_ap(new WatchpointOptions::CommandData());
+
+ // It's necessary to set both user_source and script_source to the oneliner.
+ // The former is used to generate callback description (as in watchpoint command list)
+ // while the latter is used for Python to interpret during the actual callback.
+
+ data_ap->user_source.AppendString (oneliner);
+ data_ap->script_source.assign (oneliner);
+
+ if (GenerateWatchpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
+ {
+ BatonSP baton_sp (new WatchpointOptions::CommandBaton (data_ap.release()));
+ wp_options->SetCallback (ScriptInterpreterPython::WatchpointCallbackFunction, baton_sp);
+ }
+
+ return;
+}
+
+bool
+ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def)
+{
+ // Convert StringList to one long, newline delimited, const char *.
+ std::string function_def_string(function_def.CopyList());
+
+ return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false));
+}
+
+bool
+ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input)
+{
+ int num_lines = input.GetSize ();
+ if (num_lines == 0)
+ return false;
+
+ if (!signature || *signature == 0)
+ return false;
+
+ StreamString sstr;
+ StringList auto_generated_function;
+ auto_generated_function.AppendString (signature);
+ auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
+ auto_generated_function.AppendString (" new_keys = internal_dict.keys()"); // Make a list of keys in the session dict
+ auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
+ auto_generated_function.AppendString (" global_dict.update (internal_dict)"); // Add the session dictionary to the
+ // global dictionary.
+
+ // Wrap everything up inside the function, increasing the indentation.
+
+ auto_generated_function.AppendString(" if True:");
+ for (int i = 0; i < num_lines; ++i)
+ {
+ sstr.Clear ();
+ sstr.Printf (" %s", input.GetStringAtIndex (i));
+ auto_generated_function.AppendString (sstr.GetData());
+ }
+ auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
+ auto_generated_function.AppendString (" internal_dict[key] = global_dict[key]"); // Update session dict values
+ auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
+ auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
+
+ // Verify that the results are valid Python.
+
+ if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
+ return false;
+
+ return true;
+
+}
+
+bool
+ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std::string& output, void* name_token)
+{
+ static uint32_t num_created_functions = 0;
+ user_input.RemoveBlankLines ();
+ StreamString sstr;
+
+ // Check to see if we have any data; if not, just return.
+ if (user_input.GetSize() == 0)
+ return false;
+
+ // Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
+ // ValueObject as parameter to the function.
+
+ std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token));
+ sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str());
+
+ if (!GenerateFunction(sstr.GetData(), user_input))
+ return false;
+
+ // Store the name of the auto-generated function to be called.
+ output.assign(auto_generated_function_name);
+ return true;
+}
+
+bool
+ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, std::string &output)
+{
+ static uint32_t num_created_functions = 0;
+ user_input.RemoveBlankLines ();
+ StreamString sstr;
+
+ // Check to see if we have any data; if not, just return.
+ if (user_input.GetSize() == 0)
+ return false;
+
+ std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_cmd_alias_func", num_created_functions));
+
+ sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str());
+
+ if (!GenerateFunction(sstr.GetData(),user_input))
+ return false;
+
+ // Store the name of the auto-generated function to be called.
+ output.assign(auto_generated_function_name);
+ return true;
+}
+
+
+bool
+ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::string &output, void* name_token)
+{
+ static uint32_t num_created_classes = 0;
+ user_input.RemoveBlankLines ();
+ int num_lines = user_input.GetSize ();
+ StreamString sstr;
+
+ // Check to see if we have any data; if not, just return.
+ if (user_input.GetSize() == 0)
+ return false;
+
+ // Wrap all user input into a Python class
+
+ std::string auto_generated_class_name(GenerateUniqueName("lldb_autogen_python_type_synth_class",num_created_classes,name_token));
+
+ StringList auto_generated_class;
+
+ // Create the function name & definition string.
+
+ sstr.Printf ("class %s:", auto_generated_class_name.c_str());
+ auto_generated_class.AppendString (sstr.GetData());
+
+ // Wrap everything up inside the class, increasing the indentation.
+ // we don't need to play any fancy indentation tricks here because there is no
+ // surrounding code whose indentation we need to honor
+ for (int i = 0; i < num_lines; ++i)
+ {
+ sstr.Clear ();
+ sstr.Printf (" %s", user_input.GetStringAtIndex (i));
+ auto_generated_class.AppendString (sstr.GetData());
+ }
+
+
+ // Verify that the results are valid Python.
+ // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported)
+ // (TODO: rename that method to ExportDefinitionToInterpreter)
+ if (!ExportFunctionDefinitionToInterpreter (auto_generated_class))
+ return false;
+
+ // Store the name of the auto-generated class
+
+ output.assign(auto_generated_class_name);
+ return true;
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp)
+{
+ if (class_name == NULL || class_name[0] == '\0')
+ return lldb::ScriptInterpreterObjectSP();
+
+ if (!process_sp)
+ return lldb::ScriptInterpreterObjectSP();
+
+ void* ret_val;
+
+ {
+ Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
+ ret_val = g_swig_create_os_plugin (class_name,
+ m_dictionary_name.c_str(),
+ process_sp);
+ }
+
+ return MakeScriptObject(ret_val);
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+{
+ Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
+
+ static char callee_name[] = "get_register_info";
+
+ if (!os_plugin_object_sp)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
+
+ if (implementor == NULL || implementor == Py_None)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == NULL || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ return MakeScriptObject(py_return);
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
+{
+ Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
+
+ static char callee_name[] = "get_thread_info";
+
+ if (!os_plugin_object_sp)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
+
+ if (implementor == NULL || implementor == Py_None)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == NULL || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ return MakeScriptObject(py_return);
+}
+
+// GetPythonValueFormatString provides a system independent type safe way to
+// convert a variable's type into a python value format. Python value formats
+// are defined in terms of builtin C types and could change from system to
+// as the underlying typedef for uint* types, size_t, off_t and other values
+// change.
+
+template <typename T>
+const char *GetPythonValueFormatString(T t)
+{
+ assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this type.");
+ return NULL;
+}
+template <> const char *GetPythonValueFormatString (char *) { return "s"; }
+template <> const char *GetPythonValueFormatString (char) { return "b"; }
+template <> const char *GetPythonValueFormatString (unsigned char) { return "B"; }
+template <> const char *GetPythonValueFormatString (short) { return "h"; }
+template <> const char *GetPythonValueFormatString (unsigned short) { return "H"; }
+template <> const char *GetPythonValueFormatString (int) { return "i"; }
+template <> const char *GetPythonValueFormatString (unsigned int) { return "I"; }
+template <> const char *GetPythonValueFormatString (long) { return "l"; }
+template <> const char *GetPythonValueFormatString (unsigned long) { return "k"; }
+template <> const char *GetPythonValueFormatString (long long) { return "L"; }
+template <> const char *GetPythonValueFormatString (unsigned long long) { return "K"; }
+template <> const char *GetPythonValueFormatString (float t) { return "f"; }
+template <> const char *GetPythonValueFormatString (double t) { return "d"; }
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t tid)
+{
+ Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
+
+ static char callee_name[] = "get_register_data";
+ static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid));
+
+ if (!os_plugin_object_sp)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
+
+ if (implementor == NULL || implementor == Py_None)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == NULL || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ return MakeScriptObject(py_return);
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
+ lldb::tid_t tid,
+ lldb::addr_t context)
+{
+ Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
+
+ static char callee_name[] = "create_thread";
+ std::string param_format;
+ param_format += GetPythonValueFormatString(tid);
+ param_format += GetPythonValueFormatString(context);
+
+ if (!os_plugin_object_sp)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
+
+ if (implementor == NULL || implementor == Py_None)
+ return lldb::ScriptInterpreterObjectSP();
+
+ PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ if (pmeth == NULL || pmeth == Py_None)
+ {
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyCallable_Check(pmeth) == 0)
+ {
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+ return lldb::ScriptInterpreterObjectSP();
+ }
+
+ if (PyErr_Occurred())
+ {
+ PyErr_Clear();
+ }
+
+ Py_XDECREF(pmeth);
+
+ // right now we know this function exists and is callable..
+ PyObject* py_return = PyObject_CallMethod(implementor, callee_name, &param_format[0], tid, context);
+
+ // if it fails, print the error but otherwise go on
+ if (PyErr_Occurred())
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ return MakeScriptObject(py_return);
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name,
+ lldb::ValueObjectSP valobj)
+{
+ if (class_name == NULL || class_name[0] == '\0')
+ return lldb::ScriptInterpreterObjectSP();
+
+ if (!valobj.get())
+ return lldb::ScriptInterpreterObjectSP();
+
+ ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ return lldb::ScriptInterpreterObjectSP();
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+
+ if (!script_interpreter)
+ return lldb::ScriptInterpreterObjectSP();
+
+ void* ret_val;
+
+ {
+ Locker py_lock(this);
+ ret_val = g_swig_synthetic_script (class_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ valobj);
+ }
+
+ return MakeScriptObject(ret_val);
+}
+
+bool
+ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, std::string& output, void* name_token)
+{
+ StringList input;
+ input.SplitIntoLines(oneliner, strlen(oneliner));
+ return GenerateTypeScriptFunction(input, output, name_token);
+}
+
+bool
+ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::string& output, void* name_token)
+{
+ StringList input;
+ input.SplitIntoLines(oneliner, strlen(oneliner));
+ return GenerateTypeSynthClass(input, output, name_token);
+}
+
+
+bool
+ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output)
+{
+ static uint32_t num_created_functions = 0;
+ user_input.RemoveBlankLines ();
+ StreamString sstr;
+
+ if (user_input.GetSize() == 0)
+ return false;
+
+ std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions));
+ sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str());
+
+ if (!GenerateFunction(sstr.GetData(), user_input))
+ return false;
+
+ // Store the name of the auto-generated function to be called.
+ output.assign(auto_generated_function_name);
+ return true;
+}
+
+bool
+ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user_input, std::string& output)
+{
+ static uint32_t num_created_functions = 0;
+ user_input.RemoveBlankLines ();
+ StreamString sstr;
+
+ if (user_input.GetSize() == 0)
+ return false;
+
+ std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions));
+ sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str());
+
+ if (!GenerateFunction(sstr.GetData(), user_input))
+ return false;
+
+ // Store the name of the auto-generated function to be called.
+ output.assign(auto_generated_function_name);
+ return true;
+}
+
+bool
+ScriptInterpreterPython::GetScriptedSummary (const char *python_function_name,
+ lldb::ValueObjectSP valobj,
+ lldb::ScriptInterpreterObjectSP& callee_wrapper_sp,
+ std::string& retval)
+{
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ if (!valobj.get())
+ {
+ retval.assign("<no object>");
+ return false;
+ }
+
+ void* old_callee = (callee_wrapper_sp ? callee_wrapper_sp->GetObject() : NULL);
+ void* new_callee = old_callee;
+
+ bool ret_val;
+ if (python_function_name
+ && *python_function_name)
+ {
+ {
+ Locker py_lock(this);
+ {
+ Timer scoped_timer ("g_swig_typescript_callback","g_swig_typescript_callback");
+ ret_val = g_swig_typescript_callback (python_function_name,
+ FindSessionDictionary(m_dictionary_name.c_str()),
+ valobj,
+ &new_callee,
+ retval);
+ }
+ }
+ }
+ else
+ {
+ retval.assign("<no function name>");
+ return false;
+ }
+
+ if (new_callee && old_callee != new_callee)
+ callee_wrapper_sp = MakeScriptObject(new_callee);
+
+ return ret_val;
+
+}
+
+bool
+ScriptInterpreterPython::BreakpointCallbackFunction
+(
+ void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id
+)
+{
+ BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton;
+ const char *python_function_name = bp_option_data->script_source.c_str();
+
+ if (!context)
+ return true;
+
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ return true;
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+
+ if (!script_interpreter)
+ return true;
+
+ if (python_function_name != NULL
+ && python_function_name[0] != '\0')
+ {
+ const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP());
+ BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id);
+ if (breakpoint_sp)
+ {
+ const BreakpointLocationSP bp_loc_sp (breakpoint_sp->FindLocationByID (break_loc_id));
+
+ if (stop_frame_sp && bp_loc_sp)
+ {
+ bool ret_val = true;
+ {
+ Locker py_lock(python_interpreter);
+ ret_val = g_swig_breakpoint_callback (python_function_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ stop_frame_sp,
+ bp_loc_sp);
+ }
+ return ret_val;
+ }
+ }
+ }
+ // We currently always true so we stop in case anything goes wrong when
+ // trying to call the script function
+ return true;
+}
+
+bool
+ScriptInterpreterPython::WatchpointCallbackFunction
+(
+ void *baton,
+ StoppointCallbackContext *context,
+ user_id_t watch_id
+)
+{
+ WatchpointOptions::CommandData *wp_option_data = (WatchpointOptions::CommandData *) baton;
+ const char *python_function_name = wp_option_data->script_source.c_str();
+
+ if (!context)
+ return true;
+
+ ExecutionContext exe_ctx (context->exe_ctx_ref);
+ Target *target = exe_ctx.GetTargetPtr();
+
+ if (!target)
+ return true;
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+
+ if (!script_interpreter)
+ return true;
+
+ if (python_function_name != NULL
+ && python_function_name[0] != '\0')
+ {
+ const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP());
+ WatchpointSP wp_sp = target->GetWatchpointList().FindByID (watch_id);
+ if (wp_sp)
+ {
+ if (stop_frame_sp && wp_sp)
+ {
+ bool ret_val = true;
+ {
+ Locker py_lock(python_interpreter);
+ ret_val = g_swig_watchpoint_callback (python_function_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ stop_frame_sp,
+ wp_sp);
+ }
+ return ret_val;
+ }
+ }
+ }
+ // We currently always true so we stop in case anything goes wrong when
+ // trying to call the script function
+ return true;
+}
+
+lldb::thread_result_t
+ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
+{
+ ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
+
+ if (log)
+ log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread starting...", baton);
+
+ char error_str[1024];
+ const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str));
+
+ if (pty_slave_name != NULL)
+ {
+ StreamString run_string;
+
+ // Ensure we have the GIL before running any Python code.
+ // Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed),
+ // we can just release the GIL after finishing our work.
+ // If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function.
+ Locker locker(script_interpreter,
+ ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals,
+ ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
+
+ run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(),
+ pty_slave_name);
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ // The following call drops into the embedded interpreter loop and stays there until the
+ // user chooses to exit from the Python interpreter.
+ // This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before
+ // a system call that can hang, and lock it when the syscall has returned.
+
+ // We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and
+ // PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want
+ // to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off,
+ // and things could hang (it's happened before).
+
+ run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear();
+
+ run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear();
+ }
+
+ if (script_interpreter->m_embedded_python_input_reader_sp)
+ script_interpreter->m_embedded_python_input_reader_sp->SetIsDone (true);
+
+ script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor();
+
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT);
+ if (log)
+ log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton);
+
+
+ // Clean up the input reader and make the debugger pop it off the stack.
+ Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger();
+ const InputReaderSP reader_sp = script_interpreter->m_embedded_python_input_reader_sp;
+ if (reader_sp)
+ {
+ debugger.PopInputReader (reader_sp);
+ script_interpreter->m_embedded_python_input_reader_sp.reset();
+ }
+
+ return NULL;
+}
+
+lldb::thread_result_t
+ScriptInterpreterPython::PythonInputReaderManager::RunPythonInputReader (lldb::thread_arg_t baton)
+{
+ ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+
+ const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp;
+
+ if (reader_sp)
+ reader_sp->WaitOnReaderIsDone();
+
+ return NULL;
+}
+
+size_t
+ScriptInterpreterPython::CalculateNumChildren (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+{
+ if (!implementor_sp)
+ return 0;
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return 0;
+
+ if (!g_swig_calc_children)
+ return 0;
+
+ uint32_t ret_val = 0;
+
+ {
+ Locker py_lock(this);
+ ret_val = g_swig_calc_children (implementor);
+ }
+
+ return ret_val;
+}
+
+lldb::ValueObjectSP
+ScriptInterpreterPython::GetChildAtIndex (const lldb::ScriptInterpreterObjectSP& implementor_sp, uint32_t idx)
+{
+ if (!implementor_sp)
+ return lldb::ValueObjectSP();
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return lldb::ValueObjectSP();
+
+ if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue)
+ return lldb::ValueObjectSP();
+
+ void* child_ptr = NULL;
+ lldb::SBValue* value_sb = NULL;
+ lldb::ValueObjectSP ret_val;
+
+ {
+ Locker py_lock(this);
+ child_ptr = g_swig_get_child_index (implementor,idx);
+ if (child_ptr != NULL && child_ptr != Py_None)
+ {
+ value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
+ if (value_sb == NULL)
+ Py_XDECREF(child_ptr);
+ else
+ ret_val = value_sb->GetSP();
+ }
+ else
+ {
+ Py_XDECREF(child_ptr);
+ }
+ }
+
+ return ret_val;
+}
+
+int
+ScriptInterpreterPython::GetIndexOfChildWithName (const lldb::ScriptInterpreterObjectSP& implementor_sp, const char* child_name)
+{
+ if (!implementor_sp)
+ return UINT32_MAX;
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return UINT32_MAX;
+
+ if (!g_swig_get_index_child)
+ return UINT32_MAX;
+
+ int ret_val = UINT32_MAX;
+
+ {
+ Locker py_lock(this);
+ ret_val = g_swig_get_index_child (implementor, child_name);
+ }
+
+ return ret_val;
+}
+
+bool
+ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+{
+ bool ret_val = false;
+
+ if (!implementor_sp)
+ return ret_val;
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return ret_val;
+
+ if (!g_swig_update_provider)
+ return ret_val;
+
+ {
+ Locker py_lock(this);
+ ret_val = g_swig_update_provider (implementor);
+ }
+
+ return ret_val;
+}
+
+bool
+ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor_sp)
+{
+ bool ret_val = false;
+
+ if (!implementor_sp)
+ return ret_val;
+
+ void* implementor = implementor_sp->GetObject();
+
+ if (!implementor)
+ return ret_val;
+
+ if (!g_swig_mighthavechildren_provider)
+ return ret_val;
+
+ {
+ Locker py_lock(this);
+ ret_val = g_swig_mighthavechildren_provider (implementor);
+ }
+
+ return ret_val;
+}
+
+static std::string
+ReadPythonBacktrace (PyObject* py_backtrace)
+{
+ PyObject* traceback_module = NULL,
+ *stringIO_module = NULL,
+ *stringIO_builder = NULL,
+ *stringIO_buffer = NULL,
+ *printTB = NULL,
+ *printTB_args = NULL,
+ *printTB_result = NULL,
+ *stringIO_getvalue = NULL,
+ *printTB_string = NULL;
+
+ std::string retval("backtrace unavailable");
+
+ if (py_backtrace && py_backtrace != Py_None)
+ {
+ traceback_module = PyImport_ImportModule("traceback");
+ stringIO_module = PyImport_ImportModule("StringIO");
+
+ if (traceback_module && traceback_module != Py_None && stringIO_module && stringIO_module != Py_None)
+ {
+ stringIO_builder = PyObject_GetAttrString(stringIO_module, "StringIO");
+ if (stringIO_builder && stringIO_builder != Py_None)
+ {
+ stringIO_buffer = PyObject_CallObject(stringIO_builder, NULL);
+ if (stringIO_buffer && stringIO_buffer != Py_None)
+ {
+ printTB = PyObject_GetAttrString(traceback_module, "print_tb");
+ if (printTB && printTB != Py_None)
+ {
+ printTB_args = Py_BuildValue("OOO",py_backtrace,Py_None,stringIO_buffer);
+ printTB_result = PyObject_CallObject(printTB, printTB_args);
+ stringIO_getvalue = PyObject_GetAttrString(stringIO_buffer, "getvalue");
+ if (stringIO_getvalue && stringIO_getvalue != Py_None)
+ {
+ printTB_string = PyObject_CallObject (stringIO_getvalue,NULL);
+ if (printTB_string && printTB_string != Py_None && PyString_Check(printTB_string))
+ retval.assign(PyString_AsString(printTB_string));
+ }
+ }
+ }
+ }
+ }
+ }
+ Py_XDECREF(traceback_module);
+ Py_XDECREF(stringIO_module);
+ Py_XDECREF(stringIO_builder);
+ Py_XDECREF(stringIO_buffer);
+ Py_XDECREF(printTB);
+ Py_XDECREF(printTB_args);
+ Py_XDECREF(printTB_result);
+ Py_XDECREF(stringIO_getvalue);
+ Py_XDECREF(printTB_string);
+ return retval;
+}
+
+bool
+ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
+ Process* process,
+ std::string& output,
+ Error& error)
+{
+ bool ret_val;
+ if (!process)
+ {
+ error.SetErrorString("no process");
+ return false;
+ }
+ if (!impl_function || !impl_function[0])
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+ if (!g_swig_run_script_keyword_process)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+ {
+ ProcessSP process_sp(process->shared_from_this());
+ Locker py_lock(this);
+ ret_val = g_swig_run_script_keyword_process (impl_function, m_dictionary_name.c_str(), process_sp, output);
+ if (!ret_val)
+ error.SetErrorString("python script evaluation failed");
+ }
+ return ret_val;
+}
+
+bool
+ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
+ Thread* thread,
+ std::string& output,
+ Error& error)
+{
+ bool ret_val;
+ if (!thread)
+ {
+ error.SetErrorString("no thread");
+ return false;
+ }
+ if (!impl_function || !impl_function[0])
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+ if (!g_swig_run_script_keyword_thread)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+ {
+ ThreadSP thread_sp(thread->shared_from_this());
+ Locker py_lock(this);
+ ret_val = g_swig_run_script_keyword_thread (impl_function, m_dictionary_name.c_str(), thread_sp, output);
+ if (!ret_val)
+ error.SetErrorString("python script evaluation failed");
+ }
+ return ret_val;
+}
+
+bool
+ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
+ Target* target,
+ std::string& output,
+ Error& error)
+{
+ bool ret_val;
+ if (!target)
+ {
+ error.SetErrorString("no thread");
+ return false;
+ }
+ if (!impl_function || !impl_function[0])
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+ if (!g_swig_run_script_keyword_target)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+ {
+ TargetSP target_sp(target->shared_from_this());
+ Locker py_lock(this);
+ ret_val = g_swig_run_script_keyword_target (impl_function, m_dictionary_name.c_str(), target_sp, output);
+ if (!ret_val)
+ error.SetErrorString("python script evaluation failed");
+ }
+ return ret_val;
+}
+
+bool
+ScriptInterpreterPython::RunScriptFormatKeyword (const char* impl_function,
+ StackFrame* frame,
+ std::string& output,
+ Error& error)
+{
+ bool ret_val;
+ if (!frame)
+ {
+ error.SetErrorString("no frame");
+ return false;
+ }
+ if (!impl_function || !impl_function[0])
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+ if (!g_swig_run_script_keyword_frame)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+ {
+ StackFrameSP frame_sp(frame->shared_from_this());
+ Locker py_lock(this);
+ ret_val = g_swig_run_script_keyword_frame (impl_function, m_dictionary_name.c_str(), frame_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)
+{
+ size_t pos = 0;
+ uint64_t matches = 0;
+ while((pos = str.find(oldStr, pos)) != std::string::npos)
+ {
+ matches++;
+ str.replace(pos, oldStr.length(), newStr);
+ pos += newStr.length();
+ }
+ return matches;
+}
+
+bool
+ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
+ bool can_reload,
+ bool init_session,
+ lldb_private::Error& error)
+{
+ if (!pathname || !pathname[0])
+ {
+ error.SetErrorString("invalid pathname");
+ return false;
+ }
+
+ if (!g_swig_call_module_init)
+ {
+ error.SetErrorString("internal helper function missing");
+ return false;
+ }
+
+ lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
+
+ {
+ FileSpec target_file(pathname, true);
+ std::string basename(target_file.GetFilename().GetCString());
+
+ StreamString command_stream;
+
+ // Before executing Pyton code, lock the GIL.
+ Locker py_lock (this,
+ Locker::AcquireLock | (init_session ? Locker::InitSession : 0),
+ Locker::FreeAcquiredLock | (init_session ? Locker::TearDownSession : 0));
+
+ if (target_file.GetFileType() == FileSpec::eFileTypeInvalid ||
+ target_file.GetFileType() == FileSpec::eFileTypeUnknown)
+ {
+ // if not a valid file of any sort, check if it might be a filename still
+ // dot can't be used but / and \ can, and if either is found, reject
+ if (strchr(pathname,'\\') || strchr(pathname,'/'))
+ {
+ error.SetErrorString("invalid pathname");
+ return false;
+ }
+ basename = pathname; // not a filename, probably a package of some sort, let it go through
+ }
+ else if (target_file.GetFileType() == FileSpec::eFileTypeDirectory ||
+ target_file.GetFileType() == FileSpec::eFileTypeRegular ||
+ target_file.GetFileType() == FileSpec::eFileTypeSymbolicLink)
+ {
+ std::string directory(target_file.GetDirectory().GetCString());
+ replace_all(directory,"'","\\'");
+
+ // now make sure that Python has "directory" in the search path
+ StreamString command_stream;
+ command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.insert(1,'%s');\n\n",
+ directory.c_str(),
+ directory.c_str());
+ bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false));
+ if (!syspath_retval)
+ {
+ error.SetErrorString("Python sys.path handling failed");
+ return false;
+ }
+
+ // strip .py or .pyc extension
+ ConstString extension = target_file.GetFileNameExtension();
+ if (extension)
+ {
+ if (::strcmp(extension.GetCString(), "py") == 0)
+ basename.resize(basename.length()-3);
+ else if(::strcmp(extension.GetCString(), "pyc") == 0)
+ basename.resize(basename.length()-4);
+ }
+ }
+ else
+ {
+ error.SetErrorString("no known way to import this module specification");
+ return false;
+ }
+
+ // check if the module is already import-ed
+ command_stream.Clear();
+ command_stream.Printf("sys.modules.__contains__('%s')",basename.c_str());
+ bool does_contain = false;
+ int refcount = 0;
+ // this call will succeed if the module was ever imported in any Debugger in the lifetime of the process
+ // in which this LLDB framework is living
+ bool was_imported_globally = (ExecuteOneLineWithReturn(command_stream.GetData(),
+ ScriptInterpreterPython::eScriptReturnTypeBool,
+ &does_contain,
+ ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && does_contain);
+ // this call will fail if the module was not imported in this Debugger before
+ command_stream.Clear();
+ command_stream.Printf("sys.getrefcount(%s)",basename.c_str());
+ bool was_imported_locally = (ExecuteOneLineWithReturn(command_stream.GetData(),
+ ScriptInterpreterPython::eScriptReturnTypeInt,
+ &refcount,
+ ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false)) && refcount > 0);
+
+ bool was_imported = (was_imported_globally || was_imported_locally);
+
+ if (was_imported == true && can_reload == false)
+ {
+ error.SetErrorString("module already imported");
+ return false;
+ }
+
+ // now actually do the import
+ command_stream.Clear();
+
+ if (was_imported)
+ {
+ if (!was_imported_locally)
+ command_stream.Printf("import %s ; reload(%s)",basename.c_str(),basename.c_str());
+ else
+ command_stream.Printf("reload(%s)",basename.c_str());
+ }
+ else
+ command_stream.Printf("import %s",basename.c_str());
+
+ bool import_retval = ExecuteMultipleLines(command_stream.GetData(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false).SetSetLLDBGlobals(false).SetMaskoutErrors(false));
+ PyObject* py_error = PyErr_Occurred(); // per Python docs: "you do not need to Py_DECREF()" the return of this function
+
+ if (py_error || !import_retval) // check for failure of the import
+ {
+ if (py_error) // if we have a Python error..
+ {
+ PyObject *type = NULL,*value = NULL,*traceback = NULL;
+ PyErr_Fetch (&type,&value,&traceback);
+
+ if (PyErr_GivenExceptionMatches (py_error, PyExc_ImportError)) // and it is an ImportError
+ {
+ if (value && value != Py_None)
+ error.SetErrorString(PyString_AsString(PyObject_Str(value)));
+ else
+ error.SetErrorString("ImportError raised by imported module");
+ }
+ else // any other error
+ {
+ // get the backtrace
+ std::string bt = ReadPythonBacktrace(traceback);
+
+ if (value && value != Py_None)
+ error.SetErrorStringWithFormat("Python error raised while importing module: %s - traceback: %s", PyString_AsString(PyObject_Str(value)),bt.c_str());
+ else
+ error.SetErrorStringWithFormat("Python raised an error while importing module - traceback: %s",bt.c_str());
+ }
+
+ Py_XDECREF(type);
+ Py_XDECREF(value);
+ Py_XDECREF(traceback);
+ }
+ else // we failed but have no error to explain why
+ {
+ error.SetErrorString("unknown error while importing module");
+ }
+
+ // anyway, clear the error indicator and return false
+ PyErr_Clear();
+ return false;
+ }
+
+ // if we are here, everything worked
+ // call __lldb_init_module(debugger,dict)
+ if (!g_swig_call_module_init (basename.c_str(),
+ m_dictionary_name.c_str(),
+ debugger_sp))
+ {
+ error.SetErrorString("calling __lldb_init_module failed");
+ return false;
+ }
+ return true;
+ }
+}
+
+lldb::ScriptInterpreterObjectSP
+ScriptInterpreterPython::MakeScriptObject (void* object)
+{
+ return lldb::ScriptInterpreterObjectSP(new ScriptInterpreterPythonObject(object));
+}
+
+ScriptInterpreterPython::SynchronicityHandler::SynchronicityHandler (lldb::DebuggerSP debugger_sp,
+ ScriptedCommandSynchronicity synchro) :
+ m_debugger_sp(debugger_sp),
+ m_synch_wanted(synchro),
+ m_old_asynch(debugger_sp->GetAsyncExecution())
+{
+ if (m_synch_wanted == eScriptedCommandSynchronicitySynchronous)
+ m_debugger_sp->SetAsyncExecution(false);
+ else if (m_synch_wanted == eScriptedCommandSynchronicityAsynchronous)
+ m_debugger_sp->SetAsyncExecution(true);
+}
+
+ScriptInterpreterPython::SynchronicityHandler::~SynchronicityHandler()
+{
+ if (m_synch_wanted != eScriptedCommandSynchronicityCurrentValue)
+ m_debugger_sp->SetAsyncExecution(m_old_asynch);
+}
+
+bool
+ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
+ const char* args,
+ ScriptedCommandSynchronicity synchronicity,
+ lldb_private::CommandReturnObject& cmd_retobj,
+ Error& error)
+{
+ if (!impl_function)
+ {
+ error.SetErrorString("no function to execute");
+ return false;
+ }
+
+ if (!g_swig_call_command)
+ {
+ error.SetErrorString("no helper function to run scripted commands");
+ return false;
+ }
+
+ lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
+
+ if (!debugger_sp.get())
+ {
+ error.SetErrorString("invalid Debugger pointer");
+ return false;
+ }
+
+ bool ret_val = false;
+
+ std::string err_msg;
+
+ {
+ Locker py_lock(this,
+ Locker::AcquireLock | Locker::InitSession,
+ Locker::FreeLock | Locker::TearDownSession);
+
+ SynchronicityHandler synch_handler(debugger_sp,
+ synchronicity);
+
+ // we need to save the thread state when we first start the command
+ // because we might decide to interrupt it while some action is taking
+ // place outside of Python (e.g. printing to screen, waiting for the network, ...)
+ // in that case, _PyThreadState_Current will be NULL - and we would be unable
+ // to set the asynchronous exception - not a desirable situation
+ m_command_thread_state = _PyThreadState_Current;
+
+ PythonInputReaderManager py_input(this);
+
+ ret_val = g_swig_call_command (impl_function,
+ m_dictionary_name.c_str(),
+ debugger_sp,
+ args,
+ cmd_retobj);
+ }
+
+ if (!ret_val)
+ error.SetErrorString("unable to execute script function");
+ else
+ error.Clear();
+
+ return ret_val;
+}
+
+// in Python, a special attribute __doc__ contains the docstring
+// for an object (function, method, class, ...) if any is defined
+// Otherwise, the attribute's value is None
+bool
+ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string& dest)
+{
+ dest.clear();
+ if (!item || !*item)
+ return false;
+ std::string command(item);
+ command += ".__doc__";
+
+ char* result_ptr = NULL; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully
+
+ if (ExecuteOneLineWithReturn (command.c_str(),
+ ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
+ &result_ptr,
+ ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)))
+ {
+ if (result_ptr)
+ dest.assign(result_ptr);
+ return true;
+ }
+ else
+ {
+ StreamString str_stream;
+ str_stream.Printf("Function %s was not found. Containing module might be missing.",item);
+ dest.assign(str_stream.GetData());
+ return false;
+ }
+}
+
+std::unique_ptr<ScriptInterpreterLocker>
+ScriptInterpreterPython::AcquireInterpreterLock ()
+{
+ std::unique_ptr<ScriptInterpreterLocker> py_lock(new Locker(this,
+ Locker::AcquireLock | Locker::InitSession,
+ Locker::FreeLock | Locker::TearDownSession));
+ return py_lock;
+}
+
+void
+ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback)
+{
+ g_swig_init_callback = python_swig_init_callback;
+ g_swig_breakpoint_callback = LLDBSwigPythonBreakpointCallbackFunction;
+ g_swig_watchpoint_callback = LLDBSwigPythonWatchpointCallbackFunction;
+ g_swig_typescript_callback = LLDBSwigPythonCallTypeScript;
+ g_swig_synthetic_script = LLDBSwigPythonCreateSyntheticProvider;
+ g_swig_calc_children = LLDBSwigPython_CalculateNumChildren;
+ g_swig_get_child_index = LLDBSwigPython_GetChildAtIndex;
+ g_swig_get_index_child = LLDBSwigPython_GetIndexOfChildWithName;
+ g_swig_cast_to_sbvalue = LLDBSWIGPython_CastPyObjectToSBValue;
+ g_swig_update_provider = LLDBSwigPython_UpdateSynthProviderInstance;
+ g_swig_mighthavechildren_provider = LLDBSwigPython_MightHaveChildrenSynthProviderInstance;
+ g_swig_call_command = LLDBSwigPythonCallCommand;
+ g_swig_call_module_init = LLDBSwigPythonCallModuleInit;
+ g_swig_create_os_plugin = LLDBSWIGPythonCreateOSPlugin;
+ g_swig_run_script_keyword_process = LLDBSWIGPythonRunScriptKeywordProcess;
+ g_swig_run_script_keyword_thread = LLDBSWIGPythonRunScriptKeywordThread;
+ g_swig_run_script_keyword_target = LLDBSWIGPythonRunScriptKeywordTarget;
+ g_swig_run_script_keyword_frame = LLDBSWIGPythonRunScriptKeywordFrame;
+}
+
+void
+ScriptInterpreterPython::InitializePrivate ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ // Python will muck with STDIN terminal state, so save off any current TTY
+ // settings so we can restore them.
+ TerminalState stdin_tty_state;
+ stdin_tty_state.Save(STDIN_FILENO, false);
+
+ PyGILState_STATE gstate;
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE));
+ bool threads_already_initialized = false;
+ if (PyEval_ThreadsInitialized ()) {
+ gstate = PyGILState_Ensure ();
+ if (log)
+ log->Printf("Ensured PyGILState. Previous state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : "");
+ threads_already_initialized = true;
+ } else {
+ // InitThreads acquires the GIL if it hasn't been called before.
+ PyEval_InitThreads ();
+ }
+ Py_InitializeEx (0);
+
+ // Initialize SWIG after setting up python
+ assert (g_swig_init_callback != NULL);
+ g_swig_init_callback ();
+
+ // Update the path python uses to search for modules to include the current directory.
+
+ PyRun_SimpleString ("import sys");
+ PyRun_SimpleString ("sys.path.append ('.')");
+
+ // Find the module that owns this code and use that path we get to
+ // set the sys.path appropriately.
+
+ FileSpec file_spec;
+ char python_dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypePythonDir, file_spec))
+ {
+ std::string python_path("sys.path.insert(0,\"");
+ size_t orig_len = python_path.length();
+ if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
+ {
+ python_path.append (python_dir_path);
+ python_path.append ("\")");
+ PyRun_SimpleString (python_path.c_str());
+ python_path.resize (orig_len);
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec))
+ {
+ if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
+ {
+ python_path.append (python_dir_path);
+ python_path.append ("\")");
+ PyRun_SimpleString (python_path.c_str());
+ python_path.resize (orig_len);
+ }
+ }
+ }
+
+ PyRun_SimpleString ("sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line; from termios import *");
+
+ if (threads_already_initialized) {
+ if (log)
+ log->Printf("Releasing PyGILState. Returning to state = %slocked\n", gstate == PyGILState_UNLOCKED ? "un" : "");
+ PyGILState_Release (gstate);
+ } else {
+ // We initialized the threads in this function, just unlock the GIL.
+ PyEval_SaveThread();
+ }
+
+ stdin_tty_state.Restore();
+}
+
+//void
+//ScriptInterpreterPython::Terminate ()
+//{
+// // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling
+// // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers
+// // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls
+// // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate,
+// // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls
+// // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from
+// // within Py_Finalize, which results in a seg fault.
+// //
+// // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't
+// // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the
+// // process exits).
+// //
+//// Py_Finalize ();
+//}
+
+#endif // #ifdef LLDB_DISABLE_PYTHON
diff --git a/source/Interpreter/embedded_interpreter.py b/source/Interpreter/embedded_interpreter.py
new file mode 100644
index 000000000000..0e57c1e4aec9
--- /dev/null
+++ b/source/Interpreter/embedded_interpreter.py
@@ -0,0 +1,103 @@
+import readline
+import code
+import sys
+import traceback
+
+class SimpleREPL(code.InteractiveConsole):
+ def __init__(self, prompt, dict):
+ code.InteractiveConsole.__init__(self,dict)
+ self.prompt = prompt
+ self.loop_exit = False
+ self.dict = dict
+
+ def interact(self):
+ try:
+ sys.ps1
+ except AttributeError:
+ sys.ps1 = ">>> "
+ try:
+ sys.ps2
+ except AttributeError:
+ sys.ps2 = "... "
+
+ while not self.loop_exit:
+ try:
+ self.read_py_command()
+ except (SystemExit, EOFError):
+ # EOF while in Python just breaks out to top level.
+ self.write('\n')
+ self.loop_exit = True
+ break
+ except KeyboardInterrupt:
+ self.write("\nKeyboardInterrupt\n")
+ self.resetbuffer()
+ more = 0
+ except:
+ traceback.print_exc()
+
+ def process_input (self, in_str):
+ # Canonicalize the format of the input string
+ temp_str = in_str
+ temp_str.strip(' \t')
+ words = temp_str.split()
+ temp_str = ('').join(words)
+
+ # Check the input string to see if it was the quit
+ # command. If so, intercept it, so that it doesn't
+ # close stdin on us!
+ if (temp_str.lower() == "quit()" or temp_str.lower() == "exit()"):
+ self.loop_exit = True
+ in_str = "raise SystemExit "
+ return in_str
+
+ def my_raw_input (self, prompt):
+ stream = sys.stdout
+ stream.write (prompt)
+ stream.flush ()
+ try:
+ line = sys.stdin.readline()
+ except KeyboardInterrupt:
+ line = " \n"
+ except (SystemExit, EOFError):
+ line = "quit()\n"
+ if not line:
+ raise EOFError
+ if line[-1] == '\n':
+ line = line[:-1]
+ return line
+
+ def read_py_command(self):
+ # Read off a complete Python command.
+ more = 0
+ while 1:
+ if more:
+ prompt = sys.ps2
+ else:
+ prompt = sys.ps1
+ line = self.my_raw_input(prompt)
+ # Can be None if sys.stdin was redefined
+ encoding = getattr(sys.stdin, "encoding", None)
+ if encoding and not isinstance(line, unicode):
+ line = line.decode(encoding)
+ line = self.process_input (line)
+ more = self.push(line)
+ if not more:
+ break
+
+ def one_line (self, input):
+ line = self.process_input (input)
+ more = self.push(line)
+ if more:
+ self.write ("Input not a complete line.")
+ self.resetbuffer()
+ more = 0
+
+def run_python_interpreter (dict):
+ # Pass in the dictionary, for continuity from one session to the next.
+ repl = SimpleREPL('>>> ', dict)
+ repl.interact()
+
+def run_one_line (dict, input_string):
+ repl = SimpleREPL ('', dict)
+ repl.one_line (input_string)
+
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
new file mode 100644
index 000000000000..4685c3e759e0
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -0,0 +1,861 @@
+//===-- ABIMacOSX_arm.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_arm.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ========== ======= == === ============= ============ ======================= =================== =========================== ======================= ====================== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint , eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint , eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint , eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint , eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r7", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint , eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint , eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint , eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fpscr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, gdb_arm_d0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, gdb_arm_d1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, gdb_arm_d2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, gdb_arm_d3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, gdb_arm_d4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, gdb_arm_d5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, gdb_arm_d6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, gdb_arm_d7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, gdb_arm_d8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, gdb_arm_d9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, gdb_arm_d10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, gdb_arm_d11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, gdb_arm_d12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, gdb_arm_d13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, gdb_arm_d14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, gdb_arm_d15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, gdb_arm_d16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, gdb_arm_d17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, gdb_arm_d18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, gdb_arm_d19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, gdb_arm_d20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, gdb_arm_d21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, gdb_arm_d22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, gdb_arm_d23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, gdb_arm_d24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, gdb_arm_d25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, gdb_arm_d26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, gdb_arm_d27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, gdb_arm_d28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, gdb_arm_d29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, gdb_arm_d30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, gdb_arm_d31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_usr", "sp_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_usr", "lr_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_fiq", "sp_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_fiq", "lr_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_irq", "sp_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_irq", "lr_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_abt", "sp_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_abt", "lr_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_und", "sp_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_und", "lr_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_svc", "sp_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_svc", "lr_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABIMacOSX_arm::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABIMacOSX_arm::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_arm::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ if ((arch_type == llvm::Triple::arm) ||
+ (arch_type == llvm::Triple::thumb))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_arm::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t function_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ RegisterValue reg_value;
+
+ if (arg1_ptr)
+ {
+ reg_value.SetUInt32(*arg1_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r0"), reg_value))
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_value.SetUInt32(*arg2_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r1"), reg_value))
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_value.SetUInt32(*arg3_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r2"), reg_value))
+ return false;
+ if (arg4_ptr)
+ {
+ reg_value.SetUInt32(*arg4_ptr);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3");
+ if (!reg_ctx->WriteRegister (reg_info, reg_value))
+ return false;
+ if (arg5_ptr)
+ {
+ // Keep the stack 8 byte aligned, not that we need to
+ sp -= 8;
+ sp &= ~(8ull-1ull);
+ reg_value.SetUInt32(*arg5_ptr);
+ if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp, reg_info->byte_size, reg_value).Fail())
+ return false;
+ if (arg6_ptr)
+ {
+ reg_value.SetUInt32(*arg6_ptr);
+ if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp + 4, reg_info->byte_size, reg_value).Fail())
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ TargetSP target_sp (thread.CalculateTarget());
+ Address so_addr;
+
+ // Figure out if our return address is ARM or Thumb by using the
+ // Address::GetCallableLoadAddress(Target*) which will figure out the ARM
+ // thumb-ness and set the correct address bits for us.
+ so_addr.SetLoadAddress (return_addr, target_sp.get());
+ return_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ // Set "lr" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_num, return_addr))
+ return false;
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // If bit zero or 1 is set, this must be a thumb function, no need to figure
+ // this out from the symbols.
+ so_addr.SetLoadAddress (function_addr, target_sp.get());
+ function_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ const RegisterInfo *cpsr_reg_info = reg_ctx->GetRegisterInfoByName("cpsr");
+ const uint32_t curr_cpsr = reg_ctx->ReadRegisterAsUnsigned(cpsr_reg_info, 0);
+
+ // Make a new CPSR and mask out any Thumb IT (if/then) bits
+ uint32_t new_cpsr = curr_cpsr & ~MASK_CPSR_IT_MASK;
+ // If bit zero or 1 is set, this must be thumb...
+ if (function_addr & 1ull)
+ new_cpsr |= MASK_CPSR_T; // Set T bit in CPSR
+ else
+ new_cpsr &= ~MASK_CPSR_T; // Clear T bit in CPSR
+
+ if (new_cpsr != curr_cpsr)
+ {
+ if (!reg_ctx->WriteRegisterFromUnsigned (cpsr_reg_info, new_cpsr))
+ return false;
+ }
+
+ function_addr &= ~1ull; // clear bit zero since the CPSR will take care of the mode for us
+
+ // Set "pc" to the address requested
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, function_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_arm::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ uint32_t num_values = values.GetSize();
+
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = 0;
+
+ for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx)
+ {
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ Value *value = values.GetValueAtIndex(value_idx);
+
+ if (!value)
+ return false;
+
+ ClangASTType clang_type = value->GetClangType();
+ if (clang_type)
+ {
+ bool is_signed = false;
+ size_t bit_width = 0;
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ bit_width = clang_type.GetBitSize();
+ }
+ else if (clang_type.IsPointerOrReferenceType ())
+ {
+ bit_width = clang_type.GetBitSize();
+ }
+ else
+ {
+ // We only handle integer, pointer and reference types currently...
+ return false;
+ }
+
+ if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8))
+ {
+ if (value_idx < 4)
+ {
+ // Arguments 1-4 are in r0-r3...
+ const RegisterInfo *arg_reg_info = NULL;
+ // Search by generic ID first, then fall back to by name
+ uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
+ if (arg_reg_num != LLDB_INVALID_REGNUM)
+ {
+ arg_reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num);
+ }
+ else
+ {
+ switch (value_idx)
+ {
+ case 0: arg_reg_info = reg_ctx->GetRegisterInfoByName("r0"); break;
+ case 1: arg_reg_info = reg_ctx->GetRegisterInfoByName("r1"); break;
+ case 2: arg_reg_info = reg_ctx->GetRegisterInfoByName("r2"); break;
+ case 3: arg_reg_info = reg_ctx->GetRegisterInfoByName("r3"); break;
+ }
+ }
+
+ if (arg_reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister(arg_reg_info, reg_value))
+ {
+ if (is_signed)
+ reg_value.SignExtend(bit_width);
+ if (!reg_value.GetScalarValue(value->GetScalar()))
+ return false;
+ continue;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ if (sp == 0)
+ {
+ // Read the stack pointer if it already hasn't been read
+ sp = reg_ctx->GetSP(0);
+ if (sp == 0)
+ return false;
+ }
+
+ // Arguments 5 on up are on the stack
+ const uint32_t arg_byte_size = (bit_width + (8-1)) / 8;
+ Error error;
+ if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error))
+ return false;
+
+ sp += arg_byte_size;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+ValueObjectSP
+ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread,
+ lldb_private::ClangASTType &clang_type) const
+{
+ Value value;
+ ValueObjectSP return_valobj_sp;
+
+ if (!clang_type)
+ return return_valobj_sp;
+
+ clang::ASTContext *ast_context = clang_type.GetASTContext();
+ if (!ast_context)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
+ value.SetClangType (clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0);
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ size_t bit_width = clang_type.GetBitSize();
+
+ switch (bit_width)
+ {
+ default:
+ return return_valobj_sp;
+ case 64:
+ {
+ const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0);
+ uint64_t raw_value;
+ raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ }
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ break;
+ }
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+Error
+ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ lldb::offset_t offset = 0;
+ if (num_bytes <= 8)
+ {
+ const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("r0", 0);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ {
+ const RegisterInfo *r1_info = reg_ctx->GetRegisterInfoByName("r1", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r1_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+bool
+ABIMacOSX_arm::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t lr_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ lr_reg_num = dwarf_lr;
+ sp_reg_num = dwarf_sp;
+ pc_reg_num = dwarf_pc;
+ break;
+
+ case eRegisterKindGeneric:
+ lr_reg_num = LLDB_REGNUM_GENERIC_RA;
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (lr_reg_num == LLDB_INVALID_REGNUM ||
+ sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ 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 ("arm at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABIMacOSX_arm::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t fp_reg_num = dwarf_r7; // apple uses r7 for all frames. Normal arm uses r11;
+ uint32_t pc_reg_num = dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ unwind_plan.Clear ();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+ row->SetCFARegister (fp_reg_num);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("arm-apple-ios default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+
+ return true;
+}
+
+// ARMv7 on iOS general purpose reg rules:
+// r0-r3 not preserved (used for argument passing)
+// r4-r6 preserved
+// r7 preserved (frame pointer)
+// r8 preserved
+// r9 not preserved (usable as volatile scratch register with iOS 3.x and later)
+// r10-r11 preserved
+// r12 not presrved
+// r13 preserved (stack pointer)
+// r14 not preserved (link register)
+// r15 preserved (pc)
+// cpsr not preserved (different rules for different bits)
+
+// ARMv7 on iOS floating point rules:
+// d0-d7 not preserved (aka s0-s15, q0-q3)
+// d8-d15 preserved (aka s16-s31, q4-q7)
+// d16-d31 not preserved (aka q8-q15)
+
+bool
+ABIMacOSX_arm::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Volatile registers include: r0, r1, r2, r3, r9, r12, r13
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ switch (name[1])
+ {
+ case '0': return name[2] == '\0'; // r0
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // r1
+ case '2':
+ case '3':
+ return name[2] == '\0'; // r12 - r13
+ default:
+ break;
+ }
+ break;
+
+ case '2': return name[2] == '\0'; // r2
+ case '3': return name[2] == '\0'; // r3
+ case '9': return name[2] == '\0'; // r9 (apple-ios only...)
+
+ break;
+ }
+ }
+ else if (name[0] == 'd')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // d0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d1 is volatile
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d16 - d19 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d2 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d20 - d29 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d3 is volatile
+ case '0':
+ case '1':
+ return name[3] == '\0'; // d30 - d31 are volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return name[2] == '\0'; // d4 - d7 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // s0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s1 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ return name[3] == '\0'; // s10 - s15 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s2 is volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s3 is volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[2] == '\0'; // s4 - s9 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's' && name[1] == 'p' && name[2] == '\0')
+ return true;
+ }
+ return false;
+}
+
+void
+ABIMacOSX_arm::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Mac OS X ABI for arm targets",
+ CreateInstance);
+}
+
+void
+ABIMacOSX_arm::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABIMacOSX_arm::GetPluginNameStatic()
+{
+ static ConstString g_name("macosx-arm");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABIMacOSX_arm::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABIMacOSX_arm::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
new file mode 100644
index 000000000000..27cea85aaf6f
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
@@ -0,0 +1,138 @@
+//===-- ABIMacOSX_arm.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ABIMacOSX_arm_h_
+#define liblldb_ABIMacOSX_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABIMacOSX_arm : public lldb_private::ABI
+{
+public:
+ ~ABIMacOSX_arm() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t returnAddress,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) 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:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+public:
+ 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;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 4 byte aligned
+ if (cfa & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // Just make sure the address is a valid 32 bit address. Bit zero
+ // might be set due to Thumb function calls, so don't enforce 2 byte
+ // alignment
+ return pc <= UINT32_MAX;
+ }
+
+ virtual lldb::addr_t
+ FixCodeAddress (lldb::addr_t pc)
+ {
+ // ARM uses bit zero to signify a code address is thumb, so we must
+ // strip bit zero in any code addresses.
+ return pc & ~(lldb::addr_t)1;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ return false;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+private:
+ ABIMacOSX_arm() :
+ lldb_private::ABI()
+ {
+ // Call CreateInstance instead.
+ }
+};
+
+#endif // liblldb_ABIMacOSX_arm_h_
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
new file mode 100644
index 000000000000..deb531d937a0
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -0,0 +1,977 @@
+//===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_i386.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7,
+ dwarf_ymm0 = dwarf_xmm0,
+ dwarf_ymm1 = dwarf_xmm1,
+ dwarf_ymm2 = dwarf_xmm2,
+ dwarf_ymm3 = dwarf_xmm3,
+ dwarf_ymm4 = dwarf_xmm4,
+ dwarf_ymm5 = dwarf_xmm5,
+ dwarf_ymm6 = dwarf_xmm6,
+ dwarf_ymm7 = dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48,
+ gdb_ymm0 = gdb_xmm0,
+ gdb_ymm1 = gdb_xmm1,
+ gdb_ymm2 = gdb_xmm2,
+ gdb_ymm3 = gdb_xmm3,
+ gdb_ymm4 = gdb_xmm4,
+ gdb_ymm5 = gdb_xmm5,
+ gdb_ymm6 = gdb_xmm6,
+ gdb_ymm7 = gdb_xmm7
+};
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ====== ======= == === ============= ============ ===================== ===================== ============================ ==================== ====================== ========== ===============
+ { "eax", NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ebx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ecx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_ecx , dwarf_ecx , LLDB_REGNUM_GENERIC_ARG4 , gdb_ecx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "edx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_edx , dwarf_edx , LLDB_REGNUM_GENERIC_ARG3 , gdb_edx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "esi" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_esi , dwarf_esi , LLDB_REGNUM_GENERIC_ARG2 , gdb_esi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "edi" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_edi , dwarf_edi , LLDB_REGNUM_GENERIC_ARG1 , gdb_edi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ebp" , "fp", 4, 0, eEncodingUint , eFormatHex , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "esp" , "sp", 4, 0, eEncodingUint , eFormatHex , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "eip" , "pc", 4, 0, eEncodingUint , eFormatHex , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "eflags", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ss" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ds" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "es" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "gs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm0" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm0 , LLDB_INVALID_REGNUM , gdb_stmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm1" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm1 , LLDB_INVALID_REGNUM , gdb_stmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm2" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm2 , LLDB_INVALID_REGNUM , gdb_stmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm3" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm3 , LLDB_INVALID_REGNUM , gdb_stmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm4" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm4 , LLDB_INVALID_REGNUM , gdb_stmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm5" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm5 , LLDB_INVALID_REGNUM , gdb_stmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm6" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm6 , LLDB_INVALID_REGNUM , gdb_stmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm7" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm7 , LLDB_INVALID_REGNUM , gdb_stmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fctrl" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fctrl , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fstat" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fstat , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ftag" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftag , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fiseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fiseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fioff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fioff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "foseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_foseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fooff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fooff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fop" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm0" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm0 , LLDB_INVALID_REGNUM , gdb_xmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm1" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm1 , LLDB_INVALID_REGNUM , gdb_xmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm2" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm2 , LLDB_INVALID_REGNUM , gdb_xmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm3" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm3 , LLDB_INVALID_REGNUM , gdb_xmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm4" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm4 , LLDB_INVALID_REGNUM , gdb_xmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm5" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm5 , LLDB_INVALID_REGNUM , gdb_xmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm6" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm6 , LLDB_INVALID_REGNUM , gdb_xmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm7" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm7 , LLDB_INVALID_REGNUM , gdb_xmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "mxcsr" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm0" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm0 , LLDB_INVALID_REGNUM , gdb_ymm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm1" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm1 , LLDB_INVALID_REGNUM , gdb_ymm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm2" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm2 , LLDB_INVALID_REGNUM , gdb_ymm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm3" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm3 , LLDB_INVALID_REGNUM , gdb_ymm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm4" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm4 , LLDB_INVALID_REGNUM , gdb_ymm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm5" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm5 , LLDB_INVALID_REGNUM , gdb_ymm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm6" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm6 , LLDB_INVALID_REGNUM , gdb_ymm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABIMacOSX_i386::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+size_t
+ABIMacOSX_i386::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_i386::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::x86)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_i386);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // When writing a register value down to memory, the register info used
+ // to write memory just needs to have the correct size of a 32 bit register,
+ // the actual register it pertains to is not important, just the size needs
+ // to be correct. Here we use "eax"...
+ const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
+ if (!reg_info_32)
+ return false; // TODO this should actually never happen
+
+ // Make room for the argument(s) on the stack
+
+ Error error;
+ RegisterValue reg_value;
+
+ // Write any arguments onto the stack
+ if (arg1_ptr)
+ {
+ sp -= 4;
+ if (arg2_ptr)
+ {
+ sp -= 4;
+ if (arg3_ptr)
+ {
+ sp -= 4;
+ if (arg4_ptr)
+ {
+ sp -= 4;
+ if (arg5_ptr)
+ {
+ sp -= 4;
+ if (arg6_ptr)
+ {
+ sp -= 4;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Align the SP
+ sp &= ~(16ull-1ull); // 16-byte alignment
+
+ if (arg1_ptr)
+ {
+ reg_value.SetUInt32(*arg1_ptr);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_value.SetUInt32(*arg2_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 4,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_value.SetUInt32(*arg3_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 8,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg4_ptr)
+ {
+ reg_value.SetUInt32(*arg4_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 12,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ if (arg5_ptr)
+ {
+ reg_value.SetUInt32(*arg5_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 16,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ if (arg6_ptr)
+ {
+ reg_value.SetUInt32(*arg6_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 20,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // The return address is pushed onto the stack (yes after we just set the
+ // alignment above!).
+ sp -= 4;
+ reg_value.SetUInt32(return_addr);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ ValueList &args) const
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Error error;
+ uint32_t fp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Do the argument layout
+
+ std::vector <uint32_t> argLayout; // 4-byte chunks, as discussed in the ABI Function Call Guide
+
+ size_t numArgs = args.GetSize();
+ size_t index;
+
+ for (index = 0; index < numArgs; ++index)
+ {
+ Value *val = args.GetValueAtIndex(index);
+
+ if (!val)
+ return false;
+
+ switch (val->GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ {
+ Scalar &scalar = val->GetScalar();
+ switch (scalar.GetType())
+ {
+ case Scalar::e_void:
+ return false;
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ {
+ uint64_t data = scalar.ULongLong();
+
+ switch (scalar.GetByteSize())
+ {
+ default:
+ return false;
+ case 1:
+ argLayout.push_back((uint32_t)(data & 0xffull));
+ break;
+ case 2:
+ argLayout.push_back((uint32_t)(data & 0xffffull));
+ break;
+ case 4:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ break;
+ case 8:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ argLayout.push_back((uint32_t)(data >> 32));
+ break;
+ }
+ }
+ break;
+ case Scalar::e_float:
+ {
+ float data = scalar.Float();
+ uint32_t dataRaw = *((uint32_t*)(&data));
+ argLayout.push_back(dataRaw);
+ }
+ break;
+ case Scalar::e_double:
+ {
+ double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ }
+ break;
+ case Scalar::e_long_double:
+ {
+ long double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ while ((argLayout.size() * 4) & 0xf)
+ argLayout.push_back(0);
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ argLayout.push_back(dataRaw[2]);
+ argLayout.push_back(dataRaw[3]);
+ }
+ break;
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ ClangASTType clang_type (val->GetClangType());
+ if (clang_type)
+ {
+ uint32_t cstr_length = 0;
+ if (clang_type.IsCStringType (cstr_length))
+ {
+ const char *cstr = (const char*)val->GetScalar().ULongLong();
+ cstr_length = strlen(cstr);
+
+ // Push the string onto the stack immediately.
+
+ sp -= (cstr_length + 1);
+
+ if (process->WriteMemory(sp, cstr, cstr_length + 1, error) != (cstr_length + 1))
+ return false;
+
+ // Put the address of the string into the argument array.
+
+ argLayout.push_back((uint32_t)(sp & 0xffffffff));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ default:
+ return false;
+ }
+ }
+
+ // Make room for the arguments on the stack
+
+ sp -= 4 * argLayout.size();
+
+ // Align the SP
+
+ sp &= ~(16ull-1ull); // 16-byte alignment
+
+ // Write the arguments on the stack
+
+ size_t numChunks = argLayout.size();
+
+ for (index = 0; index < numChunks; ++index)
+ if (process->WriteMemory(sp + (index * 4), &argLayout[index], sizeof(uint32_t), error) != sizeof(uint32_t))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = return_addr;
+ if (process->WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(fp_reg_num, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool
+ReadIntegerArgument (Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process *process,
+ addr_t &current_stack_argument)
+{
+
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+ if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+}
+
+bool
+ABIMacOSX_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ ClangASTType clang_type (value->GetClangType());
+ if (clang_type)
+ {
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ is_signed,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ false,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ }
+ }
+
+ return true;
+}
+
+Error
+ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ lldb::offset_t offset = 0;
+ if (num_bytes <= 8)
+ {
+ const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
+ {
+ const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (edx_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+ValueObjectSP
+ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
+ ClangASTType &clang_type) const
+{
+ Value value;
+ ValueObjectSP return_valobj_sp;
+
+ if (!clang_type)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
+ value.SetClangType (clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ size_t bit_width = clang_type.GetBitSize();
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return return_valobj_sp;
+ case 64:
+ uint64_t raw_value;
+ raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+bool
+ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ sp_reg_num = dwarf_esp;
+ pc_reg_num = dwarf_eip;
+ break;
+
+ case eRegisterKindGCC:
+ sp_reg_num = gcc_esp;
+ pc_reg_num = gcc_eip;
+ break;
+
+ case eRegisterKindGDB:
+ sp_reg_num = gdb_esp;
+ pc_reg_num = gdb_eip;
+ break;
+
+ case eRegisterKindGeneric:
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetCFARegister (sp_reg_num);
+ row->SetCFAOffset (4);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABIMacOSX_i386::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t fp_reg_num = dwarf_ebp;
+ uint32_t sp_reg_num = dwarf_esp;
+ uint32_t pc_reg_num = dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ unwind_plan.Clear ();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+ row->SetCFARegister (fp_reg_num);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABIMacOSX_i386::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+// v. http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
+
+bool
+ABIMacOSX_i386::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Saved registers are ebx, ebp, esi, edi, esp, eip
+ const char *name = reg_info->name;
+ if (name[0] == 'e')
+ {
+ switch (name[1])
+ {
+ case 'b':
+ if (name[2] == 'x' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 'd':
+ if (name[2] == 'i')
+ return name[3] == '\0';
+ break;
+ case 'i':
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 's':
+ if (name[2] == 'i' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ }
+ }
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+ }
+ return false;
+}
+
+void
+ABIMacOSX_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Mac OS X ABI for i386 targets",
+ CreateInstance);
+}
+
+void
+ABIMacOSX_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABIMacOSX_i386::GetPluginNameStatic ()
+{
+ static ConstString g_short_name("abi.macosx-i386");
+ return g_short_name;
+
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABIMacOSX_i386::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABIMacOSX_i386::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
new file mode 100644
index 000000000000..8c2d945e6342
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -0,0 +1,139 @@
+//===-- ABIMacOSX_i386.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ABIMacOSX_i386_h_
+#define liblldb_ABIMacOSX_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Core/Value.h"
+
+class ABIMacOSX_i386 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABIMacOSX_i386() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) const;
+
+ virtual bool
+ PrepareNormalCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ lldb_private::ValueList &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:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+public:
+
+ 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;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 8 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // Just make sure the address is a valid 32 bit address.
+ return pc <= UINT32_MAX;
+ }
+
+ 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);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABIMacOSX_i386() : 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
new file mode 100644
index 000000000000..a904d8b649ca
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -0,0 +1,1288 @@
+//===-- ABISysV_x86_64.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_x86_64.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_rax = 0,
+ gcc_dwarf_rdx,
+ gcc_dwarf_rcx,
+ gcc_dwarf_rbx,
+ gcc_dwarf_rsi,
+ gcc_dwarf_rdi,
+ gcc_dwarf_rbp,
+ gcc_dwarf_rsp,
+ 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_rip,
+ gcc_dwarf_xmm0,
+ gcc_dwarf_xmm1,
+ gcc_dwarf_xmm2,
+ gcc_dwarf_xmm3,
+ gcc_dwarf_xmm4,
+ gcc_dwarf_xmm5,
+ gcc_dwarf_xmm6,
+ gcc_dwarf_xmm7,
+ gcc_dwarf_xmm8,
+ gcc_dwarf_xmm9,
+ gcc_dwarf_xmm10,
+ gcc_dwarf_xmm11,
+ gcc_dwarf_xmm12,
+ gcc_dwarf_xmm13,
+ gcc_dwarf_xmm14,
+ gcc_dwarf_xmm15,
+ gcc_dwarf_stmm0,
+ gcc_dwarf_stmm1,
+ gcc_dwarf_stmm2,
+ gcc_dwarf_stmm3,
+ gcc_dwarf_stmm4,
+ gcc_dwarf_stmm5,
+ gcc_dwarf_stmm6,
+ gcc_dwarf_stmm7,
+ gcc_dwarf_ymm0,
+ gcc_dwarf_ymm1,
+ gcc_dwarf_ymm2,
+ gcc_dwarf_ymm3,
+ gcc_dwarf_ymm4,
+ gcc_dwarf_ymm5,
+ gcc_dwarf_ymm6,
+ gcc_dwarf_ymm7,
+ gcc_dwarf_ymm8,
+ gcc_dwarf_ymm9,
+ gcc_dwarf_ymm10,
+ gcc_dwarf_ymm11,
+ gcc_dwarf_ymm12,
+ gcc_dwarf_ymm13,
+ gcc_dwarf_ymm14,
+ gcc_dwarf_ymm15
+};
+
+enum gdb_regnums
+{
+ gdb_rax = 0,
+ gdb_rbx = 1,
+ gdb_rcx = 2,
+ gdb_rdx = 3,
+ gdb_rsi = 4,
+ gdb_rdi = 5,
+ gdb_rbp = 6,
+ gdb_rsp = 7,
+ gdb_r8 = 8,
+ gdb_r9 = 9,
+ gdb_r10 = 10,
+ gdb_r11 = 11,
+ gdb_r12 = 12,
+ gdb_r13 = 13,
+ gdb_r14 = 14,
+ gdb_r15 = 15,
+ gdb_rip = 16,
+ gdb_rflags = 17,
+ gdb_cs = 18,
+ gdb_ss = 19,
+ gdb_ds = 20,
+ gdb_es = 21,
+ gdb_fs = 22,
+ gdb_gs = 23,
+ gdb_stmm0 = 24,
+ gdb_stmm1 = 25,
+ gdb_stmm2 = 26,
+ gdb_stmm3 = 27,
+ gdb_stmm4 = 28,
+ gdb_stmm5 = 29,
+ gdb_stmm6 = 30,
+ gdb_stmm7 = 31,
+ gdb_fctrl = 32, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 33, gdb_fsw = gdb_fstat,
+ gdb_ftag = 34, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 35, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 36, gdb_ip = gdb_fioff,
+ gdb_foseg = 37, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 38, gdb_dp = gdb_fooff,
+ gdb_fop = 39,
+ gdb_xmm0 = 40,
+ gdb_xmm1 = 41,
+ gdb_xmm2 = 42,
+ gdb_xmm3 = 43,
+ gdb_xmm4 = 44,
+ gdb_xmm5 = 45,
+ gdb_xmm6 = 46,
+ gdb_xmm7 = 47,
+ gdb_xmm8 = 48,
+ gdb_xmm9 = 49,
+ gdb_xmm10 = 50,
+ gdb_xmm11 = 51,
+ gdb_xmm12 = 52,
+ gdb_xmm13 = 53,
+ gdb_xmm14 = 54,
+ gdb_xmm15 = 55,
+ gdb_mxcsr = 56,
+ gdb_ymm0 = 57,
+ gdb_ymm1 = 58,
+ gdb_ymm2 = 59,
+ gdb_ymm3 = 60,
+ gdb_ymm4 = 61,
+ gdb_ymm5 = 62,
+ gdb_ymm6 = 63,
+ gdb_ymm7 = 64,
+ gdb_ymm8 = 65,
+ gdb_ymm9 = 66,
+ gdb_ymm10 = 67,
+ gdb_ymm11 = 68,
+ gdb_ymm12 = 69,
+ gdb_ymm13 = 70,
+ gdb_ymm14 = 71,
+ gdb_ymm15 = 72
+};
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ======== ======= == === ============= =================== ======================= ===================== =========================== ===================== ====================== ========== ===============
+ { "rax" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rax , gcc_dwarf_rax , LLDB_INVALID_REGNUM , gdb_rax , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rbx" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rbx , gcc_dwarf_rbx , LLDB_INVALID_REGNUM , gdb_rbx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rcx" , "arg4", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rcx , gcc_dwarf_rcx , LLDB_REGNUM_GENERIC_ARG4 , gdb_rcx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rdx" , "arg3", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rdx , gcc_dwarf_rdx , LLDB_REGNUM_GENERIC_ARG3 , gdb_rdx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rsi" , "arg2", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rsi , gcc_dwarf_rsi , LLDB_REGNUM_GENERIC_ARG2 , gdb_rsi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rdi" , "arg1", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rdi , gcc_dwarf_rdi , LLDB_REGNUM_GENERIC_ARG1 , gdb_rdi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rbp" , "fp", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rbp , gcc_dwarf_rbp , LLDB_REGNUM_GENERIC_FP , gdb_rbp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rsp" , "sp", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rsp , gcc_dwarf_rsp , LLDB_REGNUM_GENERIC_SP , gdb_rsp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8" , "arg5", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r8 , gcc_dwarf_r8 , LLDB_REGNUM_GENERIC_ARG5 , gdb_r8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9" , "arg6", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r9 , gcc_dwarf_r9 , LLDB_REGNUM_GENERIC_ARG6 , gdb_r9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r10 , gcc_dwarf_r10 , LLDB_INVALID_REGNUM , gdb_r10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r11 , gcc_dwarf_r11 , LLDB_INVALID_REGNUM , gdb_r11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r12 , gcc_dwarf_r12 , LLDB_INVALID_REGNUM , gdb_r12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r13 , gcc_dwarf_r13 , LLDB_INVALID_REGNUM , gdb_r13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r14 , gcc_dwarf_r14 , LLDB_INVALID_REGNUM , gdb_r14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r15" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r15 , gcc_dwarf_r15 , LLDB_INVALID_REGNUM , gdb_r15 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rip" , "pc", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rip , gcc_dwarf_rip , LLDB_REGNUM_GENERIC_PC , gdb_rip , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rflags", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_rflags , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ss" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ds" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "es" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "gs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm0" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm0 , gcc_dwarf_stmm0 , LLDB_INVALID_REGNUM , gdb_stmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm1" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm1 , gcc_dwarf_stmm1 , LLDB_INVALID_REGNUM , gdb_stmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm2" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm2 , gcc_dwarf_stmm2 , LLDB_INVALID_REGNUM , gdb_stmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm3" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm3 , gcc_dwarf_stmm3 , LLDB_INVALID_REGNUM , gdb_stmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm4" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm4 , gcc_dwarf_stmm4 , LLDB_INVALID_REGNUM , gdb_stmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm5" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm5 , gcc_dwarf_stmm5 , LLDB_INVALID_REGNUM , gdb_stmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm6" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm6 , gcc_dwarf_stmm6 , LLDB_INVALID_REGNUM , gdb_stmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm7" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm7 , gcc_dwarf_stmm7 , LLDB_INVALID_REGNUM , gdb_stmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fctrl" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fctrl , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fstat" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fstat , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ftag" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftag , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fiseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fiseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fioff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fioff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "foseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_foseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fooff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fooff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fop" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm0" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm0 , gcc_dwarf_xmm0 , LLDB_INVALID_REGNUM , gdb_xmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm1" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm1 , gcc_dwarf_xmm1 , LLDB_INVALID_REGNUM , gdb_xmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm2" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm2 , gcc_dwarf_xmm2 , LLDB_INVALID_REGNUM , gdb_xmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm3" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm3 , gcc_dwarf_xmm3 , LLDB_INVALID_REGNUM , gdb_xmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm4" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm4 , gcc_dwarf_xmm4 , LLDB_INVALID_REGNUM , gdb_xmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm5" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm5 , gcc_dwarf_xmm5 , LLDB_INVALID_REGNUM , gdb_xmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm6" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm6 , gcc_dwarf_xmm6 , LLDB_INVALID_REGNUM , gdb_xmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm7" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm7 , gcc_dwarf_xmm7 , LLDB_INVALID_REGNUM , gdb_xmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm8" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm8 , gcc_dwarf_xmm8 , LLDB_INVALID_REGNUM , gdb_xmm8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm9" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm9 , gcc_dwarf_xmm9 , LLDB_INVALID_REGNUM , gdb_xmm9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm10" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm10 , gcc_dwarf_xmm10 , LLDB_INVALID_REGNUM , gdb_xmm10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm11" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm11 , gcc_dwarf_xmm11 , LLDB_INVALID_REGNUM , gdb_xmm11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm12" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm12 , gcc_dwarf_xmm12 , LLDB_INVALID_REGNUM , gdb_xmm12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm13" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm13 , gcc_dwarf_xmm13 , LLDB_INVALID_REGNUM , gdb_xmm13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm14" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm14 , gcc_dwarf_xmm14 , LLDB_INVALID_REGNUM , gdb_xmm14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm15" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm15 , gcc_dwarf_xmm15 , LLDB_INVALID_REGNUM , gdb_xmm15 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "mxcsr" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm0" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm0 , gcc_dwarf_ymm0 , LLDB_INVALID_REGNUM , gdb_ymm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm1" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm1 , gcc_dwarf_ymm1 , LLDB_INVALID_REGNUM , gdb_ymm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm2" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm2 , gcc_dwarf_ymm2 , LLDB_INVALID_REGNUM , gdb_ymm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm3" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm3 , gcc_dwarf_ymm3 , LLDB_INVALID_REGNUM , gdb_ymm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm4" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm4 , gcc_dwarf_ymm4 , LLDB_INVALID_REGNUM , gdb_ymm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm5" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm5 , gcc_dwarf_ymm5 , LLDB_INVALID_REGNUM , gdb_ymm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm6" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm6 , gcc_dwarf_ymm6 , LLDB_INVALID_REGNUM , gdb_ymm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm7 , gcc_dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm8" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm8 , gcc_dwarf_ymm8 , LLDB_INVALID_REGNUM , gdb_ymm8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm9" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm9 , gcc_dwarf_ymm9 , LLDB_INVALID_REGNUM , gdb_ymm9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm10" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm10 , gcc_dwarf_ymm10 , LLDB_INVALID_REGNUM , gdb_ymm10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm11" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm11 , gcc_dwarf_ymm11 , LLDB_INVALID_REGNUM , gdb_ymm11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm12" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm12 , gcc_dwarf_ymm12 , LLDB_INVALID_REGNUM , gdb_ymm12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm13" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm13 , gcc_dwarf_ymm13 , LLDB_INVALID_REGNUM , gdb_ymm13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm14" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm14 , gcc_dwarf_ymm14 , LLDB_INVALID_REGNUM , gdb_ymm14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm15" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm15 , gcc_dwarf_ymm15 , LLDB_INVALID_REGNUM , gdb_ymm15 , LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABISysV_x86_64::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABISysV_x86_64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_x86_64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_x86_64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ StreamString s;
+ s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64,
+ thread.GetID(),
+ (uint64_t)sp,
+ (uint64_t)func_addr,
+ (uint64_t)return_addr);
+
+ if (arg1_ptr)
+ {
+ s.Printf (", arg1 = 0x%" PRIx64, (uint64_t)*arg1_ptr);
+ if (arg2_ptr)
+ {
+ s.Printf (", arg2 = 0x%" PRIx64, (uint64_t)*arg2_ptr);
+ if (arg3_ptr)
+ {
+ s.Printf (", arg3 = 0x%" PRIx64, (uint64_t)*arg3_ptr);
+ if (arg4_ptr)
+ {
+ s.Printf (", arg4 = 0x%" PRIx64, (uint64_t)*arg4_ptr);
+ if (arg5_ptr)
+ {
+ s.Printf (", arg5 = 0x%" PRIx64, (uint64_t)*arg5_ptr);
+ if (arg6_ptr)
+ s.Printf (", arg6 = 0x%" PRIx64, (uint64_t)*arg6_ptr);
+ }
+ }
+ }
+ }
+ }
+ 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 (arg1_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rdi", 0);
+ if (log)
+ log->Printf("About to write arg1 (0x%" PRIx64 ") into %s", (uint64_t)*arg1_ptr, reg_info->name);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg1_ptr))
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rsi", 0);
+ if (log)
+ log->Printf("About to write arg2 (0x%" PRIx64 ") into %s", (uint64_t)*arg2_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg2_ptr))
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rdx", 0);
+ if (log)
+ log->Printf("About to write arg3 (0x%" PRIx64 ") into %s", (uint64_t)*arg3_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg3_ptr))
+ return false;
+
+ if (arg4_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rcx", 0);
+ if (log)
+ log->Printf("About to write arg4 (0x%" PRIx64 ") into %s", (uint64_t)*arg4_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg4_ptr))
+ return false;
+
+ if (arg5_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("r8", 0);
+ if (log)
+ log->Printf("About to write arg5 (0x%" PRIx64 ") into %s", (uint64_t)*arg5_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg5_ptr))
+ return false;
+
+ if (arg6_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("r9", 0);
+ if (log)
+ log->Printf("About to write arg6 (0x%" PRIx64 ") into %s", (uint64_t)*arg6_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg6_ptr))
+ 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
+
+ // The return address is pushed onto the stack (yes after the alignment...)
+ sp -= 8;
+
+ RegisterValue reg_value;
+ reg_value.SetUInt64 (return_addr);
+
+ if (log)
+ log->Printf("Pushing the return address onto the stack: new SP 0x%" PRIx64 ", return address 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr);
+
+ const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfoByName("rip");
+ Error error (reg_ctx->WriteRegisterValueToMemory(pc_reg_info, sp, pc_reg_info->byte_size, reg_value));
+ if (error.Fail())
+ return false;
+
+ // %rsp is set to the actual stack value.
+
+ if (log)
+ log->Printf("Writing SP (0x%" PRIx64 ") down", (uint64_t)sp);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoByName("rsp"), sp))
+ return false;
+
+ // %rip is set to the address of the called function.
+
+ if (log)
+ log->Printf("Writing new IP (0x%" PRIx64 ") down", (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_x86_64::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 + 8; // jump over return address
+
+ uint32_t argument_register_ids[6];
+
+ argument_register_ids[0] = reg_ctx->GetRegisterInfoByName("rdi", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[1] = reg_ctx->GetRegisterInfoByName("rsi", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[2] = reg_ctx->GetRegisterInfoByName("rdx", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[3] = reg_ctx->GetRegisterInfoByName("rcx", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[4] = reg_ctx->GetRegisterInfoByName("r8", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[5] = reg_ctx->GetRegisterInfoByName("r9", 0)->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_x86_64::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("rax", 0);
+
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ 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)
+ {
+ const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ RegisterValue xmm0_value;
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+
+ unsigned char buffer[16];
+ ByteOrder byte_order = data.GetByteOrder();
+
+ data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order);
+ xmm0_value.SetBytes(buffer, 16, byte_order);
+ reg_ctx->WriteRegister(xmm0_info, xmm0_value);
+ 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_x86_64::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 & ClangASTType::eTypeIsScalar)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+
+ bool success = false;
+ if (type_flags & ClangASTType::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;
+ 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 & ClangASTType::eTypeIsFloat)
+ {
+ if (type_flags & ClangASTType::eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ }
+ else
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size <= sizeof(long double))
+ {
+ const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ RegisterValue xmm0_value;
+ if (reg_ctx->ReadRegister (xmm0_info, xmm0_value))
+ {
+ DataExtractor data;
+ if (xmm0_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;
+ }
+ else if (byte_size == sizeof(long double))
+ {
+ // Don't handle long double since that can be encoded as 80 bit floats...
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+
+ }
+ else if (type_flags & ClangASTType::eTypeIsPointer)
+ {
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ value.SetValueType(Value::eValueTypeScalar);
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & ClangASTType::eTypeIsVector)
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size > 0)
+ {
+
+ const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("ymm0", 0);
+ if (altivec_reg == NULL)
+ {
+ altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 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_x86_64::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 *rax_info = reg_ctx_sp->GetRegisterInfoByName("rax", 0);
+ const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0);
+ const RegisterInfo *xmm0_info = reg_ctx_sp->GetRegisterInfoByName("xmm0", 0);
+ const RegisterInfo *xmm1_info = reg_ctx_sp->GetRegisterInfoByName("xmm1", 0);
+
+ RegisterValue rax_value, rdx_value, xmm0_value, xmm1_value;
+ reg_ctx_sp->ReadRegister (rax_info, rax_value);
+ reg_ctx_sp->ReadRegister (rdx_info, rdx_value);
+ reg_ctx_sp->ReadRegister (xmm0_info, xmm0_value);
+ reg_ctx_sp->ReadRegister (xmm1_info, xmm1_value);
+
+ DataExtractor rax_data, rdx_data, xmm0_data, xmm1_data;
+
+ rax_value.GetData(rax_data);
+ rdx_value.GetData(rdx_data);
+ xmm0_value.GetData(xmm0_data);
+ xmm1_value.GetData(xmm1_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 rax/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 = &rax_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)
+ {
+ // These have to be in a single xmm register.
+ if (fp_bytes == 0)
+ copy_from_extractor = &xmm0_data;
+ else
+ copy_from_extractor = &xmm1_data;
+
+ 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 = &rax_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
+ {
+ if (fp_bytes < 8)
+ copy_from_extractor = &xmm0_data;
+ else
+ copy_from_extractor = &xmm1_data;
+
+ 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, rax 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 rax_id = reg_ctx_sp->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, NULL),
+ return_clang_type);
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ sp_reg_num = gcc_dwarf_rsp;
+ pc_reg_num = gcc_dwarf_rip;
+ break;
+
+ case eRegisterKindGDB:
+ sp_reg_num = gdb_rsp;
+ pc_reg_num = gdb_rip;
+ break;
+
+ case eRegisterKindGeneric:
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetCFARegister (sp_reg_num);
+ row->SetCFAOffset (8);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("x86_64 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_x86_64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t fp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ fp_reg_num = gcc_dwarf_rbp;
+ sp_reg_num = gcc_dwarf_rsp;
+ pc_reg_num = gcc_dwarf_rip;
+ break;
+
+ case eRegisterKindGDB:
+ fp_reg_num = gdb_rbp;
+ sp_reg_num = gdb_rsp;
+ pc_reg_num = gdb_rip;
+ break;
+
+ case eRegisterKindGeneric:
+ fp_reg_num = LLDB_REGNUM_GENERIC_FP;
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (fp_reg_num == LLDB_INVALID_REGNUM ||
+ sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ const int32_t ptr_size = 8;
+ row->SetCFARegister (LLDB_REGNUM_GENERIC_FP);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("x86_64 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_x86_64::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+
+
+// See "Register Usage" in the
+// "System V Application Binary Interface"
+// "AMD64 Architecture Processor Supplement"
+// (or "x86-64(tm) Architecture Processor Supplement" in earlier revisions)
+// (this doc is also commonly referred to as the x86-64/AMD64 psABI)
+// Edited by Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
+// current version is 0.99.6 released 2012-07-02 at http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf
+
+bool
+ABISysV_x86_64::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // rbx, rsp, rbp, r12, r13, r14, r15
+ // mxcsr (partially preserved)
+ // x87 control word
+
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ switch (name[1])
+ {
+ case '1': // r12, r13, r14, r15
+ if (name[2] >= '2' && name[2] <= '5')
+ return name[3] == '\0';
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Accept shorter-variant versions, rbx/ebx, rip/ eip, etc.
+ if (name[0] == 'r' || name[0] == 'e')
+ {
+ switch (name[1])
+ {
+ case 'b': // rbp, rbx
+ if (name[2] == 'p' || name[2] == 'x')
+ return name[3] == '\0';
+ break;
+
+ case 'i': // rip
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+
+ case 's': // rsp
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+
+ }
+ }
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+ }
+ return false;
+}
+
+
+
+void
+ABISysV_x86_64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for x86_64 targets",
+ CreateInstance);
+}
+
+void
+ABISysV_x86_64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_x86_64::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-x86_64");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_x86_64::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_x86_64::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
new file mode 100644
index 000000000000..b10181960e89
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -0,0 +1,138 @@
+//===-- ABISysV_x86_64.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_x86_64_h_
+#define liblldb_ABISysV_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_x86_64 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_x86_64()
+ {
+ }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) 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;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 8 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // 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_x86_64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
new file mode 100644
index 000000000000..e920d70cd596
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -0,0 +1,864 @@
+//===-- DisassemblerLLVMC.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DisassemblerLLVMC.h"
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#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"
+
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/StackFrame.h"
+
+#include <regex.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+class InstructionLLVMC : public lldb_private::Instruction
+{
+public:
+ InstructionLLVMC (DisassemblerLLVMC &disasm,
+ const lldb_private::Address &address,
+ AddressClass addr_class) :
+ Instruction (address, addr_class),
+ m_disasm_sp (disasm.shared_from_this()),
+ m_does_branch (eLazyBoolCalculate),
+ m_is_valid (false),
+ m_using_file_addr (false)
+ {
+ }
+
+ virtual
+ ~InstructionLLVMC ()
+ {
+ }
+
+ virtual bool
+ DoesBranch ()
+ {
+ if (m_does_branch == eLazyBoolCalculate)
+ {
+ GetDisassemblerLLVMC().Lock(this, NULL);
+ DataExtractor data;
+ if (m_opcode.GetData(data))
+ {
+ bool is_alternate_isa;
+ lldb::addr_t pc = m_address.GetFileAddress();
+
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+ const uint8_t *opcode_data = data.GetDataStart();
+ const size_t opcode_data_len = data.GetByteSize();
+ llvm::MCInst inst;
+ const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+ // Be conservative, if we didn't understand the instruction, say it might branch...
+ if (inst_size == 0)
+ m_does_branch = eLazyBoolYes;
+ else
+ {
+ const bool can_branch = mc_disasm_ptr->CanBranch(inst);
+ if (can_branch)
+ m_does_branch = eLazyBoolYes;
+ else
+ m_does_branch = eLazyBoolNo;
+ }
+ }
+ GetDisassemblerLLVMC().Unlock();
+ }
+ return m_does_branch == eLazyBoolYes;
+ }
+
+ DisassemblerLLVMC::LLVMCDisassembler *
+ GetDisasmToUse (bool &is_alternate_isa)
+ {
+ is_alternate_isa = false;
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+ if (llvm_disasm.m_alternate_disasm_ap.get() != NULL)
+ {
+ const AddressClass address_class = GetAddressClass ();
+
+ if (address_class == eAddressClassCodeAlternateISA)
+ {
+ is_alternate_isa = true;
+ return llvm_disasm.m_alternate_disasm_ap.get();
+ }
+ }
+ return llvm_disasm.m_disasm_ap.get();
+ }
+
+ virtual size_t
+ Decode (const lldb_private::Disassembler &disassembler,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_offset)
+ {
+ // All we have to do is read the opcode which can be easy for some
+ // architectures
+ bool got_op = false;
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+ const ArchSpec &arch = llvm_disasm.GetArchitecture();
+
+ const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
+ const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
+ if (min_op_byte_size == max_op_byte_size)
+ {
+ // Fixed size instructions, just read that amount of data.
+ if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size))
+ return false;
+
+ switch (min_op_byte_size)
+ {
+ case 1:
+ m_opcode.SetOpcode8 (data.GetU8 (&data_offset));
+ got_op = true;
+ break;
+
+ case 2:
+ m_opcode.SetOpcode16 (data.GetU16 (&data_offset));
+ got_op = true;
+ break;
+
+ case 4:
+ m_opcode.SetOpcode32 (data.GetU32 (&data_offset));
+ got_op = true;
+ break;
+
+ case 8:
+ m_opcode.SetOpcode64 (data.GetU64 (&data_offset));
+ got_op = true;
+ break;
+
+ default:
+ m_opcode.SetOpcodeBytes(data.PeekData(data_offset, min_op_byte_size), min_op_byte_size);
+ got_op = true;
+ break;
+ }
+ }
+ if (!got_op)
+ {
+ bool is_alternate_isa = false;
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+
+ const llvm::Triple::ArchType machine = arch.GetMachine();
+ if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb)
+ {
+ if (machine == llvm::Triple::thumb || is_alternate_isa)
+ {
+ uint32_t thumb_opcode = data.GetU16(&data_offset);
+ if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
+ {
+ m_opcode.SetOpcode16 (thumb_opcode);
+ m_is_valid = true;
+ }
+ else
+ {
+ thumb_opcode <<= 16;
+ thumb_opcode |= data.GetU16(&data_offset);
+ m_opcode.SetOpcode16_2 (thumb_opcode);
+ m_is_valid = true;
+ }
+ }
+ else
+ {
+ m_opcode.SetOpcode32 (data.GetU32(&data_offset));
+ m_is_valid = true;
+ }
+ }
+ else
+ {
+ // The opcode isn't evenly sized, so we need to actually use the llvm
+ // disassembler to parse it and get the size.
+ uint8_t *opcode_data = const_cast<uint8_t *>(data.PeekData (data_offset, 1));
+ const size_t opcode_data_len = data.BytesLeft(data_offset);
+ const addr_t pc = m_address.GetFileAddress();
+ llvm::MCInst inst;
+
+ llvm_disasm.Lock(this, NULL);
+ const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+ llvm_disasm.Unlock();
+ if (inst_size == 0)
+ m_opcode.Clear();
+ else
+ {
+ m_opcode.SetOpcodeBytes(opcode_data, inst_size);
+ m_is_valid = true;
+ }
+ }
+ }
+ return m_opcode.GetByteSize();
+ }
+
+ void
+ AppendComment (std::string &description)
+ {
+ if (m_comment.empty())
+ m_comment.swap (description);
+ else
+ {
+ m_comment.append(", ");
+ m_comment.append(description);
+ }
+ }
+
+ virtual void
+ CalculateMnemonicOperandsAndComment (const lldb_private::ExecutionContext *exe_ctx)
+ {
+ DataExtractor data;
+ const AddressClass address_class = GetAddressClass ();
+
+ if (m_opcode.GetData(data))
+ {
+ char out_string[512];
+
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr;
+
+ if (address_class == eAddressClassCodeAlternateISA)
+ mc_disasm_ptr = llvm_disasm.m_alternate_disasm_ap.get();
+ else
+ mc_disasm_ptr = llvm_disasm.m_disasm_ap.get();
+
+ lldb::addr_t pc = m_address.GetFileAddress();
+ m_using_file_addr = true;
+
+ const bool data_from_file = GetDisassemblerLLVMC().m_data_from_file;
+ bool use_hex_immediates = true;
+ Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC;
+
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ use_hex_immediates = target->GetUseHexImmediates();
+ hex_style = target->GetHexImmediateStyle();
+
+ if (!data_from_file)
+ {
+ const lldb::addr_t load_addr = m_address.GetLoadAddress(target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ pc = load_addr;
+ m_using_file_addr = false;
+ }
+ }
+ }
+ }
+
+ llvm_disasm.Lock(this, exe_ctx);
+
+ const uint8_t *opcode_data = data.GetDataStart();
+ const size_t opcode_data_len = data.GetByteSize();
+ llvm::MCInst inst;
+ size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+
+ if (inst_size > 0)
+ {
+ mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
+ mc_disasm_ptr->PrintMCInst(inst, out_string, sizeof(out_string));
+ }
+
+ llvm_disasm.Unlock();
+
+ if (inst_size == 0)
+ {
+ m_comment.assign ("unknown opcode");
+ inst_size = m_opcode.GetByteSize();
+ StreamString mnemonic_strm;
+ lldb::offset_t offset = 0;
+ switch (inst_size)
+ {
+ case 1:
+ {
+ const uint8_t uval8 = data.GetU8 (&offset);
+ m_opcode.SetOpcode8 (uval8);
+ m_opcode_name.assign (".byte");
+ mnemonic_strm.Printf("0x%2.2x", uval8);
+ }
+ break;
+ case 2:
+ {
+ const uint16_t uval16 = data.GetU16(&offset);
+ m_opcode.SetOpcode16(uval16);
+ m_opcode_name.assign (".short");
+ mnemonic_strm.Printf("0x%4.4x", uval16);
+ }
+ break;
+ case 4:
+ {
+ const uint32_t uval32 = data.GetU32(&offset);
+ m_opcode.SetOpcode32(uval32);
+ m_opcode_name.assign (".long");
+ mnemonic_strm.Printf("0x%8.8x", uval32);
+ }
+ break;
+ case 8:
+ {
+ const uint64_t uval64 = data.GetU64(&offset);
+ m_opcode.SetOpcode64(uval64);
+ m_opcode_name.assign (".quad");
+ mnemonic_strm.Printf("0x%16.16" PRIx64, uval64);
+ }
+ break;
+ default:
+ if (inst_size == 0)
+ return;
+ else
+ {
+ const uint8_t *bytes = data.PeekData(offset, inst_size);
+ if (bytes == NULL)
+ return;
+ m_opcode_name.assign (".byte");
+ m_opcode.SetOpcodeBytes(bytes, inst_size);
+ mnemonic_strm.Printf("0x%2.2x", bytes[0]);
+ for (uint32_t i=1; i<inst_size; ++i)
+ mnemonic_strm.Printf(" 0x%2.2x", bytes[i]);
+ }
+ break;
+ }
+ m_mnemonics.swap(mnemonic_strm.GetString());
+ return;
+ }
+ else
+ {
+ if (m_does_branch == eLazyBoolCalculate)
+ {
+ const bool can_branch = mc_disasm_ptr->CanBranch(inst);
+ if (can_branch)
+ m_does_branch = eLazyBoolYes;
+ else
+ m_does_branch = eLazyBoolNo;
+
+ }
+ }
+
+ if (!s_regex_compiled)
+ {
+ ::regcomp(&s_regex, "[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?", REG_EXTENDED);
+ s_regex_compiled = true;
+ }
+
+ ::regmatch_t matches[3];
+
+ if (!::regexec(&s_regex, out_string, sizeof(matches) / sizeof(::regmatch_t), matches, 0))
+ {
+ if (matches[1].rm_so != -1)
+ m_opcode_name.assign(out_string + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
+ if (matches[2].rm_so != -1)
+ m_mnemonics.assign(out_string + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
+ }
+ }
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_is_valid;
+ }
+
+ bool
+ UsingFileAddress() const
+ {
+ return m_using_file_addr;
+ }
+ size_t
+ GetByteSize () const
+ {
+ return m_opcode.GetByteSize();
+ }
+
+ DisassemblerLLVMC &
+ GetDisassemblerLLVMC ()
+ {
+ return *(DisassemblerLLVMC *)m_disasm_sp.get();
+ }
+protected:
+
+ DisassemblerSP m_disasm_sp; // for ownership
+ LazyBool m_does_branch;
+ bool m_is_valid;
+ bool m_using_file_addr;
+
+ static bool s_regex_compiled;
+ static ::regex_t s_regex;
+};
+
+bool InstructionLLVMC::s_regex_compiled = false;
+::regex_t InstructionLLVMC::s_regex;
+
+DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner):
+ m_is_valid(true)
+{
+ std::string Error;
+ const llvm::Target *curr_target = llvm::TargetRegistry::lookupTarget(triple, Error);
+ if (!curr_target)
+ {
+ m_is_valid = false;
+ return;
+ }
+
+ m_instr_info_ap.reset(curr_target->createMCInstrInfo());
+ m_reg_info_ap.reset (curr_target->createMCRegInfo(triple));
+
+ std::string features_str;
+
+ m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "",
+ features_str));
+
+ m_asm_info_ap.reset(curr_target->createMCAsmInfo(*curr_target->createMCRegInfo(triple), triple));
+
+ if (m_instr_info_ap.get() == NULL || m_reg_info_ap.get() == NULL || m_subtarget_info_ap.get() == NULL || m_asm_info_ap.get() == NULL)
+ {
+ m_is_valid = false;
+ return;
+ }
+
+ m_context_ap.reset(new llvm::MCContext(m_asm_info_ap.get(), m_reg_info_ap.get(), 0));
+
+ m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get()));
+ if (m_disasm_ap.get() && m_context_ap.get())
+ {
+ llvm::OwningPtr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get()));
+ if (!RelInfo)
+ {
+ m_is_valid = false;
+ return;
+ }
+ m_disasm_ap->setupForSymbolicDisassembly(NULL,
+ DisassemblerLLVMC::SymbolLookupCallback,
+ (void *) &owner,
+ m_context_ap.get(),
+ RelInfo);
+
+ unsigned asm_printer_variant;
+ if (flavor == ~0U)
+ asm_printer_variant = m_asm_info_ap->getAssemblerDialect();
+ else
+ {
+ asm_printer_variant = flavor;
+ }
+
+ m_instr_printer_ap.reset(curr_target->createMCInstPrinter(asm_printer_variant,
+ *m_asm_info_ap.get(),
+ *m_instr_info_ap.get(),
+ *m_reg_info_ap.get(),
+ *m_subtarget_info_ap.get()));
+ if (m_instr_printer_ap.get() == NULL)
+ {
+ m_disasm_ap.reset();
+ m_is_valid = false;
+ }
+ }
+ else
+ m_is_valid = false;
+}
+
+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::MCDisassembler::DecodeStatus status;
+
+ uint64_t new_inst_size;
+ status = m_disasm_ap->getInstruction(mc_inst,
+ new_inst_size,
+ memory_object,
+ pc,
+ llvm::nulls(),
+ llvm::nulls());
+ if (status == llvm::MCDisassembler::Success)
+ return new_inst_size;
+ else
+ return 0;
+}
+
+uint64_t
+DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst,
+ char *dst,
+ size_t dst_len)
+{
+ llvm::StringRef unused_annotations;
+ llvm::SmallString<64> inst_string;
+ llvm::raw_svector_ostream inst_stream(inst_string);
+ m_instr_printer_ap->printInst (&mc_inst, inst_stream, unused_annotations);
+ inst_stream.flush();
+ const size_t output_size = std::min(dst_len - 1, inst_string.size());
+ std::memcpy(dst, inst_string.data(), output_size);
+ dst[output_size] = '\0';
+
+ return output_size;
+}
+
+void
+DisassemblerLLVMC::LLVMCDisassembler::SetStyle (bool use_hex_immed, HexImmediateStyle hex_style)
+{
+ m_instr_printer_ap->setPrintImmHex(use_hex_immed);
+ switch(hex_style)
+ {
+ case eHexStyleC: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::C); break;
+ case eHexStyleAsm: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::Asm); break;
+ }
+}
+
+bool
+DisassemblerLLVMC::LLVMCDisassembler::CanBranch (llvm::MCInst &mc_inst)
+{
+ return m_instr_info_ap->get(mc_inst.getOpcode()).mayAffectControlFlow(mc_inst, *m_reg_info_ap.get());
+}
+
+bool
+DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor)
+{
+ llvm::Triple triple = arch.GetTriple();
+ if (flavor == NULL || strcmp (flavor, "default") == 0)
+ return true;
+
+ if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64)
+ {
+ if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0)
+ return true;
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+
+Disassembler *
+DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor)
+{
+ if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch)
+ {
+ std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor));
+
+ if (disasm_ap.get() && disasm_ap->IsValid())
+ return disasm_ap.release();
+ }
+ return NULL;
+}
+
+DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) :
+ Disassembler(arch, flavor_string),
+ m_exe_ctx (NULL),
+ m_inst (NULL),
+ m_data_from_file (false)
+{
+ if (!FlavorValidForArchSpec (arch, m_flavor.c_str()))
+ {
+ m_flavor.assign("default");
+ }
+
+ const char *triple = arch.GetTriple().getTriple().c_str();
+ unsigned flavor = ~0U;
+
+ // So far the only supported flavor is "intel" on x86. The base class will set this
+ // correctly coming in.
+ if (arch.GetTriple().getArch() == llvm::Triple::x86
+ || arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ if (m_flavor == "intel")
+ {
+ flavor = 1;
+ }
+ else if (m_flavor == "att")
+ {
+ flavor = 0;
+ }
+ }
+
+ ArchSpec thumb_arch(arch);
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::string thumb_arch_name (thumb_arch.GetTriple().getArchName().str());
+ // Replace "arm" with "thumb" so we get all thumb variants correct
+ if (thumb_arch_name.size() > 3)
+ {
+ thumb_arch_name.erase(0,3);
+ thumb_arch_name.insert(0, "thumb");
+ }
+ else
+ {
+ thumb_arch_name = "thumbv7";
+ }
+ thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str()));
+ }
+
+ // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions,
+ // so hardcode the primary disassembler to thumb mode.
+ if (arch.GetTriple().getArch() == llvm::Triple::arm
+ && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em))
+ {
+ triple = thumb_arch.GetTriple().getTriple().c_str();
+ }
+
+ m_disasm_ap.reset (new LLVMCDisassembler(triple, flavor, *this));
+ if (!m_disasm_ap->IsValid())
+ {
+ // We use m_disasm_ap.get() to tell whether we are valid or not, so if this isn't good for some reason,
+ // we reset it, and then we won't be valid and FindPlugin will fail and we won't get used.
+ m_disasm_ap.reset();
+ }
+
+ // For arm CPUs that can execute arm or thumb instructions, also create a thumb instruction disassembler.
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::string thumb_triple(thumb_arch.GetTriple().getTriple());
+ m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), flavor, *this));
+ if (!m_alternate_disasm_ap->IsValid())
+ {
+ m_disasm_ap.reset();
+ m_alternate_disasm_ap.reset();
+ }
+ }
+}
+
+DisassemblerLLVMC::~DisassemblerLLVMC()
+{
+}
+
+size_t
+DisassemblerLLVMC::DecodeInstructions (const Address &base_addr,
+ const DataExtractor& data,
+ lldb::offset_t data_offset,
+ size_t num_instructions,
+ bool append,
+ bool data_from_file)
+{
+ if (!append)
+ m_instruction_list.Clear();
+
+ if (!IsValid())
+ return 0;
+
+ m_data_from_file = data_from_file;
+ uint32_t data_cursor = data_offset;
+ const size_t data_byte_size = data.GetByteSize();
+ uint32_t instructions_parsed = 0;
+ Address inst_addr(base_addr);
+
+ while (data_cursor < data_byte_size && instructions_parsed < num_instructions)
+ {
+
+ AddressClass address_class = eAddressClassCode;
+
+ if (m_alternate_disasm_ap.get() != NULL)
+ address_class = inst_addr.GetAddressClass ();
+
+ InstructionSP inst_sp(new InstructionLLVMC(*this,
+ inst_addr,
+ address_class));
+
+ if (!inst_sp)
+ break;
+
+ uint32_t inst_size = inst_sp->Decode(*this, data, data_cursor);
+
+ if (inst_size == 0)
+ break;
+
+ m_instruction_list.Append(inst_sp);
+ data_cursor += inst_size;
+ inst_addr.Slide(inst_size);
+ instructions_parsed++;
+ }
+
+ return data_cursor - data_offset;
+}
+
+void
+DisassemblerLLVMC::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Disassembler that uses LLVM MC to disassemble i386, x86_64 and ARM.",
+ CreateInstance);
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllDisassemblers();
+}
+
+void
+DisassemblerLLVMC::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+DisassemblerLLVMC::GetPluginNameStatic()
+{
+ static ConstString g_name("llvm-mc");
+ return g_name;
+}
+
+int DisassemblerLLVMC::OpInfoCallback (void *disassembler,
+ uint64_t pc,
+ uint64_t offset,
+ uint64_t size,
+ int tag_type,
+ void *tag_bug)
+{
+ return static_cast<DisassemblerLLVMC*>(disassembler)->OpInfo (pc,
+ offset,
+ size,
+ tag_type,
+ tag_bug);
+}
+
+const char *DisassemblerLLVMC::SymbolLookupCallback (void *disassembler,
+ uint64_t value,
+ uint64_t *type,
+ uint64_t pc,
+ const char **name)
+{
+ return static_cast<DisassemblerLLVMC*>(disassembler)->SymbolLookup(value,
+ type,
+ pc,
+ name);
+}
+
+int DisassemblerLLVMC::OpInfo (uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int tag_type,
+ void *tag_bug)
+{
+ switch (tag_type)
+ {
+ default:
+ break;
+ case 1:
+ bzero (tag_bug, sizeof(::LLVMOpInfo1));
+ break;
+ }
+ return 0;
+}
+
+const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
+ uint64_t *type_ptr,
+ uint64_t pc,
+ const char **name)
+{
+ if (*type_ptr)
+ {
+ if (m_exe_ctx && m_inst)
+ {
+ //std::string remove_this_prior_to_checkin;
+ Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : NULL;
+ Address value_so_addr;
+ if (m_inst->UsingFileAddress())
+ {
+ ModuleSP module_sp(m_inst->GetAddress().GetModule());
+ if (module_sp)
+ module_sp->ResolveFileAddress(value, value_so_addr);
+ }
+ else if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ target->GetSectionLoadList().ResolveLoadAddress(value, value_so_addr);
+ }
+
+ if (value_so_addr.IsValid() && value_so_addr.GetSection())
+ {
+ StreamString ss;
+
+ value_so_addr.Dump (&ss,
+ target,
+ Address::DumpStyleResolvedDescriptionNoModule,
+ Address::DumpStyleSectionNameOffset);
+
+ if (!ss.GetString().empty())
+ {
+ m_inst->AppendComment(ss.GetString());
+ }
+ }
+ }
+ }
+
+ *type_ptr = LLVMDisassembler_ReferenceType_InOut_None;
+ *name = NULL;
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+DisassemblerLLVMC::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DisassemblerLLVMC::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
new file mode 100644
index 000000000000..c567791866d5
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -0,0 +1,166 @@
+//===-- DisassemblerLLVMC.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_DisassemblerLLVMC_h_
+#define liblldb_DisassemblerLLVMC_h_
+
+#include <string>
+
+#include "llvm-c/Disassembler.h"
+
+// Opaque references to C++ Objects in LLVM's MC.
+namespace llvm
+{
+ class MCContext;
+ class MCInst;
+ class MCInstrInfo;
+ class MCRegisterInfo;
+ class MCDisassembler;
+ class MCInstPrinter;
+ class MCAsmInfo;
+ class MCSubtargetInfo;
+}
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Mutex.h"
+
+class InstructionLLVMC;
+
+class DisassemblerLLVMC : public lldb_private::Disassembler
+{
+ // Since we need to make two actual MC Disassemblers for ARM (ARM & THUMB), and there's a bit of goo to set up and own
+ // in the MC disassembler world, I added this class to manage the actual disassemblers.
+ class LLVMCDisassembler
+ {
+ public:
+ LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner);
+
+ ~LLVMCDisassembler();
+
+ uint64_t GetMCInst (const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst);
+ uint64_t PrintMCInst (llvm::MCInst &mc_inst, char *output_buffer, size_t out_buffer_len);
+ void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
+ bool CanBranch (llvm::MCInst &mc_inst);
+ bool IsValid()
+ {
+ return m_is_valid;
+ }
+
+ private:
+ bool m_is_valid;
+ std::unique_ptr<llvm::MCContext> m_context_ap;
+ std::unique_ptr<llvm::MCAsmInfo> m_asm_info_ap;
+ std::unique_ptr<llvm::MCSubtargetInfo> m_subtarget_info_ap;
+ std::unique_ptr<llvm::MCInstrInfo> m_instr_info_ap;
+ std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_ap;
+ std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_ap;
+ std::unique_ptr<llvm::MCDisassembler> m_disasm_ap;
+ };
+
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static lldb_private::Disassembler *
+ CreateInstance(const lldb_private::ArchSpec &arch, const char *flavor);
+
+ DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor /* = NULL */);
+
+ virtual
+ ~DisassemblerLLVMC();
+
+ virtual size_t
+ DecodeInstructions (const lldb_private::Address &base_addr,
+ const lldb_private::DataExtractor& data,
+ lldb::offset_t data_offset,
+ size_t num_instructions,
+ bool append,
+ bool data_from_file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ friend class InstructionLLVMC;
+
+ virtual bool
+ FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor);
+
+ bool
+ IsValid()
+ {
+ return (m_disasm_ap.get() != NULL && m_disasm_ap->IsValid());
+ }
+
+ int OpInfo(uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int TagType,
+ void *TagBug);
+
+ const char *SymbolLookup (uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName);
+
+ static int OpInfoCallback (void *DisInfo,
+ uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int TagType,
+ void *TagBug);
+
+ static const char *SymbolLookupCallback(void *DisInfo,
+ uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName);
+
+ void Lock(InstructionLLVMC *inst,
+ const lldb_private::ExecutionContext *exe_ctx)
+ {
+ m_mutex.Lock();
+ m_inst = inst;
+ m_exe_ctx = exe_ctx;
+ }
+
+ void Unlock()
+ {
+ m_inst = NULL;
+ m_exe_ctx = NULL;
+ m_mutex.Unlock();
+ }
+
+ const lldb_private::ExecutionContext *m_exe_ctx;
+ InstructionLLVMC *m_inst;
+ lldb_private::Mutex m_mutex;
+ bool m_data_from_file;
+
+ std::unique_ptr<LLVMCDisassembler> m_disasm_ap;
+ std::unique_ptr<LLVMCDisassembler> m_alternate_disasm_ap;
+};
+
+#endif // liblldb_DisassemblerLLVM_h_
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
new file mode 100644
index 000000000000..2604ae670164
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
@@ -0,0 +1,177 @@
+//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#endif
+
+#include "AuxVector.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+GetMaxU64(DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ uint64_t *value,
+ unsigned int byte_size)
+{
+ lldb::offset_t saved_offset = *offset_ptr;
+ *value = data.GetMaxU64(offset_ptr, byte_size);
+ return *offset_ptr != saved_offset;
+}
+
+static bool
+ParseAuxvEntry(DataExtractor &data,
+ AuxVector::Entry &entry,
+ lldb::offset_t *offset_ptr,
+ unsigned int byte_size)
+{
+ if (!GetMaxU64(data, offset_ptr, &entry.type, byte_size))
+ return false;
+
+ if (!GetMaxU64(data, offset_ptr, &entry.value, byte_size))
+ return false;
+
+ return true;
+}
+
+DataBufferSP
+AuxVector::GetAuxvData()
+{
+#if defined(__linux__) or defined(__FreeBSD__)
+ if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
+#endif
+ return lldb_private::Host::GetAuxvData(m_process);
+}
+
+void
+AuxVector::ParseAuxv(DataExtractor &data)
+{
+ const unsigned int byte_size = m_process->GetAddressByteSize();
+ lldb::offset_t offset = 0;
+
+ for (;;)
+ {
+ Entry entry;
+
+ if (!ParseAuxvEntry(data, entry, &offset, byte_size))
+ break;
+
+ if (entry.type == AT_NULL)
+ break;
+
+ if (entry.type == AT_IGNORE)
+ continue;
+
+ m_auxv.push_back(entry);
+ }
+}
+
+AuxVector::AuxVector(Process *process)
+ : m_process(process)
+{
+ DataExtractor data;
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ data.SetData(GetAuxvData());
+ data.SetByteOrder(m_process->GetByteOrder());
+ data.SetAddressByteSize(m_process->GetAddressByteSize());
+
+ ParseAuxv(data);
+
+ if (log)
+ DumpToLog(log);
+}
+
+AuxVector::iterator
+AuxVector::FindEntry(EntryType type) const
+{
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ if (I->type == static_cast<uint64_t>(type))
+ return I;
+ }
+
+ return end();
+}
+
+void
+AuxVector::DumpToLog(Log *log) const
+{
+ if (!log)
+ return;
+
+ log->PutCString("AuxVector: ");
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ log->Printf(" %s [%" PRIu64 "]: %" PRIx64, GetEntryName(*I), I->type, I->value);
+ }
+}
+
+const char *
+AuxVector::GetEntryName(EntryType type)
+{
+ const char *name = "AT_???";
+
+#define ENTRY_NAME(_type) _type: name = #_type
+ switch (type)
+ {
+ case ENTRY_NAME(AT_NULL); break;
+ case ENTRY_NAME(AT_IGNORE); break;
+ case ENTRY_NAME(AT_EXECFD); break;
+ case ENTRY_NAME(AT_PHDR); break;
+ case ENTRY_NAME(AT_PHENT); break;
+ case ENTRY_NAME(AT_PHNUM); break;
+ case ENTRY_NAME(AT_PAGESZ); break;
+ case ENTRY_NAME(AT_BASE); break;
+ case ENTRY_NAME(AT_FLAGS); break;
+ case ENTRY_NAME(AT_ENTRY); break;
+ case ENTRY_NAME(AT_NOTELF); break;
+ case ENTRY_NAME(AT_UID); break;
+ case ENTRY_NAME(AT_EUID); break;
+ case ENTRY_NAME(AT_GID); break;
+ case ENTRY_NAME(AT_EGID); break;
+ case ENTRY_NAME(AT_CLKTCK); break;
+ case ENTRY_NAME(AT_PLATFORM); break;
+ case ENTRY_NAME(AT_HWCAP); break;
+ case ENTRY_NAME(AT_FPUCW); break;
+ case ENTRY_NAME(AT_DCACHEBSIZE); break;
+ case ENTRY_NAME(AT_ICACHEBSIZE); break;
+ case ENTRY_NAME(AT_UCACHEBSIZE); break;
+ case ENTRY_NAME(AT_IGNOREPPC); break;
+ case ENTRY_NAME(AT_SECURE); break;
+ case ENTRY_NAME(AT_BASE_PLATFORM); break;
+ case ENTRY_NAME(AT_RANDOM); break;
+ case ENTRY_NAME(AT_EXECFN); break;
+ case ENTRY_NAME(AT_SYSINFO); break;
+ case ENTRY_NAME(AT_SYSINFO_EHDR); break;
+ case ENTRY_NAME(AT_L1I_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L1D_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L2_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L3_CACHESHAPE); break;
+ }
+#undef ENTRY_NAME
+
+ return name;
+}
+
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
new file mode 100644
index 000000000000..2d39eddcacc6
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
@@ -0,0 +1,115 @@
+//===-- AuxVector.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_AuxVector_H_
+#define liblldb_AuxVector_H_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/lldb-forward.h"
+
+namespace lldb_private {
+class DataExtractor;
+}
+
+/// @class AuxVector
+/// @brief Represents a processes auxiliary vector.
+///
+/// When a process is loaded on Linux a vector of values is placed onto the
+/// stack communicating operating system specific information. On construction
+/// this class locates and parses this information and provides a simple
+/// read-only interface to the entries found.
+class AuxVector {
+
+public:
+ AuxVector(lldb_private::Process *process);
+
+ struct Entry {
+ uint64_t type;
+ uint64_t value;
+
+ Entry() : type(0), value(0) { }
+ };
+
+ /// Constants describing the type of entry.
+ /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information.
+ enum EntryType {
+ AT_NULL = 0, ///< End of auxv.
+ AT_IGNORE = 1, ///< Ignore entry.
+ AT_EXECFD = 2, ///< File descriptor of program.
+ AT_PHDR = 3, ///< Program headers.
+ AT_PHENT = 4, ///< Size of program header.
+ AT_PHNUM = 5, ///< Number of program headers.
+ AT_PAGESZ = 6, ///< Page size.
+ AT_BASE = 7, ///< Interpreter base address.
+ AT_FLAGS = 8, ///< Flags.
+ AT_ENTRY = 9, ///< Program entry point.
+ AT_NOTELF = 10, ///< Set if program is not an ELF.
+ AT_UID = 11, ///< UID.
+ AT_EUID = 12, ///< Effective UID.
+ AT_GID = 13, ///< GID.
+ AT_EGID = 14, ///< Effective GID.
+ AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)).
+ AT_PLATFORM = 15, ///< String identifying platform.
+ AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities.
+ AT_FPUCW = 18, ///< Used FPU control word.
+ AT_DCACHEBSIZE = 19, ///< Data cache block size.
+ AT_ICACHEBSIZE = 20, ///< Instruction cache block size.
+ AT_UCACHEBSIZE = 21, ///< Unified cache block size.
+ AT_IGNOREPPC = 22, ///< Entry should be ignored.
+ AT_SECURE = 23, ///< Boolean, was exec setuid-like?
+ AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
+ AT_RANDOM = 25, ///< Address of 16 random bytes.
+ AT_EXECFN = 31, ///< Filename of executable.
+ AT_SYSINFO = 32, ///< Pointer to the global system page used for system calls and other nice things.
+ AT_SYSINFO_EHDR = 33,
+ AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches.
+ AT_L1D_CACHESHAPE = 35,
+ AT_L2_CACHESHAPE = 36,
+ AT_L3_CACHESHAPE = 37,
+ };
+
+private:
+ typedef std::vector<Entry> EntryVector;
+
+public:
+ typedef EntryVector::const_iterator iterator;
+
+ iterator begin() const { return m_auxv.begin(); }
+ iterator end() const { return m_auxv.end(); }
+
+ iterator
+ FindEntry(EntryType type) const;
+
+ static const char *
+ GetEntryName(const Entry &entry) {
+ return GetEntryName(static_cast<EntryType>(entry.type));
+ }
+
+ static const char *
+ GetEntryName(EntryType type);
+
+ void
+ DumpToLog(lldb_private::Log *log) const;
+
+private:
+ lldb_private::Process *m_process;
+ EntryVector m_auxv;
+
+ lldb::DataBufferSP
+ GetAuxvData();
+
+ void
+ ParseAuxv(lldb_private::DataExtractor &data);
+};
+
+#endif
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
new file mode 100644
index 000000000000..3e1b52938f49
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -0,0 +1,336 @@
+//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "DYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Locates the address of the rendezvous structure. Returns the address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+static addr_t
+ResolveRendezvousAddress(Process *process)
+{
+ addr_t info_location;
+ addr_t info_addr;
+ Error error;
+ size_t size;
+
+ info_location = process->GetImageInfoAddress();
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ info_addr = 0;
+ size = process->DoReadMemory(info_location, &info_addr,
+ process->GetAddressByteSize(), error);
+ if (size != process->GetAddressByteSize() || error.Fail())
+ return LLDB_INVALID_ADDRESS;
+
+ if (info_addr == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_addr;
+}
+
+DYLDRendezvous::DYLDRendezvous(Process *process)
+ : m_process(process),
+ m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_current(),
+ m_previous(),
+ m_soentries(),
+ m_added_soentries(),
+ m_removed_soentries()
+{
+ // Cache a copy of the executable path
+ if (m_process)
+ {
+ Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
+ if (exe_mod)
+ exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ }
+}
+
+bool
+DYLDRendezvous::Resolve()
+{
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr = ResolveRendezvousAddress(m_process);
+ else
+ cursor = info_addr = m_rendezvous_addr;
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.brk, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ return UpdateSOEntries();
+}
+
+bool
+DYLDRendezvous::IsValid()
+{
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntries()
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // When the previous and current states are consistent this is the first
+ // time we have been asked to update. Just take a snapshot of the currently
+ // loaded modules.
+ if (m_previous.state == eConsistent && m_current.state == eConsistent)
+ return TakeSnapshot(m_soentries);
+
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ if (m_current.state == eAdd || m_current.state == eDelete)
+ {
+ assert(m_previous.state == eConsistent);
+ m_soentries.clear();
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ }
+ assert(m_current.state == eConsistent);
+
+ // Otherwise check the previous state to determine what to expect and update
+ // accordingly.
+ if (m_previous.state == eAdd)
+ return UpdateSOEntriesForAddition();
+ else if (m_previous.state == eDelete)
+ return UpdateSOEntriesForDeletion();
+
+ return false;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForAddition()
+{
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
+ if (pos == m_soentries.end())
+ {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForDeletion()
+{
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ pos = std::find(entry_list.begin(), entry_list.end(), *I);
+ if (pos == entry_list.end())
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool
+DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t
+DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size)
+{
+ size_t bytes_read;
+ Error error;
+
+ bytes_read = m_process->DoReadMemory(addr, dst, size, error);
+ if (bytes_read != size || error.Fail())
+ return 0;
+
+ return addr + bytes_read;
+}
+
+std::string
+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++;
+ }
+ }
+
+ return str;
+}
+
+bool
+DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
+{
+ size_t address_size = m_process->GetAddressByteSize();
+
+ entry.clear();
+
+ if (!(addr = ReadMemory(addr, &entry.base_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.path_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.next, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.prev, address_size)))
+ return false;
+
+ entry.path = ReadStringFromMemory(entry.path_addr);
+
+ return true;
+}
+
+void
+DYLDRendezvous::DumpToLog(Log *log) const
+{
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("DYLDRendezvous:");
+ log->Printf(" Address: %" PRIx64, GetRendezvousAddress());
+ log->Printf(" Version: %" PRIu64, GetVersion());
+ log->Printf(" Link : %" PRIx64, GetLinkMapAddress());
+ log->Printf(" Break : %" PRIx64, GetBreakAddress());
+ log->Printf(" LDBase : %" PRIx64, GetLDBase());
+ log->Printf(" State : %s",
+ (state == eConsistent) ? "consistent" :
+ (state == eAdd) ? "add" :
+ (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("DYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i)
+ {
+ log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
+ log->Printf(" Base : %" PRIx64, I->base_addr);
+ log->Printf(" Path : %" PRIx64, I->path_addr);
+ log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
+ log->Printf(" Next : %" PRIx64, I->next);
+ log->Printf(" Prev : %" PRIx64, I->prev);
+ }
+}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
new file mode 100644
index 000000000000..67e7228a38de
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -0,0 +1,230 @@
+//===-- DYLDRendezvous.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_Rendezvous_H_
+#define liblldb_Rendezvous_H_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+class Process;
+}
+
+/// @class DYLDRendezvous
+/// @brief Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// runtime liker each time a module is loaded or unloaded. This class provides
+/// an interface to this structure and maintains a consistent snapshot of the
+/// currently loaded modules.
+class DYLDRendezvous {
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version;
+ lldb::addr_t map_addr;
+ lldb::addr_t brk;
+ uint64_t state;
+ lldb::addr_t ldbase;
+
+ Rendezvous()
+ : version(0), map_addr(0), brk(0), state(0), ldbase(0) { }
+ };
+
+public:
+ DYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// @returns true on success and false on failure.
+ ///
+ /// @see GetBreakAddress().
+ bool
+ Resolve();
+
+ /// @returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool
+ IsValid();
+
+ /// @returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t
+ GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// @returns the version of the rendezvous protocol being used.
+ uint64_t
+ GetVersion() const { return m_current.version; }
+
+ /// @returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t
+ GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// @returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// @see Resolve()
+ lldb::addr_t
+ GetBreakAddress() const { return m_current.brk; }
+
+ /// Returns the current state of the rendezvous structure.
+ uint64_t
+ GetState() const { return m_current.state; }
+
+ /// @returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t
+ GetLDBase() const { return m_current.ldbase; }
+
+ /// @returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// @returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void
+ DumpToLog(lldb_private::Log *log) const;
+
+ /// @brief Constants describing the state of the rendezvous.
+ ///
+ /// @see GetState().
+ enum RendezvousState {
+ eConsistent,
+ eAdd,
+ eDelete
+ };
+
+ /// @brief Structure representing the shared objects currently loaded into
+ /// the inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ std::string path; ///< File name of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator ==(const SOEntry &entry) {
+ return this->path == entry.path;
+ }
+
+ void clear() {
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ path.clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ // Cached copy of executable pathname
+ char m_exe_path[PATH_MAX];
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Reads @p size bytes from the inferiors address space starting at @p
+ /// addr.
+ ///
+ /// @returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t
+ ReadMemory(lldb::addr_t addr, void *dst, size_t size);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string
+ ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at @p addr.
+ bool
+ ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool
+ UpdateSOEntries();
+
+ bool
+ UpdateSOEntriesForAddition();
+
+ bool
+ UpdateSOEntriesForDeletion();
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool
+ TakeSnapshot(SOEntryList &entry_list);
+};
+
+#endif
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
new file mode 100644
index 000000000000..91c7cd3dfca7
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -0,0 +1,481 @@
+//===-- DynamicLoaderPOSIX.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+
+#include "AuxVector.h"
+#include "DynamicLoaderPOSIXDYLD.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+DynamicLoaderPOSIXDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderPOSIXDYLD::Terminate()
+{
+}
+
+lldb_private::ConstString
+DynamicLoaderPOSIXDYLD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+lldb_private::ConstString
+DynamicLoaderPOSIXDYLD::GetPluginNameStatic()
+{
+ static ConstString g_name("linux-dyld");
+ return g_name;
+}
+
+const char *
+DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in POSIX processes.";
+}
+
+void
+DynamicLoaderPOSIXDYLD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+uint32_t
+DynamicLoaderPOSIXDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+DynamicLoader *
+DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::Linux ||
+ triple_ref.getOS() == llvm::Triple::FreeBSD)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderPOSIXDYLD (process);
+ return NULL;
+}
+
+DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process)
+ : DynamicLoader(process),
+ m_rendezvous(process),
+ m_load_offset(LLDB_INVALID_ADDRESS),
+ m_entry_point(LLDB_INVALID_ADDRESS),
+ m_auxv(),
+ m_dyld_bid(LLDB_INVALID_BREAK_ID)
+{
+}
+
+DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD()
+{
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID)
+ {
+ m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid);
+ m_dyld_bid = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::DidAttach()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = GetTargetExecutable();
+ load_offset = ComputeLoadOffset();
+
+ if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ LoadAllCurrentModules();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::DidLaunch()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = GetTargetExecutable();
+ load_offset = ComputeLoadOffset();
+
+ if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ ProbeEntry();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+ModuleSP
+DynamicLoaderPOSIXDYLD::GetTargetExecutable()
+{
+ Target &target = m_process->GetTarget();
+ ModuleSP executable = target.GetExecutableModule();
+
+ if (executable.get())
+ {
+ if (executable->GetFileSpec().Exists())
+ {
+ ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture());
+ ModuleSP module_sp (new Module (module_spec));
+
+ // Check if the executable has changed and set it to the target executable if they differ.
+ if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid())
+ {
+ if (module_sp->GetUUID() != executable->GetUUID())
+ executable.reset();
+ }
+ else if (executable->FileHasChanged())
+ {
+ executable.reset();
+ }
+
+ if (!executable.get())
+ {
+ executable = target.GetSharedModule(module_spec);
+ if (executable.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded
+ const bool get_dependent_images = false;
+ target.SetExecutableModule(executable, get_dependent_images);
+ }
+ }
+ }
+ }
+ return executable;
+}
+
+Error
+DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error();
+}
+
+Log *
+DynamicLoaderPOSIXDYLD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+Error
+DynamicLoaderPOSIXDYLD::CanLoadImage()
+{
+ return Error();
+}
+
+void
+DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr)
+{
+ ObjectFile *obj_file = module->GetObjectFile();
+ SectionList *sections = obj_file->GetSectionList();
+ SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList();
+ const size_t num_sections = sections->GetSize();
+
+ for (unsigned i = 0; i < num_sections; ++i)
+ {
+ SectionSP section_sp (sections->GetSectionAtIndex(i));
+ lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr;
+ lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp);
+
+ // If the file address of the section is zero then this is not an
+ // allocatable/loadable section (property of ELF sh_addr). Skip it.
+ if (new_load_addr == base_addr)
+ continue;
+
+ if (old_load_addr == LLDB_INVALID_ADDRESS ||
+ old_load_addr != new_load_addr)
+ load_list.SetSectionLoadAddress(section_sp, new_load_addr);
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::ProbeEntry()
+{
+ Breakpoint *entry_break;
+ addr_t entry;
+
+ if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return;
+
+ entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get();
+ entry_break->SetCallback(EntryBreakpointHit, this, true);
+ entry_break->SetBreakpointKind("shared-library-event");
+}
+
+// The runtime linker has run and initialized the rendezvous structure once the
+// process has hit its entry point. When we hit the corresponding breakpoint we
+// interrogate the rendezvous structure to get the load addresses of all
+// dependent modules for the process. Similarly, we can discover the runtime
+// linker function and setup a breakpoint to notify us of any dynamically loaded
+// modules (via dlopen).
+bool
+DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderPOSIXDYLD* dyld_instance;
+
+ dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
+ dyld_instance->LoadAllCurrentModules();
+ dyld_instance->SetRendezvousBreakpoint();
+ return false; // Continue running.
+}
+
+void
+DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint()
+{
+ addr_t break_addr = m_rendezvous.GetBreakAddress();
+ Target &target = m_process->GetTarget();
+
+ if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true).get();
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind ("shared-library-event");
+ m_dyld_bid = dyld_break->GetID();
+ }
+
+ // Make sure our breakpoint is at the right address.
+ assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid);
+}
+
+bool
+DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderPOSIXDYLD* dyld_instance;
+
+ 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();
+}
+
+void
+DynamicLoaderPOSIXDYLD::RefreshModules()
+{
+ if (!m_rendezvous.Resolve())
+ return;
+
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad())
+ {
+ ModuleList new_modules;
+
+ E = m_rendezvous.loaded_end();
+ for (I = m_rendezvous.loaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (module_sp.get())
+ loaded_modules.AppendIfNeeded(module_sp);
+ }
+ }
+
+ if (m_rendezvous.ModulesDidUnload())
+ {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSpec module_spec (file);
+ ModuleSP module_sp =
+ loaded_modules.FindFirstModule (module_spec);
+ if (module_sp.get())
+ old_modules.Append(module_sp);
+ }
+ loaded_modules.Remove(old_modules);
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
+{
+ ThreadPlanSP thread_plan_sp;
+
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *sym = context.symbol;
+
+ if (sym == NULL || !sym->IsTrampoline())
+ return thread_plan_sp;
+
+ const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
+ if (!sym_name)
+ return thread_plan_sp;
+
+ SymbolContextList target_symbols;
+ Target &target = thread.GetProcess()->GetTarget();
+ const ModuleList &images = target.GetImages();
+
+ images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
+ size_t num_targets = target_symbols.GetSize();
+ if (!num_targets)
+ return thread_plan_sp;
+
+ typedef std::vector<lldb::addr_t> AddressVector;
+ AddressVector addrs;
+ for (size_t i = 0; i < num_targets; ++i)
+ {
+ SymbolContext context;
+ AddressRange range;
+ if (target_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange(eSymbolContextEverything, 0, false, range);
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addrs.push_back(addr);
+ }
+ }
+
+ if (addrs.size() > 0)
+ {
+ AddressVector::iterator start = addrs.begin();
+ AddressVector::iterator end = addrs.end();
+
+ std::sort(start, end);
+ addrs.erase(std::unique(start, end), end);
+ thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
+ }
+
+ return thread_plan_sp;
+}
+
+void
+DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
+{
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+ ModuleList module_list;
+
+ if (!m_rendezvous.Resolve())
+ return;
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), false);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (module_sp.get())
+ module_list.Append(module_sp);
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+ModuleSP
+DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ ModuleSpec module_spec (file, target.GetArchitecture());
+ if ((module_sp = modules.FindFirstModule (module_spec)))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ }
+ else if ((module_sp = target.GetSharedModule(module_spec)))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ }
+
+ return module_sp;
+}
+
+addr_t
+DynamicLoaderPOSIXDYLD::ComputeLoadOffset()
+{
+ addr_t virt_entry;
+
+ if (m_load_offset != LLDB_INVALID_ADDRESS)
+ return m_load_offset;
+
+ if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ ModuleSP module = m_process->GetTarget().GetExecutableModule();
+ if (!module)
+ return LLDB_INVALID_ADDRESS;
+
+ ObjectFile *exe = module->GetObjectFile();
+ Address file_entry = exe->GetEntryPointAddress();
+
+ if (!file_entry.IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ m_load_offset = virt_entry - file_entry.GetFileAddress();
+ return m_load_offset;
+}
+
+addr_t
+DynamicLoaderPOSIXDYLD::GetEntryPoint()
+{
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+
+ if (m_auxv.get() == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
+
+ if (I == m_auxv->end())
+ return LLDB_INVALID_ADDRESS;
+
+ m_entry_point = static_cast<addr_t>(I->value);
+ return m_entry_point;
+}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
new file mode 100644
index 000000000000..0476e45d0465
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -0,0 +1,170 @@
+//===-- DynamicLoaderPOSIX.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_DynamicLoaderPOSIX_H_
+#define liblldb_DynamicLoaderPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "DYLDRendezvous.h"
+
+class AuxVector;
+
+class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ DynamicLoaderPOSIXDYLD(lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderPOSIXDYLD();
+
+ //------------------------------------------------------------------
+ // DynamicLoader protocol
+ //------------------------------------------------------------------
+
+ virtual void
+ DidAttach();
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ /// Runtime linker rendezvous structure.
+ DYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Auxiliary vector of the inferior process.
+ std::unique_ptr<AuxVector> m_auxv;
+
+ /// Rendezvous breakpoint.
+ lldb::break_id_t m_dyld_bid;
+
+ /// Enables a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ void
+ SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool
+ RendezvousBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void
+ RefreshModules();
+
+ /// Updates the load address of every allocatable section in @p module.
+ ///
+ /// @param module The module to traverse.
+ ///
+ /// @param base_addr The virtual base address @p module is loaded at.
+ void
+ UpdateLoadedSections(lldb::ModuleSP module,
+ lldb::addr_t base_addr = 0);
+
+ /// Locates or creates a module given by @p file and updates/loads the
+ /// resulting module at the virtual base address @p base_addr.
+ lldb::ModuleSP
+ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr);
+
+ /// Resolves the entry point for the current inferior process and sets a
+ /// breakpoint at that address.
+ void
+ ProbeEntry();
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ void
+ LoadAllCurrentModules();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ GetEntryPoint();
+
+ /// Checks to see if the target module has changed, updates the target
+ /// accordingly and returns the target executable module.
+ lldb::ModuleSP
+ GetTargetExecutable();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD);
+};
+
+#endif // liblldb_DynamicLoaderPOSIXDYLD_H_
diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
new file mode 100644
index 000000000000..274ba328ad1f
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
@@ -0,0 +1,209 @@
+//===-- DynamicLoaderStatic.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/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+#include "DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+DynamicLoader *
+DynamicLoaderStatic::CreateInstance (Process* process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ const llvm::Triple::OSType os_type = triple_ref.getOS();
+ if ((os_type == llvm::Triple::UnknownOS))
+ create = true;
+ }
+
+ if (!create)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ create = (object_file->GetStrata() == ObjectFile::eStrataRawImage);
+ }
+ }
+ }
+
+ if (create)
+ return new DynamicLoaderStatic (process);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderStatic::DynamicLoaderStatic (Process* process) :
+ DynamicLoader(process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderStatic::~DynamicLoaderStatic()
+{
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderStatic::DidAttach ()
+{
+ LoadAllImagesAtFileAddresses();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderStatic::DidLaunch ()
+{
+ LoadAllImagesAtFileAddresses();
+}
+
+void
+DynamicLoaderStatic::LoadAllImagesAtFileAddresses ()
+{
+ const ModuleList &module_list = m_process->GetTarget().GetImages();
+
+ ModuleList loaded_module_list;
+
+ // Disable JIT for static dynamic loader targets
+ m_process->SetCanJIT(false);
+
+ Mutex::Locker mutex_locker(module_list.GetMutex());
+
+ const size_t num_modules = module_list.GetSize();
+ for (uint32_t idx = 0; idx < num_modules; ++idx)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (idx));
+ if (module_sp)
+ {
+ bool changed = false;
+ ObjectFile *image_object_file = module_sp->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ if (section_sp)
+ {
+ if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress()))
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed)
+ loaded_module_list.AppendIfNeeded (module_sp);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+}
+
+ThreadPlanSP
+DynamicLoaderStatic::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ return ThreadPlanSP();
+}
+
+Error
+DynamicLoaderStatic::CanLoadImage ()
+{
+ Error error;
+ error.SetErrorString ("can't load images on with a static debug session");
+ return error;
+}
+
+void
+DynamicLoaderStatic::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderStatic::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+DynamicLoaderStatic::GetPluginNameStatic()
+{
+ static ConstString g_name("static");
+ return g_name;
+}
+
+const char *
+DynamicLoaderStatic::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that will load any images at the static addresses contained in each image.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+DynamicLoaderStatic::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderStatic::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
new file mode 100644
index 000000000000..a99435fa32ad
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
@@ -0,0 +1,88 @@
+//===-- DynamicLoaderStatic.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_DynamicLoaderStatic_h_
+#define liblldb_DynamicLoaderStatic_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+#include "llvm/Support/MachO.h"
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+class DynamicLoaderStatic : public lldb_private::DynamicLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ DynamicLoaderStatic (lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderStatic ();
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ void
+ LoadAllImagesAtFileAddresses ();
+
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderStatic);
+};
+
+#endif // liblldb_DynamicLoaderStatic_h_
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
new file mode 100644
index 000000000000..2dd04dd8733d
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -0,0 +1,13625 @@
+//===-- EmulateInstructionARM.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 "EmulateInstructionARM.h"
+#include "EmulationStateARM.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/ARMUtils.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
+ // and countTrailingZeros function
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Convenient macro definitions.
+#define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS)
+#define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS)
+
+#define AlignPC(pc_val) (pc_val & 0xFFFFFFFC)
+
+//----------------------------------------------------------------------
+//
+// ITSession implementation
+//
+//----------------------------------------------------------------------
+
+// A8.6.50
+// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
+static uint32_t
+CountITSize (uint32_t ITMask) {
+ // First count the trailing zeros of the IT mask.
+ uint32_t TZ = llvm::countTrailingZeros(ITMask);
+ if (TZ > 3)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT Mask '0000'\n");
+#endif
+ return 0;
+ }
+ return (4 - TZ);
+}
+
+// Init ITState. Note that at least one bit is always 1 in mask.
+bool ITSession::InitIT(uint32_t bits7_0)
+{
+ ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
+ if (ITCounter == 0)
+ return false;
+
+ // A8.6.50 IT
+ unsigned short FirstCond = Bits32(bits7_0, 7, 4);
+ if (FirstCond == 0xF)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT FirstCond '1111'\n");
+#endif
+ return false;
+ }
+ if (FirstCond == 0xE && ITCounter != 1)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n");
+#endif
+ return false;
+ }
+
+ ITState = bits7_0;
+ return true;
+}
+
+// Update ITState if necessary.
+void ITSession::ITAdvance()
+{
+ //assert(ITCounter);
+ --ITCounter;
+ if (ITCounter == 0)
+ ITState = 0;
+ else
+ {
+ unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
+ SetBits32(ITState, 4, 0, NewITState4_0);
+ }
+}
+
+// Return true if we're inside an IT Block.
+bool ITSession::InITBlock()
+{
+ return ITCounter != 0;
+}
+
+// Return true if we're the last instruction inside an IT Block.
+bool ITSession::LastInITBlock()
+{
+ return ITCounter == 1;
+}
+
+// Get condition bits for the current thumb instruction.
+uint32_t ITSession::GetCond()
+{
+ if (InITBlock())
+ return Bits32(ITState, 7, 4);
+ else
+ return COND_AL;
+}
+
+// ARM constants used during decoding
+#define REG_RD 0
+#define LDM_REGLIST 1
+#define SP_REG 13
+#define LR_REG 14
+#define PC_REG 15
+#define PC_REGLIST_BIT 0x8000
+
+#define ARMv4 (1u << 0)
+#define ARMv4T (1u << 1)
+#define ARMv5T (1u << 2)
+#define ARMv5TE (1u << 3)
+#define ARMv5TEJ (1u << 4)
+#define ARMv6 (1u << 5)
+#define ARMv6K (1u << 6)
+#define ARMv6T2 (1u << 7)
+#define ARMv7 (1u << 8)
+#define ARMv7S (1u << 9)
+#define ARMv8 (1u << 10)
+#define ARMvAll (0xffffffffu)
+
+#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5TE_ABOVE (ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5J_ABOVE (ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV6_ABOVE (ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV7_ABOVE (ARMv7|ARMv7S|ARMv8)
+
+#define No_VFP 0
+#define VFPv1 (1u << 1)
+#define VFPv2 (1u << 2)
+#define VFPv3 (1u << 3)
+#define AdvancedSIMD (1u << 4)
+
+#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2v3 (VFPv2 | VFPv3)
+
+//----------------------------------------------------------------------
+//
+// EmulateInstructionARM implementation
+//
+//----------------------------------------------------------------------
+
+void
+EmulateInstructionARM::Initialize ()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic (),
+ GetPluginDescriptionStatic (),
+ CreateInstance);
+}
+
+void
+EmulateInstructionARM::Terminate ()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+ConstString
+EmulateInstructionARM::GetPluginNameStatic ()
+{
+ static ConstString g_name("arm");
+ return g_name;
+}
+
+const char *
+EmulateInstructionARM::GetPluginDescriptionStatic ()
+{
+ return "Emulate instructions for the ARM architecture.";
+}
+
+EmulateInstruction *
+EmulateInstructionARM::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
+{
+ if (EmulateInstructionARM::SupportsEmulatingIntructionsOfTypeStatic(inst_type))
+ {
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::unique_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch));
+
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ std::unique_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch));
+
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionARM::SetTargetTriple (const ArchSpec &arch)
+{
+ if (arch.GetTriple().getArch () == llvm::Triple::arm)
+ return true;
+ else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
+ return true;
+
+ return false;
+}
+
+// Write "bits (32) UNKNOWN" to memory address "address". Helper function for many ARM instructions.
+bool
+EmulateInstructionARM::WriteBits32UnknownToMemory (addr_t address)
+{
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextWriteMemoryRandomBits;
+ context.SetNoArgs ();
+
+ uint32_t random_data = rand ();
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, random_data, addr_byte_size))
+ return false;
+
+ return true;
+}
+
+// Write "bits (32) UNKNOWN" to register n. Helper function for many ARM instructions.
+bool
+EmulateInstructionARM::WriteBits32Unknown (int n)
+{
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextWriteRegisterRandomBits;
+ context.SetNoArgs ();
+
+ bool success;
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
+{
+ if (reg_kind == eRegisterKindGeneric)
+ {
+ switch (reg_num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc; break;
+ case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp; break;
+ case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_r7; break;
+ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = dwarf_lr; break;
+ case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_cpsr; break;
+ default: return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ return GetARMDWARFRegisterInfo(reg_num, reg_info);
+ return false;
+}
+
+uint32_t
+EmulateInstructionARM::GetFramePointerRegisterNumber () const
+{
+ if (m_opcode_mode == eModeThumb)
+ {
+ switch (m_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ return 7;
+ default:
+ break;
+ }
+ }
+ return 11;
+}
+
+uint32_t
+EmulateInstructionARM::GetFramePointerDWARFRegisterNumber () const
+{
+ if (m_opcode_mode == eModeThumb)
+ {
+ switch (m_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ return dwarf_r7;
+ default:
+ break;
+ }
+ }
+ return dwarf_r11;
+}
+
+// Push Multiple Registers stores multiple registers to the stack, storing to
+// consecutive memory locations ending just below the address in SP, and updates
+// SP to point to the start of the stored data.
+bool
+EmulateInstructionARM::EmulatePUSH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ NullCheckIfThumbEE(13);
+ address = SP - 4*BitCount(registers);
+
+ for (i = 0 to 14)
+ {
+ if (registers<i> == '1')
+ {
+ if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+ }
+ }
+
+ if (registers<15> == '1') // Only possible for encoding A1 or A2
+ MemA[address,4] = PCStoreValue();
+
+ SP = SP - 4*BitCount(registers);
+ }
+#endif
+
+ bool conditional = false;
+ bool success = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t registers = 0;
+ uint32_t Rt; // the source register
+ switch (encoding) {
+ case eEncodingT1:
+ registers = Bits32(opcode, 7, 0);
+ // The M bit represents LR.
+ if (Bit32(opcode, 8))
+ registers |= (1u << 14);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // Ignore bits 15 & 13.
+ registers = Bits32(opcode, 15, 0) & ~0xa000;
+ // if BitCount(registers) < 2 then UNPREDICTABLE;
+ if (BitCount(registers) < 2)
+ return false;
+ break;
+ case eEncodingT3:
+ Rt = Bits32(opcode, 15, 12);
+ // if BadReg(t) then UNPREDICTABLE;
+ if (BadReg(Rt))
+ return false;
+ registers = (1u << Rt);
+ break;
+ case eEncodingA1:
+ registers = Bits32(opcode, 15, 0);
+ // Instead of return false, let's handle the following case as well,
+ // which amounts to pushing one reg onto the full descending stacks.
+ // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
+ break;
+ case eEncodingA2:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 then UNPREDICTABLE;
+ if (Rt == dwarf_sp)
+ return false;
+ registers = (1u << Rt);
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = addr_byte_size * BitCount (registers);
+ addr_t addr = sp - sp_offset;
+ uint32_t i;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo reg_info;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<15; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, reg_info);
+ context.SetRegisterToRegisterPlusOffset (reg_info, sp_reg, addr - sp);
+ uint32_t reg_value = ReadCoreReg(i, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, reg_value, addr_byte_size))
+ return false;
+ addr += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, reg_info);
+ context.SetRegisterToRegisterPlusOffset (reg_info, sp_reg, addr - sp);
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, pc, addr_byte_size))
+ return false;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Pop Multiple Registers loads multiple registers from the stack, loading from
+// consecutive memory locations staring at the address in SP, and updates
+// SP to point just above the loaded data.
+bool
+EmulateInstructionARM::EmulatePOP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(13);
+ address = SP;
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ if UnalignedAllowed then
+ LoadWritePC(MemU[address,4]);
+ else
+ LoadWritePC(MemA[address,4]);
+ if registers<13> == '0' then SP = SP + 4*BitCount(registers);
+ if registers<13> == '1' then SP = bits(32) UNKNOWN;
+ }
+#endif
+
+ bool success = false;
+
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t registers = 0;
+ uint32_t Rt; // the destination register
+ switch (encoding) {
+ case eEncodingT1:
+ registers = Bits32(opcode, 7, 0);
+ // The P bit represents PC.
+ if (Bit32(opcode, 8))
+ registers |= (1u << 15);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // Ignore bit 13.
+ registers = Bits32(opcode, 15, 0) & ~0x2000;
+ // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
+ return false;
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingT3:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
+ if (Rt == 13)
+ return false;
+ if (Rt == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ registers = (1u << Rt);
+ break;
+ case eEncodingA1:
+ registers = Bits32(opcode, 15, 0);
+ // Instead of return false, let's handle the following case as well,
+ // which amounts to popping one reg from the full descending stacks.
+ // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
+
+ // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE;
+ if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7)
+ return false;
+ break;
+ case eEncodingA2:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 then UNPREDICTABLE;
+ if (Rt == dwarf_sp)
+ return false;
+ registers = (1u << Rt);
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = addr_byte_size * BitCount (registers);
+ addr_t addr = sp;
+ uint32_t i, data;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+
+ for (i=0; i<15; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, 4, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+ addr += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, 4, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ //addr += addr_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 or ip to point to saved value residing within the stack.
+// ADD (SP plus immediate)
+bool
+EmulateInstructionARM::EmulateADDRdSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rd; // the destination register
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 7;
+ imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp + sp_offset; // a pointer to the stack area
+
+ EmulateInstruction::Context context;
+ context.type = eContextSetFramePointer;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 or ip to the current stack pointer.
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVRdSP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = R[m];
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ // APSR.C unchanged
+ // APSR.V unchanged
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rd; // the destination register
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 7;
+ break;
+ case eEncodingA1:
+ Rd = 12;
+ break;
+ default:
+ return false;
+ }
+
+ EmulateInstruction::Context context;
+ if (Rd == GetFramePointerRegisterNumber())
+ context.type = EmulateInstruction::eContextSetFramePointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, 0);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
+ return false;
+ }
+ return true;
+}
+
+// Move from high register (r8-r15) to low register (r0-r7).
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVLowHigh (const uint32_t opcode, const ARMEncoding encoding)
+{
+ return EmulateMOVRdRm (opcode, encoding);
+}
+
+// Move from register to register.
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = R[m];
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ // APSR.C unchanged
+ // APSR.V unchanged
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rm; // the source register
+ uint32_t Rd; // the destination register
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ setflags = false;
+ if (Rd == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = true;
+ if (InITBlock())
+ return false;
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (setflags && (BadReg(Rd) || BadReg(Rm)))
+ return false;
+ // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then UNPREDICTABLE;
+ if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13)))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ uint32_t result = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that Rm is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags))
+ return false;
+ }
+ return true;
+}
+
+// Move (immediate) writes an immediate value to the destination register. It
+// can optionally update the condition flags based on the value.
+// MOV (immediate)
+bool
+EmulateInstructionARM::EmulateMOVRdImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t imm32; // the immediate value to be written to Rd
+ uint32_t carry = 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C.
+ // for setflags == false, this value is a don't care
+ // initialized to 0 to silence the static analyzer
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
+ carry = APSR_C;
+
+ break;
+
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
+ if (BadReg(Rd))
+ return false;
+
+ break;
+
+ case eEncodingT3:
+ {
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8, 32);
+ Rd = Bits32 (opcode, 11, 8);
+ setflags = false;
+ uint32_t imm4 = Bits32 (opcode, 19, 16);
+ uint32_t imm3 = Bits32 (opcode, 14, 12);
+ uint32_t i = Bit32 (opcode, 26);
+ uint32_t imm8 = Bits32 (opcode, 7, 0);
+ imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+
+ // if BadReg(d) then UNPREDICTABLE;
+ if (BadReg (Rd))
+ return false;
+ }
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); setflags = (S == Ô1Õ); (imm32, carry) = ARMExpandImm_C(imm12, APSR.C);
+ Rd = Bits32 (opcode, 15, 12);
+ setflags = BitIsSet (opcode, 20);
+ imm32 = ARMExpandImm_C (opcode, APSR_C, carry);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if ((Rd == 15) && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+
+ break;
+
+ case eEncodingA2:
+ {
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32);
+ Rd = Bits32 (opcode, 15, 12);
+ setflags = false;
+ uint32_t imm4 = Bits32 (opcode, 19, 16);
+ uint32_t imm12 = Bits32 (opcode, 11, 0);
+ imm32 = (imm4 << 12) | imm12;
+
+ // if d == 15 then UNPREDICTABLE;
+ if (Rd == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+ uint32_t result = imm32;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// MUL multiplies two register values. The least significant 32 bits of the result are written to the destination
+// register. These 32 bits do not depend on whether the source register values are considered to be signed values or
+// unsigned values.
+//
+// Optionally, it can update the condition flags based on the result. In the Thumb instruction set, this option is
+// limited to only a few forms of the instruction.
+bool
+EmulateInstructionARM::EmulateMUL (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results
+ operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results
+ result = operand1 * operand2;
+ R[d] = result<31:0>;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ if ArchVersion() == 4 then
+ APSR.C = bit UNKNOWN;
+ // else APSR.C unchanged
+ // APSR.V always unchanged
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool setflags;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock();
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 2, 0);
+ setflags = !InITBlock();
+
+ // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
+ if ((ArchVersion() < ARMv6) && (d == n))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE;
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = false;
+
+ // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (n) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1');
+ d = Bits32 (opcode, 19, 16);
+ n = Bits32 (opcode, 3, 0);
+ m = Bits32 (opcode, 11, 8);
+ setflags = BitIsSet (opcode, 20);
+
+ // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (n == 15) || (m == 15))
+ return false;
+
+ // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
+ if ((ArchVersion() < ARMv6) && (d == n))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ bool success = false;
+
+ // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results
+ uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results
+ uint64_t operand2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // result = operand1 * operand2;
+ uint64_t result = operand1 * operand2;
+
+ // R[d] = result<31:0>;
+ RegisterInfo op1_reg;
+ RegisterInfo op2_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, op1_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, op2_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ context.SetRegisterRegisterOperands (op1_reg, op2_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (0x0000ffff & result)))
+ return false;
+
+ // if setflags then
+ if (setflags)
+ {
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ m_new_inst_cpsr = m_opcode_cpsr;
+ SetBit32 (m_new_inst_cpsr, CPSR_N_POS, Bit32 (result, 31));
+ SetBit32 (m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
+ if (m_new_inst_cpsr != m_opcode_cpsr)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+
+ // if ArchVersion() == 4 then
+ // APSR.C = bit UNKNOWN;
+ }
+ }
+ return true;
+}
+
+// Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to the destination register.
+// It can optionally update the condition flags based on the value.
+bool
+EmulateInstructionARM::EmulateMVNImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = NOT(imm32);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C
+ uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ uint32_t result = ~imm32;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise NOT (register) writes the bitwise inverse of a register value to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateMVNReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = NOT(shifted);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rm; // the source register
+ uint32_t Rd; // the destination register
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry; // the carry bit after the shift operation
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (InITBlock())
+ return false;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (BadReg(Rd) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ uint32_t value = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(value, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = ~shifted;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// PC relative immediate load into register, possibly followed by ADD (SP plus register).
+// LDR (literal)
+bool
+EmulateInstructionARM::EmulateLDRRtPCRelative (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,4];
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ if CurrentInstrSet() == InstrSet_ARM then
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+ else
+ R[t] = bits(32) UNKNOWN;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ // PC relative immediate load context
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 0);
+
+ uint32_t Rt; // the destination register
+ uint32_t imm32; // immediate offset from the PC
+ bool add; // +imm32 or -imm32?
+ addr_t base; // the base address
+ addr_t address; // the PC relative address
+ uint32_t data; // the literal data value from the PC relative load
+ switch (encoding) {
+ case eEncodingT1:
+ Rt = Bits32(opcode, 10, 8);
+ imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
+ add = true;
+ break;
+ case eEncodingT2:
+ Rt = Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32);
+ add = BitIsSet(opcode, 23);
+ if (Rt == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ base = Align(pc, 4);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ context.SetRegisterPlusOffset(pc_reg, address - base);
+ data = MemURead(context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ if (Rt == 15)
+ {
+ if (Bits32(address, 1, 0) == 0)
+ {
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+ else
+ return false;
+ }
+ else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
+ return false;
+ }
+ else // We don't handle ARM for now.
+ return false;
+
+ }
+ return true;
+}
+
+// An add operation to adjust the SP.
+// ADD (SP plus immediate)
+bool
+EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t imm32; // the immediate operand
+ uint32_t d;
+ //bool setflags = false; // Add this back if/when support eEncodingT3 eEncodingA1
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32);
+ d = Bits32 (opcode, 10, 8);
+ imm32 = (Bits32 (opcode, 7, 0) << 2);
+
+ break;
+
+ case eEncodingT2:
+ // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
+ d = 13;
+ imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
+
+ break;
+
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp + sp_offset; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, sp_offset);
+
+ if (d == 15)
+ {
+ if (!ALUWritePC (context, addr))
+ return false;
+ }
+ else
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr))
+ return false;
+
+ // Add this back if/when support eEncodingT3 eEncodingA1
+ //if (setflags)
+ //{
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+ //}
+ }
+ }
+ return true;
+}
+
+// An add operation to adjust the SP.
+// ADD (SP plus register)
+bool
+EmulateInstructionARM::EmulateADDSPRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(SP, shifted, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rm; // the second operand
+ switch (encoding) {
+ case eEncodingT2:
+ Rm = Bits32(opcode, 6, 3);
+ break;
+ default:
+ return false;
+ }
+ int32_t reg_value = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+
+ RegisterInfo other_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, other_reg);
+ context.SetRegisterRegisterOperands (sp_reg, other_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
+ return false;
+ }
+ return true;
+}
+
+// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
+// at a PC-relative address, and changes instruction set from ARM to Thumb, or
+// from Thumb to ARM.
+// BLX (immediate)
+bool
+EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ if CurrentInstrSet() == InstrSet_ARM then
+ LR = PC - 4;
+ else
+ LR = PC<31:1> : '1';
+ if targetInstrSet == InstrSet_ARM then
+ targetAddress = Align(PC,4) + imm32;
+ else
+ targetAddress = PC + imm32;
+ SelectInstrSet(targetInstrSet);
+ BranchWritePC(targetAddress);
+ }
+#endif
+
+ bool success = true;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ addr_t lr; // next instruction address
+ addr_t target; // target address
+ int32_t imm32; // PC-relative offset
+ switch (encoding) {
+ case eEncodingT1:
+ {
+ lr = pc | 1u; // return address
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10 = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ }
+ case eEncodingT2:
+ {
+ lr = pc | 1u; // return address
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10H = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm10L = Bits32(opcode, 10, 1);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = Align(pc, 4) + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 4 + imm32);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ }
+ case eEncodingA1:
+ lr = pc - 4; // return address
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
+ target = Align(pc, 4) + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 8 + imm32);
+ break;
+ case eEncodingA2:
+ lr = pc - 4; // return address
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 8 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ if (!BranchWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch with Link and Exchange (register) calls a subroutine at an address and
+// instruction set specified by a register.
+// BLX (register)
+bool
+EmulateInstructionARM::EmulateBLXRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ target = R[m];
+ if CurrentInstrSet() == InstrSet_ARM then
+ next_instr_addr = PC - 4;
+ LR = next_instr_addr;
+ else
+ next_instr_addr = PC - 2;
+ LR = next_instr_addr<31:1> : '1';
+ BXWritePC(target);
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ addr_t lr; // next instruction address
+ if (!success)
+ return false;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ lr = (pc - 2) | 1u; // return address
+ Rm = Bits32(opcode, 6, 3);
+ // if m == 15 then UNPREDICTABLE;
+ if (Rm == 15)
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ lr = pc - 4; // return address
+ Rm = Bits32(opcode, 3, 0);
+ // if m == 15 then UNPREDICTABLE;
+ if (Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch and Exchange causes a branch to an address and instruction set specified by a register.
+bool
+EmulateInstructionARM::EmulateBXRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ BXWritePC(R[m]);
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ Rm = Bits32(opcode, 6, 3);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rm = Bits32(opcode, 3, 0);
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch and Exchange Jazelle attempts to change to Jazelle state. If the attempt fails, it branches to an
+// address and instruction set specified by a register as though it were a BX instruction.
+//
+// TODO: Emulate Jazelle architecture?
+// We currently assume that switching to Jazelle state fails, thus treating BXJ as a BX operation.
+bool
+EmulateInstructionARM::EmulateBXJRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then
+ BXWritePC(R[m]);
+ else
+ if JazelleAcceptsExecution() then
+ SwitchToJazelleExecution();
+ else
+ SUBARCHITECTURE_DEFINED handler call;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ Rm = Bits32(opcode, 19, 16);
+ if (BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rm = Bits32(opcode, 3, 0);
+ if (Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 to point to some ip offset.
+// SUB (immediate)
+bool
+EmulateInstructionARM::EmulateSUBR7IPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const addr_t ip = ReadCoreReg (12, &success);
+ if (!success)
+ return false;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingA1:
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t ip_offset = imm32;
+ addr_t addr = ip - ip_offset; // the adjusted ip value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r12, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, -ip_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
+ return false;
+ }
+ return true;
+}
+
+// Set ip to point to some stack offset.
+// SUB (SP minus immediate)
+bool
+EmulateInstructionARM::EmulateSUBIPSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingA1:
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp - sp_offset; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, -sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
+ return false;
+ }
+ return true;
+}
+
+// This instruction subtracts an immediate value from the SP value, and writes
+// the result to the destination register.
+//
+// If Rd == 13 => A sub operation to adjust the SP -- allocate space for local storage.
+bool
+EmulateInstructionARM::EmulateSUBSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rd;
+ bool setflags;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 13;
+ setflags = false;
+ imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rd == 15 && setflags)
+ return EmulateCMPImm(opcode, eEncodingT2);
+ if (Rd == 15 && !setflags)
+ return false;
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = false;
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+ if (Rd == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ AddWithCarryResult res = AddWithCarry(sp, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ if (Rd == 13)
+ {
+ uint64_t imm64 = imm32; // Need to expand it to 64 bits before attempting to negate it, or the wrong
+ // value gets passed down to context.SetImmediateSigned.
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-imm64); // the stack pointer offset
+ }
+ else
+ {
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ }
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// A store operation to the stack that also updates the SP.
+bool
+EmulateInstructionARM::EmulateSTRRtSP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ if wback then R[n] = offset_addr;
+ }
+#endif
+
+ bool conditional = false;
+ bool success = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rt; // the source register
+ uint32_t imm12;
+ uint32_t Rn; // This function assumes Rn is the SP, but we should verify that.
+
+ bool index;
+ bool add;
+ bool wback;
+ switch (encoding) {
+ case eEncodingA1:
+ Rt = Bits32(opcode, 15, 12);
+ imm12 = Bits32(opcode, 11, 0);
+ Rn = Bits32 (opcode, 19, 16);
+
+ if (Rn != 13) // 13 is the SP reg on ARM. Verify that Rn == SP.
+ return false;
+
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ if (wback && ((Rn == 15) || (Rn == Rt)))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ addr_t offset_addr;
+ if (add)
+ offset_addr = sp + imm12;
+ else
+ offset_addr = sp - imm12;
+
+ addr_t addr;
+ if (index)
+ addr = offset_addr;
+ else
+ addr = sp;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo sp_reg;
+ RegisterInfo dwarf_reg;
+
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rt, dwarf_reg);
+ context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp);
+ if (Rt != 15)
+ {
+ uint32_t reg_value = ReadCoreReg(Rt, &success);
+ if (!success)
+ return false;
+ if (!MemUWrite (context, addr, reg_value, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ if (!MemUWrite (context, addr, pc, addr_byte_size))
+ return false;
+ }
+
+
+ if (wback)
+ {
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (addr - sp);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// Vector Push stores multiple extension registers to the stack.
+// It also updates SP to point to the start of the stored data.
+bool
+EmulateInstructionARM::EmulateVPUSH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
+ address = SP - imm32;
+ SP = SP - imm32;
+ if single_regs then
+ for r = 0 to regs-1
+ MemA[address,4] = S[d+r]; address = address+4;
+ else
+ for r = 0 to regs-1
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ address = address+8;
+ }
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ bool single_regs;
+ uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
+ uint32_t imm32; // stack offset
+ uint32_t regs; // number of registers
+ switch (encoding) {
+ case eEncodingT1:
+ case eEncodingA1:
+ single_regs = false;
+ d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ // If UInt(imm8) is odd, see "FSTMX".
+ regs = Bits32(opcode, 7, 0) / 2;
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ case eEncodingT2:
+ case eEncodingA2:
+ single_regs = true;
+ d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ regs = Bits32(opcode, 7, 0);
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+ uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
+ addr_t sp_offset = imm32;
+ addr_t addr = sp - sp_offset;
+ uint32_t i;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo dwarf_reg;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<regs; ++i)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
+ context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp);
+ // uint64_t to accommodate 64-bit registers.
+ uint64_t reg_value = ReadRegisterUnsigned (&dwarf_reg, 0, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, reg_value, reg_byte_size))
+ return false;
+ addr += reg_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Vector Pop loads multiple extension registers from the stack.
+// It also updates SP to point just above the loaded data.
+bool
+EmulateInstructionARM::EmulateVPOP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
+ address = SP;
+ SP = SP + imm32;
+ if single_regs then
+ for r = 0 to regs-1
+ S[d+r] = MemA[address,4]; address = address+4;
+ else
+ for r = 0 to regs-1
+ word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+ }
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ bool single_regs;
+ uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
+ uint32_t imm32; // stack offset
+ uint32_t regs; // number of registers
+ switch (encoding) {
+ case eEncodingT1:
+ case eEncodingA1:
+ single_regs = false;
+ d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ // If UInt(imm8) is odd, see "FLDMX".
+ regs = Bits32(opcode, 7, 0) / 2;
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ case eEncodingT2:
+ case eEncodingA2:
+ single_regs = true;
+ d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ regs = Bits32(opcode, 7, 0);
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+ uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
+ addr_t sp_offset = imm32;
+ addr_t addr = sp;
+ uint32_t i;
+ uint64_t data; // uint64_t to accomodate 64-bit registers.
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+ RegisterInfo dwarf_reg;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<regs; ++i)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, reg_byte_size, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned(context, &dwarf_reg, data))
+ return false;
+ addr += reg_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// SVC (previously SWI)
+bool
+EmulateInstructionARM::EmulateSVC (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ CallSupervisor();
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ addr_t lr; // next instruction address
+ if (!success)
+ return false;
+ uint32_t imm32; // the immediate constant
+ uint32_t mode; // ARM or Thumb mode
+ switch (encoding) {
+ case eEncodingT1:
+ lr = (pc + 2) | 1u; // return address
+ imm32 = Bits32(opcode, 7, 0);
+ mode = eModeThumb;
+ break;
+ case eEncodingA1:
+ lr = pc + 4; // return address
+ imm32 = Bits32(opcode, 23, 0);
+ mode = eModeARM;
+ break;
+ default:
+ return false;
+ }
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextSupervisorCall;
+ context.SetISAAndImmediate (mode, imm32);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ }
+ return true;
+}
+
+// If Then makes up to four following instructions (the IT block) conditional.
+bool
+EmulateInstructionARM::EmulateIT (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations();
+ ITSTATE.IT<7:0> = firstcond:mask;
+#endif
+
+ m_it_session.InitIT(Bits32(opcode, 7, 0));
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateNop (const uint32_t opcode, const ARMEncoding encoding)
+{
+ // NOP, nothing to do...
+ return true;
+}
+
+// Branch causes a branch to a target address.
+bool
+EmulateInstructionARM::EmulateB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ BranchWritePC(PC + imm32);
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ addr_t target; // target address
+ int32_t imm32; // PC-relative offset
+ switch (encoding) {
+ case eEncodingT1:
+ // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
+ imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ case eEncodingT2:
+ imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ case eEncodingT3:
+ // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
+ {
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm6 = Bits32(opcode, 21, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<21>(imm21);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ }
+ case eEncodingT4:
+ {
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10 = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ }
+ case eEncodingA1:
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 8 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (!BranchWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
+// zero and conditionally branch forward a constant value. They do not affect the condition flags.
+// CBNZ, CBZ
+bool
+EmulateInstructionARM::EmulateCB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations();
+ if nonzero ^ IsZero(R[n]) then
+ BranchWritePC(PC + imm32);
+#endif
+
+ bool success = false;
+
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Bits32(opcode, 2, 0), &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ addr_t target; // target address
+ uint32_t imm32; // PC-relative offset to branch forward
+ bool nonzero;
+ switch (encoding) {
+ case eEncodingT1:
+ imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
+ nonzero = BitIsSet(opcode, 11);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (nonzero ^ (reg_val == 0))
+ if (!BranchWritePC(context, target))
+ return false;
+
+ return true;
+}
+
+// Table Branch Byte causes a PC-relative forward branch using a table of single byte offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the byte returned from the table.
+//
+// Table Branch Halfword causes a PC-relative forward branch using a table of single halfword offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the halfword returned from the table.
+// TBB, TBH
+bool
+EmulateInstructionARM::EmulateTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ if is_tbh then
+ halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]);
+ else
+ halfwords = UInt(MemU[R[n]+R[m], 1]);
+ BranchWritePC(PC + 2*halfwords);
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the base register which contains the address of the table of branch lengths
+ uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
+ bool is_tbh; // true if table branch halfword
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ is_tbh = BitIsSet(opcode, 4);
+ if (Rn == 13 || BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // Read the address of the table from the operand register Rn.
+ // The PC can be used, in which case the table immediately follows this instruction.
+ uint32_t base = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // the table index
+ uint32_t index = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // the offsetted table address
+ addr_t addr = base + (is_tbh ? index*2 : index);
+
+ // PC-relative offset to branch forward
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextTableBranchReadMemory;
+ uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
+ if (!success)
+ return false;
+
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ // target address
+ addr_t target = pc + offset;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
+
+ if (!BranchWritePC(context, target))
+ return false;
+
+ return true;
+}
+
+// This instruction adds an immediate value to a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ bool setflags;
+ uint32_t imm32;
+ uint32_t carry_out;
+
+ //EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 = ZeroExtend(imm3, 32);
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = Bits32 (opcode, 8,6);
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 = ZeroExtend(imm8, 32);
+ d = Bits32 (opcode, 10, 8);
+ n = Bits32 (opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32 (opcode, 7, 0);
+
+ break;
+
+ case eEncodingT3:
+ // if Rd == '1111' && S == '1' then SEE CMN (immediate);
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ setflags = BitIsSet (opcode, 20);
+ imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out);
+
+ // if BadReg(d) || n == 15 then UNPREDICTABLE;
+ if (BadReg (d) || (n == 15))
+ return false;
+
+ break;
+
+ case eEncodingT4:
+ {
+ // if Rn == '1111' then SEE ADR;
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ setflags = false;
+ uint32_t i = Bit32 (opcode, 26);
+ uint32_t imm3 = Bits32 (opcode, 14, 12);
+ uint32_t imm8 = Bits32 (opcode, 7, 0);
+ imm32 = (i << 11) | (imm3 << 8) | imm8;
+
+ // if BadReg(d) then UNPREDICTABLE;
+ if (BadReg (d))
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ AddWithCarryResult res = AddWithCarry (Rn, imm32, 0);
+
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ context.SetRegisterPlusOffset (reg_n, imm32);
+
+ //R[d] = result;
+ //if setflags then
+ //APSR.N = result<31>;
+ //APSR.Z = IsZeroBit(result);
+ //APSR.C = carry;
+ //APSR.V = overflow;
+ if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
+ return false;
+
+ }
+ return true;
+}
+
+// This instruction adds an immediate value to a register value, and writes the result to the destination
+// register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(val1, imm32, 0);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, Rn, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, imm32);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// This instruction adds a register value and an optionally-shifted register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ Rm = Bits32(opcode, 8, 6);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ setflags = false;
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (Rn == 15 && Rm == 15)
+ return false;
+ if (Rd == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo op1_reg;
+ RegisterInfo op2_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, op1_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, op2_reg);
+ context.SetRegisterRegisterOperands (op1_reg, op2_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// Compare Negative (immediate) adds a register value and an immediate value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMNImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t imm32; // the immediate value to be compared with
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rn == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, imm32, 0);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare Negative (register) adds a register value and an optionally-shifted register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMNReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if n == 15 || BadReg(m) then UNPREDICTABLE;
+ if (Rn == 15 || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare (immediate) subtracts an immediate value from a register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t imm32; // the immediate value to be compared with
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 10, 8);
+ imm32 = Bits32(opcode, 7, 0);
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rn == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare (register) subtracts an optionally-shifted register value from a register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMPReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (Rn < 8 && Rm < 8)
+ return false;
+ if (Rn == 15 || Rm == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, ~shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Arithmetic Shift Right (immediate) shifts a register value right by an immediate number of bits,
+// shifting in copies of its sign bit, and writes the result to the destination register. It can
+// optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateASRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_ASR);
+}
+
+// Arithmetic Shift Right (register) shifts a register value right by a variable number of bits,
+// shifting in copies of its sign bit, and writes the result to the destination register.
+// The variable number of bits is read from the bottom byte of a register. It can optionally update
+// the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateASRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_ASR);
+}
+
+// Logical Shift Left (immediate) shifts a register value left by an immediate number of bits,
+// shifting in zeros, and writes the result to the destination register. It can optionally
+// update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSLImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_LSL);
+}
+
+// Logical Shift Left (register) shifts a register value left by a variable number of bits,
+// shifting in zeros, and writes the result to the destination register. The variable number
+// of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSLReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_LSL);
+}
+
+// Logical Shift Right (immediate) shifts a register value right by an immediate number of bits,
+// shifting in zeros, and writes the result to the destination register. It can optionally
+// update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_LSR);
+}
+
+// Logical Shift Right (register) shifts a register value right by a variable number of bits,
+// shifting in zeros, and writes the result to the destination register. The variable number
+// of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_LSR);
+}
+
+// Rotate Right (immediate) provides the value of the contents of a register rotated by a constant value.
+// The bits that are rotated off the right end are inserted into the vacated bit positions on the left.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRORImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_ROR);
+}
+
+// Rotate Right (register) provides the value of the contents of a register rotated by a variable number of bits.
+// The bits that are rotated off the right end are inserted into the vacated bit positions on the left.
+// The variable number of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateRORReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_ROR);
+}
+
+// Rotate Right with Extend provides the value of the contents of a register shifted right by one place,
+// with the carry flag shifted into bit [31].
+//
+// RRX can optionally update the condition flags based on the result.
+// In that case, bit [0] is shifted into the carry flag.
+bool
+EmulateInstructionARM::EmulateRRX (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_RRX);
+}
+
+bool
+EmulateInstructionARM::EmulateShiftImm (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type)
+{
+// assert(shift_type == SRType_ASR
+// || shift_type == SRType_LSL
+// || shift_type == SRType_LSR
+// || shift_type == SRType_ROR
+// || shift_type == SRType_RRX);
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t Rm; // the first operand register
+ uint32_t imm5; // encoding for the shift amount
+ uint32_t carry; // the carry bit after the shift operation
+ bool setflags;
+
+ // Special case handling!
+ // A8.6.139 ROR (immediate) -- Encoding T1
+ ARMEncoding use_encoding = encoding;
+ if (shift_type == SRType_ROR && use_encoding == eEncodingT1)
+ {
+ // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding to
+ // have the same decoding of bit fields as the other Thumb2 shift operations.
+ use_encoding = eEncodingT2;
+ }
+
+ switch (use_encoding) {
+ case eEncodingT1:
+ // Due to the above special case handling!
+ if (shift_type == SRType_ROR)
+ return false;
+
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm5 = Bits32(opcode, 10, 6);
+ break;
+ case eEncodingT2:
+ // A8.6.141 RRX
+ // There's no imm form of RRX instructions.
+ if (shift_type == SRType_RRX)
+ return false;
+
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6);
+ if (BadReg(Rd) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ imm5 = Bits32(opcode, 11, 7);
+ break;
+ default:
+ return false;
+ }
+
+ // A8.6.139 ROR (immediate)
+ if (shift_type == SRType_ROR && imm5 == 0)
+ shift_type = SRType_RRX;
+
+ // Get the first operand.
+ uint32_t value = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ // Decode the shift amount if not RRX.
+ uint32_t amt = (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5));
+
+ uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateShiftReg (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type)
+{
+ // assert(shift_type == SRType_ASR
+ // || shift_type == SRType_LSL
+ // || shift_type == SRType_LSR
+ // || shift_type == SRType_ROR);
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand register
+ uint32_t Rm; // the register whose bottom byte contains the amount to shift by
+ uint32_t carry; // the carry bit after the shift operation
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Rd;
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 3, 0);
+ Rm = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ if (Rd == 15 || Rn == 15 || Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // Get the first operand.
+ uint32_t value = ReadCoreReg (Rn, &success);
+ if (!success)
+ return false;
+ // Get the Rm register content.
+ uint32_t val = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ // Get the shift amount.
+ uint32_t amt = Bits32(val, 7, 0);
+
+ uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// LDM loads multiple registers from consecutive memory locations, using an
+// address from a base register. Optionally the address just above the highest of those locations
+// can be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed()
+ EncodingSpecificOperations(); NullCheckIfThumbEE (n);
+ address = R[n];
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address, 4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC (MemA[address, 4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = '00000000':register_list; wback = (registers<n> == '0');
+ n = Bits32 (opcode, 10, 8);
+ registers = Bits32 (opcode, 7, 0);
+ registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
+ wback = BitIsClear (registers, n);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // if W == '1' && Rn == '1101' then SEE POP;
+ // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0xdfff; // Make sure bit 13 is zero.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if ((n == 15)
+ || (BitCount (registers) < 2)
+ || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
+ return false;
+
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback
+ && BitIsSet (registers, n))
+ return false;
+ break;
+
+ case eEncodingA1:
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+ if ((n == 15)
+ || (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ int32_t offset = 0;
+ const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ if (wback && (n == 13)) // Pop Instruction
+ {
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+ }
+
+ // R[i] = MemA [address, 4]; address = address + 4;
+ uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ //LoadWritePC (MemA [address, 4]);
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ if (wback && BitIsClear (registers, n))
+ {
+ // R[n] = R[n] + 4 * BitCount (registers)
+ int32_t offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
+ return false;
+ }
+ if (wback && BitIsSet (registers, n))
+ // R[n] bits(32) UNKNOWN;
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMDA loads multiple registers from consecutive memory locations using an address from a base register.
+// The consecutive memory locations end at this address and the address just below the lowest of those locations
+// can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMDA (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] - 4*BitCount(registers) + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+ // address = R[n] - 4*BitCount(registers) + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers)) + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ // for i = 0 to 14
+ for (int i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset));
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The
+// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can
+// be optionally written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] - 4*BitCount(registers);
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0xdfff; // Make sure bit 13 is a zero.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if ((n == 15)
+ || (BitCount (registers) < 2)
+ || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
+ return false;
+
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers);
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers));
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - address);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset));
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMIB loads multiple registers from consecutive memory locations using an address from a base register. The
+// consecutive memory locations start just above this address, and thea ddress of the last of those locations can
+// optinoally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMIB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+ default:
+ return false;
+ }
+ // address = R[n] + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+
+ context.SetRegisterPlusOffset (dwarf_reg, offset + addr_byte_size);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// Load Register (immediate) calculates an address from a base register value and
+// an immediate offset, loads a word from memory, and writes to a register.
+// LDR (immediate, Thumb)
+bool
+EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rt; // the destination register
+ uint32_t Rn; // the base register
+ uint32_t imm32; // the immediate offset used to form the address
+ addr_t offset_addr; // the offset address
+ addr_t address; // the calculated address
+ uint32_t data; // the literal data value from memory load
+ bool add, index, wback;
+ switch (encoding) {
+ case eEncodingT1:
+ Rt = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
+ // index = TRUE; add = TRUE; wback = FALSE
+ add = true;
+ index = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT2:
+ // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
+ Rt = Bits32 (opcode, 10, 8);
+ Rn = 13;
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then SEE LDR (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ Rt = Bits32 (opcode, 15, 12);
+ Rn = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if ((Rt == 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingT4:
+ // if Rn == '1111' then SEE LDR (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRT;
+ // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 == '00000100' then SEE POP;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ Rt = Bits32 (opcode, 15, 12);
+ Rn = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
+ if ((wback && (Rn == Rt)) || ((Rt == 15) && InITBlock() && !LastInITBlock()))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+ uint32_t base = ReadCoreReg (Rn, &success);
+ if (!success)
+ return false;
+ if (add)
+ offset_addr = base + imm32;
+ else
+ offset_addr = base - imm32;
+
+ address = (index ? offset_addr : base);
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, base_reg);
+ if (wback)
+ {
+ EmulateInstruction::Context ctx;
+ ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
+ ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+
+ if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
+ return false;
+ }
+
+ // Prepare to write to the Rt register.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+
+ // Read memory from the address.
+ data = MemURead(context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ if (Rt == 15)
+ {
+ if (Bits32(address, 1, 0) == 0)
+ {
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+ else
+ return false;
+ }
+ else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
+ return false;
+ }
+ else
+ WriteBits32Unknown (Rt);
+ }
+ return true;
+}
+
+// STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations start at this address, and teh address just above the last
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n];
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then // Only possible for encoding A1
+ MemA[address,4] = PCStoreValue();
+ if wback then R[n] = R[n] + 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE;
+ n = Bits32 (opcode, 10, 8);
+ registers = Bits32 (opcode, 7, 0);
+ registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
+ wback = true;
+
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount (registers) < 1)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 2))
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n];
+ int32_t offset = 0;
+ const addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_set_bit = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset);
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then // Only possible for encoding A1
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] + 4*BitCount(registers);
+ if (wback)
+ {
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = address + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMDA (Store Multiple Decrement After) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations end at this address, and the address just below the lowest
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMDA (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] - 4*BitCount(registers) + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] - 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers) + 4;
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers)) + 4;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_bit_set = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_bit_set)
+ lowest_bit_set = i;
+ //if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_bit_set))
+ // MemA[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset));
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] - 4*BitCount(registers);
+ if (wback)
+ {
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMDB (Store Multiple Decrement Before) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations end just below this address, and the address of the first of
+// those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMDB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] - 4*BitCount(registers);
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then // Only possible for encoding A1
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] - 4*BitCount(registers);
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if W == '1' && Rn == '1101' then SEE PUSH;
+ if ((BitIsSet (opcode, 21)) && (Bits32 (opcode, 19, 16) == 13))
+ {
+ // See PUSH
+ }
+ // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
+ wback = BitIsSet (opcode, 21);
+ // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
+ if ((n == 15) || BitCount (registers) < 2)
+ return false;
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if W == '1' && Rn == '1101Õ && BitCount(register_list) >= 2 then SEE PUSH;
+ if (BitIsSet (opcode, 21) && (Bits32 (opcode, 19, 16) == 13) && BitCount (Bits32 (opcode, 15, 0)) >= 2)
+ {
+ // See Push
+ }
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || BitCount (registers) < 1)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers);
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers));
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_set_bit = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset));
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then // Only possible for encoding A1
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] - 4*BitCount(registers);
+ if (wback)
+ {
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMIB (Store Multiple Increment Before) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations start just above this address, and the address of the last
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMIB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] + 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) && (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ // address = R[n] + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t lowest_set_bit = 14;
+ // for i = 0 to 14
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address + offset);
+ // else
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset + addr_byte_size);
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] + 4*BitCount(registers);
+ if (wback)
+ {
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word
+// from a register to memory. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateSTRThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ if UnalignedSupport() || address<1:0> == '00' then
+ MemU[address,4] = R[t];
+ else // Can only occur before ARMv7
+ MemU[address,4] = bits(32) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+ // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = false;
+ wback = false;
+ break;
+
+ case eEncodingT2:
+ // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
+ t = Bits32 (opcode, 10, 8);
+ n = 13;
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+
+ case eEncodingT4:
+ // if P == '1' && U == '1' && W == '0' then SEE STRT;
+ // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 == '00000100' then SEE PUSH;
+ // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
+ if ((Bits32 (opcode, 19, 16) == 15)
+ || (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t base_address = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // if UnalignedSupport() || address<1:0> == '00' then
+ if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // MemU[address,4] = R[t];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ int32_t offset = address - base_address;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset);
+ if (!MemUWrite (context, address, data, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ // MemU[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address);
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STR (Store Register) calculates an address from a base register value and an offset register value, stores a
+// word from a register to memory. The offset register value can optionally be shifted.
+bool
+EmulateInstructionARM::EmulateSTRRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ if t == 15 then // Only possible for encoding A1
+ data = PCStoreValue();
+ else
+ data = R[t];
+ if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
+ MemU[address,4] = data;
+ else // Can only occur before ARMv7
+ MemU[address,4] = bits(32) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 15) || (BadReg (m)))
+ return false;
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE STRT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t typ = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift(typ, imm5, shift_t);
+
+ // if m == 15 then UNPREDICTABLE;
+ if (m == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+ int32_t offset = 0;
+
+ addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rm_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset = Shift (Rm_data, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = base_address + offset;
+ else
+ offset_addr = base_address - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ uint32_t data;
+ // if t == 15 then // Only possible for encoding A1
+ if (t == 15)
+ // data = PCStoreValue();
+ data = ReadCoreReg (PC_REG, &success);
+ else
+ // data = R[t];
+ data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+
+ // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
+ if (UnalignedSupport ()
+ || (BitIsClear (address, 1) && BitIsClear (address, 0))
+ || CurrentInstrSet() == eModeARM)
+ {
+ // MemU[address,4] = data;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address);
+ if (!MemUWrite (context, address, data, addr_byte_size))
+ return false;
+
+ }
+ else
+ // MemU[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address);
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateSTRBThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,1] = R[t]<7:0>;
+ if wback then R[n] = offset_addr;
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if BadReg(t) then UNPREDICTABLE;
+ if (BadReg (t))
+ return false;
+ break;
+
+ case eEncodingT3:
+ // if P == '1' && U == '1' && W == '0' then SEE STRBT;
+ // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE
+ if ((BadReg (t)) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+ addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ // MemU[address,1] = R[t]<7:0>
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address);
+
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ data = Bits32 (data, 7, 0);
+
+ if (!MemUWrite (context, address, data, 1))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+// STRH (register) calculates an address from a base register value and an offset register value, and stores a
+// halfword from a register to memory. The offset register alue can be shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ if UnalignedSupport() || address<0> == '0' then
+ MemU[address,2] = R[t]<15:0>;
+ else // Can only occur before ARMv7
+ MemU[address,2] = bits(16) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ if (n == 15)
+ return false;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if BadReg(t) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (t) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE STRHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ // if UnalignedSupport() || address<0> == '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // MemU[address,2] = R[t]<15:0>;
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ if (!MemUWrite (context, address, Bits32 (Rt, 15, 0), 2))
+ return false;
+ }
+ else // Can only occur before ARMv7
+ {
+ // MemU[address,2] = bits(16) UNKNOWN;
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Add with Carry (immediate) adds an immediate value and the carry flag value to a register value,
+// and writes the result to the destination register. It can optionally update the condition flags
+// based on the result.
+bool
+EmulateInstructionARM::EmulateADCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ int32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(val1, imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// Add with Carry (register) adds a register value, the carry flag value, and an optionally-shifted
+// register value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ int32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ int32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// This instruction adds an immediate value to the PC value to form a PC-relative address,
+// and writes the result to the destination register.
+bool
+EmulateInstructionARM::EmulateADR (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32);
+ if d == 15 then // Can only occur for ARM encodings
+ ALUWritePC(result);
+ else
+ R[d] = result;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd;
+ uint32_t imm32; // the immediate value to be added/subtracted to/from the PC
+ bool add;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 10, 8);
+ imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32)
+ add = true;
+ break;
+ case eEncodingT2:
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+ add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB
+ if (BadReg(Rd))
+ return false;
+ break;
+ case eEncodingA1:
+ case eEncodingA2:
+ Rd = Bits32(opcode, 15, 12);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB
+ break;
+ default:
+ return false;
+ }
+
+ // Read the PC value.
+ uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreReg(context, result, Rd))
+ return false;
+ }
+ return true;
+}
+
+// This instruction performs a bitwise AND of a register value and an immediate value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateANDImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rd == '1111' && S == '1' then SEE TST (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateTSTImm(opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// This instruction performs a bitwise AND of a register value and an optionally-shifted register value,
+// and writes the result to the destination register. It can optionally update the condition flags
+// based on the result.
+bool
+EmulateInstructionARM::EmulateANDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rd == '1111' && S == '1' then SEE TST (register);
+ if (Rd == 15 && setflags)
+ return EmulateTSTReg(opcode, eEncodingT2);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and the complement of an
+// immediate value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateBICImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND NOT(imm32);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & ~imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Bit Clear (register) performs a bitwise AND of a register value and the complement of an
+// optionally-shifted register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateBICReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND NOT(shifted);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & ~shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// LDR (immediate, ARM) calculates an address from a base register value and an immediate offset, loads a word
+// from memory, and writes it to a register. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRImmediateARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rn == '1111' then SEE LDR (literal);
+ // if P == '0' && W == '1' then SEE LDRT;
+ // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 == '000000000100' then SEE POP;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // if wback && n == t then UNPREDICTABLE;
+ if (wback && (n == t))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t address;
+ addr_t offset_addr;
+ addr_t base_address = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ // data = MemU[address,4];
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+
+ uint64_t data = MemURead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if t == 15 then
+ if (t == 15)
+ {
+ // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ if (BitIsClear (address, 1) && BitIsClear (address, 0))
+ {
+ // LoadWritePC (data);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+ LoadWritePC (context, data);
+ }
+ else
+ return false;
+ }
+ // elsif UnalignedSupport() || address<1:0> = '00' then
+ else if (UnalignedSupport() || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // R[t] = data;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ // else // Can only apply before ARMv7
+ else
+ {
+ // R[t] = ROR(data, 8*UInt(address<1:0>));
+ data = ROR (data, Bits32 (address, 1, 0), &success);
+ if (!success)
+ return false;
+ context.type = eContextRegisterLoad;
+ context.SetImmediate (data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+
+ }
+ return true;
+}
+
+// LDR (register) calculates an address from a base register value and an offset register value, loads a word
+// from memory, and writes it to a resgister. The offset register value can optionally be shifted.
+bool
+EmulateInstructionARM::EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ if CurrentInstrSet() == InstrSet_ARM then
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+ else
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDR (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if BadReg(m) then UNPREDICTABLE;
+ if (BadReg (m))
+ return false;
+
+ // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if ((t == 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE LDRT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t type = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift (type, imm5, shift_t);
+
+ // if m == 15 then UNPREDICTABLE;
+ if (m == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ }
+ break;
+
+
+ default:
+ return false;
+ }
+
+ uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is an application level alias for the CPSR".
+ addr_t offset = Shift (Rm, shift_t, shift_n, Bit32 (m_opcode_cpsr, APSR_C), &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,4];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if t == 15 then
+ if (t == 15)
+ {
+ // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ if (BitIsClear (address, 1) && BitIsClear (address, 0))
+ {
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ LoadWritePC (context, data);
+ }
+ else
+ return false;
+ }
+ // elsif UnalignedSupport() || address<1:0> = '00' then
+ else if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // R[t] = data;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // if CurrentInstrSet() == InstrSet_ARM then
+ if (CurrentInstrSet () == eModeARM)
+ {
+ // R[t] = ROR(data, 8*UInt(address<1:0>));
+ data = ROR (data, Bits32 (address, 1, 0), &success);
+ if (!success)
+ return false;
+ context.type = eContextRegisterLoad;
+ context.SetImmediate (data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ }
+ return true;
+}
+
+// LDRB (immediate, Thumb)
+bool
+EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = ZeroExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback= false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT3:
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRBT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address;
+ addr_t offset_addr;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = ZeroExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory,
+// zero-extends it to form a 32-bit word and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRBLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ R[t] = ZeroExtend(MemU[address,1], 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLD;
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint32_t pc_val = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t base = AlignPC (pc_val);
+
+ addr_t address;
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // R[t] = ZeroExtend(MemU[address,1], 32);
+ EmulateInstruction::Context context;
+ context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (address - base);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ return true;
+}
+
+// LDRB (register) calculates an address from a base register value and an offset rigister value, loads a byte from
+// memory, zero-extends it to form a 32-bit word, and writes it to a register. The offset register value can
+// optionally be shifted.
+bool
+EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ R[t] = ZeroExtend(MemU[address,1],32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE LDRBT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t type = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift (type, imm5, shift_t);
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = ZeroExtend(MemU[address,1],32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRH (immediate, Thumb) calculates an address from a base register value and an immediate offset, loads a
+// halfword from memory, zero-extends it to form a 32-bit word, and writes it to a register. It can use offset,
+// post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRHImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6) << 1;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // if Rn == '1111' then SEE LDRH (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then SEE LDRH (literal);
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints";
+ // if P == '1' && U == '1' && W == '0' then SEE LDRHT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport () || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRH (literal) caculates an address from the PC value and an immediate offset, loads a halfword from memory,
+// zero-extends it to form a 32-bit word, and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRHLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,2];
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ addr_t base = AlignPC (pc_value);
+ addr_t address;
+
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport () || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRH (literal) calculates an address from a base register value and an offset register value, loads a halfword
+// from memory, zero-extends it to form a 32-bit word, and writes it to a register. The offset register value can
+// be shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSB (immediate) calculates an address from a base register value and an immediate offset, loads a byte from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. It can use offset, post-indexed,
+// or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRSBImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = SignExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRSBT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (((t == 13) || ((t == 15)
+ && (BitIsClear (opcode, 10) || BitIsSet (opcode, 9) || BitIsSet (opcode, 8))))
+ || (wback && (n == t)))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // if P == '0' && W == '1' then SEE LDRSBT;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ uint64_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// LDRSB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory,
+// sign-extends it to form a 32-bit word, and writes tit to a register.
+bool
+EmulateInstructionARM::EmulateLDRSBLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ R[t] = SignExtend(MemU[address,1], 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLI;
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+ uint64_t base = AlignPC (pc_value);
+
+ // address = if add then (base + imm32) else (base - imm32);
+ addr_t address;
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ return true;
+}
+
+// LDRSB (register) calculates an address from a base register value and an offset register value, loadsa byte from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. The offset register value can be
+// shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRSBRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ R[t] = SignExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRSBT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRSH (immediate) calculates an address from a base register value and an immediate offset, loads a halfword from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. It can use offset, post-indexed, or
+// pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRSHImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints";
+ // if P == '1' && U == '1' && W == '0' then SEE LDRSHT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if P == '0' && W == '1' then SEE LDRSHT;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ uint32_t imm4H = Bits32 (opcode, 11,8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSH (literal) calculates an address from the PC value and an immediate offset, loads a halfword from memory,
+// sign-extends it to from a 32-bit word, and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRSHLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,2];
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint64_t base = AlignPC (pc_value);
+
+ addr_t address;
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, imm32);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSH (register) calculates an address from a base register value and an offset register value, loads a halfword
+// from memory, sign-extends it to form a 32-bit word, and writes it to a register. The offset register value can be
+// shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRSHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRSHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination
+// register. You can specifiy a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value.
+bool
+EmulateInstructionARM::EmulateSXTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = SignExtend(rotated<7:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = SignExtend(rotated<7:0>, 32);
+ int64_t data = llvm::SignExtend64<8>(rotated);
+
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data))
+ return false;
+ }
+ return true;
+}
+
+// SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
+bool
+EmulateInstructionARM::EmulateSXTH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = SignExtend(rotated<15:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = SignExtend(rotated<15:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ int64_t data = llvm::SignExtend64<16> (rotated);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data))
+ return false;
+ }
+
+ return true;
+}
+
+// UXTB extracts an 8-bit value from a register, zero-extneds it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value.
+bool
+EmulateInstructionARM::EmulateUXTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = ZeroExtend(rotated<7:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = ZeroExtend(rotated<7:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 7, 0)))
+ return false;
+ }
+ return true;
+}
+
+// UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
+bool
+EmulateInstructionARM::EmulateUXTH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = ZeroExtend(rotated<15:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = ZeroExtend(rotated<15:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 15, 0)))
+ return false;
+ }
+ return true;
+}
+
+// RFE (Return From Exception) loads the PC and the CPSR from the word at the specified address and the following
+// word respectively.
+bool
+EmulateInstructionARM::EmulateRFE (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
+ UNPREDICTABLE;
+ else
+ address = if increment then R[n] else R[n]-8;
+ if wordhigher then address = address+4;
+ CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE);
+ BranchWritePC(MemA[address,4]);
+ if wback then R[n] = if increment then R[n]+8 else R[n]-8;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ bool wback;
+ bool increment;
+ bool wordhigher;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ wback = BitIsSet (opcode, 21);
+ increment = false;
+ wordhigher = false;
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ wback = BitIsSet (opcode, 21);
+ increment = true;
+ wordhigher = false;
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn);
+ n = Bits32 (opcode, 19, 16);
+
+ // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U);
+ wback = BitIsSet (opcode, 21);
+ increment = BitIsSet (opcode, 23);
+ wordhigher = (Bit32 (opcode, 24) == Bit32 (opcode, 23));
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
+ if (!CurrentModeIsPrivileged ())
+ // UNPREDICTABLE;
+ return false;
+ else
+ {
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address;
+ // address = if increment then R[n] else R[n]-8;
+ if (increment)
+ address = Rn;
+ else
+ address = Rn - 8;
+
+ // if wordhigher then address = address+4;
+ if (wordhigher)
+ address = address + 4;
+
+ // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextReturnFromException;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemARead (context, address + 4, 4, 0, &success);
+ if (!success)
+ return false;
+
+ CPSRWriteByInstr (data, 15, true);
+
+ // BranchWritePC(MemA[address,4]);
+ uint64_t data2 = MemARead (context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ BranchWritePC (context, data2);
+
+ // if wback then R[n] = if increment then R[n]+8 else R[n]-8;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ if (increment)
+ {
+ context.SetOffset (8);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + 8))
+ return false;
+ }
+ else
+ {
+ context.SetOffset (-8);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn - 8))
+ return false;
+ }
+ } // if wback
+ }
+ } // if ConditionPassed()
+ return true;
+}
+
+// Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value,
+// and writes the result to the destination register. It can optionally update the condition flags based on
+// the result.
+bool
+EmulateInstructionARM::EmulateEORImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] EOR imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rd == '1111' && S == '1' then SEE TEQ (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateTEQImm (opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 ^ imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a register value and an
+// optionally-shifted register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateEORReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] EOR shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rd == '1111' && S == '1' then SEE TEQ (register);
+ if (Rd == 15 && setflags)
+ return EmulateTEQReg (opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 ^ shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value and an immediate value, and
+// writes the result to the destination register. It can optionally update the condition flags based
+// on the result.
+bool
+EmulateInstructionARM::EmulateORRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] OR imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rn == '1111' then SEE MOV (immediate);
+ if (Rn == 15)
+ return EmulateMOVRdImm (opcode, eEncodingT2);
+ if (BadReg(Rd) || Rn == 13)
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 | imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise OR (register) performs a bitwise (inclusive) OR of a register value and an optionally-shifted register
+// value, and writes the result to the destination register. It can optionally update the condition flags based
+// on the result.
+bool
+EmulateInstructionARM::EmulateORRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] OR shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rn == '1111' then SEE MOV (register);
+ if (Rn == 15)
+ return EmulateMOVRdRm (opcode, eEncodingT3);
+ if (BadReg(Rd) || Rn == 13 || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 | shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Reverse Subtract (immediate) subtracts a register value from an immediate value, and writes the result to
+// the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSBImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(~reg_val, imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract (register) subtracts a register value from an optionally-shifted register value, and writes the
+// result to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSBReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(~val1, shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract with Carry (immediate) subtracts a register value and the value of NOT (Carry flag) from
+// an immediate value, and writes the result to the destination register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C);
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(~reg_val, imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract with Carry (register) subtracts a register value and the value of NOT (Carry flag) from an
+// optionally-shifted register value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C);
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(~val1, shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Subtract with Carry (immediate) subtracts an immediate value and the value of
+// NOT (Carry flag) from a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSBCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Subtract with Carry (register) subtracts an optionally-shifted register value and the value of
+// NOT (Carry flag) from a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSBCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, ~shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// This instruction subtracts an immediate value from a register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSUBImmThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 8, 6); // imm32 = ZeroExtend(imm3, 32)
+ break;
+ case eEncodingT2:
+ Rd = Rn = Bits32(opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+
+ // if Rd == '1111' && S == '1' then SEE CMP (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateCMPImm (opcode, eEncodingT2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingT2);
+
+ // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE;
+ if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15)
+ return false;
+ break;
+ case eEncodingT4:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+
+ // if Rn == '1111' then SEE ADR;
+ if (Rn == 15)
+ return EmulateADR (opcode, eEncodingT2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingT3);
+
+ if (BadReg(Rd))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// This instruction subtracts an immediate value from a register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSUBImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rn == '1111' && S == '0' then SEE ADR;
+ if (Rn == 15 && !setflags)
+ return EmulateADR (opcode, eEncodingA2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingA1);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Test Equivalence (immediate) performs a bitwise exclusive OR operation on a register value and an
+// immediate value. It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTEQImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] EOR imm32;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 ^ imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test Equivalence (register) performs a bitwise exclusive OR operation on a register value and an
+// optionally-shifted register value. It updates the condition flags based on the result, and discards
+// the result.
+bool
+EmulateInstructionARM::EmulateTEQReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] EOR shifted;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 ^ shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test (immediate) performs a bitwise AND operation on a register value and an immediate value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTSTImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND imm32;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test (register) performs a bitwise AND operation on a register value and an optionally-shifted register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTSTReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND shifted;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.216 SUB (SP minus register)
+bool
+EmulateInstructionARM::EmulateSUBSPReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
+ shift_n = DecodeImmShiftThumb (opcode, shift_t);
+
+ // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then UNPREDICTABLE;
+ if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3)))
+ return false;
+
+ // if d == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((d == 15) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if (d == 15 && setflags)
+ EmulateSUBSPcLrEtc (opcode, encoding);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+ break;
+
+ default:
+ return false;
+ }
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ);
+ uint32_t sp_val = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (sp_val, ~shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, dwarf_reg);
+ context.SetRegisterRegisterOperands (sp_reg, dwarf_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+
+// A8.6.7 ADD (register-shifted register)
+bool
+EmulateInstructionARM::EmulateADDRegShift (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[s]<7:0>);
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ uint32_t s;
+ bool setflags;
+ ARM_ShifterType shift_t;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs);
+ d = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ s = Bits32 (opcode, 11, 8);
+
+ // setflags = (S == Ô1Õ); shift_t = DecodeRegShift(type);
+ setflags = BitIsSet (opcode, 20);
+ shift_t = DecodeRegShift (Bits32 (opcode, 6, 5));
+
+ // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15) || (m == 15) || (s == 15))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // shift_n = UInt(R[s]<7:0>);
+ uint32_t Rs = ReadCoreReg (s, &success);
+ if (!success)
+ return false;
+
+ uint32_t shift_n = Bits32 (Rs, 7, 0);
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (Rn, shifted, 0);
+
+ // R[d] = result;
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+ RegisterInfo reg_m;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m);
+
+ context.SetRegisterRegisterOperands (reg_n, reg_m);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, res.result))
+ return false;
+
+ // if setflags then
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+ if (setflags)
+ return WriteFlags (context, res.result, res.carry_out, res.overflow);
+ }
+ return true;
+}
+
+// A8.6.213 SUB (register)
+bool
+EmulateInstructionARM::EmulateSUBReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock();
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+ setflags = !InITBlock();
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register);
+ // if Rn == Ô1101Õ then SEE SUB (SP minus register);
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
+ shift_n = DecodeImmShiftThumb (opcode, shift_t);
+
+ // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((d == 13) || ((d == 15) && BitIsClear (opcode, 20)) || (n == 15) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if Rn == Ô1101Õ then SEE SUB (SP minus register);
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if ((d == 15) && setflags)
+ EmulateSUBSPcLrEtc (opcode, encoding);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (Rn, ~shifted, 1);
+
+ // if d == 15 then // Can only occur for ARM encoding
+ // ALUWritePC(result); // setflags is always FALSE here
+ // else
+ // R[d] = result;
+ // if setflags then
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+ RegisterInfo reg_m;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m);
+ context.SetRegisterRegisterOperands (reg_n, reg_m);
+
+ if (!WriteCoreRegOptionalFlags (context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.202 STREX
+// Store Register Exclusive calculates an address from a base register value and an immediate offset, and stores a
+// word from a register to memory if the executing processor has exclusive access to the memory addressed.
+bool
+EmulateInstructionARM::EmulateSTREX (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] + imm32;
+ if ExclusiveMonitorsPass(address,4) then
+ MemA[address,4] = R[t];
+ R[d] = 0;
+ else
+ R[d] = 1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = Bits32 (opcode, 11, 8);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (t) || (n == 15))
+ return false;
+
+ // if d == n || d == t then UNPREDICTABLE;
+ if ((d == n) || (d == t))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero offset
+ d = Bits32 (opcode, 15, 12);
+ t = Bits32 (opcode, 3, 0);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = 0;
+
+ // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE;
+ if ((d == 15) || (t == 15) || (n == 15))
+ return false;
+
+ // if d == n || d == t then UNPREDICTABLE;
+ if ((d == n) || (d == t))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] + imm32;
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn + imm32;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, imm32);
+
+ // if ExclusiveMonitorsPass(address,4) then
+ // if (ExclusiveMonitorsPass (address, addr_byte_size)) -- For now, for the sake of emulation, we will say this
+ // always return true.
+ if (true)
+ {
+ // MemA[address,4] = R[t];
+ uint32_t Rt = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address, Rt, addr_byte_size))
+ return false;
+
+ // R[d] = 0;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 0))
+ return false;
+ }
+ else
+ {
+ // R[d] = 1;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.197 STRB (immediate, ARM)
+bool
+EmulateInstructionARM::EmulateSTRBImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,1] = R[t]<7:0>;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if P == Ô0Õ && W == Ô1Õ then SEE STRBT;
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // MemU[address,1] = R[t]<7:0>;
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (!MemUWrite (context, address, Bits32 (Rt, 7, 0), 1))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.194 STR (immediate, ARM)
+bool
+EmulateInstructionARM::EmulateSTRImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if P == Ô0Õ && W == Ô1Õ then SEE STRT;
+ // if Rn == Ô1101Õ && P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && imm12 == Ô000000000100Õ then SEE PUSH;
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ // MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ if (t == 15)
+ {
+ uint32_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemUWrite (context, address, pc_value, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ if (!MemUWrite (context, address, Rt, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetImmediate (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.66 LDRD (immediate)
+// Load Register Dual (immediate) calculates an address from a base register value and an immediate offset, loads two
+// words from memory, and writes them to two registers. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRDImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = MemA[address,4];
+ R[t2] = MemA[address+4,4];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ //if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ //if Rn == Ô1111Õ then SEE LDRD (literal);
+ //t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ t = Bits32 (opcode, 15, 12);
+ t2 = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ //if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ //if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE;
+ if (BadReg (t) || BadReg (t2) || (t == t2))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ //if Rn == Ô1111Õ then SEE LDRD (literal);
+ //if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ //t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0);
+
+ //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ //if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ //if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ //if t2 == 15 then UNPREDICTABLE;
+ if (t2 == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ //address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ //R[t] = MemA[address,4];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ //R[t2] = MemA[address+4,4];
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn);
+ data = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data))
+ return false;
+
+ //if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.68 LDRD (register)
+// Load Register Dual (register) calculates an address from a base register value and a register offset, loads two
+// words from memory, and writes them to two registers. It can use offset, post-indexed or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRDRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ address = if index then offset_addr else R[n];
+ R[t] = MemA[address,4];
+ R[t2] = MemA[address+4,4];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE;
+ if ((t2 == 15) || (m == 15) || (m == t) || (m == t2))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
+ if ((ArchVersion() < 6) && wback && (m == n))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + Rm;
+ else
+ offset_addr = Rn - Rm;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ // R[t] = MemA[address,4];
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // R[t2] = MemA[address+4,4];
+
+ data = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.200 STRD (immediate)
+// Store Register Dual (immediate) calculates an address from a base register value and an immediate offset, and
+// stores two words from two registers to memory. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateSTRDImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemA[address,4] = R[t];
+ MemA[address+4,4] = R[t2];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ t = Bits32 (opcode, 15, 12);
+ t2 = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE;
+ if ((n == 15) || BadReg (t) || BadReg (t2))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if t2 == 15 then UNPREDICTABLE;
+ if (t2 == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ //address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ //MemA[address,4] = R[t];
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ uint32_t data = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+
+ //MemA[address+4,4] = R[t2];
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+
+ data = ReadCoreReg (t2, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + 4, data, addr_byte_size))
+ return false;
+
+ //if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+
+// A8.6.201 STRD (register)
+bool
+EmulateInstructionARM::EmulateSTRDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ address = if index then offset_addr else R[n];
+ MemA[address,4] = R[t];
+ MemA[address+4,4] = R[t2];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+
+ t2 = t+1;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if t2 == 15 || m == 15 then UNPREDICTABLE;
+ if ((t2 == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
+ if ((ArchVersion() < 6) && wback && (m == n))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+ RegisterInfo data_reg;
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + Rm;
+ else
+ offset_addr = Rn - Rm;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+ // MemA[address,4] = R[t];
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, Rt, addr_byte_size))
+ return false;
+
+ // MemA[address+4,4] = R[t2];
+ uint32_t Rt2 = ReadCoreReg (t2, &success);
+ if (!success)
+ return false;
+
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
+
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ if (!MemAWrite (context, address + 4, Rt2, addr_byte_size))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+
+ }
+ }
+ return true;
+}
+
+// A8.6.319 VLDM
+// Vector Load Multiple loads multiple extension registers from consecutive memory locations using an address from
+// an ARM core register.
+bool
+EmulateInstructionARM::EmulateVLDM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then R[n] else R[n]-imm32;
+ if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ for r = 0 to regs-1
+ if single_regs then
+ S[d+r] = MemA[address,4]; address = address+4;
+ else
+ word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ bool single_regs;
+ bool add;
+ bool wback;
+ uint32_t d;
+ uint32_t n;
+ uint32_t imm32;
+ uint32_t regs;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VLDR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ single_regs = false;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFLDMXÓ.
+ regs = Bits32 (opcode, 7, 0) / 2;
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if (n == 15 && (wback || CurrentInstrSet() != eModeARM))
+ return false;
+
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VLDR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn);
+ single_regs = true;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+ regs = Bits32 (opcode, 7, 0);
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
+ return false;
+
+ // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || ((d + regs) > 32))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then R[n] else R[n]-imm32;
+ addr_t address;
+ if (add)
+ address = Rn;
+ else
+ address = Rn - imm32;
+
+ // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ EmulateInstruction::Context context;
+
+ if (wback)
+ {
+ uint32_t value;
+ if (add)
+ value = Rn + imm32;
+ else
+ value = Rn - imm32;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetImmediateSigned (value - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+
+ }
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+
+ context.type = eContextRegisterLoad;
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ if (single_regs)
+ {
+ // S[d+r] = MemA[address,4]; address = address+4;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data))
+ return false;
+
+ address = address + 4;
+ }
+ else
+ {
+ // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn);
+ uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ address = address + 8;
+ // // Combine the word-aligned words in the correct order for current endianness.
+ // D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+ uint64_t data;
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ data = word1;
+ data = (data << 32) | word2;
+ }
+ else
+ {
+ data = word2;
+ data = (data << 32) | word1;
+ }
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.399 VSTM
+// Vector Store Multiple stores multiple extension registers to consecutive memory locations using an address from an
+// ARM core register.
+bool
+EmulateInstructionARM::EmulateVSTM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then R[n] else R[n]-imm32;
+ if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ for r = 0 to regs-1
+ if single_regs then
+ MemA[address,4] = S[d+r]; address = address+4;
+ else
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ address = address+8;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_regs;
+ bool add;
+ bool wback;
+ uint32_t d;
+ uint32_t n;
+ uint32_t imm32;
+ uint32_t regs;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VSTR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ single_regs = false;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFSTMXÓ.
+ regs = Bits32 (opcode, 7, 0) / 2;
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
+ return false;
+
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VSTR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn);
+ single_regs = true;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+ regs = Bits32 (opcode, 7, 0);
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet () != eModeARM)))
+ return false;
+
+ // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then R[n] else R[n]-imm32;
+ addr_t address;
+ if (add)
+ address = Rn;
+ else
+ address = Rn - imm32;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ if (wback)
+ {
+ uint32_t value;
+ if (add)
+ value = Rn + imm32;
+ else
+ value = Rn - imm32;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, value - Rn);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+ }
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+
+ context.type = eContextRegisterStore;
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+
+ if (single_regs)
+ {
+ // MemA[address,4] = S[d+r]; address = address+4;
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+
+ address = address + 4;
+ }
+ else
+ {
+ // // Store as two word-aligned words in the correct order for current endianness.
+ // MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg);
+
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address+ 4, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+ }
+ else
+ {
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+ }
+ // address = address+8;
+ address = address + 8;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.320
+// This instruciton loads a single extension register fronm memory, using an address from an ARM core register, with
+// an optional offset.
+bool
+EmulateInstructionARM::EmulateVLDR (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ base = if n == 15 then Align(PC,4) else R[n];
+ address = if add then (base + imm32) else (base - imm32);
+ if single_reg then
+ S[d] = MemA[address,4];
+ else
+ word1 = MemA[address,4]; word2 = MemA[address+4,4];
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d] = if BigEndian() then word1:word2 else word2:word1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_reg;
+ bool add;
+ uint32_t imm32;
+ uint32_t d;
+ uint32_t n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = false;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(D:Vd); n = UInt(Rn);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = true;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(Vd:D); n = UInt(Rn);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ break;
+
+ default:
+ return false;
+ }
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // base = if n == 15 then Align(PC,4) else R[n];
+ uint32_t base;
+ if (n == 15)
+ base = AlignPC (Rn);
+ else
+ base = Rn;
+
+ // address = if add then (base + imm32) else (base - imm32);
+ addr_t address;
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ if (single_reg)
+ {
+ // S[d] = MemA[address,4];
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data))
+ return false;
+ }
+ else
+ {
+ // word1 = MemA[address,4]; word2 = MemA[address+4,4];
+ uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - base);
+ uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // // Combine the word-aligned words in the correct order for current endianness.
+ // D[d] = if BigEndian() then word1:word2 else word2:word1;
+ uint64_t data64;
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ data64 = word1;
+ data64 = (data64 << 32) | word2;
+ }
+ else
+ {
+ data64 = word2;
+ data64 = (data64 << 32) | word1;
+ }
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data64))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.400 VSTR
+// This instruction stores a signle extension register to memory, using an address from an ARM core register, with an
+// optional offset.
+bool
+EmulateInstructionARM::EmulateVSTR (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then (R[n] + imm32) else (R[n] - imm32);
+ if single_reg then
+ MemA[address,4] = S[d];
+ else
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_reg;
+ bool add;
+ uint32_t imm32;
+ uint32_t d;
+ uint32_t n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = false;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(D:Vd); n = UInt(Rn);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
+ if ((n == 15) && (CurrentInstrSet() != eModeARM))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = true;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(Vd:D); n = UInt(Rn);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
+ if ((n == 15) && (CurrentInstrSet() != eModeARM))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then (R[n] + imm32) else (R[n] - imm32);
+ addr_t address;
+ if (add)
+ address = Rn + imm32;
+ else
+ address = Rn - imm32;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (single_reg)
+ {
+ // MemA[address,4] = S[d];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ // // Store as two word-aligned words in the correct order for current endianness.
+ // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
+ // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
+ uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success);
+ if (!success)
+ return false;
+
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+ }
+ else
+ {
+ if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.307 VLDI1 (multiple single elements)
+// This instruction loads elements from memory into one, two, three or four registers, without de-interleaving. Every
+// element of each register is loaded.
+bool
+EmulateInstructionARM::EmulateVLD1Multiple (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ for r = 0 to regs-1
+ for e = 0 to elements-1
+ Elem[D[d+r],e,esize] = MemU[address,ebytes];
+ address = address + ebytes;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t elements;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ // case type of
+ // when Ô0111Õ
+ // regs = 1; if align<1> == Ô1Õ then UNDEFINED;
+ // when Ô1010Õ
+ // regs = 2; if align == Ô11Õ then UNDEFINED;
+ // when Ô0110Õ
+ // regs = 3; if align<1> == Ô1Õ then UNDEFINED;
+ // when Ô0010Õ
+ // regs = 4;
+ // otherwise
+ // SEE ÒRelated encodingsÓ;
+ uint32_t type = Bits32 (opcode, 11, 8);
+ uint32_t align = Bits32 (opcode, 5, 4);
+ if (type == 7) // '0111'
+ {
+ regs = 1;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 10) // '1010'
+ {
+ regs = 2;
+ if (align == 3)
+ return false;
+
+ }
+ else if (type == 6) // '0110'
+ {
+ regs = 3;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 2) // '0010'
+ {
+ regs = 4;
+ }
+ else
+ return false;
+
+ // alignment = if align == Ô00Õ then 1 else 4 << UInt(align);
+ if (align == 0)
+ alignment = 1;
+ else
+ alignment = 4 << align;
+
+ // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
+ ebytes = 1 << Bits32 (opcode, 7, 6);
+ esize = 8 * ebytes;
+ elements = 8 / ebytes;
+
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 15);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ // if d+regs > 32 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = 8 * regs;
+
+ uint32_t value = Rn + offset;
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+
+ }
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ // for e = 0 to elements-1
+ uint64_t assembled_data = 0;
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ // Elem[D[d+r],e,esize] = MemU[address,ebytes];
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ uint64_t data = MemURead (context, address, ebytes, 0, &success);
+ if (!success)
+ return false;
+
+ assembled_data = (data << (e * esize)) | assembled_data; // New data goes to the left of existing data
+
+ // address = address + ebytes;
+ address = address + ebytes;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, assembled_data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.308 VLD1 (single element to one lane)
+//
+bool
+EmulateInstructionARM::EmulateVLD1Single (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ Elem[D[d],index,esize] = MemU[address,ebytes];
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t index;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t size = Bits32 (opcode, 11, 10);
+ uint32_t index_align = Bits32 (opcode, 7, 4);
+ // if size == Ô11Õ then SEE VLD1 (single element to all lanes);
+ if (size == 3)
+ return EmulateVLD1SingleAll (opcode, encoding);
+ // case size of
+ if (size == 0) // when '00'
+ {
+ // if index_align<0> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 0))
+ return false;
+
+ // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
+ ebytes = 1;
+ esize = 8;
+ index = Bits32 (index_align, 3, 1);
+ alignment = 1;
+ }
+ else if (size == 1) // when Ô01Õ
+ {
+ // if index_align<1> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 1))
+ return false;
+
+ // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
+ ebytes = 2;
+ esize = 16;
+ index = Bits32 (index_align, 3, 2);
+
+ // alignment = if index_align<0> == Ô0Õ then 1 else 2;
+ if (BitIsClear (index_align, 0))
+ alignment = 1;
+ else
+ alignment = 2;
+ }
+ else if (size == 2) // when Ô10Õ
+ {
+ // if index_align<2> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 2))
+ return false;
+
+ // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED;
+ if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3))
+ return false;
+
+ // ebytes = 4; esize = 32; index = UInt(index_align<3>);
+ ebytes = 4;
+ esize = 32;
+ index = Bit32 (index_align, 3);
+
+ // alignment = if index_align<1:0> == Ô00Õ then 1 else 4;
+ if (Bits32 (index_align, 1, 0) == 0)
+ alignment = 1;
+ else
+ alignment = 4;
+ }
+ else
+ {
+ return false;
+ }
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 then UNPREDICTABLE;
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ if (n == 15)
+ return false;
+
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ uint32_t value = Rn + offset;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+ }
+
+ // Elem[D[d],index,esize] = MemU[address,ebytes];
+ uint32_t element = MemURead (context, address, esize, 0, &success);
+ if (!success)
+ return false;
+
+ element = element << (index * esize);
+
+ uint64_t reg_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t all_ones = -1;
+ uint64_t mask = all_ones << ((index+1) * esize); // mask is all 1's to left of where 'element' goes, & all 0's
+ // at element & to the right of element.
+ if (index > 0)
+ mask = mask | Bits64 (all_ones, (index * esize) - 1, 0); // add 1's to the right of where 'element' goes.
+ // now mask should be 0's where element goes & 1's
+ // everywhere else.
+
+ uint64_t masked_reg = reg_data & mask; // Take original reg value & zero out 'element' bits
+ reg_data = masked_reg & element; // Put 'element' into those bits in reg_data.
+
+ context.type = eContextRegisterLoad;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, reg_data))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.391 VST1 (multiple single elements)
+// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four regsiters, without
+// interleaving. Every element of each register is stored.
+bool
+EmulateInstructionARM::EmulateVST1Multiple (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ for r = 0 to regs-1
+ for e = 0 to elements-1
+ MemU[address,ebytes] = Elem[D[d+r],e,esize];
+ address = address + ebytes;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t elements;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t type = Bits32 (opcode, 11, 8);
+ uint32_t align = Bits32 (opcode, 5, 4);
+
+ // case type of
+ if (type == 7) // when Ô0111Õ
+ {
+ // regs = 1; if align<1> == Ô1Õ then UNDEFINED;
+ regs = 1;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 10) // when Ô1010Õ
+ {
+ // regs = 2; if align == Ô11Õ then UNDEFINED;
+ regs = 2;
+ if (align == 3)
+ return false;
+ }
+ else if (type == 6) // when Ô0110Õ
+ {
+ // regs = 3; if align<1> == Ô1Õ then UNDEFINED;
+ regs = 3;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 2) // when Ô0010Õ
+ // regs = 4;
+ regs = 4;
+ else // otherwise
+ // SEE ÒRelated encodingsÓ;
+ return false;
+
+ // alignment = if align == Ô00Õ then 1 else 4 << UInt(align);
+ if (align == 0)
+ alignment = 1;
+ else
+ alignment = 4 << align;
+
+ // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
+ ebytes = 1 << Bits32 (opcode,7, 6);
+ esize = 8 * ebytes;
+ elements = 8 / ebytes;
+
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+
+ if (n == 15)
+ return false;
+
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = 8 * regs;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ RegisterInfo data_reg;
+ context.type = eContextRegisterStore;
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d + r, data_reg);
+ uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ // for e = 0 to elements-1
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ // MemU[address,ebytes] = Elem[D[d+r],e,esize];
+ uint64_t word = Bits64 (register_data, ((e + 1) * esize) - 1, e * esize);
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemUWrite (context, address, word, ebytes))
+ return false;
+
+ // address = address + ebytes;
+ address = address + ebytes;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.392 VST1 (single element from one lane)
+// This instruction stores one element to memory from one element of a register.
+bool
+EmulateInstructionARM::EmulateVST1Single (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ MemU[address,ebytes] = Elem[D[d],index,esize];
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t index;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t size = Bits32 (opcode, 11, 10);
+ uint32_t index_align = Bits32 (opcode, 7, 4);
+
+ // if size == Ô11Õ then UNDEFINED;
+ if (size == 3)
+ return false;
+
+ // case size of
+ if (size == 0) // when Ô00Õ
+ {
+ // if index_align<0> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 0))
+ return false;
+ // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
+ ebytes = 1;
+ esize = 8;
+ index = Bits32 (index_align, 3, 1);
+ alignment = 1;
+ }
+ else if (size == 1) // when Ô01Õ
+ {
+ // if index_align<1> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 1))
+ return false;
+
+ // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
+ ebytes = 2;
+ esize = 16;
+ index = Bits32 (index_align, 3, 2);
+
+ // alignment = if index_align<0> == Ô0Õ then 1 else 2;
+ if (BitIsClear (index_align, 0))
+ alignment = 1;
+ else
+ alignment = 2;
+ }
+ else if (size == 2) // when Ô10Õ
+ {
+ // if index_align<2> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 2))
+ return false;
+
+ // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED;
+ if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3))
+ return false;
+
+ // ebytes = 4; esize = 32; index = UInt(index_align<3>);
+ ebytes = 4;
+ esize = 32;
+ index = Bit32 (index_align, 3);
+
+ // alignment = if index_align<1:0> == Ô00Õ then 1 else 4;
+ if (Bits32 (index_align, 1, 0) == 0)
+ alignment = 1;
+ else
+ alignment = 4;
+ }
+ else
+ {
+ return false;
+ }
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 then UNPREDICTABLE;
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ if (n == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ // MemU[address,ebytes] = Elem[D[d],index,esize];
+ uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t word = Bits64 (register_data, ((index + 1) * esize) - 1, index * esize);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d, data_reg);
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (!MemUWrite (context, address, word, ebytes))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.309 VLD1 (single element to all lanes)
+// This instruction loads one element from memory into every element of one or two vectors.
+bool
+EmulateInstructionARM::EmulateVLD1SingleAll (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ replicated_element = Replicate(MemU[address,ebytes], elements);
+ for r = 0 to regs-1
+ D[d+r] = replicated_element;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t elements;
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ //if size == Ô11Õ || (size == Ô00Õ && a == Ô1Õ) then UNDEFINED;
+ uint32_t size = Bits32 (opcode, 7, 6);
+ if ((size == 3) || ((size == 0) && BitIsSet (opcode, 4)))
+ return false;
+
+ //ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == Ô0Õ then 1 else 2;
+ ebytes = 1 << size;
+ elements = 8 / ebytes;
+ if (BitIsClear (opcode, 5))
+ regs = 1;
+ else
+ regs = 2;
+
+ //alignment = if a == Ô0Õ then 1 else ebytes;
+ if (BitIsClear (opcode, 4))
+ alignment = 1;
+ else
+ alignment = ebytes;
+
+ //d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ //wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ //if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+
+ if (n == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ // replicated_element = Replicate(MemU[address,ebytes], elements);
+
+ context.type = eContextRegisterLoad;
+ uint64_t word = MemURead (context, address, ebytes, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t replicated_element = 0;
+ uint32_t esize = ebytes * 8;
+ for (uint32_t e = 0; e < elements; ++e)
+ replicated_element = (replicated_element << esize) | Bits64 (word, esize - 1, 0);
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ // D[d+r] = replicated_element;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, replicated_element))
+ return false;
+ }
+ }
+ return true;
+}
+
+// B6.2.13 SUBS PC, LR and related instructions
+//The SUBS PC, LR, #<const? instruction provides an exception return without the use of the stack. It subtracts the
+// immediate constant from the LR, branches to the resulting address, and also copies the SPSR to the CPSR.
+bool
+EmulateInstructionARM::EmulateSUBSPcLrEtc (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ if CurrentInstrSet() == InstrSet_ThumbEE then
+ UNPREDICTABLE;
+ operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32;
+ case opcode of
+ when Ô0000Õ result = R[n] AND operand2; // AND
+ when Ô0001Õ result = R[n] EOR operand2; // EOR
+ when Ô0010Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB
+ when Ô0011Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB
+ when Ô0100Õ (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD
+ when Ô0101Õ (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
+ when Ô0110Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
+ when Ô0111Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
+ when Ô1100Õ result = R[n] OR operand2; // ORR
+ when Ô1101Õ result = operand2; // MOV
+ when Ô1110Õ result = R[n] AND NOT(operand2); // BIC
+ when Ô1111Õ result = NOT(operand2); // MVN
+ CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE);
+ BranchWritePC(result);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t n;
+ uint32_t m;
+ uint32_t imm32;
+ bool register_form;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+ uint32_t code;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE
+ // n = 14; imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = Ô0010Õ; // = SUB
+ n = 14;
+ imm32 = Bits32 (opcode, 7, 0);
+ register_form = false;
+ code = 2;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = ARMExpandImm (opcode);
+ register_form = false;
+ code = Bits32 (opcode, 24, 21);
+
+ break;
+
+ case eEncodingA2:
+ // n = UInt(Rn); m = UInt(Rm); register_form = TRUE;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ register_form = true;
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32;
+ uint32_t operand2;
+ if (register_form)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ operand2 = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ }
+ else
+ {
+ operand2 = imm32;
+ }
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult result;
+
+ // case opcode of
+ switch (code)
+ {
+ case 0: // when Ô0000Õ
+ // result = R[n] AND operand2; // AND
+ result.result = Rn & operand2;
+ break;
+
+ case 1: // when Ô0001Õ
+ // result = R[n] EOR operand2; // EOR
+ result.result = Rn ^ operand2;
+ break;
+
+ case 2: // when Ô0010Õ
+ // (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB
+ result = AddWithCarry (Rn, ~(operand2), 1);
+ break;
+
+ case 3: // when Ô0011Õ
+ // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB
+ result = AddWithCarry (~(Rn), operand2, 1);
+ break;
+
+ case 4: // when Ô0100Õ
+ // (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD
+ result = AddWithCarry (Rn, operand2, 0);
+ break;
+
+ case 5: // when Ô0101Õ
+ // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
+ result = AddWithCarry (Rn, operand2, APSR_C);
+ break;
+
+ case 6: // when Ô0110Õ
+ // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
+ result = AddWithCarry (Rn, ~(operand2), APSR_C);
+ break;
+
+ case 7: // when Ô0111Õ
+ // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
+ result = AddWithCarry (~(Rn), operand2, APSR_C);
+ break;
+
+ case 10: // when Ô1100Õ
+ // result = R[n] OR operand2; // ORR
+ result.result = Rn | operand2;
+ break;
+
+ case 11: // when Ô1101Õ
+ // result = operand2; // MOV
+ result.result = operand2;
+ break;
+
+ case 12: // when Ô1110Õ
+ // result = R[n] AND NOT(operand2); // BIC
+ result.result = Rn & ~(operand2);
+ break;
+
+ case 15: // when Ô1111Õ
+ // result = NOT(operand2); // MVN
+ result.result = ~(operand2);
+ break;
+
+ default:
+ return false;
+ }
+ // CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE);
+
+ // For now, in emulation mode, we don't have access to the SPSR, so we will use the CPSR instead, and hope for
+ // the best.
+ uint32_t spsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_cpsr, 0, &success);
+ if (!success)
+ return false;
+
+ CPSRWriteByInstr (spsr, 15, true);
+
+ // BranchWritePC(result);
+ EmulateInstruction::Context context;
+ context.type = eContextAdjustPC;
+ context.SetImmediate (result.result);
+
+ BranchWritePC (context, result.result);
+ }
+ return true;
+}
+
+EmulateInstructionARM::ARMOpcode*
+EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa)
+{
+ static ARMOpcode
+ g_arm_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <registers>" },
+ { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <register>" },
+
+ // set r7 to point to a stack offset
+ { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #<const>" },
+ { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #<const>"},
+ // copy the stack pointer to ip
+ { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp" },
+ { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #<const>" },
+ { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #<const>"},
+
+ // adjust the stack pointer
+ { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #<const>"},
+ { 0x0fef0010, 0x004d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" },
+
+ // push one register
+ // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
+ { 0x0e5f0000, 0x040d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
+
+ // vector push consecutive extension register(s)
+ { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
+ { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Epilogue instructions
+ //----------------------------------------------------------------------
+
+ { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
+ { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <register>"},
+ { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
+ { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Supervisor Call (previously Software Interrupt)
+ //----------------------------------------------------------------------
+ { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"},
+ // To resolve ambiguity, "blx <label>" should come before "bl <label>".
+ { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
+ { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
+ { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
+ // for example, "bx lr"
+ { 0x0ffffff0, 0x012fff10, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
+ // bxj
+ { 0x0ffffff0, 0x012fff20, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Data-processing instructions
+ //----------------------------------------------------------------------
+ // adc (immediate)
+ { 0x0fe00000, 0x02a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"},
+ // adc (register)
+ { 0x0fe00010, 0x00a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (immediate)
+ { 0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmARM, "add{s}<c> <Rd>, <Rn>, #const"},
+ // add (register)
+ { 0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDReg, "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (register-shifted register)
+ { 0x0fe00090, 0x00800010, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRegShift, "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"},
+ // adr
+ { 0x0fff0000, 0x028f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ { 0x0fff0000, 0x024f0000, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
+ // and (immediate)
+ { 0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"},
+ // and (register)
+ { 0x0fe00010, 0x00000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // bic (immediate)
+ { 0x0fe00000, 0x03c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"},
+ // bic (register)
+ { 0x0fe00010, 0x01c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // eor (immediate)
+ { 0x0fe00000, 0x02200000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"},
+ // eor (register)
+ { 0x0fe00010, 0x00200000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // orr (immediate)
+ { 0x0fe00000, 0x03800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"},
+ // orr (register)
+ { 0x0fe00010, 0x01800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsb (immediate)
+ { 0x0fe00000, 0x02600000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"},
+ // rsb (register)
+ { 0x0fe00010, 0x00600000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsc (immediate)
+ { 0x0fe00000, 0x02e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"},
+ // rsc (register)
+ { 0x0fe00010, 0x00e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCReg, "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sbc (immediate)
+ { 0x0fe00000, 0x02c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
+ // sbc (register)
+ { 0x0fe00010, 0x00c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sub (immediate, ARM)
+ { 0x0fe00000, 0x02400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmARM, "sub{s}<c> <Rd>, <Rn>, #<const>"},
+ // sub (sp minus immediate)
+ { 0x0fef0000, 0x024d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"},
+ // sub (register)
+ { 0x0fe00010, 0x00400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"},
+ // teq (immediate)
+ { 0x0ff0f000, 0x03300000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"},
+ // teq (register)
+ { 0x0ff0f010, 0x01300000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
+ // tst (immediate)
+ { 0x0ff0f000, 0x03100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"},
+ // tst (register)
+ { 0x0ff0f010, 0x01100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"},
+
+ // mov (immediate)
+ { 0x0fef0000, 0x03a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c> <Rd>, #<const>"},
+ { 0x0ff00000, 0x03000000, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>, #<imm16>" },
+ // mov (register)
+ { 0x0fef0ff0, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"},
+ // mvn (immediate)
+ { 0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"},
+ // mvn (register)
+ { 0x0fef0010, 0x01e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c> <Rd>, <Rm> {,<shift>}"},
+ // cmn (immediate)
+ { 0x0ff0f000, 0x03700000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
+ // cmn (register)
+ { 0x0ff0f010, 0x01700000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
+ // cmp (immediate)
+ { 0x0ff0f000, 0x03500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"},
+ // cmp (register)
+ { 0x0ff0f010, 0x01500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"},
+ // asr (immediate)
+ { 0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"},
+ // asr (register)
+ { 0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"},
+ // lsl (immediate)
+ { 0x0fef0070, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"},
+ // lsl (register)
+ { 0x0fef00f0, 0x01a00010, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"},
+ // lsr (immediate)
+ { 0x0fef0070, 0x01a00020, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"},
+ // lsr (register)
+ { 0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"},
+ // rrx is a special case encoding of ror (immediate)
+ { 0x0fef0ff0, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"},
+ // ror (immediate)
+ { 0x0fef0070, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"},
+ // ror (register)
+ { 0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"},
+ // mul
+ { 0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>" },
+
+ // subs pc, lr and related instructions
+ { 0x0e10f000, 0x0210f000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,#<const> | <Rn>,#<const>" },
+ { 0x0e10f010, 0x0010f000, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,<Rn>,<Rm{,<shift>}" },
+
+ //----------------------------------------------------------------------
+ // Load instructions
+ //----------------------------------------------------------------------
+ { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" },
+ { 0x0e500000, 0x04100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRImmediateARM, "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]" },
+ { 0x0e500010, 0x06100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}" },
+ { 0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>, [...]"},
+ { 0xfe500010, 0x06500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}" },
+ { 0x0e5f00f0, 0x005f00b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" },
+ { 0x0e5000f0, 0x001000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x005000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]" },
+ { 0x0e5f00f0, 0x005f00d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt> <label>" },
+ { 0x0e5000f0, 0x001000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x005000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]"},
+ { 0x0e5f00f0, 0x005f00f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" },
+ { 0x0e5000f0, 0x001000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x004000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!"},
+ { 0x0e500ff0, 0x000000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDRegister, "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
+ { 0x0e100f00, 0x0c100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0x0e100f00, 0x0c100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0x0f300f00, 0x0d100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0x0f300f00, 0x0d100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf4200000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf4a00000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00f00, 0xf4a00c00, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Store instructions
+ //----------------------------------------------------------------------
+ { 0x0fd00000, 0x08800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x08000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDA, "stmda<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMIB, "stmib<c> <Rn>{!} <registers>" },
+ { 0x0e500010, 0x06000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}" },
+ { 0x0e5000f0, 0x000000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}" },
+ { 0x0ff00ff0, 0x01800f90, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn>]"},
+ { 0x0e500000, 0x04400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBImmARM, "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
+ { 0x0e500000, 0x04000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRImmARM, "str<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
+ { 0x0e5000f0, 0x004000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!"},
+ { 0x0e500ff0, 0x000000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDReg, "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
+ { 0x0e100f00, 0x0c000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
+ { 0x0e100f00, 0x0c000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
+ { 0x0f300f00, 0x0d000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]"},
+ { 0x0f300f00, 0x0d000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf4000000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf4800000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Other instructions
+ //----------------------------------------------------------------------
+ { 0x0fff00f0, 0x06af00f0, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06bf0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06ef0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" }
+
+ };
+ static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
+
+ for (size_t i=0; i<k_num_arm_opcodes; ++i)
+ {
+ if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value &&
+ (g_arm_opcodes[i].variants & arm_isa) != 0)
+ return &g_arm_opcodes[i];
+ }
+ return NULL;
+}
+
+
+EmulateInstructionARM::ARMOpcode*
+EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa)
+{
+
+ static ARMOpcode
+ g_thumb_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePUSH, "push <registers>" },
+ { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <registers>" },
+ { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <register>" },
+
+ // set r7 to point to a stack offset
+ { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm" },
+ // copy the stack pointer to r7
+ { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp" },
+ // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
+ { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15" },
+
+ // PC-relative load into register (see also EmulateADDSPRm)
+ { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"},
+
+ // adjust the stack pointer
+ { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPRm, "add sp, <Rm>"},
+ { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #imm"},
+ { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub.w sp, sp, #<const>"},
+ { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw sp, sp, #imm12"},
+ { 0xffef8000, 0xebad0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" },
+
+ // vector push consecutive extension register(s)
+ { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
+ { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Epilogue instructions
+ //----------------------------------------------------------------------
+
+ { 0xfffff800, 0x0000a800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add<c> <Rd>, sp, #imm"},
+ { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add sp, #imm"},
+ { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
+ { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <registers>" },
+ { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <register>" },
+ { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
+ { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Supervisor Call (previously Software Interrupt)
+ //----------------------------------------------------------------------
+ { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
+
+ //----------------------------------------------------------------------
+ // If Then makes up to four following instructions conditional.
+ //----------------------------------------------------------------------
+ // The next 5 opcode _must_ come before the if then instruction
+ { 0xffffffff, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop"},
+ { 0xffffffff, 0x0000bf10, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop YIELD (yield hint)"},
+ { 0xffffffff, 0x0000bf20, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFE (wait for event hint)"},
+ { 0xffffffff, 0x0000bf30, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFI (wait for interrupt hint)"},
+ { 0xffffffff, 0x0000bf40, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop SEV (send event hint)"},
+ { 0xffffff00, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
+ { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
+ { 0xfffff800, 0x0000e000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm11 (outside or last in IT)"},
+ { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
+ { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside or last in IT)"},
+ // J1 == J2 == 1
+ { 0xf800d000, 0xf000d000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
+ // J1 == J2 == 1
+ { 0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
+ { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
+ // for example, "bx lr"
+ { 0xffffff87, 0x00004700, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
+ // bxj
+ { 0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
+ // compare and branch
+ { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
+ // table branch byte
+ { 0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"},
+ // table branch halfword
+ { 0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"},
+
+ //----------------------------------------------------------------------
+ // Data-processing instructions
+ //----------------------------------------------------------------------
+ // adc (immediate)
+ { 0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"},
+ // adc (register)
+ { 0xffffffc0, 0x00004140, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADCReg, "adcs|adc<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xeb400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (register)
+ { 0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"},
+ // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
+ { 0xffffff00, 0x00004400, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"},
+ // adr
+ { 0xfffff800, 0x0000a000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ { 0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
+ { 0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ // and (immediate)
+ { 0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"},
+ // and (register)
+ { 0xffffffc0, 0x00004000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateANDReg, "ands|and<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea000000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // bic (immediate)
+ { 0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"},
+ // bic (register)
+ { 0xffffffc0, 0x00004380, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBICReg, "bics|bic<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // eor (immediate)
+ { 0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"},
+ // eor (register)
+ { 0xffffffc0, 0x00004040, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateEORReg, "eors|eor<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // orr (immediate)
+ { 0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"},
+ // orr (register)
+ { 0xffffffc0, 0x00004300, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateORRReg, "orrs|orr<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsb (immediate)
+ { 0xffffffc0, 0x00004240, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRSBImm, "rsbs|rsb<c> <Rd>, <Rn>, #0"},
+ { 0xfbe08000, 0xf1c00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c>.w <Rd>, <Rn>, #<const>"},
+ // rsb (register)
+ { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sbc (immediate)
+ { 0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
+ // sbc (register)
+ { 0xffffffc0, 0x00004180, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSBCReg, "sbcs|sbc<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xeb600000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (immediate, Thumb)
+ { 0xfffffe00, 0x00001c00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rd>,<Rn>,#<imm3>" },
+ { 0xfffff800, 0x00003000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rdn>,#<imm8>" },
+ { 0xfbe08000, 0xf1000000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "add{s}<c>.w <Rd>,<Rn>,#<const>" },
+ { 0xfbf08000, 0xf2000000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "addw<c> <Rd>,<Rn>,#<imm12>" },
+ // sub (immediate, Thumb)
+ { 0xfffffe00, 0x00001e00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rd>, <Rn> #imm3"},
+ { 0xfffff800, 0x00003800, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rdn>, #imm8"},
+ { 0xfbe08000, 0xf1a00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "sub{s}<c>.w <Rd>, <Rn>, #<const>"},
+ { 0xfbf08000, 0xf2a00000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "subw<c> <Rd>, <Rn>, #imm12"},
+ // sub (sp minus immediate)
+ { 0xfbef8000, 0xf1ad0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}.w <Rd>, sp, #<const>"},
+ { 0xfbff8000, 0xf2ad0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw<c> <Rd>, sp, #imm12"},
+ // sub (register)
+ { 0xfffffe00, 0x00001a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBReg, "subs|sub<c> <Rd>, <Rn>, <Rm>"},
+ { 0xffe08000, 0xeba00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}"},
+ // teq (immediate)
+ { 0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"},
+ // teq (register)
+ { 0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
+ // tst (immediate)
+ { 0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"},
+ // tst (register)
+ { 0xffffffc0, 0x00004200, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rdn>, <Rm>"},
+ { 0xfff08f00, 0xea100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c>.w <Rn>, <Rm> {,<shift>}"},
+
+
+ // move from high register to high register
+ { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"},
+ // move from low register to low register
+ { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"},
+ // mov{s}<c>.w <Rd>, <Rm>
+ { 0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"},
+ // move immediate
+ { 0xfffff800, 0x00002000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdImm, "movs|mov<c> <Rd>, #imm8"},
+ { 0xfbef8000, 0xf04f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c>.w <Rd>, #<const>"},
+ { 0xfbf08000, 0xf2400000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>,#<imm16>"},
+ // mvn (immediate)
+ { 0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"},
+ // mvn (register)
+ { 0xffffffc0, 0x000043c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMVNReg, "mvns|mvn<c> <Rd>, <Rm>"},
+ { 0xffef8000, 0xea6f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}"},
+ // cmn (immediate)
+ { 0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
+ // cmn (register)
+ { 0xffffffc0, 0x000042c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm>"},
+ { 0xfff08f00, 0xeb100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
+ // cmp (immediate)
+ { 0xfffff800, 0x00002800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #imm8"},
+ { 0xfbf08f00, 0xf1b00f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c>.w <Rn>, #<const>"},
+ // cmp (register) (Rn and Rm both from r0-r7)
+ { 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
+ // cmp (register) (Rn and Rm not both from r0-r7)
+ { 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
+ // asr (immediate)
+ { 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"},
+ // asr (register)
+ { 0xffffffc0, 0x00004100, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // lsl (immediate)
+ { 0xfffff800, 0x00000000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLImm, "lsls|lsl<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c>.w <Rd>, <Rm>, #imm"},
+ // lsl (register)
+ { 0xffffffc0, 0x00004080, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLReg, "lsls|lsl<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // lsr (immediate)
+ { 0xfffff800, 0x00000800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRImm, "lsrs|lsr<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0010, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c>.w <Rd>, <Rm>, #imm"},
+ // lsr (register)
+ { 0xffffffc0, 0x000040c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRReg, "lsrs|lsr<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa20f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // rrx is a special case encoding of ror (immediate)
+ { 0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"},
+ // ror (immediate)
+ { 0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"},
+ // ror (register)
+ { 0xffffffc0, 0x000041c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRORReg, "rors|ror<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa60f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // mul
+ { 0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>" },
+ // mul
+ { 0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>" },
+
+ // subs pc, lr and related instructions
+ { 0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>" },
+
+ //----------------------------------------------------------------------
+ // RFE instructions *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE LDM.. Instructions in this table;
+ // otherwise the wrong instructions will be selected.
+ //----------------------------------------------------------------------
+
+ { 0xffd0ffff, 0xe810c000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}" },
+ { 0xffd0ffff, 0xe990c000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}" },
+
+ //----------------------------------------------------------------------
+ // Load instructions
+ //----------------------------------------------------------------------
+ { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
+ { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
+ { 0xfffff800, 0x00006800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"},
+ { 0xfffff800, 0x00009800, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [SP{,#imm}]"},
+ { 0xfff00000, 0xf8d00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c>.w <Rt>, [<Rn>{,#imm12}]"},
+ { 0xfff00800, 0xf8500800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}"},
+ // Thumb2 PC-relative load into register
+ { 0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr<c>.w <Rt>, [PC, +/-#imm}]"},
+ { 0xfffffe00, 0x00005800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt>, [<Rn>, <Rm>]" },
+ { 0xfff00fc0, 0xf8500000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfffff800, 0x00007800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]" },
+ { 0xfff00000, 0xf8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]" },
+ { 0xfff00800, 0xf8100800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}" },
+ { 0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>,[...]" },
+ { 0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" },
+ { 0xfffff800, 0x00008800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>, [<Rn>{,#<imm>}]" },
+ { 0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]" },
+ { 0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}" },
+ { 0xff7f0000, 0xf83f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" },
+ { 0xfffffe00, 0x00005a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>, [<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfff00000, 0xf9900000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf9100800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]" },
+ { 0xff7f0000, 0xf91f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt>, <label>" },
+ { 0xfffffe00, 0x00005600, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf9100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" },
+ { 0xfff00000, 0xf9b00000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf9300800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]" },
+ { 0xff7f0000, 0xf93f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" },
+ { 0xfffffe00, 0x00005e00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf9300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfe500000, 0xe8500000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!"},
+ { 0xfe100f00, 0xec100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0xfe100f00, 0xec100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>" },
+ { 0xffe00f00, 0xed100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xff300f00, 0xed100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf9200000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
+ { 0xffb00300, 0xf9a00000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
+ { 0xffb00f00, 0xf9a00c00, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Store instructions
+ //----------------------------------------------------------------------
+ { 0xfffff800, 0x0000c000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c>.w <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe9000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" },
+ { 0xfffff800, 0x00006000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>{,#<imm>}]" },
+ { 0xfffff800, 0x00009000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [SP,#<imm>]" },
+ { 0xfff00000, 0xf8c00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c>.w <Rt>, [<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf8400800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>,#+/-<imm8>]" },
+ { 0xfffffe00, 0x00005000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> ,{<Rn>, <Rm>]" },
+ { 0xfff00fc0, 0xf8400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]" },
+ { 0xfffff800, 0x00007000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt>, [<Rn>, #<imm5>]" },
+ { 0xfff00000, 0xf8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c>.w <Rt>, [<Rn>, #<imm12>]" },
+ { 0xfff00800, 0xf8000800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}" },
+ { 0xfffffe00, 0x00005200, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfff00000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]" },
+ { 0xfe500000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!"},
+ { 0xfe100f00, 0xec000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
+ { 0xfea00f00, 0xec000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
+ { 0xff300f00, 0xed000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xff300f00, 0xed000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf9000000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf9800000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Other instructions
+ //----------------------------------------------------------------------
+ { 0xffffffc0, 0x0000b240, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa4ff080, ARMV6_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b200, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa0ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b2c0, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b280, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" },
+ };
+
+ const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
+ for (size_t i=0; i<k_num_thumb_opcodes; ++i)
+ {
+ if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value &&
+ (g_thumb_opcodes[i].variants & arm_isa) != 0)
+ return &g_thumb_opcodes[i];
+ }
+ return NULL;
+}
+
+bool
+EmulateInstructionARM::SetArchitecture (const ArchSpec &arch)
+{
+ m_arch = arch;
+ m_arm_isa = 0;
+ const char *arch_cstr = arch.GetArchitectureName ();
+ if (arch_cstr)
+ {
+ if (0 == ::strcasecmp(arch_cstr, "armv4t")) m_arm_isa = ARMv4T;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5tej")) m_arm_isa = ARMv5TEJ;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5te")) m_arm_isa = ARMv5TE;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5t")) m_arm_isa = ARMv5T;
+ else if (0 == ::strcasecmp(arch_cstr, "armv6k")) m_arm_isa = ARMv6K;
+ else if (0 == ::strcasecmp(arch_cstr, "armv6t2")) m_arm_isa = ARMv6T2;
+ else if (0 == ::strcasecmp(arch_cstr, "armv7s")) m_arm_isa = ARMv7S;
+ else if (0 == ::strcasecmp(arch_cstr, "arm")) m_arm_isa = ARMvAll;
+ else if (0 == ::strcasecmp(arch_cstr, "thumb")) m_arm_isa = ARMvAll;
+ else if (0 == ::strncasecmp(arch_cstr,"armv4", 5)) m_arm_isa = ARMv4;
+ else if (0 == ::strncasecmp(arch_cstr,"armv6", 5)) m_arm_isa = ARMv6;
+ else if (0 == ::strncasecmp(arch_cstr,"armv7", 5)) m_arm_isa = ARMv7;
+ else if (0 == ::strncasecmp(arch_cstr,"armv8", 5)) m_arm_isa = ARMv8;
+ }
+ return m_arm_isa != 0;
+}
+
+bool
+EmulateInstructionARM::SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target)
+{
+ if (EmulateInstruction::SetInstruction (insn_opcode, inst_addr, target))
+ {
+ if (m_arch.GetTriple().getArch() == llvm::Triple::thumb)
+ m_opcode_mode = eModeThumb;
+ else
+ {
+ AddressClass addr_class = inst_addr.GetAddressClass();
+
+ if ((addr_class == eAddressClassCode) || (addr_class == eAddressClassUnknown))
+ m_opcode_mode = eModeARM;
+ else if (addr_class == eAddressClassCodeAlternateISA)
+ m_opcode_mode = eModeThumb;
+ else
+ return false;
+ }
+ if (m_opcode_mode == eModeThumb)
+ m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T;
+ else
+ m_opcode_cpsr = CPSR_MODE_USR;
+ return true;
+ }
+ return false;
+}
+
+bool
+EmulateInstructionARM::ReadInstruction ()
+{
+ bool success = false;
+ m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
+ if (success)
+ {
+ addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
+ if (success)
+ {
+ Context read_inst_context;
+ read_inst_context.type = eContextReadOpcode;
+ read_inst_context.SetNoArgs ();
+
+ if (m_opcode_cpsr & MASK_CPSR_T)
+ {
+ m_opcode_mode = eModeThumb;
+ uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success);
+
+ if (success)
+ {
+ if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
+ {
+ m_opcode.SetOpcode16 (thumb_opcode);
+ }
+ else
+ {
+ m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success));
+ }
+ }
+ }
+ else
+ {
+ m_opcode_mode = eModeARM;
+ m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success));
+ }
+ }
+ }
+ if (!success)
+ {
+ m_opcode_mode = eModeInvalid;
+ m_addr = LLDB_INVALID_ADDRESS;
+ }
+ return success;
+}
+
+uint32_t
+EmulateInstructionARM::ArchVersion ()
+{
+ return m_arm_isa;
+}
+
+bool
+EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditional)
+{
+ // If we are ignoring conditions, then always return true.
+ // this allows us to iterate over disassembly code and still
+ // emulate an instruction even if we don't have all the right
+ // bits set in the CPSR register...
+ if (m_ignore_conditions)
+ return true;
+
+ if (is_conditional)
+ *is_conditional = true;
+
+ const uint32_t cond = CurrentCond (opcode);
+
+ if (cond == UINT32_MAX)
+ return false;
+
+ bool result = false;
+ switch (UnsignedBits(cond, 3, 1))
+ {
+ case 0:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_Z) != 0;
+ break;
+ case 1:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_C) != 0;
+ break;
+ case 2:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_N) != 0;
+ break;
+ case 3:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_V) != 0;
+ break;
+ case 4:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
+ break;
+ case 5:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ {
+ bool n = (m_opcode_cpsr & MASK_CPSR_N);
+ bool v = (m_opcode_cpsr & MASK_CPSR_V);
+ result = n == v;
+ }
+ break;
+ case 6:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ {
+ bool n = (m_opcode_cpsr & MASK_CPSR_N);
+ bool v = (m_opcode_cpsr & MASK_CPSR_V);
+ result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
+ }
+ break;
+ case 7:
+ // Always execute (cond == 0b1110, or the special 0b1111 which gives
+ // opcodes different meanings, but always means execution happpens.
+ if (is_conditional)
+ *is_conditional = false;
+ result = true;
+ break;
+ }
+
+ if (cond & 1)
+ result = !result;
+ return result;
+}
+
+uint32_t
+EmulateInstructionARM::CurrentCond (const uint32_t opcode)
+{
+ switch (m_opcode_mode)
+ {
+ case eModeInvalid:
+ break;
+
+ case eModeARM:
+ return UnsignedBits(opcode, 31, 28);
+
+ case eModeThumb:
+ // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
+ // 'cond' field of the encoding.
+ {
+ const uint32_t byte_size = m_opcode.GetByteSize();
+ if (byte_size == 2)
+ {
+ if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 7) != 0x0f)
+ return Bits32(opcode, 11, 7);
+ }
+ else if (byte_size == 4)
+ {
+ if (Bits32(opcode, 31, 27) == 0x1e &&
+ Bits32(opcode, 15, 14) == 0x02 &&
+ Bits32(opcode, 12, 12) == 0x00 &&
+ Bits32(opcode, 25, 22) <= 0x0d)
+ {
+ return Bits32(opcode, 25, 22);
+ }
+ }
+ else
+ // We have an invalid thumb instruction, let's bail out.
+ break;
+
+ return m_it_session.GetCond();
+ }
+ }
+ return UINT32_MAX; // Return invalid value
+}
+
+bool
+EmulateInstructionARM::InITBlock()
+{
+ return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock();
+}
+
+bool
+EmulateInstructionARM::LastInITBlock()
+{
+ return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock();
+}
+
+bool
+EmulateInstructionARM::BadMode (uint32_t mode)
+{
+
+ switch (mode)
+ {
+ case 16: return false; // '10000'
+ case 17: return false; // '10001'
+ case 18: return false; // '10010'
+ case 19: return false; // '10011'
+ case 22: return false; // '10110'
+ case 23: return false; // '10111'
+ case 27: return false; // '11011'
+ case 31: return false; // '11111'
+ default: return true;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::CurrentModeIsPrivileged ()
+{
+ uint32_t mode = Bits32 (m_opcode_cpsr, 4, 0);
+
+ if (BadMode (mode))
+ return false;
+
+ if (mode == 16)
+ return false;
+
+ return true;
+}
+
+void
+EmulateInstructionARM::CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate)
+{
+ bool privileged = CurrentModeIsPrivileged();
+
+ uint32_t tmp_cpsr = Bits32 (m_opcode_cpsr, 23, 20) << 20;
+
+ if (BitIsSet (bytemask, 3))
+ {
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 31, 27) << 27);
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 26, 24) << 24);
+ }
+
+ if (BitIsSet (bytemask, 2))
+ {
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 19, 16) << 16);
+ }
+
+ if (BitIsSet (bytemask, 1))
+ {
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 15, 10) << 10);
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 9) << 9);
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 8) << 8);
+ }
+
+ if (BitIsSet (bytemask, 0))
+ {
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 7, 6) << 6);
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 5) << 5);
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | Bits32 (value, 4, 0);
+ }
+
+ m_opcode_cpsr = tmp_cpsr;
+}
+
+
+bool
+EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
+{
+ addr_t target;
+
+ // Check the current instruction set.
+ if (CurrentInstrSet() == eModeARM)
+ target = addr & 0xfffffffc;
+ else
+ target = addr & 0xfffffffe;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
+ return false;
+
+ return true;
+}
+
+// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
+bool
+EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
+{
+ addr_t target;
+ // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
+ // we want to record it and issue a WriteRegister callback so the clients
+ // can track the mode changes accordingly.
+ bool cpsr_changed = false;
+
+ if (BitIsSet(addr, 0))
+ {
+ if (CurrentInstrSet() != eModeThumb)
+ {
+ SelectInstrSet(eModeThumb);
+ cpsr_changed = true;
+ }
+ target = addr & 0xfffffffe;
+ context.SetISA (eModeThumb);
+ }
+ else if (BitIsClear(addr, 1))
+ {
+ if (CurrentInstrSet() != eModeARM)
+ {
+ SelectInstrSet(eModeARM);
+ cpsr_changed = true;
+ }
+ target = addr & 0xfffffffc;
+ context.SetISA (eModeARM);
+ }
+ else
+ return false; // address<1:0> == '10' => UNPREDICTABLE
+
+ if (cpsr_changed)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
+ return false;
+
+ return true;
+}
+
+// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
+bool
+EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
+{
+ if (ArchVersion() >= ARMv5T)
+ return BXWritePC(context, addr);
+ else
+ return BranchWritePC((const Context)context, addr);
+}
+
+// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
+bool
+EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
+{
+ if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
+ return BXWritePC(context, addr);
+ else
+ return BranchWritePC((const Context)context, addr);
+}
+
+EmulateInstructionARM::Mode
+EmulateInstructionARM::CurrentInstrSet ()
+{
+ return m_opcode_mode;
+}
+
+// Set the 'T' bit of our CPSR. The m_opcode_mode gets updated when the next
+// ReadInstruction() is performed. This function has a side effect of updating
+// the m_new_inst_cpsr member variable if necessary.
+bool
+EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
+{
+ m_new_inst_cpsr = m_opcode_cpsr;
+ switch (arm_or_thumb)
+ {
+ default:
+ return false;
+ case eModeARM:
+ // Clear the T bit.
+ m_new_inst_cpsr &= ~MASK_CPSR_T;
+ break;
+ case eModeThumb:
+ // Set the T bit.
+ m_new_inst_cpsr |= MASK_CPSR_T;
+ break;
+ }
+ return true;
+}
+
+// This function returns TRUE if the processor currently provides support for
+// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
+// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
+bool
+EmulateInstructionARM::UnalignedSupport()
+{
+ return (ArchVersion() >= ARMv7);
+}
+
+// The main addition and subtraction instructions can produce status information
+// about both unsigned carry and signed overflow conditions. This status
+// information can be used to synthesize multi-word additions and subtractions.
+EmulateInstructionARM::AddWithCarryResult
+EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
+{
+ uint32_t result;
+ uint8_t carry_out;
+ uint8_t overflow;
+
+ uint64_t unsigned_sum = x + y + carry_in;
+ int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
+
+ result = UnsignedBits(unsigned_sum, 31, 0);
+// carry_out = (result == unsigned_sum ? 0 : 1);
+ overflow = ((int32_t)result == signed_sum ? 0 : 1);
+
+ if (carry_in)
+ carry_out = ((int32_t) x >= (int32_t) (~y)) ? 1 : 0;
+ else
+ carry_out = ((int32_t) x > (int32_t) y) ? 1 : 0;
+
+ AddWithCarryResult res = { result, carry_out, overflow };
+ return res;
+}
+
+uint32_t
+EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success)
+{
+ uint32_t reg_kind, reg_num;
+ switch (num)
+ {
+ case SP_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ break;
+ case LR_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_RA;
+ break;
+ case PC_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ default:
+ if (num < SP_REG)
+ {
+ reg_kind = eRegisterKindDWARF;
+ reg_num = dwarf_r0 + num;
+ }
+ else
+ {
+ //assert(0 && "Invalid register number");
+ *success = false;
+ return UINT32_MAX;
+ }
+ break;
+ }
+
+ // Read our register.
+ uint32_t val = ReadRegisterUnsigned (reg_kind, reg_num, 0, success);
+
+ // When executing an ARM instruction , PC reads as the address of the current
+ // instruction plus 8.
+ // When executing a Thumb instruction , PC reads as the address of the current
+ // instruction plus 4.
+ if (num == 15)
+ {
+ if (CurrentInstrSet() == eModeARM)
+ val += 8;
+ else
+ val += 4;
+ }
+
+ return val;
+}
+
+// Write the result to the ARM core register Rd, and optionally update the
+// condition flags based on the result.
+//
+// This helper method tries to encapsulate the following pseudocode from the
+// ARM Architecture Reference Manual:
+//
+// if d == 15 then // Can only occur for encoding A1
+// ALUWritePC(result); // setflags is always FALSE here
+// else
+// R[d] = result;
+// if setflags then
+// APSR.N = result<31>;
+// APSR.Z = IsZeroBit(result);
+// APSR.C = carry;
+// // APSR.V unchanged
+//
+// In the above case, the API client does not pass in the overflow arg, which
+// defaults to ~0u.
+bool
+EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context,
+ const uint32_t result,
+ const uint32_t Rd,
+ bool setflags,
+ const uint32_t carry,
+ const uint32_t overflow)
+{
+ if (Rd == 15)
+ {
+ if (!ALUWritePC (context, result))
+ return false;
+ }
+ else
+ {
+ uint32_t reg_kind, reg_num;
+ switch (Rd)
+ {
+ case SP_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ break;
+ case LR_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_RA;
+ break;
+ default:
+ reg_kind = eRegisterKindDWARF;
+ reg_num = dwarf_r0 + Rd;
+ }
+ if (!WriteRegisterUnsigned (context, reg_kind, reg_num, result))
+ return false;
+ if (setflags)
+ return WriteFlags (context, result, carry, overflow);
+ }
+ return true;
+}
+
+// This helper method tries to encapsulate the following pseudocode from the
+// ARM Architecture Reference Manual:
+//
+// APSR.N = result<31>;
+// APSR.Z = IsZeroBit(result);
+// APSR.C = carry;
+// APSR.V = overflow
+//
+// Default arguments can be specified for carry and overflow parameters, which means
+// not to update the respective flags.
+bool
+EmulateInstructionARM::WriteFlags (Context &context,
+ const uint32_t result,
+ const uint32_t carry,
+ const uint32_t overflow)
+{
+ m_new_inst_cpsr = m_opcode_cpsr;
+ SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS));
+ SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
+ if (carry != ~0u)
+ SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry);
+ if (overflow != ~0u)
+ SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow);
+ if (m_new_inst_cpsr != m_opcode_cpsr)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EvaluateInstruction (uint32_t evaluate_options)
+{
+ // Advance the ITSTATE bits to their values for the next instruction.
+ if (m_opcode_mode == eModeThumb && m_it_session.InITBlock())
+ m_it_session.ITAdvance();
+
+ ARMOpcode *opcode_data = NULL;
+
+ if (m_opcode_mode == eModeThumb)
+ opcode_data = GetThumbOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa);
+ else if (m_opcode_mode == eModeARM)
+ opcode_data = GetARMOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa);
+
+ if (opcode_data == NULL)
+ return false;
+
+ const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
+ m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions;
+
+ bool success = false;
+ if (m_opcode_cpsr == 0 || m_ignore_conditions == false)
+ {
+ m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindDWARF,
+ dwarf_cpsr,
+ 0,
+ &success);
+ }
+
+ // Only return false if we are unable to read the CPSR if we care about conditions
+ if (success == false && m_ignore_conditions == false)
+ return false;
+
+ uint32_t orig_pc_value = 0;
+ if (auto_advance_pc)
+ {
+ orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success);
+ if (!success)
+ return false;
+ }
+
+ // Call the Emulate... function.
+ success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc)
+ {
+ uint32_t after_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc && (after_pc_value == orig_pc_value))
+ {
+ if (opcode_data->size == eSize32)
+ after_pc_value += 4;
+ else if (opcode_data->size == eSize16)
+ after_pc_value += 2;
+
+ EmulateInstruction::Context context;
+ context.type = eContextAdvancePC;
+ context.SetNoArgs();
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc, after_pc_value))
+ return false;
+
+ }
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data)
+{
+ if (!test_data)
+ {
+ out_stream->Printf ("TestEmulation: Missing test data.\n");
+ return false;
+ }
+
+ static ConstString opcode_key ("opcode");
+ static ConstString before_key ("before_state");
+ static ConstString after_key ("after_state");
+
+ OptionValueSP value_sp = test_data->GetValueForKey (opcode_key);
+
+ uint32_t test_opcode;
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeUInt64))
+ {
+ out_stream->Printf ("TestEmulation: Error reading opcode from test file.\n");
+ return false;
+ }
+ test_opcode = value_sp->GetUInt64Value ();
+
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ m_opcode_mode = eModeARM;
+ m_opcode.SetOpcode32 (test_opcode);
+ }
+ else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ m_opcode_mode = eModeThumb;
+ if (test_opcode < 0x10000)
+ m_opcode.SetOpcode16 (test_opcode);
+ else
+ m_opcode.SetOpcode32 (test_opcode);
+
+ }
+ else
+ {
+ out_stream->Printf ("TestEmulation: Invalid arch.\n");
+ return false;
+ }
+
+ EmulationStateARM before_state;
+ EmulationStateARM after_state;
+
+ value_sp = test_data->GetValueForKey (before_key);
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed to find 'before' state.\n");
+ return false;
+ }
+
+ OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary ();
+ if (!before_state.LoadStateFromDictionary (state_dictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed loading 'before' state.\n");
+ return false;
+ }
+
+ value_sp = test_data->GetValueForKey (after_key);
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed to find 'after' state.\n");
+ return false;
+ }
+
+ state_dictionary = value_sp->GetAsDictionary ();
+ if (!after_state.LoadStateFromDictionary (state_dictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed loading 'after' state.\n");
+ return false;
+ }
+
+ SetBaton ((void *) &before_state);
+ SetCallbacks (&EmulationStateARM::ReadPseudoMemory,
+ &EmulationStateARM::WritePseudoMemory,
+ &EmulationStateARM::ReadPseudoRegister,
+ &EmulationStateARM::WritePseudoRegister);
+
+ bool success = EvaluateInstruction (eEmulateInstructionOptionAutoAdvancePC);
+ if (!success)
+ {
+ out_stream->Printf ("TestEmulation: EvaluateInstruction() failed.\n");
+ return false;
+ }
+
+ success = before_state.CompareState (after_state);
+ if (!success)
+ out_stream->Printf ("TestEmulation: 'before' and 'after' states do not match.\n");
+
+ return success;
+}
+//
+//
+//const char *
+//EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num)
+//{
+// if (reg_kind == eRegisterKindGeneric)
+// {
+// switch (reg_num)
+// {
+// case LLDB_REGNUM_GENERIC_PC: return "pc";
+// case LLDB_REGNUM_GENERIC_SP: return "sp";
+// case LLDB_REGNUM_GENERIC_FP: return "fp";
+// case LLDB_REGNUM_GENERIC_RA: return "lr";
+// case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr";
+// default: return NULL;
+// }
+// }
+// else if (reg_kind == eRegisterKindDWARF)
+// {
+// return GetARMDWARFRegisterName (reg_num);
+// }
+// return NULL;
+//}
+//
+bool
+EmulateInstructionARM::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our previous Call Frame Address is the stack pointer
+ row->SetCFARegister (dwarf_sp);
+
+ // Our previous PC is in the LR
+ row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true);
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("EmulateInstructionARM");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ return true;
+}
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
new file mode 100644
index 000000000000..b926dc0deb4a
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -0,0 +1,990 @@
+//===-- lldb_EmulateInstructionARM.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulateInstructionARM_h_
+#define lldb_EmulateInstructionARM_h_
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+namespace lldb_private {
+
+// ITSession - Keep track of the IT Block progression.
+class ITSession
+{
+public:
+ ITSession() : ITCounter(0), ITState(0) {}
+ ~ITSession() {}
+
+ // InitIT - Initializes ITCounter/ITState.
+ bool InitIT(uint32_t bits7_0);
+
+ // ITAdvance - Updates ITCounter/ITState as IT Block progresses.
+ void ITAdvance();
+
+ // InITBlock - Returns true if we're inside an IT Block.
+ bool InITBlock();
+
+ // LastInITBlock - Returns true if we're the last instruction inside an IT Block.
+ bool LastInITBlock();
+
+ // GetCond - Gets condition bits for the current thumb instruction.
+ uint32_t GetCond();
+
+private:
+ uint32_t ITCounter; // Possible values: 0, 1, 2, 3, 4.
+ uint32_t ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially.
+};
+
+class EmulateInstructionARM : public EmulateInstruction
+{
+public:
+ typedef enum
+ {
+ eEncodingA1,
+ eEncodingA2,
+ eEncodingA3,
+ eEncodingA4,
+ eEncodingA5,
+ eEncodingT1,
+ eEncodingT2,
+ eEncodingT3,
+ eEncodingT4,
+ eEncodingT5
+ } ARMEncoding;
+
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetPluginDescriptionStatic ();
+
+ static lldb_private::EmulateInstruction *
+ CreateInstance (const lldb_private::ArchSpec &arch,
+ InstructionType inst_type);
+
+ static bool
+ SupportsEmulatingIntructionsOfTypeStatic (InstructionType inst_type)
+ {
+ switch (inst_type)
+ {
+ case eInstructionTypeAny:
+ case eInstructionTypePrologueEpilogue:
+ case eInstructionTypePCModifying:
+ return true;
+
+ case eInstructionTypeAll:
+ return false;
+ }
+ return false;
+ }
+
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+ bool
+ SetTargetTriple (const ArchSpec &arch);
+
+ enum Mode
+ {
+ eModeInvalid = -1,
+ eModeARM,
+ eModeThumb
+ };
+
+ EmulateInstructionARM (const ArchSpec &arch) :
+ EmulateInstruction (arch),
+ m_arm_isa (0),
+ m_opcode_mode (eModeInvalid),
+ m_opcode_cpsr (0),
+ m_it_session (),
+ m_ignore_conditions (false)
+ {
+ SetArchitecture (arch);
+ }
+
+// EmulateInstructionARM (const ArchSpec &arch,
+// bool ignore_conditions,
+// void *baton,
+// ReadMemory read_mem_callback,
+// WriteMemory write_mem_callback,
+// ReadRegister read_reg_callback,
+// WriteRegister write_reg_callback) :
+// EmulateInstruction (arch,
+// ignore_conditions,
+// baton,
+// read_mem_callback,
+// write_mem_callback,
+// read_reg_callback,
+// write_reg_callback),
+// m_arm_isa (0),
+// m_opcode_mode (eModeInvalid),
+// m_opcode_cpsr (0),
+// m_it_session ()
+// {
+// }
+
+ virtual bool
+ SupportsEmulatingIntructionsOfType (InstructionType inst_type)
+ {
+ return SupportsEmulatingIntructionsOfTypeStatic (inst_type);
+ }
+
+ virtual bool
+ SetArchitecture (const ArchSpec &arch);
+
+ virtual bool
+ ReadInstruction ();
+
+ virtual bool
+ SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target);
+
+ virtual bool
+ EvaluateInstruction (uint32_t evaluate_options);
+
+ virtual bool
+ TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data);
+
+ virtual bool
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info);
+
+
+ virtual bool
+ CreateFunctionEntryUnwind (UnwindPlan &unwind_plan);
+
+ uint32_t
+ ArchVersion();
+
+ bool
+ ConditionPassed (const uint32_t opcode,
+ bool *is_conditional = NULL); // Filled in with true if the opcode is a conditional opcode
+ // Filled in with false if the opcode is always executed
+
+ uint32_t
+ CurrentCond (const uint32_t opcode);
+
+ // InITBlock - Returns true if we're in Thumb mode and inside an IT Block.
+ bool InITBlock();
+
+ // LastInITBlock - Returns true if we're in Thumb mode and the last instruction inside an IT Block.
+ bool LastInITBlock();
+
+ bool
+ BadMode (uint32_t mode);
+
+ bool
+ CurrentModeIsPrivileged ();
+
+ void
+ CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate);
+
+ bool
+ BranchWritePC(const Context &context, uint32_t addr);
+
+ bool
+ BXWritePC(Context &context, uint32_t addr);
+
+ bool
+ LoadWritePC(Context &context, uint32_t addr);
+
+ bool
+ ALUWritePC(Context &context, uint32_t addr);
+
+ Mode
+ CurrentInstrSet();
+
+ bool
+ SelectInstrSet(Mode arm_or_thumb);
+
+ bool
+ WriteBits32Unknown (int n);
+
+ bool
+ WriteBits32UnknownToMemory (lldb::addr_t address);
+
+ bool
+ UnalignedSupport();
+
+ typedef struct
+ {
+ uint32_t result;
+ uint8_t carry_out;
+ uint8_t overflow;
+ } AddWithCarryResult;
+
+ AddWithCarryResult
+ AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in);
+
+ // Helper method to read the content of an ARM core register.
+ uint32_t
+ ReadCoreReg (uint32_t regnum, bool *success);
+
+ // See A8.6.96 MOV (immediate) Operation.
+ // Default arguments are specified for carry and overflow parameters, which means
+ // not to update the respective flags even if setflags is true.
+ bool
+ WriteCoreRegOptionalFlags (Context &context,
+ const uint32_t result,
+ const uint32_t Rd,
+ bool setflags,
+ const uint32_t carry = ~0u,
+ const uint32_t overflow = ~0u);
+
+ bool
+ WriteCoreReg (Context &context,
+ const uint32_t result,
+ const uint32_t Rd)
+ {
+ // Don't set the flags.
+ return WriteCoreRegOptionalFlags(context, result, Rd, false);
+ }
+
+ // See A8.6.35 CMP (immediate) Operation.
+ // Default arguments are specified for carry and overflow parameters, which means
+ // not to update the respective flags.
+ bool
+ WriteFlags (Context &context,
+ const uint32_t result,
+ const uint32_t carry = ~0u,
+ const uint32_t overflow = ~0u);
+
+ inline uint64_t
+ MemARead (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint32_t size,
+ uint64_t fail_value,
+ bool *success_ptr)
+ {
+ // This is a stub function corresponding to "MemA[]" in the ARM manual pseudocode, for
+ // aligned reads from memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // ReadMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return ReadMemoryUnsigned (context, address, size, fail_value, success_ptr);
+ }
+
+ inline bool
+ MemAWrite (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint64_t data_val,
+ uint32_t size)
+
+ {
+ // This is a stub function corresponding to "MemA[]" in the ARM manual pseudocode, for
+ // aligned writes to memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // WriteMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return WriteMemoryUnsigned (context, address, data_val, size);
+ }
+
+
+ inline uint64_t
+ MemURead (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint32_t size,
+ uint64_t fail_value,
+ bool *success_ptr)
+ {
+ // This is a stub function corresponding to "MemU[]" in the ARM manual pseudocode, for
+ // unaligned reads from memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // ReadMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return ReadMemoryUnsigned (context, address, size, fail_value, success_ptr);
+ }
+
+ inline bool
+ MemUWrite (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint64_t data_val,
+ uint32_t size)
+
+ {
+ // This is a stub function corresponding to "MemU[]" in the ARM manual pseudocode, for
+ // unaligned writes to memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // WriteMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return WriteMemoryUnsigned (context, address, data_val, size);
+ }
+
+protected:
+
+ // Typedef for the callback function used during the emulation.
+ // Pass along (ARMEncoding)encoding as the callback data.
+ typedef enum
+ {
+ eSize16,
+ eSize32
+ } ARMInstrSize;
+
+ typedef struct
+ {
+ uint32_t mask;
+ uint32_t value;
+ uint32_t variants;
+ EmulateInstructionARM::ARMEncoding encoding;
+ uint32_t vfp_variants;
+ ARMInstrSize size;
+ bool (EmulateInstructionARM::*callback) (const uint32_t opcode, const EmulateInstructionARM::ARMEncoding encoding);
+ const char *name;
+ } ARMOpcode;
+
+ uint32_t
+ GetFramePointerRegisterNumber () const;
+
+ uint32_t
+ GetFramePointerDWARFRegisterNumber () const;
+
+ static ARMOpcode*
+ GetARMOpcodeForInstruction (const uint32_t opcode, uint32_t isa_mask);
+
+ static ARMOpcode*
+ GetThumbOpcodeForInstruction (const uint32_t opcode, uint32_t isa_mask);
+
+ // A8.6.123 PUSH
+ bool
+ EmulatePUSH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.122 POP
+ bool
+ EmulatePOP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.8 ADD (SP plus immediate)
+ bool
+ EmulateADDRdSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register) -- Rd == r7|ip and Rm == sp
+ bool
+ EmulateMOVRdSP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register) -- move from r8-r15 to r0-r7
+ bool
+ EmulateMOVLowHigh (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.59 LDR (literal)
+ bool
+ EmulateLDRRtPCRelative (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.8 ADD (SP plus immediate)
+ bool
+ EmulateADDSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.9 ADD (SP plus register)
+ bool
+ EmulateADDSPRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.23 BL, BLX (immediate)
+ bool
+ EmulateBLXImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.24 BLX (register)
+ bool
+ EmulateBLXRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.25 BX
+ bool
+ EmulateBXRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.26 BXJ
+ bool
+ EmulateBXJRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.212 SUB (immediate, ARM) -- Rd == r7 and Rm == ip
+ bool
+ EmulateSUBR7IPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.215 SUB (SP minus immediate) -- Rd == ip
+ bool
+ EmulateSUBIPSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.215 SUB (SP minus immediate)
+ bool
+ EmulateSUBSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.216 SUB (SP minus register)
+ bool
+ EmulateSUBSPReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.194 STR (immediate, ARM) -- Rn == sp
+ bool
+ EmulateSTRRtSP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.355 VPUSH
+ bool
+ EmulateVPUSH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.354 VPOP
+ bool
+ EmulateVPOP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.218 SVC (previously SWI)
+ bool
+ EmulateSVC (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.50 IT
+ bool
+ EmulateIT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // NOP
+ bool
+ EmulateNop (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.16 B
+ bool
+ EmulateB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.27 CBNZ, CBZ
+ bool
+ EmulateCB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.226 TBB, TBH
+ bool
+ EmulateTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.4 ADD (immediate, Thumb)
+ bool
+ EmulateADDImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.5 ADD (immediate, ARM)
+ bool
+ EmulateADDImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.6 ADD (register)
+ bool
+ EmulateADDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.7 ADD (register-shifted register)
+ bool
+ EmulateADDRegShift (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register)
+ bool
+ EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.96 MOV (immediate)
+ bool
+ EmulateMOVRdImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.35 CMP (immediate)
+ bool
+ EmulateCMPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.36 CMP (register)
+ bool
+ EmulateCMPReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.14 ASR (immediate)
+ bool
+ EmulateASRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.15 ASR (register)
+ bool
+ EmulateASRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.88 LSL (immediate)
+ bool
+ EmulateLSLImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.89 LSL (register)
+ bool
+ EmulateLSLReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.90 LSR (immediate)
+ bool
+ EmulateLSRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.91 LSR (register)
+ bool
+ EmulateLSRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.139 ROR (immediate)
+ bool
+ EmulateRORImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.140 ROR (register)
+ bool
+ EmulateRORReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.141 RRX
+ bool
+ EmulateRRX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // Helper method for ASR, LSL, LSR, ROR (immediate), and RRX
+ bool
+ EmulateShiftImm (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type);
+
+ // Helper method for ASR, LSL, LSR, and ROR (register)
+ bool
+ EmulateShiftReg (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type);
+
+ // LOAD FUNCTIONS
+
+ // A8.6.53 LDM/LDMIA/LDMFD
+ bool
+ EmulateLDM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.54 LDMDA/LDMFA
+ bool
+ EmulateLDMDA (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.55 LDMDB/LDMEA
+ bool
+ EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.56 LDMIB/LDMED
+ bool
+ EmulateLDMIB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.57 LDR (immediate, Thumb) -- Encoding T1
+ bool
+ EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.58 LDR (immediate, ARM) - Encoding A1
+ bool
+ EmulateLDRImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.59 LDR (literal)
+ bool
+ EmulateLDRLiteral (const uint32_t, const ARMEncoding encoding);
+
+ // A8.6.60 LDR (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.61 LDRB (immediate, Thumb) - Encoding T1, T2, T3
+ bool
+ EmulateLDRBImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.62 LDRB (immediate, ARM)
+ bool
+ EmulateLDRBImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.63 LDRB (literal) - Encoding T1, A1
+ bool
+ EmulateLDRBLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.64 LDRB (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRBRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.65 LDRBT
+ bool
+ EmulateLDRBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.66 LDRD (immediate)
+ bool
+ EmulateLDRDImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.67
+ bool
+ EmulateLDRDLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.68 LDRD (register)
+ bool
+ EmulateLDRDRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.69 LDREX
+ bool
+ EmulateLDREX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.70 LDREXB
+ bool
+ EmulateLDREXB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.71 LDREXD
+ bool
+ EmulateLDREXD (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.72 LDREXH
+ bool
+ EmulateLDREXH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.73 LDRH (immediate, Thumb) - Encoding T1, T2, T3
+ bool
+ EmulateLDRHImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.74 LDRS (immediate, ARM)
+ bool
+ EmulateLDRHImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.75 LDRH (literal) - Encoding T1, A1
+ bool
+ EmulateLDRHLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.76 LDRH (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.77 LDRHT
+ bool
+ EmulateLDRHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.78 LDRSB (immediate) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSBImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.79 LDRSB (literal) - Encoding T1, A1
+ bool
+ EmulateLDRSBLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.80 LDRSB (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSBRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.81 LDRSBT
+ bool
+ EmulateLDRSBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.82 LDRSH (immediate) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSHImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.83 LDRSH (literal) - Encoding T1, A1
+ bool
+ EmulateLDRSHLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.84 LDRSH (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.85 LDRSHT
+ bool
+ EmulateLDRSHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.86
+ bool
+ EmulateLDRT (const uint32_t opcode, const ARMEncoding encoding);
+
+
+ // STORE FUNCTIONS
+
+ // A8.6.189 STM/STMIA/STMEA
+ bool
+ EmulateSTM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.190 STMDA/STMED
+ bool
+ EmulateSTMDA (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.191 STMDB/STMFD
+ bool
+ EmulateSTMDB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.192 STMIB/STMFA
+ bool
+ EmulateSTMIB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.193 STR (immediate, Thumb)
+ bool
+ EmulateSTRThumb(const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.194 STR (immediate, ARM)
+ bool
+ EmulateSTRImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.195 STR (register)
+ bool
+ EmulateSTRRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.196 STRB (immediate, Thumb)
+ bool
+ EmulateSTRBThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.197 STRB (immediate, ARM)
+ bool
+ EmulateSTRBImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.198 STRB (register)
+ bool
+ EmulateSTRBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.199 STRBT
+ bool
+ EmulateSTRBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.200 STRD (immediate)
+ bool
+ EmulateSTRDImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.201 STRD (register)
+ bool
+ EmulateSTRDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.202 STREX
+ bool
+ EmulateSTREX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.203 STREXB
+ bool
+ EmulateSTREXB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.204 STREXD
+ bool
+ EmulateSTREXD (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.205 STREXH
+ bool
+ EmulateSTREXH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.206 STRH (immediate, Thumb)
+ bool
+ EmulateSTRHImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.207 STRH (immediate, ARM)
+ bool
+ EmulateSTRHImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.208 STRH (register)
+ bool
+ EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.209 STRHT
+ bool
+ EmulateSTRHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.210 STRT
+ bool
+ EmulateSTRT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.1 ADC (immediate)
+ bool
+ EmulateADCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.2 ADC (Register)
+ bool
+ EmulateADCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.10 ADR
+ bool
+ EmulateADR (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.11 AND (immediate)
+ bool
+ EmulateANDImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.12 AND (register)
+ bool
+ EmulateANDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.19 BIC (immediate)
+ bool
+ EmulateBICImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.20 BIC (register)
+ bool
+ EmulateBICReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.26 BXJ
+ bool
+ EmulateBXJ (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.32 CMN (immediate)
+ bool
+ EmulateCMNImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.33 CMN (register)
+ bool
+ EmulateCMNReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.44 EOR (immediate)
+ bool
+ EmulateEORImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.45 EOR (register)
+ bool
+ EmulateEORReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.105 MUL
+ bool
+ EmulateMUL (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.106 MVN (immediate)
+ bool
+ EmulateMVNImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.107 MVN (register)
+ bool
+ EmulateMVNReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.113 ORR (immediate)
+ bool
+ EmulateORRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.114 ORR (register)
+ bool
+ EmulateORRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.117 PLD (immediate, literal) - Encoding T1, T2, T3, A1
+ bool
+ EmulatePLDImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.119 PLI (immediate,literal) - Encoding T3, A1
+ bool
+ EmulatePLIImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.120 PLI (register) - Encoding T1, A1
+ bool
+ EmulatePLIRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.141 RSB (immediate)
+ bool
+ EmulateRSBImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.142 RSB (register)
+ bool
+ EmulateRSBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.144 RSC (immediate)
+ bool
+ EmulateRSCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.145 RSC (register)
+ bool
+ EmulateRSCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.150 SBC (immediate)
+ bool
+ EmulateSBCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.151 SBC (register)
+ bool
+ EmulateSBCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.211 SUB (immediate, Thumb)
+ bool
+ EmulateSUBImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.212 SUB (immediate, ARM)
+ bool
+ EmulateSUBImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.213 SUB (register)
+ bool
+ EmulateSUBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.214 SUB (register-shifted register)
+ bool
+ EmulateSUBRegShift (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.222 SXTB - Encoding T1
+ bool
+ EmulateSXTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.224 SXTH - EncodingT1
+ bool
+ EmulateSXTH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.227 TEQ (immediate) - Encoding A1
+ bool
+ EmulateTEQImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.228 TEQ (register) - Encoding A1
+ bool
+ EmulateTEQReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.230 TST (immediate) - Encoding A1
+ bool
+ EmulateTSTImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.231 TST (register) - Encoding T1, A1
+ bool
+ EmulateTSTReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.262 UXTB - Encoding T1
+ bool
+ EmulateUXTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.264 UXTH - Encoding T1
+ bool
+ EmulateUXTH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // B6.1.8 RFE
+ bool
+ EmulateRFE (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.319 VLDM
+ bool
+ EmulateVLDM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.399 VSTM
+ bool
+ EmulateVSTM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.307 VLD1 (multiple single elements)
+ bool
+ EmulateVLD1Multiple (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.308 VLD1 (single element to one lane)
+ bool
+ EmulateVLD1Single (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.309 VLD1 (single element to all lanes)
+ bool
+ EmulateVLD1SingleAll (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.391 VST1 (multiple single elements)
+ bool
+ EmulateVST1Multiple (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.392 VST1 (single element from one lane)
+ bool
+ EmulateVST1Single (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.317 VLDR
+ bool
+ EmulateVLDR (const uint32_t opcode, const ARMEncoding encoding);
+
+
+ // A8.6.400 VSTR
+ bool
+ EmulateVSTR (const uint32_t opcode, const ARMEncoding encoding);
+
+ // B6.2.13 SUBS PC, LR and related instructions
+ bool
+ EmulateSUBSPcLrEtc (const uint32_t opcode, const ARMEncoding encoding);
+
+ uint32_t m_arm_isa;
+ Mode m_opcode_mode;
+ uint32_t m_opcode_cpsr;
+ uint32_t m_new_inst_cpsr; // This can get updated by the opcode.
+ ITSession m_it_session;
+ bool m_ignore_conditions;
+};
+
+} // namespace lldb_private
+
+#endif // lldb_EmulateInstructionARM_h_
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
new file mode 100644
index 000000000000..bad4118971e0
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -0,0 +1,406 @@
+//===-- EmulationStateARM.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulationStateARM.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+EmulationStateARM::EmulationStateARM () :
+ m_gpr (),
+ m_vfp_regs (),
+ m_memory ()
+{
+ ClearPseudoRegisters();
+}
+
+EmulationStateARM::~EmulationStateARM ()
+{
+}
+
+bool
+EmulationStateARM::LoadPseudoRegistersFromFrame (StackFrame &frame)
+{
+ RegisterContext *reg_ctx = frame.GetRegisterContext().get();
+ bool success = true;
+ uint32_t reg_num;
+
+ for (int i = dwarf_r0; i < dwarf_r0 + 17; ++i)
+ {
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ m_gpr[i - dwarf_r0] = reg_value.GetAsUInt32();
+ }
+ else
+ success = false;
+ }
+
+ for (int i = dwarf_d0; i < dwarf_d0 + 32; ++i)
+ {
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ RegisterValue reg_value;
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ uint32_t idx = i - dwarf_d0;
+ if (i < 16)
+ m_vfp_regs.sd_regs[idx].d_reg = reg_value.GetAsUInt64();
+ else
+ m_vfp_regs.d_regs[idx - 16] = reg_value.GetAsUInt64();
+ }
+ else
+ success = false;
+ }
+
+ return success;
+}
+
+bool
+EmulationStateARM::StorePseudoRegisterValue (uint32_t reg_num, uint64_t value)
+{
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ m_gpr[reg_num - dwarf_r0] = (uint32_t) value;
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2] = (uint32_t) value;
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ {
+ m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg = value;
+ }
+ else
+ m_vfp_regs.d_regs[reg_num - dwarf_d16] = value;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+uint64_t
+EmulationStateARM::ReadPseudoRegisterValue (uint32_t reg_num, bool &success)
+{
+ uint64_t value = 0;
+ success = true;
+
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ value = m_gpr[reg_num - dwarf_r0];
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ value = m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2];
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ value = m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg;
+ else
+ value = m_vfp_regs.d_regs[reg_num - dwarf_d16];
+ }
+ else
+ success = false;
+
+ return value;
+}
+
+void
+EmulationStateARM::ClearPseudoRegisters ()
+{
+ for (int i = 0; i < 17; ++i)
+ m_gpr[i] = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.sd_regs[i].d_reg = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.d_regs[i] = 0;
+}
+
+void
+EmulationStateARM::ClearPseudoMemory ()
+{
+ m_memory.clear();
+}
+
+bool
+EmulationStateARM::StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size)
+{
+ if (size > 8)
+ return false;
+
+ if (size <= 4)
+ m_memory[p_address] = value;
+ else if (size == 8)
+ {
+ m_memory[p_address] = (value << 32) >> 32;
+ m_memory[p_address + 4] = value << 32;
+ }
+ return true;
+}
+
+uint32_t
+EmulationStateARM::ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success)
+{
+ std::map<lldb::addr_t,uint32_t>::iterator pos;
+ uint32_t ret_val = 0;
+
+ success = true;
+ pos = m_memory.find(p_address);
+ if (pos != m_memory.end())
+ ret_val = pos->second;
+ else
+ success = false;
+
+ return ret_val;
+}
+
+size_t
+EmulationStateARM::ReadPseudoMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ if (length <= 4)
+ {
+ uint32_t value = pseudo_state->ReadFromPseudoAddress (addr, length, success);
+ if (!success)
+ return 0;
+
+ *((uint32_t *) dst) = value;
+ }
+ else if (length == 8)
+ {
+ uint32_t value1 = pseudo_state->ReadFromPseudoAddress (addr, 4, success);
+ if (!success)
+ return 0;
+
+ uint32_t value2 = pseudo_state->ReadFromPseudoAddress (addr + 4, 4, success);
+ if (!success)
+ return 0;
+
+ uint64_t value64 = value2;
+ value64 = (value64 << 32) | value1;
+ *((uint64_t *) dst) = value64;
+ }
+ else
+ success = false;
+
+ if (success)
+ return length;
+
+ return 0;
+}
+
+size_t
+EmulationStateARM::WritePseudoMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ uint64_t value = *((uint64_t *) dst);
+ success = pseudo_state->StoreToPseudoAddress (addr, value, length);
+ if (success)
+ return length;
+
+ return 0;
+}
+
+bool
+EmulationStateARM::ReadPseudoRegister (EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value)
+{
+ if (!baton || !reg_info)
+ return false;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
+ assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
+ uint64_t reg_uval = pseudo_state->ReadPseudoRegisterValue (dwarf_reg_num, success);
+
+ if (success)
+ success = reg_value.SetUInt(reg_uval, reg_info->byte_size);
+ return success;
+
+}
+
+bool
+EmulationStateARM::WritePseudoRegister (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value)
+{
+ if (!baton || !reg_info)
+ return false;
+
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
+ assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
+ return pseudo_state->StorePseudoRegisterValue (dwarf_reg_num, reg_value.GetAsUInt64());
+}
+
+bool
+EmulationStateARM::CompareState (EmulationStateARM &other_state)
+{
+ bool match = true;
+
+ for (int i = 0; match && i < 17; ++i)
+ {
+ if (m_gpr[i] != other_state.m_gpr[i])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 16; ++i)
+ {
+ if (m_vfp_regs.sd_regs[i].s_reg[0] != other_state.m_vfp_regs.sd_regs[i].s_reg[0])
+ match = false;
+
+ if (m_vfp_regs.sd_regs[i].s_reg[1] != other_state.m_vfp_regs.sd_regs[i].s_reg[1])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 32; ++i)
+ {
+ if (i < 16)
+ {
+ if (m_vfp_regs.sd_regs[i].d_reg != other_state.m_vfp_regs.sd_regs[i].d_reg)
+ match = false;
+ }
+ else
+ {
+ if (m_vfp_regs.d_regs[i - 16] != other_state.m_vfp_regs.d_regs[i - 16])
+ match = false;
+ }
+ }
+
+ return match;
+}
+
+bool
+EmulationStateARM::LoadStateFromDictionary (OptionValueDictionary *test_data)
+{
+ static ConstString memory_key ("memory");
+ static ConstString registers_key ("registers");
+
+ if (!test_data)
+ return false;
+
+ OptionValueSP value_sp = test_data->GetValueForKey (memory_key);
+
+ // Load memory, if present.
+
+ if (value_sp.get() != NULL)
+ {
+ static ConstString address_key ("address");
+ static ConstString data_key ("data");
+ uint64_t start_address = 0;
+
+ OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();
+ value_sp = mem_dict->GetValueForKey (address_key);
+ if (value_sp.get() == NULL)
+ return false;
+ else
+ start_address = value_sp->GetUInt64Value ();
+
+ value_sp = mem_dict->GetValueForKey (data_key);
+ OptionValueArray *mem_array = value_sp->GetAsArray();
+ if (!mem_array)
+ return false;
+
+ uint32_t num_elts = mem_array->GetSize();
+ uint32_t address = (uint32_t) start_address;
+
+ for (uint32_t i = 0; i < num_elts; ++i)
+ {
+ value_sp = mem_array->GetValueAtIndex (i);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t value = value_sp->GetUInt64Value();
+ StoreToPseudoAddress (address, value, 4);
+ address = address + 4;
+ }
+ }
+
+ value_sp = test_data->GetValueForKey (registers_key);
+ if (value_sp.get() == NULL)
+ return false;
+
+
+ // Load General Registers
+
+ OptionValueDictionary *reg_dict = value_sp->GetAsDictionary ();
+
+ StreamString sstr;
+ for (int i = 0; i < 16; ++i)
+ {
+ sstr.Clear();
+ sstr.Printf ("r%d", i);
+ ConstString reg_name (sstr.GetData());
+ value_sp = reg_dict->GetValueForKey (reg_name);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue (dwarf_r0 + i, reg_value);
+ }
+
+ static ConstString cpsr_name ("cpsr");
+ value_sp = reg_dict->GetValueForKey (cpsr_name);
+ if (value_sp.get() == NULL)
+ return false;
+ StorePseudoRegisterValue (dwarf_cpsr, value_sp->GetUInt64Value());
+
+ // Load s/d Registers
+ for (int i = 0; i < 32; ++i)
+ {
+ sstr.Clear();
+ sstr.Printf ("s%d", i);
+ ConstString reg_name (sstr.GetData());
+ value_sp = reg_dict->GetValueForKey (reg_name);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue (dwarf_s0 + i, reg_value);
+ }
+
+ return true;
+}
+
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.h b/source/Plugins/Instruction/ARM/EmulationStateARM.h
new file mode 100644
index 000000000000..8d84abc75614
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.h
@@ -0,0 +1,100 @@
+//===-- lldb_EmulationStateARM.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulationStateARM_h_
+#define lldb_EmulationStateARM_h_
+
+#include <map>
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Opcode.h"
+
+class EmulationStateARM {
+public:
+
+ EmulationStateARM ();
+
+ virtual
+ ~EmulationStateARM ();
+
+ bool
+ StorePseudoRegisterValue (uint32_t reg_num, uint64_t value);
+
+ uint64_t
+ ReadPseudoRegisterValue (uint32_t reg_num, bool &success);
+
+ bool
+ StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size);
+
+ uint32_t
+ ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success);
+
+ void
+ ClearPseudoRegisters ();
+
+ void
+ ClearPseudoMemory ();
+
+ bool
+ LoadPseudoRegistersFromFrame (lldb_private::StackFrame &frame);
+
+ bool
+ LoadStateFromDictionary (lldb_private::OptionValueDictionary *test_data);
+
+ bool
+ CompareState (EmulationStateARM &other_state);
+
+ static size_t
+ ReadPseudoMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WritePseudoMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadPseudoRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ static bool
+ WritePseudoRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+private:
+ uint32_t m_gpr[17];
+ struct sd_regs
+ {
+ union
+ {
+ uint32_t s_reg[2];
+ uint64_t d_reg;
+ } sd_regs[16]; // sregs 0 - 31 & dregs 0 - 15
+
+ uint64_t d_regs[16]; // dregs 16-31
+
+ } m_vfp_regs;
+
+ std::map<lldb::addr_t, uint32_t> m_memory; // Eventually will want to change uint32_t to a data buffer heap type.
+
+ DISALLOW_COPY_AND_ASSIGN (EmulationStateARM);
+};
+
+#endif // lldb_EmulationStateARM_h_
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
new file mode 100644
index 000000000000..247d7b0e7fe4
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -0,0 +1,461 @@
+//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ItaniumABILanguageRuntime.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *vtable_demangled_prefix = "vtable for ";
+
+bool
+ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
+{
+ const bool check_cxx = true;
+ const bool check_objc = false;
+ return in_value.GetClangType().IsPossibleDynamicType (NULL, check_cxx, check_objc);
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name,
+ Address &dynamic_address)
+{
+ // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
+ // in the object. That will point to the "address point" within the vtable (not the beginning of the
+ // vtable.) We can then look up the symbol containing this "address point" and that symbol's name
+ // demangled will contain the full class name.
+ // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the
+ // start of the value object which holds the dynamic type.
+ //
+
+ class_type_or_name.Clear();
+
+ // Only a pointer or reference type can have a different dynamic and static type:
+ if (CouldHaveDynamicValue (in_value))
+ {
+ // First job, pull out the address at 0 offset from the object.
+ AddressType address_type;
+ lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
+ if (original_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+
+ char memory_buffer[16];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ size_t address_byte_size = process->GetAddressByteSize();
+ Error error;
+ size_t bytes_read = process->ReadMemory (original_ptr,
+ memory_buffer,
+ address_byte_size,
+ error);
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ lldb::offset_t offset = 0;
+ lldb::addr_t vtable_address_point = data.GetAddress (&offset);
+
+ if (offset == 0)
+ return false;
+
+ // Now find the symbol that contains this address:
+
+ SymbolContext sc;
+ Address address_point_address;
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
+ {
+ target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
+ Symbol *symbol = sc.symbol;
+ if (symbol != NULL)
+ {
+ const char *name = symbol->GetMangled().GetDemangledName().AsCString();
+ if (strstr(name, vtable_demangled_prefix) == name)
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n",
+ original_ptr,
+ in_value.GetTypeName().GetCString(),
+ name);
+ // We are a C++ class, that's good. Get the class name and look it up:
+ const char *class_name = name + strlen(vtable_demangled_prefix);
+ class_type_or_name.SetName (class_name);
+ const bool exact_match = true;
+ TypeList class_types;
+
+ uint32_t num_matches = 0;
+ // First look in the module that the vtable symbol came from
+ // and look for a single exact match.
+ if (sc.module_sp)
+ {
+ num_matches = sc.module_sp->FindTypes (sc,
+ ConstString(class_name),
+ exact_match,
+ 1,
+ class_types);
+ }
+
+ // If we didn't find a symbol, then move on to the entire
+ // module list in the target and get as many unique matches
+ // as possible
+ if (num_matches == 0)
+ {
+ num_matches = target->GetImages().FindTypes (sc,
+ ConstString(class_name),
+ exact_match,
+ UINT32_MAX,
+ class_types);
+ }
+
+ lldb::TypeSP type_sp;
+ if (num_matches == 0)
+ {
+ if (log)
+ log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr);
+ return false;
+ }
+ if (num_matches == 1)
+ {
+ type_sp = class_types.GetTypeAtIndex(0);
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+
+ class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
+ }
+ else if (num_matches > 1)
+ {
+ size_t i;
+ if (log)
+ {
+ for (i = 0; i < num_matches; i++)
+ {
+ type_sp = class_types.GetTypeAtIndex(i);
+ if (type_sp)
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+ }
+ }
+ }
+
+ for (i = 0; i < num_matches; i++)
+ {
+ type_sp = class_types.GetTypeAtIndex(i);
+ if (type_sp)
+ {
+ if (type_sp->GetClangFullType().IsCXXClassType())
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+ class_type_or_name.SetTypeSP(type_sp);
+ break;
+ }
+ }
+ }
+
+ if (i == num_matches)
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString());
+ return false;
+ }
+ }
+
+ // There can only be one type with a given name,
+ // so we've just found duplicate definitions, and this
+ // one will do as well as any other.
+ // We don't consider something to have a dynamic type if
+ // it is the same as the static type. So compare against
+ // the value we were handed.
+ if (type_sp)
+ {
+ if (ClangASTContext::AreTypesSame (in_value.GetClangType(),
+ type_sp->GetClangFullType()))
+ {
+ // The dynamic type we found was the same type,
+ // so we don't have a dynamic type here...
+ return false;
+ }
+
+ // The offset_to_top is two pointers above the address.
+ Address offset_to_top_address = address_point_address;
+ int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
+ offset_to_top_address.Slide (slide);
+
+ Error error;
+ lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
+
+ size_t bytes_read = process->ReadMemory (offset_to_top_location,
+ memory_buffer,
+ address_byte_size,
+ error);
+
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ offset = 0;
+ int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize());
+
+ // So the dynamic type is a value that starts at offset_to_top
+ // above the original address.
+ lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
+ if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
+ {
+ dynamic_address.SetRawAddress(dynamic_addr);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return class_type_or_name.IsEmpty() == false;
+}
+
+bool
+ItaniumABILanguageRuntime::IsVTableName (const char *name)
+{
+ if (name == NULL)
+ return false;
+
+ // Can we maybe ask Clang about this?
+ if (strstr (name, "_vptr$") == name)
+ return true;
+ else
+ return false;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+LanguageRuntime *
+ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language)
+{
+ // FIXME: We have to check the process and make sure we actually know that this process supports
+ // the Itanium ABI.
+ if (language == eLanguageTypeC_plus_plus)
+ return new ItaniumABILanguageRuntime (process);
+ else
+ return NULL;
+}
+
+void
+ItaniumABILanguageRuntime::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Itanium ABI for the C++ language",
+ CreateInstance);
+}
+
+void
+ItaniumABILanguageRuntime::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ItaniumABILanguageRuntime::GetPluginNameStatic()
+{
+ static ConstString g_name("itanium");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ItaniumABILanguageRuntime::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ItaniumABILanguageRuntime::GetPluginVersion()
+{
+ return 1;
+}
+
+BreakpointResolverSP
+ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
+{
+ return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false);
+}
+
+BreakpointResolverSP
+ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions)
+{
+ // One complication here is that most users DON'T want to stop at __cxa_allocate_expression, but until we can do
+ // anything better with predicting unwinding the expression parser does. So we have two forms of the exception
+ // breakpoints, one for expressions that leaves out __cxa_allocate_exception, and one that includes it.
+ // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in the runtime the former.
+ static const char *g_catch_name = "__cxa_begin_catch";
+ static const char *g_throw_name1 = "__cxa_throw";
+ static const char *g_throw_name2 = "__cxa_rethrow";
+ static const char *g_exception_throw_name = "__cxa_allocate_exception";
+ std::vector<const char *> exception_names;
+ exception_names.reserve(4);
+ if (catch_bp)
+ exception_names.push_back(g_catch_name);
+
+ if (throw_bp)
+ {
+ exception_names.push_back(g_throw_name1);
+ exception_names.push_back(g_throw_name2);
+ }
+
+ if (for_expressions)
+ exception_names.push_back(g_exception_throw_name);
+
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (bkpt,
+ exception_names.data(),
+ exception_names.size(),
+ eFunctionNameTypeBase,
+ eLazyBoolNo));
+
+ return resolver_sp;
+}
+
+
+
+lldb::SearchFilterSP
+ItaniumABILanguageRuntime::CreateExceptionSearchFilter ()
+{
+ Target &target = m_process->GetTarget();
+
+ if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple)
+ {
+ // Limit the number of modules that are searched for these breakpoints for
+ // Apple binaries.
+ FileSpecList filter_modules;
+ filter_modules.Append(FileSpec("libc++abi.dylib", false));
+ filter_modules.Append(FileSpec("libSystem.B.dylib", false));
+ return target.GetSearchFilterForModuleList(&filter_modules);
+ }
+ else
+ {
+ return LanguageRuntime::CreateExceptionSearchFilter();
+ }
+}
+
+lldb::BreakpointSP
+ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp,
+ bool throw_bp,
+ bool for_expressions,
+ bool is_internal)
+{
+ Target &target = m_process->GetTarget();
+ FileSpecList filter_modules;
+ BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions);
+ SearchFilterSP filter_sp (CreateExceptionSearchFilter ());
+ return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal);
+}
+
+void
+ItaniumABILanguageRuntime::SetExceptionBreakpoints ()
+{
+ if (!m_process)
+ return;
+
+ const bool catch_bp = false;
+ const bool throw_bp = true;
+ const bool is_internal = true;
+ const bool for_expressions = true;
+
+ // For the exception breakpoints set by the Expression parser, we'll be a little more aggressive and
+ // stop at exception allocation as well.
+
+ if (m_cxx_exception_bp_sp)
+ {
+ m_cxx_exception_bp_sp->SetEnabled (true);
+ }
+ else
+ {
+ m_cxx_exception_bp_sp = CreateExceptionBreakpoint (catch_bp, throw_bp, for_expressions, is_internal);
+ if (m_cxx_exception_bp_sp)
+ m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception");
+ }
+
+}
+
+void
+ItaniumABILanguageRuntime::ClearExceptionBreakpoints ()
+{
+ if (!m_process)
+ return;
+
+ if (m_cxx_exception_bp_sp)
+ {
+ m_cxx_exception_bp_sp->SetEnabled (false);
+ }
+}
+
+bool
+ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
+{
+ if (!m_process)
+ return false;
+
+ if (!stop_reason ||
+ stop_reason->GetStopReason() != eStopReasonBreakpoint)
+ return false;
+
+ uint64_t break_site_id = stop_reason->GetValue();
+ return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id,
+ m_cxx_exception_bp_sp->GetID());
+
+}
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
new file mode 100644
index 000000000000..6b2c437de252
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -0,0 +1,101 @@
+//===-- ItaniumABILanguageRuntime.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_ItaniumABILanguageRuntime_h_
+#define liblldb_ItaniumABILanguageRuntime_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Core/Value.h"
+
+namespace lldb_private {
+
+ class ItaniumABILanguageRuntime :
+ public lldb_private::CPPLanguageRuntime
+ {
+ public:
+ ~ItaniumABILanguageRuntime() { }
+
+ virtual bool
+ IsVTableName (const char *name);
+
+ virtual bool
+ GetDynamicTypeAndAddress (ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name,
+ Address &address);
+
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::LanguageRuntime *
+ CreateInstance (Process *process, lldb::LanguageType language);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ SetExceptionBreakpoints ();
+
+ virtual void
+ ClearExceptionBreakpoints ();
+
+ virtual bool
+ ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason);
+
+ virtual lldb::BreakpointResolverSP
+ CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp);
+
+ virtual lldb::SearchFilterSP
+ CreateExceptionSearchFilter ();
+
+ protected:
+
+ lldb::BreakpointResolverSP
+ CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions);
+
+ lldb::BreakpointSP
+ CreateExceptionBreakpoint(bool catch_bp,
+ bool throw_bp,
+ bool for_expressions,
+ bool is_internal);
+
+ private:
+ ItaniumABILanguageRuntime(Process *process) : lldb_private::CPPLanguageRuntime(process) { } // Call CreateInstance instead.
+
+ lldb::BreakpointSP m_cxx_exception_bp_sp;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ItaniumABILanguageRuntime_h_
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
new file mode 100644
index 000000000000..1ec5f3d733a0
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -0,0 +1,585 @@
+//===-- ObjectContainerBSDArchive.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerBSDArchive.h"
+
+#include <ar.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+ObjectContainerBSDArchive::Object::Object() :
+ ar_name(),
+ ar_date(0),
+ ar_uid(0),
+ ar_gid(0),
+ ar_mode(0),
+ ar_size(0),
+ ar_file_offset(0),
+ ar_file_size(0)
+{
+}
+
+void
+ObjectContainerBSDArchive::Object::Clear()
+{
+ ar_name.Clear();
+ ar_date = 0;
+ ar_uid = 0;
+ ar_gid = 0;
+ ar_mode = 0;
+ ar_size = 0;
+ ar_file_offset = 0;
+ ar_file_size = 0;
+}
+
+lldb::offset_t
+ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::offset_t offset)
+{
+ size_t ar_name_len = 0;
+ std::string str;
+ char *err;
+ str.assign ((const char *)data.GetData(&offset, 16), 16);
+ if (str.find("#1/") == 0)
+ {
+ // If the name is longer than 16 bytes, or contains an embedded space
+ // then it will use this format where the length of the name is
+ // here and the name characters are after this header.
+ ar_name_len = strtoul(str.c_str() + 3, &err, 10);
+ }
+ else
+ {
+ // Strip off any spaces (if the object file name contains spaces it
+ // will use the extended format above).
+ str.erase (str.find(' '));
+ ar_name.SetCString(str.c_str());
+ }
+
+ str.assign ((const char *)data.GetData(&offset, 12), 12);
+ ar_date = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_uid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_gid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 8), 8);
+ ar_mode = strtoul(str.c_str(), &err, 8);
+
+ str.assign ((const char *)data.GetData(&offset, 10), 10);
+ ar_size = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 2), 2);
+ if (str == ARFMAG)
+ {
+ if (ar_name_len > 0)
+ {
+ str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len);
+ ar_name.SetCString (str.c_str());
+ }
+ ar_file_offset = offset;
+ ar_file_size = ar_size - ar_name_len;
+ return offset;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+ObjectContainerBSDArchive::Archive::Archive
+(
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data
+) :
+ m_arch (arch),
+ m_time (time),
+ m_file_offset (file_offset),
+ m_objects(),
+ m_data (data)
+{
+}
+
+ObjectContainerBSDArchive::Archive::~Archive ()
+{
+}
+
+size_t
+ObjectContainerBSDArchive::Archive::ParseObjects ()
+{
+ DataExtractor &data = m_data;
+ std::string str;
+ lldb::offset_t offset = 0;
+ str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG);
+ if (str == ARMAG)
+ {
+ Object obj;
+ do
+ {
+ offset = obj.Extract (data, offset);
+ if (offset == LLDB_INVALID_OFFSET)
+ break;
+ size_t obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append (obj.ar_name.GetCString(), obj_idx);
+ offset += obj.ar_file_size;
+ obj.Clear();
+ } while (data.ValidOffset(offset));
+
+ // Now sort all of the object name pointers
+ m_object_name_to_index_map.Sort ();
+ }
+ return m_objects.size();
+}
+
+ObjectContainerBSDArchive::Object *
+ObjectContainerBSDArchive::Archive::FindObject (const ConstString &object_name, const TimeValue &object_mod_time)
+{
+ const ObjectNameToIndexMap::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString());
+ if (match)
+ {
+ if (object_mod_time.IsValid())
+ {
+ const uint64_t object_date = object_mod_time.GetAsSecondsSinceJan1_1970();
+ if (m_objects[match->value].ar_date == object_date)
+ return &m_objects[match->value];
+ const ObjectNameToIndexMap::Entry *next_match = m_object_name_to_index_map.FindNextValueForName (match);
+ while (next_match)
+ {
+ if (m_objects[next_match->value].ar_date == object_date)
+ return &m_objects[next_match->value];
+ next_match = m_object_name_to_index_map.FindNextValueForName (next_match);
+ }
+ }
+ else
+ {
+ return &m_objects[match->value];
+ }
+ }
+ return NULL;
+}
+
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time, lldb::offset_t file_offset)
+{
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ shared_ptr archive_sp;
+ Archive::Map &archive_map = Archive::GetArchiveCache ();
+ Archive::Map::iterator pos = archive_map.find (file);
+ // Don't cache a value for "archive_map.end()" below since we might
+ // delete an archive entry...
+ while (pos != archive_map.end() && pos->first == file)
+ {
+ bool match = true;
+ if (arch.IsValid() && pos->second->GetArchitecture().IsCompatibleMatch(arch) == false)
+ match = false;
+ else if (file_offset != LLDB_INVALID_OFFSET && pos->second->GetFileOffset() != file_offset)
+ match = false;
+ if (match)
+ {
+ if (pos->second->GetModificationTime() == time)
+ {
+ return pos->second;
+ }
+ else
+ {
+ // We have a file at the same path with the same architecture
+ // whose modification time doesn't match. It doesn't make sense
+ // for us to continue to use this BSD archive since we cache only
+ // the object info which consists of file time info and also the
+ // file offset and file size of any contianed objects. Since
+ // this information is now out of date, we won't get the correct
+ // information if we go and extract the file data, so we should
+ // remove the old and outdated entry.
+ archive_map.erase (pos);
+ pos = archive_map.find (file);
+ continue; // Continue to next iteration so we don't increment pos below...
+ }
+ }
+ ++pos;
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
+(
+ const FileSpec &file,
+ const ArchSpec &arch,
+ const TimeValue &time,
+ lldb::offset_t file_offset,
+ DataExtractor &data
+)
+{
+ shared_ptr archive_sp(new Archive (arch, time, file_offset, data));
+ if (archive_sp)
+ {
+ const size_t num_objects = archive_sp->ParseObjects ();
+ if (num_objects > 0)
+ {
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
+ }
+ else
+ {
+ archive_sp.reset();
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::Map &
+ObjectContainerBSDArchive::Archive::GetArchiveCache ()
+{
+ static Archive::Map g_archive_map;
+ return g_archive_map;
+}
+
+Mutex &
+ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex ()
+{
+ static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive);
+ return g_archive_map_mutex;
+}
+
+
+void
+ObjectContainerBSDArchive::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectContainerBSDArchive::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+ObjectContainerBSDArchive::GetPluginNameStatic()
+{
+ static ConstString g_name("bsd-archive");
+ return g_name;
+}
+
+const char *
+ObjectContainerBSDArchive::GetPluginDescriptionStatic()
+{
+ return "BSD Archive object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerBSDArchive::CreateInstance
+(
+ const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ ConstString object_name (module_sp->GetObjectName());
+ if (object_name)
+ {
+ if (data_sp)
+ {
+ // We have data, which means this is the first 512 bytes of the file
+ // Check to see if the magic bytes match and if they do, read the entire
+ // table of contents for the archive and cache it
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, length);
+ if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data))
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "ObjectContainerBSDArchive::CreateInstance (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ file, (uint64_t) file_offset, (uint64_t) length);
+
+ // Map the entire .a file to be sure that we don't lose any data if the file
+ // gets updated by a new build while this .a file is being used for debugging
+ DataBufferSP archive_data_sp (file->MemoryMapFileContents(file_offset, length));
+ lldb::offset_t archive_data_offset = 0;
+
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ file_offset));
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module_sp,
+ archive_data_sp,
+ archive_data_offset,
+ file,
+ file_offset,
+ length));
+
+ if (container_ap.get())
+ {
+ if (archive_sp)
+ {
+ // We already have this archive in our cache, use it
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ else if (container_ap->ParseHeader())
+ return container_ap.release();
+ }
+ }
+ }
+ else
+ {
+ // No data, just check for a cached archive
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ file_offset));
+ if (archive_sp)
+ {
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module_sp, data_sp, data_offset, file, file_offset, length));
+
+ if (container_ap.get())
+ {
+ // We already have this archive in our cache, use it
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerBSDArchive::MagicBytesMatch (const DataExtractor &data)
+{
+ uint32_t offset = 0;
+ const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr));
+ if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0)
+ {
+ armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
+ if (strncmp(armag, ARFMAG, 2) == 0)
+ return true;
+ }
+ return false;
+}
+
+ObjectContainerBSDArchive::ObjectContainerBSDArchive
+(
+ const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t size
+) :
+ ObjectContainer (module_sp, file, file_offset, size, data_sp, data_offset),
+ m_archive_sp ()
+{
+}
+void
+ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp)
+{
+ m_archive_sp = archive_sp;
+}
+
+
+
+ObjectContainerBSDArchive::~ObjectContainerBSDArchive()
+{
+}
+
+bool
+ObjectContainerBSDArchive::ParseHeader ()
+{
+ if (m_archive_sp.get() == NULL)
+ {
+ if (m_data.GetByteSize() > 0)
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ m_offset,
+ m_data);
+ }
+ // Clear the m_data that contains the entire archive
+ // data and let our m_archive_sp hold onto the data.
+ m_data.Clear();
+ }
+ }
+ return m_archive_sp.get() != NULL;
+}
+
+void
+ObjectContainerBSDArchive::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerBSDArchive, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
+ uint32_t i;
+ ArchSpec arch;
+ s->IndentMore();
+ for (i=0; i<num_archs; i++)
+ {
+ s->Indent();
+ GetArchitectureAtIndex(i, arch);
+ s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+ObjectFileSP
+ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
+{
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ if (module_sp->GetObjectName() && m_archive_sp)
+ {
+ Object *object = m_archive_sp->FindObject (module_sp->GetObjectName(),
+ module_sp->GetObjectModificationTime());
+ if (object)
+ {
+ lldb::offset_t data_offset = object->ar_file_offset;
+ return ObjectFile::FindPlugin (module_sp,
+ file,
+ m_offset + object->ar_file_offset,
+ object->ar_file_size,
+ m_archive_sp->GetData().GetSharedDataBuffer(),
+ data_offset);
+ }
+ }
+ }
+ return ObjectFileSP();
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectContainerBSDArchive::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerBSDArchive::GetPluginVersion()
+{
+ return 1;
+}
+
+
+size_t
+ObjectContainerBSDArchive::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb_private::ModuleSpecList &specs)
+{
+
+ // We have data, which means this is the first 512 bytes of the file
+ // Check to see if the magic bytes match and if they do, read the entire
+ // table of contents for the archive and cache it
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, data_sp->GetByteSize());
+ if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data))
+ {
+ const size_t initial_count = specs.GetSize();
+ TimeValue file_mod_time = file.GetModificationTime();
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (file, ArchSpec(), file_mod_time, file_offset));
+ bool set_archive_arch = false;
+ if (!archive_sp)
+ {
+ set_archive_arch = true;
+ DataBufferSP data_sp (file.MemoryMapFileContents(file_offset, file_size));
+ data.SetData (data_sp, 0, data_sp->GetByteSize());
+ archive_sp = Archive::ParseAndCacheArchiveForFile(file, ArchSpec(), file_mod_time, file_offset, data);
+ }
+
+ if (archive_sp)
+ {
+ const size_t num_objects = archive_sp->GetNumObjects();
+ for (size_t idx = 0; idx < num_objects; ++idx)
+ {
+ const Object *object = archive_sp->GetObjectAtIndex (idx);
+ if (object)
+ {
+ const lldb::offset_t object_file_offset = file_offset + object->ar_file_offset;
+ if (object->ar_file_offset < file_size && file_size > object_file_offset)
+ {
+ if (ObjectFile::GetModuleSpecifications(file,
+ object_file_offset,
+ file_size - object_file_offset,
+ specs))
+ {
+ ModuleSpec &spec = specs.GetModuleSpecRefAtIndex (specs.GetSize() - 1);
+ TimeValue object_mod_time;
+ object_mod_time.OffsetWithSeconds(object->ar_date);
+ spec.GetObjectName () = object->ar_name;
+ spec.SetObjectOffset(object_file_offset);
+ spec.GetObjectModificationTime () = object_mod_time;
+ }
+ }
+ }
+ }
+ }
+ const size_t end_count = specs.GetSize();
+ size_t num_specs_added = end_count - initial_count;
+ if (set_archive_arch && num_specs_added > 0)
+ {
+ // The archive was created but we didn't have an architecture
+ // so we need to set it
+ for (size_t i=initial_count; i<end_count; ++ i)
+ {
+ ModuleSpec module_spec;
+ if (specs.GetModuleSpecAtIndex(i, module_spec))
+ {
+ if (module_spec.GetArchitecture().IsValid())
+ {
+ archive_sp->SetArchitecture (module_spec.GetArchitecture());
+ break;
+ }
+ }
+ }
+ }
+ return num_specs_added;
+ }
+ return 0;
+}
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
new file mode 100644
index 000000000000..8093c580ff97
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -0,0 +1,229 @@
+//===-- ObjectContainerBSDArchive.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_ObjectContainerBSDArchive_h_
+#define liblldb_ObjectContainerBSDArchive_h_
+
+#include "lldb/Symbol/ObjectContainer.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Host/TimeValue.h"
+
+class ObjectContainerBSDArchive :
+ public lldb_private::ObjectContainer
+{
+public:
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool
+ MagicBytesMatch (const lldb_private::DataExtractor &data);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerBSDArchive (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ virtual
+ ~ObjectContainerBSDArchive();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual size_t
+ GetNumObjects () const
+ {
+ if (m_archive_sp)
+ return m_archive_sp->GetNumObjects();
+ return 0;
+ }
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual lldb::ObjectFileSP
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+
+ struct Object
+ {
+ Object();
+
+ void
+ Clear();
+
+ lldb::offset_t
+ Extract (const lldb_private::DataExtractor& data, lldb::offset_t offset);
+
+ lldb_private::ConstString ar_name; // name
+ uint32_t ar_date; // modification time
+ uint16_t ar_uid; // user id
+ uint16_t ar_gid; // group id
+ uint16_t ar_mode; // octal file permissions
+ uint32_t ar_size; // size in bytes
+ lldb::offset_t ar_file_offset; // file offset in bytes from the beginning of the file of the object data
+ lldb::offset_t ar_file_size; // length of the object data
+
+ typedef std::vector<Object> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ class Archive
+ {
+ public:
+ typedef std::shared_ptr<Archive> shared_ptr;
+ typedef std::multimap<lldb_private::FileSpec, shared_ptr> Map;
+
+ static Map &
+ GetArchiveCache ();
+
+ static lldb_private::Mutex &
+ GetArchiveCacheMutex ();
+
+ static Archive::shared_ptr
+ FindCachedArchive (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset);
+
+ static Archive::shared_ptr
+ ParseAndCacheArchiveForFile (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ Archive (const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ ~Archive ();
+
+ size_t
+ GetNumObjects () const
+ {
+ return m_objects.size();
+ }
+
+ const Object *
+ GetObjectAtIndex (size_t idx)
+ {
+ if (idx < m_objects.size())
+ return &m_objects[idx];
+ return NULL;
+ }
+
+ size_t
+ ParseObjects ();
+
+ Object *
+ FindObject (const lldb_private::ConstString &object_name,
+ const lldb_private::TimeValue &object_mod_time);
+
+ lldb::offset_t
+ GetFileOffset () const
+ {
+ return m_file_offset;
+ }
+
+ const lldb_private::TimeValue &
+ GetModificationTime()
+ {
+ return m_time;
+ }
+
+ const lldb_private::ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ void
+ SetArchitecture (const lldb_private::ArchSpec &arch)
+ {
+ m_arch = arch;
+ }
+
+ bool
+ HasNoExternalReferences() const;
+
+ lldb_private::DataExtractor &
+ GetData ()
+ {
+ return m_data;
+ }
+
+ protected:
+ typedef lldb_private::UniqueCStringMap<uint32_t> ObjectNameToIndexMap;
+ //----------------------------------------------------------------------
+ // Member Variables
+ //----------------------------------------------------------------------
+ lldb_private::ArchSpec m_arch;
+ lldb_private::TimeValue m_time;
+ lldb::offset_t m_file_offset;
+ Object::collection m_objects;
+ ObjectNameToIndexMap m_object_name_to_index_map;
+ lldb_private::DataExtractor m_data; ///< The data for this object container so we don't lose data if the .a files gets modified
+ };
+
+ void
+ SetArchive (Archive::shared_ptr &archive_sp);
+
+ Archive::shared_ptr m_archive_sp;
+};
+
+#endif // liblldb_ObjectContainerBSDArchive_h_
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
new file mode 100644
index 000000000000..a63a01d7ed7a
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -0,0 +1,465 @@
+//===-- ELFHeader.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 "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+
+#include "ELFHeader.h"
+
+using namespace elf;
+using namespace lldb;
+using namespace llvm::ELF;
+
+//------------------------------------------------------------------------------
+// Static utility functions.
+//
+// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor
+// with error handling code and provide for parsing a sequence of values.
+static bool
+GetMaxU64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ uint64_t *value,
+ uint32_t byte_size)
+{
+ const lldb::offset_t saved_offset = *offset;
+ *value = data.GetMaxU64(offset, byte_size);
+ return *offset != saved_offset;
+}
+
+static bool
+GetMaxU64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ uint64_t *value,
+ uint32_t byte_size,
+ uint32_t count)
+{
+ lldb::offset_t saved_offset = *offset;
+
+ for (uint32_t i = 0; i < count; ++i, ++value)
+ {
+ if (GetMaxU64(data, offset, value, byte_size) == false)
+ {
+ *offset = saved_offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+GetMaxS64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ int64_t *value,
+ uint32_t byte_size)
+{
+ const lldb::offset_t saved_offset = *offset;
+ *value = data.GetMaxS64(offset, byte_size);
+ return *offset != saved_offset;
+}
+
+static bool
+GetMaxS64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ int64_t *value,
+ uint32_t byte_size,
+ uint32_t count)
+{
+ lldb::offset_t saved_offset = *offset;
+
+ for (uint32_t i = 0; i < count; ++i, ++value)
+ {
+ if (GetMaxS64(data, offset, value, byte_size) == false)
+ {
+ *offset = saved_offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFHeader
+
+ELFHeader::ELFHeader()
+{
+ memset(this, 0, sizeof(ELFHeader));
+}
+
+ByteOrder
+ELFHeader::GetByteOrder() const
+{
+ if (e_ident[EI_DATA] == ELFDATA2MSB)
+ return eByteOrderBig;
+ if (e_ident[EI_DATA] == ELFDATA2LSB)
+ return eByteOrderLittle;
+ return eByteOrderInvalid;
+}
+
+bool
+ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ // Read e_ident. This provides byte order and address size info.
+ if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL)
+ return false;
+
+ const unsigned byte_size = Is32Bit() ? 4 : 8;
+ data.SetByteOrder(GetByteOrder());
+ data.SetAddressByteSize(byte_size);
+
+ // Read e_type and e_machine.
+ if (data.GetU16(offset, &e_type, 2) == NULL)
+ return false;
+
+ // Read e_version.
+ if (data.GetU32(offset, &e_version, 1) == NULL)
+ return false;
+
+ // Read e_entry, e_phoff and e_shoff.
+ if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false)
+ return false;
+
+ // Read e_flags.
+ if (data.GetU32(offset, &e_flags, 1) == NULL)
+ return false;
+
+ // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and
+ // e_shstrndx.
+ if (data.GetU16(offset, &e_ehsize, 6) == NULL)
+ return false;
+
+ return true;
+}
+
+bool
+ELFHeader::MagicBytesMatch(const uint8_t *magic)
+{
+ return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;
+}
+
+unsigned
+ELFHeader::AddressSizeInBytes(const uint8_t *magic)
+{
+ unsigned address_size = 0;
+
+ switch (magic[EI_CLASS])
+ {
+ case ELFCLASS32:
+ address_size = 4;
+ break;
+
+ case ELFCLASS64:
+ address_size = 8;
+ break;
+ }
+ return address_size;
+}
+
+unsigned
+ELFHeader::GetRelocationJumpSlotType() const
+{
+ unsigned slot = 0;
+
+ switch (e_machine)
+ {
+ default:
+ assert(false && "architecture not supported");
+ break;
+ case EM_386:
+ case EM_486:
+ slot = R_386_JUMP_SLOT;
+ break;
+ case EM_X86_64:
+ slot = R_X86_64_JUMP_SLOT;
+ break;
+ case EM_ARM:
+ slot = R_ARM_JUMP_SLOT;
+ break;
+ }
+
+ return slot;
+}
+
+//------------------------------------------------------------------------------
+// ELFSectionHeader
+
+ELFSectionHeader::ELFSectionHeader()
+{
+ memset(this, 0, sizeof(ELFSectionHeader));
+}
+
+bool
+ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read sh_name and sh_type.
+ if (data.GetU32(offset, &sh_name, 2) == NULL)
+ return false;
+
+ // Read sh_flags.
+ if (GetMaxU64(data, offset, &sh_flags, byte_size) == false)
+ return false;
+
+ // Read sh_addr, sh_off and sh_size.
+ if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false)
+ return false;
+
+ // Read sh_link and sh_info.
+ if (data.GetU32(offset, &sh_link, 2) == NULL)
+ return false;
+
+ // Read sh_addralign and sh_entsize.
+ if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false)
+ return false;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFSymbol
+
+ELFSymbol::ELFSymbol()
+{
+ memset(this, 0, sizeof(ELFSymbol));
+}
+
+#define ENUM_TO_CSTR(e) case e: return #e
+
+const char *
+ELFSymbol::bindingToCString(unsigned char binding)
+{
+ switch (binding)
+ {
+ ENUM_TO_CSTR(STB_LOCAL);
+ ENUM_TO_CSTR(STB_GLOBAL);
+ ENUM_TO_CSTR(STB_WEAK);
+ ENUM_TO_CSTR(STB_LOOS);
+ ENUM_TO_CSTR(STB_HIOS);
+ ENUM_TO_CSTR(STB_LOPROC);
+ ENUM_TO_CSTR(STB_HIPROC);
+ }
+ return "";
+}
+
+const char *
+ELFSymbol::typeToCString(unsigned char type)
+{
+ switch (type)
+ {
+ ENUM_TO_CSTR(STT_NOTYPE);
+ ENUM_TO_CSTR(STT_OBJECT);
+ ENUM_TO_CSTR(STT_FUNC);
+ ENUM_TO_CSTR(STT_SECTION);
+ ENUM_TO_CSTR(STT_FILE);
+ ENUM_TO_CSTR(STT_COMMON);
+ ENUM_TO_CSTR(STT_TLS);
+ ENUM_TO_CSTR(STT_LOOS);
+ ENUM_TO_CSTR(STT_HIOS);
+ ENUM_TO_CSTR(STT_GNU_IFUNC);
+ ENUM_TO_CSTR(STT_LOPROC);
+ ENUM_TO_CSTR(STT_HIPROC);
+ }
+ return "";
+}
+
+const char *
+ELFSymbol::sectionIndexToCString (elf_half shndx,
+ const lldb_private::SectionList *section_list)
+{
+ switch (shndx)
+ {
+ ENUM_TO_CSTR(SHN_UNDEF);
+ ENUM_TO_CSTR(SHN_LOPROC);
+ ENUM_TO_CSTR(SHN_HIPROC);
+ ENUM_TO_CSTR(SHN_LOOS);
+ ENUM_TO_CSTR(SHN_HIOS);
+ ENUM_TO_CSTR(SHN_ABS);
+ ENUM_TO_CSTR(SHN_COMMON);
+ ENUM_TO_CSTR(SHN_XINDEX);
+ default:
+ {
+ const lldb_private::Section *section = section_list->GetSectionAtIndex(shndx).get();
+ if (section)
+ return section->GetName().AsCString("");
+ }
+ break;
+ }
+ return "";
+}
+
+void
+ELFSymbol::Dump (lldb_private::Stream *s,
+ uint32_t idx,
+ const lldb_private::DataExtractor *strtab_data,
+ const lldb_private::SectionList *section_list)
+{
+ s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",
+ idx,
+ st_value,
+ st_size,
+ st_name,
+ st_info,
+ bindingToCString (getBinding()),
+ typeToCString (getType()),
+ st_other,
+ st_shndx,
+ sectionIndexToCString (st_shndx, section_list),
+ strtab_data ? strtab_data->PeekCStr(st_name) : "");
+}
+
+bool
+ELFSymbol::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+ const bool parsing_32 = byte_size == 4;
+
+ // Read st_name.
+ if (data.GetU32(offset, &st_name, 1) == NULL)
+ return false;
+
+ if (parsing_32)
+ {
+ // Read st_value and st_size.
+ if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false)
+ return false;
+
+ // Read st_info and st_other.
+ if (data.GetU8(offset, &st_info, 2) == NULL)
+ return false;
+
+ // Read st_shndx.
+ if (data.GetU16(offset, &st_shndx, 1) == NULL)
+ return false;
+ }
+ else
+ {
+ // Read st_info and st_other.
+ if (data.GetU8(offset, &st_info, 2) == NULL)
+ return false;
+
+ // Read st_shndx.
+ if (data.GetU16(offset, &st_shndx, 1) == NULL)
+ return false;
+
+ // Read st_value and st_size.
+ if (data.GetU64(offset, &st_value, 2) == NULL)
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFProgramHeader
+
+ELFProgramHeader::ELFProgramHeader()
+{
+ memset(this, 0, sizeof(ELFProgramHeader));
+}
+
+bool
+ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset)
+{
+ const uint32_t byte_size = data.GetAddressByteSize();
+ const bool parsing_32 = byte_size == 4;
+
+ // Read p_type;
+ if (data.GetU32(offset, &p_type, 1) == NULL)
+ return false;
+
+ if (parsing_32) {
+ // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.
+ if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false)
+ return false;
+
+ // Read p_flags.
+ if (data.GetU32(offset, &p_flags, 1) == NULL)
+ return false;
+
+ // Read p_align.
+ if (GetMaxU64(data, offset, &p_align, byte_size) == false)
+ return false;
+ }
+ else {
+ // Read p_flags.
+ if (data.GetU32(offset, &p_flags, 1) == NULL)
+ return false;
+
+ // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.
+ if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false)
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFDynamic
+
+ELFDynamic::ELFDynamic()
+{
+ memset(this, 0, sizeof(ELFDynamic));
+}
+
+bool
+ELFDynamic::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+ return GetMaxS64(data, offset, &d_tag, byte_size, 2);
+}
+
+//------------------------------------------------------------------------------
+// ELFRel
+
+ELFRel::ELFRel()
+{
+ memset(this, 0, sizeof(ELFRel));
+}
+
+bool
+ELFRel::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read r_offset and r_info.
+ if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
+ return false;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFRela
+
+ELFRela::ELFRela()
+{
+ memset(this, 0, sizeof(ELFRela));
+}
+
+bool
+ELFRela::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read r_offset and r_info.
+ if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
+ return false;
+
+ // Read r_addend;
+ if (GetMaxS64(data, offset, &r_addend, byte_size) == false)
+ return false;
+
+ return true;
+}
+
+
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h
new file mode 100644
index 000000000000..aa2c16b6168c
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h
@@ -0,0 +1,433 @@
+//===-- ELFHeader.h ------------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// @brief Generic structures and typedefs for ELF files.
+///
+/// This file provides definitions for the various entities comprising an ELF
+/// file. The structures are generic in the sense that they do not correspond
+/// to the exact binary layout of an ELF, but can be used to hold the
+/// information present in both 32 and 64 bit variants of the format. Each
+/// entity provides a \c Parse method which is capable of transparently reading
+/// both 32 and 64 bit instances of the object.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ELFHeader_h_
+#define liblldb_ELFHeader_h_
+
+#include "llvm/Support/ELF.h"
+
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private
+{
+class DataExtractor;
+} // End namespace lldb_private.
+
+namespace elf
+{
+
+//------------------------------------------------------------------------------
+/// @name ELF type definitions.
+///
+/// Types used to represent the various components of ELF structures. All types
+/// are signed or unsigned integral types wide enough to hold values from both
+/// 32 and 64 bit ELF variants.
+//@{
+typedef uint64_t elf_addr;
+typedef uint64_t elf_off;
+typedef uint16_t elf_half;
+typedef uint32_t elf_word;
+typedef int32_t elf_sword;
+typedef uint64_t elf_size;
+typedef uint64_t elf_xword;
+typedef int64_t elf_sxword;
+//@}
+
+//------------------------------------------------------------------------------
+/// @class ELFHeader
+/// @brief Generic representation of an ELF file header.
+///
+/// This object is used to identify the general attributes on an ELF file and to
+/// locate additional sections within the file.
+struct ELFHeader
+{
+ unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification.
+ elf_addr e_entry; ///< Virtual address program entry point.
+ elf_off e_phoff; ///< File offset of program header table.
+ elf_off e_shoff; ///< File offset of section header table.
+ elf_word e_flags; ///< Processor specific flags.
+ elf_word e_version; ///< Version of object file (always 1).
+ elf_half e_type; ///< Object file type.
+ elf_half e_machine; ///< Target architecture.
+ elf_half e_ehsize; ///< Byte size of the ELF header.
+ elf_half e_phentsize; ///< Size of a program header table entry.
+ elf_half e_phnum; ///< Number of program header entries.
+ elf_half e_shentsize; ///< Size of a section header table entry.
+ elf_half e_shnum; ///< Number of section header entries.
+ elf_half e_shstrndx; ///< String table section index.
+
+ ELFHeader();
+
+ //--------------------------------------------------------------------------
+ /// Returns true if this is a 32 bit ELF file header.
+ ///
+ /// @return
+ /// True if this is a 32 bit ELF file header.
+ bool Is32Bit() const {
+ return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32;
+ }
+
+ //--------------------------------------------------------------------------
+ /// Returns true if this is a 64 bit ELF file header.
+ ///
+ /// @return
+ /// True if this is a 64 bit ELF file header.
+ bool Is64Bit() const {
+ return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64;
+ }
+
+ //--------------------------------------------------------------------------
+ /// The byte order of this ELF file header.
+ ///
+ /// @return
+ /// The byte order of this ELF file as described by the header.
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ //--------------------------------------------------------------------------
+ /// The jump slot relocation type of this ELF.
+ unsigned
+ GetRelocationJumpSlotType() const;
+
+ //--------------------------------------------------------------------------
+ /// Parse an ELFHeader entry starting at position \p offset and
+ /// update the data extractor with the address size and byte order
+ /// attributes as defined by the header.
+ ///
+ /// @param[in,out] data
+ /// The DataExtractor to read from. Updated with the address size and
+ /// byte order attributes appropriate to this header.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ //--------------------------------------------------------------------------
+ /// Examines at most EI_NIDENT bytes starting from the given pointer and
+ /// determines if the magic ELF identification exists.
+ ///
+ /// @return
+ /// True if the given sequence of bytes identifies an ELF file.
+ static bool
+ MagicBytesMatch(const uint8_t *magic);
+
+ //--------------------------------------------------------------------------
+ /// Examines at most EI_NIDENT bytes starting from the given address and
+ /// determines the address size of the underlying ELF file. This function
+ /// should only be called on an pointer for which MagicBytesMatch returns
+ /// true.
+ ///
+ /// @return
+ /// The number of bytes forming an address in the ELF file (either 4 or
+ /// 8), else zero if the address size could not be determined.
+ static unsigned
+ AddressSizeInBytes(const uint8_t *magic);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFSectionHeader
+/// @brief Generic representation of an ELF section header.
+struct ELFSectionHeader
+{
+ elf_word sh_name; ///< Section name string index.
+ elf_word sh_type; ///< Section type.
+ elf_xword sh_flags; ///< Section attributes.
+ elf_addr sh_addr; ///< Virtual address of the section in memory.
+ elf_off sh_offset; ///< Start of section from beginning of file.
+ elf_xword sh_size; ///< Number of bytes occupied in the file.
+ elf_word sh_link; ///< Index of associated section.
+ elf_word sh_info; ///< Extra section info (overloaded).
+ elf_xword sh_addralign; ///< Power of two alignment constraint.
+ elf_xword sh_entsize; ///< Byte size of each section entry.
+
+ ELFSectionHeader();
+
+ //--------------------------------------------------------------------------
+ /// Parse an ELFSectionHeader entry from the given DataExtracter starting at
+ /// position \p offset.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFSectionHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFProgramHeader
+/// @brief Generic representation of an ELF program header.
+struct ELFProgramHeader
+{
+ elf_word p_type; ///< Type of program segment.
+ elf_word p_flags; ///< Segment attributes.
+ elf_off p_offset; ///< Start of segment from beginning of file.
+ elf_addr p_vaddr; ///< Virtual address of segment in memory.
+ elf_addr p_paddr; ///< Physical address (for non-VM systems).
+ elf_xword p_filesz; ///< Byte size of the segment in file.
+ elf_xword p_memsz; ///< Byte size of the segment in memory.
+ elf_xword p_align; ///< Segment alignment constraint.
+
+ ELFProgramHeader();
+
+ /// Parse an ELFProgramHeader entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFProgramHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFSymbol
+/// @brief Represents a symbol within an ELF symbol table.
+struct ELFSymbol
+{
+ elf_addr st_value; ///< Absolute or relocatable address.
+ elf_xword st_size; ///< Size of the symbol or zero.
+ elf_word st_name; ///< Symbol name string index.
+ unsigned char st_info; ///< Symbol type and binding attributes.
+ unsigned char st_other; ///< Reserved for future use.
+ elf_half st_shndx; ///< Section to which this symbol applies.
+
+ ELFSymbol();
+
+ /// Returns the binding attribute of the st_info member.
+ unsigned char getBinding() const { return st_info >> 4; }
+
+ /// Returns the type attribute of the st_info member.
+ unsigned char getType() const { return st_info & 0x0F; }
+
+ /// Sets the binding and type of the st_info member.
+ void setBindingAndType(unsigned char binding, unsigned char type) {
+ st_info = (binding << 4) + (type & 0x0F);
+ }
+
+ static const char *
+ bindingToCString(unsigned char binding);
+
+ static const char *
+ typeToCString(unsigned char type);
+
+ static const char *
+ sectionIndexToCString(elf_half shndx,
+ const lldb_private::SectionList *section_list);
+
+ /// Parse an ELFSymbol entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFSymbol was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ void
+ Dump (lldb_private::Stream *s,
+ uint32_t idx,
+ const lldb_private::DataExtractor *strtab_data,
+ const lldb_private::SectionList *section_list);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFDynamic
+/// @brief Represents an entry in an ELF dynamic table.
+struct ELFDynamic
+{
+ elf_sxword d_tag; ///< Type of dynamic table entry.
+ union
+ {
+ elf_xword d_val; ///< Integer value of the table entry.
+ elf_addr d_ptr; ///< Pointer value of the table entry.
+ };
+
+ ELFDynamic();
+
+ /// Parse an ELFDynamic entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFDynamic entry was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFRel
+/// @brief Represents a relocation entry with an implicit addend.
+struct ELFRel
+{
+ elf_addr r_offset; ///< Address of reference.
+ elf_xword r_info; ///< symbol index and type of relocation.
+
+ ELFRel();
+
+ /// Parse an ELFRel entry from the given DataExtractor starting at position
+ /// \p offset. The address size of the DataExtractor determines if a 32 or
+ /// 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRel entry was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ /// Returns the type when the given entry represents a 32-bit relocation.
+ static unsigned
+ RelocType32(const ELFRel &rel)
+ {
+ return rel.r_info & 0x0ff;
+ }
+
+ /// Returns the type when the given entry represents a 64-bit relocation.
+ static unsigned
+ RelocType64(const ELFRel &rel)
+ {
+ return rel.r_info & 0xffffffff;
+ }
+
+ /// Returns the symbol index when the given entry represents a 32-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol32(const ELFRel &rel)
+ {
+ return rel.r_info >> 8;
+ }
+
+ /// Returns the symbol index when the given entry represents a 64-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol64(const ELFRel &rel)
+ {
+ return rel.r_info >> 32;
+ }
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFRela
+/// @brief Represents a relocation entry with an explicit addend.
+struct ELFRela
+{
+ elf_addr r_offset; ///< Address of reference.
+ elf_xword r_info; ///< Symbol index and type of relocation.
+ elf_sxword r_addend; ///< Constant part of expression.
+
+ ELFRela();
+
+ /// Parse an ELFRela entry from the given DataExtractor starting at position
+ /// \p offset. The address size of the DataExtractor determines if a 32 or
+ /// 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRela entry was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ /// Returns the type when the given entry represents a 32-bit relocation.
+ static unsigned
+ RelocType32(const ELFRela &rela)
+ {
+ return rela.r_info & 0x0ff;
+ }
+
+ /// Returns the type when the given entry represents a 64-bit relocation.
+ static unsigned
+ RelocType64(const ELFRela &rela)
+ {
+ return rela.r_info & 0xffffffff;
+ }
+
+ /// Returns the symbol index when the given entry represents a 32-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol32(const ELFRela &rela)
+ {
+ return rela.r_info >> 8;
+ }
+
+ /// Returns the symbol index when the given entry represents a 64-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol64(const ELFRela &rela)
+ {
+ return rela.r_info >> 32;
+ }
+};
+
+} // End namespace elf.
+
+#endif // #ifndef liblldb_ELFHeader_h_
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
new file mode 100644
index 000000000000..2e9f6903280c
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -0,0 +1,1893 @@
+//===-- ObjectFileELF.cpp ------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileELF.h"
+
+#include <cassert>
+#include <algorithm>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Host/Host.h"
+
+#include "llvm/ADT/PointerUnion.h"
+
+#define CASE_AND_STREAM(s, def, width) \
+ case def: s->Printf("%-*s", width, #def); break;
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace elf;
+using namespace llvm::ELF;
+
+namespace {
+//===----------------------------------------------------------------------===//
+/// @class ELFRelocation
+/// @brief Generic wrapper for ELFRel and ELFRela.
+///
+/// This helper class allows us to parse both ELFRel and ELFRela relocation
+/// entries in a generic manner.
+class ELFRelocation
+{
+public:
+
+ /// Constructs an ELFRelocation entry with a personality as given by @p
+ /// type.
+ ///
+ /// @param type Either DT_REL or DT_RELA. Any other value is invalid.
+ ELFRelocation(unsigned type);
+
+ ~ELFRelocation();
+
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ static unsigned
+ RelocType32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocType64(const ELFRelocation &rel);
+
+ static unsigned
+ RelocSymbol32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocSymbol64(const ELFRelocation &rel);
+
+private:
+ typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion;
+
+ RelocUnion reloc;
+};
+
+ELFRelocation::ELFRelocation(unsigned type)
+{
+ if (type == DT_REL)
+ reloc = new ELFRel();
+ else if (type == DT_RELA)
+ reloc = new ELFRela();
+ else {
+ assert(false && "unexpected relocation type");
+ reloc = static_cast<ELFRel*>(NULL);
+ }
+}
+
+ELFRelocation::~ELFRelocation()
+{
+ if (reloc.is<ELFRel*>())
+ delete reloc.get<ELFRel*>();
+ else
+ delete reloc.get<ELFRela*>();
+}
+
+bool
+ELFRelocation::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ if (reloc.is<ELFRel*>())
+ return reloc.get<ELFRel*>()->Parse(data, offset);
+ else
+ return reloc.get<ELFRela*>()->Parse(data, offset);
+}
+
+unsigned
+ELFRelocation::RelocType32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocType32(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocType32(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocType64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocType64(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocType64(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocSymbol32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocSymbol32(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocSymbol32(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocSymbol64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocSymbol64(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>());
+}
+
+} // end anonymous namespace
+
+//------------------------------------------------------------------
+// Static methods.
+//------------------------------------------------------------------
+void
+ObjectFileELF::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ CreateMemoryInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectFileELF::Terminate()
+{
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+ObjectFileELF::GetPluginNameStatic()
+{
+ static ConstString g_name("elf");
+ return g_name;
+}
+
+const char *
+ObjectFileELF::GetPluginDescriptionStatic()
+{
+ return "ELF object file reader.";
+}
+
+ObjectFile *
+ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ if (!data_sp)
+ {
+ data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_offset = 0;
+ }
+
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset))
+ {
+ const uint8_t *magic = data_sp->GetBytes() + data_offset;
+ if (ELFHeader::MagicBytesMatch(magic))
+ {
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length) {
+ data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_offset = 0;
+ magic = data_sp->GetBytes();
+ }
+ unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
+ if (address_size == 4 || address_size == 8)
+ {
+ std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, data_offset, file, file_offset, length));
+ ArchSpec spec;
+ if (objfile_ap->GetArchitecture(spec) &&
+ objfile_ap->SetModulesArchitecture(spec))
+ return objfile_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+ObjectFile*
+ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+{
+ return NULL;
+}
+
+bool
+ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp,
+ lldb::addr_t data_offset,
+ lldb::addr_t data_length)
+{
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset))
+ {
+ const uint8_t *magic = data_sp->GetBytes() + data_offset;
+ return ELFHeader::MagicBytesMatch(magic);
+ }
+ return false;
+}
+
+/*
+ * crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c
+ *
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+static uint32_t
+calc_gnu_debuglink_crc32(const void *buf, size_t size)
+{
+ static const uint32_t g_crc32_tab[] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ };
+ const uint8_t *p = (const uint8_t *)buf;
+ uint32_t crc;
+
+ crc = ~0U;
+ while (size--)
+ crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ return crc ^ ~0U;
+}
+
+size_t
+ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs)
+{
+ const size_t initial_count = specs.GetSize();
+
+ if (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
+ {
+ DataExtractor data;
+ data.SetData(data_sp);
+ elf::ELFHeader header;
+ if (header.Parse(data, &data_offset))
+ {
+ if (data_sp)
+ {
+ ModuleSpec spec;
+ spec.GetFileSpec() = file;
+ spec.GetArchitecture().SetArchitecture(eArchTypeELF,
+ header.e_machine,
+ LLDB_INVALID_CPUTYPE);
+ if (spec.GetArchitecture().IsValid())
+ {
+ // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the
+ // machine information. However, this info isn't guaranteed to exist or be correct. Details:
+ // http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
+ // Instead of passing potentially incorrect information down the pipeline, grab
+ // the host information and use it.
+ spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString());
+ spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString());
+
+ // Try to get the UUID from the section list. Usually that's at the end, so
+ // map the file in if we don't have it already.
+ size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize;
+ if (section_header_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents (file_offset, section_header_end);
+ data.SetData(data_sp);
+ }
+
+ uint32_t gnu_debuglink_crc = 0;
+ std::string gnu_debuglink_file;
+ SectionHeaderColl section_headers;
+ lldb_private::UUID &uuid = spec.GetUUID();
+ GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc);
+
+ if (!uuid.IsValid())
+ {
+ if (!gnu_debuglink_crc)
+ {
+ // Need to map entire file into memory to calculate the crc.
+ data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
+ data.SetData(data_sp);
+ gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ }
+ if (gnu_debuglink_crc)
+ {
+ // Use 4 bytes of crc from the .gnu_debuglink section.
+ uint32_t uuidt[4] = { gnu_debuglink_crc, 0, 0, 0 };
+ uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
+ }
+
+ specs.Append(spec);
+ }
+ }
+ }
+ }
+
+ return specs.GetSize() - initial_count;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectFileELF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileELF::GetPluginVersion()
+{
+ return m_plugin_version;
+}
+//------------------------------------------------------------------
+// ObjectFile protocol
+//------------------------------------------------------------------
+
+ObjectFileELF::ObjectFileELF (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length) :
+ ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
+ m_header(),
+ m_program_headers(),
+ m_section_headers(),
+ m_filespec_ap()
+{
+ if (file)
+ m_file = *file;
+ ::memset(&m_header, 0, sizeof(m_header));
+ m_gnu_debuglink_crc = 0;
+ m_gnu_debuglink_file.clear();
+}
+
+ObjectFileELF::~ObjectFileELF()
+{
+}
+
+bool
+ObjectFileELF::IsExecutable() const
+{
+ return m_header.e_entry != 0;
+}
+
+ByteOrder
+ObjectFileELF::GetByteOrder() const
+{
+ if (m_header.e_ident[EI_DATA] == ELFDATA2MSB)
+ return eByteOrderBig;
+ if (m_header.e_ident[EI_DATA] == ELFDATA2LSB)
+ return eByteOrderLittle;
+ return eByteOrderInvalid;
+}
+
+uint32_t
+ObjectFileELF::GetAddressByteSize() const
+{
+ return m_data.GetAddressByteSize();
+}
+
+size_t
+ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I)
+{
+ return std::distance(m_section_headers.begin(), I) + 1u;
+}
+
+size_t
+ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const
+{
+ return std::distance(m_section_headers.begin(), I) + 1u;
+}
+
+bool
+ObjectFileELF::ParseHeader()
+{
+ lldb::offset_t offset = 0;
+ return m_header.Parse(m_data, &offset);
+}
+
+bool
+ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
+{
+ // Need to parse the section list to get the UUIDs, so make sure that's been done.
+ if (!ParseSectionHeaders())
+ return false;
+
+ if (m_uuid.IsValid())
+ {
+ // We have the full build id uuid.
+ *uuid = m_uuid;
+ return true;
+ }
+ else
+ {
+ if (!m_gnu_debuglink_crc)
+ m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize());
+ if (m_gnu_debuglink_crc)
+ {
+ // Use 4 bytes of crc from the .gnu_debuglink section.
+ uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 };
+ uuid->SetBytes (uuidt, sizeof(uuidt));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+lldb_private::FileSpecList
+ObjectFileELF::GetDebugSymbolFilePaths()
+{
+ FileSpecList file_spec_list;
+
+ if (!m_gnu_debuglink_file.empty())
+ {
+ FileSpec file_spec (m_gnu_debuglink_file.c_str(), false);
+ file_spec_list.Append (file_spec);
+ }
+ return file_spec_list;
+}
+
+uint32_t
+ObjectFileELF::GetDependentModules(FileSpecList &files)
+{
+ size_t num_modules = ParseDependentModules();
+ uint32_t num_specs = 0;
+
+ for (unsigned i = 0; i < num_modules; ++i)
+ {
+ if (files.AppendIfUnique(m_filespec_ap->GetFileSpecAtIndex(i)))
+ num_specs++;
+ }
+
+ return num_specs;
+}
+
+Address
+ObjectFileELF::GetImageInfoAddress()
+{
+ if (!ParseDynamicSymbols())
+ return Address();
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return Address();
+
+ // Find the SHT_DYNAMIC (.dynamic) section.
+ SectionSP dynsym_section_sp (section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true));
+ if (!dynsym_section_sp)
+ return Address();
+ assert (dynsym_section_sp->GetObjectFile() == this);
+
+ user_id_t dynsym_id = dynsym_section_sp->GetID();
+ const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id);
+ if (!dynsym_hdr)
+ return Address();
+
+ for (size_t i = 0; i < m_dynamic_symbols.size(); ++i)
+ {
+ ELFDynamic &symbol = m_dynamic_symbols[i];
+
+ if (symbol.d_tag == DT_DEBUG)
+ {
+ // Compute the offset as the number of previous entries plus the
+ // size of d_tag.
+ addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize();
+ return Address(dynsym_section_sp, offset);
+ }
+ }
+
+ return Address();
+}
+
+lldb_private::Address
+ObjectFileELF::GetEntryPointAddress ()
+{
+ if (m_entry_point_address.IsValid())
+ return m_entry_point_address;
+
+ if (!ParseHeader() || !IsExecutable())
+ return m_entry_point_address;
+
+ SectionList *section_list = GetSectionList();
+ addr_t offset = m_header.e_entry;
+
+ if (!section_list)
+ m_entry_point_address.SetOffset(offset);
+ else
+ m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list);
+ return m_entry_point_address;
+}
+
+//----------------------------------------------------------------------
+// ParseDependentModules
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseDependentModules()
+{
+ if (m_filespec_ap.get())
+ return m_filespec_ap->GetSize();
+
+ m_filespec_ap.reset(new FileSpecList());
+
+ if (!ParseSectionHeaders())
+ return 0;
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Find the SHT_DYNAMIC section.
+ Section *dynsym = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
+ if (!dynsym)
+ return 0;
+ assert (dynsym->GetObjectFile() == this);
+
+ const ELFSectionHeaderInfo *header = GetSectionHeaderByIndex (dynsym->GetID());
+ if (!header)
+ return 0;
+ // sh_link: section header index of string table used by entries in the section.
+ Section *dynstr = section_list->FindSectionByID (header->sh_link + 1).get();
+ if (!dynstr)
+ return 0;
+
+ DataExtractor dynsym_data;
+ DataExtractor dynstr_data;
+ if (ReadSectionData(dynsym, dynsym_data) &&
+ ReadSectionData(dynstr, dynstr_data))
+ {
+ ELFDynamic symbol;
+ const lldb::offset_t section_size = dynsym_data.GetByteSize();
+ lldb::offset_t offset = 0;
+
+ // The only type of entries we are concerned with are tagged DT_NEEDED,
+ // yielding the name of a required library.
+ while (offset < section_size)
+ {
+ if (!symbol.Parse(dynsym_data, &offset))
+ break;
+
+ if (symbol.d_tag != DT_NEEDED)
+ continue;
+
+ uint32_t str_index = static_cast<uint32_t>(symbol.d_val);
+ const char *lib_name = dynstr_data.PeekCStr(str_index);
+ m_filespec_ap->Append(FileSpec(lib_name, true));
+ }
+ }
+
+ return m_filespec_ap->GetSize();
+}
+
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ // We have already parsed the program headers
+ if (!m_program_headers.empty())
+ return m_program_headers.size();
+
+ // If there are no program headers to read we are done.
+ if (m_header.e_phnum == 0)
+ return 0;
+
+ m_program_headers.resize(m_header.e_phnum);
+ if (m_program_headers.size() != m_header.e_phnum)
+ return 0;
+
+ const size_t ph_size = m_header.e_phnum * m_header.e_phentsize;
+ const elf_off ph_offset = m_header.e_phoff;
+ DataExtractor data;
+ if (GetData (ph_offset, ph_size, data) != ph_size)
+ return 0;
+
+ uint32_t idx;
+ lldb::offset_t offset;
+ for (idx = 0, offset = 0; idx < m_header.e_phnum; ++idx)
+ {
+ if (m_program_headers[idx].Parse(data, &offset) == false)
+ break;
+ }
+
+ if (idx < m_program_headers.size())
+ m_program_headers.resize(idx);
+
+ return m_program_headers.size();
+}
+
+static bool
+ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid)
+{
+ // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id.
+ // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId
+ struct
+ {
+ uint32_t name_len; // Length of note name
+ uint32_t desc_len; // Length of note descriptor
+ uint32_t type; // Type of note (1 is ABI_TAG, 3 is BUILD_ID)
+ } notehdr;
+ lldb::offset_t offset = 0;
+ static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h
+
+ while (true)
+ {
+ if (data.GetU32 (&offset, &notehdr, 3) == NULL)
+ return false;
+
+ notehdr.name_len = llvm::RoundUpToAlignment (notehdr.name_len, 4);
+ notehdr.desc_len = llvm::RoundUpToAlignment (notehdr.desc_len, 4);
+
+ lldb::offset_t offset_next_note = offset + notehdr.name_len + notehdr.desc_len;
+
+ // 16 bytes is UUID|MD5, 20 bytes is SHA1
+ if ((notehdr.type == g_gnu_build_id) && (notehdr.name_len == 4) &&
+ (notehdr.desc_len == 16 || notehdr.desc_len == 20))
+ {
+ char name[4];
+ if (data.GetU8 (&offset, name, 4) == NULL)
+ return false;
+ if (!strcmp(name, "GNU"))
+ {
+ uint8_t uuidbuf[20];
+ if (data.GetU8 (&offset, &uuidbuf, notehdr.desc_len) == NULL)
+ return false;
+ uuid.SetBytes (uuidbuf, notehdr.desc_len);
+ return true;
+ }
+ }
+ offset = offset_next_note;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// GetSectionHeaderInfo
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+ lldb_private::DataExtractor &object_data,
+ const elf::ELFHeader &header,
+ lldb_private::UUID &uuid,
+ std::string &gnu_debuglink_file,
+ uint32_t &gnu_debuglink_crc)
+{
+ // We have already parsed the section headers
+ if (!section_headers.empty())
+ return section_headers.size();
+
+ // If there are no section headers we are done.
+ if (header.e_shnum == 0)
+ return 0;
+
+ section_headers.resize(header.e_shnum);
+ if (section_headers.size() != header.e_shnum)
+ return 0;
+
+ const size_t sh_size = header.e_shnum * header.e_shentsize;
+ const elf_off sh_offset = header.e_shoff;
+ DataExtractor sh_data;
+ if (sh_data.SetData (object_data, sh_offset, sh_size) != sh_size)
+ return 0;
+
+ uint32_t idx;
+ lldb::offset_t offset;
+ for (idx = 0, offset = 0; idx < header.e_shnum; ++idx)
+ {
+ if (section_headers[idx].Parse(sh_data, &offset) == false)
+ break;
+ }
+ if (idx < section_headers.size())
+ section_headers.resize(idx);
+
+ const unsigned strtab_idx = header.e_shstrndx;
+ if (strtab_idx && strtab_idx < section_headers.size())
+ {
+ const ELFSectionHeaderInfo &sheader = section_headers[strtab_idx];
+ const size_t byte_size = sheader.sh_size;
+ const Elf64_Off offset = sheader.sh_offset;
+ lldb_private::DataExtractor shstr_data;
+
+ if (shstr_data.SetData (object_data, offset, byte_size) == byte_size)
+ {
+ for (SectionHeaderCollIter I = section_headers.begin();
+ I != section_headers.end(); ++I)
+ {
+ static ConstString g_sect_name_gnu_debuglink (".gnu_debuglink");
+ const ELFSectionHeaderInfo &header = *I;
+ const uint64_t section_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+ ConstString name(shstr_data.PeekCStr(I->sh_name));
+
+ I->section_name = name;
+
+ if (name == g_sect_name_gnu_debuglink)
+ {
+ DataExtractor data;
+ if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+ {
+ lldb::offset_t gnu_debuglink_offset = 0;
+ gnu_debuglink_file = data.GetCStr (&gnu_debuglink_offset);
+ gnu_debuglink_offset = llvm::RoundUpToAlignment (gnu_debuglink_offset, 4);
+ data.GetU32 (&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
+ }
+ }
+
+ if (header.sh_type == SHT_NOTE && !uuid.IsValid())
+ {
+ DataExtractor data;
+ if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+ {
+ ParseNoteGNUBuildID (data, uuid);
+ }
+ }
+ }
+
+ return section_headers.size();
+ }
+ }
+
+ section_headers.clear();
+ return 0;
+}
+
+size_t
+ObjectFileELF::GetProgramHeaderCount()
+{
+ return ParseProgramHeaders();
+}
+
+const elf::ELFProgramHeader *
+ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id)
+{
+ if (!id || !ParseProgramHeaders())
+ return NULL;
+
+ if (--id < m_program_headers.size())
+ return &m_program_headers[id];
+
+ return NULL;
+}
+
+DataExtractor
+ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
+{
+ const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id);
+ if (segment_header == NULL)
+ return DataExtractor();
+ return DataExtractor(m_data, segment_header->p_offset, segment_header->p_filesz);
+}
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseSectionHeaders()
+{
+ return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc);
+}
+
+const ObjectFileELF::ELFSectionHeaderInfo *
+ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
+{
+ if (!id || !ParseSectionHeaders())
+ return NULL;
+
+ if (--id < m_section_headers.size())
+ return &m_section_headers[id];
+
+ return NULL;
+}
+
+void
+ObjectFileELF::CreateSections(SectionList &unified_section_list)
+{
+ if (!m_sections_ap.get() && ParseSectionHeaders())
+ {
+ m_sections_ap.reset(new SectionList());
+
+ for (SectionHeaderCollIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I)
+ {
+ const ELFSectionHeaderInfo &header = *I;
+
+ ConstString& name = I->section_name;
+ const uint64_t file_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+ const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0;
+
+ static ConstString g_sect_name_text (".text");
+ static ConstString g_sect_name_data (".data");
+ static ConstString g_sect_name_bss (".bss");
+ static ConstString g_sect_name_tdata (".tdata");
+ static ConstString g_sect_name_tbss (".tbss");
+ static ConstString g_sect_name_dwarf_debug_abbrev (".debug_abbrev");
+ static ConstString g_sect_name_dwarf_debug_aranges (".debug_aranges");
+ static ConstString g_sect_name_dwarf_debug_frame (".debug_frame");
+ static ConstString g_sect_name_dwarf_debug_info (".debug_info");
+ static ConstString g_sect_name_dwarf_debug_line (".debug_line");
+ static ConstString g_sect_name_dwarf_debug_loc (".debug_loc");
+ static ConstString g_sect_name_dwarf_debug_macinfo (".debug_macinfo");
+ static ConstString g_sect_name_dwarf_debug_pubnames (".debug_pubnames");
+ static ConstString g_sect_name_dwarf_debug_pubtypes (".debug_pubtypes");
+ static ConstString g_sect_name_dwarf_debug_ranges (".debug_ranges");
+ static ConstString g_sect_name_dwarf_debug_str (".debug_str");
+ static ConstString g_sect_name_eh_frame (".eh_frame");
+
+ SectionType sect_type = eSectionTypeOther;
+
+ bool is_thread_specific = false;
+
+ if (name == g_sect_name_text) sect_type = eSectionTypeCode;
+ else if (name == g_sect_name_data) sect_type = eSectionTypeData;
+ else if (name == g_sect_name_bss) sect_type = eSectionTypeZeroFill;
+ else if (name == g_sect_name_tdata)
+ {
+ sect_type = eSectionTypeData;
+ is_thread_specific = true;
+ }
+ else if (name == g_sect_name_tbss)
+ {
+ sect_type = eSectionTypeZeroFill;
+ is_thread_specific = true;
+ }
+ // .debug_abbrev – Abbreviations used in the .debug_info section
+ // .debug_aranges – Lookup table for mapping addresses to compilation units
+ // .debug_frame – Call frame information
+ // .debug_info – The core DWARF information section
+ // .debug_line – Line number information
+ // .debug_loc – Location lists used in DW_AT_location attributes
+ // .debug_macinfo – Macro information
+ // .debug_pubnames – Lookup table for mapping object and function names to compilation units
+ // .debug_pubtypes – Lookup table for mapping type names to compilation units
+ // .debug_ranges – Address ranges used in DW_AT_ranges attributes
+ // .debug_str – String table used in .debug_info
+ // MISSING? .gnu_debugdata - "mini debuginfo / MiniDebugInfo" section, http://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html
+ // MISSING? .debug-index - http://src.chromium.org/viewvc/chrome/trunk/src/build/gdb-add-index?pathrev=144644
+ // MISSING? .debug_types - Type descriptions from DWARF 4? See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo
+ else if (name == g_sect_name_dwarf_debug_abbrev) sect_type = eSectionTypeDWARFDebugAbbrev;
+ else if (name == g_sect_name_dwarf_debug_aranges) sect_type = eSectionTypeDWARFDebugAranges;
+ else if (name == g_sect_name_dwarf_debug_frame) sect_type = eSectionTypeDWARFDebugFrame;
+ else if (name == g_sect_name_dwarf_debug_info) sect_type = eSectionTypeDWARFDebugInfo;
+ else if (name == g_sect_name_dwarf_debug_line) sect_type = eSectionTypeDWARFDebugLine;
+ else if (name == g_sect_name_dwarf_debug_loc) sect_type = eSectionTypeDWARFDebugLoc;
+ else if (name == g_sect_name_dwarf_debug_macinfo) sect_type = eSectionTypeDWARFDebugMacInfo;
+ else if (name == g_sect_name_dwarf_debug_pubnames) sect_type = eSectionTypeDWARFDebugPubNames;
+ else if (name == g_sect_name_dwarf_debug_pubtypes) sect_type = eSectionTypeDWARFDebugPubTypes;
+ else if (name == g_sect_name_dwarf_debug_ranges) sect_type = eSectionTypeDWARFDebugRanges;
+ else if (name == g_sect_name_dwarf_debug_str) sect_type = eSectionTypeDWARFDebugStr;
+ else if (name == g_sect_name_eh_frame) sect_type = eSectionTypeEHFrame;
+
+ switch (header.sh_type)
+ {
+ case SHT_SYMTAB:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFSymbolTable;
+ break;
+ case SHT_DYNSYM:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFDynamicSymbols;
+ break;
+ case SHT_RELA:
+ case SHT_REL:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFRelocationEntries;
+ break;
+ case SHT_DYNAMIC:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFDynamicLinkInfo;
+ break;
+ }
+
+ SectionSP section_sp (new Section(GetModule(), // Module to which this section belongs.
+ this, // ObjectFile to which this section belongs and should read section data from.
+ SectionIndex(I), // Section ID.
+ name, // Section name.
+ sect_type, // Section type.
+ header.sh_addr, // VM address.
+ vm_size, // VM size in bytes of this section.
+ header.sh_offset, // Offset of this section in the file.
+ file_size, // Size of the section as found in the file.
+ header.sh_flags)); // Flags for this section.
+
+ if (is_thread_specific)
+ section_sp->SetIsThreadSpecific (is_thread_specific);
+ m_sections_ap->AddSection(section_sp);
+ }
+ }
+
+ if (m_sections_ap.get())
+ {
+ if (GetType() == eTypeDebugInfo)
+ {
+ static const SectionType g_sections[] =
+ {
+ eSectionTypeDWARFDebugAranges,
+ eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugFrame,
+ eSectionTypeDWARFDebugLine,
+ eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugMacInfo,
+ eSectionTypeDWARFDebugPubNames,
+ eSectionTypeDWARFDebugPubTypes,
+ eSectionTypeDWARFDebugRanges,
+ eSectionTypeELFSymbolTable,
+ };
+ SectionList *elf_section_list = m_sections_ap.get();
+ for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx)
+ {
+ SectionType section_type = g_sections[idx];
+ SectionSP section_sp (elf_section_list->FindSectionByType (section_type, true));
+ if (section_sp)
+ {
+ SectionSP module_section_sp (unified_section_list.FindSectionByType (section_type, true));
+ if (module_section_sp)
+ unified_section_list.ReplaceSection (module_section_sp->GetID(), section_sp);
+ else
+ unified_section_list.AddSection (section_sp);
+ }
+ }
+ }
+ else
+ {
+ unified_section_list = *m_sections_ap;
+ }
+ }
+}
+
+// private
+unsigned
+ObjectFileELF::ParseSymbols (Symtab *symtab,
+ user_id_t start_id,
+ SectionList *section_list,
+ const size_t num_symbols,
+ const DataExtractor &symtab_data,
+ const DataExtractor &strtab_data)
+{
+ ELFSymbol symbol;
+ lldb::offset_t offset = 0;
+
+ static ConstString text_section_name(".text");
+ static ConstString init_section_name(".init");
+ static ConstString fini_section_name(".fini");
+ static ConstString ctors_section_name(".ctors");
+ static ConstString dtors_section_name(".dtors");
+
+ static ConstString data_section_name(".data");
+ static ConstString rodata_section_name(".rodata");
+ static ConstString rodata1_section_name(".rodata1");
+ static ConstString data2_section_name(".data1");
+ static ConstString bss_section_name(".bss");
+
+ //StreamFile strm(stdout, false);
+ unsigned i;
+ for (i = 0; i < num_symbols; ++i)
+ {
+ if (symbol.Parse(symtab_data, &offset) == false)
+ break;
+
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+
+ // No need to add symbols that have no names
+ if (symbol_name == NULL || symbol_name[0] == '\0')
+ continue;
+
+ //symbol.Dump (&strm, i, &strtab_data, section_list);
+
+ SectionSP symbol_section_sp;
+ SymbolType symbol_type = eSymbolTypeInvalid;
+ Elf64_Half symbol_idx = symbol.st_shndx;
+
+ switch (symbol_idx)
+ {
+ case SHN_ABS:
+ symbol_type = eSymbolTypeAbsolute;
+ break;
+ case SHN_UNDEF:
+ symbol_type = eSymbolTypeUndefined;
+ break;
+ default:
+ symbol_section_sp = section_list->GetSectionAtIndex(symbol_idx);
+ break;
+ }
+
+ // If a symbol is undefined do not process it further even if it has a STT type
+ if (symbol_type != eSymbolTypeUndefined)
+ {
+ switch (symbol.getType())
+ {
+ default:
+ case STT_NOTYPE:
+ // The symbol's type is not specified.
+ break;
+
+ case STT_OBJECT:
+ // The symbol is associated with a data object, such as a variable,
+ // an array, etc.
+ symbol_type = eSymbolTypeData;
+ break;
+
+ case STT_FUNC:
+ // The symbol is associated with a function or other executable code.
+ symbol_type = eSymbolTypeCode;
+ break;
+
+ case STT_SECTION:
+ // The symbol is associated with a section. Symbol table entries of
+ // this type exist primarily for relocation and normally have
+ // STB_LOCAL binding.
+ break;
+
+ case STT_FILE:
+ // Conventionally, the symbol's name gives the name of the source
+ // file associated with the object file. A file symbol has STB_LOCAL
+ // binding, its section index is SHN_ABS, and it precedes the other
+ // STB_LOCAL symbols for the file, if it is present.
+ symbol_type = eSymbolTypeSourceFile;
+ break;
+
+ case STT_GNU_IFUNC:
+ // The symbol is associated with an indirect function. The actual
+ // function will be resolved if it is referenced.
+ symbol_type = eSymbolTypeResolver;
+ break;
+ }
+ }
+
+ if (symbol_type == eSymbolTypeInvalid)
+ {
+ if (symbol_section_sp)
+ {
+ const ConstString &sect_name = symbol_section_sp->GetName();
+ if (sect_name == text_section_name ||
+ sect_name == init_section_name ||
+ sect_name == fini_section_name ||
+ sect_name == ctors_section_name ||
+ sect_name == dtors_section_name)
+ {
+ symbol_type = eSymbolTypeCode;
+ }
+ else if (sect_name == data_section_name ||
+ sect_name == data2_section_name ||
+ sect_name == rodata_section_name ||
+ sect_name == rodata1_section_name ||
+ sect_name == bss_section_name)
+ {
+ symbol_type = eSymbolTypeData;
+ }
+ }
+ }
+
+ // 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))
+ {
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ SectionList *module_section_list = module_sp->GetSectionList();
+ if (module_section_list && module_section_list != section_list)
+ {
+ const ConstString &sect_name = symbol_section_sp->GetName();
+ lldb::SectionSP section_sp (module_section_list->FindSectionByName (sect_name));
+ if (section_sp && section_sp->GetFileSize())
+ {
+ symbol_section_sp = section_sp;
+ }
+ }
+ }
+ }
+
+ uint64_t symbol_value = symbol.st_value;
+ if (symbol_section_sp)
+ symbol_value -= symbol_section_sp->GetFileAddress();
+ bool is_global = symbol.getBinding() == STB_GLOBAL;
+ uint32_t flags = symbol.st_other << 8 | symbol.st_info;
+ 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.
+ is_mangled, // Is the symbol name mangled?
+ symbol_type, // Type of this symbol
+ is_global, // Is this globally visible?
+ false, // Is this symbol debug info?
+ false, // Is this symbol a trampoline?
+ false, // Is this symbol artificial?
+ symbol_section_sp, // Section in which this symbol is defined or null.
+ symbol_value, // Offset in section or symbol value.
+ symbol.st_size, // Size in bytes of this symbol.
+ true, // Size is valid
+ flags); // Symbol flags.
+ symtab->AddSymbol(dc_symbol);
+ }
+
+ return i;
+}
+
+unsigned
+ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_private::Section *symtab)
+{
+ if (symtab->GetObjectFile() != this)
+ {
+ // If the symbol table section is owned by a different object file, have it do the
+ // parsing.
+ ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile());
+ return obj_file_elf->ParseSymbolTable (symbol_table, start_id, symtab);
+ }
+
+ // Get section list for this object file.
+ SectionList *section_list = m_sections_ap.get();
+ if (!section_list)
+ return 0;
+
+ user_id_t symtab_id = symtab->GetID();
+ const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id);
+ assert(symtab_hdr->sh_type == SHT_SYMTAB ||
+ symtab_hdr->sh_type == SHT_DYNSYM);
+
+ // sh_link: section header index of associated string table.
+ // Section ID's are ones based.
+ user_id_t strtab_id = symtab_hdr->sh_link + 1;
+ Section *strtab = section_list->FindSectionByID(strtab_id).get();
+
+ unsigned num_symbols = 0;
+ if (symtab && strtab)
+ {
+ assert (symtab->GetObjectFile() == this);
+ assert (strtab->GetObjectFile() == this);
+
+ DataExtractor symtab_data;
+ DataExtractor strtab_data;
+ if (ReadSectionData(symtab, symtab_data) &&
+ ReadSectionData(strtab, strtab_data))
+ {
+ size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize;
+
+ num_symbols = ParseSymbols(symbol_table, start_id,
+ section_list, num_symbols,
+ symtab_data, strtab_data);
+ }
+ }
+
+ return num_symbols;
+}
+
+size_t
+ObjectFileELF::ParseDynamicSymbols()
+{
+ if (m_dynamic_symbols.size())
+ return m_dynamic_symbols.size();
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Find the SHT_DYNAMIC section.
+ Section *dynsym = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
+ if (!dynsym)
+ return 0;
+ assert (dynsym->GetObjectFile() == this);
+
+ ELFDynamic symbol;
+ DataExtractor dynsym_data;
+ if (ReadSectionData(dynsym, dynsym_data))
+ {
+ const lldb::offset_t section_size = dynsym_data.GetByteSize();
+ lldb::offset_t cursor = 0;
+
+ while (cursor < section_size)
+ {
+ if (!symbol.Parse(dynsym_data, &cursor))
+ break;
+
+ m_dynamic_symbols.push_back(symbol);
+ }
+ }
+
+ return m_dynamic_symbols.size();
+}
+
+const ELFDynamic *
+ObjectFileELF::FindDynamicSymbol(unsigned tag)
+{
+ if (!ParseDynamicSymbols())
+ return NULL;
+
+ DynamicSymbolCollIter I = m_dynamic_symbols.begin();
+ DynamicSymbolCollIter E = m_dynamic_symbols.end();
+ for ( ; I != E; ++I)
+ {
+ ELFDynamic *symbol = &*I;
+
+ if (symbol->d_tag == tag)
+ return symbol;
+ }
+
+ return NULL;
+}
+
+unsigned
+ObjectFileELF::PLTRelocationType()
+{
+ const ELFDynamic *symbol = FindDynamicSymbol(DT_PLTREL);
+
+ if (symbol)
+ return symbol->d_val;
+
+ return 0;
+}
+
+static unsigned
+ParsePLTRelocations(Symtab *symbol_table,
+ user_id_t start_id,
+ unsigned rel_type,
+ const ELFHeader *hdr,
+ const ELFSectionHeader *rel_hdr,
+ const ELFSectionHeader *plt_hdr,
+ const ELFSectionHeader *sym_hdr,
+ const lldb::SectionSP &plt_section_sp,
+ DataExtractor &rel_data,
+ DataExtractor &symtab_data,
+ DataExtractor &strtab_data)
+{
+ ELFRelocation rel(rel_type);
+ ELFSymbol symbol;
+ lldb::offset_t offset = 0;
+ const elf_xword plt_entsize = plt_hdr->sh_entsize;
+ const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
+
+ typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel);
+ reloc_info_fn reloc_type;
+ reloc_info_fn reloc_symbol;
+
+ if (hdr->Is32Bit())
+ {
+ reloc_type = ELFRelocation::RelocType32;
+ reloc_symbol = ELFRelocation::RelocSymbol32;
+ }
+ else
+ {
+ reloc_type = ELFRelocation::RelocType64;
+ reloc_symbol = ELFRelocation::RelocSymbol64;
+ }
+
+ unsigned slot_type = hdr->GetRelocationJumpSlotType();
+ unsigned i;
+ for (i = 0; i < num_relocations; ++i)
+ {
+ if (rel.Parse(rel_data, &offset) == false)
+ break;
+
+ if (reloc_type(rel) != slot_type)
+ continue;
+
+ lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize;
+ uint64_t plt_index = (i + 1) * plt_entsize;
+
+ if (!symbol.Parse(symtab_data, &symbol_offset))
+ break;
+
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+ bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
+
+ Symbol jump_symbol(
+ i + start_id, // Symbol table index
+ symbol_name, // symbol name.
+ is_mangled, // is the symbol name mangled?
+ eSymbolTypeTrampoline, // Type of this symbol
+ false, // Is this globally visible?
+ false, // Is this symbol debug info?
+ true, // Is this symbol a trampoline?
+ true, // Is this symbol artificial?
+ plt_section_sp, // Section in which this symbol is defined or null.
+ plt_index, // Offset in section or symbol value.
+ plt_entsize, // Size in bytes of this symbol.
+ true, // Size is valid
+ 0); // Symbol flags.
+
+ symbol_table->AddSymbol(jump_symbol);
+ }
+
+ return i;
+}
+
+unsigned
+ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
+ user_id_t start_id,
+ const ELFSectionHeaderInfo *rel_hdr,
+ user_id_t rel_id)
+{
+ assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL);
+
+ // The link field points to the associated symbol table. The info field
+ // points to the section holding the plt.
+ user_id_t symtab_id = rel_hdr->sh_link;
+ user_id_t plt_id = rel_hdr->sh_info;
+
+ if (!symtab_id || !plt_id)
+ return 0;
+
+ // Section ID's are ones based;
+ symtab_id++;
+ plt_id++;
+
+ const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id);
+ if (!plt_hdr)
+ return 0;
+
+ const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id);
+ if (!sym_hdr)
+ return 0;
+
+ SectionList *section_list = m_sections_ap.get();
+ if (!section_list)
+ return 0;
+
+ Section *rel_section = section_list->FindSectionByID(rel_id).get();
+ if (!rel_section)
+ return 0;
+
+ SectionSP plt_section_sp (section_list->FindSectionByID(plt_id));
+ if (!plt_section_sp)
+ return 0;
+
+ Section *symtab = section_list->FindSectionByID(symtab_id).get();
+ if (!symtab)
+ return 0;
+
+ // sh_link points to associated string table.
+ Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get();
+ if (!strtab)
+ return 0;
+
+ DataExtractor rel_data;
+ if (!ReadSectionData(rel_section, rel_data))
+ return 0;
+
+ DataExtractor symtab_data;
+ if (!ReadSectionData(symtab, symtab_data))
+ return 0;
+
+ DataExtractor strtab_data;
+ if (!ReadSectionData(strtab, strtab_data))
+ return 0;
+
+ unsigned rel_type = PLTRelocationType();
+ if (!rel_type)
+ return 0;
+
+ return ParsePLTRelocations (symbol_table,
+ start_id,
+ rel_type,
+ &m_header,
+ rel_hdr,
+ plt_hdr,
+ sym_hdr,
+ plt_section_sp,
+ rel_data,
+ symtab_data,
+ strtab_data);
+}
+
+Symtab *
+ObjectFileELF::GetSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ return NULL;
+
+ // We always want to use the main object file so we (hopefully) only have one cached copy
+ // of our symtab, dynamic sections, etc.
+ ObjectFile *module_obj_file = module_sp->GetObjectFile();
+ if (module_obj_file && module_obj_file != this)
+ return module_obj_file->GetSymtab();
+
+ if (m_symtab_ap.get() == NULL)
+ {
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return NULL;
+
+ uint64_t symbol_id = 0;
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+
+ m_symtab_ap.reset(new Symtab(this));
+
+ // Sharable objects and dynamic executables usually have 2 distinct symbol
+ // tables, one named ".symtab", and the other ".dynsym". The dynsym is a smaller
+ // version of the symtab that only contains global symbols. The information found
+ // in the dynsym is therefore also found in the symtab, while the reverse is not
+ // necessarily true.
+ Section *symtab = section_list->FindSectionByType (eSectionTypeELFSymbolTable, true).get();
+ if (!symtab)
+ {
+ // The symtab section is non-allocable and can be stripped, so if it doesn't exist
+ // then use the dynsym section which should always be there.
+ symtab = section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true).get();
+ }
+ if (symtab)
+ symbol_id += ParseSymbolTable (m_symtab_ap.get(), symbol_id, symtab);
+
+ // Synthesize trampoline symbols to help navigate the PLT.
+ const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL);
+ if (symbol)
+ {
+ addr_t addr = symbol->d_ptr;
+ Section *reloc_section = section_list->FindSectionContainingFileAddress(addr).get();
+ if (reloc_section)
+ {
+ user_id_t reloc_id = reloc_section->GetID();
+ const ELFSectionHeaderInfo *reloc_header = GetSectionHeaderByIndex(reloc_id);
+ assert(reloc_header);
+
+ ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id);
+ }
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+bool
+ObjectFileELF::IsStripped ()
+{
+ // TODO: determine this for ELF
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Dump
+//
+// Dump the specifics of the runtime file container (such as any headers
+// segments, sections, etc).
+//----------------------------------------------------------------------
+void
+ObjectFileELF::Dump(Stream *s)
+{
+ DumpELFHeader(s, m_header);
+ s->EOL();
+ DumpELFProgramHeaders(s);
+ s->EOL();
+ DumpELFSectionHeaders(s);
+ s->EOL();
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ section_list->Dump(s, NULL, true, UINT32_MAX);
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ symtab->Dump(s, NULL, eSortOrderNone);
+ s->EOL();
+ DumpDependentModules(s);
+ s->EOL();
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader
+//
+// Dump the ELF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header)
+{
+ s->PutCString("ELF Header\n");
+ s->Printf("e_ident[EI_MAG0 ] = 0x%2.2x\n", header.e_ident[EI_MAG0]);
+ s->Printf("e_ident[EI_MAG1 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG1], header.e_ident[EI_MAG1]);
+ s->Printf("e_ident[EI_MAG2 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG2], header.e_ident[EI_MAG2]);
+ s->Printf("e_ident[EI_MAG3 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG3], header.e_ident[EI_MAG3]);
+
+ s->Printf("e_ident[EI_CLASS ] = 0x%2.2x\n", header.e_ident[EI_CLASS]);
+ s->Printf("e_ident[EI_DATA ] = 0x%2.2x ", header.e_ident[EI_DATA]);
+ DumpELFHeader_e_ident_EI_DATA(s, header.e_ident[EI_DATA]);
+ s->Printf ("\ne_ident[EI_VERSION] = 0x%2.2x\n", header.e_ident[EI_VERSION]);
+ s->Printf ("e_ident[EI_PAD ] = 0x%2.2x\n", header.e_ident[EI_PAD]);
+
+ s->Printf("e_type = 0x%4.4x ", header.e_type);
+ DumpELFHeader_e_type(s, header.e_type);
+ s->Printf("\ne_machine = 0x%4.4x\n", header.e_machine);
+ s->Printf("e_version = 0x%8.8x\n", header.e_version);
+ s->Printf("e_entry = 0x%8.8" PRIx64 "\n", header.e_entry);
+ s->Printf("e_phoff = 0x%8.8" PRIx64 "\n", header.e_phoff);
+ s->Printf("e_shoff = 0x%8.8" PRIx64 "\n", header.e_shoff);
+ s->Printf("e_flags = 0x%8.8x\n", header.e_flags);
+ s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize);
+ s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize);
+ s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum);
+ s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize);
+ s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum);
+ s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx);
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_type
+//
+// Dump an token value for the ELF header member e_type
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_type(Stream *s, elf_half e_type)
+{
+ switch (e_type)
+ {
+ case ET_NONE: *s << "ET_NONE"; break;
+ case ET_REL: *s << "ET_REL"; break;
+ case ET_EXEC: *s << "ET_EXEC"; break;
+ case ET_DYN: *s << "ET_DYN"; break;
+ case ET_CORE: *s << "ET_CORE"; break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_ident_EI_DATA
+//
+// Dump an token value for the ELF header member e_ident[EI_DATA]
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_ident_EI_DATA(Stream *s, unsigned char ei_data)
+{
+ switch (ei_data)
+ {
+ case ELFDATANONE: *s << "ELFDATANONE"; break;
+ case ELFDATA2LSB: *s << "ELFDATA2LSB - Little Endian"; break;
+ case ELFDATA2MSB: *s << "ELFDATA2MSB - Big Endian"; break;
+ default:
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader
+//
+// Dump a single ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader(Stream *s, const ELFProgramHeader &ph)
+{
+ DumpELFProgramHeader_p_type(s, ph.p_type);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, ph.p_offset, ph.p_vaddr, ph.p_paddr);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8x (", ph.p_filesz, ph.p_memsz, ph.p_flags);
+
+ DumpELFProgramHeader_p_flags(s, ph.p_flags);
+ s->Printf(") %8.8" PRIx64, ph.p_align);
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_type
+//
+// Dump an token value for the ELF program header member p_type which
+// describes the type of the program header
+// ----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, elf_word p_type)
+{
+ const int kStrWidth = 15;
+ switch (p_type)
+ {
+ CASE_AND_STREAM(s, PT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, PT_LOAD , kStrWidth);
+ CASE_AND_STREAM(s, PT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, PT_INTERP , kStrWidth);
+ CASE_AND_STREAM(s, PT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, PT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, PT_PHDR , kStrWidth);
+ CASE_AND_STREAM(s, PT_TLS , kStrWidth);
+ CASE_AND_STREAM(s, PT_GNU_EH_FRAME, kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", p_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_flags
+//
+// Dump an token value for the ELF program header member p_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags)
+{
+ *s << ((p_flags & PF_X) ? "PF_X" : " ")
+ << (((p_flags & PF_X) && (p_flags & PF_W)) ? '+' : ' ')
+ << ((p_flags & PF_W) ? "PF_W" : " ")
+ << (((p_flags & PF_W) && (p_flags & PF_R)) ? '+' : ' ')
+ << ((p_flags & PF_R) ? "PF_R" : " ");
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeaders
+//
+// Dump all of the ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeaders(Stream *s)
+{
+ if (ParseProgramHeaders())
+ {
+ s->PutCString("Program Headers\n");
+ s->PutCString("IDX p_type p_offset p_vaddr p_paddr "
+ "p_filesz p_memsz p_flags p_align\n");
+ s->PutCString("==== --------------- -------- -------- -------- "
+ "-------- -------- ------------------------- --------\n");
+
+ uint32_t idx = 0;
+ for (ProgramHeaderCollConstIter I = m_program_headers.begin();
+ I != m_program_headers.end(); ++I, ++idx)
+ {
+ s->Printf("[%2u] ", idx);
+ ObjectFileELF::DumpELFProgramHeader(s, *I);
+ s->EOL();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader
+//
+// Dump a single ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeaderInfo &sh)
+{
+ s->Printf("%8.8x ", sh.sh_name);
+ DumpELFSectionHeader_sh_type(s, sh.sh_type);
+ s->Printf(" %8.8" PRIx64 " (", sh.sh_flags);
+ DumpELFSectionHeader_sh_flags(s, sh.sh_flags);
+ s->Printf(") %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addr, sh.sh_offset, sh.sh_size);
+ s->Printf(" %8.8x %8.8x", sh.sh_link, sh.sh_info);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addralign, sh.sh_entsize);
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_type
+//
+// Dump an token value for the ELF section header member sh_type which
+// describes the type of the section
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, elf_word sh_type)
+{
+ const int kStrWidth = 12;
+ switch (sh_type)
+ {
+ CASE_AND_STREAM(s, SHT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_PROGBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SYMTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_STRTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_RELA , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HASH , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_REL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNSYM , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOUSER , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIUSER , kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", sh_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_flags
+//
+// Dump an token value for the ELF section header member sh_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, elf_xword sh_flags)
+{
+ *s << ((sh_flags & SHF_WRITE) ? "WRITE" : " ")
+ << (((sh_flags & SHF_WRITE) && (sh_flags & SHF_ALLOC)) ? '+' : ' ')
+ << ((sh_flags & SHF_ALLOC) ? "ALLOC" : " ")
+ << (((sh_flags & SHF_ALLOC) && (sh_flags & SHF_EXECINSTR)) ? '+' : ' ')
+ << ((sh_flags & SHF_EXECINSTR) ? "EXECINSTR" : " ");
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeaders
+//
+// Dump all of the ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeaders(Stream *s)
+{
+ if (!ParseSectionHeaders())
+ return;
+
+ s->PutCString("Section Headers\n");
+ s->PutCString("IDX name type flags "
+ "addr offset size link info addralgn "
+ "entsize Name\n");
+ s->PutCString("==== -------- ------------ -------------------------------- "
+ "-------- -------- -------- -------- -------- -------- "
+ "-------- ====================\n");
+
+ uint32_t idx = 0;
+ for (SectionHeaderCollConstIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I, ++idx)
+ {
+ s->Printf("[%2u] ", idx);
+ ObjectFileELF::DumpELFSectionHeader(s, *I);
+ const char* section_name = I->section_name.AsCString("");
+ if (section_name)
+ *s << ' ' << section_name << "\n";
+ }
+}
+
+void
+ObjectFileELF::DumpDependentModules(lldb_private::Stream *s)
+{
+ size_t num_modules = ParseDependentModules();
+
+ if (num_modules > 0)
+ {
+ s->PutCString("Dependent Modules:\n");
+ for (unsigned i = 0; i < num_modules; ++i)
+ {
+ const FileSpec &spec = m_filespec_ap->GetFileSpecAtIndex(i);
+ s->Printf(" %s\n", spec.GetFilename().GetCString());
+ }
+ }
+}
+
+bool
+ObjectFileELF::GetArchitecture (ArchSpec &arch)
+{
+ if (!ParseHeader())
+ return false;
+
+ arch.SetArchitecture (eArchTypeELF, m_header.e_machine, LLDB_INVALID_CPUTYPE);
+ arch.GetTriple().setOSName (Host::GetOSString().GetCString());
+ arch.GetTriple().setVendorName(Host::GetVendorString().GetCString());
+ return true;
+}
+
+ObjectFile::Type
+ObjectFileELF::CalculateType()
+{
+ switch (m_header.e_type)
+ {
+ case llvm::ELF::ET_NONE:
+ // 0 - No file type
+ return eTypeUnknown;
+
+ case llvm::ELF::ET_REL:
+ // 1 - Relocatable file
+ return eTypeObjectFile;
+
+ case llvm::ELF::ET_EXEC:
+ // 2 - Executable file
+ return eTypeExecutable;
+
+ case llvm::ELF::ET_DYN:
+ // 3 - Shared object file
+ return eTypeSharedLibrary;
+
+ case ET_CORE:
+ // 4 - Core file
+ return eTypeCoreFile;
+
+ default:
+ break;
+ }
+ return eTypeUnknown;
+}
+
+ObjectFile::Strata
+ObjectFileELF::CalculateStrata()
+{
+ switch (m_header.e_type)
+ {
+ case llvm::ELF::ET_NONE:
+ // 0 - No file type
+ return eStrataUnknown;
+
+ case llvm::ELF::ET_REL:
+ // 1 - Relocatable file
+ return eStrataUnknown;
+
+ case llvm::ELF::ET_EXEC:
+ // 2 - Executable file
+ // TODO: is there any way to detect that an executable is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUser;
+
+ case llvm::ELF::ET_DYN:
+ // 3 - Shared object file
+ // TODO: is there any way to detect that an shared library is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUnknown;
+
+ case ET_CORE:
+ // 4 - Core file
+ // TODO: is there any way to detect that an core file is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUnknown;
+
+ default:
+ break;
+ }
+ return eStrataUnknown;
+}
+
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
new file mode 100644
index 000000000000..2365101f4275
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -0,0 +1,333 @@
+//===-- ObjectFileELF.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_ObjectFileELF_h_
+#define liblldb_ObjectFileELF_h_
+
+#include <stdint.h>
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/UUID.h"
+
+#include "ELFHeader.h"
+
+//------------------------------------------------------------------------------
+/// @class ObjectFileELF
+/// @brief Generic ELF object file reader.
+///
+/// This class provides a generic ELF (32/64 bit) reader plugin implementing the
+/// ObjectFile protocol.
+class ObjectFileELF :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length);
+
+ static lldb_private::ObjectFile *
+ CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t
+ GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb_private::ModuleSpecList &specs);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& data_sp,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // ObjectFile Protocol.
+ //------------------------------------------------------------------
+ virtual
+ ~ObjectFileELF();
+
+ virtual bool
+ ParseHeader();
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual bool
+ IsExecutable () const;
+
+ virtual uint32_t
+ GetAddressByteSize() const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual bool
+ IsStripped ();
+
+ virtual void
+ CreateSections (lldb_private::SectionList &unified_section_list);
+
+ virtual void
+ Dump(lldb_private::Stream *s);
+
+ virtual bool
+ GetArchitecture (lldb_private::ArchSpec &arch);
+
+ virtual bool
+ GetUUID(lldb_private::UUID* uuid);
+
+ virtual lldb_private::FileSpecList
+ GetDebugSymbolFilePaths();
+
+ virtual uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files);
+
+ virtual lldb_private::Address
+ GetImageInfoAddress();
+
+ virtual lldb_private::Address
+ GetEntryPointAddress ();
+
+ virtual ObjectFile::Type
+ CalculateType();
+
+ virtual ObjectFile::Strata
+ CalculateStrata();
+
+ // Returns number of program headers found in the ELF file.
+ size_t
+ GetProgramHeaderCount();
+
+ // Returns the program header with the given index.
+ const elf::ELFProgramHeader *
+ GetProgramHeaderByIndex(lldb::user_id_t id);
+
+ // Returns segment data for the given index.
+ lldb_private::DataExtractor
+ GetSegmentDataByIndex(lldb::user_id_t id);
+
+private:
+ ObjectFileELF(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl;
+ typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
+ typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
+
+ struct ELFSectionHeaderInfo : public elf::ELFSectionHeader
+ {
+ lldb_private::ConstString section_name;
+ };
+ typedef std::vector<ELFSectionHeaderInfo> SectionHeaderColl;
+ typedef SectionHeaderColl::iterator SectionHeaderCollIter;
+ typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
+
+ typedef std::vector<elf::ELFDynamic> DynamicSymbolColl;
+ typedef DynamicSymbolColl::iterator DynamicSymbolCollIter;
+ typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter;
+
+ /// Version of this reader common to all plugins based on this class.
+ static const uint32_t m_plugin_version = 1;
+
+ /// ELF file header.
+ elf::ELFHeader m_header;
+
+ /// ELF build ID.
+ lldb_private::UUID m_uuid;
+
+ /// ELF .gnu_debuglink file and crc data if available.
+ std::string m_gnu_debuglink_file;
+ uint32_t m_gnu_debuglink_crc;
+
+ /// Collection of program headers.
+ ProgramHeaderColl m_program_headers;
+
+ /// Collection of section headers.
+ SectionHeaderColl m_section_headers;
+
+ /// Collection of symbols from the dynamic table.
+ DynamicSymbolColl m_dynamic_symbols;
+
+ /// List of file specifications corresponding to the modules (shared
+ /// libraries) on which this object file depends.
+ mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_ap;
+
+ /// Cached value of the entry point for this module.
+ lldb_private::Address m_entry_point_address;
+
+ /// Returns a 1 based index of the given section header.
+ size_t
+ SectionIndex(const SectionHeaderCollIter &I);
+
+ /// Returns a 1 based index of the given section header.
+ size_t
+ SectionIndex(const SectionHeaderCollConstIter &I) const;
+
+ /// Parses all section headers present in this object file and populates
+ /// m_program_headers. This method will compute the header list only once.
+ /// Returns the number of headers parsed.
+ size_t
+ ParseProgramHeaders();
+
+ /// Parses all section headers present in this object file and populates
+ /// m_section_headers. This method will compute the header list only once.
+ /// Returns the number of headers parsed.
+ size_t
+ ParseSectionHeaders();
+
+ /// Parses the elf section headers and returns the uuid, debug link name, crc.
+ static size_t
+ GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+ lldb_private::DataExtractor &data,
+ const elf::ELFHeader &header,
+ lldb_private::UUID &uuid,
+ std::string &gnu_debuglink_file,
+ uint32_t &gnu_debuglink_crc);
+
+ /// Scans the dynamic section and locates all dependent modules (shared
+ /// libraries) populating m_filespec_ap. This method will compute the
+ /// dependent module list only once. Returns the number of dependent
+ /// modules parsed.
+ size_t
+ ParseDependentModules();
+
+ /// Parses the dynamic symbol table and populates m_dynamic_symbols. The
+ /// vector retains the order as found in the object file. Returns the
+ /// number of dynamic symbols parsed.
+ size_t
+ ParseDynamicSymbols();
+
+ /// Populates m_symtab_ap will all non-dynamic linker symbols. This method
+ /// will parse the symbols only once. Returns the number of symbols parsed.
+ unsigned
+ ParseSymbolTable(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ lldb_private::Section *symtab);
+
+ /// Helper routine for ParseSymbolTable().
+ unsigned
+ ParseSymbols(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ lldb_private::SectionList *section_list,
+ const size_t num_symbols,
+ const lldb_private::DataExtractor &symtab_data,
+ const lldb_private::DataExtractor &strtab_data);
+
+ /// Scans the relocation entries and adds a set of artificial symbols to the
+ /// given symbol table for each PLT slot. Returns the number of symbols
+ /// added.
+ unsigned
+ ParseTrampolineSymbols(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ const ELFSectionHeaderInfo *rela_hdr,
+ lldb::user_id_t section_id);
+
+ /// Returns the section header with the given id or NULL.
+ const ELFSectionHeaderInfo *
+ GetSectionHeaderByIndex(lldb::user_id_t id);
+
+ /// @name ELF header dump routines
+ //@{
+ static void
+ DumpELFHeader(lldb_private::Stream *s, const elf::ELFHeader& header);
+
+ static void
+ DumpELFHeader_e_ident_EI_DATA(lldb_private::Stream *s,
+ unsigned char ei_data);
+
+ static void
+ DumpELFHeader_e_type(lldb_private::Stream *s, elf::elf_half e_type);
+ //@}
+
+ /// @name ELF program header dump routines
+ //@{
+ void
+ DumpELFProgramHeaders(lldb_private::Stream *s);
+
+ static void
+ DumpELFProgramHeader(lldb_private::Stream *s,
+ const elf::ELFProgramHeader &ph);
+
+ static void
+ DumpELFProgramHeader_p_type(lldb_private::Stream *s, elf::elf_word p_type);
+
+ static void
+ DumpELFProgramHeader_p_flags(lldb_private::Stream *s,
+ elf::elf_word p_flags);
+ //@}
+
+ /// @name ELF section header dump routines
+ //@{
+ void
+ DumpELFSectionHeaders(lldb_private::Stream *s);
+
+ static void
+ DumpELFSectionHeader(lldb_private::Stream *s,
+ const ELFSectionHeaderInfo& sh);
+
+ static void
+ DumpELFSectionHeader_sh_type(lldb_private::Stream *s,
+ elf::elf_word sh_type);
+
+ static void
+ DumpELFSectionHeader_sh_flags(lldb_private::Stream *s,
+ elf::elf_xword sh_flags);
+ //@}
+
+ /// ELF dependent module dump routine.
+ void
+ DumpDependentModules(lldb_private::Stream *s);
+
+ const elf::ELFDynamic *
+ FindDynamicSymbol(unsigned tag);
+
+ unsigned
+ PLTRelocationType();
+};
+
+#endif // #ifndef liblldb_ObjectFileELF_h_
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
new file mode 100644
index 000000000000..4cfe38e5840f
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -0,0 +1,417 @@
+//===-- OperatingSystemPython.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"
+
+#ifndef LLDB_DISABLE_PYTHON
+
+#include "OperatingSystemPython.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/PythonDataObjects.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
+#include "Plugins/Process/Utility/RegisterContextDummy.h"
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "Plugins/Process/Utility/ThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OperatingSystemPython::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+OperatingSystemPython::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+OperatingSystem *
+OperatingSystemPython::CreateInstance (Process *process, bool force)
+{
+ // Python OperatingSystem plug-ins must be requested by name, so force must be true
+ FileSpec python_os_plugin_spec (process->GetPythonOSPluginPath());
+ if (python_os_plugin_spec && python_os_plugin_spec.Exists())
+ {
+ std::unique_ptr<OperatingSystemPython> os_ap (new OperatingSystemPython (process, python_os_plugin_spec));
+ if (os_ap.get() && os_ap->IsValid())
+ return os_ap.release();
+ }
+ return NULL;
+}
+
+
+ConstString
+OperatingSystemPython::GetPluginNameStatic()
+{
+ static ConstString g_name("python");
+ return g_name;
+}
+
+const char *
+OperatingSystemPython::GetPluginDescriptionStatic()
+{
+ return "Operating system plug-in that gathers OS information from a python class that implements the necessary OperatingSystem functionality.";
+}
+
+
+OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process, const FileSpec &python_module_path) :
+ OperatingSystem (process),
+ m_thread_list_valobj_sp (),
+ m_register_info_ap (),
+ m_interpreter (NULL),
+ m_python_object_sp ()
+{
+ if (!process)
+ return;
+ TargetSP target_sp = process->CalculateTarget();
+ if (!target_sp)
+ return;
+ m_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (m_interpreter)
+ {
+
+ std::string os_plugin_class_name (python_module_path.GetFilename().AsCString(""));
+ if (!os_plugin_class_name.empty())
+ {
+ const bool init_session = false;
+ const bool allow_reload = true;
+ char python_module_path_cstr[PATH_MAX];
+ python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr));
+ Error error;
+ if (m_interpreter->LoadScriptingModule (python_module_path_cstr, allow_reload, init_session, error))
+ {
+ // Strip the ".py" extension if there is one
+ size_t py_extension_pos = os_plugin_class_name.rfind(".py");
+ if (py_extension_pos != std::string::npos)
+ os_plugin_class_name.erase (py_extension_pos);
+ // Add ".OperatingSystemPlugIn" to the module name to get a string like "modulename.OperatingSystemPlugIn"
+ os_plugin_class_name += ".OperatingSystemPlugIn";
+ ScriptInterpreterObjectSP object_sp = m_interpreter->OSPlugin_CreatePluginObject(os_plugin_class_name.c_str(), process->CalculateProcess());
+ if (object_sp && object_sp->GetObject())
+ m_python_object_sp = object_sp;
+ }
+ }
+ }
+}
+
+OperatingSystemPython::~OperatingSystemPython ()
+{
+}
+
+DynamicRegisterInfo *
+OperatingSystemPython::GetDynamicRegisterInfo ()
+{
+ if (m_register_info_ap.get() == NULL)
+ {
+ if (!m_interpreter || !m_python_object_sp)
+ return NULL;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OS));
+
+ if (log)
+ log->Printf ("OperatingSystemPython::GetDynamicRegisterInfo() fetching thread register definitions from python for pid %" PRIu64, m_process->GetID());
+
+ PythonDictionary dictionary(m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp));
+ if (!dictionary)
+ return NULL;
+
+ m_register_info_ap.reset (new DynamicRegisterInfo (dictionary));
+ assert (m_register_info_ap->GetNumRegisters() > 0);
+ assert (m_register_info_ap->GetNumRegisterSets() > 0);
+ }
+ return m_register_info_ap.get();
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+OperatingSystemPython::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+OperatingSystemPython::GetPluginVersion()
+{
+ return 1;
+}
+
+bool
+OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
+ ThreadList &core_thread_list,
+ ThreadList &new_thread_list)
+{
+ if (!m_interpreter || !m_python_object_sp)
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OS));
+
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ if (log)
+ log->Printf ("OperatingSystemPython::UpdateThreadList() fetching thread data from python for pid %" PRIu64, m_process->GetID());
+
+ // The threads that are in "new_thread_list" upon entry are the threads from the
+ // lldb_private::Process subclass, no memory threads will be in this list.
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure threads_list stays alive
+ PythonList threads_list(m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp));
+ if (threads_list)
+ {
+ if (log)
+ {
+ StreamString strm;
+ threads_list.Dump(strm);
+ log->Printf("threads_list = %s", strm.GetString().c_str());
+ }
+ uint32_t i;
+ const uint32_t num_threads = threads_list.GetSize();
+ if (num_threads > 0)
+ {
+ for (i=0; i<num_threads; ++i)
+ {
+ PythonDictionary thread_dict(threads_list.GetItemAtIndex(i));
+ if (thread_dict)
+ {
+ ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, NULL));
+ if (thread_sp)
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+ }
+ }
+
+ // No new threads added from the thread info array gotten from python, just
+ // display the core threads.
+ if (new_thread_list.GetSize(false) == 0)
+ new_thread_list = core_thread_list;
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ThreadSP
+OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict,
+ ThreadList &core_thread_list,
+ ThreadList &old_thread_list,
+ bool *did_create_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_dict)
+ {
+ PythonString tid_pystr("tid");
+ const tid_t tid = thread_dict.GetItemForKeyAsInteger (tid_pystr, LLDB_INVALID_THREAD_ID);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ PythonString core_pystr("core");
+ PythonString name_pystr("name");
+ PythonString queue_pystr("queue");
+ //PythonString state_pystr("state");
+ //PythonString stop_reason_pystr("stop_reason");
+ PythonString reg_data_addr_pystr ("register_data_addr");
+
+ const uint32_t core_number = thread_dict.GetItemForKeyAsInteger (core_pystr, UINT32_MAX);
+ const addr_t reg_data_addr = thread_dict.GetItemForKeyAsInteger (reg_data_addr_pystr, LLDB_INVALID_ADDRESS);
+ const char *name = thread_dict.GetItemForKeyAsString (name_pystr);
+ const char *queue = thread_dict.GetItemForKeyAsString (queue_pystr);
+ //const char *state = thread_dict.GetItemForKeyAsString (state_pystr);
+ //const char *stop_reason = thread_dict.GetItemForKeyAsString (stop_reason_pystr);
+
+ // See if a thread already exists for "tid"
+ thread_sp = old_thread_list.FindThreadByID (tid, false);
+ if (thread_sp)
+ {
+ // A thread already does exist for "tid", make sure it was an operating system
+ // plug-in generated thread.
+ if (!IsOperatingSystemPluginThread(thread_sp))
+ {
+ // We have thread ID overlap between the protocol threads and the
+ // operating system threads, clear the thread so we create an
+ // operating system thread for this.
+ thread_sp.reset();
+ }
+ }
+
+ if (!thread_sp)
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+ thread_sp.reset (new ThreadMemory (*m_process,
+ tid,
+ name,
+ queue,
+ reg_data_addr));
+
+ }
+
+ if (core_number < core_thread_list.GetSize(false))
+ {
+ ThreadSP core_thread_sp (core_thread_list.GetThreadAtIndex(core_number, false));
+ if (core_thread_sp)
+ {
+ ThreadSP backing_core_thread_sp (core_thread_sp->GetBackingThread());
+ if (backing_core_thread_sp)
+ {
+ thread_sp->SetBackingThread(backing_core_thread_sp);
+ }
+ else
+ {
+ thread_sp->SetBackingThread(core_thread_sp);
+ }
+ }
+ }
+ }
+ }
+ return thread_sp;
+}
+
+
+
+void
+OperatingSystemPython::ThreadWasSelected (Thread *thread)
+{
+}
+
+RegisterContextSP
+OperatingSystemPython::CreateRegisterContextForThread (Thread *thread, addr_t reg_data_addr)
+{
+ RegisterContextSP reg_ctx_sp;
+ if (!m_interpreter || !m_python_object_sp || !thread)
+ return reg_ctx_sp;
+
+ if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
+ return reg_ctx_sp;
+
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure python objects stays alive
+ if (reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ // The registers data is in contiguous memory, just create the register
+ // context using the address provided
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64 ") creating memory register context",
+ thread->GetID(),
+ thread->GetProtocolID(),
+ reg_data_addr);
+ reg_ctx_sp.reset (new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), reg_data_addr));
+ }
+ else
+ {
+ // No register data address is provided, query the python plug-in to let
+ // it make up the data as it sees fit
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ", 0x%" PRIx64 ") fetching register data from python",
+ thread->GetID(),
+ thread->GetProtocolID());
+
+ PythonString reg_context_data(m_interpreter->OSPlugin_RegisterContextData (m_python_object_sp, thread->GetID()));
+ if (reg_context_data)
+ {
+ DataBufferSP data_sp (new DataBufferHeap (reg_context_data.GetString(),
+ reg_context_data.GetSize()));
+ if (data_sp->GetByteSize())
+ {
+ RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), LLDB_INVALID_ADDRESS);
+ if (reg_ctx_memory)
+ {
+ reg_ctx_sp.reset(reg_ctx_memory);
+ reg_ctx_memory->SetAllRegisterData (data_sp);
+ }
+ }
+ }
+ }
+ // if we still have no register data, fallback on a dummy context to avoid crashing
+ if (!reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ") forcing a dummy register context", thread->GetID());
+ reg_ctx_sp.reset(new RegisterContextDummy(*thread,0,target.GetArchitecture().GetAddressByteSize()));
+ }
+ return reg_ctx_sp;
+}
+
+StopInfoSP
+OperatingSystemPython::CreateThreadStopReason (lldb_private::Thread *thread)
+{
+ // We should have gotten the thread stop info from the dictionary of data for
+ // the thread in the initial call to get_thread_info(), this should have been
+ // cached so we can return it here
+ StopInfoSP stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
+ return stop_info_sp;
+}
+
+lldb::ThreadSP
+OperatingSystemPython::CreateThread (lldb::tid_t tid, addr_t context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateThread (tid = 0x%" PRIx64 ", context = 0x%" PRIx64 ") fetching register data from python", tid, context);
+
+ if (m_interpreter && m_python_object_sp)
+ {
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure thread_info_dict stays alive
+ PythonDictionary thread_info_dict (m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context));
+ if (thread_info_dict)
+ {
+ ThreadList core_threads(m_process);
+ ThreadList &thread_list = m_process->GetThreadList();
+ bool did_create = false;
+ ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, &did_create));
+ if (did_create)
+ thread_list.AddThread(thread_sp);
+ return thread_sp;
+ }
+ }
+ return ThreadSP();
+}
+
+
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
new file mode 100644
index 000000000000..077039e50d56
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
@@ -0,0 +1,109 @@
+//===-- OperatingSystemPython.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLDB_DISABLE_PYTHON
+
+#ifndef liblldb_OperatingSystemPython_h_
+#define liblldb_OperatingSystemPython_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/OperatingSystem.h"
+
+class DynamicRegisterInfo;
+
+class OperatingSystemPython : public lldb_private::OperatingSystem
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static lldb_private::OperatingSystem *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------------
+ OperatingSystemPython (lldb_private::Process *process,
+ const lldb_private::FileSpec &python_module_path);
+
+ virtual
+ ~OperatingSystemPython ();
+
+ //------------------------------------------------------------------
+ // lldb_private::PluginInterface Methods
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // lldb_private::OperatingSystem Methods
+ //------------------------------------------------------------------
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &real_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ virtual void
+ ThreadWasSelected (lldb_private::Thread *thread);
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForThread (lldb_private::Thread *thread,
+ lldb::addr_t reg_data_addr);
+
+ virtual lldb::StopInfoSP
+ CreateThreadStopReason (lldb_private::Thread *thread);
+
+ //------------------------------------------------------------------
+ // Method for lazy creation of threads on demand
+ //------------------------------------------------------------------
+ virtual lldb::ThreadSP
+ CreateThread (lldb::tid_t tid, lldb::addr_t context);
+
+protected:
+
+ bool IsValid() const
+ {
+ return m_python_object_sp && m_python_object_sp->GetObject() != NULL;
+ }
+
+ lldb::ThreadSP
+ CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict,
+ lldb_private::ThreadList &core_thread_list,
+ lldb_private::ThreadList &old_thread_list,
+ bool *did_create_ptr);
+
+ DynamicRegisterInfo *
+ GetDynamicRegisterInfo ();
+
+ lldb::ValueObjectSP m_thread_list_valobj_sp;
+ std::unique_ptr<DynamicRegisterInfo> m_register_info_ap;
+ lldb_private::ScriptInterpreter *m_interpreter;
+ lldb::ScriptInterpreterObjectSP m_python_object_sp;
+
+};
+
+#endif // #ifndef liblldb_OperatingSystemPython_h_
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
new file mode 100644
index 000000000000..dc0917255d9b
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -0,0 +1,648 @@
+//===-- PlatformFreeBSD.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 "PlatformFreeBSD.h"
+
+// C Includes
+#include <stdio.h>
+#include <sys/utsname.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Platform *
+PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+{
+ // The only time we create an instance is when we are creating a remote
+ // freebsd platform
+ const bool is_host = false;
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::PC:
+ create = true;
+ break;
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // Only accept "unknown" for the vendor if the host is BSD and
+ // it "unknown" wasn't specified (it was just returned becasue it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::KFreeBSD:
+ break;
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // Only accept "unknown" for the OS if the host is BSD and
+ // it "unknown" wasn't specified (it was just returned becasue it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ if (create)
+ return new PlatformFreeBSD (is_host);
+ return NULL;
+
+}
+
+lldb_private::ConstString
+PlatformFreeBSD::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-freebsd");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformFreeBSD::GetDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local FreeBSD user platform plug-in.";
+ else
+ return "Remote FreeBSD user platform plug-in.";
+}
+
+static uint32_t g_initialize_count = 0;
+
+void
+PlatformFreeBSD::Initialize ()
+{
+ if (g_initialize_count++ == 0)
+ {
+#if defined (__FreeBSD__)
+ // Force a host flag to true for the default platform object.
+ PlatformSP default_platform_sp (new PlatformFreeBSD(true));
+ default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
+ Platform::SetDefaultPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
+ PlatformFreeBSD::GetDescriptionStatic(false),
+ PlatformFreeBSD::CreateInstance);
+ }
+}
+
+void
+PlatformFreeBSD::Terminate ()
+{
+ if (g_initialize_count > 0 && --g_initialize_count == 0)
+ PluginManager::UnregisterPlugin (PlatformFreeBSD::CreateInstance);
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
+Platform(is_host)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformFreeBSD::~PlatformFreeBSD()
+{
+}
+
+
+Error
+PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &exe_arch,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ FileSpec resolved_exe_file (exe_file);
+
+ if (IsHost())
+ {
+ // If we have "ls" as the exe_file, resolve the executable location based on
+ // the current path variables
+ if (!resolved_exe_file.Exists())
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ resolved_exe_file.SetFile(exe_path, true);
+ }
+
+ if (!resolved_exe_file.Exists())
+ resolved_exe_file.ResolveExecutableLocation ();
+
+ if (resolved_exe_file.Exists())
+ error.Clear();
+ else
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ResolveExecutable (exe_file,
+ exe_arch,
+ exe_module_sp,
+ module_search_paths_ptr);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle (resolved_exe_file);
+
+ if (resolved_exe_file.Exists()) {
+ error.Clear();
+ }
+ 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);
+ }
+ }
+ }
+
+
+ if (error.Success())
+ {
+ ModuleSpec module_spec (resolved_exe_file, exe_arch);
+ if (module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+
+ if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ exe_file.GetPath().c_str(),
+ exe_arch.GetArchitectureName());
+ }
+ }
+ else
+ {
+ // 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
+ StreamString arch_names;
+ ArchSpec platform_arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (platform_arch.GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ exe_file.GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ exe_file.GetPath().c_str());
+ }
+
+ return error;
+}
+
+size_t
+PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ ArchSpec arch = target.GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ size_t trap_opcode_size = 0;
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+ trap_opcode = g_i386_opcode;
+ trap_opcode_size = sizeof(g_i386_opcode);
+ }
+ break;
+ }
+
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+
+ return 0;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSVersion ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetOSVersion (m_major_os_version,
+ m_minor_os_version,
+ m_update_os_version);
+ return false;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSBuildString (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSBuildString (s);
+ s.clear();
+ return false;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSKernelDescription (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
+ s.clear();
+ return false;
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformFreeBSD::GetRemoteSystemArchitecture ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteSystemArchitecture ();
+ return ArchSpec();
+}
+
+
+const char *
+PlatformFreeBSD::GetHostname ()
+{
+ if (IsHost())
+ return Platform::GetHostname();
+
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetHostname ();
+ return NULL;
+}
+
+bool
+PlatformFreeBSD::IsConnected () const
+{
+ if (IsHost())
+ return true;
+ else if (m_remote_platform_sp)
+ return m_remote_platform_sp->IsConnected();
+ return false;
+}
+
+Error
+PlatformFreeBSD::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
+
+ if (m_remote_platform_sp)
+ {
+ if (error.Success())
+ {
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ConnectRemote (args);
+ }
+ else
+ {
+ error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
+ }
+ }
+ }
+ else
+ error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
+
+ if (error.Fail())
+ m_remote_platform_sp.reset();
+ }
+
+ return error;
+}
+
+Error
+PlatformFreeBSD::DisconnectRemote ()
+{
+ Error error;
+
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->DisconnectRemote ();
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+bool
+PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else if (m_remote_platform_sp)
+ {
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+
+
+uint32_t
+PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ uint32_t match_count = 0;
+ if (IsHost())
+ {
+ // Let the base class figure out the host details
+ match_count = Platform::FindProcesses (match_info, process_infos);
+ }
+ else
+ {
+ // If we are remote, we can only return results if we are connected
+ if (m_remote_platform_sp)
+ match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
+ }
+ return match_count;
+}
+
+Error
+PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (IsHost())
+ {
+ error = Platform::LaunchProcess (launch_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->LaunchProcess (launch_info);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Listener &listener,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ if (IsHost())
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+ ArchSpec emptyArchSpec;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ emptyArchSpec,
+ false,
+ m_remote_platform_sp,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+ // The freebsd always currently uses the GDB remote debugger plug-in
+ // so even when debugging locally we are debugging remotely!
+ // Just like the darwin plugin.
+ process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
+
+ if (process_sp)
+ error = process_sp->Attach (attach_info);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
+}
+
+const char *
+PlatformFreeBSD::GetUserName (uint32_t uid)
+{
+ // Check the cache in Platform in case we have already looked this uid up
+ const char *user_name = Platform::GetUserName(uid);
+ if (user_name)
+ return user_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetUserName(uid);
+ return NULL;
+}
+
+const char *
+PlatformFreeBSD::GetGroupName (uint32_t gid)
+{
+ const char *group_name = Platform::GetGroupName(gid);
+ if (group_name)
+ return group_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetGroupName(gid);
+ return NULL;
+}
+
+
+// From PlatformMacOSX only
+Error
+PlatformFreeBSD::GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file);
+ }
+
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+Error
+PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error;
+ module_sp.reset();
+
+ if (IsRemote())
+ {
+ // If we have a remote platform always, let it try and locate
+ // the shared module first.
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ }
+
+ if (!module_sp)
+ {
+ // Fall back to the local platform and find the file locally
+ error = Platform::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return error;
+}
+
+
+bool
+PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ // From macosx;s plugin code. For FreeBSD we may want to support more archs.
+ if (idx == 0)
+ {
+ arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ return arch.IsValid();
+ }
+ else if (idx == 1)
+ {
+ ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture));
+ ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64));
+ if (platform_arch.IsExactMatch(platform_arch64))
+ {
+ // This freebsd platform supports both 32 and 64 bit. Since we already
+ // returned the 64 bit arch for idx == 0, return the 32 bit arch
+ // for idx == 1
+ arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ return arch.IsValid();
+ }
+ }
+ return false;
+}
+
+void
+PlatformFreeBSD::GetStatus (Stream &strm)
+{
+ struct utsname un;
+
+ if (uname(&un)) {
+ strm << "FreeBSD";
+ return;
+ }
+
+ strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n';
+ Platform::GetStatus(strm);
+}
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
new file mode 100644
index 000000000000..4aa158eb6e87
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -0,0 +1,162 @@
+//===-- PlatformFreeBSD.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_PlatformFreeBSD_h_
+#define liblldb_PlatformFreeBSD_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+
+class PlatformFreeBSD : public lldb_private::Platform
+{
+public:
+ // Mostly taken from PlatformDarwin and PlatformMacOSX
+
+ //------------------------------------------------------------
+ // Class functions
+ //------------------------------------------------------------
+ static lldb_private::Platform*
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetDescriptionStatic (bool is_host);
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformFreeBSD (bool is_host);
+
+ virtual
+ ~PlatformFreeBSD();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic (IsHost());
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ return GetDescriptionStatic(IsHost());
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ virtual lldb_private::Error
+ ResolveExecutable (const lldb_private::FileSpec &exe_file,
+ const lldb_private::ArchSpec &arch,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site);
+
+ virtual bool
+ GetRemoteOSVersion ();
+
+ virtual bool
+ GetRemoteOSBuildString (std::string &s);
+
+ virtual bool
+ GetRemoteOSKernelDescription (std::string &s);
+
+ // Remote Platform subclasses need to override this function
+ virtual lldb_private::ArchSpec
+ GetRemoteSystemArchitecture ();
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb_private::Error
+ ConnectRemote (lldb_private::Args& args);
+
+ virtual lldb_private::Error
+ DisconnectRemote ();
+
+ virtual const char *
+ GetHostname ();
+
+ virtual const char *
+ GetUserName (uint32_t uid);
+
+ virtual const char *
+ GetGroupName (uint32_t gid);
+
+ virtual bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info);
+
+ virtual uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ virtual lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb::ProcessSP
+ Attach(lldb_private::ProcessAttachInfo &attach_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Listener &listener,
+ lldb_private::Error &error);
+
+ // FreeBSD processes can not be launched by spawning and attaching.
+ virtual bool
+ CanDebugProcess () { return false; }
+
+ // Only on PlatformMacOSX:
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
+ virtual bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ virtual void
+ GetStatus (lldb_private::Stream &strm);
+
+protected:
+ lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformFreeBSD);
+};
+
+#endif // liblldb_PlatformFreeBSD_h_
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
new file mode 100644
index 000000000000..684d1921e920
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -0,0 +1,418 @@
+//===-- PlatformRemoteGDBServer.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 "PlatformRemoteGDBServer.h"
+
+// C Includes
+#include <sys/sysctl.h>
+
+// C++ Includes
+// 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/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool g_initialized = false;
+
+void
+PlatformRemoteGDBServer::Initialize ()
+{
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (PlatformRemoteGDBServer::GetPluginNameStatic(),
+ PlatformRemoteGDBServer::GetDescriptionStatic(),
+ PlatformRemoteGDBServer::CreateInstance);
+ }
+}
+
+void
+PlatformRemoteGDBServer::Terminate ()
+{
+ if (g_initialized)
+ {
+ g_initialized = false;
+ PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance);
+ }
+}
+
+Platform*
+PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+{
+ bool create = force;
+ if (!create)
+ {
+ create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
+ }
+ if (create)
+ return new PlatformRemoteGDBServer ();
+ return NULL;
+}
+
+
+lldb_private::ConstString
+PlatformRemoteGDBServer::GetPluginNameStatic()
+{
+ static ConstString g_name("remote-gdb-server");
+ return g_name;
+}
+
+const char *
+PlatformRemoteGDBServer::GetDescriptionStatic()
+{
+ return "A platform that uses the GDB remote protocol as the communication transport.";
+}
+
+const char *
+PlatformRemoteGDBServer::GetDescription ()
+{
+ if (m_platform_description.empty())
+ {
+ if (IsConnected())
+ {
+ // Send the get description packet
+ }
+ }
+
+ if (!m_platform_description.empty())
+ return m_platform_description.c_str();
+ return GetDescriptionStatic();
+}
+
+Error
+PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &exe_arch,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+ return error;
+}
+
+Error
+PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformRemoteGDBServer::PlatformRemoteGDBServer () :
+ Platform(false), // This is a remote platform
+ m_gdb_client(true)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformRemoteGDBServer::~PlatformRemoteGDBServer()
+{
+}
+
+bool
+PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ return false;
+}
+
+size_t
+PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ // This isn't needed if the z/Z packets are supported in the GDB remote
+ // server. But we might need a packet to detect this.
+ return 0;
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSVersion ()
+{
+ uint32_t major, minor, update;
+ if (m_gdb_client.GetOSVersion (major, minor, update))
+ {
+ m_major_os_version = major;
+ m_minor_os_version = minor;
+ m_update_os_version = update;
+ return true;
+ }
+ return false;
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSBuildString (std::string &s)
+{
+ return m_gdb_client.GetOSBuildString (s);
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSKernelDescription (std::string &s)
+{
+ return m_gdb_client.GetOSKernelDescription (s);
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformRemoteGDBServer::GetRemoteSystemArchitecture ()
+{
+ return m_gdb_client.GetSystemArchitecture();
+}
+
+bool
+PlatformRemoteGDBServer::IsConnected () const
+{
+ return m_gdb_client.IsConnected();
+}
+
+Error
+PlatformRemoteGDBServer::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsConnected())
+ {
+ error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection",
+ GetHostname());
+ }
+ else
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ const char *url = args.GetArgumentAtIndex(0);
+ m_gdb_client.SetConnection (new ConnectionFileDescriptor());
+ const ConnectionStatus status = m_gdb_client.Connect(url, &error);
+ if (status == eConnectionStatusSuccess)
+ {
+ if (m_gdb_client.HandshakeWithServer(&error))
+ {
+ m_gdb_client.QueryNoAckModeSupported();
+ m_gdb_client.GetHostInfo();
+#if 0
+ m_gdb_client.TestPacketSpeed(10000);
+#endif
+ }
+ else
+ {
+ m_gdb_client.Disconnect();
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformRemoteGDBServer::DisconnectRemote ()
+{
+ Error error;
+ m_gdb_client.Disconnect(&error);
+ return error;
+}
+
+const char *
+PlatformRemoteGDBServer::GetHostname ()
+{
+ m_gdb_client.GetHostname (m_name);
+ if (m_name.empty())
+ return NULL;
+ return m_name.c_str();
+}
+
+const char *
+PlatformRemoteGDBServer::GetUserName (uint32_t uid)
+{
+ // Try and get a cache user name first
+ const char *cached_user_name = Platform::GetUserName(uid);
+ if (cached_user_name)
+ return cached_user_name;
+ std::string name;
+ if (m_gdb_client.GetUserName(uid, name))
+ return SetCachedUserName(uid, name.c_str(), name.size());
+
+ SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
+ return NULL;
+}
+
+const char *
+PlatformRemoteGDBServer::GetGroupName (uint32_t gid)
+{
+ const char *cached_group_name = Platform::GetGroupName(gid);
+ if (cached_group_name)
+ return cached_group_name;
+ std::string name;
+ if (m_gdb_client.GetGroupName(gid, name))
+ return SetCachedGroupName(gid, name.c_str(), name.size());
+
+ SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
+ return NULL;
+}
+
+uint32_t
+PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ return m_gdb_client.FindProcesses (match_info, process_infos);
+}
+
+bool
+PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ return m_gdb_client.GetProcessInfo (pid, process_info);
+}
+
+
+Error
+PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ m_gdb_client.SetSTDIN ("/dev/null");
+ m_gdb_client.SetSTDOUT ("/dev/null");
+ m_gdb_client.SetSTDERR ("/dev/null");
+ m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
+
+ const char *working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir && working_dir[0])
+ {
+ m_gdb_client.SetWorkingDir (working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ const char **argv = launch_info.GetArguments().GetConstArgumentVector();
+ const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+
+ if (envp)
+ {
+ const char *env_entry;
+ for (int i=0; (env_entry = envp[i]); ++i)
+ {
+ if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
+ break;
+ }
+ }
+ const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
+ int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
+ m_gdb_client.SetPacketTimeout (old_packet_timeout);
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_client.GetLaunchSuccess (error_str))
+ {
+ pid = m_gdb_client.GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ launch_info.SetProcessID (pid);
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
+ }
+ return error;
+}
+
+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;
+ if (IsRemote())
+ {
+ if (IsConnected())
+ {
+ uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort();
+
+ if (port == 0)
+ {
+ error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
+ }
+ else
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ NULL,
+ false,
+ NULL,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ // 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);
+
+ if (process_sp)
+ {
+ char connect_url[256];
+ const int connect_url_len = ::snprintf (connect_url,
+ sizeof(connect_url),
+ "connect://%s:%u",
+ GetHostname (),
+ port);
+ assert (connect_url_len < (int)sizeof(connect_url));
+ error = process_sp->ConnectRemote (NULL, connect_url);
+ if (error.Success())
+ error = process_sp->Attach(attach_info);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("not connected to remote gdb server");
+ }
+ }
+ return process_sp;
+}
+
+
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
new file mode 100644
index 000000000000..22b3dd49be54
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -0,0 +1,147 @@
+//===-- PlatformRemoteGDBServer.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_PlatformRemoteGDBServer_h_
+#define liblldb_PlatformRemoteGDBServer_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+#include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h"
+
+class PlatformRemoteGDBServer : public lldb_private::Platform
+{
+public:
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::Platform*
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetDescriptionStatic();
+
+
+ PlatformRemoteGDBServer ();
+
+ virtual
+ ~PlatformRemoteGDBServer();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ virtual lldb_private::Error
+ ResolveExecutable (const lldb_private::FileSpec &exe_file,
+ const lldb_private::ArchSpec &arch,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr);
+
+ virtual const char *
+ GetDescription ();
+
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ virtual bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info);
+
+ virtual uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ virtual lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb::ProcessSP
+ Attach (lldb_private::ProcessAttachInfo &attach_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ lldb_private::Listener &listener,
+ lldb_private::Error &error);
+
+ virtual bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site);
+
+ virtual bool
+ GetRemoteOSVersion ();
+
+ virtual bool
+ GetRemoteOSBuildString (std::string &s);
+
+ virtual bool
+ GetRemoteOSKernelDescription (std::string &s);
+
+ // Remote Platform subclasses need to override this function
+ virtual lldb_private::ArchSpec
+ GetRemoteSystemArchitecture ();
+
+ // Remote subclasses should override this and return a valid instance
+ // name if connected.
+ virtual const char *
+ GetHostname ();
+
+ virtual const char *
+ GetUserName (uint32_t uid);
+
+ virtual const char *
+ GetGroupName (uint32_t gid);
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb_private::Error
+ ConnectRemote (lldb_private::Args& args);
+
+ virtual lldb_private::Error
+ DisconnectRemote ();
+
+protected:
+ GDBRemoteCommunicationClient m_gdb_client;
+ std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer);
+
+};
+
+#endif // liblldb_PlatformRemoteGDBServer_h_
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
new file mode 100644
index 000000000000..ea26d972b860
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -0,0 +1,132 @@
+//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+
+lldb::ProcessSP
+ProcessFreeBSD::CreateInstance(Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessFreeBSD (target, listener));
+ return process_sp;
+}
+
+void
+ProcessFreeBSD::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks);
+ ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic());
+ g_initialized = true;
+ }
+}
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginNameStatic()
+{
+ static ConstString g_name("freebsd");
+ return g_name;
+}
+
+const char *
+ProcessFreeBSD::GetPluginDescriptionStatic()
+{
+ return "Process plugin for FreeBSD";
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessFreeBSD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+Error
+ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Log *
+ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener)
+ : ProcessPOSIX(target, listener)
+{
+}
+
+void
+ProcessFreeBSD::Terminate()
+{
+}
+
+bool
+ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // XXX haxx
+ new_thread_list = old_thread_list;
+
+ return false;
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
new file mode 100644
index 000000000000..5f79b74cad30
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -0,0 +1,82 @@
+//===-- ProcessFreeBSD.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_ProcessFreeBSD_H_
+#define liblldb_ProcessFreeBSD_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ThreadList.h"
+#include "ProcessMessage.h"
+#include "ProcessPOSIX.h"
+
+class ProcessMonitor;
+
+class ProcessFreeBSD :
+ public ProcessPOSIX
+{
+
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessFreeBSD(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command,
+ lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm,
+ lldb_private::Args &command);
+
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
new file mode 100644
index 000000000000..9fd51d2d640a
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -0,0 +1,1677 @@
+//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+
+#include "POSIXThread.h"
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+
+extern "C" {
+ extern char ** environ;
+ }
+
+using namespace lldb;
+using namespace lldb_private;
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+// Wrapper for ptrace to catch errors and log calls.
+
+const char *
+Get_PT_IO_OP(int op)
+{
+ switch (op) {
+ case PIOD_READ_D: return "READ_D";
+ case PIOD_WRITE_D: return "WRITE_D";
+ case PIOD_READ_I: return "READ_I";
+ case PIOD_WRITE_I: return "WRITE_I";
+ default: return "Unknown op";
+ }
+}
+
+// Wrapper for ptrace to catch errors and log calls.
+// Note that ptrace sets errno on error because -1 is reserved as a valid result.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
+ const char* reqName, const char* file, int line)
+{
+ long int result;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (log) {
+ log->Printf("ptrace(%s, %lu, %p, %x) called from file %s line %d",
+ reqName, pid, addr, data, file, line);
+ if (req == PT_IO) {
+ struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr;
+
+ log->Printf("PT_IO: op=%s offs=%zx size=%ld",
+ Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len);
+ }
+ }
+
+ //PtraceDisplayBytes(req, data);
+
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t) addr, data);
+
+ //PtraceDisplayBytes(req, data);
+
+ if (log && errno != 0)
+ {
+ const char* str;
+ switch (errno)
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = "<unknown>";
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+ }
+
+#ifdef __amd64__
+ if (log) {
+ if (req == PT_GETREGS) {
+ struct reg *r = (struct reg *) addr;
+
+ log->Printf("PT_GETREGS: ip=0x%lx", r->r_rip);
+ log->Printf("PT_GETREGS: sp=0x%lx", r->r_rsp);
+ log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp);
+ log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax);
+ }
+ }
+#endif
+
+ return result;
+}
+
+// Wrapper for ptrace when logging is not required.
+// Sets errno to 0 prior to calling ptrace.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data)
+{
+ long result = 0;
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t)addr, data);
+ return result;
+}
+
+#define PTRACE(req, pid, addr, data) \
+ PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
+#else
+ PtraceWrapper((req), (pid), (addr), (data))
+#endif
+
+//------------------------------------------------------------------------------
+// Static implementations of ProcessMonitor::ReadMemory and
+// ProcessMonitor::WriteMemory. This enables mutual recursion between these
+// functions without needed to go thru the thread funnel.
+
+static size_t
+DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_READ_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+static size_t
+DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf,
+ size_t size, Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_WRITE_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = (void *)buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+ int status;
+
+ if ((status = fcntl(fd, F_GETFL)) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+/// @class Operation
+/// @brief Represents a ProcessMonitor operation.
+///
+/// Under FreeBSD, it is not possible to ptrace() from any other thread but the
+/// one that spawned or attached to the process from the start. Therefore, when
+/// a ProcessMonitor is asked to deliver or change the state of an inferior
+/// process the operation must be "funneled" to a specific thread to perform the
+/// task. The Operation class provides an abstract base for all services the
+/// ProcessMonitor must perform via the single virtual function Execute, thus
+/// encapsulating the code that needs to run in the privileged context.
+class Operation
+{
+public:
+ virtual ~Operation() {}
+ virtual void Execute(ProcessMonitor *monitor) = 0;
+};
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::ReadMemory.
+class ReadOperation : public Operation
+{
+public:
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+ReadOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteOperation
+/// @brief Implements ProcessMonitor::WriteMemory.
+class WriteOperation : public Operation
+{
+public:
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+WriteOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadRegOperation
+/// @brief Implements ProcessMonitor::ReadRegisterValue.
+class ReadRegOperation : public Operation
+{
+public:
+ ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_size(size),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ unsigned m_size;
+ RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+ReadRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+ int rc;
+
+ 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
+ memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteRegOperation
+/// @brief Implements ProcessMonitor::WriteRegisterValue.
+class WriteRegOperation : public Operation
+{
+public:
+ WriteRegOperation(lldb::tid_t tid, unsigned offset,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ const RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+WriteRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+
+ if (PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0) < 0) {
+ m_result = false;
+ return;
+ }
+ *(uintptr_t *)(((caddr_t)&regs) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)&regs, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadGPROperation
+/// @brief Implements ProcessMonitor::ReadGPR.
+class ReadGPROperation : public Operation
+{
+public:
+ ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadGPROperation::Execute(ProcessMonitor *monitor)
+{
+ int rc;
+
+ errno = 0;
+ rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0);
+ if (errno != 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadFPROperation
+/// @brief Implements ProcessMonitor::ReadFPR.
+class ReadFPROperation : public Operation
+{
+public:
+ ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteGPROperation
+/// @brief Implements ProcessMonitor::WriteGPR.
+class WriteGPROperation : public Operation
+{
+public:
+ WriteGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteGPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteFPROperation
+/// @brief Implements ProcessMonitor::WriteFPR.
+class WriteFPROperation : public Operation
+{
+public:
+ WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::Resume.
+class ResumeOperation : public Operation
+{
+public:
+ ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) :
+ m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+ResumeOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_CONTINUE, m_tid, (caddr_t)1, data))
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno));
+ m_result = false;
+ }
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class SingleStepOperation
+/// @brief Implements ProcessMonitor::SingleStep.
+class SingleStepOperation : public Operation
+{
+public:
+ SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result)
+ : m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+SingleStepOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_STEP, m_tid, NULL, data))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class LwpInfoOperation
+/// @brief Implements ProcessMonitor::GetLwpInfo.
+class LwpInfoOperation : public Operation
+{
+public:
+ LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
+ : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+ int &m_err;
+};
+
+void
+LwpInfoOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) {
+ m_result = false;
+ m_err = errno;
+ } else {
+ memcpy(m_info, &plwp, sizeof(plwp));
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class EventMessageOperation
+/// @brief Implements ProcessMonitor::GetEventMessage.
+class EventMessageOperation : public Operation
+{
+public:
+ EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+ : m_tid(tid), m_message(message), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+};
+
+void
+EventMessageOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp)))
+ m_result = false;
+ else {
+ if (plwp.pl_flags & PL_FLAG_FORKED) {
+ m_message = (unsigned long *)plwp.pl_child_pid;
+ m_result = true;
+ } else
+ m_result = false;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class KillOperation : public Operation
+{
+public:
+ KillOperation(bool &result) : m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ bool &m_result;
+};
+
+void
+KillOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_KILL, pid, NULL, 0))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class DetachOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class DetachOperation : public Operation
+{
+public:
+ DetachOperation(Error &result) : m_error(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ Error &m_error;
+};
+
+void
+DetachOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_DETACH, pid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+
+}
+
+ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
+ : m_monitor(monitor)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::OperationArgs::~OperationArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir)
+ : OperationArgs(monitor),
+ m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_path(stdin_path),
+ m_stdout_path(stdout_path),
+ m_stderr_path(stderr_path),
+ m_working_dir(working_dir) { }
+
+ProcessMonitor::LaunchArgs::~LaunchArgs()
+{ }
+
+ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid)
+ : OperationArgs(monitor), m_pid(pid) { }
+
+ProcessMonitor::AttachArgs::~AttachArgs()
+{ }
+
+//------------------------------------------------------------------------------
+/// The basic design of the ProcessMonitor is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state. When a change is detected a
+/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// launching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc. See the comments
+/// on the Operation class for more info as to why this is needed.
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ 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_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<LaunchArgs> args;
+
+ args.reset(new LaunchArgs(this, module, argv, envp,
+ stdin_path, stdout_path, stderr_path, working_dir));
+
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartLaunchOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the launch was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // 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))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process launch failed.");
+ return;
+ }
+}
+
+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_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<AttachArgs> args;
+
+ args.reset(new AttachArgs(this, pid));
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartAttachOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the attach was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // 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))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process attach failed.");
+ return;
+ }
+}
+
+ProcessMonitor::~ProcessMonitor()
+{
+ StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+void
+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))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::LaunchOpThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Launch(LaunchArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const char *stdin_path = args->m_stdin_path;
+ const char *stdout_path = args->m_stdout_path;
+ const char *stderr_path = args->m_stderr_path;
+ const char *working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+
+ lldb::ThreadSP inferior;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ // Pseudo terminal setup.
+ if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len))
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Could not open controlling TTY.");
+ goto FINISH;
+ }
+
+ if ((pid = terminal.Fork(err_str, err_len)) == -1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ // Trace this process.
+ if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0)
+ exit(ePtraceFailed);
+
+ // Do not inherit setgid powers.
+ setgid(getgid());
+
+ // Let us have our own process group.
+ setpgid(0, 0);
+
+ // Dup file descriptors if needed.
+ //
+ // FIXME: If two or more of the paths are the same we needlessly open
+ // the same file multiple times.
+ if (stdin_path != NULL && stdin_path[0])
+ if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY))
+ exit(eDupStdinFailed);
+
+ if (stdout_path != NULL && stdout_path[0])
+ if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStdoutFailed);
+
+ if (stderr_path != NULL && stderr_path[0])
+ if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStderrFailed);
+
+ // Change working directory
+ if (working_dir != NULL && working_dir[0])
+ if (0 != ::chdir(working_dir))
+ exit(eChdirFailed);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(eExecFailed);
+ }
+
+ // Wait for the child process to to trap on its call to execve.
+ ::pid_t wpid;
+ int status;
+ if ((wpid = waitpid(pid, &status, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ args->m_error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ args->m_error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ args->m_error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ args->m_error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ args->m_error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ args->m_error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ args->m_error.SetErrorString("Child exec failed.");
+ break;
+ default:
+ args->m_error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+ goto FINISH;
+ }
+ assert(WIFSTOPPED(status) && wpid == pid &&
+ "Could not sync with inferior process.");
+
+#ifdef notyet
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+#endif
+ // Release the master terminal descriptor and pass it off to the
+ // ProcessMonitor instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ monitor->m_pid = pid;
+
+ // Set the terminal fd to be in non blocking mode (it simplifies the
+ // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking
+ // descriptor to read from).
+ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ goto FINISH;
+
+ // Update the process thread list with this new thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ if (log)
+ log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+ process.GetThreadList().AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::EnableIPC()
+{
+ int fd[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
+ return false;
+
+ m_client_fd = fd[0];
+ m_server_fd = fd[1];
+ return true;
+}
+
+void
+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))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::AttachOpThread(void *arg)
+{
+ AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+ if (!Attach(args))
+ return NULL;
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Attach(AttachArgs *args)
+{
+ lldb::pid_t pid = args->m_pid;
+
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ ThreadList &tl = process.GetThreadList();
+ lldb::ThreadSP inferior;
+
+ if (pid <= 1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+ goto FINISH;
+ }
+
+ // Attach to the requested process.
+ if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ int status;
+ if ((status = waitpid(pid, NULL, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ // Update the process thread list with the attached thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ tl.AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+ FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status)
+{
+ ProcessMessage message;
+ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
+ ProcessFreeBSD *process = monitor->m_process;
+ assert(process);
+ bool stop_monitoring;
+ struct ptrace_lwpinfo plwp;
+ int ptrace_err;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (exited)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Exit(pid, status);
+ process->SendMessage(message);
+ return pid == process->GetID();
+ }
+
+ if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err))
+ stop_monitoring = true; // pid is gone. Bail.
+ else {
+ switch (plwp.pl_siginfo.si_signo)
+ {
+ case SIGTRAP:
+ message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, pid);
+ break;
+
+ default:
+ message = MonitorSignal(monitor, &plwp.pl_siginfo, pid);
+ break;
+ }
+
+ process->SendMessage(message);
+ stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage;
+ }
+
+ return stop_monitoring;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ assert(monitor);
+ assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ break;
+
+ case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */):
+ {
+ // The inferior process is about to exit. Maintain the process in a
+ // state of "limbo" until we are explicitly commanded to detach,
+ // destroy, resume, etc.
+ unsigned long data = 0;
+ if (!monitor->GetEventMessage(pid, &data))
+ data = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
+ message = ProcessMessage::Limbo(pid, (data >> 8));
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Trace(pid);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Break(pid);
+ break;
+ }
+
+ return message;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+ int signo = info->si_signo;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+ if (info->si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d",
+ __FUNCTION__,
+ monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
+ "SI_USER",
+ info->si_pid);
+ if (info->si_pid == getpid())
+ return ProcessMessage::SignalDelivered(pid, signo);
+ else
+ return ProcessMessage::Signal(pid, signo);
+ }
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
+
+ if (signo == SIGSEGV) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGILL) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGFPE) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGBUS) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ // Everything else is "normal" and does not require any special action on
+ // our part.
+ return ProcessMessage::Signal(pid, signo);
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGSEGV);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGSEGV");
+ break;
+ case SEGV_MAPERR:
+ reason = ProcessMessage::eInvalidAddress;
+ break;
+ case SEGV_ACCERR:
+ reason = ProcessMessage::ePrivilegedAddress;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGILL);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGILL");
+ break;
+ case ILL_ILLOPC:
+ reason = ProcessMessage::eIllegalOpcode;
+ break;
+ case ILL_ILLOPN:
+ reason = ProcessMessage::eIllegalOperand;
+ break;
+ case ILL_ILLADR:
+ reason = ProcessMessage::eIllegalAddressingMode;
+ break;
+ case ILL_ILLTRP:
+ reason = ProcessMessage::eIllegalTrap;
+ break;
+ case ILL_PRVOPC:
+ reason = ProcessMessage::ePrivilegedOpcode;
+ break;
+ case ILL_PRVREG:
+ reason = ProcessMessage::ePrivilegedRegister;
+ break;
+ case ILL_COPROC:
+ reason = ProcessMessage::eCoprocessorError;
+ break;
+ case ILL_BADSTK:
+ reason = ProcessMessage::eInternalStackError;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGFPE);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGFPE");
+ break;
+ case FPE_INTDIV:
+ reason = ProcessMessage::eIntegerDivideByZero;
+ break;
+ case FPE_INTOVF:
+ reason = ProcessMessage::eIntegerOverflow;
+ break;
+ case FPE_FLTDIV:
+ reason = ProcessMessage::eFloatDivideByZero;
+ break;
+ case FPE_FLTOVF:
+ reason = ProcessMessage::eFloatOverflow;
+ break;
+ case FPE_FLTUND:
+ reason = ProcessMessage::eFloatUnderflow;
+ break;
+ case FPE_FLTRES:
+ reason = ProcessMessage::eFloatInexactResult;
+ break;
+ case FPE_FLTINV:
+ reason = ProcessMessage::eFloatInvalidOperation;
+ break;
+ case FPE_FLTSUB:
+ reason = ProcessMessage::eFloatSubscriptRange;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGBUS);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGBUS");
+ break;
+ case BUS_ADRALN:
+ reason = ProcessMessage::eIllegalAlignment;
+ break;
+ case BUS_ADRERR:
+ reason = ProcessMessage::eIllegalAddress;
+ break;
+ case BUS_OBJERR:
+ reason = ProcessMessage::eHardwareError;
+ break;
+ }
+
+ return reason;
+}
+
+void
+ProcessMonitor::ServeOperation(OperationArgs *args)
+{
+ int status;
+ pollfd fdset;
+
+ ProcessMonitor *monitor = args->m_monitor;
+
+ fdset.fd = monitor->m_server_fd;
+ fdset.events = POLLIN | POLLPRI;
+ fdset.revents = 0;
+
+ // We are finised with the arguments and are ready to go. Sync with the
+ // parent thread and start serving operations on the inferior.
+ sem_post(&args->m_semaphore);
+
+ for (;;)
+ {
+ if ((status = poll(&fdset, 1, -1)) < 0)
+ {
+ switch (errno)
+ {
+ default:
+ assert(false && "Unexpected poll() failure!");
+ continue;
+
+ case EINTR: continue; // Just poll again.
+ case EBADF: return; // Connection terminated.
+ }
+ }
+
+ assert(status == 1 && "Too many descriptors!");
+
+ if (fdset.revents & POLLIN)
+ {
+ Operation *op = NULL;
+
+ READ_AGAIN:
+ if ((status = read(fdset.fd, &op, sizeof(op))) < 0)
+ {
+ // There is only one acceptable failure.
+ assert(errno == EINTR);
+ goto READ_AGAIN;
+ }
+ if (status == 0)
+ continue; // Poll again. The connection probably terminated.
+ assert(status == sizeof(op));
+ op->Execute(monitor);
+ write(fdset.fd, &op, sizeof(op));
+ }
+ }
+}
+
+void
+ProcessMonitor::DoOperation(Operation *op)
+{
+ int status;
+ Operation *ack = NULL;
+ Mutex::Locker lock(m_server_mutex);
+
+ // FIXME: Do proper error checking here.
+ write(m_client_fd, &op, sizeof(op));
+
+READ_AGAIN:
+ if ((status = read(m_client_fd, &ack, sizeof(ack))) < 0)
+ {
+ // If interrupted by a signal handler try again. Otherwise the monitor
+ // thread probably died and we have a stale file descriptor -- abort the
+ // operation.
+ if (errno == EINTR)
+ goto READ_AGAIN;
+ return;
+ }
+
+ assert(status == sizeof(ack));
+ assert(ack == op && "Invalid monitor thread response!");
+}
+
+size_t
+ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ size_t result;
+ ReadOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+size_t
+ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error)
+{
+ size_t result;
+ WriteOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name,
+ unsigned size, RegisterValue &value)
+{
+ bool result;
+ ReadRegOperation op(tid, offset, size, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char* reg_name, const RegisterValue &value)
+{
+ bool result;
+ WriteRegOperation op(tid, offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ m_process->GetUnixSignals().GetSignalAsCString (signo));
+ ResumeOperation op(tid, signo, result);
+ DoOperation(&op);
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+ return result;
+}
+
+bool
+ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ SingleStepOperation op(tid, signo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::BringProcessIntoLimbo()
+{
+ bool result;
+ KillOperation op(result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)
+{
+ bool result;
+ LwpInfoOperation op(tid, lwpinfo, result, ptrace_err);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+lldb_private::Error
+ProcessMonitor::Detach(lldb::tid_t tid)
+{
+ lldb_private::Error error;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(error);
+ DoOperation(&op);
+ }
+ return error;
+}
+
+bool
+ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
+{
+ int target_fd = open(path, flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ return (dup2(target_fd, fd) == -1) ? false : true;
+}
+
+void
+ProcessMonitor::StopMonitoringChildProcess()
+{
+ lldb::thread_result_t thread_result;
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ Host::ThreadCancel(m_monitor_thread, NULL);
+ Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
+ m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+ }
+}
+
+void
+ProcessMonitor::StopMonitor()
+{
+ StopMonitoringChildProcess();
+ StopOpThread();
+ CloseFD(m_terminal_fd);
+ CloseFD(m_client_fd);
+ CloseFD(m_server_fd);
+}
+
+void
+ProcessMonitor::StopOpThread()
+{
+ lldb::thread_result_t result;
+
+ if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ Host::ThreadCancel(m_operation_thread, NULL);
+ Host::ThreadJoin(m_operation_thread, &result, NULL);
+ m_operation_thread = LLDB_INVALID_HOST_THREAD;
+}
+
+void
+ProcessMonitor::CloseFD(int &fd)
+{
+ if (fd != -1)
+ {
+ close(fd);
+ fd = -1;
+ }
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
new file mode 100644
index 000000000000..ce66c03f2f8c
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -0,0 +1,322 @@
+//===-- ProcessMonitor.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_ProcessMonitor_H_
+#define liblldb_ProcessMonitor_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessFreeBSD;
+class Operation;
+
+/// @class ProcessMonitor
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are propagated to the associated
+/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitor
+{
+public:
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error);
+
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error);
+
+ ~ProcessMonitor();
+
+ /// Provides the process number of debugee.
+ lldb::pid_t
+ GetPID() const { return m_pid; }
+
+ /// Returns the process associated with this ProcessMonitor.
+ ProcessFreeBSD &
+ GetProcess() { return *m_process; }
+
+ /// Returns a file descriptor to the controlling terminal of the inferior
+ /// process.
+ ///
+ /// Reads from this file descriptor yield both the standard output and
+ /// standard error of this debugee. Even if stderr and stdout were
+ /// redirected on launch it may still happen that data is available on this
+ /// descriptor (if the inferior process opens /dev/tty, for example).
+ ///
+ /// If this monitor was attached to an existing process this method returns
+ /// -1.
+ int
+ GetTerminalFD() const { return m_terminal_fd; }
+
+ /// Reads @p size bytes from address @vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoReadMemory.
+ size_t
+ ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Writes @p size bytes from address @p vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoWriteMemory.
+ size_t
+ WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ unsigned size, lldb_private::RegisterValue &value);
+
+ /// Writes the given value to the register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const lldb_private::RegisterValue &value);
+
+ /// Reads all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
+ /// to the memory region pointed to by @p lwpinfo.
+ bool
+ GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread IDto the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ Resume(lldb::tid_t tid, uint32_t signo);
+
+ /// Single steps the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ SingleStep(lldb::tid_t tid, uint32_t signo);
+
+ /// Sends the inferior process a PTRACE_KILL signal. The inferior will
+ /// still exists and can be interrogated. Once resumed it will exit as
+ /// though it received a SIGKILL.
+ bool
+ BringProcessIntoLimbo();
+
+ lldb_private::Error
+ Detach(lldb::tid_t tid);
+
+ void
+ StopMonitor();
+
+private:
+ ProcessFreeBSD *m_process;
+
+ lldb::thread_t m_operation_thread;
+ lldb::thread_t m_monitor_thread;
+ lldb::pid_t m_pid;
+
+
+ lldb_private::Mutex m_server_mutex;
+ int m_terminal_fd;
+ int m_client_fd;
+ int m_server_fd;
+
+ struct OperationArgs
+ {
+ OperationArgs(ProcessMonitor *monitor);
+
+ ~OperationArgs();
+
+ ProcessMonitor *m_monitor; // The monitor performing the attach.
+ sem_t m_semaphore; // Posted to once operation complete.
+ lldb_private::Error m_error; // Set if process operation failed.
+ };
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs : OperationArgs
+ {
+ LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir);
+
+ ~LaunchArgs();
+
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const char *m_stdin_path; // Redirect stdin or NULL.
+ const char *m_stdout_path; // Redirect stdout or NULL.
+ const char *m_stderr_path; // Redirect stderr or NULL.
+ const char *m_working_dir; // Working directory or NULL.
+ };
+
+ void
+ StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+ static void *
+ LaunchOpThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ bool
+ EnableIPC();
+
+ struct AttachArgs : OperationArgs
+ {
+ AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid);
+
+ ~AttachArgs();
+
+ lldb::pid_t m_pid; // pid of the process to be attached.
+ };
+
+ void
+ StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+ static void *
+ AttachOpThread(void *args);
+
+ static bool
+ Attach(AttachArgs *args);
+
+ static void
+ ServeOperation(OperationArgs *args);
+
+ static bool
+ DupDescriptor(const char *path, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, bool exited, int signal, int status);
+
+ static ProcessMessage
+ MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage
+ MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGILL(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
+
+ void
+ DoOperation(Operation *op);
+
+ /// Stops the child monitor thread.
+ void
+ StopMonitoringChildProcess();
+
+ /// Stops the operation thread used to attach/launch a process.
+ void
+ StopOpThread();
+
+ void
+ CloseFD(int &fd);
+};
+
+#endif // #ifndef liblldb_ProcessMonitor_H_
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
new file mode 100644
index 000000000000..6e2c140682ba
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
@@ -0,0 +1,89 @@
+//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "POSIXStopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//===----------------------------------------------------------------------===//
+// POSIXLimboStopInfo
+
+POSIXLimboStopInfo::~POSIXLimboStopInfo() { }
+
+lldb::StopReason
+POSIXLimboStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonThreadExiting;
+}
+
+const char *
+POSIXLimboStopInfo::GetDescription()
+{
+ return "thread exiting";
+}
+
+bool
+POSIXLimboStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXLimboStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXCrashStopInfo
+
+POSIXCrashStopInfo::~POSIXCrashStopInfo() { }
+
+lldb::StopReason
+POSIXCrashStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonException;
+}
+
+const char *
+POSIXCrashStopInfo::GetDescription()
+{
+ return ProcessMessage::GetCrashReasonString(m_crash_reason, m_fault_addr);
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXNewThreadStopInfo
+
+POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { }
+
+lldb::StopReason
+POSIXNewThreadStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonNone;
+}
+
+const char *
+POSIXNewThreadStopInfo::GetDescription()
+{
+ return "thread spawned";
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/POSIX/POSIXStopInfo.h
new file mode 100644
index 000000000000..cbf309e53506
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.h
@@ -0,0 +1,120 @@
+//===-- POSIXStopInfo.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_POSIXStopInfo_H_
+#define liblldb_POSIXStopInfo_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+#include "POSIXThread.h"
+#include "ProcessMessage.h"
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXStopInfo
+/// @brief Simple base class for all POSIX-specific StopInfo objects.
+///
+class POSIXStopInfo
+ : public lldb_private::StopInfo
+{
+public:
+ POSIXStopInfo(lldb_private::Thread &thread, uint32_t status)
+ : StopInfo(thread, status)
+ { }
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXLimboStopInfo
+/// @brief Represents the stop state of a process ready to exit.
+///
+class POSIXLimboStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXLimboStopInfo(POSIXThread &thread)
+ : POSIXStopInfo(thread, 0)
+ { }
+
+ ~POSIXLimboStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXCrashStopInfo
+/// @brief Represents the stop state of process that is ready to crash.
+///
+class POSIXCrashStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXCrashStopInfo(POSIXThread &thread, uint32_t status,
+ ProcessMessage::CrashReason reason,
+ lldb::addr_t fault_addr)
+ : POSIXStopInfo(thread, status),
+ m_crash_reason(reason),
+ m_fault_addr(fault_addr)
+ { }
+
+ ~POSIXCrashStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+private:
+ ProcessMessage::CrashReason m_crash_reason;
+ lldb::addr_t m_fault_addr;
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXNewThreadStopInfo
+/// @brief Represents the stop state of process when a new thread is spawned.
+///
+
+class POSIXNewThreadStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXNewThreadStopInfo (POSIXThread &thread)
+ : POSIXStopInfo (thread, 0)
+ { }
+
+ ~POSIXNewThreadStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
new file mode 100644
index 000000000000..93c296679df2
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -0,0 +1,578 @@
+//===-- POSIXThread.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"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "POSIXStopInfo.h"
+#include "POSIXThread.h"
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86_64.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContextLinux_x86_64.h"
+#include "RegisterContextFreeBSD_x86_64.h"
+
+#include "UnwindLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+POSIXThread::POSIXThread(Process &process, lldb::tid_t tid)
+ : Thread(process, tid),
+ m_frame_ap (),
+ m_breakpoint (),
+ m_thread_name_valid (false),
+ m_thread_name ()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+
+ // Set the current watchpoints for this thread.
+ Target &target = GetProcess()->GetTarget();
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ size_t wp_size = wp_list.GetSize();
+
+ for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
+ {
+ lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
+ if (wp.get() && wp->IsEnabled())
+ {
+ assert(EnableHardwareWatchpoint(wp.get()));
+ }
+ }
+}
+
+POSIXThread::~POSIXThread()
+{
+ DestroyThread();
+}
+
+ProcessMonitor &
+POSIXThread::GetMonitor()
+{
+ ProcessSP base = GetProcess();
+ ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
+ return process.GetMonitor();
+}
+
+void
+POSIXThread::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ //if (StateIsStoppedState(GetState())
+ {
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+ }
+ // FIXME: This should probably happen somewhere else.
+ SetResumeState(eStateRunning);
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
+}
+
+const char *
+POSIXThread::GetInfo()
+{
+ return NULL;
+}
+
+void
+POSIXThread::SetName (const char *name)
+{
+ m_thread_name_valid = (name && name[0]);
+ if (m_thread_name_valid)
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+}
+
+const char *
+POSIXThread::GetName ()
+{
+ if (!m_thread_name_valid)
+ {
+ SetName(Host::GetThreadName(GetProcess()->GetID(), GetID()).c_str());
+ m_thread_name_valid = true;
+ }
+
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+lldb::RegisterContextSP
+POSIXThread::GetRegisterContext()
+{
+ if (!m_reg_context_sp)
+ {
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ m_reg_context_sp.reset(new RegisterContext_i386(*this, 0));
+ break;
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0));
+ break;
+ case llvm::Triple::Linux:
+ m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0));
+ break;
+ default:
+ assert(false && "OS not supported");
+ break;
+ }
+ break;
+ }
+ }
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s ()", __FUNCTION__);
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ reg_ctx_sp = GetRegisterContext();
+ else
+ {
+ assert(GetUnwinder());
+ reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool
+POSIXThread::CalculateStopInfo()
+{
+ SetStopInfo (m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+POSIXThread::GetUnwinder()
+{
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+
+ return m_unwinder_ap.get();
+}
+
+void
+POSIXThread::WillResume(lldb::StateType resume_state)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
+ // TODO: the line below shouldn't really be done, but
+ // the POSIXThread might rely on this so I will leave this in for now
+ SetResumeState(resume_state);
+}
+
+void
+POSIXThread::DidStop()
+{
+ // Don't set the thread state to stopped unless we really stopped.
+}
+
+bool
+POSIXThread::Resume()
+{
+ lldb::StateType resume_state = GetResumeState();
+ ProcessMonitor &monitor = GetMonitor();
+ bool status;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
+ StateAsCString(resume_state));
+
+ switch (resume_state)
+ {
+ default:
+ assert(false && "Unexpected state for resume!");
+ status = false;
+ break;
+
+ case lldb::eStateRunning:
+ SetState(resume_state);
+ status = monitor.Resume(GetID(), GetResumeSignal());
+ break;
+
+ case lldb::eStateStepping:
+ SetState(resume_state);
+ status = monitor.SingleStep(GetID(), GetResumeSignal());
+ break;
+ case lldb::eStateStopped:
+ case lldb::eStateSuspended:
+ status = true;
+ break;
+ }
+
+ return status;
+}
+
+void
+POSIXThread::Notify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64,
+ __FUNCTION__, message.PrintKind(), GetID());
+
+ switch (message.GetKind())
+ {
+ default:
+ assert(false && "Unexpected message kind!");
+ break;
+
+ case ProcessMessage::eExitMessage:
+ // Nothing to be done.
+ break;
+
+ case ProcessMessage::eLimboMessage:
+ LimboNotify(message);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ SignalNotify(message);
+ break;
+
+ case ProcessMessage::eSignalDeliveredMessage:
+ SignalDeliveredNotify(message);
+ break;
+
+ case ProcessMessage::eTraceMessage:
+ TraceNotify(message);
+ break;
+
+ case ProcessMessage::eBreakpointMessage:
+ BreakNotify(message);
+ break;
+
+ case ProcessMessage::eWatchpointMessage:
+ WatchNotify(message);
+ break;
+
+ case ProcessMessage::eCrashMessage:
+ CrashNotify(message);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ ThreadNotify(message);
+ break;
+ }
+}
+
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool wp_set = false;
+ if (wp)
+ {
+ addr_t wp_addr = wp->GetLoadAddress();
+ size_t wp_size = wp->GetByteSize();
+ bool wp_read = wp->WatchpointRead();
+ bool wp_write = wp->WatchpointWrite();
+ uint32_t wp_hw_index = wp->GetHardwareIndex();
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
+ wp_read, wp_write,
+ wp_hw_index);
+ }
+ return wp_set;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ }
+ return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+POSIXThread::FindVacantWatchpointIndex()
+{
+ uint32_t hw_index = LLDB_INVALID_INDEX32;
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointVacant(wp_idx))
+ {
+ hw_index = wp_idx;
+ break;
+ }
+ }
+ }
+ return hw_index;
+}
+
+void
+POSIXThread::BreakNotify(const ProcessMessage &message)
+{
+ bool status;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ assert(GetRegisterContext());
+ status = GetRegisterContextPOSIX()->UpdateAfterBreakpoint();
+ assert(status && "Breakpoint update failed!");
+
+ // With our register state restored, resolve the breakpoint object
+ // corresponding to our current PC.
+ assert(GetRegisterContext());
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ if (log)
+ log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
+ lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site && bp_site->ValidForThisThread(this))
+ {
+ lldb::break_id_t bp_id = bp_site->GetID();
+ if (GetProcess()->GetThreadList().SetSelectedThreadByID(GetID()))
+ SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
+ else
+ assert(false && "Invalid thread ID during BreakNotify.");
+ }
+ else
+ {
+ const ThreadSpec *spec = bp_site ?
+ bp_site->GetOwnerAtIndex(0)->GetOptionsNoCreate()->GetThreadSpecNoCreate() : 0;
+
+ if (spec && spec->TIDMatches(*this))
+ assert(false && "BreakpointSite is invalid for the current ThreadSpec.");
+ else
+ {
+ if (!m_stop_info_sp) {
+ StopInfoSP invalid_stop_info_sp;
+ SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ }
+}
+
+void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ lldb::addr_t halt_addr = message.GetHWAddress();
+ if (log)
+ log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+ PRIx64, __FUNCTION__, halt_addr);
+
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ // Clear the watchpoint hit here
+ reg_ctx->ClearWatchpointHits();
+ break;
+ }
+ }
+
+ if (wp_idx == num_hw_wps)
+ return;
+
+ Target &target = GetProcess()->GetTarget();
+ lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+ assert(wp_sp.get() && "No watchpoint found");
+ SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+ wp_sp->GetID()));
+ }
+}
+
+void
+POSIXThread::TraceNotify(const ProcessMessage &message)
+{
+ SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
+}
+
+void
+POSIXThread::LimboNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
+}
+
+void
+POSIXThread::SignalNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::CrashNotify(const ProcessMessage &message)
+{
+ // FIXME: Update stop reason as per bugzilla 14598
+ int signo = message.GetSignal();
+
+ assert(message.GetKind() == ProcessMessage::eCrashMessage);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'",
+ __FUNCTION__, signo, message.PrintCrashReason());
+
+ SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
+ message.GetCrashReason(),
+ message.GetFaultAddress())));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::ThreadNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this)));
+}
+
+unsigned
+POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg = LLDB_INVALID_REGNUM;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ llvm_unreachable("CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ RegisterContextSP base = GetRegisterContext();
+ if (base) {
+ RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base);
+ reg = context.GetRegisterIndexFromOffset(offset);
+ }
+ }
+ break;
+ }
+ return reg;
+}
+
+const char *
+POSIXThread::GetRegisterName(unsigned reg)
+{
+ const char * name = nullptr;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ name = GetRegisterContext()->GetRegisterName(reg);
+ break;
+ }
+ return name;
+}
+
+const char *
+POSIXThread::GetRegisterNameFromOffset(unsigned offset)
+{
+ return GetRegisterName(GetRegisterIndexFromOffset(offset));
+}
+
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h
new file mode 100644
index 000000000000..d051d23860df
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.h
@@ -0,0 +1,133 @@
+//===-- POSIXThread.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_POSIXThread_H_
+#define liblldb_POSIXThread_H_
+
+// C Includes
+// C++ Includes
+#include <memory>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMessage;
+class ProcessMonitor;
+class RegisterContextPOSIX;
+
+//------------------------------------------------------------------------------
+// @class POSIXThread
+// @brief Abstraction of a POSIX thread.
+class POSIXThread
+ : public lldb_private::Thread
+{
+public:
+ POSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual ~POSIXThread();
+
+ void
+ RefreshStateAfterStop();
+
+ virtual void
+ WillResume(lldb::StateType resume_state);
+
+ // This notifies the thread when a private stop occurs.
+ virtual void
+ DidStop ();
+
+ const char *
+ GetInfo();
+
+ void
+ SetName (const char *name);
+
+ const char *
+ GetName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ //--------------------------------------------------------------------------
+ // These functions provide a mapping from the register offset
+ // back to the register index or name for use in debugging or log
+ // output.
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ const char *
+ GetRegisterNameFromOffset(unsigned offset);
+
+ //--------------------------------------------------------------------------
+ // These methods form a specialized interface to POSIX threads.
+ //
+ bool Resume();
+
+ void Notify(const ProcessMessage &message);
+
+ //--------------------------------------------------------------------------
+ // These methods provide an interface to watchpoints
+ //
+ bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ uint32_t NumSupportedHardwareWatchpoints();
+
+ uint32_t FindVacantWatchpointIndex();
+
+protected:
+ RegisterContextPOSIX *
+ GetRegisterContextPOSIX ()
+ {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = GetRegisterContext();
+#if 0
+ return dynamic_cast<RegisterContextPOSIX*>(m_reg_context_sp.get());
+#endif
+ return (RegisterContextPOSIX *)m_reg_context_sp.get();
+ }
+
+ std::unique_ptr<lldb_private::StackFrame> m_frame_ap;
+
+ lldb::BreakpointSiteSP m_breakpoint;
+
+ bool m_thread_name_valid;
+ std::string m_thread_name;
+
+ ProcessMonitor &
+ GetMonitor();
+
+ virtual bool
+ CalculateStopInfo();
+
+ void BreakNotify(const ProcessMessage &message);
+ void WatchNotify(const ProcessMessage &message);
+ virtual void TraceNotify(const ProcessMessage &message);
+ void LimboNotify(const ProcessMessage &message);
+ void SignalNotify(const ProcessMessage &message);
+ void SignalDeliveredNotify(const ProcessMessage &message);
+ void CrashNotify(const ProcessMessage &message);
+ void ThreadNotify(const ProcessMessage &message);
+ void ExitNotify(const ProcessMessage &message);
+
+ lldb_private::Unwind *
+ GetUnwinder();
+};
+
+#endif // #ifndef liblldb_POSIXThread_H_
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.cpp b/source/Plugins/Process/POSIX/ProcessMessage.cpp
new file mode 100644
index 000000000000..60a29e07cea8
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.cpp
@@ -0,0 +1,258 @@
+//===-- ProcessMessage.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMessage.h"
+
+#include <sstream>
+
+using namespace lldb_private;
+
+namespace {
+
+inline void AppendFaultAddr(std::string& str, lldb::addr_t addr)
+{
+ std::stringstream ss;
+ ss << " (fault address: 0x" << std::hex << addr << ")";
+ str += ss.str();
+}
+
+}
+
+const char *
+ProcessMessage::GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr)
+{
+ static std::string str;
+
+ switch (reason)
+ {
+ default:
+ assert(false && "invalid CrashReason");
+ break;
+
+ case eInvalidAddress:
+ str = "invalid address";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case ePrivilegedAddress:
+ str = "address access protected";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case eIllegalOpcode:
+ str = "illegal instruction";
+ break;
+ case eIllegalOperand:
+ str = "illegal instruction operand";
+ break;
+ case eIllegalAddressingMode:
+ str = "illegal addressing mode";
+ break;
+ case eIllegalTrap:
+ str = "illegal trap";
+ break;
+ case ePrivilegedOpcode:
+ str = "privileged instruction";
+ break;
+ case ePrivilegedRegister:
+ str = "privileged register";
+ break;
+ case eCoprocessorError:
+ str = "coprocessor error";
+ break;
+ case eInternalStackError:
+ str = "internal stack error";
+ break;
+ case eIllegalAlignment:
+ str = "illegal alignment";
+ break;
+ case eIllegalAddress:
+ str = "illegal address";
+ break;
+ case eHardwareError:
+ str = "hardware error";
+ break;
+ case eIntegerDivideByZero:
+ str = "integer divide by zero";
+ break;
+ case eIntegerOverflow:
+ str = "integer overflow";
+ break;
+ case eFloatDivideByZero:
+ str = "floating point divide by zero";
+ break;
+ case eFloatOverflow:
+ str = "floating point overflow";
+ break;
+ case eFloatUnderflow:
+ str = "floating point underflow";
+ break;
+ case eFloatInexactResult:
+ str = "inexact floating point result";
+ break;
+ case eFloatInvalidOperation:
+ str = "invalid floating point operation";
+ break;
+ case eFloatSubscriptRange:
+ str = "invalid floating point subscript range";
+ break;
+ }
+
+ return str.c_str();
+}
+
+const char *
+ProcessMessage::PrintCrashReason(CrashReason reason)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (reason)
+ {
+ case eInvalidCrashReason:
+ str = "eInvalidCrashReason";
+ break;
+
+ // SIGSEGV crash reasons.
+ case eInvalidAddress:
+ str = "eInvalidAddress";
+ break;
+ case ePrivilegedAddress:
+ str = "ePrivilegedAddress";
+ break;
+
+ // SIGILL crash reasons.
+ case eIllegalOpcode:
+ str = "eIllegalOpcode";
+ break;
+ case eIllegalOperand:
+ str = "eIllegalOperand";
+ break;
+ case eIllegalAddressingMode:
+ str = "eIllegalAddressingMode";
+ break;
+ case eIllegalTrap:
+ str = "eIllegalTrap";
+ break;
+ case ePrivilegedOpcode:
+ str = "ePrivilegedOpcode";
+ break;
+ case ePrivilegedRegister:
+ str = "ePrivilegedRegister";
+ break;
+ case eCoprocessorError:
+ str = "eCoprocessorError";
+ break;
+ case eInternalStackError:
+ str = "eInternalStackError";
+ break;
+
+ // SIGBUS crash reasons:
+ case eIllegalAlignment:
+ str = "eIllegalAlignment";
+ break;
+ case eIllegalAddress:
+ str = "eIllegalAddress";
+ break;
+ case eHardwareError:
+ str = "eHardwareError";
+ break;
+
+ // SIGFPE crash reasons:
+ case eIntegerDivideByZero:
+ str = "eIntegerDivideByZero";
+ break;
+ case eIntegerOverflow:
+ str = "eIntegerOverflow";
+ break;
+ case eFloatDivideByZero:
+ str = "eFloatDivideByZero";
+ break;
+ case eFloatOverflow:
+ str = "eFloatOverflow";
+ break;
+ case eFloatUnderflow:
+ str = "eFloatUnderflow";
+ break;
+ case eFloatInexactResult:
+ str = "eFloatInexactResult";
+ break;
+ case eFloatInvalidOperation:
+ str = "eFloatInvalidOperation";
+ break;
+ case eFloatSubscriptRange:
+ str = "eFloatSubscriptRange";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintCrashReason() const
+{
+ return PrintCrashReason(m_crash_reason);
+}
+
+const char *
+ProcessMessage::PrintKind(Kind kind)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (kind)
+ {
+ case eInvalidMessage:
+ str = "eInvalidMessage";
+ break;
+ case eExitMessage:
+ str = "eExitMessage";
+ break;
+ case eLimboMessage:
+ str = "eLimboMessage";
+ break;
+ case eSignalMessage:
+ str = "eSignalMessage";
+ break;
+ case eSignalDeliveredMessage:
+ str = "eSignalDeliveredMessage";
+ break;
+ case eTraceMessage:
+ str = "eTraceMessage";
+ break;
+ case eBreakpointMessage:
+ str = "eBreakpointMessage";
+ break;
+ case eWatchpointMessage:
+ str = "eWatchpointMessage";
+ break;
+ case eCrashMessage:
+ str = "eCrashMessage";
+ break;
+ case eNewThreadMessage:
+ str = "eNewThreadMessage";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintKind() const
+{
+ return PrintKind(m_kind);
+}
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.h b/source/Plugins/Process/POSIX/ProcessMessage.h
new file mode 100644
index 000000000000..c6c460c13445
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.h
@@ -0,0 +1,207 @@
+//===-- ProcessMessage.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_ProcessMessage_H_
+#define liblldb_ProcessMessage_H_
+
+#include <cassert>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+class ProcessMessage
+{
+public:
+
+ /// The type of signal this message can correspond to.
+ enum Kind
+ {
+ eInvalidMessage,
+ eExitMessage,
+ eLimboMessage,
+ eSignalMessage,
+ eSignalDeliveredMessage,
+ eTraceMessage,
+ eBreakpointMessage,
+ eWatchpointMessage,
+ eCrashMessage,
+ eNewThreadMessage
+ };
+
+ enum CrashReason
+ {
+ eInvalidCrashReason,
+
+ // SIGSEGV crash reasons.
+ eInvalidAddress,
+ ePrivilegedAddress,
+
+ // SIGILL crash reasons.
+ eIllegalOpcode,
+ eIllegalOperand,
+ eIllegalAddressingMode,
+ eIllegalTrap,
+ ePrivilegedOpcode,
+ ePrivilegedRegister,
+ eCoprocessorError,
+ eInternalStackError,
+
+ // SIGBUS crash reasons,
+ eIllegalAlignment,
+ eIllegalAddress,
+ eHardwareError,
+
+ // SIGFPE crash reasons,
+ eIntegerDivideByZero,
+ eIntegerOverflow,
+ eFloatDivideByZero,
+ eFloatOverflow,
+ eFloatUnderflow,
+ eFloatInexactResult,
+ eFloatInvalidOperation,
+ eFloatSubscriptRange
+ };
+
+ ProcessMessage()
+ : m_tid(LLDB_INVALID_PROCESS_ID),
+ m_kind(eInvalidMessage),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0) { }
+
+ Kind GetKind() const { return m_kind; }
+
+ lldb::tid_t GetTID() const { return m_tid; }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Limbo(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eLimboMessage, status);
+ }
+
+ /// Indicates that the thread @p tid had the signal @p signum delivered.
+ static ProcessMessage Signal(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalMessage, signum);
+ }
+
+ /// Indicates that a signal @p signum generated by the debugging process was
+ /// delivered to the thread @p tid.
+ static ProcessMessage SignalDelivered(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalDeliveredMessage, signum);
+ }
+
+ /// Indicates that the thread @p tid encountered a trace point.
+ static ProcessMessage Trace(lldb::tid_t tid) {
+ return ProcessMessage(tid, eTraceMessage);
+ }
+
+ /// Indicates that the thread @p tid encountered a break point.
+ static ProcessMessage Break(lldb::tid_t tid) {
+ return ProcessMessage(tid, eBreakpointMessage);
+ }
+
+ static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+ return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+ }
+
+ /// Indicates that the thread @p tid crashed.
+ static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
+ int signo, lldb::addr_t fault_addr) {
+ ProcessMessage message(pid, eCrashMessage, signo, fault_addr);
+ message.m_crash_reason = reason;
+ return message;
+ }
+
+ /// Indicates that the thread @p child_tid was spawned.
+ static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
+ return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
+ }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Exit(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eExitMessage, status);
+ }
+
+ int GetExitStatus() const {
+ assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
+ return m_status;
+ }
+
+ int GetSignal() const {
+ assert(GetKind() == eSignalMessage || GetKind() == eCrashMessage ||
+ GetKind() == eSignalDeliveredMessage);
+ return m_status;
+ }
+
+ int GetStopStatus() const {
+ assert(GetKind() == eSignalMessage);
+ return m_status;
+ }
+
+ CrashReason GetCrashReason() const {
+ assert(GetKind() == eCrashMessage);
+ return m_crash_reason;
+ }
+
+ lldb::addr_t GetFaultAddress() const {
+ assert(GetKind() == eCrashMessage);
+ return m_addr;
+ }
+
+ lldb::addr_t GetHWAddress() const {
+ assert(GetKind() == eWatchpointMessage || GetKind() == eTraceMessage);
+ return m_addr;
+ }
+
+ lldb::tid_t GetChildTID() const {
+ assert(GetKind() == eNewThreadMessage);
+ return m_child_tid;
+ }
+
+ static const char *
+ GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr);
+
+ const char *
+ PrintCrashReason() const;
+
+ static const char *
+ PrintCrashReason(CrashReason reason);
+
+ const char *
+ PrintKind() const;
+
+ static const char *
+ PrintKind(Kind);
+
+private:
+ ProcessMessage(lldb::tid_t tid, Kind kind,
+ int status = 0, lldb::addr_t addr = 0)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(status),
+ m_addr(addr),
+ m_child_tid(0) { }
+
+ ProcessMessage(lldb::tid_t tid, Kind kind, lldb::tid_t child_tid)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0),
+ m_child_tid(child_tid) { }
+
+ lldb::tid_t m_tid;
+ Kind m_kind : 8;
+ CrashReason m_crash_reason : 8;
+ int m_status;
+ lldb::addr_t m_addr;
+ lldb::tid_t m_child_tid;
+};
+
+#endif // #ifndef liblldb_ProcessMessage_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
new file mode 100644
index 000000000000..f04631ddf914
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -0,0 +1,911 @@
+//===-- ProcessPOSIX.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"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+#if 0
+Process*
+ProcessPOSIX::CreateInstance(Target& target, Listener &listener)
+{
+ return new ProcessPOSIX(target, listener);
+}
+
+
+void
+ProcessPOSIX::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks);
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener)
+ : Process(target, listener),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_monitor(NULL),
+ m_module(NULL),
+ m_message_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_now(false),
+ m_seen_initial_stop()
+{
+ // FIXME: Putting this code in the ctor and saving the byte order in a
+ // member variable is a hack to avoid const qual issues in GetByteOrder.
+ lldb::ModuleSP module = GetTarget().GetExecutableModule();
+ if (module && module->GetObjectFile())
+ m_byte_order = module->GetObjectFile()->GetByteOrder();
+}
+
+ProcessPOSIX::~ProcessPOSIX()
+{
+ delete m_monitor;
+}
+
+//------------------------------------------------------------------------------
+// Process protocol.
+void
+ProcessPOSIX::Finalize()
+{
+ Process::Finalize();
+
+ if (m_monitor)
+ m_monitor->StopMonitor();
+}
+
+bool
+ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ // If there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ m_monitor = new ProcessMonitor(this, pid, error);
+
+ if (!error.Success())
+ return error;
+
+ PlatformSP platform_sp (m_target.GetPlatform ());
+ assert (platform_sp.get());
+ if (!platform_sp)
+ return error; // FIXME: Detatch?
+
+ // Find out what we can about this process
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (pid, process_info);
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
+ m_target.GetArchitecture(),
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return error;
+
+ // Fix the target architecture if necessary
+ const ArchSpec &module_arch = exe_module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch))
+ m_target.SetArchitecture(module_arch);
+
+ // Initialize the target module list
+ m_target.SetExecutableModule (exe_module_sp, true);
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(pid);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ return DoAttachToProcessWithID(pid);
+}
+
+Error
+ProcessPOSIX::WillLaunch(Module* module)
+{
+ Error error;
+ return error;
+}
+
+const char *
+ProcessPOSIX::GetFilePath(
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path)
+{
+ const char *pts_name = "/dev/pts/";
+ const char *path = NULL;
+
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ path = file_action->GetPath();
+ // By default the stdio paths passed in will be pseudo-terminal
+ // (/dev/pts). If so, convert to using a different default path
+ // instead to redirect I/O to the debugger console. This should
+ // also handle user overrides to /dev/null or a different file.
+ if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
+ path = default_path;
+ }
+
+ return path;
+}
+
+Error
+ProcessPOSIX::DoLaunch (Module *module,
+ const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ const char* working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir) {
+ FileSpec WorkingDir(working_dir, true);
+ if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
+ {
+ error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
+ return error;
+ }
+ }
+
+ SetPrivateState(eStateLaunching);
+
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+
+ // Default of NULL will mean to use existing open file descriptors
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ stdin_path = GetFilePath(file_action, stdin_path);
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ stdout_path = GetFilePath(file_action, stdout_path);
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ stderr_path = GetFilePath(file_action, stderr_path);
+
+ m_monitor = new ProcessMonitor (this,
+ module,
+ launch_info.GetArguments().GetConstArgumentVector(),
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
+ stdin_path,
+ stdout_path,
+ stderr_path,
+ working_dir,
+ error);
+
+ m_module = module;
+
+ if (!error.Success())
+ return error;
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(m_monitor->GetPID());
+ return error;
+}
+
+void
+ProcessPOSIX::DidLaunch()
+{
+}
+
+Error
+ProcessPOSIX::DoResume()
+{
+ StateType state = GetPrivateState();
+
+ assert(state == eStateStopped);
+
+ SetPrivateState(eStateRunning);
+
+ bool did_resume = false;
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ did_resume = thread->Resume() || did_resume;
+ }
+ assert(did_resume && "Process resume failed!");
+
+ return Error();
+}
+
+addr_t
+ProcessPOSIX::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress();
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessPOSIX::DoHalt(bool &caused_stop)
+{
+ Error error;
+
+ if (IsStopped())
+ {
+ caused_stop = false;
+ }
+ else if (kill(GetID(), SIGSTOP))
+ {
+ caused_stop = false;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ caused_stop = true;
+ }
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDetach(bool keep_stopped)
+{
+ Error error;
+ if (keep_stopped)
+ {
+ // FIXME: If you want to implement keep_stopped,
+ // this would be the place to do it.
+ error.SetErrorString("Detaching with keep_stopped true is not currently supported on this platform.");
+ return error;
+ }
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ error = m_monitor->Detach(thread->GetID());
+ }
+
+ if (error.Success())
+ SetPrivateState(eStateDetached);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoSignal(int signal)
+{
+ Error error;
+
+ if (kill(GetID(), signal))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDestroy()
+{
+ Error error;
+
+ if (!HasExited())
+ {
+ // Drive the exit event to completion (do not keep the inferior in
+ // limbo).
+ m_exit_now = true;
+
+ if ((m_monitor == NULL || kill(m_monitor->GetPID(), SIGKILL)) && error.Success())
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ SetPrivateState(eStateExited);
+ }
+
+ return error;
+}
+
+void
+ProcessPOSIX::SendMessage(const ProcessMessage &message)
+{
+ Mutex::Locker lock(m_message_mutex);
+
+ Mutex::Locker thread_lock(m_thread_list.GetMutex());
+
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.FindThreadByID(message.GetTID(), false).get());
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ return;
+
+ case ProcessMessage::eLimboMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ if (m_exit_now)
+ {
+ SetPrivateState(eStateExited);
+ m_monitor->Detach(GetID());
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ break;
+
+ case ProcessMessage::eExitMessage:
+ assert(thread);
+ thread->SetState(eStateExited);
+ // FIXME: I'm not sure we need to do this.
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ SetExitStatus(m_exit_status, NULL);
+ }
+ else if (!IsAThreadRunning())
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ if (message.GetSignal() == SIGSTOP &&
+ AddThreadForInitialStopIfNeeded(message.GetTID()))
+ return;
+ // Intentional fall-through
+
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eNewThreadMessage:
+ case ProcessMessage::eCrashMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ break;
+ }
+
+ m_message_queue.push(message);
+}
+
+void
+ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
+{
+ // FIXME: Will this work the same way on FreeBSD and Linux?
+}
+
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+ bool added_to_set = false;
+ ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+ if (it == m_seen_initial_stop.end())
+ {
+ m_seen_initial_stop.insert(stop_tid);
+ added_to_set = true;
+ }
+ return added_to_set;
+}
+
+POSIXThread *
+ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid)
+{
+ return new POSIXThread(process, tid);
+}
+
+void
+ProcessPOSIX::RefreshStateAfterStop()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
+
+ Mutex::Locker lock(m_message_mutex);
+
+ // This method used to only handle one message. Changing it to loop allows
+ // it to handle the case where we hit a breakpoint while handling a different
+ // breakpoint.
+ while (!m_message_queue.empty())
+ {
+ ProcessMessage &message = m_message_queue.front();
+
+ // Resolve the thread this message corresponds to and pass it along.
+ lldb::tid_t tid = message.GetTID();
+ if (log)
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ GetThreadList().FindThreadByID(tid, false).get());
+
+ if (message.GetKind() == ProcessMessage::eNewThreadMessage)
+ {
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
+ lldb::tid_t child_tid = message.GetChildTID();
+ ThreadSP thread_sp;
+ thread_sp.reset(CreateNewPOSIXThread(*this, child_tid));
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ m_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list.RefreshStateAfterStop();
+
+ if (thread)
+ thread->Notify(message);
+
+ if (message.GetKind() == ProcessMessage::eExitMessage)
+ {
+ // FIXME: We should tell the user about this, but the limbo message is probably better for that.
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
+ thread_sp.reset();
+ m_seen_initial_stop.erase(tid);
+ }
+
+ m_message_queue.pop();
+ }
+}
+
+bool
+ProcessPOSIX::IsAlive()
+{
+ StateType state = GetPrivateState();
+ return state != eStateDetached
+ && state != eStateExited
+ && state != eStateInvalid
+ && state != eStateUnloaded;
+}
+
+size_t
+ProcessPOSIX::DoReadMemory(addr_t vm_addr,
+ void *buf, size_t size, Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->ReadMemory(vm_addr, buf, size, error);
+}
+
+size_t
+ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
+ Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->WriteMemory(vm_addr, buf, size, error);
+}
+
+addr_t
+ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions,
+ Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[allocated_addr] = size;
+ error.Clear();
+ } else {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+
+ return allocated_addr;
+}
+
+Error
+ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
+{
+ Error error;
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+
+ return error;
+}
+
+addr_t
+ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error)
+{
+ addr_t function_addr = LLDB_INVALID_ADDRESS;
+ if (address == NULL) {
+ error.SetErrorStringWithFormat("unable to determine direct function call for NULL address");
+ } else if (!InferiorCall(this, address, function_addr)) {
+ function_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s",
+ address->CalculateSymbolContextSymbol()->GetName().AsCString());
+ }
+ return function_addr;
+}
+
+size_t
+ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
+{
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+
+ ArchSpec arch = GetTarget().GetArchitecture();
+ const uint8_t *opcode = NULL;
+ size_t opcode_size = 0;
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_64_x86_64:
+ opcode = g_i386_opcode;
+ opcode_size = sizeof(g_i386_opcode);
+ break;
+ }
+
+ bp_site->SetTrapOpcode(opcode, opcode_size);
+ return opcode_size;
+}
+
+Error
+ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site)
+{
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site)
+{
+ return DisableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ // Try to find a vacant watchpoint slot in the inferiors' main thread
+ uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+
+ if (thread)
+ wp_hw_index = thread->FindVacantWatchpointIndex();
+
+ if (wp_hw_index == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorString("Setting hardware watchpoint failed.");
+ }
+ else
+ {
+ wp->SetHardwareIndex(wp_hw_index);
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ wp_enabled = false;
+ }
+ if (wp_enabled)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ {
+ // Watchpoint enabling failed on at least one
+ // of the threads so roll back all of them
+ DisableWatchpoint(wp, false);
+ error.SetErrorString("Setting hardware watchpoint failed");
+ }
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+ watchID, (uint64_t)addr);
+ // This is needed (for now) to keep watchpoints disabled correctly
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ bool wp_disabled = true;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+ else
+ wp_disabled = false;
+ }
+ if (wp_disabled)
+ {
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("Disabling hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+ Error error;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+ if (thread)
+ num = thread->NumSupportedHardwareWatchpoints();
+ else
+ error.SetErrorString("Process does not exist.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+ Error error = GetWatchpointSupportInfo(num);
+ // Watchpoints trigger and halt the inferior after
+ // the corresponding instruction has been executed.
+ after = true;
+ return error;
+}
+
+uint32_t
+ProcessPOSIX::UpdateThreadListIfNeeded()
+{
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ // Do not allow recursive updates.
+ return m_thread_list.GetSize(false);
+}
+
+bool
+ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ // Update the process thread list with this new thread.
+ // FIXME: We should be using tid, not pid.
+ assert(m_monitor);
+ ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
+ if (!thread_sp) {
+ thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+ }
+
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
+ new_thread_list.AddThread(thread_sp);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ByteOrder
+ProcessPOSIX::GetByteOrder() const
+{
+ // FIXME: We should be able to extract this value directly. See comment in
+ // ProcessPOSIX().
+ return m_byte_order;
+}
+
+size_t
+ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
+{
+ ssize_t status;
+ if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
+ {
+ error.SetErrorToErrno();
+ return 0;
+ }
+ return status;
+}
+
+UnixSignals &
+ProcessPOSIX::GetUnixSignals()
+{
+ return m_signals;
+}
+
+//------------------------------------------------------------------------------
+// Utility functions.
+
+bool
+ProcessPOSIX::HasExited()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsStopped()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+ bool is_running = false;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ StateType thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping)
+ {
+ is_running = true;
+ break;
+ }
+ }
+ return is_running;
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
new file mode 100644
index 000000000000..48b19bac47e7
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -0,0 +1,211 @@
+//===-- ProcessPOSIX.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_ProcessPOSIX_H_
+#define liblldb_ProcessPOSIX_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+#include "ProcessMessage.h"
+
+class ProcessMonitor;
+class POSIXThread;
+
+class ProcessPOSIX :
+ public lldb_private::Process
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessPOSIX(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessPOSIX();
+
+ //------------------------------------------------------------------
+ // Process protocol.
+ //------------------------------------------------------------------
+ virtual void
+ Finalize();
+
+ virtual bool
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+
+ virtual lldb_private::Error
+ WillLaunch(lldb_private::Module *module);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID(lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ const lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb_private::Error
+ DoResume();
+
+ virtual lldb_private::Error
+ DoHalt(bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach(bool keep_stopped);
+
+ virtual lldb_private::Error
+ DoSignal(int signal);
+
+ virtual lldb_private::Error
+ DoDestroy();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual bool
+ IsAlive();
+
+ virtual size_t
+ DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory(size_t size, uint32_t permissions,
+ lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory(lldb::addr_t ptr);
+
+ virtual lldb::addr_t
+ ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
+
+ virtual lldb_private::Error
+ EnableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num, bool &after);
+
+ virtual uint32_t
+ UpdateThreadListIfNeeded();
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) = 0;
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ virtual size_t
+ PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+
+ //--------------------------------------------------------------------------
+ // ProcessPOSIX internal API.
+
+ /// Registers the given message with this process.
+ void SendMessage(const ProcessMessage &message);
+
+ ProcessMonitor &
+ GetMonitor() { assert(m_monitor); return *m_monitor; }
+
+ lldb_private::UnixSignals &
+ GetUnixSignals();
+
+ const char *
+ GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path);
+
+ /// Stops all threads in the process.
+ /// The \p stop_tid parameter indicates the thread which initiated the stop.
+ virtual void
+ StopAllThreads(lldb::tid_t stop_tid);
+
+ /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+ /// The \p stop_tid paramter indicates the thread which the stop happened for.
+ bool
+ AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
+ virtual POSIXThread *
+ CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+protected:
+ /// Target byte order.
+ lldb::ByteOrder m_byte_order;
+
+ /// Process monitor;
+ ProcessMonitor *m_monitor;
+
+ /// The module we are executing.
+ lldb_private::Module *m_module;
+
+ /// Message queue notifying this instance of inferior process state changes.
+ lldb_private::Mutex m_message_mutex;
+ std::queue<ProcessMessage> m_message_queue;
+
+ /// Drive any exit events to completion.
+ bool m_exit_now;
+
+ /// OS-specific signal set.
+ lldb_private::UnixSignals m_signals;
+
+ /// Returns true if the process has exited.
+ bool HasExited();
+
+ /// Returns true if the process is stopped.
+ bool IsStopped();
+
+ /// Returns true if at least one running is currently running
+ bool IsAThreadRunning();
+
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ MMapMap m_addr_to_mmap_size;
+
+ typedef std::set<lldb::tid_t> ThreadStopSet;
+ /// Every thread begins with a stop signal. This keeps track
+ /// of the threads for which we have received the stop signal.
+ ThreadStopSet m_seen_initial_stop;
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
new file mode 100644
index 000000000000..624ca87b883a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -0,0 +1,193 @@
+//===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIXLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+
+Log *
+ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+static uint32_t
+GetFlagBits (const char *arg)
+{
+ if (::strcasecmp (arg, "all") == 0 ) return POSIX_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) return POSIX_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) return POSIX_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) return POSIX_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) return POSIX_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) return POSIX_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) return POSIX_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) return POSIX_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) return POSIX_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) return POSIX_LOG_PROCESS;
+ else if (::strcasecmp (arg, "ptrace") == 0 ) return POSIX_LOG_PTRACE;
+ else if (::strcasecmp (arg, "registers") == 0 ) return POSIX_LOG_REGISTERS;
+ else if (::strcasecmp (arg, "step") == 0 ) return POSIX_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) return POSIX_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) return POSIX_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) return POSIX_LOG_WATCHPOINTS;
+ return 0;
+}
+
+void
+ProcessPOSIXLog::DisableLog (const char **args, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ flag_bits = log->GetMask().Get();
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits &= ~bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessPOSIXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits |= bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = POSIX_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ g_log_enabled = true;
+ }
+ return g_log;
+}
+
+void
+ProcessPOSIXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ " ptrace - log all calls to ptrace\n"
+#endif
+ " registers - log register read/writes\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessPOSIXLog::m_pluginname);
+}
+
+
+void
+ProcessPOSIXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+int ProcessPOSIXLog::m_nestinglevel;
+const char *ProcessPOSIXLog::m_pluginname = "";
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
new file mode 100644
index 000000000000..a1e2e3747d21
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -0,0 +1,111 @@
+//===-- ProcessPOSIXLog.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_ProcessPOSIXLog_h_
+#define liblldb_ProcessPOSIXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define POSIX_LOG_VERBOSE (1u << 0)
+#define POSIX_LOG_PROCESS (1u << 1)
+#define POSIX_LOG_THREAD (1u << 2)
+#define POSIX_LOG_PACKETS (1u << 3)
+#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define POSIX_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define POSIX_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define POSIX_LOG_BREAKPOINTS (1u << 7)
+#define POSIX_LOG_WATCHPOINTS (1u << 8)
+#define POSIX_LOG_STEP (1u << 9)
+#define POSIX_LOG_COMM (1u << 10)
+#define POSIX_LOG_ASYNC (1u << 11)
+#define POSIX_LOG_PTRACE (1u << 12)
+#define POSIX_LOG_REGISTERS (1u << 13)
+#define POSIX_LOG_ALL (UINT32_MAX)
+#define POSIX_LOG_DEFAULT POSIX_LOG_PACKETS
+
+// The size which determines "short memory reads/writes".
+#define POSIX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
+
+class ProcessPOSIXLog
+{
+ static int m_nestinglevel;
+ static const char *m_pluginname;
+
+public:
+ static void
+ RegisterPluginName(const char *pluginName)
+ {
+ m_pluginname = pluginName;
+ }
+
+ static void
+ RegisterPluginName(lldb_private::ConstString pluginName)
+ {
+ m_pluginname = pluginName.GetCString();
+ }
+
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **args, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ const char **args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+
+ // The following functions can be used to enable the client to limit
+ // logging to only the top level function calls. This is useful for
+ // recursive functions. FIXME: not thread safe!
+ // Example:
+ // void NestingFunc() {
+ // LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
+ // if (log)
+ // {
+ // ProcessPOSIXLog::IncNestLevel();
+ // if (ProcessPOSIXLog::AtTopNestLevel())
+ // log->Print(msg);
+ // }
+ // NestingFunc();
+ // if (log)
+ // ProcessPOSIXLog::DecNestLevel();
+ // }
+
+ static bool
+ AtTopNestLevel()
+ {
+ return m_nestinglevel == 1;
+ }
+
+ static void
+ IncNestLevel()
+ {
+ ++m_nestinglevel;
+ }
+
+ static void
+ DecNestLevel()
+ {
+ --m_nestinglevel;
+ assert(m_nestinglevel >= 0);
+ }
+};
+
+#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..0fb9dc1cb3dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,136 @@
+//===-- RegisterContextFreeBSD_x86_64.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the FreeBSD specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rax;
+ uint32_t trapno;
+ uint16_t fs;
+ uint16_t gs;
+ uint32_t err;
+ uint16_t es;
+ uint16_t ds;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+} GPR;
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextFreeBSD_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the FreeBSD specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextFreeBSD_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..ffff40a9c65b
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextFreeBSD_x86_64.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_x86_64_H_
+#define liblldb_RegisterContextFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextFreeBSD_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextFreeBSD_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
new file mode 100644
index 000000000000..c1aea2a41a1f
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
@@ -0,0 +1,180 @@
+//===-- RegisterContextLinux_x86_64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include "RegisterContextLinux_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the Linux specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+
+#define UPDATE_DR_INFO(reg_index) \
+do { \
+ GetRegisterContext()[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \
+ GetRegisterContext()[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_ax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+typedef RegisterContext_x86_64::FXSAVE FXSAVE;
+
+struct UserArea
+{
+ GPR gpr; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FXSAVE i387; // General purpose floating point registers (see FPR for extended register sets).
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segment size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FXSAVE* fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+};
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextLinux_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the Linux specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextLinux_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+
+ UPDATE_DR_INFO(0);
+ UPDATE_DR_INFO(1);
+ UPDATE_DR_INFO(2);
+ UPDATE_DR_INFO(3);
+ UPDATE_DR_INFO(4);
+ UPDATE_DR_INFO(5);
+ UPDATE_DR_INFO(6);
+ UPDATE_DR_INFO(7);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
new file mode 100644
index 000000000000..1509ef55b8dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextLinux_x86_64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_x86_64_H_
+#define liblldb_RegisterContextLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextLinux_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextLinux_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
new file mode 100644
index 000000000000..63ae01e83a90
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
@@ -0,0 +1,70 @@
+//===-- RegisterContextPOSIX.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_H_
+#define liblldb_RegisterContextPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Target/RegisterContext.h"
+
+//------------------------------------------------------------------------------
+/// @class RegisterContextPOSIX
+///
+/// @brief Extends RegisterClass with a few virtual operations useful on POSIX.
+class RegisterContextPOSIX
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx)
+ { m_watchpoints_initialized = false; }
+
+ /// Updates the register state of the associated thread after hitting a
+ /// breakpoint (if that make sense for the architecture). Default
+ /// implementation simply returns true for architectures which do not
+ /// require any update.
+ ///
+ /// @return
+ /// True if the operation succeeded and false otherwise.
+ virtual bool UpdateAfterBreakpoint() { return true; }
+
+ /// Determines the index in lldb's register file given a kernel byte offset.
+ virtual unsigned
+ GetRegisterIndexFromOffset(unsigned offset) { return LLDB_INVALID_REGNUM; }
+
+ // Checks to see if a watchpoint specified by hw_index caused the inferior
+ // to stop.
+ virtual bool
+ IsWatchpointHit (uint32_t hw_index) { return false; }
+
+ // Resets any watchpoints that have been hit.
+ virtual bool
+ ClearWatchpointHits () { return false; }
+
+ // Returns the watchpoint address associated with a watchpoint hardware
+ // index.
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index) { return LLDB_INVALID_ADDRESS; }
+
+ virtual bool
+ IsWatchpointVacant (uint32_t hw_index) { return false; }
+
+ virtual bool
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index) { return false; }
+
+protected:
+ bool m_watchpoints_initialized;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_H_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.cpp b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
new file mode 100644
index 000000000000..49676bd3fc73
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
@@ -0,0 +1,551 @@
+//===-- RegisterContextPOSIX_i386.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+enum
+{
+ k_first_gpr,
+ gpr_eax = k_first_gpr,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+ k_last_gpr = gpr_gs,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ k_last_fpr = fpu_xmm7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpu_registers = k_last_fpr - k_first_fpr + 1
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpu_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }
+};
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, regs) + \
+ offsetof(RegisterContext_i386::GPR, regname))
+
+// Computes the offset of the given FPR in the user data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, i387) + \
+ offsetof(RegisterContext_i386::FPU, regname))
+
+// Number of bytes needed to represent a GPR.
+#define GPR_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_i386::FPU*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_i386::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_i386::XMMReg)
+
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax),
+ DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx),
+ DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx),
+ DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx),
+ DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi),
+ DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi),
+ DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp),
+ DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss),
+ DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags),
+ DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs),
+
+ // Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip),
+ DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs),
+ DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp),
+ DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr),
+
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+
+};
+
+#ifndef NDEBUG
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+#endif
+
+static unsigned GetRegOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_offset;
+}
+
+static unsigned GetRegSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_size;
+}
+
+RegisterContext_i386::RegisterContext_i386(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+}
+
+RegisterContext_i386::~RegisterContext_i386()
+{
+}
+
+ProcessMonitor &
+RegisterContext_i386::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+void
+RegisterContext_i386::Invalidate()
+{
+}
+
+void
+RegisterContext_i386::InvalidateAllRegisters()
+{
+}
+
+size_t
+RegisterContext_i386::GetRegisterCount()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_i386::GetRegisterInfoAtIndex(size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_i386::GetRegisterSetCount()
+{
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+RegisterContext_i386::GetRegisterSet(size_t set)
+{
+ if (set < k_num_register_sets)
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_i386::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (g_register_infos[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_i386::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return g_register_infos[reg].name;
+}
+
+bool
+RegisterContext_i386::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), GetRegSize(reg), value);
+}
+
+bool
+RegisterContext_i386::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool RegisterContext_i386::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), value);
+}
+
+bool
+RegisterContext_i386::WriteAllRegisterValues(const DataBufferSP &data)
+{
+ return false;
+}
+
+bool
+RegisterContext_i386::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_fos;
+ case gdb_dp : return fpu_foo;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContext_i386::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t eflags;
+
+ if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (eflags & TRACE_BIT)
+ return true;
+
+ eflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(eflags & TRACE_BIT))
+ return false;
+
+ eflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_eflags, eflags);
+}
+
+void
+RegisterContext_i386::LogGPR(const char *title)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8" PRIx64, g_register_infos[reg].name, ((uint64_t*)&user.regs)[reg]);
+ }
+ }
+}
+
+bool
+RegisterContext_i386::ReadGPR()
+{
+ bool result;
+
+ ProcessMonitor &monitor = GetMonitor();
+ result = monitor.ReadGPR(m_thread.GetID(), &user.regs, sizeof(user.regs));
+ LogGPR("RegisterContext_i386::ReadGPR()");
+ return result;
+}
+
+bool
+RegisterContext_i386::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &user.i387, sizeof(user.i387));
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.h b/source/Plugins/Process/POSIX/RegisterContext_i386.h
new file mode 100644
index 000000000000..96066c47b815
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.h
@@ -0,0 +1,169 @@
+//===-- RegisterContext_i386.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_i386_h_
+#define liblldb_RegisterContext_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class RegisterContext_i386 : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_i386(lldb_private::Thread &thread,
+ uint32_t concreate_frame_idx);
+
+ ~RegisterContext_i386();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ bool
+ ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value);
+
+ bool
+ ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value);
+
+ bool
+ WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data,
+ uint32_t data_offset = 0);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ struct GPR
+ {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t orig_ax;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[8];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint32_t ip;
+ uint32_t cs;
+ uint32_t foo;
+ uint32_t fos;
+ uint32_t mxcsr;
+ uint32_t reserved;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint32_t pad[56];
+ };
+
+ // A user area like this no longer exists on FreeBSD
+ // making this a Linux artifact. Nonetheless, it is safe
+ // leaving it here while the code is being cleaned up and generalized.
+
+ struct UserArea
+ {
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ FPU i387; // FPU registers.
+ uint32_t tsize; // Text segment size.
+ uint32_t dsize; // Data segment size.
+ uint32_t ssize; // Stack segment size.
+ uint32_t start_code; // VM address of text.
+ uint32_t start_stack; // VM address of stack bottom (top in rsp).
+ int32_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ uint32_t ar0; // Location of GPR's.
+ FPU* fpstate; // Location of FPR's.
+ uint32_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ };
+private:
+ UserArea user;
+
+ ProcessMonitor &GetMonitor();
+
+ void LogGPR(const char *title);
+
+ bool ReadGPR();
+ bool ReadFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_i386_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/POSIX/RegisterContext_x86.h
new file mode 100644
index 000000000000..61a25c407758
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86.h
@@ -0,0 +1,110 @@
+//===-- RegisterContext_x86.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_x86_H_
+#define liblldb_RegisterContext_x86_H_
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fcw = 24,
+ gdb_fsw = 25,
+ gdb_ftw = 26,
+ gdb_fpu_cs = 27,
+ gdb_ip = 28,
+ gdb_fpu_ds = 29,
+ gdb_dp = 30,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
new file mode 100644
index 000000000000..617b18484e5a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
@@ -0,0 +1,1563 @@
+//===-- RegisterContext_x86_64.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 "ProcessPOSIX.h"
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "ProcessMonitor.h"
+#endif
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContext_x86_64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+ #define NT_X86_XSTATE 0x202
+#endif
+
+enum
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7,
+ gcc_dwarf_fpu_ymm0,
+ gcc_dwarf_fpu_ymm1,
+ gcc_dwarf_fpu_ymm2,
+ gcc_dwarf_fpu_ymm3,
+ gcc_dwarf_fpu_ymm4,
+ gcc_dwarf_fpu_ymm5,
+ gcc_dwarf_fpu_ymm6,
+ gcc_dwarf_fpu_ymm7,
+ gcc_dwarf_fpu_ymm8,
+ gcc_dwarf_fpu_ymm9,
+ gcc_dwarf_fpu_ymm10,
+ gcc_dwarf_fpu_ymm11,
+ gcc_dwarf_fpu_ymm12,
+ gcc_dwarf_fpu_ymm13,
+ gcc_dwarf_fpu_ymm14,
+ gcc_dwarf_fpu_ymm15
+};
+
+enum
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fcw = 32,
+ gdb_fpu_fsw = 33,
+ gdb_fpu_ftw = 34,
+ gdb_fpu_cs_64 = 35,
+ gdb_fpu_ip = 36,
+ gdb_fpu_ds_64 = 37,
+ gdb_fpu_dp = 38,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56,
+ gdb_fpu_ymm0 = 57,
+ gdb_fpu_ymm1 = 58,
+ gdb_fpu_ymm2 = 59,
+ gdb_fpu_ymm3 = 60,
+ gdb_fpu_ymm4 = 61,
+ gdb_fpu_ymm5 = 62,
+ gdb_fpu_ymm6 = 63,
+ gdb_fpu_ymm7 = 64,
+ gdb_fpu_ymm8 = 65,
+ gdb_fpu_ymm9 = 66,
+ gdb_fpu_ymm10 = 67,
+ gdb_fpu_ymm11 = 68,
+ gdb_fpu_ymm12 = 69,
+ gdb_fpu_ymm13 = 70,
+ gdb_fpu_ymm14 = 71,
+ gdb_fpu_ymm15 = 72
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpr_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static const uint32_t
+g_avx_regnums[k_num_avx_registers] =
+{
+ fpu_ymm0,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers, g_fpu_regnums },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers, g_avx_regnums }
+};
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::FPR, xstate) + \
+ offsetof(RegisterContext_x86_64::FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+#define YMM_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::YMM, regname))
+
+// Number of bytes needed to represent a i386 GPR
+#define GPR_i386_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FXSAVE*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_x86_64::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_x86_64::XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(RegisterContext_x86_64::YMMReg)
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, 0, 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+// Dummy data for RegisterInfo::value_regs as expected by DumpRegisterSet.
+static uint32_t value_regs = LLDB_INVALID_REGNUM;
+
+#define DEFINE_GPR_i386(reg_i386, reg_x86_64, alt, kind1, kind2, kind3, kind4) \
+ { #reg_i386, alt, GPR_i386_SIZE(reg_i386), 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg_i386 }, &value_regs, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_YMM(reg, i) \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR))
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ DEFINE_GPR(rax, NULL, gcc_dwarf_gpr_rax, gcc_dwarf_gpr_rax, LLDB_INVALID_REGNUM, gdb_gpr_rax),
+ DEFINE_GPR(rbx, NULL, gcc_dwarf_gpr_rbx, gcc_dwarf_gpr_rbx, LLDB_INVALID_REGNUM, gdb_gpr_rbx),
+ DEFINE_GPR(rcx, NULL, gcc_dwarf_gpr_rcx, gcc_dwarf_gpr_rcx, LLDB_INVALID_REGNUM, gdb_gpr_rcx),
+ DEFINE_GPR(rdx, NULL, gcc_dwarf_gpr_rdx, gcc_dwarf_gpr_rdx, LLDB_INVALID_REGNUM, gdb_gpr_rdx),
+ DEFINE_GPR(rdi, NULL, gcc_dwarf_gpr_rdi, gcc_dwarf_gpr_rdi, LLDB_INVALID_REGNUM, gdb_gpr_rdi),
+ DEFINE_GPR(rsi, NULL, gcc_dwarf_gpr_rsi, gcc_dwarf_gpr_rsi, LLDB_INVALID_REGNUM, gdb_gpr_rsi),
+ DEFINE_GPR(rbp, "fp", gcc_dwarf_gpr_rbp, gcc_dwarf_gpr_rbp, LLDB_REGNUM_GENERIC_FP, gdb_gpr_rbp),
+ DEFINE_GPR(rsp, "sp", gcc_dwarf_gpr_rsp, gcc_dwarf_gpr_rsp, LLDB_REGNUM_GENERIC_SP, gdb_gpr_rsp),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_gpr_r8, gcc_dwarf_gpr_r8, LLDB_INVALID_REGNUM, gdb_gpr_r8),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_gpr_r9, gcc_dwarf_gpr_r9, LLDB_INVALID_REGNUM, gdb_gpr_r9),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_gpr_r10, gcc_dwarf_gpr_r10, LLDB_INVALID_REGNUM, gdb_gpr_r10),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_gpr_r11, gcc_dwarf_gpr_r11, LLDB_INVALID_REGNUM, gdb_gpr_r11),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_gpr_r12, gcc_dwarf_gpr_r12, LLDB_INVALID_REGNUM, gdb_gpr_r12),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_gpr_r13, gcc_dwarf_gpr_r13, LLDB_INVALID_REGNUM, gdb_gpr_r13),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_gpr_r14, gcc_dwarf_gpr_r14, LLDB_INVALID_REGNUM, gdb_gpr_r14),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_gpr_r15, gcc_dwarf_gpr_r15, LLDB_INVALID_REGNUM, gdb_gpr_r15),
+ DEFINE_GPR(rip, "pc", gcc_dwarf_gpr_rip, gcc_dwarf_gpr_rip, LLDB_REGNUM_GENERIC_PC, gdb_gpr_rip),
+ DEFINE_GPR(rflags, "flags", LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_cs),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_fs),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_gs),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ss),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_es),
+ // i386 registers
+ DEFINE_GPR_i386(eax, rax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax),
+ DEFINE_GPR_i386(ebx, rbx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx),
+ DEFINE_GPR_i386(ecx, rcx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx),
+ DEFINE_GPR_i386(edx, rdx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx),
+ DEFINE_GPR_i386(edi, rdi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi),
+ DEFINE_GPR_i386(esi, rsi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi),
+ DEFINE_GPR_i386(ebp, rbp, "fp", gcc_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, gdb_ebp),
+ DEFINE_GPR_i386(esp, rsp, "sp", gcc_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, gdb_esp),
+ DEFINE_GPR_i386(eip, rip, "pc", gcc_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, gdb_eip),
+ DEFINE_GPR_i386(eflags, rflags, "flags", gcc_eflags, dwarf_eflags, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags),
+ // i387 Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ip),
+ // FIXME: Extract segment from ip.
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs_64),
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_dp),
+ // FIXME: Extract segment from dp.
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds_64),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_mxcsr),
+ DEFINE_FPR(mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+ DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9),
+ DEFINE_XMM(xmm, 10),
+ DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12),
+ DEFINE_XMM(xmm, 13),
+ DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0),
+ DEFINE_YMM(ymm, 1),
+ DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3),
+ DEFINE_YMM(ymm, 4),
+ DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6),
+ DEFINE_YMM(ymm, 7),
+ DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9),
+ DEFINE_YMM(ymm, 10),
+ DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12),
+ DEFINE_YMM(ymm, 13),
+ DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
+};
+
+static bool IsGPR(unsigned reg)
+{
+ return reg <= k_last_gpr; // GPR's come first.
+}
+
+static bool IsAVX(unsigned reg)
+{
+ return (k_first_avx <= reg && reg <= k_last_avx);
+}
+static bool IsFPR(unsigned reg)
+{
+ return (k_first_fpr <= reg && reg <= k_last_fpr);
+}
+
+
+bool RegisterContext_x86_64::IsFPR(unsigned reg, FPRType fpr_type)
+{
+ bool generic_fpr = ::IsFPR(reg);
+ if (fpr_type == eXSAVE)
+ return generic_fpr || IsAVX(reg);
+
+ return generic_fpr;
+}
+
+RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ ::memset(&m_fpr, 0, sizeof(RegisterContext_x86_64::FPR));
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
+ m_fpr_type = eXSAVE; // extended floating-point registers, if available
+ if (false == ReadFPR())
+ m_fpr_type = eFXSAVE; // assume generic floating-point registers
+}
+
+RegisterContext_x86_64::~RegisterContext_x86_64()
+{
+}
+
+void
+RegisterContext_x86_64::Invalidate()
+{
+}
+
+void
+RegisterContext_x86_64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterCount()
+{
+ size_t num_registers = k_num_gpr_registers + k_num_fpr_registers;
+ if (m_fpr_type == eXSAVE)
+ return num_registers + k_num_avx_registers;
+ return num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::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 g_register_infos;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContext_x86_64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_x86_64::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContext_x86_64::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;
+}
+
+// Parse ymm registers and into xmm.bytes and ymmh.bytes.
+bool RegisterContext_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+// Concatenate xmm.bytes with ymmh.bytes
+bool RegisterContext_x86_64::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+bool
+RegisterContext_x86_64::IsRegisterSetAvailable(size_t set_index)
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets...
+ size_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+ if (m_fpr_type == eXSAVE) // ...and to start with AVX registers.
+ ++num_sets;
+
+ return (set_index < num_sets);
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg, m_fpr_type)) {
+ if (!ReadFPR())
+ return false;
+ }
+ else {
+ bool success = ReadRegister(reg, value);
+
+ // If an i386 register should be parsed from an x86_64 register...
+ if (success && reg >= k_first_i386 && reg <= k_last_i386)
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info); // ...use the type specified by reg_info rather than the uint64_t default
+ return success;
+ }
+
+ if (reg_info->encoding == eEncodingVector) {
+ ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != ByteOrder::eByteOrderInvalid) {
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7) {
+ value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15) {
+ value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (m_fpr_type == eXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ value.SetBytes(m_ymm_set.ymm[reg - fpu_ymm0].bytes, reg_info->byte_size, byte_order);
+ else
+ return false;
+ }
+ return value.GetType() == RegisterValue::eTypeBytes;
+ }
+ return false;
+ }
+
+ // Note that lldb uses slightly different naming conventions from sys/user.h
+ switch (reg)
+ {
+ default:
+ return false;
+ case fpu_dp:
+ value = m_fpr.xstate.fxsave.dp;
+ break;
+ case fpu_fcw:
+ value = m_fpr.xstate.fxsave.fcw;
+ break;
+ case fpu_fsw:
+ value = m_fpr.xstate.fxsave.fsw;
+ break;
+ case fpu_ip:
+ value = m_fpr.xstate.fxsave.ip;
+ break;
+ case fpu_fop:
+ value = m_fpr.xstate.fxsave.fop;
+ break;
+ case fpu_ftw:
+ value = m_fpr.xstate.fxsave.ftw;
+ break;
+ case fpu_mxcsr:
+ value = m_fpr.xstate.fxsave.mxcsr;
+ break;
+ case fpu_mxcsrmask:
+ value = m_fpr.xstate.fxsave.mxcsrmask;
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContext_x86_64::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, GetGPRSize());
+ dst += GetGPRSize();
+ }
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyXSTATEtoYMM(reg, byte_order);
+
+ if (success) {
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (IsGPR(reg)) {
+ return WriteRegister(reg, value);
+ }
+
+ if (IsFPR(reg, m_fpr_type)) {
+ switch (reg)
+ {
+ default:
+ if (reg_info->encoding != eEncodingVector)
+ return false;
+
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ if (m_fpr_type != eXSAVE)
+ return false; // the target processor does not support AVX
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg - fpu_ymm0].bytes, value.GetBytes(), value.GetByteSize());
+ if (false == CopyYMMtoXSTATE(reg, GetByteOrder()))
+ return false;
+ }
+ break;
+ case fpu_dp:
+ m_fpr.xstate.fxsave.dp = value.GetAsUInt64();
+ break;
+ case fpu_fcw:
+ m_fpr.xstate.fxsave.fcw = value.GetAsUInt16();
+ break;
+ case fpu_fsw:
+ m_fpr.xstate.fxsave.fsw = value.GetAsUInt16();
+ break;
+ case fpu_ip:
+ m_fpr.xstate.fxsave.ip = value.GetAsUInt64();
+ break;
+ case fpu_fop:
+ m_fpr.xstate.fxsave.fop = value.GetAsUInt16();
+ break;
+ case fpu_ftw:
+ m_fpr.xstate.fxsave.ftw = value.GetAsUInt16();
+ break;
+ case fpu_mxcsr:
+ m_fpr.xstate.fxsave.mxcsr = value.GetAsUInt32();
+ break;
+ case fpu_mxcsrmask:
+ m_fpr.xstate.fxsave.mxcsrmask = value.GetAsUInt32();
+ break;
+ }
+ if (WriteFPR()) {
+ if (IsAVX(reg))
+ return CopyYMMtoXSTATE(reg, GetByteOrder());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContext_x86_64::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, src, GetGPRSize());
+
+ if (WriteGPR()) {
+ src += GetGPRSize();
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ if (m_fpr_type == eXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ success = WriteFPR();
+ if (success) {
+ success = true;
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyYMMtoXSTATE(reg, byte_order);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ const Process *process = CalculateProcess().get();
+ if (process)
+ {
+ const ArchSpec arch = process->GetTarget().GetArchitecture();;
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_ds; //fpu_fos
+ case gdb_dp : return fpu_dp; //fpu_foo
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ break;
+ }
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ case gcc_dwarf_fpu_ymm0: return fpu_ymm0;
+ case gcc_dwarf_fpu_ymm1: return fpu_ymm1;
+ case gcc_dwarf_fpu_ymm2: return fpu_ymm2;
+ case gcc_dwarf_fpu_ymm3: return fpu_ymm3;
+ case gcc_dwarf_fpu_ymm4: return fpu_ymm4;
+ case gcc_dwarf_fpu_ymm5: return fpu_ymm5;
+ case gcc_dwarf_fpu_ymm6: return fpu_ymm6;
+ case gcc_dwarf_fpu_ymm7: return fpu_ymm7;
+ case gcc_dwarf_fpu_ymm8: return fpu_ymm8;
+ case gcc_dwarf_fpu_ymm9: return fpu_ymm9;
+ case gcc_dwarf_fpu_ymm10: return fpu_ymm10;
+ case gcc_dwarf_fpu_ymm11: return fpu_ymm11;
+ case gcc_dwarf_fpu_ymm12: return fpu_ymm12;
+ case gcc_dwarf_fpu_ymm13: return fpu_ymm13;
+ case gcc_dwarf_fpu_ymm14: return fpu_ymm14;
+ case gcc_dwarf_fpu_ymm15: return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_ss;
+ case gdb_gpr_ds : return gpr_ds;
+ case gdb_gpr_es : return gpr_es;
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fcw : return fpu_fcw;
+ case gdb_fpu_fsw : return fpu_fsw;
+ case gdb_fpu_ftw : return fpu_ftw;
+ case gdb_fpu_cs_64 : return fpu_cs;
+ case gdb_fpu_ip : return fpu_ip;
+ case gdb_fpu_ds_64 : return fpu_ds;
+ case gdb_fpu_dp : return fpu_dp;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ case gdb_fpu_ymm0 : return fpu_ymm0;
+ case gdb_fpu_ymm1 : return fpu_ymm1;
+ case gdb_fpu_ymm2 : return fpu_ymm2;
+ case gdb_fpu_ymm3 : return fpu_ymm3;
+ case gdb_fpu_ymm4 : return fpu_ymm4;
+ case gdb_fpu_ymm5 : return fpu_ymm5;
+ case gdb_fpu_ymm6 : return fpu_ymm6;
+ case gdb_fpu_ymm7 : return fpu_ymm7;
+ case gdb_fpu_ymm8 : return fpu_ymm8;
+ case gdb_fpu_ymm9 : return fpu_ymm9;
+ case gdb_fpu_ymm10 : return fpu_ymm10;
+ case gdb_fpu_ymm11 : return fpu_ymm11;
+ case gdb_fpu_ymm12 : return fpu_ymm12;
+ case gdb_fpu_ymm13 : return fpu_ymm13;
+ case gdb_fpu_ymm14 : return fpu_ymm14;
+ case gdb_fpu_ymm15 : return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+ }
+ }
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+uint32_t
+RegisterContext_x86_64::NumSupportedHardwareWatchpoints()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+ bool is_vacant = false;
+ RegisterValue value;
+
+ assert(hw_index < NumSupportedHardwareWatchpoints());
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (ReadRegister(dr7, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_vacant = (val & (3 << 2*hw_index)) == 0;
+ }
+
+ return is_vacant;
+}
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+ uint32_t rw;
+ if (read) {
+ rw = 0x3; // READ or READ/WRITE
+ } else if (write) {
+ rw = 0x1; // WRITE
+ } else {
+ assert(0 && "read and write cannot both be false");
+ }
+
+ switch (size) {
+ case 1:
+ return rw;
+ case 2:
+ return (0x1 << 2) | rw;
+ case 4:
+ return (0x3 << 2) | rw;
+ case 8:
+ return (0x2 << 2) | rw;
+ default:
+ assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ }
+}
+
+uint32_t
+RegisterContext_x86_64::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
+RegisterContext_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
+ return false;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return false;
+
+ if (read == false && write == false)
+ return false;
+
+ if (!IsWatchpointVacant(hw_index))
+ return false;
+
+ // Set both dr7 (debug control register) and dri (debug address register).
+
+ // dr7{7-0} encodes the local/gloabl enable bits:
+ // global enable --. .-- local enable
+ // | |
+ // v v
+ // dr0 -> bits{1-0}
+ // dr1 -> bits{3-2}
+ // dr2 -> bits{5-4}
+ // dr3 -> bits{7-6}
+ //
+ // dr7{31-16} encodes the rw/len bits:
+ // b_x+3, b_x+2, b_x+1, b_x
+ // where bits{x+1, x} => rw
+ // 0b00: execute, 0b01: write, 0b11: read-or-write,
+ // 0b10: io read-or-write (unused)
+ // and bits{x+3, x+2} => len
+ // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+ //
+ // dr0 -> bits{19-16}
+ // dr1 -> bits{23-20}
+ // dr2 -> bits{27-24}
+ // dr3 -> bits{31-28}
+ if (hw_index < num_hw_watchpoints)
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+ (1 << (2*hw_index) |
+ size_and_rw_bits(size, read, write) <<
+ (16+4*hw_index));
+
+ if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
+ WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+ if (WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+ bool is_hit = false;
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr6, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_hit = val & (1 << hw_index);
+ }
+ }
+
+ return is_hit;
+}
+
+addr_t
+RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+ addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ if (!IsWatchpointVacant(hw_index))
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr0 + hw_index, value))
+ wp_monitor_addr = value.GetAsUInt64();
+ }
+ }
+
+ return wp_monitor_addr;
+}
+
+
+bool
+RegisterContext_x86_64::ClearWatchpointHits()
+{
+ return WriteRegister(dr6, RegisterValue((uint64_t)0));
+}
+
+bool
+RegisterContext_x86_64::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t rflags;
+
+ if ((rflags = ReadRegisterAsUnsigned(gpr_rflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (rflags & TRACE_BIT)
+ return true;
+
+ rflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(rflags & TRACE_BIT))
+ return false;
+
+ rflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_rflags, rflags);
+}
+
+#if defined(__linux__) or defined(__FreeBSD__)
+
+ProcessMonitor &
+RegisterContext_x86_64::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ value);
+}
+
+#else
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
new file mode 100644
index 000000000000..9d59bd78e547
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
@@ -0,0 +1,347 @@
+//===-- RegisterContext_x86_64.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_x86_64_H_
+#define liblldb_RegisterContext_x86_64_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+// Internal codes for all x86_64 registers.
+enum
+{
+ k_first_gpr,
+ gpr_rax = k_first_gpr,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ k_first_i386,
+ gpr_eax = k_first_i386,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags, // eRegisterKindLLDB == 33
+ k_last_i386 = gpr_eflags,
+ k_last_gpr = gpr_eflags,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+ k_last_fpr = fpu_xmm15,
+ k_first_avx,
+ fpu_ymm0 = k_first_avx,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15,
+ k_last_avx = fpu_ymm15,
+
+ dr0,
+ dr1,
+ dr2,
+ dr3,
+ dr4,
+ dr5,
+ dr6,
+ dr7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
+ k_num_avx_registers = k_last_avx - k_first_avx + 1
+};
+
+class RegisterContext_x86_64
+ : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContext_x86_64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize() = 0;
+
+ 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);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t, size_t size, bool read,
+ bool write, uint32_t hw_index);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ IsWatchpointHit (uint32_t hw_index);
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ //---------------------------------------------------------------------------
+ // Generic floating-point registers
+ //---------------------------------------------------------------------------
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16]; // 128-bits for each XMM register
+ };
+
+ struct FXSAVE
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint64_t ip;
+ uint64_t dp;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint32_t padding[24];
+ };
+
+ //---------------------------------------------------------------------------
+ // Extended floating-point registers
+ //---------------------------------------------------------------------------
+ struct YMMHReg
+ {
+ uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register
+ };
+
+ struct YMMReg
+ {
+ uint8_t bytes[32]; // 16 * 16 bits for each YMM register
+ };
+
+ struct YMM
+ {
+ YMMReg ymm[16]; // assembled from ymmh and xmm registers
+ };
+
+ struct XSAVE_HDR
+ {
+ uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor
+ uint64_t reserved1[2];
+ uint64_t reserved2[5];
+ } __attribute__((packed));
+
+ // x86 extensions to FXSAVE (i.e. for AVX processors)
+ struct XSAVE
+ {
+ FXSAVE i387; // floating point registers typical in i387_fxsave_struct
+ XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable
+ YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE)
+ // Slot any extensions to the register file here
+ } __attribute__((packed, aligned (64)));
+
+ struct IOVEC
+ {
+ void *iov_base; // pointer to XSAVE
+ size_t iov_len; // sizeof(XSAVE)
+ };
+
+ //---------------------------------------------------------------------------
+ // Note: prefer kernel definitions over user-land
+ //---------------------------------------------------------------------------
+ enum FPRType
+ {
+ eNotValid = 0,
+ eFSAVE, // TODO
+ eFXSAVE,
+ eSOFT, // TODO
+ eXSAVE
+ };
+
+ // Floating-point registers
+ struct FPR
+ {
+ // Thread state for the floating-point unit of the processor read by ptrace.
+ union XSTATE {
+ FXSAVE fxsave; // Generic floating-point registers.
+ XSAVE xsave; // x86 extended processor state.
+ } xstate;
+ };
+
+protected:
+ // 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();
+
+ virtual bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+private:
+ uint64_t m_gpr[k_num_gpr_registers]; // general purpose registers.
+ 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.
+ IOVEC m_iovec; // wrapper for xsave.
+ YMM m_ymm_set; // copy of ymmh and xmm register halves.
+
+ ProcessMonitor &GetMonitor();
+ lldb::ByteOrder GetByteOrder();
+
+ bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order);
+ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+ bool IsFPR(unsigned reg, FPRType fpr_type);
+
+ bool ReadGPR();
+ bool ReadFPR();
+
+ bool WriteGPR();
+ bool WriteFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_x86_64_H_
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 000000000000..4b1f06a2f9cd
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,110 @@
+//===-- lldb_ARMDefines.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMDefines_h_
+#define lldb_ARMDefines_h_
+
+// Common defintions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+typedef enum
+{
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+} ARM_ShifterType;
+
+// ARM conditions // Meaning (integer) Meaning (floating-point) Condition flags
+#define COND_EQ 0x0 // Equal Equal Z == 1
+#define COND_NE 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI 0x4 // Minus, negative Less than N == 1
+#define COND_PL 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS 0x6 // Overflow Unordered V == 1
+#define COND_VC 0x7 // No overflow Not unordered V == 0
+#define COND_HI 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z == 0
+#define COND_LS 0x9 // Unsigned lower or same Less than or equal C == 0 or Z == 1
+#define COND_GE 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT 0xB // Less than Less than, or unordered N != V
+#define COND_GT 0xC // Greater than Greater than Z == 0 and N == V
+#define COND_LE 0xD // Less than or equal <, ==, or unordered Z == 1 or N != V
+#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *ARMCondCodeToString(uint32_t CC)
+{
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case COND_EQ: return "eq";
+ case COND_NE: return "ne";
+ case COND_HS: return "hs";
+ case COND_LO: return "lo";
+ case COND_MI: return "mi";
+ case COND_PL: return "pl";
+ case COND_VS: return "vs";
+ case COND_VC: return "vc";
+ case COND_HI: return "hi";
+ case COND_LS: return "ls";
+ case COND_GE: return "ge";
+ case COND_LT: return "lt";
+ case COND_GT: return "gt";
+ case COND_LE: return "le";
+ case COND_AL: return "al";
+ }
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // lldb_ARMDefines_h_
diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 000000000000..76d64e15a53e
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,394 @@
+//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMUtils_h_
+#define lldb_ARMUtils_h_
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment)
+{
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
+{
+ switch (type)
+ {
+ default:
+ //assert(0 && "Invalid shift type");
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0)
+ {
+ shift_t = SRType_RRX;
+ return 1;
+ }
+ else
+ {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
+{
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
+{
+ switch (type) {
+ default:
+ //assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32)
+ {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ }
+ else
+ {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t amt = amount % 32;
+ uint32_t result = Rotr32(value, amt);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
+{
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, bool *success)
+{
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
+{
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
+{
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
+{
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0)
+ {
+ imm32 = imm;
+ carry_out = carry_in;
+ }
+ else
+ {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expaned result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0)
+ {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ }
+ else
+ {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode)
+{
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
+{
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
+{
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // lldb_ARMUtils_h_
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
new file mode 100644
index 000000000000..0c95d66cef94
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -0,0 +1,279 @@
+//===-- DynamicRegisterInfo.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 "DynamicRegisterInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Interpreter/PythonDataObjects.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicRegisterInfo::DynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+}
+
+DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+ SetRegisterInfo (dict);
+}
+
+DynamicRegisterInfo::~DynamicRegisterInfo ()
+{
+}
+
+
+size_t
+DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ PythonList sets (dict.GetItemForKey("sets"));
+ if (sets)
+ {
+ const uint32_t num_sets = sets.GetSize();
+ for (uint32_t i=0; i<num_sets; ++i)
+ {
+ PythonString py_set_name(sets.GetItemAtIndex(i));
+ ConstString set_name;
+ if (py_set_name)
+ set_name.SetCString(py_set_name.GetString());
+ if (set_name)
+ {
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ m_set_reg_nums.resize(m_sets.size());
+ }
+ PythonList regs (dict.GetItemForKey("registers"));
+ if (regs)
+ {
+ const uint32_t num_regs = regs.GetSize();
+ PythonString name_pystr("name");
+ PythonString altname_pystr("alt-name");
+ PythonString bitsize_pystr("bitsize");
+ PythonString offset_pystr("offset");
+ PythonString encoding_pystr("encoding");
+ PythonString format_pystr("format");
+ PythonString set_pystr("set");
+ PythonString gcc_pystr("gcc");
+ PythonString dwarf_pystr("dwarf");
+ PythonString generic_pystr("generic");
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
+ if (reg_info_dict)
+ {
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ bzero (&reg_info, sizeof(reg_info));
+
+ reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
+ if (reg_info.name == NULL)
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
+
+ reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ Clear();
+ return 0;
+ }
+ reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
+
+ if (reg_info.byte_size == 0)
+ {
+ Clear();
+ return 0;
+ }
+
+ const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
+ if (format_cstr)
+ {
+ if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
+ {
+ Clear();
+ return 0;
+ }
+ }
+ else
+ reg_info.format = eFormatHex;
+
+ const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
+ if (encoding_cstr)
+ reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
+ else
+ reg_info.encoding = eEncodingUint;
+
+ const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
+ if (set >= m_sets.size())
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
+ const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+
+ m_regs.push_back (reg_info);
+ m_set_reg_nums[set].push_back(i);
+
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ Finalize ();
+ }
+#endif
+ return 0;
+}
+
+
+void
+DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
+ ConstString &reg_name,
+ ConstString &reg_alt_name,
+ ConstString &set_name)
+{
+ const uint32_t reg_num = m_regs.size();
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name, true);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+}
+
+void
+DynamicRegisterInfo::Finalize ()
+{
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisters() const
+{
+ return m_regs.size();
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisterSets() const
+{
+ return m_sets.size();
+}
+
+size_t
+DynamicRegisterInfo::GetRegisterDataByteSize() const
+{
+ return m_reg_data_byte_size;
+}
+
+const RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfoAtIndex (uint32_t i) const
+{
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+}
+
+const RegisterSet *
+DynamicRegisterInfo::GetRegisterSet (uint32_t i) const
+{
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+}
+
+uint32_t
+DynamicRegisterInfo::GetRegisterSetIndexByName (ConstString &set_name, bool can_create)
+{
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return std::distance (m_set_names.begin(), pos);
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+}
+
+uint32_t
+DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return std::distance (m_regs.begin(), pos);
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+void
+DynamicRegisterInfo::Clear()
+{
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_set_names.clear();
+}
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
new file mode 100644
index 000000000000..a11cd333545f
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -0,0 +1,85 @@
+//===-- DynamicRegisterInfo.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_DynamicRegisterInfo_h_
+#define lldb_DynamicRegisterInfo_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+
+class DynamicRegisterInfo
+{
+public:
+ DynamicRegisterInfo ();
+
+ DynamicRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ virtual
+ ~DynamicRegisterInfo ();
+
+ size_t
+ SetRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ void
+ AddRegister (lldb_private::RegisterInfo &reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name);
+
+ void
+ Finalize ();
+
+ size_t
+ GetNumRegisters() const;
+
+ size_t
+ GetNumRegisterSets() const;
+
+ size_t
+ GetRegisterDataByteSize() const;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const;
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ void
+ Clear();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DynamicRegisterInfo can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_set_names;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+#endif // lldb_DynamicRegisterInfo_h_
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 000000000000..499d6d766150
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,274 @@
+//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#include <sys/mman.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
+ addr_t addr, addr_t length, unsigned prot,
+ unsigned flags, addr_t fd, addr_t offset) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ addr_t prot_arg, flags_arg = 0;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ if (flags & eMmapFlagsPrivate)
+ flags_arg |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_arg |= MAP_ANON;
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
+ {
+ 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,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length,
+ &prot_arg,
+ &flags_arg,
+ &fd,
+ &offset);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+
+ allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
+ addr_t length) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
+ {
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ munmap_range.GetBaseAddress(),
+ ClangASTType(),
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL || address == NULL)
+ return false;
+
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ 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,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (returned_func == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (returned_func == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 000000000000..d8b6d0ed57fd
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,43 @@
+//===-- InferiorCallPOSIX.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InferiorCallPOSIX_h_
+#define lldb_InferiorCallPOSIX_h_
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+enum MmapFlags {
+ eMmapFlagsPrivate = 1,
+ eMmapFlagsAnon = 2
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
+} // namespace lldb_private
+
+#endif // lldb_InferiorCallPOSIX_h_
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 000000000000..4bb644e6efe6
--- /dev/null
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,136 @@
+//===-- InstructionUtils.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InstructionUtils_h_
+#define lldb_InstructionUtils_h_
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+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 the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t
+Bits32 (const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t
+Bit32 (const uint32_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t
+Bit64 (const uint64_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void
+SetBits32(uint32_t &bits, const uint32_t msbit, const uint32_t lsbit, const uint32_t val)
+{
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void
+SetBit32(uint32_t &bits, const uint32_t bit, const uint32_t val)
+{
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t
+Rotr32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32-amt)&31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t
+Rotl32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32-amt)&31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t
+MaskUpToBit (const uint64_t bit)
+{
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t
+BitCount (uint64_t x)
+{
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c)
+ {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool
+BitIsSet (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool
+BitIsClear (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t
+UnsignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit (msbit - lsbit);
+ return result;
+}
+
+static inline int64_t
+SignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = UnsignedBits (value, msbit, lsbit);
+ if (BitIsSet(value, msbit))
+ {
+ // Sign extend
+ result |= ~MaskUpToBit (msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // lldb_InstructionUtils_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 000000000000..4d77b6f20fdc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1226 @@
+//===-- RegisterContextDarwin_arm.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextDarwin_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+
+RegisterContextDarwin_arm::RegisterContextDarwin_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm::~RegisterContextDarwin_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC))
+
+static RegisterInfo g_register_infos[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_r0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_sp,
+ gpr_lr,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_exception,
+ exc_fsr,
+ exc_far,
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_arm::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_arm::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int
+RegisterContextDarwin_arm::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextDarwin_arm::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt32 (gpr.r[reg - gpr_r0]);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32 (fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32 (exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.GetAsUInt32();
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_r7;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_r0: return gpr_r0;
+ case dwarf_r1: return gpr_r1;
+ case dwarf_r2: return gpr_r2;
+ case dwarf_r3: return gpr_r3;
+ case dwarf_r4: return gpr_r4;
+ case dwarf_r5: return gpr_r5;
+ case dwarf_r6: return gpr_r6;
+ case dwarf_r7: return gpr_r7;
+ case dwarf_r8: return gpr_r8;
+ case dwarf_r9: return gpr_r9;
+ case dwarf_r10: return gpr_r10;
+ case dwarf_r11: return gpr_r11;
+ case dwarf_r12: return gpr_r12;
+ case dwarf_sp: return gpr_sp;
+ case dwarf_lr: return gpr_lr;
+ case dwarf_pc: return gpr_pc;
+ case dwarf_spsr: return gpr_cpsr;
+
+ case dwarf_s0: return fpu_s0;
+ case dwarf_s1: return fpu_s1;
+ case dwarf_s2: return fpu_s2;
+ case dwarf_s3: return fpu_s3;
+ case dwarf_s4: return fpu_s4;
+ case dwarf_s5: return fpu_s5;
+ case dwarf_s6: return fpu_s6;
+ case dwarf_s7: return fpu_s7;
+ case dwarf_s8: return fpu_s8;
+ case dwarf_s9: return fpu_s9;
+ case dwarf_s10: return fpu_s10;
+ case dwarf_s11: return fpu_s11;
+ case dwarf_s12: return fpu_s12;
+ case dwarf_s13: return fpu_s13;
+ case dwarf_s14: return fpu_s14;
+ case dwarf_s15: return fpu_s15;
+ case dwarf_s16: return fpu_s16;
+ case dwarf_s17: return fpu_s17;
+ case dwarf_s18: return fpu_s18;
+ case dwarf_s19: return fpu_s19;
+ case dwarf_s20: return fpu_s20;
+ case dwarf_s21: return fpu_s21;
+ case dwarf_s22: return fpu_s22;
+ case dwarf_s23: return fpu_s23;
+ case dwarf_s24: return fpu_s24;
+ case dwarf_s25: return fpu_s25;
+ case dwarf_s26: return fpu_s26;
+ case dwarf_s27: return fpu_s27;
+ case dwarf_s28: return fpu_s28;
+ case dwarf_s29: return fpu_s29;
+ case dwarf_s30: return fpu_s30;
+ case dwarf_s31: return fpu_s31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case gcc_r0: return gpr_r0;
+ case gcc_r1: return gpr_r1;
+ case gcc_r2: return gpr_r2;
+ case gcc_r3: return gpr_r3;
+ case gcc_r4: return gpr_r4;
+ case gcc_r5: return gpr_r5;
+ case gcc_r6: return gpr_r6;
+ case gcc_r7: return gpr_r7;
+ case gcc_r8: return gpr_r8;
+ case gcc_r9: return gpr_r9;
+ case gcc_r10: return gpr_r10;
+ case gcc_r11: return gpr_r11;
+ case gcc_r12: return gpr_r12;
+ case gcc_sp: return gpr_sp;
+ case gcc_lr: return gpr_lr;
+ case gcc_pc: return gpr_pc;
+ case gcc_cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((dbg.bcr[i] & BCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_breakpoints)
+ {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2)
+ {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+// else
+// {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+// }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.bcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.bvr[hw_index],
+// hw_index,
+// dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.wvr[hw_index],
+// hw_index,
+// dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 000000000000..0bf204f57c80
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,333 @@
+//===-- RegisterContextDarwin_arm.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_arm_h_
+#define liblldb_RegisterContextDarwin_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define BCR_ENABLE ((uint32_t)(1u))
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+
+// struct NeonReg
+// {
+// uint8_t bytes[16];
+// };
+//
+// struct VFPv3
+// {
+// union {
+// uint32_t s[32];
+// uint64_t d[32];
+// NeonReg q[16];
+// } v3;
+// uint32_t fpscr;
+// };
+
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 000000000000..a94d1f538a28
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,980 @@
+//===-- RegisterContextDarwin_i386.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_i386::~RegisterContextDarwin_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::FPU, reg) + sizeof (RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::EXC, reg) + sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU) + sizeof (RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ======================= =================== ========================= ================== ================= ========== ===============
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , gpr_eax }, NULL, NULL},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , gpr_ebx }, NULL, NULL},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx , gpr_ecx }, NULL, NULL},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx , gpr_edx }, NULL, NULL},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi , gpr_edi }, NULL, NULL},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi , gpr_esi }, NULL, NULL},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , gpr_ebp }, NULL, NULL},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , gpr_esp }, NULL, NULL},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ss , gpr_ss }, NULL, NULL},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , gpr_eflags }, NULL, NULL},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , gpr_eip }, NULL, NULL},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , gpr_ds }, NULL, NULL},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_es , gpr_es }, NULL, NULL},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask}, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_i386::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_i386::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_i386::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+
+void
+RegisterContextDarwin_i386::LogGPR(Log *log, const char *title)
+{
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&gpr.eax)[reg]);
+ }
+ }
+}
+
+
+
+int
+RegisterContextDarwin_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_i386::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ default: break;
+ }
+ }
+ return -1;
+}
+
+bool
+RegisterContextDarwin_i386::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_i386::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_eflags: return gpr_eflags;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fctrl : return fpu_fctrl;
+ case gdb_fstat : return fpu_fstat;
+ case gdb_ftag : return fpu_ftag;
+ case gdb_fiseg : return fpu_fiseg;
+ case gdb_fioff : return fpu_fioff;
+ case gdb_foseg : return fpu_foseg;
+ case gdb_fooff : return fpu_fooff;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextDarwin_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != 0)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ }
+ else
+ {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == 0;
+}
+
+
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 000000000000..a588494f9dcf
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,269 @@
+//===-- RegisterContextDarwin_i386.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_i386_h_
+#define liblldb_RegisterContextDarwin_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_i386();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 000000000000..433782fe20c0
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1066 @@
+//===-- RegisterContextDarwin_x86_64.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stdarg.h>
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7
+
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fctrl = 32, gdb_fpu_fcw = gdb_fpu_fctrl,
+ gdb_fpu_fstat = 33, gdb_fpu_fsw = gdb_fpu_fstat,
+ gdb_fpu_ftag = 34, gdb_fpu_ftw = gdb_fpu_ftag,
+ gdb_fpu_fiseg = 35, gdb_fpu_cs = gdb_fpu_fiseg,
+ gdb_fpu_fioff = 36, gdb_fpu_ip = gdb_fpu_fioff,
+ gdb_fpu_foseg = 37, gdb_fpu_ds = gdb_fpu_foseg,
+ gdb_fpu_fooff = 38, gdb_fpu_dp = gdb_fpu_fooff,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56
+};
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext (thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::FPU, reg) + sizeof (RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::EXC, reg) + sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU) + sizeof (RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ====================== =================== ========================== ==================== =================== ========== ===============
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax , gpr_rax }, NULL, NULL},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx , gpr_rbx }, NULL, NULL},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx , gpr_rcx }, NULL, NULL},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx , gpr_rdx }, NULL, NULL},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi , gpr_rdi }, NULL, NULL},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi , gpr_rsi }, NULL, NULL},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp , gpr_rbp }, NULL, NULL},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp , gpr_rsp }, NULL, NULL},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 , gpr_r8 }, NULL, NULL},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 , gpr_r9 }, NULL, NULL},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 , gpr_r10 }, NULL, NULL},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 , gpr_r11 }, NULL, NULL},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 , gpr_r12 }, NULL, NULL},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 , gpr_r13 }, NULL, NULL},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 , gpr_r14 }, NULL, NULL},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 , gpr_r15 }, NULL, NULL},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip , gpr_rip }, NULL, NULL},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags , gpr_rflags }, NULL, NULL},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask }, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+ { DEFINE_FPU_VECT(xmm,8) },
+ { DEFINE_FPU_VECT(xmm,9) },
+ { DEFINE_FPU_VECT(xmm,10) },
+ { DEFINE_FPU_VECT(xmm,11) },
+ { DEFINE_FPU_VECT(xmm,12) },
+ { DEFINE_FPU_VECT(xmm,13) },
+ { DEFINE_FPU_VECT(xmm,14) },
+ { DEFINE_FPU_VECT(xmm,15) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextDarwin_x86_64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+
+static uint32_t g_gpr_regnums[] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs
+};
+
+static uint32_t g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextDarwin_x86_64::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void
+RegisterContextDarwin_x86_64::LogGPR(Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_rax + i;
+ log->Printf("%12s = 0x%16.16" PRIx64, g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+int
+RegisterContextDarwin_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadRegisterSet(uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR (force);
+ case FPURegSet: return ReadFPU (force);
+ case EXCRegSet: return ReadEXC (force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_x86_64::WriteRegisterSet(uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR ();
+ case FPURegSet: return WriteFPU ();
+ case EXCRegSet: return WriteEXC ();
+ default: break;
+ }
+ return -1;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_gs; // HACK: For now for "ss", just copy what is in "gs"
+ case gdb_gpr_ds : return gpr_gs; // HACK: For now for "ds", just copy what is in "gs"
+ case gdb_gpr_es : return gpr_gs; // HACK: For now for "es", just copy what is in "gs"
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fctrl : return fpu_fctrl;
+ case gdb_fpu_fstat : return fpu_fstat;
+ case gdb_fpu_ftag : return fpu_ftag;
+ case gdb_fpu_fiseg : return fpu_fiseg;
+ case gdb_fpu_fioff : return fpu_fioff;
+ case gdb_fpu_foseg : return fpu_foseg;
+ case gdb_fpu_fooff : return fpu_fooff;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextDarwin_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != 0)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable)
+ {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ }
+ else
+ {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == 0;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 000000000000..4b8127af997c
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,274 @@
+//===-- RegisterContextDarwin_x86_64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_x86_64_h_
+#define liblldb_RegisterContextDarwin_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextDarwin_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_x86_64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ 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 rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 4,
+ FPURegSet = 5,
+ EXCRegSet = 6
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextDarwin_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 000000000000..1e282ce74f2e
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,137 @@
+//===-- RegisterContextDummy.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/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size) :
+RegisterContext (thread, concrete_frame_idx)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextDummy::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextDummy::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextDummy::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextDummy::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 000000000000..ee8d5a134bbc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextDummy.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextDummy_h_
+#define lldb_RegisterContextDummy_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextDummy ();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ 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);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextDummy);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextDummy_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 000000000000..1ffc30da5762
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,1541 @@
+//===-- RegisterContextLLDB.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/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextLLDB::RegisterContextLLDB
+(
+ Thread& thread,
+ const SharedPtr &next_frame,
+ SymbolContext& sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB& unwind_lldb
+) :
+ RegisterContext (thread, frame_number),
+ m_thread(thread),
+ m_fast_unwind_plan_sp (),
+ m_full_unwind_plan_sp (),
+ m_all_registers_available(false),
+ m_frame_type (-1),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_start_pc (),
+ m_current_pc (),
+ m_current_offset (0),
+ m_current_offset_backed_up_one (0),
+ m_sym_ctx(sym_ctx),
+ m_sym_ctx_valid (false),
+ m_frame_number (frame_number),
+ m_registers(),
+ m_parent_unwind (unwind_lldb)
+{
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero ())
+ {
+ InitializeZerothFrame ();
+ }
+ else
+ {
+ InitializeNonZerothFrame ();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
+ if (IsFrameZero()
+ || next_frame->m_frame_type == eSigtrampFrame
+ || next_frame->m_frame_type == eDebuggerFrame)
+ {
+ m_all_registers_available = true;
+ }
+}
+
+// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
+// executing frame.
+
+void
+RegisterContextLLDB::InitializeZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if (pc_module_sp.get()
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
+
+ static ConstString g_sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection())
+ {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ }
+ else if (m_current_pc.GetModule() == m_start_pc.GetModule())
+ {
+ // This means that whatever symbol we kicked up isn't really correct
+ // --- we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption
+ // here due to inlined functions?
+ m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ 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,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
+// to provide things like its current pc value.
+
+void
+RegisterContextLLDB::InitializeNonZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero ())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ if (!m_thread.GetRegisterContext())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ UnwindLogMsg ("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (log)
+ {
+ UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl
+ if (pc == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions)
+ && (permissions & ePermissionsExecutable) == 0)
+ {
+ // If this is the second frame off the stack, we may have unwound the first frame
+ // incorrectly. But using the architecture default unwind plan may get us back on
+ // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
+ // pc and see if we can get any further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
+ {
+ UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
+ (uint64_t) pc);
+ m_frame_type = eSkipFrame;
+ }
+ else
+ {
+ // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ if (abi)
+ {
+ m_fast_unwind_plan_sp.reset ();
+ m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ 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))
+ {
+ UnwindLogMsg ("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ return;
+ }
+ m_cfa = cfa_regval + cfa_offset;
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 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,
+ // see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(cfa_regval, permissions)
+ && (permissions & ePermissionsReadable) == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+ else
+ {
+ UnwindLogMsg ("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+
+ bool decr_pc_and_recompute_addr_range = false;
+
+ // If the symbol lookup failed...
+ if (m_sym_ctx_valid == false)
+ decr_pc_and_recompute_addr_range = true;
+
+ // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
+ // and our "current" pc is the start of a function...
+ if (m_sym_ctx_valid
+ && GetNextFrame()->m_frame_type != eSigtrampFrame
+ && GetNextFrame()->m_frame_type != eDebuggerFrame
+ && addr_range.GetBaseAddress().IsValid()
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+ {
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+ // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+ // 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);
+ m_sym_ctx_valid = false;
+ if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ 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_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);
+ }
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ static ConstString sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
+ || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
+ // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ 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 ("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)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // 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.
+ addr_t next_frame_cfa;
+ 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;
+ }
+ }
+ if (repeating_frames && abi->FunctionCallsChangeCFA())
+ {
+ 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::IsFrameZero () const
+{
+ return m_frame_number == 0;
+}
+
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFastUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ return unwind_plan_sp;
+
+ if (IsFrameZero ())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
+ if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
+ if (unwind_plan_sp)
+ {
+ if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose ("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ else
+ {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFullUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero ()
+ || GetNextFrame()->m_frame_type == eSigtrampFrame
+ || GetNextFrame()->m_frame_type == eDebuggerFrame)
+ {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
+ // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
+ // Also, if this Process can report on memory region attributes, any non-executable region means
+ // we jumped through a bad function pointer - handle the same way as 0x0.
+ // Note, if the symbol context has a function for the symbol, then we don't need to do this check.
+
+ if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ {
+ 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)
+ && (permissions & ePermissionsExecutable) == 0))
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid)
+ {
+ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
+ // Try using the eh_frame information relative to the current PC,
+ // and finally fall back on the architectural default unwind.
+ if (!func_unwinders_sp)
+ {
+ DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ?
+ pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
+
+ m_frame_type = eNormalFrame;
+ if (eh_frame && m_current_pc.IsValid())
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
+ if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
+ // 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 == eSigtrampFrame)
+ {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ return unwind_plan_sp;
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+ // This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
+ // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+ // right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+ // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+ // 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);
+ 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",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
+ if (behaves_like_zeroth_frame)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // 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 (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
+ // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that does the job.
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ return arch_default_unwind_plan_sp;
+}
+
+
+void
+RegisterContextLLDB::InvalidateAllRegisters ()
+{
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t
+RegisterContextLLDB::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextLLDB::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount ();
+}
+
+const RegisterSet *
+RegisterContextLLDB::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->ReadRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (ReadRegisterValueFromMemory(reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+bool
+RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->WriteRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (WriteRegisterValueToMemory (reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+
+bool
+RegisterContextLLDB::IsValid () const
+{
+ return m_frame_type != eNotAValidFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
+// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
+// user knows we're displaying bad data and we may have skipped one frame of their real program in the
+// process of getting back on track.
+
+bool
+RegisterContextLLDB::IsSkipFrame () const
+{
+ return m_frame_type == eSkipFrame;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
+{
+ // 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);
+ if (iterator != m_registers.end())
+ {
+ regloc = iterator->second;
+ UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
+ 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;
+
+ 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))
+ {
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc)
+ {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ if (m_full_unwind_plan_sp)
+ {
+ 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;
+
+ // 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)
+ {
+ 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);
+ }
+ else
+ {
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ if (unwindplan_registerkind == eRegisterKindGeneric)
+ UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
+ else
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
+ // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
+ // Handle this specially.
+
+ if (have_unwindplan_regloc == false
+ && row_register_rewritten_to_return_address_reg == true
+ && IsFrameZero()
+ && row_regnum != LLDB_INVALID_REGNUM)
+ {
+ uint32_t ra_regnum_in_lldb_reg_numbering;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
+ {
+ 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;
+ 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);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it defines a Return Address register)
+ // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has likely been misled.
+ // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
+ // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
+ // the stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
+ // 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
+ && unwindplan_regloc.IsInOtherRegister()
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
+ && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
+ && !m_all_registers_available)
+ {
+ UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ InvalidateFullUnwindPlan();
+
+ // Now re-fetch the pc value we're searching for
+ uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
+ 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))
+ {
+ have_unwindplan_regloc = true;
+ }
+ else
+ {
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (have_unwindplan_regloc == false)
+ {
+ // If a volatile register is being requested, we don't want to forward the next frame's register contents
+ // up the stack -- the register is not retrievable at this frame.
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ if (reg_info && abi->RegisterIsVolatile (reg_info))
+ {
+ UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+ }
+
+ if (IsFrameZero ())
+ {
+ // 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;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified())
+ {
+ 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);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsSame())
+ {
+ if (IsFrameZero ())
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ else
+ {
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset())
+ {
+ 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", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset())
+ {
+ 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", lldb_regnum);
+ 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))
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ 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);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
+ {
+ DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (unwindplan_registerkind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression())
+ {
+ 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);
+ 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);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+
+ // 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 unwindplna, 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.
+
+void
+RegisterContextLLDB::InvalidateFullUnwindPlan ()
+{
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ if (arch_default_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = arch_default_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())
+ {
+ func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ if (func_unwinders_sp)
+ {
+ func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
+ }
+ }
+ m_registers.clear();
+ m_full_unwind_plan_sp = arch_default_unwind_plan_sp;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+ {
+ m_cfa = cfa_regval + active_row->GetCFAOffset ();
+ }
+
+ 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(), arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ }
+ }
+ }
+}
+
+// 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.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool
+RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
+{
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB)
+ {
+ lldb_regnum = regnum;
+ }
+ else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
+ {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
+ if (IsFrameZero ())
+ {
+ if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+ else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
+ && generic_regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
+ {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+// Find the value of a register in THIS frame
+
+bool
+RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
+}
+
+bool
+RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
+{
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool
+RegisterContextLLDB::GetCFA (addr_t& cfa)
+{
+ if (!IsValid())
+ {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetNextFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
+}
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetPrevFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool
+RegisterContextLLDB::GetStartPC (addr_t& start_pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid())
+ {
+ return ReadPC (start_pc);
+ }
+ start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool
+RegisterContextLLDB::ReadPC (addr_t& pc)
+{
+ if (!IsValid())
+ return false;
+
+ 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.
+ // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
+ // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
+ // find the bug.
+
+ if (m_all_registers_available == false
+ && (pc == 0 || pc == 1))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void
+RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+void
+RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
new file mode 100644
index 000000000000..dc6d8c61fa4a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -0,0 +1,212 @@
+//===-- RegisterContextLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextLLDB_h_
+#define lldb_RegisterContextLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "UnwindLLDB.h"
+
+namespace lldb_private {
+
+class UnwindLLDB;
+
+class RegisterContextLLDB : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;
+
+ RegisterContextLLDB (lldb_private::Thread &thread,
+ const SharedPtr& next_frame,
+ lldb_private::SymbolContext& sym_ctx,
+ uint32_t frame_number, lldb_private::UnwindLLDB& unwind_lldb);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextLLDB () { }
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ 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);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ bool
+ IsValid () const;
+
+ bool
+ GetCFA (lldb::addr_t& cfa);
+
+ bool
+ GetStartPC (lldb::addr_t& start_pc);
+
+ bool
+ ReadPC (lldb::addr_t& start_pc);
+
+private:
+
+ enum FrameType
+ {
+ eNormalFrame,
+ eSigtrampFrame,
+ eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
+ eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
+ eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
+ };
+
+ // UnwindLLDB needs to pass around references to RegisterLocations
+ friend class UnwindLLDB;
+
+ // Indicates whether this frame is frame zero -- the currently
+ // executing frame -- or not.
+ bool
+ IsFrameZero () const;
+
+ void
+ InitializeZerothFrame ();
+
+ void
+ InitializeNonZerothFrame();
+
+ SharedPtr
+ GetNextFrame () const;
+
+ SharedPtr
+ GetPrevFrame () const;
+
+ // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've got one bogus frame at frame #1.
+ // There is a good chance we'll get back on track if we follow the frame pointer chain (or whatever is appropriate
+ // on this ABI) so we allow one invalid frame to be in the stack. Ideally we'll mark this frame specially at some
+ // point and indicate to the user that the unwinder had a hiccup. Often when this happens we will miss a frame of
+ // the program's actual stack in the unwind and we want to flag that for the user somehow.
+ bool
+ IsSkipFrame () const;
+
+ // Provide a location for where THIS function saved the CALLER's register value
+ // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
+ // function didn't modify/use.
+ //
+ // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register
+ // being queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may
+ // or may not be the value of that reg when the function was executing), we won't return any value.
+ //
+ // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested
+ // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same
+ // as the requesting frame's.
+ lldb_private::UnwindLLDB::RegisterSearchResult
+ SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc);
+
+ bool
+ ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ void
+ InvalidateFullUnwindPlan ();
+
+ // Get the contents of a general purpose (address-size) register for this frame
+ // (usually retrieved from the next frame)
+ bool
+ ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value);
+
+ lldb::UnwindPlanSP
+ GetFastUnwindPlanForFrame ();
+
+ lldb::UnwindPlanSP
+ GetFullUnwindPlanForFrame ();
+
+ void
+ UnwindLogMsg (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ lldb_private::Thread& m_thread;
+
+ ///
+ // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above)
+ // i.e. where THIS frame saved them
+ ///
+
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
+ int m_frame_type; // enum FrameType
+
+ lldb::addr_t m_cfa;
+ lldb_private::Address m_start_pc;
+ lldb_private::Address m_current_pc;
+
+ int m_current_offset; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+
+ int m_current_offset_backed_up_one; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+ // On architectures where the return address on the stack points
+ // to the instruction after the CALL, this value will have 1
+ // subtracted from it. Else a function that ends in a CALL will
+ // have an offset pointing into the next function's address range.
+ // m_current_pc has the actual address of the "current" pc.
+
+ lldb_private::SymbolContext& m_sym_ctx;
+ bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to use m_sym_ctx
+
+ uint32_t m_frame_number; // What stack frame this RegisterContext is
+
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> m_registers; // where to find reg values for this frame
+
+ lldb_private::UnwindLLDB& m_parent_unwind; // The UnwindLLDB that is creating this RegisterContextLLDB
+
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextLLDB_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..2c3eee452488
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,206 @@
+//===-- RegisterContextMacOSXFrameBackchain.cpp -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ switch (reg_info->kinds[eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ if (m_cursor.pc == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ case LLDB_REGNUM_GENERIC_FP:
+ if (m_cursor.fp == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.fp;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ case eEncodingVector:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ value.SetUInt(reg_value, reg_info->byte_size);
+ return true;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ break;
+
+ // TOOD: need a better way to detect when "long double" types are
+ // the same bytes size as "double"
+#if !defined(__arm__)
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ break;
+#endif
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..449e053e5ef1
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextMacOSXFrameBackchain.h -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMacOSXFrameBackchain_h_
+#define lldb_RegisterContextMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindMacOSXFrameBackchain.h"
+
+class RegisterContextMacOSXFrameBackchain : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMacOSXFrameBackchain (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ 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);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ UnwindMacOSXFrameBackchain::Cursor m_cursor;
+ bool m_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For RegisterContextMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMacOSXFrameBackchain);
+};
+
+#endif // lldb_RegisterContextMacOSXFrameBackchain_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 000000000000..7ceb536272f4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+int
+RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int
+RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 000000000000..e97a4bfff2b6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,56 @@
+//===-- RegisterContextMach_arm.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_arm_h_
+#define liblldb_RegisterContextMach_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 000000000000..3d6c9a6baca6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_i386.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+int
+RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 000000000000..ad0f69d1c052
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_i386.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_i386_h_
+#define liblldb_RegisterContextMach_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 000000000000..f03685e1313f
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_x86_64.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+int
+RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 000000000000..9e6dfa395500
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_x86_64.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_RegisterContextMach_x86_64_h_
+#define liblldb_RegisterContextMach_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 000000000000..8c33a6814acc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,174 @@
+//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DynamicRegisterInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMemory constructor
+//----------------------------------------------------------------------
+RegisterContextMemory::RegisterContextMemory
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_infos (reg_infos),
+ m_reg_valid (),
+ m_reg_data (),
+ m_reg_data_addr (reg_data_addr)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert (num_regs > 0);
+ m_reg_valid.resize (num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_infos.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMemory::~RegisterContextMemory()
+{
+}
+
+void
+RegisterContextMemory::InvalidateAllRegisters ()
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid (false);
+}
+
+void
+RegisterContextMemory::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+RegisterContextMemory::GetRegisterCount ()
+{
+ return m_reg_infos.GetNumRegisters ();
+}
+
+const RegisterInfo *
+RegisterContextMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_infos.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextMemory::GetRegisterSetCount ()
+{
+ return m_reg_infos.GetNumRegisterSets ();
+}
+
+const RegisterSet *
+RegisterContextMemory::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_infos.GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num])
+ {
+ if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer ()))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok).Success();
+}
+
+bool
+RegisterContextMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Error error (WriteRegisterValueToMemory(reg_info, reg_addr, reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::ReadAllRegisterValues (DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ {
+ SetAllRegisterValid (true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::WriteAllRegisterValues (const DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ SetAllRegisterValid (false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+RegisterContextMemory::SetAllRegisterData (const lldb::DataBufferSP &data_sp)
+{
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid (true);
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 000000000000..8bba52c627f3
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextMemory.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMemory_h_
+#define lldb_RegisterContextMemory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+class DynamicRegisterInfo;
+
+class RegisterContextMemory : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMemory (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ virtual
+ ~RegisterContextMemory ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+
+ //------------------------------------------------------------------
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+ //------------------------------------------------------------------
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ void
+ SetAllRegisterData (const lldb::DataBufferSP &data_sp);
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register context that is stored in memmory
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMemory);
+};
+
+#endif // lldb_RegisterContextMemory_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 000000000000..d35a5d095705
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,261 @@
+//===-- RegisterContextThreadMemory.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/Core/Error.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr) :
+ RegisterContext (thread, 0),
+ m_thread_wp (thread.shared_from_this()),
+ m_reg_ctx_sp (),
+ m_register_data_addr (register_data_addr),
+ m_stop_id(0)
+{
+}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory()
+{
+}
+
+void
+RegisterContextThreadMemory::UpdateRegisterContext ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->GetProcess());
+
+ if (process_sp)
+ {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id)
+ {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp)
+ {
+ ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
+ if (backing_thread_sp)
+ {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ }
+ else
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os->IsOperatingSystemPluginThread (thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+//------------------------------------------------------------------
+// Subclasses must override these functions
+//------------------------------------------------------------------
+void
+RegisterContextThreadMemory::InvalidateAllRegisters ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return NULL;
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterSetCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *
+RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return NULL;
+}
+
+bool
+RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::HardwareSingleStep (bool enable)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Error
+RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Error
+RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 000000000000..8d7a4b622fe8
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,114 @@
+//===-- RegisterContextThreadMemory.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextThreadMemory_h_
+#define lldb_RegisterContextThreadMemory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr);
+
+ virtual ~RegisterContextThreadMemory();
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value);
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+protected:
+ void
+ UpdateRegisterContext ();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+private:
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 000000000000..51d2052e1931
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,482 @@
+//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+StopInfoMachException::GetDescription ()
+{
+ if (m_description.empty() && m_value != 0)
+ {
+ ExecutionContext exe_ctx (m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = NULL;
+ const char *code_label = "code";
+ const char *code_desc = NULL;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = NULL;
+ switch (m_value)
+ {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 0xd: code_desc = "EXC_I386_GPFLT"; m_exc_data_count = 1; break;
+ }
+ break;
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
+ case 0x102: code_desc = "EXC_PPC_BADSPACE"; break;
+ case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
+ case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
+ case 3: code_desc = "EXC_PPC_PRIVINST"; break;
+ case 4: code_desc = "EXC_PPC_PRIVREG"; break;
+ case 5: code_desc = "EXC_PPC_TRACE"; break;
+ case 6: code_desc = "EXC_PPC_PERFMON"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_DIV"; break;
+ case 2: code_desc = "EXC_I386_INTO"; break;
+ case 3: code_desc = "EXC_I386_NOEXT"; break;
+ case 4: code_desc = "EXC_I386_EXTOVR"; break;
+ case 5: code_desc = "EXC_I386_EXTERR"; break;
+ case 6: code_desc = "EXC_I386_EMERR"; break;
+ case 7: code_desc = "EXC_I386_BOUND"; break;
+ case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
+ case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
+ case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
+ case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
+ case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
+ case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
+ case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003)
+ {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_SGL"; break;
+ case 2: code_desc = "EXC_I386_BPT"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ // FIXME temporary workaround, exc_code 0 does not really mean EXC_ARM_BREAKPOINT
+ case 0: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1)
+ {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2)
+ {
+ if (subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+}
+
+
+
+
+
+StopInfoSP
+StopInfoMachException::CreateStopReasonWithMachException
+(
+ Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted,
+ bool adjust_pc_if_needed
+)
+{
+ if (exc_type != 0)
+ {
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ switch (exc_type)
+ {
+ case 1: // EXC_BAD_ACCESS
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ switch (cpu)
+ {
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (exc_code)
+ {
+ case 1: // EXC_PPC_INVALID_SYSCALL
+ case 2: // EXC_PPC_UNIPL_INST
+ case 3: // EXC_PPC_PRIVINST
+ case 4: // EXC_PPC_PRIVREG
+ break;
+ case 5: // EXC_PPC_TRACE
+ return StopInfo::CreateStopReasonToTrace (thread);
+ case 6: // EXC_PPC_PERFMON
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5)
+ {
+ // On MacOSX, a SIGTRAP can signify that a process has called
+ // exec, so we should check with our dynamic loader to verify.
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec())
+ {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec (thread);
+ }
+// if (!process_did_exec)
+// {
+// // We have a SIGTRAP, make sure we didn't exec by checking
+// // for the PC being at "_dyld_start"...
+// lldb::StackFrameSP frame_sp (thread.GetStackFrameAtIndex(0));
+// if (frame_sp)
+// {
+// const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+// if (symbol)
+// {
+// if (symbol->GetName() == ConstString("_dyld_start"))
+// process_did_exec = true;
+// }
+// }
+// }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code)
+ return StopInfo::CreateStopReasonToTrace(thread);
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ }
+ else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
+ break;
+
+ case llvm::Triple::arm:
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel is currently returning this so accept it as indicating a breakpoint until the kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint)
+ {
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp (thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Update the PC if we were asked to do so, but only do
+ // so if we find a breakpoint that we know about cause
+ // this could be a trap instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC (pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (&thread))
+ return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
+ {
+ return StopInfo::CreateStopReasonToTrace (thread);
+ }
+ }
+ }
+ break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
+ }
+ return StopInfoSP();
+}
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.h b/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 000000000000..130ee0b709b0
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,77 @@
+//===-- StopInfoMachException.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_StopInfoMachException_h_
+#define liblldb_StopInfoMachException_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfoMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_subcode) :
+ StopInfo (thread, exc_type),
+ m_exc_data_count (exc_data_count),
+ m_exc_code (exc_code),
+ m_exc_subcode (exc_subcode)
+ {
+ }
+
+ virtual ~StopInfoMachException()
+ {
+ }
+
+
+ virtual lldb::StopReason
+ GetStopReason () const
+ {
+ return lldb::eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ();
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP
+ CreateStopReasonWithMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true,
+ bool adjust_pc_if_needed = false);
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfoMachException_h_
diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 000000000000..56e5a9a59fab
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,140 @@
+//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory (Process &process,
+ tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (thread_info_valobj_sp),
+ m_name(),
+ m_queue()
+{
+}
+
+
+ThreadMemory::ThreadMemory (Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (),
+ m_name(),
+ m_queue(),
+ m_register_data_addr (register_data_addr)
+{
+ if (name)
+ m_name = name;
+ if (queue)
+ m_queue = queue;
+}
+
+
+ThreadMemory::~ThreadMemory()
+{
+ DestroyThread();
+}
+
+void
+ThreadMemory::WillResume (StateType resume_state)
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void
+ThreadMemory::ClearStackFrames ()
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadMemory::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr));
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ reg_ctx_sp = GetRegisterContext ();
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMemory::CalculateStopInfo ()
+{
+ if (m_backing_thread_sp)
+ {
+ lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp)
+ {
+ backing_stop_info_sp->SetThread (shared_from_this());
+ SetStopInfo (backing_stop_info_sp);
+ return true;
+ }
+ }
+ else
+ {
+ ProcessSP process_sp (GetProcess());
+
+ if (process_sp)
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os)
+ {
+ SetStopInfo (os->CreateThreadStopReason (this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+ThreadMemory::RefreshStateAfterStop()
+{
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/source/Plugins/Process/Utility/ThreadMemory.h b/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 000000000000..07eb45dcb431
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,152 @@
+//===-- ThreadMemory.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_ThreadMemory_h_
+#define liblldb_ThreadMemory_h_
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory :
+ public lldb_private::Thread
+{
+public:
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const lldb::ValueObjectSP &thread_info_valobj_sp);
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr);
+
+ virtual
+ ~ThreadMemory();
+
+ //------------------------------------------------------------------
+ // lldb_private::Thread methods
+ //------------------------------------------------------------------
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ CalculateStopInfo ();
+
+ virtual const char *
+ GetInfo ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetInfo();
+ return NULL;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (!m_name.empty())
+ return m_name.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetName();
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ if (!m_queue.empty())
+ return m_queue.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetQueueName();
+ return NULL;
+ }
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->DidResume();
+ }
+
+ virtual lldb::user_id_t
+ GetProtocolID () const
+ {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->GetProtocolID();
+ return Thread::GetProtocolID();
+ }
+
+ virtual void
+ RefreshStateAfterStop();
+
+ lldb::ValueObjectSP &
+ GetValueObject ()
+ {
+ return m_thread_info_valobj_sp;
+ }
+
+ virtual void
+ ClearStackFrames ();
+
+ virtual void
+ ClearBackingThread ()
+ {
+ m_backing_thread_sp.reset();
+ }
+
+ virtual bool
+ SetBackingThread (const lldb::ThreadSP &thread_sp)
+ {
+ //printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(), thread_sp->GetID());
+ m_backing_thread_sp = thread_sp;
+ return (bool)thread_sp;
+ }
+
+ virtual lldb::ThreadSP
+ GetBackingThread () const
+ {
+ return m_backing_thread_sp;
+ }
+
+protected:
+
+ virtual bool
+ IsOperatingSystemPluginThread () const
+ {
+ return true;
+ }
+
+
+ //------------------------------------------------------------------
+ // For ThreadMemory and subclasses
+ //------------------------------------------------------------------
+ // If this memory thread is actually represented by a thread from the
+ // lldb_private::Process subclass, then fill in the thread here and
+ // all APIs will be routed through this thread object. If m_backing_thread_sp
+ // is empty, then this thread is simply in memory with no representation
+ // through the process plug-in.
+ lldb::ThreadSP m_backing_thread_sp;
+ lldb::ValueObjectSP m_thread_info_valobj_sp;
+ std::string m_name;
+ std::string m_queue;
+ lldb::addr_t m_register_data_addr;
+private:
+ //------------------------------------------------------------------
+ // For ThreadMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadMemory);
+};
+
+#endif // liblldb_ThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
new file mode 100644
index 000000000000..0eea00363498
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -0,0 +1,322 @@
+//===-- UnwindLLDB.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/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindLLDB.h"
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLLDB::UnwindLLDB (Thread &thread) :
+ Unwind (thread),
+ m_frames(),
+ m_unwind_complete(false)
+{
+}
+
+uint32_t
+UnwindLLDB::DoGetFrameCount()
+{
+ if (!m_unwind_complete)
+ {
+//#define DEBUG_FRAME_SPEED 1
+#if DEBUG_FRAME_SPEED
+#define FRAME_COUNT 10000
+ TimeValue time_value (TimeValue::Now());
+#endif
+ if (!AddFirstFrame ())
+ return 0;
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (AddOneMoreFrame (abi))
+ {
+#if DEBUG_FRAME_SPEED
+ if ((m_frames.size() % FRAME_COUNT) == 0)
+ {
+ TimeValue now(TimeValue::Now());
+ uint64_t delta_t = now - time_value;
+ printf ("%u frames in %" PRIu64 ".%09llu ms (%g frames/sec)\n",
+ FRAME_COUNT,
+ delta_t / TimeValue::NanoSecPerSec,
+ delta_t % TimeValue::NanoSecPerSec,
+ (float)FRAME_COUNT / ((float)delta_t / (float)TimeValue::NanoSecPerSec));
+ time_value = now;
+ }
+#endif
+ }
+ }
+ return m_frames.size ();
+}
+
+bool
+UnwindLLDB::AddFirstFrame ()
+{
+ if (m_frames.size() > 0)
+ return true;
+
+ // First, set up the 0th (initial) frame
+ CursorSP first_cursor_sp(new Cursor ());
+ RegisterContextLLDBSP reg_ctx_sp (new RegisterContextLLDB (m_thread,
+ RegisterContextLLDBSP(),
+ first_cursor_sp->sctx,
+ 0, *this));
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ goto unwind_done;
+
+ if (!reg_ctx_sp->GetCFA (first_cursor_sp->cfa))
+ goto unwind_done;
+
+ if (!reg_ctx_sp->ReadPC (first_cursor_sp->start_pc))
+ goto unwind_done;
+
+ // Everything checks out, so release the auto pointer value and let the
+ // cursor own it in its shared pointer
+ first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (first_cursor_sp);
+ return true;
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+// For adding a non-zero stack frame to m_frames.
+bool
+UnwindLLDB::AddOneMoreFrame (ABI *abi)
+{
+ // If we've already gotten to the end of the stack, don't bother to try again...
+ if (m_unwind_complete)
+ return false;
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ CursorSP cursor_sp(new Cursor ());
+
+ // Frame zero is a little different
+ if (m_frames.size() == 0)
+ return false;
+
+ uint32_t cur_idx = m_frames.size ();
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread,
+ m_frames[cur_idx - 1]->reg_ctx_lldb_sp,
+ cursor_sp->sctx,
+ cur_idx,
+ *this));
+
+ // We want to detect an unwind that cycles erronously and stop backtracing.
+ // Don't want this maximum unwind limit to be too low -- if you have a backtrace
+ // with an "infinitely recursing" bug, it will crash when the stack blows out
+ // and the first 35,000 frames are uninteresting - it's the top most 5 frames that
+ // you actually care about. So you can't just cap the unwind at 10,000 or something.
+ // Realistically anything over around 200,000 is going to blow out the stack space.
+ // If we're still unwinding at that point, we're probably never going to finish.
+ if (cur_idx > 300000)
+ {
+ if (log)
+ log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ goto unwind_done;
+ }
+
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))
+ {
+ 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 (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!m_frames.empty())
+ {
+ if (m_frames.back()->start_pc == cursor_sp->start_pc)
+ {
+ if (m_frames.back()->cfa == cursor_sp->cfa)
+ goto unwind_done; // Infinite loop where the current cursor is the same as the previous one...
+ else if (abi && abi->StackUsesFrames())
+ {
+ // We might have a CFA that is not using the frame pointer and
+ // we want to validate that the frame pointer is valid.
+ if (reg_ctx_sp->GetFP() == 0)
+ goto unwind_done;
+ }
+ }
+ }
+ cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (cursor_sp);
+ return true;
+
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+bool
+UnwindLLDB::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return false;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size() && AddOneMoreFrame (abi))
+ ;
+
+ if (idx < m_frames.size ())
+ {
+ cfa = m_frames[idx]->cfa;
+ pc = m_frames[idx]->start_pc;
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindLLDB::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t idx = frame->GetConcreteFrameIndex ();
+
+ if (idx == 0)
+ {
+ return m_thread.GetRegisterContext();
+ }
+
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return reg_ctx_sp;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size())
+ {
+ if (!AddOneMoreFrame (abi))
+ break;
+ }
+
+ const uint32_t num_frames = m_frames.size();
+ if (idx < num_frames)
+ {
+ Cursor *frame_cursor = m_frames[idx].get();
+ reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp;
+ }
+ return reg_ctx_sp;
+}
+
+UnwindLLDB::RegisterContextLLDBSP
+UnwindLLDB::GetRegisterContextForFrameNum (uint32_t frame_num)
+{
+ RegisterContextLLDBSP reg_ctx_sp;
+ if (frame_num < m_frames.size())
+ reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp;
+ return reg_ctx_sp;
+}
+
+bool
+UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_reg)
+{
+ int64_t frame_num = starting_frame_num;
+ if (frame_num >= m_frames.size())
+ return false;
+
+ // Never interrogate more than one level while looking for the saved pc value. If the value
+ // isn't saved by frame_num, none of the frames lower on the stack will have a useful value.
+ if (pc_reg)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ else
+ return false;
+ }
+ while (frame_num >= 0)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+
+ // 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
+ // down the stack, or an actual value from a live RegisterContext at frame 0.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister
+ && frame_num > 0)
+ {
+ result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ lldb_regnum = regloc.location.register_number;
+ }
+
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile)
+ return false;
+ frame_num--;
+ }
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h
new file mode 100644
index 000000000000..5725654a6869
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -0,0 +1,125 @@
+//===-- UnwindLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindLLDB_h_
+#define lldb_UnwindLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-public.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+
+namespace lldb_private {
+
+class RegisterContextLLDB;
+
+class UnwindLLDB : public lldb_private::Unwind
+{
+public:
+ UnwindLLDB (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindLLDB() { }
+
+ enum RegisterSearchResult
+ {
+ eRegisterFound = 0,
+ eRegisterNotFound,
+ eRegisterIsVolatile
+ };
+
+protected:
+ friend class lldb_private::RegisterContextLLDB;
+
+ struct RegisterLocation {
+ enum RegisterLocationTypes
+ {
+ eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable
+ 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)
+ };
+ int type;
+ union
+ {
+ lldb::addr_t target_memory_location;
+ uint32_t register_number; // in eRegisterKindLLDB register numbering system
+ void* host_memory_location;
+ uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset
+ } location;
+ };
+
+ void
+ DoClear()
+ {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& start_pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP;
+
+ // Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame 1's RegisterContextLLDB)
+ // The RegisterContext for frame_num must already exist or this returns an empty shared pointer.
+ RegisterContextLLDBSP
+ GetRegisterContextForFrameNum (uint32_t frame_num);
+
+ // Iterate over the RegisterContextLLDB's in our m_frames vector, look for the first one that
+ // has a saved location for this reg.
+ bool
+ SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_register);
+
+
+private:
+
+ struct Cursor
+ {
+ lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown
+ lldb::addr_t cfa; // The canonical frame address for this stack frame
+ lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation
+ RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextLLDB's
+
+ Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx_lldb_sp() { }
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Cursor);
+ };
+
+ typedef std::shared_ptr<Cursor> CursorSP;
+ std::vector<CursorSP> m_frames;
+ bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the
+ // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
+ // is how far we've currently gone.
+
+
+ bool AddOneMoreFrame (ABI *abi);
+ bool AddFirstFrame ();
+
+ //------------------------------------------------------------------
+ // For UnwindLLDB only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_UnwindLLDB_h_
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..d011314b0963
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,275 @@
+//===-- UnwindMacOSXFrameBackchain.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/Core/ArchSpec.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::DoGetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const ArchSpec& target_arch = target->GetArchitecture ();
+ // Frame zero should always be supplied by the thread...
+ exe_ctx.SetFrameSP (m_thread.GetStackFrameAtIndex (0));
+
+ if (target_arch.GetAddressByteSize() == 8)
+ GetStackFrameData_x86_64 (exe_ctx);
+ else
+ GetStackFrameData_i386 (exe_ctx);
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
+ return false;
+ if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
+ return false;
+
+ pc = m_cursors[idx].pc;
+ cfa = m_cursors[idx].fp;
+
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
+ const uint32_t frame_count = GetFrameCount();
+ if (concrete_idx < frame_count)
+ reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
+ return reg_ctx_sp;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };
+
+ m_cursors.push_back(cursor);
+
+ const size_t k_frame_size = sizeof(frame);
+ Error error;
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (8 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+// uint32_t i=0;
+// printf(" PC FP\n");
+// printf(" ------------------ ------------------ \n");
+// for (i=0; i<m_cursors.size(); ++i)
+// {
+// printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_x86_64 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+ Error error;
+ const size_t k_frame_size = sizeof(frame);
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (16 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return m_cursors.size();
+}
+
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..2695376fd6e0
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,74 @@
+//===-- UnwindMacOSXFrameBackchain.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindMacOSXFrameBackchain_h_
+#define lldb_UnwindMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindMacOSXFrameBackchain : public lldb_private::Unwind
+{
+public:
+ UnwindMacOSXFrameBackchain (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindMacOSXFrameBackchain()
+ {
+ }
+
+protected:
+ virtual void
+ DoClear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ struct Cursor
+ {
+ lldb::addr_t pc; // Program counter
+ lldb::addr_t fp; // Frame pointer for us with backchain
+ };
+
+private:
+ std::vector<Cursor> m_cursors;
+
+ size_t
+ GetStackFrameData_i386 (const lldb_private::ExecutionContext &exe_ctx);
+
+ size_t
+ GetStackFrameData_x86_64 (const lldb_private::ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
new file mode 100644
index 000000000000..dd553ce36c89
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -0,0 +1,619 @@
+//===-- ProcessElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdlib.h>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "ProcessPOSIXLog.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+
+// Project includes
+#include "ProcessElfCore.h"
+#include "ThreadElfCore.h"
+
+using namespace lldb_private;
+
+ConstString
+ProcessElfCore::GetPluginNameStatic()
+{
+ static ConstString g_name("elf-core");
+ return g_name;
+}
+
+const char *
+ProcessElfCore::GetPluginDescriptionStatic()
+{
+ return "ELF core dump plug-in.";
+}
+
+void
+ProcessElfCore::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessElfCore::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file)
+ process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+ return process_sp;
+}
+
+bool
+ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ if (!m_core_module_sp && m_core_file.Exists())
+ {
+ ModuleSpec core_module_spec(m_core_file, target.GetArchitecture());
+ Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp,
+ NULL, NULL, NULL));
+ if (m_core_module_sp)
+ {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessElfCore constructor
+//----------------------------------------------------------------------
+ProcessElfCore::ProcessElfCore(Target& target, Listener &listener,
+ const FileSpec &core_file) :
+ Process (target, listener),
+ m_core_module_sp (),
+ m_core_file (core_file),
+ m_dyld_plugin_name (),
+ m_thread_data_valid(false),
+ m_thread_data(),
+ m_core_aranges ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessElfCore::~ProcessElfCore()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessElfCore::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessElfCore::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::addr_t
+ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header)
+{
+ lldb::addr_t addr = header->p_vaddr;
+ FileRange file_range (header->p_offset, header->p_filesz);
+ VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range);
+
+ VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+ if (last_entry &&
+ last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+ last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase())
+ {
+ last_entry->SetRangeEnd (range_entry.GetRangeEnd());
+ last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd());
+ }
+ else
+ {
+ m_core_aranges.Append(range_entry);
+ }
+
+ return addr;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessElfCore::DoLoadCore ()
+{
+ Error error;
+ if (!m_core_module_sp)
+ {
+ error.SetErrorString ("invalid core module");
+ return error;
+ }
+
+ ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ if (core == NULL)
+ {
+ error.SetErrorString ("invalid core object file");
+ return error;
+ }
+
+ const uint32_t num_segments = core->GetProgramHeaderCount();
+ if (num_segments == 0)
+ {
+ error.SetErrorString ("core file has no sections");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ m_thread_data_valid = true;
+
+ bool ranges_are_sorted = true;
+ lldb::addr_t vm_addr = 0;
+ /// Walk through segments and Thread and Address Map information.
+ /// PT_NOTE - Contains Thread and Register information
+ /// PT_LOAD - Contains a contiguous range of Process Address Space
+ for(uint32_t i = 1; i <= num_segments; i++)
+ {
+ const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i);
+ assert(header != NULL);
+
+ DataExtractor data = core->GetSegmentDataByIndex(i);
+
+ // Parse thread contexts and auxv structure
+ if (header->p_type == llvm::ELF::PT_NOTE)
+ ParseThreadContextsFromNoteSegment(header, data);
+
+ // PT_LOAD segments contains address map
+ if (header->p_type == llvm::ELF::PT_LOAD)
+ {
+ lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header);
+ if (vm_addr > last_addr)
+ ranges_are_sorted = false;
+ vm_addr = last_addr;
+ }
+ }
+
+ if (!ranges_are_sorted)
+ m_core_aranges.Sort();
+
+ // Even if the architecture is set in the target, we need to override
+ // it to match the core file which is always single arch.
+ ArchSpec arch (m_core_module_sp->GetArchitecture());
+ if (arch.IsValid())
+ m_target.SetArchitecture(arch);
+
+ return error;
+}
+
+lldb_private::DynamicLoader *
+ProcessElfCore::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic().GetCString()));
+ return m_dyld_ap.get();
+}
+
+bool
+ProcessElfCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ const uint32_t num_threads = GetNumThreadContexts ();
+ if (!m_thread_data_valid)
+ return false;
+
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid)
+ {
+ const ThreadData &td = m_thread_data[tid];
+ lldb::ThreadSP thread_sp(new ThreadElfCore (*this, tid, td));
+ new_thread_list.AddThread (thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessElfCore::RefreshStateAfterStop ()
+{
+}
+
+Error
+ProcessElfCore::DoDestroy ()
+{
+ return Error();
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessElfCore::IsAlive ()
+{
+ return true;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessElfCore::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since in core files we have it all cached our our core file anyway.
+ return DoReadMemory (addr, buf, size, error);
+}
+
+size_t
+ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile == NULL)
+ return 0;
+
+ // Get the address range
+ const VMRangeToFileOffset::Entry *address_range = m_core_aranges.FindEntryThatContains (addr);
+ if (address_range == NULL || address_range->GetRangeEnd() < addr)
+ {
+ error.SetErrorStringWithFormat ("core file does not contain 0x%" PRIx64, addr);
+ return 0;
+ }
+
+ // Convert the address into core file offset
+ const lldb::addr_t offset = addr - address_range->GetRangeBase();
+ const lldb::addr_t file_start = address_range->data.GetRangeBase();
+ const lldb::addr_t file_end = address_range->data.GetRangeEnd();
+ size_t bytes_to_read = size; // Number of bytes to read from the core file
+ size_t bytes_copied = 0; // Number of bytes actually read from the core file
+ size_t zero_fill_size = 0; // Padding
+ lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address
+
+ if (file_end > offset)
+ bytes_left = file_end - offset;
+
+ if (bytes_to_read > bytes_left)
+ {
+ zero_fill_size = bytes_to_read - bytes_left;
+ bytes_to_read = bytes_left;
+ }
+
+ // If there is data available on the core file read it
+ if (bytes_to_read)
+ bytes_copied = core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
+
+ assert(zero_fill_size <= size);
+ // Pad remaining bytes
+ if (zero_fill_size)
+ memset(((char *)buf) + bytes_copied, 0, zero_fill_size);
+
+ return bytes_copied + zero_fill_size;
+}
+
+void
+ProcessElfCore::Clear()
+{
+ m_thread_list.Clear();
+}
+
+void
+ProcessElfCore::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance);
+ }
+}
+
+lldb::addr_t
+ProcessElfCore::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress();
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+}
+
+/// Core files PT_NOTE segment descriptor types
+enum {
+ NT_PRSTATUS = 1,
+ NT_FPREGSET,
+ NT_PRPSINFO,
+ NT_TASKSTRUCT,
+ NT_PLATFORM,
+ NT_AUXV
+};
+
+enum {
+ NT_FREEBSD_PRSTATUS = 1,
+ NT_FREEBSD_FPREGSET,
+ NT_FREEBSD_PRPSINFO,
+ NT_FREEBSD_THRMISC = 7,
+ NT_FREEBSD_PROCSTAT_AUXV = 16
+};
+
+/// Align the given value to next boundary specified by the alignment bytes
+static uint32_t
+AlignToNext(uint32_t value, int alignment_bytes)
+{
+ return (value + alignment_bytes - 1) & ~(alignment_bytes - 1);
+}
+
+/// Note Structure found in ELF core dumps.
+/// This is PT_NOTE type program/segments in the core file.
+struct ELFNote
+{
+ elf::elf_word n_namesz;
+ elf::elf_word n_descsz;
+ elf::elf_word n_type;
+
+ std::string n_name;
+
+ ELFNote() : n_namesz(0), n_descsz(0), n_type(0)
+ {
+ }
+
+ /// Parse an ELFNote entry from the given DataExtractor starting at position
+ /// \p offset.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRel entry was successfully read and false otherwise.
+ bool
+ Parse(const DataExtractor &data, lldb::offset_t *offset)
+ {
+ // Read all fields.
+ if (data.GetU32(offset, &n_namesz, 3) == NULL)
+ return false;
+
+ // The name field is required to be nul-terminated, and n_namesz
+ // includes the terminating nul in observed implementations (contrary
+ // to the ELF-64 spec). A special case is needed for cores generated
+ // by some older Linux versions, which write a note named "CORE"
+ // without a nul terminator and n_namesz = 4.
+ if (n_namesz == 4)
+ {
+ char buf[4];
+ if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4)
+ return false;
+ if (strncmp (buf, "CORE", 4) == 0)
+ {
+ n_name = "CORE";
+ *offset += 4;
+ return true;
+ }
+ }
+
+ const char *cstr = data.GetCStr(offset, AlignToNext(n_namesz, 4));
+ if (cstr == NULL)
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log)
+ log->Printf("Failed to parse note name lacking nul terminator");
+
+ return false;
+ }
+ n_name = cstr;
+ return true;
+ }
+};
+
+// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
+static void
+ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data,
+ ArchSpec &arch)
+{
+ lldb::offset_t offset = 0;
+ bool have_padding = (arch.GetMachine() == llvm::Triple::x86_64);
+ int pr_version = data.GetU32(&offset);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log)
+ {
+ if (pr_version > 1)
+ log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version);
+ }
+
+ if (have_padding)
+ offset += 4;
+ offset += 28; // pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
+ thread_data->signo = data.GetU32(&offset); // pr_cursig
+ offset += 4; // pr_pid
+ if (have_padding)
+ offset += 4;
+
+ size_t len = data.GetByteSize() - offset;
+ thread_data->gpregset = DataExtractor(data, offset, len);
+}
+
+static void
+ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data)
+{
+ lldb::offset_t offset = 0;
+ thread_data->name = data.GetCStr(&offset, 20);
+}
+
+/// Parse Thread context from PT_NOTE segment and store it in the thread list
+/// Notes:
+/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
+/// 2) NOTE Entry contains a standard header followed by variable size data.
+/// (see ELFNote structure)
+/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
+/// a) NT_PRSTATUS - Register context
+/// b) NT_PRPSINFO - Process info(pid..)
+/// c) NT_FPREGSET - Floating point registers
+/// 4) The NOTE entries can be in any order
+/// 5) If a core file contains multiple thread contexts then there is two data forms
+/// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
+/// b) All thread context is stored in a single segment(PT_NOTE).
+/// This case is little tricker since while parsing we have to find where the
+/// new thread starts. The current implementation marks beginning of
+/// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
+/// For case (b) there may be either one NT_PRPSINFO per thread, or a single
+/// one that applies to all threads (depending on the platform type).
+void
+ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,
+ DataExtractor segment_data)
+{
+ assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
+
+ lldb::offset_t offset = 0;
+ ThreadData *thread_data = new ThreadData();
+ bool have_prstatus = false;
+ bool have_prpsinfo = false;
+
+ ArchSpec arch = GetArchitecture();
+ ELFLinuxPrPsInfo prpsinfo;
+ ELFLinuxPrStatus prstatus;
+ size_t header_size;
+ size_t len;
+
+ // Loop through the NOTE entires in the segment
+ while (offset < segment_header->p_filesz)
+ {
+ ELFNote note = ELFNote();
+ note.Parse(segment_data, &offset);
+
+ // Beginning of new thread
+ if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
+ (note.n_type == NT_PRPSINFO && have_prpsinfo))
+ {
+ assert(thread_data->gpregset.GetByteSize() > 0);
+ // Add the new thread to thread list
+ m_thread_data.push_back(*thread_data);
+ thread_data = new ThreadData();
+ have_prstatus = false;
+ have_prpsinfo = false;
+ }
+
+ size_t note_start, note_size;
+ note_start = offset;
+ note_size = AlignToNext(note.n_descsz, 4);
+
+ // Store the NOTE information in the current thread
+ DataExtractor note_data (segment_data, note_start, note_size);
+ if (note.n_name == "FreeBSD")
+ {
+ switch (note.n_type)
+ {
+ case NT_FREEBSD_PRSTATUS:
+ have_prstatus = true;
+ ParseFreeBSDPrStatus(thread_data, note_data, arch);
+ break;
+ case NT_FREEBSD_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case NT_FREEBSD_PRPSINFO:
+ have_prpsinfo = true;
+ break;
+ case NT_FREEBSD_THRMISC:
+ ParseFreeBSDThrMisc(thread_data, note_data);
+ break;
+ case NT_FREEBSD_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;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (note.n_type)
+ {
+ case NT_PRSTATUS:
+ have_prstatus = true;
+ prstatus.Parse(note_data, arch);
+ thread_data->signo = prstatus.pr_cursig;
+ header_size = ELFLinuxPrStatus::GetSize(arch);
+ len = note_data.GetByteSize() - header_size;
+ thread_data->gpregset = DataExtractor(note_data, header_size, len);
+ break;
+ case NT_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case NT_PRPSINFO:
+ have_prpsinfo = true;
+ prpsinfo.Parse(note_data, arch);
+ thread_data->name = prpsinfo.pr_fname;
+ break;
+ case NT_AUXV:
+ m_auxv = DataExtractor(note_data);
+ break;
+ default:
+ break;
+ }
+ }
+
+ offset += note_size;
+ }
+ // Add last entry in the note section
+ if (thread_data && thread_data->gpregset.GetByteSize() > 0)
+ {
+ m_thread_data.push_back(*thread_data);
+ }
+}
+
+uint32_t
+ProcessElfCore::GetNumThreadContexts ()
+{
+ if (!m_thread_data_valid)
+ DoLoadCore();
+ return m_thread_data.size();
+}
+
+ArchSpec
+ProcessElfCore::GetArchitecture()
+{
+ ObjectFileELF *core_file = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ ArchSpec arch;
+ core_file->GetArchitecture(arch);
+ return arch;
+}
+
+const lldb::DataBufferSP
+ProcessElfCore::GetAuxvData()
+{
+ const uint8_t *start = m_auxv.GetDataStart();
+ size_t len = m_auxv.GetByteSize();
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
+ return buffer;
+}
+
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h
new file mode 100644
index 000000000000..1c1ed98ce17a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -0,0 +1,171 @@
+//===-- ProcessElfCore.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Notes about Linux Process core dumps:
+// 1) Linux core dump is stored as ELF file.
+// 2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's
+// address space and thread contexts.
+// 3) PT_NOTE segment contains note entries which describes a thread context.
+// 4) PT_LOAD segment describes a valid contigous range of process address
+// space.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessElfCore_h_
+#define liblldb_ProcessElfCore_h_
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
+
+struct ThreadData;
+
+class ProcessElfCore : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessElfCore(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec &core_file);
+
+ virtual
+ ~ProcessElfCore();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target,
+ bool plugin_specified_by_name);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoLoadCore ();
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ GetImageInfoAddress ();
+
+ lldb_private::ArchSpec
+ GetArchitecture();
+
+ // Returns AUXV structure found in the core file
+ const lldb::DataBufferSP
+ GetAuxvData();
+
+protected:
+ void
+ Clear ( );
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessElfCore only
+ //------------------------------------------------------------------
+ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+ typedef lldb_private::RangeDataArray<lldb::addr_t, lldb::addr_t, FileRange, 1> VMRangeToFileOffset;
+
+ lldb::ModuleSP m_core_module_sp;
+ lldb_private::FileSpec m_core_file;
+ std::string m_dyld_plugin_name;
+ DISALLOW_COPY_AND_ASSIGN (ProcessElfCore);
+
+ // True if m_thread_contexts contains valid entries
+ bool m_thread_data_valid;
+
+ // Contain thread data read from NOTE segments
+ std::vector<ThreadData> m_thread_data;
+
+ // AUXV structure found from the NOTE segment
+ lldb_private::DataExtractor m_auxv;
+
+ // Address ranges found in the core
+ VMRangeToFileOffset m_core_aranges;
+
+ // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
+ void
+ ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header,
+ lldb_private::DataExtractor segment_data);
+
+ // Returns number of thread contexts stored in the core file
+ uint32_t
+ GetNumThreadContexts();
+
+ // Parse a contiguous address range of the process from LOAD segment
+ lldb::addr_t
+ AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header);
+};
+
+#endif // liblldb_ProcessElffCore_h_
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..6210175f9a7f
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.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 "RegisterContextCoreFreeBSD_x86_64.h"
+
+RegisterContextCoreFreeBSD_x86_64::RegisterContextCoreFreeBSD_x86_64(Thread &thread,
+ const DataExtractor &gpregset, const DataExtractor &fpregset)
+ : RegisterContextFreeBSD_x86_64(thread, 0)
+{
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset = new uint8_t[size];
+ len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+ assert(len == size);
+}
+
+RegisterContextCoreFreeBSD_x86_64::~RegisterContextCoreFreeBSD_x86_64()
+{
+ delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::UpdateAfterBreakpoint()
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h
new file mode 100644
index 000000000000..acd594a6e666
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h
@@ -0,0 +1,47 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.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_RegisterContextCoreFreeBSD_x86_64_H_
+#define liblldb_RegisterContextCoreFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreFreeBSD_x86_64: public RegisterContextFreeBSD_x86_64
+{
+public:
+ RegisterContextCoreFreeBSD_x86_64 (Thread &thread, const DataExtractor &gpregset,
+ const DataExtractor &fpregset);
+
+ ~RegisterContextCoreFreeBSD_x86_64();
+
+ virtual bool
+ ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+private:
+ uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp
new file mode 100644
index 000000000000..d9e3f6d5f90b
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreLinux_x86_64.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 "RegisterContextCoreLinux_x86_64.h"
+
+RegisterContextCoreLinux_x86_64::RegisterContextCoreLinux_x86_64(Thread &thread,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextLinux_x86_64(thread, 0)
+{
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset = new uint8_t[size];
+ len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+ assert(len == size);
+}
+
+RegisterContextCoreLinux_x86_64::~RegisterContextCoreLinux_x86_64()
+{
+ delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::UpdateAfterBreakpoint()
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h
new file mode 100644
index 000000000000..9cf545afd56a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h
@@ -0,0 +1,54 @@
+//===-- RegisterContextCoreLinux_x86_64.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_RegisterContextCoreLinux_x86_64_H_
+#define liblldb_RegisterContextCoreLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreLinux_x86_64: public RegisterContextLinux_x86_64
+{
+public:
+ RegisterContextCoreLinux_x86_64 (Thread &thread, const DataExtractor &gpregset,
+ const DataExtractor &fpregset);
+
+ ~RegisterContextCoreLinux_x86_64();
+
+ virtual bool
+ ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+protected:
+ bool
+ ReadFPR()
+ {
+ assert(0);
+ }
+
+private:
+ uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreLinux_x86_64_H_
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
new file mode 100644
index 000000000000..a7229663dc89
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -0,0 +1,176 @@
+//===-- ThreadElfCore.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/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "ProcessPOSIXLog.h"
+
+#include "ThreadElfCore.h"
+#include "ProcessElfCore.h"
+#include "RegisterContextCoreFreeBSD_x86_64.h"
+#include "RegisterContextCoreLinux_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Construct a Thread object with given data
+//----------------------------------------------------------------------
+ThreadElfCore::ThreadElfCore (Process &process, tid_t tid,
+ const ThreadData &td) :
+ Thread(process, tid),
+ m_thread_name(td.name),
+ m_thread_reg_ctx_sp (),
+ m_signo(td.signo),
+ m_gpregset_data(td.gpregset),
+ m_fpregset_data(td.fpregset)
+{
+}
+
+ThreadElfCore::~ThreadElfCore ()
+{
+ DestroyThread();
+}
+
+void
+ThreadElfCore::RefreshStateAfterStop()
+{
+ GetRegisterContext()->InvalidateIfNeeded (false);
+}
+
+void
+ThreadElfCore::ClearStackFrames ()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadElfCore::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL) {
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ if (m_thread_reg_ctx_sp)
+ return m_thread_reg_ctx_sp;
+
+ ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86_64:
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCoreFreeBSD_x86_64 (*this, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::Linux:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCoreLinux_x86_64 (*this, m_gpregset_data, m_fpregset_data));
+ break;
+ default:
+ if (log)
+ log->Printf ("elf-core::%s:: OS(%d) not supported",
+ __FUNCTION__, arch.GetTriple().getOS());
+ assert (false && "OS not supported");
+ break;
+ }
+ break;
+ default:
+ if (log)
+ log->Printf ("elf-core::%s:: Architecture(%d) not supported",
+ __FUNCTION__, arch.GetMachine());
+ assert (false && "Architecture not supported");
+ }
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ }
+ else if (m_unwinder_ap.get())
+ {
+ reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadElfCore::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, m_signo));
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------
+// Parse PRSTATUS from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrStatus::ELFLinuxPrStatus()
+{
+ memset(this, 0, sizeof(ELFLinuxPrStatus));
+}
+
+bool
+ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRSTATUS64_SIZE, byteorder, this);
+ return len == ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return false;
+ }
+}
+
+//----------------------------------------------------------------
+// Parse PRPSINFO from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrPsInfo::ELFLinuxPrPsInfo()
+{
+ memset(this, 0, sizeof(ELFLinuxPrPsInfo));
+}
+
+bool
+ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRPSINFO64_SIZE, byteorder, this);
+ return len == ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return false;
+ }
+}
+
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h
new file mode 100644
index 000000000000..ca6339d7ec9d
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -0,0 +1,174 @@
+//===-- ThreadElfCore.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_ThreadElfCore_h_
+#define liblldb_ThreadElfCore_h_
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataExtractor.h"
+
+struct compat_timeval
+{
+ int64_t tv_sec;
+ int32_t tv_usec;
+};
+
+// PRSTATUS structure's size differs based on architecture.
+// Currently parsing done only for x86-64 architecture by
+// simply reading data from the buffer.
+// The following macros are used to specify the size.
+// Calculating size using sizeof() wont work because of padding.
+#define ELFLINUXPRSTATUS64_SIZE (112)
+#define ELFLINUXPRPSINFO64_SIZE (132)
+
+struct ELFLinuxPrStatus
+{
+ int32_t si_signo;
+ int32_t si_code;
+ int32_t si_errno;
+
+ int16_t pr_cursig;
+
+ uint64_t pr_sigpend;
+ uint64_t pr_sighold;
+
+ uint32_t pr_pid;
+ uint32_t pr_ppid;
+ uint32_t pr_pgrp;
+ uint32_t pr_sid;
+
+ compat_timeval pr_utime;
+ compat_timeval pr_stime;
+ compat_timeval pr_cutime;
+ compat_timeval pr_cstime;
+
+ ELFLinuxPrStatus();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return 0;
+ }
+ }
+};
+
+struct ELFLinuxPrPsInfo
+{
+ char pr_state;
+ char pr_sname;
+ char pr_zomb;
+ char pr_nice;
+ uint64_t pr_flag;
+ uint32_t pr_uid;
+ uint32_t pr_gid;
+ int32_t pr_pid;
+ int32_t pr_ppid;
+ int32_t pr_pgrp;
+ int32_t pr_sid;
+ char pr_fname[16];
+ char pr_psargs[80];
+
+ ELFLinuxPrPsInfo();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return 0;
+ }
+ }
+
+};
+
+struct ThreadData
+{
+ lldb_private::DataExtractor gpregset;
+ lldb_private::DataExtractor fpregset;
+ int signo;
+ std::string name;
+};
+
+class ThreadElfCore : public lldb_private::Thread
+{
+public:
+ ThreadElfCore (lldb_private::Process &process, lldb::tid_t tid,
+ const ThreadData &td);
+
+ virtual
+ ~ThreadElfCore ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual void
+ ClearStackFrames ();
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread)
+ {
+ return thread != 0;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+ }
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+ int m_signo;
+
+ lldb_private::DataExtractor m_gpregset_data;
+ lldb_private::DataExtractor m_fpregset_data;
+
+ virtual bool CalculateStopInfo();
+
+};
+
+#endif // liblldb_ThreadElfCore_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 000000000000..d7efdf2302d8
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,643 @@
+//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunication.h"
+
+// C Includes
+#include <limits.h>
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+
+#define DEBUGSERVER_BASENAME "debugserver"
+
+using namespace lldb;
+using namespace lldb_private;
+
+GDBRemoteCommunication::History::History (uint32_t size) :
+ m_packets(),
+ m_curr_idx (0),
+ m_total_packet_count (0),
+ m_dumped_to_log (false)
+{
+ m_packets.resize(size);
+}
+
+GDBRemoteCommunication::History::~History ()
+{
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (1, packet_char);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (src, 0, src_len);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const
+{
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ strm.Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const
+{
+ if (log && !m_dumped_to_log)
+ {
+ m_dumped_to_log = true;
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ log->Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name,
+ bool is_platform) :
+ Communication(comm_name),
+ m_packet_timeout (1),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_public_is_running (false),
+ m_private_is_running (false),
+ m_history (512),
+ m_send_acks (true),
+ m_is_platform (is_platform)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ if (IsConnected())
+ {
+ Disconnect();
+ }
+}
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ for (size_t i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '+';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t
+GDBRemoteCommunication::SendNack ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '-';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, payload_length);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
+{
+ if (IsConnected())
+ {
+ StreamString packet(0, 4, eByteOrderBig);
+
+ packet.PutChar('$');
+ packet.Write (payload, payload_length);
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum (payload, payload_length));
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ if (log)
+ {
+ // 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
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ log->Printf ("<%4zu> send packet: %.*s", bytes_written, (int)packet.GetSize(), packet.GetData());
+ }
+
+ m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written);
+
+
+ if (bytes_written == packet.GetSize())
+ {
+ if (GetSendAcks ())
+ {
+ if (GetAck () != '+')
+ {
+ if (log)
+ log->Printf("get ack failed...");
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
+ }
+ return bytes_written;
+ }
+ return 0;
+}
+
+char
+GDBRemoteCommunication::GetAck ()
+{
+ StringExtractorGDBRemote packet;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1)
+ return packet.GetChar();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message)
+{
+ if (IsRunning())
+ return locker.TryLock (m_sequence_mutex, failure_message);
+
+ locker.Lock (m_sequence_mutex);
+ return true;
+}
+
+
+bool
+GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+ return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)
+{
+ uint8_t buffer[8192];
+ Error error;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE));
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket (NULL, 0, packet))
+ return packet.GetStringRef().size();
+
+ bool timed_out = false;
+ while (IsConnected() && !timed_out)
+ {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
+
+ if (log)
+ log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
+ __PRETTY_FUNCTION__,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ error.AsCString(),
+ (uint64_t)bytes_read);
+
+ if (bytes_read > 0)
+ {
+ if (CheckForPacket (buffer, bytes_read, packet))
+ return packet.GetStringRef().size();
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusTimedOut:
+ timed_out = true;
+ break;
+ case eConnectionStatusSuccess:
+ //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
+ break;
+
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusNoConnection:
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusError:
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear ();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ if (src && src_len > 0)
+ {
+ if (log && log->GetVerbose())
+ {
+ StreamString s;
+ log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s",
+ __FUNCTION__,
+ (uint32_t)src_len,
+ (uint32_t)src_len,
+ src);
+ }
+ m_bytes.append ((const char *)src, src_len);
+ }
+
+ // Parse up the packets into gdb remote packets
+ if (!m_bytes.empty())
+ {
+ // end_idx must be one past the last valid packet byte. Start
+ // it off with an invalid value that is the same as the current
+ // index.
+ size_t content_start = 0;
+ size_t content_length = 0;
+ size_t total_length = 0;
+ size_t checksum_idx = std::string::npos;
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ content_length = total_length = 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ {
+ size_t hash_pos = m_bytes.find('#');
+ if (hash_pos != std::string::npos)
+ {
+ if (hash_pos + 2 < m_bytes.size())
+ {
+ checksum_idx = hash_pos + 1;
+ // Skip the dollar sign
+ content_start = 1;
+ // Don't include the # in the content or the $ in the content length
+ content_length = hash_pos - 1;
+
+ total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ content_length = std::string::npos;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // We have an unexpected byte and we need to flush all bad
+ // data that is in m_bytes, so we need to find the first
+ // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt),
+ // or '$' character (start of packet header) or of course,
+ // the end of the data in m_bytes...
+ const size_t bytes_len = m_bytes.size();
+ bool done = false;
+ uint32_t idx;
+ for (idx = 1; !done && idx < bytes_len; ++idx)
+ {
+ switch (m_bytes[idx])
+ {
+ case '+':
+ case '-':
+ case '\x03':
+ case '$':
+ done = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
+ __FUNCTION__, idx, idx, m_bytes.c_str());
+ m_bytes.erase(0, idx);
+ }
+ break;
+ }
+
+ if (content_length == std::string::npos)
+ {
+ packet.Clear();
+ return false;
+ }
+ else if (total_length > 0)
+ {
+
+ // We have a valid packet...
+ assert (content_length <= m_bytes.size());
+ assert (total_length <= m_bytes.size());
+ assert (content_length <= total_length);
+
+ bool success = true;
+ std::string &packet_str = packet.GetStringRef();
+
+
+ if (log)
+ {
+ // If logging was just enabled and we have history, then dump out what
+ // 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
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ log->Printf ("<%4zu> read packet: %.*s", total_length, (int)(total_length), m_bytes.c_str());
+ }
+
+ m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
+
+ packet_str.assign (m_bytes, content_start, content_length);
+
+ if (m_bytes[0] == '$')
+ {
+ assert (checksum_idx < m_bytes.size());
+ if (::isxdigit (m_bytes[checksum_idx+0]) ||
+ ::isxdigit (m_bytes[checksum_idx+1]))
+ {
+ if (GetSendAcks ())
+ {
+ const char *packet_checksum_cstr = &m_bytes[checksum_idx];
+ char packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
+ char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size());
+ success = packet_checksum == actual_checksum;
+ if (!success)
+ {
+ if (log)
+ log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(total_length),
+ m_bytes.c_str(),
+ (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ SendNack();
+ else
+ SendAck();
+ }
+ }
+ else
+ {
+ success = false;
+ if (log)
+ log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str());
+ }
+ }
+
+ m_bytes.erase(0, total_length);
+ packet.SetFilePos(0);
+ return success;
+ }
+ }
+ packet.Clear();
+ return false;
+}
+
+Error
+GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
+ const char *unix_socket_name, // For handshaking
+ lldb_private::ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ // This function will fill in the launch information for the debugserver
+ // instance that gets launched.
+ launch_info.Clear();
+
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ debugserver_file_spec.SetFile (env_debugserver_path, false);
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
+ {
+ debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
+ debugserver_exists = debugserver_file_spec.Exists();
+ if (debugserver_exists)
+ {
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ Args &debugserver_args = launch_info.GetArguments();
+ debugserver_args.Clear();
+ char arg_cstr[PATH_MAX];
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--native-regs");
+ // make debugserver run in its own session so signals generated by
+ // special terminal key sequences (^C) don't affect debugserver
+ debugserver_args.AppendArgument("--setsid");
+
+ if (unix_socket_name && unix_socket_name[0])
+ {
+ debugserver_args.AppendArgument("--unix-socket");
+ debugserver_args.AppendArgument(unix_socket_name);
+ }
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+ // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
+ // debugserver_args.AppendArgument("--log-flags=0x802e0e");
+
+ // We currently send down all arguments, attach pids, or attach
+ // process names in dedicated GDB server packets, so we don't need
+ // to pass them as arguments. This is currently because of all the
+ // things we need to setup prior to launching: the environment,
+ // current working dir, file actions, etc.
+#if 0
+ // Now append the program arguments
+ if (inferior_argv)
+ {
+ // Terminate the debugserver args so we can now append the inferior args
+ debugserver_args.AppendArgument("--");
+
+ for (int i = 0; inferior_argv[i] != NULL; ++i)
+ debugserver_args.AppendArgument (inferior_argv[i]);
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
+ debugserver_args.AppendArgument (arg_cstr);
+ }
+ else if (attach_name && attach_name[0])
+ {
+ if (wait_for_launch)
+ debugserver_args.AppendArgument ("--waitfor");
+ else
+ debugserver_args.AppendArgument ("--attach");
+ debugserver_args.AppendArgument (attach_name);
+ }
+#endif
+
+ // Close STDIN, STDOUT and STDERR. We might need to redirect them
+ // to "/dev/null" if we run into any problems.
+// launch_info.AppendCloseFileAction (STDIN_FILENO);
+// launch_info.AppendCloseFileAction (STDOUT_FILENO);
+// launch_info.AppendCloseFileAction (STDERR_FILENO);
+
+ error = Host::LaunchProcess(launch_info);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
+ }
+ return error;
+}
+
+void
+GDBRemoteCommunication::DumpHistory(Stream &strm)
+{
+ m_history.Dump (strm);
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 000000000000..a1077957c6a6
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,268 @@
+//===-- GDBRemoteCommunication.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_GDBRemoteCommunication_h_
+#define liblldb_GDBRemoteCommunication_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/TimeValue.h"
+
+#include "Utility/StringExtractorGDBRemote.h"
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication : public lldb_private::Communication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name,
+ bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunication();
+
+ char
+ GetAck ();
+
+ size_t
+ SendAck ();
+
+ size_t
+ SendNack ();
+
+ char
+ CalculcateChecksum (const char *payload,
+ size_t payload_length);
+
+ bool
+ GetSequenceMutex (lldb_private::Mutex::Locker& locker, const char *failure_message = NULL);
+
+ bool
+ CheckForPacket (const uint8_t *src,
+ size_t src_len,
+ StringExtractorGDBRemote &packet);
+ bool
+ IsRunning() const
+ {
+ return m_public_is_running.GetValue();
+ }
+
+ bool
+ GetSendAcks ()
+ {
+ return m_send_acks;
+ }
+
+ //------------------------------------------------------------------
+ // Client and server must implement these pure virtual functions
+ //------------------------------------------------------------------
+ virtual bool
+ GetThreadSuffixSupported () = 0;
+
+ //------------------------------------------------------------------
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this might not
+ // get used, and if it doesn't this should be moved to the
+ // GDBRemoteCommunicationClient.
+ //------------------------------------------------------------------
+ uint32_t
+ SetPacketTimeout (uint32_t packet_timeout)
+ {
+ const uint32_t old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ uint32_t
+ GetPacketTimeoutInMicroSeconds () const
+ {
+ return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
+ }
+ //------------------------------------------------------------------
+ // Start a debugserver instance on the current host using the
+ // supplied connection URL.
+ //------------------------------------------------------------------
+ lldb_private::Error
+ StartDebugserverProcess (const char *connect_url,
+ const char *unix_socket_name,
+ lldb_private::ProcessLaunchInfo &launch_info);
+
+ void
+ DumpHistory(lldb_private::Stream &strm);
+
+protected:
+
+ class History
+ {
+ public:
+ enum PacketType
+ {
+ ePacketTypeInvalid = 0,
+ ePacketTypeSend,
+ ePacketTypeRecv
+ };
+
+ struct Entry
+ {
+ Entry() :
+ packet(),
+ type (ePacketTypeInvalid),
+ bytes_transmitted (0),
+ packet_idx (0),
+ tid (LLDB_INVALID_THREAD_ID)
+ {
+ }
+
+ void
+ Clear ()
+ {
+ packet.clear();
+ type = ePacketTypeInvalid;
+ bytes_transmitted = 0;
+ packet_idx = 0;
+ tid = LLDB_INVALID_THREAD_ID;
+ }
+ std::string packet;
+ PacketType type;
+ uint32_t bytes_transmitted;
+ uint32_t packet_idx;
+ lldb::tid_t tid;
+ };
+
+ History (uint32_t size);
+
+ ~History ();
+
+ // For single char packets for ack, nack and /x03
+ void
+ AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted);
+ void
+ AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted);
+
+ void
+ Dump (lldb_private::Stream &strm) const;
+
+ void
+ Dump (lldb_private::Log *log) const;
+
+ bool
+ DidDumpToLog () const
+ {
+ return m_dumped_to_log;
+ }
+
+protected:
+ uint32_t
+ GetFirstSavedPacketIndex () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return 0;
+ else
+ return m_curr_idx + 1;
+ }
+
+ uint32_t
+ GetNumPacketsInHistory () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return m_total_packet_count;
+ else
+ return (uint32_t)m_packets.size();
+ }
+
+ uint32_t
+ GetNextIndex()
+ {
+ ++m_total_packet_count;
+ const uint32_t idx = m_curr_idx;
+ m_curr_idx = NormalizeIndex(idx + 1);
+ return idx;
+ }
+
+ uint32_t
+ NormalizeIndex (uint32_t i) const
+ {
+ return i % m_packets.size();
+ }
+
+
+ std::vector<Entry> m_packets;
+ uint32_t m_curr_idx;
+ uint32_t m_total_packet_count;
+ mutable bool m_dumped_to_log;
+ };
+
+ size_t
+ SendPacket (const char *payload,
+ size_t payload_length);
+
+ size_t
+ SendPacketNoLock (const char *payload,
+ size_t payload_length);
+
+ size_t
+ WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response,
+ uint32_t timeout_usec);
+
+ bool
+ WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunication can see and modify these
+ //------------------------------------------------------------------
+ uint32_t m_packet_timeout;
+#ifdef LLDB_CONFIGURATION_DEBUG
+ lldb_private::TrackingMutex m_sequence_mutex;
+#else
+ lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+#endif
+ lldb_private::Predicate<bool> m_public_is_running;
+ lldb_private::Predicate<bool> m_private_is_running;
+ History m_history;
+ bool m_send_acks;
+ bool m_is_platform; // Set to true if this class represents a platform,
+ // false if this class represents a debug session for
+ // a single process
+
+
+
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
+};
+
+#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
new file mode 100644
index 000000000000..ca594a8f3fd5
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -0,0 +1,2348 @@
+//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunicationClient.h"
+
+// C Includes
+// C++ Includes
+#include <sstream>
+
+// Other libraries and framework includes
+#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/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationClient constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
+ GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform),
+ m_supports_not_sending_acks (eLazyBoolCalculate),
+ m_supports_thread_suffix (eLazyBoolCalculate),
+ m_supports_threads_in_stop_reply (eLazyBoolCalculate),
+ m_supports_vCont_all (eLazyBoolCalculate),
+ m_supports_vCont_any (eLazyBoolCalculate),
+ m_supports_vCont_c (eLazyBoolCalculate),
+ m_supports_vCont_C (eLazyBoolCalculate),
+ m_supports_vCont_s (eLazyBoolCalculate),
+ m_supports_vCont_S (eLazyBoolCalculate),
+ m_qHostInfo_is_valid (eLazyBoolCalculate),
+ m_qProcessInfo_is_valid (eLazyBoolCalculate),
+ m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
+ m_supports_memory_region_info (eLazyBoolCalculate),
+ m_supports_watchpoint_support_info (eLazyBoolCalculate),
+ m_supports_detach_stay_stopped (eLazyBoolCalculate),
+ m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
+ m_attach_or_wait_reply(eLazyBoolCalculate),
+ m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
+ m_supports_qProcessInfoPID (true),
+ m_supports_qfProcessInfo (true),
+ m_supports_qUserName (true),
+ m_supports_qGroupName (true),
+ m_supports_qThreadStopInfo (true),
+ m_supports_z0 (true),
+ m_supports_z1 (true),
+ m_supports_z2 (true),
+ m_supports_z3 (true),
+ m_supports_z4 (true),
+ m_curr_tid (LLDB_INVALID_THREAD_ID),
+ m_curr_tid_run (LLDB_INVALID_THREAD_ID),
+ m_num_supported_hardware_watchpoints (0),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_response (),
+ m_async_signal (-1),
+ m_thread_id_to_used_usec_map (),
+ m_host_arch(),
+ m_process_arch(),
+ m_os_version_major (UINT32_MAX),
+ m_os_version_minor (UINT32_MAX),
+ m_os_version_update (UINT32_MAX)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
+{
+ if (IsConnected())
+ Disconnect();
+}
+
+bool
+GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
+{
+ // Start the read thread after we send the handshake ack since if we
+ // fail to send the handshake ack, there is no reason to continue...
+ if (SendAck())
+ return true;
+
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to send the handshake ack");
+ return false;
+}
+
+void
+GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
+{
+ if (m_supports_not_sending_acks == eLazyBoolCalculate)
+ {
+ m_send_acks = true;
+ m_supports_not_sending_acks = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_send_acks = false;
+ m_supports_not_sending_acks = eLazyBoolYes;
+ }
+ }
+ }
+}
+
+void
+GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()
+{
+ if (m_supports_threads_in_stop_reply == eLazyBoolCalculate)
+ {
+ m_supports_threads_in_stop_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false))
+ {
+ if (response.IsOKResponse())
+ m_supports_threads_in_stop_reply = eLazyBoolYes;
+ }
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()
+{
+ if (m_attach_or_wait_reply == eLazyBoolCalculate)
+ {
+ m_attach_or_wait_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_attach_or_wait_reply = eLazyBoolYes;
+ }
+ }
+ if (m_attach_or_wait_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
+{
+ if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate)
+ {
+ m_prepare_for_reg_writing_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_prepare_for_reg_writing_reply = eLazyBoolYes;
+ }
+ }
+ if (m_prepare_for_reg_writing_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+
+void
+GDBRemoteCommunicationClient::ResetDiscoverableSettings()
+{
+ m_supports_not_sending_acks = eLazyBoolCalculate;
+ m_supports_thread_suffix = eLazyBoolCalculate;
+ m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ m_supports_vCont_c = eLazyBoolCalculate;
+ m_supports_vCont_C = eLazyBoolCalculate;
+ m_supports_vCont_s = eLazyBoolCalculate;
+ m_supports_vCont_S = eLazyBoolCalculate;
+ m_qHostInfo_is_valid = eLazyBoolCalculate;
+ m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
+ m_supports_memory_region_info = eLazyBoolCalculate;
+ m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+ m_attach_or_wait_reply = eLazyBoolCalculate;
+
+ m_supports_qProcessInfoPID = true;
+ m_supports_qfProcessInfo = true;
+ m_supports_qUserName = true;
+ m_supports_qGroupName = true;
+ m_supports_qThreadStopInfo = true;
+ m_supports_z0 = true;
+ m_supports_z1 = true;
+ m_supports_z2 = true;
+ m_supports_z3 = true;
+ m_supports_z4 = true;
+ m_host_arch.Clear();
+ m_process_arch.Clear();
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetThreadSuffixSupported ()
+{
+ if (m_supports_thread_suffix == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_thread_suffix = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_supports_thread_suffix = eLazyBoolYes;
+ }
+ }
+ return m_supports_thread_suffix;
+}
+bool
+GDBRemoteCommunicationClient::GetVContSupported (char flavor)
+{
+ if (m_supports_vCont_c == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_vCont_any = eLazyBoolNo;
+ m_supports_vCont_all = eLazyBoolNo;
+ m_supports_vCont_c = eLazyBoolNo;
+ m_supports_vCont_C = eLazyBoolNo;
+ m_supports_vCont_s = eLazyBoolNo;
+ m_supports_vCont_S = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("vCont?", response, false))
+ {
+ const char *response_cstr = response.GetStringRef().c_str();
+ if (::strstr (response_cstr, ";c"))
+ m_supports_vCont_c = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";C"))
+ m_supports_vCont_C = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";s"))
+ m_supports_vCont_s = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";S"))
+ m_supports_vCont_S = eLazyBoolYes;
+
+ if (m_supports_vCont_c == eLazyBoolYes &&
+ m_supports_vCont_C == eLazyBoolYes &&
+ m_supports_vCont_s == eLazyBoolYes &&
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_all = eLazyBoolYes;
+ }
+
+ if (m_supports_vCont_c == eLazyBoolYes ||
+ m_supports_vCont_C == eLazyBoolYes ||
+ m_supports_vCont_s == eLazyBoolYes ||
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_any = eLazyBoolYes;
+ }
+ }
+ }
+
+ switch (flavor)
+ {
+ case 'a': return m_supports_vCont_any;
+ case 'A': return m_supports_vCont_all;
+ case 'c': return m_supports_vCont_c;
+ case 'C': return m_supports_vCont_C;
+ case 's': return m_supports_vCont_s;
+ case 'S': return m_supports_vCont_S;
+ default: break;
+ }
+ return false;
+}
+
+
+size_t
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ send_async);
+}
+
+size_t
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ Mutex::Locker locker;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ size_t response_len = 0;
+ if (GetSequenceMutex (locker))
+ {
+ if (SendPacketNoLock (payload, payload_length))
+ response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ else
+ {
+ if (log)
+ log->Printf("error: failed to send '%*s'", (int) payload_length, payload);
+ }
+ }
+ else
+ {
+ if (send_async)
+ {
+ if (IsRunning())
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ if (log)
+ log->Printf ("async: async packet = %s", m_async_packet.c_str());
+
+ bool timed_out = false;
+ if (SendInterrupt(locker, 2, timed_out))
+ {
+ if (m_interrupt_sent)
+ {
+ m_interrupt_sent = false;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (m_packet_timeout);
+
+ if (log)
+ log->Printf ("async: sent interrupt");
+
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ if (log)
+ log->Printf ("async: got response");
+
+ // Swap the response buffer to avoid malloc and string copy
+ response.GetStringRef().swap (m_async_response.GetStringRef());
+ response_len = response.GetStringRef().size();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for response");
+ }
+
+ // Make sure we wait until the continue packet has been sent again...
+ if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out))
+ {
+ if (log)
+ {
+ if (timed_out)
+ log->Printf ("async: timed out waiting for process to resume, but process was resumed");
+ else
+ log->Printf ("async: async packet sent");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for process to resume");
+ }
+ }
+ else
+ {
+ // We had a racy condition where we went to send the interrupt
+ // yet we were able to get the lock, so the process must have
+ // just stopped?
+ if (log)
+ log->Printf ("async: got lock without sending interrupt");
+ // Send the packet normally since we got the lock
+ if (SendPacketNoLock (payload, payload_length))
+ response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ else
+ {
+ if (log)
+ log->Printf("error: failed to send '%*s'", (int) payload_length, payload);
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: failed to interrupt");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: not running, async is ignored");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);
+ }
+ }
+ if (response_len == 0)
+ {
+ if (log)
+ log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload);
+ }
+ return response_len;
+}
+
+static const char *end_delimiter = "--end--;";
+static const int end_delimiter_len = 8;
+
+std::string
+GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData
+( ProcessGDBRemote *process,
+ StringExtractorGDBRemote& profileDataExtractor
+)
+{
+ std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map;
+ std::stringstream final_output;
+ std::string name, value;
+
+ // Going to assuming thread_used_usec comes first, else bail out.
+ while (profileDataExtractor.GetNameColonValue(name, value))
+ {
+ if (name.compare("thread_used_id") == 0)
+ {
+ StringExtractor threadIDHexExtractor(value.c_str());
+ uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0);
+
+ bool has_used_usec = false;
+ uint32_t curr_used_usec = 0;
+ std::string usec_name, usec_value;
+ uint32_t input_file_pos = profileDataExtractor.GetFilePos();
+ if (profileDataExtractor.GetNameColonValue(usec_name, usec_value))
+ {
+ if (usec_name.compare("thread_used_usec") == 0)
+ {
+ has_used_usec = true;
+ curr_used_usec = strtoull(usec_value.c_str(), NULL, 0);
+ }
+ else
+ {
+ // We didn't find what we want, it is probably
+ // an older version. Bail out.
+ profileDataExtractor.SetFilePos(input_file_pos);
+ }
+ }
+
+ if (has_used_usec)
+ {
+ uint32_t prev_used_usec = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id);
+ if (iterator != m_thread_id_to_used_usec_map.end())
+ {
+ prev_used_usec = m_thread_id_to_used_usec_map[thread_id];
+ }
+
+ uint32_t real_used_usec = curr_used_usec - prev_used_usec;
+ // A good first time record is one that runs for at least 0.25 sec
+ bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000);
+ bool good_subsequent_time = (prev_used_usec > 0) &&
+ ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id)));
+
+ if (good_first_time || good_subsequent_time)
+ {
+ // We try to avoid doing too many index id reservation,
+ // resulting in fast increase of index ids.
+
+ final_output << name << ":";
+ int32_t index_id = process->AssignIndexIDToThread(thread_id);
+ final_output << index_id << ";";
+
+ final_output << usec_name << ":" << usec_value << ";";
+ }
+ else
+ {
+ // Skip past 'thread_used_name'.
+ std::string local_name, local_value;
+ profileDataExtractor.GetNameColonValue(local_name, local_value);
+ }
+
+ // Store current time as previous time so that they can be compared later.
+ new_thread_id_to_used_usec_map[thread_id] = curr_used_usec;
+ }
+ else
+ {
+ // Bail out and use old string.
+ final_output << name << ":" << value << ";";
+ }
+ }
+ else
+ {
+ final_output << name << ":" << value << ";";
+ }
+ }
+ final_output << end_delimiter;
+ m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map;
+
+ return final_output.str();
+}
+
+StateType
+GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ StateType state = eStateRunning;
+
+ BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
+ m_public_is_running.SetValue (true, eBroadcastNever);
+ // Set the starting continue packet into "continue_packet". This packet
+ // may change if we are interrupted and we continue after an async packet...
+ std::string continue_packet(payload, packet_length);
+
+ bool got_async_packet = false;
+
+ while (state == eStateRunning)
+ {
+ if (!got_async_packet)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str());
+ if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0)
+ state = eStateInvalid;
+
+ m_private_is_running.SetValue (true, eBroadcastAlways);
+ }
+
+ got_async_packet = false;
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str());
+
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX))
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str());
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ if (process->GetStopID() == 0)
+ {
+ if (process->GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ process->SetID (pid);
+ }
+ process->BuildDynamicRegisterInfo (true);
+ }
+
+ // Privately notify any internal threads that we have stopped
+ // in case we wanted to interrupt our process, yet we might
+ // send a packet and continue without returning control to the
+ // user.
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+
+ const uint8_t signo = response.GetHexU8 (UINT8_MAX);
+
+ bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue();
+ if (continue_after_async || m_interrupt_sent)
+ {
+ // We sent an interrupt packet to stop the inferior process
+ // for an async signal or to send an async packet while running
+ // but we might have been single stepping and received the
+ // stop packet for the step instead of for the interrupt packet.
+ // Typically when an interrupt is sent a SIGINT or SIGSTOP
+ // is used, so if we get anything else, we need to try and
+ // get another stop reply packet that may have been sent
+ // due to sending the interrupt when the target is stopped
+ // which will just re-send a copy of the last stop reply
+ // packet. If we don't do this, then the reply for our
+ // async packet will be the repeat stop reply packet and cause
+ // a lot of trouble for us!
+ if (signo != SIGINT && signo != SIGSTOP)
+ {
+ continue_after_async = false;
+
+ // We didn't get a a SIGINT or SIGSTOP, so try for a
+ // very brief time (1 ms) to get another stop reply
+ // packet to make sure it doesn't get in the way
+ StringExtractorGDBRemote extra_stop_reply_packet;
+ uint32_t timeout_usec = 1000;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec))
+ {
+ switch (extra_stop_reply_packet.GetChar())
+ {
+ case 'T':
+ case 'S':
+ // We did get an extra stop reply, which means
+ // our interrupt didn't stop the target so we
+ // shouldn't continue after the async signal
+ // or packet is sent...
+ continue_after_async = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (m_async_signal != -1)
+ {
+ if (log)
+ log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal));
+
+ // Save off the async signal we are supposed to send
+ const int async_signal = m_async_signal;
+ // Clear the async signal member so we don't end up
+ // sending the signal multiple times...
+ m_async_signal = -1;
+ // Check which signal we stopped with
+ if (signo == async_signal)
+ {
+ if (log)
+ log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo));
+
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ }
+ else
+ {
+ // We stopped with a different signal that the one
+ // we wanted to stop with, so now we must resume
+ // with the signal we want
+ char signal_packet[32];
+ int signal_packet_len = 0;
+ signal_packet_len = ::snprintf (signal_packet,
+ sizeof (signal_packet),
+ "C%2.2x",
+ async_signal);
+
+ if (log)
+ log->Printf ("async: stopped with signal %s, resume with %s",
+ Host::GetSignalAsCString (signo),
+ Host::GetSignalAsCString (async_signal));
+
+ // Set the continue packet to resume even if the
+ // interrupt didn't cause our stop (ignore continue_after_async)
+ continue_packet.assign(signal_packet, signal_packet_len);
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (m_async_packet.empty())
+ {
+ if (packet_log)
+ packet_log->Printf ("async: error: empty async packet");
+
+ }
+ else
+ {
+ if (packet_log)
+ packet_log->Printf ("async: sending packet");
+
+ SendPacketAndWaitForResponse (&m_async_packet[0],
+ m_async_packet.size(),
+ m_async_response,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent and response is
+ // ready...
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ if (packet_log)
+ packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async);
+
+ // Set the continue packet to resume if our interrupt
+ // for the async packet did cause the stop
+ if (continue_after_async)
+ {
+ // Reverting this for now as it is causing deadlocks
+ // in programs (<rdar://problem/11529853>). In the future
+ // we should check our thread list and "do the right thing"
+ // for new threads that show up while we stop and run async
+ // packets. Setting the packet to 'c' to continue all threads
+ // is the right thing to do 99.99% of the time because if a
+ // thread was single stepping, and we sent an interrupt, we
+ // will notice above that we didn't stop due to an interrupt
+ // but stopped due to stepping and we would _not_ continue.
+ continue_packet.assign (1, 'c');
+ continue;
+ }
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ }
+ break;
+
+ case 'W':
+ case 'X':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ got_async_packet = true;
+ std::string inferior_stdout;
+ inferior_stdout.reserve(response.GetBytesLeft () / 2);
+ char ch;
+ while ((ch = response.GetHexU8()) != '\0')
+ inferior_stdout.append(1, ch);
+ process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
+ }
+ break;
+
+ case 'A':
+ // Async miscellaneous reply. Right now, only profile data is coming through this channel.
+ {
+ got_async_packet = true;
+ std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A'
+ if (m_partial_profile_data.length() > 0)
+ {
+ m_partial_profile_data.append(input);
+ input = m_partial_profile_data;
+ m_partial_profile_data.clear();
+ }
+
+ size_t found, pos = 0, len = input.length();
+ while ((found = input.find(end_delimiter, pos)) != std::string::npos)
+ {
+ StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str());
+ std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor);
+ process->BroadcastAsyncProfileData (profile_data);
+
+ pos = found + end_delimiter_len;
+ }
+
+ if (pos < len)
+ {
+ // Last incomplete chunk.
+ m_partial_profile_data = input.substr(pos);
+ }
+ }
+ break;
+
+ case 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__);
+ state = eStateInvalid;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+ m_public_is_running.SetValue (false, eBroadcastAlways);
+ return state;
+}
+
+bool
+GDBRemoteCommunicationClient::SendAsyncSignal (int signo)
+{
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_signal = signo;
+ bool timed_out = false;
+ Mutex::Locker locker;
+ if (SendInterrupt (locker, 1, timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+// This function takes a mutex locker as a parameter in case the GetSequenceMutex
+// actually succeeds. If it doesn't succeed in acquiring the sequence mutex
+// (the expected result), then it will send the halt packet. If it does succeed
+// then the caller that requested the interrupt will want to keep the sequence
+// locked down so that no one else can send packets while the caller has control.
+// This function usually gets called when we are running and need to stop the
+// target. It can also be used when we are running and and we need to do something
+// else (like read/write memory), so we need to interrupt the running process
+// (gdb remote protocol requires this), and do what we need to do, then resume.
+
+bool
+GDBRemoteCommunicationClient::SendInterrupt
+(
+ Mutex::Locker& locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out
+)
+{
+ timed_out = false;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+
+ if (IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (GetSequenceMutex (locker))
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt");
+ }
+ else
+ {
+ // Someone has the mutex locked waiting for a response or for the
+ // inferior to stop, so send the interrupt on the down low...
+ char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (&ctrl_c, 1, status, NULL);
+ if (log)
+ log->PutCString("send packet: \\x03");
+ if (bytes_written > 0)
+ {
+ m_interrupt_sent = true;
+ if (seconds_to_wait_for_stop)
+ {
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out))
+ {
+ if (log)
+ log->PutCString ("SendInterrupt () - sent interrupt, private state stopped");
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop...");
+ return true;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - failed to write interrupt");
+ }
+ return false;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - not running");
+ }
+ return true;
+}
+
+lldb::pid_t
+GDBRemoteCommunicationClient::GetCurrentProcessID ()
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false))
+ {
+ if (response.GetChar() == 'Q')
+ if (response.GetChar() == 'C')
+ return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ if (response.GetChar() == 'E')
+ {
+ // A string the describes what failed when launching...
+ error_str = response.GetStringRef().substr(1);
+ }
+ else
+ {
+ error_str.assign ("unknown error occurred launching process");
+ }
+ }
+ else
+ {
+ error_str.assign ("timed out waiting for app to launch");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[])
+{
+ if (argv && argv[0])
+ {
+ StreamString packet;
+ packet.PutChar('A');
+ const char *arg;
+ for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
+ {
+ const int arg_len = strlen(arg);
+ if (i > 0)
+ packet.PutChar(',');
+ packet.Printf("%i,%i,", arg_len * 2, i);
+ packet.PutBytesAsRawHex8 (arg, arg_len);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value)
+{
+ if (name_equal_value && name_equal_value[0])
+ {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
+{
+ if (arch && arch[0])
+ {
+ StreamString packet;
+ packet.Printf("QLaunchArch:%s", arch);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update)
+{
+ if (GetHostInfo ())
+ {
+ if (m_os_version_major != UINT32_MAX)
+ {
+ major = m_os_version_major;
+ minor = m_os_version_minor;
+ update = m_os_version_update;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSBuildString (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_build.empty())
+ {
+ s = m_os_build;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_kernel.empty())
+ {
+ s = m_os_kernel;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetHostname (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_hostname.empty())
+ {
+ s = m_hostname;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+ArchSpec
+GDBRemoteCommunicationClient::GetSystemArchitecture ()
+{
+ if (GetHostInfo ())
+ return m_host_arch;
+ return ArchSpec();
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetProcessArchitecture ()
+{
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo ();
+ return m_process_arch;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetHostInfo (bool force)
+{
+ if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
+ {
+ m_qHostInfo_is_valid = eLazyBoolNo;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ sub = Args::StringToUInt32 (value.c_str(), 0, 0);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("arch") == 0)
+ {
+ arch_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("triple") == 0)
+ {
+ // The triple comes as ASCII hex bytes since it contains '-' chars
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_build") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_build);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("hostname") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_hostname);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_kernel") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_kernel);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_version") == 0)
+ {
+ Args::StringToVersion (value.c_str(),
+ m_os_version_major,
+ m_os_version_minor,
+ m_os_version_update);
+ if (m_os_version_major != UINT32_MAX)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("watchpoint_exceptions_received") == 0)
+ {
+ ++num_keys_decoded;
+ if (strcmp(value.c_str(),"before") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolNo;
+ else if (strcmp(value.c_str(),"after") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolYes;
+ else
+ --num_keys_decoded;
+ }
+
+ }
+
+ if (num_keys_decoded > 0)
+ m_qHostInfo_is_valid = eLazyBoolYes;
+
+ if (triple.empty())
+ {
+ if (arch_name.empty())
+ {
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ {
+ m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ if (!os_name.empty() && vendor_name.compare("apple") == 0 && os_name.find("darwin") == 0)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ os_name = "ios";
+ break;
+ default:
+ os_name = "macosx";
+ break;
+ }
+ }
+ if (!vendor_name.empty())
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ if (!os_name.empty())
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+
+ }
+ }
+ else
+ {
+ std::string triple;
+ triple += arch_name;
+ if (!vendor_name.empty() || !os_name.empty())
+ {
+ triple += '-';
+ if (vendor_name.empty())
+ triple += "unknown";
+ else
+ triple += vendor_name;
+ triple += '-';
+ if (os_name.empty())
+ triple += "unknown";
+ else
+ triple += os_name;
+ }
+ m_host_arch.SetTriple (triple.c_str());
+
+ llvm::Triple &host_triple = m_host_arch.GetTriple();
+ if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ host_triple.setOS(llvm::Triple::IOS);
+ break;
+ default:
+ host_triple.setOS(llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ }
+ }
+ else
+ {
+ m_host_arch.SetTriple (triple.c_str());
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+ }
+ }
+ }
+ }
+ return m_qHostInfo_is_valid == eLazyBoolYes;
+}
+
+int
+GDBRemoteCommunicationClient::SendAttach
+(
+ lldb::pid_t pid,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsErrorResponse())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetHostArchitecture ()
+{
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo ();
+ return m_host_arch;
+}
+
+addr_t
+GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s",
+ (uint64_t)size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (!response.IsErrorResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return false;
+}
+
+Error
+GDBRemoteCommunicationClient::Detach (bool keep_stopped)
+{
+ Error error;
+
+ if (keep_stopped)
+ {
+ if (m_supports_detach_stay_stopped == eLazyBoolCalculate)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ m_supports_detach_stay_stopped = eLazyBoolYes;
+ }
+ else
+ {
+ m_supports_detach_stay_stopped = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_detach_stay_stopped == eLazyBoolNo)
+ {
+ error.SetErrorString("Stays stopped not supported by this target.");
+ return error;
+ }
+ else
+ {
+ size_t num_sent = SendPacket ("D1", 2);
+ if (num_sent == 0)
+ error.SetErrorString ("Sending extended disconnect packet failed.");
+ }
+ }
+ else
+ {
+ size_t num_sent = SendPacket ("D", 1);
+ if (num_sent == 0)
+ error.SetErrorString ("Sending disconnect packet failed.");
+ }
+ return error;
+}
+
+Error
+GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
+ lldb_private::MemoryRegionInfo &region_info)
+{
+ Error error;
+ region_info.Clear();
+
+ if (m_supports_memory_region_info != eLazyBoolNo)
+ {
+ m_supports_memory_region_info = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ std::string name;
+ std::string value;
+ addr_t addr_value;
+ bool success = true;
+ bool saw_permissions = false;
+ while (success && response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("start") == 0)
+ {
+ addr_value = Args::StringToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success);
+ if (success)
+ region_info.GetRange().SetRangeBase(addr_value);
+ }
+ else if (name.compare ("size") == 0)
+ {
+ addr_value = Args::StringToUInt64(value.c_str(), 0, 16, &success);
+ if (success)
+ region_info.GetRange().SetByteSize (addr_value);
+ }
+ else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid())
+ {
+ saw_permissions = true;
+ if (region_info.GetRange().Contains (addr))
+ {
+ if (value.find('r') != std::string::npos)
+ region_info.SetReadable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+
+ if (value.find('w') != std::string::npos)
+ region_info.SetWritable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+
+ if (value.find('x') != std::string::npos)
+ region_info.SetExecutable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ else
+ {
+ // The reported region does not contain this address -- we're looking at an unmapped page
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else if (name.compare ("error") == 0)
+ {
+ StringExtractorGDBRemote name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ error.SetErrorString(value.c_str());
+ }
+ }
+
+ // We got a valid address range back but no permissions -- which means this is an unmapped page
+ if (region_info.GetRange().IsValid() && saw_permissions == false)
+ {
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else
+ {
+ m_supports_memory_region_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_memory_region_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qMemoryRegionInfo is not supported");
+ }
+ if (error.Fail())
+ region_info.Clear();
+ return error;
+
+}
+
+Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num)
+{
+ Error error;
+
+ if (m_supports_watchpoint_support_info == eLazyBoolYes)
+ {
+ num = m_num_supported_hardware_watchpoints;
+ return error;
+ }
+
+ // Set num to 0 first.
+ num = 0;
+ if (m_supports_watchpoint_support_info != eLazyBoolNo)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ m_supports_watchpoint_support_info = eLazyBoolYes;
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("num") == 0)
+ {
+ num = Args::StringToUInt32(value.c_str(), 0, 0);
+ m_num_supported_hardware_watchpoints = num;
+ }
+ }
+ }
+ else
+ {
+ m_supports_watchpoint_support_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_watchpoint_support_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qWatchpointSupportInfo is not supported");
+ }
+ return error;
+
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after)
+{
+ Error error(GetWatchpointSupportInfo(num));
+ if (error.Success())
+ error = GetWatchpointsTriggerAfterInstruction(after);
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after)
+{
+ Error error;
+
+ // we assume watchpoints will happen after running the relevant opcode
+ // and we only want to override this behavior if we have explicitly
+ // received a qHostInfo telling us otherwise
+ if (m_qHostInfo_is_valid != eLazyBoolYes)
+ after = true;
+ else
+ after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo);
+ return error;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDIN (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDIN:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDOUT:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDERR (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDERR:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetWorkingDir:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
+{
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info)
+{
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ StringExtractor extractor;
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("pid") == 0)
+ {
+ process_info.SetProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("ppid") == 0)
+ {
+ process_info.SetParentProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("uid") == 0)
+ {
+ process_info.SetUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("euid") == 0)
+ {
+ process_info.SetEffectiveUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("gid") == 0)
+ {
+ process_info.SetGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("egid") == 0)
+ {
+ process_info.SetEffectiveGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("triple") == 0)
+ {
+ // The triple comes as ASCII hex bytes since it contains '-' chars
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetArchitecture ().SetTriple (value.c_str());
+ }
+ else if (name.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ // The process name from ASCII hex bytes since we can't
+ // control the characters in a process name
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetExecutableFile().SetFile (value.c_str(), false);
+ }
+ }
+
+ if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+
+ if (m_supports_qProcessInfoPID)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ return DecodeProcessInfoResponse (response, process_info);
+ }
+ else
+ {
+ m_supports_qProcessInfoPID = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
+{
+ if (m_qProcessInfo_is_valid == eLazyBoolYes)
+ return true;
+ if (m_qProcessInfo_is_valid == eLazyBoolNo)
+ return false;
+
+ GetHostInfo ();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qProcessInfo", response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ sub = Args::StringToUInt32 (value.c_str(), 0, 16);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 16);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ }
+ if (num_keys_decoded > 0)
+ m_qProcessInfo_is_valid = eLazyBoolYes;
+ if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
+ {
+ m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+ return true;
+ }
+ }
+ }
+ else
+ {
+ m_qProcessInfo_is_valid = eLazyBoolNo;
+ }
+
+ return false;
+}
+
+
+uint32_t
+GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+
+ if (m_supports_qfProcessInfo)
+ {
+ StreamString packet;
+ packet.PutCString ("qfProcessInfo");
+ if (!match_info.MatchAllProcesses())
+ {
+ packet.PutChar (':');
+ const char *name = match_info.GetProcessInfo().GetName();
+ bool has_name_match = false;
+ if (name && name[0])
+ {
+ has_name_match = true;
+ NameMatchType name_match_type = match_info.GetNameMatchType();
+ switch (name_match_type)
+ {
+ case eNameMatchIgnore:
+ has_name_match = false;
+ break;
+
+ case eNameMatchEquals:
+ packet.PutCString ("name_match:equals;");
+ break;
+
+ case eNameMatchContains:
+ packet.PutCString ("name_match:contains;");
+ break;
+
+ case eNameMatchStartsWith:
+ packet.PutCString ("name_match:starts_with;");
+ break;
+
+ case eNameMatchEndsWith:
+ packet.PutCString ("name_match:ends_with;");
+ break;
+
+ case eNameMatchRegularExpression:
+ packet.PutCString ("name_match:regex;");
+ break;
+ }
+ if (has_name_match)
+ {
+ packet.PutCString ("name:");
+ packet.PutBytesAsRawHex8(name, ::strlen(name));
+ packet.PutChar (';');
+ }
+ }
+
+ if (match_info.GetProcessInfo().ProcessIDIsValid())
+ packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID());
+ if (match_info.GetProcessInfo().ParentProcessIDIsValid())
+ packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID());
+ if (match_info.GetProcessInfo().UserIDIsValid())
+ packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID());
+ if (match_info.GetProcessInfo().GroupIDIsValid())
+ packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID());
+ if (match_info.GetProcessInfo().EffectiveUserIDIsValid())
+ packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0);
+ if (match_info.GetProcessInfo().GetArchitecture().IsValid())
+ {
+ const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture();
+ const llvm::Triple &triple = match_arch.GetTriple();
+ packet.PutCString("triple:");
+ packet.PutCStringAsRawHex8(triple.getTriple().c_str());
+ packet.PutChar (';');
+ }
+ }
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ do
+ {
+ ProcessInstanceInfo process_info;
+ if (!DecodeProcessInfoResponse (response, process_info))
+ break;
+ process_infos.Append(process_info);
+ response.GetStringRef().clear();
+ response.SetFilePos(0);
+ } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false));
+ }
+ else
+ {
+ m_supports_qfProcessInfo = false;
+ return 0;
+ }
+ }
+ return process_infos.GetSize();
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name)
+{
+ if (m_supports_qUserName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded user name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qUserName = false;
+ return false;
+ }
+ }
+ return false;
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)
+{
+ if (m_supports_qGroupName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded group name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qGroupName = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+void
+GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets)
+{
+ uint32_t i;
+ TimeValue start_time, end_time;
+ uint64_t total_time_nsec;
+ float packets_per_second;
+ if (SendSpeedTestPacket (0, 0))
+ {
+ for (uint32_t send_size = 0; send_size <= 1024; send_size *= 2)
+ {
+ for (uint32_t recv_size = 0; recv_size <= 1024; recv_size *= 2)
+ {
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
+ {
+ SendSpeedTestPacket (send_size, recv_size);
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+ packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ printf ("%u qSpeedTest(send=%-5u, recv=%-5u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n",
+ num_packets,
+ send_size,
+ recv_size,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second);
+ if (recv_size == 0)
+ recv_size = 32;
+ }
+ if (send_size == 0)
+ send_size = 32;
+ }
+ }
+ else
+ {
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
+ {
+ GetCurrentProcessID ();
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+ packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ printf ("%u 'qC' packets packets in 0x%" PRIu64 "%9.9" PRIu64 " sec for %f packets/sec.\n",
+ num_packets,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second);
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size)
+{
+ StreamString packet;
+ packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ }
+ else
+ {
+ packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0;
+ return false;
+}
+
+uint16_t
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false))
+ {
+ std::string name;
+ std::string value;
+ uint16_t port = 0;
+ //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.size() == 4 && name.compare("port") == 0)
+ port = Args::StringToUInt32(value.c_str(), 0, 0);
+// if (name.size() == 3 && name.compare("pid") == 0)
+// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+ }
+ return port;
+ }
+ return 0;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
+{
+ if (m_curr_tid == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid);
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid)
+{
+ if (m_curr_tid_run == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid);
+
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid_run = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response)
+{
+ if (SendPacketAndWaitForResponse("?", 1, response, false))
+ return response.IsNormalResponse();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+ if (m_supports_qThreadStopInfo)
+ {
+ char packet[256];
+ int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ m_supports_qThreadStopInfo = false;
+ }
+ }
+// if (SetCurrentThread (tid))
+// return GetStopReply (response);
+ return false;
+}
+
+
+uint8_t
+GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length)
+{
+ switch (type)
+ {
+ case eBreakpointSoftware: if (!m_supports_z0) return UINT8_MAX; break;
+ case eBreakpointHardware: if (!m_supports_z1) return UINT8_MAX; break;
+ case eWatchpointWrite: if (!m_supports_z2) return UINT8_MAX; break;
+ case eWatchpointRead: if (!m_supports_z3) return UINT8_MAX; break;
+ case eWatchpointReadWrite: if (!m_supports_z4) return UINT8_MAX; break;
+ }
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet,
+ sizeof(packet),
+ "%c%i,%" PRIx64 ",%x",
+ insert ? 'Z' : 'z',
+ type,
+ addr,
+ length);
+
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, true))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ else if (response.IsErrorResponse())
+ return response.GetError();
+ }
+ else
+ {
+ switch (type)
+ {
+ case eBreakpointSoftware: m_supports_z0 = false; break;
+ case eBreakpointHardware: m_supports_z1 = false; break;
+ case eWatchpointWrite: m_supports_z2 = false; break;
+ case eWatchpointRead: m_supports_z3 = false; break;
+ case eWatchpointReadWrite: m_supports_z4 = false; break;
+ }
+ }
+
+ return UINT8_MAX;
+}
+
+size_t
+GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable)
+{
+ Mutex::Locker locker;
+ thread_ids.clear();
+
+ if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"))
+ {
+ sequence_mutex_unavailable = false;
+ StringExtractorGDBRemote response;
+
+ for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ response.IsNormalResponse();
+ SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()))
+ {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm')
+ {
+ do
+ {
+ tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID);
+
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ thread_ids.push_back (tid);
+ }
+ ch = response.GetChar(); // Skip the command separator
+ } while (ch == ','); // Make sure we got a comma separator
+ }
+ }
+ }
+ else
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex");
+#else
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'");
+#endif
+ sequence_mutex_unavailable = true;
+ }
+ return thread_ids.size();
+}
+
+lldb::addr_t
+GDBRemoteCommunicationClient::GetShlibInfoAddr()
+{
+ if (!IsRunning())
+ {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false))
+ {
+ if (response.IsNormalResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
new file mode 100644
index 000000000000..5bb8387b9094
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -0,0 +1,430 @@
+//===-- GDBRemoteCommunicationClient.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_GDBRemoteCommunicationClient_h_
+#define liblldb_GDBRemoteCommunicationClient_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/Process.h"
+
+#include "GDBRemoteCommunication.h"
+
+typedef enum
+{
+ eBreakpointSoftware = 0,
+ eBreakpointHardware,
+ eWatchpointWrite,
+ eWatchpointRead,
+ eWatchpointReadWrite
+} GDBStoppointType;
+
+class GDBRemoteCommunicationClient : public GDBRemoteCommunication
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationClient(bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunicationClient();
+
+ //------------------------------------------------------------------
+ // After connecting, send the handshake to the server to make sure
+ // we are communicating with it.
+ //------------------------------------------------------------------
+ bool
+ HandshakeWithServer (lldb_private::Error *error_ptr);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ size_t send_length,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
+ const char *packet_payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+
+ virtual bool
+ GetThreadSuffixSupported ();
+
+ void
+ QueryNoAckModeSupported ();
+
+ void
+ GetListThreadsInStopReplySupported ();
+
+ bool
+ SendAsyncSignal (int signo);
+
+ bool
+ SendInterrupt (lldb_private::Mutex::Locker &locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out);
+
+ lldb::pid_t
+ GetCurrentProcessID ();
+
+ bool
+ GetLaunchSuccess (std::string &error_str);
+
+ uint16_t
+ LaunchGDBserverAndGetPort ();
+
+ //------------------------------------------------------------------
+ /// Sends a GDB remote protocol 'A' packet that delivers program
+ /// arguments to the remote server.
+ ///
+ /// @param[in] argv
+ /// A NULL terminated array of const C strings to use as the
+ /// arguments.
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendArgumentsPacket (char const *argv[]);
+
+ //------------------------------------------------------------------
+ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
+ /// environment that will get used when launching an application
+ /// in conjunction with the 'A' packet. This function can be called
+ /// multiple times in a row in order to pass on the desired
+ /// environment that the inferior should be launched with.
+ ///
+ /// @param[in] name_equal_value
+ /// A NULL terminated C string that contains a single environment
+ /// in the format "NAME=VALUE".
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendEnvironmentPacket (char const *name_equal_value);
+
+ int
+ SendLaunchArchPacket (const char *arch);
+ //------------------------------------------------------------------
+ /// Sends a "vAttach:PID" where PID is in hex.
+ ///
+ /// @param[in] pid
+ /// A process ID for the remote gdb server to attach to.
+ ///
+ /// @param[out] response
+ /// The response received from the gdb server. If the return
+ /// value is zero, \a response will contain a stop reply
+ /// packet.
+ ///
+ /// @return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ //------------------------------------------------------------------
+ int
+ SendAttach (lldb::pid_t pid,
+ StringExtractorGDBRemote& response);
+
+
+ //------------------------------------------------------------------
+ /// Sets the path to use for stdin/out/err for a process
+ /// that will be launched with the 'A' packet.
+ ///
+ /// @param[in] path
+ /// The path to use for stdin/out/err
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetSTDIN (char const *path);
+ int
+ SetSTDOUT (char const *path);
+ int
+ SetSTDERR (char const *path);
+
+ //------------------------------------------------------------------
+ /// Sets the disable ASLR flag to \a enable for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// @param[in] enable
+ /// A boolean value indicating wether to disable ASLR or not.
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetDisableASLR (bool enable);
+
+ //------------------------------------------------------------------
+ /// Sets the working directory to \a path for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// @param[in] path
+ /// The path to a directory to use when launching our processs
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetWorkingDir (char const *path);
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions);
+
+ bool
+ DeallocateMemory (lldb::addr_t addr);
+
+ lldb_private::Error
+ Detach (bool keep_stopped);
+
+ lldb_private::Error
+ GetMemoryRegionInfo (lldb::addr_t addr,
+ lldb_private::MemoryRegionInfo &range_info);
+
+ lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num);
+
+ lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after);
+
+ lldb_private::Error
+ GetWatchpointsTriggerAfterInstruction (bool &after);
+
+ const lldb_private::ArchSpec &
+ GetHostArchitecture ();
+
+ const lldb_private::ArchSpec &
+ GetProcessArchitecture ();
+
+ bool
+ GetVContSupported (char flavor);
+
+ bool
+ GetVAttachOrWaitSupported ();
+
+ bool
+ GetSyncThreadStateSupported();
+
+ void
+ ResetDiscoverableSettings();
+
+ bool
+ GetHostInfo (bool force = false);
+
+ bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update);
+
+ bool
+ GetOSBuildString (std::string &s);
+
+ bool
+ GetOSKernelDescription (std::string &s);
+
+ lldb_private::ArchSpec
+ GetSystemArchitecture ();
+
+ bool
+ GetHostname (std::string &s);
+
+ lldb::addr_t
+ GetShlibInfoAddr();
+
+ bool
+ GetSupportsThreadSuffix ();
+
+ bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &process_info);
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &process_match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ bool
+ GetUserName (uint32_t uid, std::string &name);
+
+ bool
+ GetGroupName (uint32_t gid, std::string &name);
+
+ bool
+ HasFullVContSupport ()
+ {
+ return GetVContSupported ('A');
+ }
+
+ bool
+ HasAnyVContSupport ()
+ {
+ return GetVContSupported ('a');
+ }
+
+ bool
+ GetStopReply (StringExtractorGDBRemote &response);
+
+ bool
+ GetThreadStopInfo (lldb::tid_t tid,
+ StringExtractorGDBRemote &response);
+
+ bool
+ SupportsGDBStoppointPacket (GDBStoppointType type)
+ {
+ switch (type)
+ {
+ case eBreakpointSoftware: return m_supports_z0;
+ case eBreakpointHardware: return m_supports_z1;
+ case eWatchpointWrite: return m_supports_z2;
+ case eWatchpointRead: return m_supports_z3;
+ case eWatchpointReadWrite: return m_supports_z4;
+ }
+ return false;
+ }
+ uint8_t
+ SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint
+ bool insert, // Insert or remove?
+ lldb::addr_t addr, // Address of breakpoint or watchpoint
+ uint32_t length); // Byte Size of breakpoint or watchpoint
+
+ void
+ TestPacketSpeed (const uint32_t num_packets);
+
+ // This packet is for testing the speed of the interface only. Both
+ // the client and server need to support it, but this allows us to
+ // measure the packet speed without any other work being done on the
+ // other end and avoids any of that work affecting the packet send
+ // and response times.
+ bool
+ SendSpeedTestPacket (uint32_t send_size,
+ uint32_t recv_size);
+
+ bool
+ SetCurrentThread (uint64_t tid);
+
+ bool
+ SetCurrentThreadForRun (uint64_t tid);
+
+ lldb_private::LazyBool
+ SupportsAllocDeallocMemory () // const
+ {
+ // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets.
+ // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo;
+ return m_supports_alloc_dealloc_memory;
+ }
+
+ size_t
+ GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable);
+
+ bool
+ GetInterruptWasSent () const
+ {
+ return m_interrupt_sent;
+ }
+
+ std::string
+ HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
+ StringExtractorGDBRemote &inputStringExtractor);
+
+protected:
+
+ bool
+ GetCurrentProcessInfo ();
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these
+ //------------------------------------------------------------------
+ lldb_private::LazyBool m_supports_not_sending_acks;
+ lldb_private::LazyBool m_supports_thread_suffix;
+ lldb_private::LazyBool m_supports_threads_in_stop_reply;
+ lldb_private::LazyBool m_supports_vCont_all;
+ lldb_private::LazyBool m_supports_vCont_any;
+ lldb_private::LazyBool m_supports_vCont_c;
+ lldb_private::LazyBool m_supports_vCont_C;
+ lldb_private::LazyBool m_supports_vCont_s;
+ lldb_private::LazyBool m_supports_vCont_S;
+ lldb_private::LazyBool m_qHostInfo_is_valid;
+ lldb_private::LazyBool m_qProcessInfo_is_valid;
+ lldb_private::LazyBool m_supports_alloc_dealloc_memory;
+ lldb_private::LazyBool m_supports_memory_region_info;
+ lldb_private::LazyBool m_supports_watchpoint_support_info;
+ lldb_private::LazyBool m_supports_detach_stay_stopped;
+ lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
+ lldb_private::LazyBool m_attach_or_wait_reply;
+ lldb_private::LazyBool m_prepare_for_reg_writing_reply;
+
+ bool
+ m_supports_qProcessInfoPID:1,
+ m_supports_qfProcessInfo:1,
+ m_supports_qUserName:1,
+ m_supports_qGroupName:1,
+ m_supports_qThreadStopInfo:1,
+ m_supports_z0:1,
+ m_supports_z1:1,
+ m_supports_z2:1,
+ m_supports_z3:1,
+ m_supports_z4:1;
+
+
+ lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
+ lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc
+
+
+ uint32_t m_num_supported_hardware_watchpoints;
+
+ // If we need to send a packet while the target is running, the m_async_XXX
+ // member variables take care of making this happen.
+ lldb_private::Mutex m_async_mutex;
+ lldb_private::Predicate<bool> m_async_packet_predicate;
+ std::string m_async_packet;
+ StringExtractorGDBRemote m_async_response;
+ int m_async_signal; // We were asked to deliver a signal to the inferior process.
+ bool m_interrupt_sent;
+ std::string m_partial_profile_data;
+ std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+
+ lldb_private::ArchSpec m_host_arch;
+ lldb_private::ArchSpec m_process_arch;
+ uint32_t m_os_version_major;
+ uint32_t m_os_version_minor;
+ uint32_t m_os_version_update;
+ std::string m_os_build;
+ std::string m_os_kernel;
+ std::string m_hostname;
+
+ bool
+ DecodeProcessInfoResponse (StringExtractorGDBRemote &response,
+ lldb_private::ProcessInstanceInfo &process_info);
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationClient only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient);
+};
+
+#endif // liblldb_GDBRemoteCommunicationClient_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
new file mode 100644
index 000000000000..3a14e9fe759a
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -0,0 +1,839 @@
+//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunicationServer.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#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/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServer constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
+ GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_process_launch_info (),
+ m_process_launch_error (),
+ m_proc_infos (),
+ m_proc_infos_index (0),
+ m_lo_port_num (0),
+ m_hi_port_num (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
+{
+}
+
+
+//void *
+//GDBRemoteCommunicationServer::AsyncThread (void *arg)
+//{
+// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
+//
+// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+// if (log)
+// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
+//
+// StringExtractorGDBRemote packet;
+//
+// while ()
+// {
+// if (packet.
+// }
+//
+// if (log)
+// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
+//
+// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+// return NULL;
+//}
+//
+bool
+GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+{
+ StringExtractorGDBRemote packet;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec))
+ {
+ const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
+ switch (packet_type)
+ {
+ case StringExtractorGDBRemote::eServerPacketType_nack:
+ case StringExtractorGDBRemote::eServerPacketType_ack:
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_invalid:
+ error.SetErrorString("invalid packet");
+ quit = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_interrupt:
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_unimplemented:
+ return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;
+
+ case StringExtractorGDBRemote::eServerPacketType_A:
+ return Handle_A (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
+ return Handle_qfProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
+ return Handle_qsProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qC:
+ return Handle_qC (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
+ return Handle_qHostInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
+ return Handle_qLaunchGDBServer (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
+ return Handle_qLaunchSuccess (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qGroupName:
+ return Handle_qGroupName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
+ return Handle_qProcessInfoPID (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
+ return Handle_qSpeedTest (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qUserName:
+ return Handle_qUserName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
+ return Handle_QEnvironment (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
+ return Handle_QSetDisableASLR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
+ return Handle_QSetSTDIN (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
+ return Handle_QSetSTDOUT (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
+ return Handle_QSetSTDERR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
+ return Handle_QSetWorkingDir (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
+ return Handle_QStartNoAckMode (packet);
+ }
+ return true;
+ }
+ else
+ {
+ if (!IsConnected())
+ error.SetErrorString("lost connection");
+ else
+ error.SetErrorString("timeout");
+ }
+
+ return false;
+}
+
+size_t
+GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+{
+ // TODO: Log the packet we aren't handling...
+ return SendPacketNoLock ("", 0);
+}
+
+size_t
+GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
+{
+ char packet[16];
+ int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
+ assert (packet_len < (int)sizeof(packet));
+ return SendPacketNoLock (packet, packet_len);
+}
+
+
+size_t
+GDBRemoteCommunicationServer::SendOKResponse ()
+{
+ return SendPacketNoLock ("OK", 2);
+}
+
+bool
+GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+{
+ return GetAck();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch (Host::GetArchitecture ());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+ uint32_t cpu = host_arch.GetMachOCPUType();
+ uint32_t sub = host_arch.GetMachOCPUSubType();
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cpusubtype:%u;", sub);
+
+ if (cpu == ArchSpec::kCore_arm_any)
+ response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+
+ switch (lldb::endian::InlHostByteOrder())
+ {
+ case eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default: response.PutCString ("endian:unknown;"); break;
+ }
+
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ if (Host::GetOSVersion (major, minor, update))
+ {
+ if (major != UINT32_MAX)
+ {
+ response.Printf("os_version:%u", major);
+ if (minor != UINT32_MAX)
+ {
+ response.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ response.Printf(".%u", update);
+ }
+ response.PutChar(';');
+ }
+ }
+
+ std::string s;
+ if (Host::GetOSBuildString (s))
+ {
+ response.PutCString ("os_build:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (Host::GetOSKernelDescription (s))
+ {
+ response.PutCString ("os_kernel:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (Host::GetHostname (s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+
+ return SendPacketNoLock (response.GetData(), response.GetSize()) > 0;
+}
+
+static void
+CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+ response.PutCString ("name:");
+ response.PutCStringAsRawHex8(proc_info.GetName());
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+ }
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos(::strlen ("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo(pid, proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse (proc_info, response);
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (1);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+ m_proc_infos_index = 0;
+ m_proc_infos.Clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
+ if (packet.GetChar() == ':')
+ {
+
+ std::string key;
+ std::string value;
+ while (packet.GetNameColonValue(key, value))
+ {
+ bool success = true;
+ if (key.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.GetHexByteString (value);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+ }
+ else if (key.compare("name_match") == 0)
+ {
+ if (value.compare("equals") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEquals);
+ }
+ else if (value.compare("starts_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ }
+ else if (value.compare("ends_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ }
+ else if (value.compare("contains") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchContains);
+ }
+ else if (value.compare("regex") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else if (key.compare("pid") == 0)
+ {
+ match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("parent_pid") == 0)
+ {
+ match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("uid") == 0)
+ {
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("gid") == 0)
+ {
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("euid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("egid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("all_users") == 0)
+ {
+ match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+ }
+ else if (key.compare("triple") == 0)
+ {
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+ }
+ else
+ {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse (2);
+ }
+ }
+
+ if (Host::FindProcesses (match_info, m_proc_infos))
+ {
+ // We found something, return the first item by calling the get
+ // subsequent process info packet handler...
+ return Handle_qsProcessInfo (packet);
+ }
+ return SendErrorResponse (3);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+ if (m_proc_infos_index < m_proc_infos.GetSize())
+ {
+ StreamString response;
+ CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse (4);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qUserName:%i" where %i is the uid
+ packet.SetFilePos(::strlen ("qUserName:"));
+ uint32_t uid = packet.GetU32 (UINT32_MAX);
+ if (uid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetUserName (uid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (5);
+
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qGroupName:%i" where %i is the gid
+ packet.SetFilePos(::strlen ("qGroupName:"));
+ uint32_t gid = packet.GetU32 (UINT32_MAX);
+ if (gid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetGroupName (gid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (6);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+ std::string key;
+ std::string value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key.compare("response_size") == 0)
+ {
+ uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
+ if (success)
+ {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left -= 26;
+ }
+ else
+ {
+ response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (7);
+}
+
+
+static void *
+AcceptPortFromInferior (void *arg)
+{
+ const char *connect_url = (const char *)arg;
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
+ {
+ char pid_str[256];
+ ::memset (pid_str, 0, sizeof(pid_str));
+ ConnectionStatus status;
+ const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
+ if (pid_str_len > 0)
+ {
+ int pid = atoi (pid_str);
+ return (void *)(intptr_t)pid;
+ }
+ }
+ return NULL;
+}
+//
+//static bool
+//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+//{
+// const int time_delta_usecs = 100000;
+// const int num_retries = timeout_in_seconds/time_delta_usecs;
+// for (int i=0; i<num_retries; i++)
+// {
+// struct proc_bsdinfo bsd_info;
+// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+// (uint64_t) 0,
+// &bsd_info,
+// PROC_PIDTBSDINFO_SIZE);
+//
+// switch (error)
+// {
+// case EINVAL:
+// case ENOTSUP:
+// case ESRCH:
+// case EPERM:
+// return false;
+//
+// default:
+// break;
+//
+// case 0:
+// if (bsd_info.pbi_status == SSTOP)
+// return true;
+// }
+// ::usleep (time_delta_usecs);
+// }
+// return false;
+//}
+
+bool
+GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // separated hex encoded argument value list, but we will stay true to the
+ // documented version of the 'A' packet here...
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument index. We ignore this really becuase
+ // who would really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteString(arg) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes lft
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+ m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
+ m_process_launch_error = Host::LaunchProcess (m_process_launch_info);
+ if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ return SendOKResponse ();
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ StreamString response;
+ response.Printf("QC%" PRIx64, pid);
+ if (m_is_platform)
+ {
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ char connect_url[PATH_MAX];
+ Error error;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ if (::mktemp (unix_socket_name) == NULL)
+ {
+ error.SetErrorString ("failed to make temporary path for a unix socket");
+ }
+ else
+ {
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+ lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
+ AcceptPortFromInferior,
+ connect_url,
+ &error);
+
+ if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
+ {
+ // Spawn a debugserver and try to get
+ ProcessLaunchInfo debugserver_launch_info;
+ error = StartDebugserverProcess ("localhost:0",
+ unix_socket_name,
+ debugserver_launch_info);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+ if (error.Success())
+ {
+ bool success = false;
+
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ {
+ if (accept_thread_result)
+ {
+ uint16_t port = (intptr_t)accept_thread_result;
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+ assert (response_len < (int)sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
+ }
+ }
+ ::unlink (unix_socket_name);
+
+ if (!success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
+ }
+ return success;
+ }
+ }
+ }
+ }
+ return SendErrorResponse (13);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (9);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ m_process_launch_info.SwapWorkingDirectory (path);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (10);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+ // Send response first before changing m_send_acks to we ack this packet
+ SendOKResponse ();
+ m_send_acks = false;
+ return true;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
new file mode 100644
index 000000000000..cce0e4e64c1e
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -0,0 +1,147 @@
+//===-- GDBRemoteCommunicationServer.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_GDBRemoteCommunicationServer_h_
+#define liblldb_GDBRemoteCommunicationServer_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Process.h"
+
+#include "GDBRemoteCommunication.h"
+
+class ProcessGDBRemote;
+class StringExtractorGDBRemote;
+
+class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationServer(bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunicationServer();
+
+ bool
+ GetPacketAndSendResponse (uint32_t timeout_usec,
+ lldb_private::Error &error,
+ bool &interrupt,
+ bool &quit);
+
+ virtual bool
+ GetThreadSuffixSupported ()
+ {
+ return true;
+ }
+
+ // After connecting, do a little handshake with the client to make sure
+ // we are at least communicating
+ bool
+ HandshakeWithClient (lldb_private::Error *error_ptr);
+
+ // Set both ports to zero to let the platform automatically bind to
+ // a port chosen by the OS.
+ void
+ SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num)
+ {
+ m_lo_port_num = lo_port_num;
+ m_hi_port_num = hi_port_num;
+ }
+
+protected:
+ //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap;
+
+ lldb::thread_t m_async_thread;
+ lldb_private::ProcessLaunchInfo m_process_launch_info;
+ lldb_private::Error m_process_launch_error;
+ lldb_private::ProcessInstanceInfoList m_proc_infos;
+ uint32_t m_proc_infos_index;
+ uint16_t m_lo_port_num;
+ uint16_t m_hi_port_num;
+ //PortToPIDMap m_port_to_pid_map;
+
+ size_t
+ SendUnimplementedResponse (const char *packet);
+
+ size_t
+ SendErrorResponse (uint8_t error);
+
+ size_t
+ SendOKResponse ();
+
+ bool
+ Handle_A (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qHostInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qUserName (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qGroupName (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qSpeedTest (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QEnvironment (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServer only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
+};
+
+#endif // liblldb_GDBRemoteCommunicationServer_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 000000000000..b1612a5f3c2f
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,971 @@
+//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/Utils.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteRegisterContext constructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::GDBRemoteRegisterContext
+(
+ ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_info (reg_info),
+ m_reg_valid (),
+ m_reg_data (),
+ m_read_all_at_once (read_all_at_once)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ m_reg_valid.resize (reg_info.GetNumRegisters());
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
+{
+}
+
+void
+GDBRemoteRegisterContext::InvalidateAllRegisters ()
+{
+ SetAllRegisterValid (false);
+}
+
+void
+GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterCount ()
+{
+ return m_reg_info.GetNumRegisters ();
+}
+
+const RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_info.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterSetCount ()
+{
+ return m_reg_info.GetNumRegisterSets ();
+}
+
+
+
+const RegisterSet *
+GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_info.GetRegisterSet (reg_set);
+}
+
+
+
+bool
+GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ // Read the register
+ if (ReadRegisterBytes (reg_info, m_reg_data))
+ {
+ const bool partial_data_ok = false;
+ Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ // Invalidate if needed
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg_byte_size = reg_info->byte_size;
+ const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc');
+ bool success = bytes_copied == reg_byte_size;
+ if (success)
+ {
+ SetRegisterIsValid(reg, true);
+ }
+ else if (bytes_copied > 0)
+ {
+ // Only set register is valid to false if we copied some bytes, else
+ // leave it as it was.
+ SetRegisterIsValid(reg, false);
+ }
+ return success;
+}
+
+// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
+bool
+GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ char packet[64];
+ StringExtractorGDBRemote response;
+ int packet_len = 0;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (gdb_comm.GetThreadSuffixSupported())
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+ return PrivateSetRegisterValue (reg, response);
+
+ return false;
+}
+bool
+GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (!GetRegisterIsValid(reg))
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ char packet[64];
+ StringExtractorGDBRemote response;
+ int packet_len = 0;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+ {
+ if (response.IsNormalResponse())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ }
+ else if (reg_info->value_regs)
+ {
+ // Process this composite register request by delegating to the constituent
+ // primordial registers.
+
+ // Index of the primordial register.
+ bool success = true;
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t prim_reg = reg_info->value_regs[idx];
+ if (prim_reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial regsiter as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
+ if (prim_reg_info == NULL)
+ success = false;
+ else
+ {
+ // Read the containing register if it hasn't already been read
+ if (!GetRegisterIsValid(prim_reg))
+ success = GetPrimordialRegister(prim_reg_info, gdb_comm);
+ }
+ }
+
+ if (success)
+ {
+ // If we reach this point, all primordial register requests have succeeded.
+ // Validate this composite register.
+ SetRegisterIsValid (reg_info, true);
+ }
+ }
+ else
+ {
+ // Get each register individually
+ GetPrimordialRegister(reg_info, gdb_comm);
+ }
+ }
+ }
+ else
+ {
+#if LLDB_CONFIGURATION_DEBUG
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ Host::SetCrashDescription (strm.GetData());
+ assert (!"Didn't get sequence mutex for read register.");
+#else
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData());
+ }
+ else
+ {
+ log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name);
+ }
+ }
+#endif
+ }
+
+ // Make sure we got a valid register value after reading it
+ if (!GetRegisterIsValid(reg))
+ return false;
+ }
+
+ if (&data != &m_reg_data)
+ {
+ // If we aren't extracting into our own buffer (which
+ // only happens when this function is called from
+ // ReadRegisterValue(uint32_t, Scalar&)) then
+ // we transfer bytes from our buffer into the data
+ // buffer that was passed in
+ data.SetByteOrder (m_reg_data.GetByteOrder());
+ data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
+ }
+ return true;
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ DataExtractor data;
+ if (value.GetData (data))
+ return WriteRegisterBytes (reg_info, data, 0);
+ return false;
+}
+
+// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
+bool
+GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (gdb_comm.GetThreadSuffixSupported())
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate just this register
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+void
+GDBRemoteRegisterContext::SyncThreadState(Process *process)
+{
+ // NB. We assume our caller has locked the sequence mutex.
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
+ if (!gdb_comm.GetSyncThreadStateSupported())
+ return;
+
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ InvalidateAllRegisters();
+ }
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (gdb_comm.IsRunning())
+// return false;
+
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
+
+ if (dst == NULL)
+ return false;
+
+
+ if (data.CopyByteOrderedData (data_offset, // src offset
+ reg_info->byte_size, // src length
+ dst, // dst
+ reg_info->byte_size, // dst length
+ m_reg_data.GetByteOrder())) // dst byte order
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ StreamString packet;
+ StringExtractorGDBRemote response;
+
+ if (m_read_all_at_once)
+ {
+ // Set all registers in one packet
+ packet.PutChar ('G');
+ packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
+ m_reg_data.GetByteSize(),
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate all register values
+ InvalidateIfNeeded (true);
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ SetAllRegisterValid (false);
+ if (response.IsOKResponse())
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ bool success = true;
+
+ if (reg_info->value_regs)
+ {
+ // This register is part of another register. In this case we read the actual
+ // register data for any "value_regs", and once all that data is read, we will
+ // have enough data in our register context bytes for the value of this register
+
+ // Invalidate this composite register first.
+
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t reg = reg_info->value_regs[idx];
+ if (reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial regsiter as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg);
+ if (value_reg_info == NULL)
+ success = false;
+ else
+ success = SetPrimordialRegister(value_reg_info, gdb_comm);
+ }
+ }
+ else
+ {
+ // This is an actual register, write it
+ success = SetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Check if writing this register will invalidate any other register values?
+ // If so, invalidate them
+ if (reg_info->invalidate_regs)
+ {
+ for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0];
+ reg != LLDB_INVALID_REGNUM;
+ reg = reg_info->invalidate_regs[++idx])
+ {
+ SetRegisterIsValid(reg, false);
+ }
+ }
+
+ return success;
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ StringExtractorGDBRemote response;
+
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
+ {
+ SyncThreadState(process);
+
+ char packet[32];
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsErrorResponse())
+ return false;
+
+ std::string &response_str = response.GetStringRef();
+ if (isxdigit(response_str[0]))
+ {
+ response_str.insert(0, 1, 'G');
+ if (thread_suffix_supported)
+ {
+ char thread_id_cstr[64];
+ ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ response_str.append (thread_id_cstr);
+ }
+ data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers");
+ }
+ }
+
+ data_sp.reset();
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
+ return false;
+
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ StringExtractorGDBRemote response;
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ // The data_sp contains the entire G response packet including the
+ // G, and if the thread suffix is supported, it has the thread suffix
+ // as well.
+ const char *G_packet = (const char *)data_sp->GetBytes();
+ size_t G_packet_len = data_sp->GetByteSize();
+ if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ else if (response.IsErrorResponse())
+ {
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and
+ // restore them manually
+
+ response.GetStringRef().assign (G_packet, G_packet_len);
+ response.SetFilePos(1); // Skip the leading 'G'
+ DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
+ DataExtractor restore_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
+ restore_data.GetByteSize(),
+ '\xcc');
+
+ if (bytes_extracted < restore_data.GetByteSize())
+ restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
+
+ //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
+ const RegisterInfo *reg_info;
+ // We have to march the offset of each register along in the
+ // buffer to make sure we get the right offset.
+ uint32_t reg_byte_offset = 0;
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
+ {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ // Skip composite registers.
+ if (reg_info->value_regs)
+ continue;
+
+ // Only write down the registers that need to be written
+ // if we are going to be doing registers individually.
+ bool write_reg = true;
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
+ if (restore_src)
+ {
+ if (GetRegisterIsValid(reg))
+ {
+ const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
+ if (current_src)
+ write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ }
+
+ if (write_reg)
+ {
+ StreamString packet;
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
+ }
+ }
+ }
+ }
+ return num_restored > 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers");
+ }
+ }
+ return false;
+}
+
+
+uint32_t
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+void
+GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch)
+{
+ // For Advanced SIMD and VFP register mapping.
+ static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1)
+ static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3)
+ static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5)
+ static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7)
+ static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9)
+ static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11)
+ static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13)
+ static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15)
+ static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17)
+ static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19)
+ static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21)
+ static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23)
+ static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25)
+ static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27)
+ static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29)
+ static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31)
+ static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3)
+ static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7)
+ static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11)
+ static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15)
+ static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19)
+ static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23)
+ static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27)
+ static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31)
+ static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17)
+ static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19)
+ static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21)
+ static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23)
+ static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25)
+ static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27)
+ static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29)
+ static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31)
+
+ // This is our array of composite registers, with each element coming from the above register mappings.
+ static uint32_t *g_composites[] = {
+ g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs,
+ g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs,
+ g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs,
+ g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs
+ };
+
+ static RegisterInfo g_register_infos[] = {
+// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// ====== ====== === === ============= ============ =================== =================== ====================== === ==== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL},
+ { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL},
+ { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL},
+ { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL},
+ { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL},
+ { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL},
+ { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL},
+ { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL},
+ { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL},
+ { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL},
+ { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL},
+ { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL},
+ { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL},
+ { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL},
+ { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL},
+ { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL},
+ { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL},
+ { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL},
+ { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL},
+ { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL},
+ { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL},
+ { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL},
+ { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL},
+ { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL},
+ { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL},
+ { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL},
+ { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL},
+ { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL},
+ { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL}
+ };
+
+ static const uint32_t num_registers = llvm::array_lengthof(g_register_infos);
+ static ConstString gpr_reg_set ("General Purpose Registers");
+ static ConstString sfp_reg_set ("Software Floating Point Registers");
+ static ConstString vfp_reg_set ("Floating Point Registers");
+ size_t i;
+ if (from_scratch)
+ {
+ // Calculate the offsets of the registers
+ // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the
+ // "primordial" registers is important. This enables us to calculate the offset of the composite
+ // register by using the offset of its first primordial register. For example, to calculate the
+ // offset of q0, use s0's offset.
+ if (g_register_infos[2].byte_offset == 0)
+ {
+ uint32_t byte_offset = 0;
+ for (i=0; i<num_registers; ++i)
+ {
+ // For primordial registers, increment the byte_offset by the byte_size to arrive at the
+ // byte_offset for the next register. Otherwise, we have a composite register whose
+ // offset can be calculated by consulting the offset of its first primordial register.
+ if (!g_register_infos[i].value_regs)
+ {
+ g_register_infos[i].byte_offset = byte_offset;
+ byte_offset += g_register_infos[i].byte_size;
+ }
+ else
+ {
+ const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0];
+ g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset;
+ }
+ }
+ }
+ for (i=0; i<num_registers; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ if (g_register_infos[i].name && g_register_infos[i].name[0])
+ name.SetCString(g_register_infos[i].name);
+ if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
+ alt_name.SetCString(g_register_infos[i].alt_name);
+
+ if (i <= 15 || i == 25)
+ AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set);
+ else if (i <= 24)
+ AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set);
+ else
+ AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ else
+ {
+ // Add composite registers to our primordial registers, then.
+ const size_t num_composites = llvm::array_lengthof(g_composites);
+ const size_t num_dynamic_regs = GetNumRegisters();
+ const size_t num_common_regs = num_registers - num_composites;
+ RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs;
+
+ // First we need to validate that all registers that we already have match the non composite regs.
+ // If so, then we can add the registers, else we need to bail
+ bool match = true;
+ if (num_dynamic_regs == num_common_regs)
+ {
+ for (i=0; match && i<num_dynamic_regs; ++i)
+ {
+ // Make sure all register names match
+ if (m_regs[i].name && g_register_infos[i].name)
+ {
+ if (strcmp(m_regs[i].name, g_register_infos[i].name))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ // Make sure all register byte sizes match
+ if (m_regs[i].byte_size != g_register_infos[i].byte_size)
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Wrong number of registers.
+ match = false;
+ }
+ // If "match" is true, then we can add extra registers.
+ if (match)
+ {
+ for (i=0; i<num_composites; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0];
+ const char *reg_name = g_register_infos[first_primordial_reg].name;
+ if (reg_name && reg_name[0])
+ {
+ for (uint32_t j = 0; j < num_dynamic_regs; ++j)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j);
+ // Find a matching primordial register info entry.
+ if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0)
+ {
+ // The name matches the existing primordial entry.
+ // Find and assign the offset, and then add this composite register entry.
+ g_comp_register_infos[i].byte_offset = reg_info->byte_offset;
+ name.SetCString(g_comp_register_infos[i].name);
+ AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 000000000000..3110ddf8edf9
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,311 @@
+//===-- GDBRemoteRegisterContext.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_GDBRemoteRegisterContext_h_
+#define lldb_GDBRemoteRegisterContext_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+#include "GDBRemoteCommunicationClient.h"
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+class StringExtractor;
+
+class GDBRemoteDynamicRegisterInfo
+{
+public:
+ GDBRemoteDynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_reg_names (),
+ m_reg_alt_names (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+ {
+ }
+
+ ~GDBRemoteDynamicRegisterInfo ()
+ {
+ }
+
+ void
+ AddRegister (lldb_private::RegisterInfo reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name)
+ {
+ const uint32_t reg_num = (uint32_t)m_regs.size();
+ m_reg_names.push_back (reg_name);
+ m_reg_alt_names.push_back (reg_alt_name);
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ uint32_t i;
+ if (reg_info.value_regs)
+ {
+ for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
+ m_value_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = m_value_regs_map[reg_num].data();
+ }
+ if (reg_info.invalidate_regs)
+ {
+ for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
+ m_invalidate_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = m_invalidate_regs_map[reg_num].data();
+ }
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+ }
+
+ void
+ Finalize ()
+ {
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+ }
+
+ size_t
+ GetNumRegisters() const
+ {
+ return m_regs.size();
+ }
+
+ size_t
+ GetNumRegisterSets() const
+ {
+ return m_sets.size();
+ }
+
+ size_t
+ GetRegisterDataByteSize() const
+ {
+ return m_reg_data_byte_size;
+ }
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const
+ {
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+ }
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const
+ {
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+ }
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name)
+ {
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return static_cast<uint32_t>(std::distance (m_set_names.begin(), pos));
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ lldb_private::RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return static_cast<uint32_t>(m_sets.size() - 1);
+ }
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+ {
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return static_cast<uint32_t>(std::distance (m_regs.begin(), pos));
+ }
+
+ return LLDB_INVALID_REGNUM;
+ }
+ void
+ Clear()
+ {
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_reg_names.clear();
+ m_reg_alt_names.clear();
+ m_set_names.clear();
+ }
+
+ void
+ HardcodeARMRegisters(bool from_scratch);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteRegisterContext can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+ typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_reg_names;
+ name_collection m_reg_alt_names;
+ name_collection m_set_names;
+ reg_to_regs_map m_value_regs_map;
+ reg_to_regs_map m_invalidate_regs_map;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+class GDBRemoteRegisterContext : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteRegisterContext (ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once);
+
+ virtual
+ ~GDBRemoteRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ 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);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+protected:
+ friend class ThreadGDBRemote;
+
+ bool
+ ReadRegisterBytes (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::DataExtractor &data);
+
+ bool
+ WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::DataExtractor &data,
+ uint32_t data_offset);
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg, StringExtractor &response);
+
+ void
+ SetAllRegisterValid (bool b);
+
+ bool
+ GetRegisterIsValid (uint32_t reg) const
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ return m_reg_valid[reg];
+ return false;
+ }
+
+ void
+ SetRegisterIsValid (const lldb_private::RegisterInfo *reg_info, bool valid)
+ {
+ if (reg_info)
+ return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid);
+ }
+
+ void
+ SetRegisterIsValid (uint32_t reg, bool valid)
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ m_reg_valid[reg] = valid;
+ }
+
+ void
+ SyncThreadState(lldb_private::Process *process); // Assumes the sequence mutex has already been acquired.
+
+ GDBRemoteDynamicRegisterInfo &m_reg_info;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+
+private:
+ // Helper function for ReadRegisterBytes().
+ bool GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+ // Helper function for WriteRegisterBytes().
+ bool SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+
+ //------------------------------------------------------------------
+ // For GDBRemoteRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
+};
+
+#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 000000000000..d27207f121d3
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,3291 @@
+//===-- ProcessGDBRemote.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"
+
+// C Includes
+#include <errno.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/mman.h> // for mmap
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
+#include "Utility/StringExtractorGDBRemote.h"
+#include "GDBRemoteRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+
+
+namespace lldb
+{
+ // Provide a function that can easily dump the packet history if we know a
+ // ProcessGDBRemote * value (which we can get from logs or from debugging).
+ // We need the function in the lldb namespace so it makes it into the final
+ // executable since the LLDB shared library only exports stuff in the lldb
+ // namespace. This allows you to attach with a debugger and call this
+ // function and get the packet history dumped to a file.
+ void
+ DumpProcessGDBRemotePacketHistory (void *p, const char *path)
+ {
+ lldb_private::StreamFile strm;
+ lldb_private::Error error (strm.GetFile().Open(path, lldb_private::File::eOpenOptionWrite | lldb_private::File::eOpenOptionCanCreate));
+ if (error.Success())
+ ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm);
+ }
+}
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+
+
+namespace {
+
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+ };
+
+ enum
+ {
+ ePropertyPacketTimeout
+ };
+
+ class PluginProperties : public Properties
+ {
+ public:
+
+ static ConstString
+ GetSettingName ()
+ {
+ return ProcessGDBRemote::GetPluginNameStatic();
+ }
+
+ PluginProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PluginProperties()
+ {
+ }
+
+ uint64_t
+ GetPacketTimeout()
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value);
+ }
+ };
+
+ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
+
+ static const ProcessKDPPropertiesSP &
+ GetGlobalPluginProperties()
+ {
+ static ProcessKDPPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PluginProperties ());
+ return g_settings_sp;
+ }
+
+} // anonymous namespace end
+
+static bool rand_initialized = false;
+
+// TODO Randomly assigning a port is unsafe. We should get an unused
+// ephemeral port from the kernel and make sure we reserve it before passing
+// it to debugserver.
+
+#if defined (__APPLE__)
+#define LOW_PORT (IPPORT_RESERVED)
+#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
+#else
+#define LOW_PORT (1024u)
+#define HIGH_PORT (49151u)
+#endif
+
+static inline uint16_t
+get_random_port ()
+{
+ if (!rand_initialized)
+ {
+ time_t seed = time(NULL);
+
+ rand_initialized = true;
+ srand(seed);
+ }
+ return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
+}
+
+
+lldb_private::ConstString
+ProcessGDBRemote::GetPluginNameStatic()
+{
+ static ConstString g_name("gdb-remote");
+ return g_name;
+}
+
+const char *
+ProcessGDBRemote::GetPluginDescriptionStatic()
+{
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void
+ProcessGDBRemote::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessGDBRemote::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset (new ProcessGDBRemote (target, listener));
+ return process_sp;
+}
+
+bool
+ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ Module *exe_module = target.GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ // We can't debug core files...
+ switch (exe_objfile->GetType())
+ {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeSharedLibrary:
+ case ObjectFile::eTypeStubLibrary:
+ return false;
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeUnknown:
+ break;
+ }
+ return exe_module->GetFileSpec().Exists();
+ }
+ // However, if there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+//----------------------------------------------------------------------
+// ProcessGDBRemote constructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_flags (0),
+ m_gdb_comm(false),
+ m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
+ m_last_stop_packet (),
+ m_last_stop_packet_mutex (Mutex::eMutexTypeNormal),
+ m_register_info (),
+ m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_async_thread_state(eAsyncThreadNotStarted),
+ m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
+ m_thread_ids (),
+ m_continue_c_tids (),
+ m_continue_C_tids (),
+ m_continue_s_tids (),
+ m_continue_S_tids (),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_max_memory_size (512),
+ m_addr_to_mmap_size (),
+ m_thread_create_bp_sp (),
+ m_waiting_for_attach (false),
+ m_destroy_tried_resuming (false),
+ m_command_sp ()
+{
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadDidExit, "async thread did exit");
+ const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_gdb_comm.SetPacketTimeout(timeout_seconds);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::~ProcessGDBRemote()
+{
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+
+ // The general Finalize is going to try to destroy the process and that SHOULD
+ // shut down the async thread. However, if we don't kill it it will get stranded and
+ // its connection will go away so when it wakes up it will crash. So kill it for sure here.
+ StopAsyncThread();
+ KillDebugserverProcess();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessGDBRemote::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessGDBRemote::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
+{
+ if (!force && m_register_info.GetNumRegisters() > 0)
+ return;
+
+ char packet[128];
+ m_register_info.Clear();
+ uint32_t reg_offset = 0;
+ uint32_t reg_num = 0;
+ for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
+ response_type == StringExtractorGDBRemote::eResponse;
+ ++reg_num)
+ {
+ const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ std::string name;
+ std::string value;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ reg_num, // GDB reg num
+ reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ reg_name.SetCString(value.c_str());
+ }
+ else if (name.compare("alt-name") == 0)
+ {
+ alt_name.SetCString(value.c_str());
+ }
+ else if (name.compare("bitsize") == 0)
+ {
+ reg_info.byte_size = Args::StringToUInt32(value.c_str(), 0, 0) / CHAR_BIT;
+ }
+ else if (name.compare("offset") == 0)
+ {
+ uint32_t offset = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (reg_offset != offset)
+ {
+ reg_offset = offset;
+ }
+ }
+ else if (name.compare("encoding") == 0)
+ {
+ const Encoding encoding = Args::StringToEncoding (value.c_str());
+ if (encoding != eEncodingInvalid)
+ reg_info.encoding = encoding;
+ }
+ else if (name.compare("format") == 0)
+ {
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.c_str(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value.compare("binary") == 0)
+ reg_info.format = eFormatBinary;
+ else if (value.compare("decimal") == 0)
+ reg_info.format = eFormatDecimal;
+ else if (value.compare("hex") == 0)
+ reg_info.format = eFormatHex;
+ else if (value.compare("float") == 0)
+ reg_info.format = eFormatFloat;
+ else if (value.compare("vector-sint8") == 0)
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value.compare("vector-uint8") == 0)
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value.compare("vector-sint16") == 0)
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value.compare("vector-uint16") == 0)
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value.compare("vector-sint32") == 0)
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value.compare("vector-uint32") == 0)
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value.compare("vector-float32") == 0)
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value.compare("vector-uint128") == 0)
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name.compare("set") == 0)
+ {
+ set_name.SetCString(value.c_str());
+ }
+ else if (name.compare("gcc") == 0)
+ {
+ reg_info.kinds[eRegisterKindGCC] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("dwarf") == 0)
+ {
+ reg_info.kinds[eRegisterKindDWARF] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("generic") == 0)
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str());
+ }
+ else if (name.compare("container-regs") == 0)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = value;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = Args::StringToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
+ if (reg != LLDB_INVALID_REGNUM)
+ value_regs.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ }
+ else if (name.compare("invalidate-regs") == 0)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = value;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = Args::StringToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
+ if (reg != LLDB_INVALID_REGNUM)
+ invalidate_regs.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ }
+ }
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
+ {
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
+ }
+ if (!invalidate_regs.empty())
+ {
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
+ }
+
+ m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // We didn't get anything if the accumulated reg_num is zero. See if we are
+ // debugging ARM and fill with a hard coded register set until we can get an
+ // updated debugserver down on the devices.
+ // On the other hand, if the accumulated reg_num is positive, see if we can
+ // add composite registers to the existing primordial ones.
+ bool from_scratch = (reg_num == 0);
+
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ // Use the process' architecture instead of the host arch, if available
+ ArchSpec remote_arch;
+ if (remote_process_arch.IsValid ())
+ remote_arch = remote_process_arch;
+ else
+ remote_arch = remote_host_arch;
+
+ if (!target_arch.IsValid())
+ {
+ if (remote_arch.IsValid()
+ && remote_arch.GetMachine() == llvm::Triple::arm
+ && remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+ else if (target_arch.GetMachine() == llvm::Triple::arm)
+ {
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+
+ // At this point, we can finalize our register info.
+ m_register_info.Finalize ();
+}
+
+Error
+ProcessGDBRemote::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
+{
+ Error error (WillLaunchOrAttach ());
+
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (remote_url);
+
+ if (error.Fail())
+ return error;
+ StartAsyncThread ();
+
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // We don't have a valid process ID, so note that we are connected
+ // and could now request to launch or attach, or get remote process
+ // listings...
+ SetPrivateState (eStateConnected);
+ }
+ else
+ {
+ // We have a valid process
+ SetID (pid);
+ GetThreadList();
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false))
+ {
+ const StateType state = SetThreadStopInfo (m_last_stop_packet);
+ if (state == eStateStopped)
+ {
+ SetPrivateState (state);
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state));
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
+ }
+
+ if (error.Success()
+ && !GetTarget().GetArchitecture().IsValid()
+ && m_gdb_comm.GetHostArchitecture().IsValid())
+ {
+ // Prefer the *process'* architecture over that of the *host*, if available.
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ else
+ GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+
+ return error;
+}
+
+Error
+ProcessGDBRemote::WillLaunchOrAttach ()
+{
+ Error error;
+ m_stdio_communication.Clear ();
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+
+ uint32_t launch_flags = launch_info.GetFlags().Get();
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+ const char *working_dir = launch_info.GetWorkingDirectory();
+
+ const ProcessLaunchInfo::FileAction *file_action;
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stdin_path = file_action->GetPath();
+ }
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stdout_path = file_action->GetPath();
+ }
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stderr_path = file_action->GetPath();
+ }
+
+ // ::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)
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ error = StartDebugserverProcess (host_port, launch_info);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("failed to start debugserver process: %s", error.AsCString());
+ return error;
+ }
+
+ error = ConnectToDebugserver (connect_url);
+ }
+
+ if (error.Success())
+ {
+ lldb_utility::PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // since 'O' packets can really slow down debugging if the inferior
+ // does a lot of output.
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp && platform_sp->IsHost() && !disable_stdio)
+ {
+ const char *slave_name = NULL;
+ if (stdin_path == NULL || stdout_path == NULL || stderr_path == NULL)
+ {
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
+ slave_name = pty.GetSlaveName (NULL, 0);
+ }
+ if (stdin_path == NULL)
+ stdin_path = slave_name;
+
+ if (stdout_path == NULL)
+ stdout_path = slave_name;
+
+ if (stderr_path == NULL)
+ stderr_path = slave_name;
+ }
+
+ // Set STDIN to /dev/null if we want STDIO disabled or if either
+ // STDOUT or STDERR have been set to something and STDIN hasn't
+ if (disable_stdio || (stdin_path == NULL && (stdout_path || stderr_path)))
+ stdin_path = "/dev/null";
+
+ // Set STDOUT to /dev/null if we want STDIO disabled or if either
+ // STDIN or STDERR have been set to something and STDOUT hasn't
+ if (disable_stdio || (stdout_path == NULL && (stdin_path || stderr_path)))
+ stdout_path = "/dev/null";
+
+ // Set STDERR to /dev/null if we want STDIO disabled or if either
+ // STDIN or STDOUT have been set to something and STDERR hasn't
+ if (disable_stdio || (stderr_path == NULL && (stdin_path || stdout_path)))
+ stderr_path = "/dev/null";
+
+ if (stdin_path)
+ m_gdb_comm.SetSTDIN (stdin_path);
+ if (stdout_path)
+ m_gdb_comm.SetSTDOUT (stdout_path);
+ if (stderr_path)
+ m_gdb_comm.SetSTDERR (stderr_path);
+
+ m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
+
+ m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
+
+ if (working_dir && working_dir[0])
+ {
+ m_gdb_comm.SetWorkingDir (working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ const Args &environment = launch_info.GetEnvironmentEntries();
+ if (environment.GetArgumentCount())
+ {
+ size_t num_environment_entries = environment.GetArgumentCount();
+ for (size_t i=0; i<num_environment_entries; ++i)
+ {
+ const char *env_entry = environment.GetArgumentAtIndex(i);
+ if (env_entry == NULL || m_gdb_comm.SendEnvironmentPacket(env_entry) != 0)
+ break;
+ }
+ }
+
+ const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10);
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector());
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID ());
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
+ }
+
+ m_gdb_comm.SetPacketTimeout (old_packet_timeout);
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ KillDebugserverProcess ();
+ return error;
+ }
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false))
+ {
+ SetPrivateState (SetThreadStopInfo (m_last_stop_packet));
+
+ if (!disable_stdio)
+ {
+ if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
+ SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor());
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ }
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s",
+ exe_module->GetFileSpec().GetFilename().AsCString(),
+ exe_module->GetArchitecture().GetArchitectureName());
+ }
+ return error;
+
+}
+
+
+Error
+ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
+{
+ Error error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected())
+ {
+ if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess)
+ {
+ m_gdb_comm.SetConnection (conn_ap.release());
+ break;
+ }
+ else if (error.WasInterrupted())
+ {
+ // If we were interrupted, don't keep retrying.
+ break;
+ }
+
+ retry_count++;
+
+ if (retry_count >= max_retry_count)
+ break;
+
+ usleep (100000);
+ }
+ }
+
+ if (!m_gdb_comm.IsConnected())
+ {
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ // We always seem to be able to open a connection to a local port
+ // so we need to make sure we can then send data to it. If we can't
+ // then we aren't actually connected to anything, so try and do the
+ // handshake with the remote GDB server and make sure that goes
+ // alright.
+ if (!m_gdb_comm.HandshakeWithServer (NULL))
+ {
+ m_gdb_comm.Disconnect();
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+ m_gdb_comm.ResetDiscoverableSettings();
+ m_gdb_comm.QueryNoAckModeSupported ();
+ m_gdb_comm.GetThreadSuffixSupported ();
+ m_gdb_comm.GetListThreadsInStopReplySupported ();
+ m_gdb_comm.GetHostInfo ();
+ m_gdb_comm.GetVContSupported ('c');
+ m_gdb_comm.GetVAttachOrWaitSupported();
+
+ size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
+ for (size_t idx = 0; idx < num_cmds; idx++)
+ {
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false);
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidLaunchOrAttach ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DidLaunch()");
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+
+ BuildDynamicRegisterInfo (false);
+
+ // See if the GDB server supports the qHostInfo information
+
+ ArchSpec gdb_remote_arch = m_gdb_comm.GetHostArchitecture();
+
+ // See if the GDB server supports the qProcessInfo packet, if so
+ // prefer that over the Host information as it will be more specific
+ // to our process.
+
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ gdb_remote_arch = m_gdb_comm.GetProcessArchitecture();
+
+ if (gdb_remote_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
+ // 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
+ // it has, so we really need to take the remote host architecture as our
+ // defacto architecture in this case.
+
+ if (gdb_remote_arch.GetMachine() == llvm::Triple::arm &&
+ gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ {
+ target_arch = gdb_remote_arch;
+ }
+ else
+ {
+ // Fill in what is missing in the triple
+ const llvm::Triple &remote_triple = gdb_remote_arch.GetTriple();
+ llvm::Triple &target_triple = target_arch.GetTriple();
+ if (target_triple.getVendorName().size() == 0)
+ {
+ target_triple.setVendor (remote_triple.getVendor());
+
+ if (target_triple.getOSName().size() == 0)
+ {
+ target_triple.setOS (remote_triple.getOS());
+
+ if (target_triple.getEnvironmentName().size() == 0)
+ target_triple.setEnvironment (remote_triple.getEnvironment());
+ }
+ }
+ }
+ }
+ else
+ {
+ // The target doesn't have a valid architecture yet, set it from
+ // the architecture we got from the remote GDB server
+ target_arch = gdb_remote_arch;
+ }
+ }
+ }
+}
+
+void
+ProcessGDBRemote::DidLaunch ()
+{
+ DidLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
+{
+ ProcessAttachInfo attach_info;
+ return DoAttachToProcessWithID(attach_pid, attach_info);
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ error = StartDebugserverProcess (host_port, attach_info);
+
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (connect_url);
+ }
+ }
+
+ if (error.Success())
+ {
+ 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;
+}
+
+size_t
+ProcessGDBRemote::AttachInputReaderCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ if (notification == eInputReaderGotToken)
+ {
+ ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton;
+ if (gdb_process->m_waiting_for_attach)
+ gdb_process->m_waiting_for_attach = false;
+ reader->SetIsDone(true);
+ return 1;
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+
+ if (process_name && process_name[0])
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ error = StartDebugserverProcess (host_port, attach_info);
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (connect_url);
+ }
+ }
+
+ if (error.Success())
+ {
+ StreamString packet;
+
+ if (wait_for_launch)
+ {
+ if (!m_gdb_comm.GetVAttachOrWaitSupported())
+ {
+ packet.PutCString ("vAttachWait");
+ }
+ else
+ {
+ if (attach_info.GetIgnoreExisting())
+ packet.PutCString("vAttachWait");
+ else
+ packet.PutCString ("vAttachOrWait");
+ }
+ }
+ else
+ packet.PutCString("vAttachName");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize()));
+
+ }
+ }
+ return error;
+}
+
+
+void
+ProcessGDBRemote::DidAttach ()
+{
+ DidLaunchOrAttach ();
+}
+
+
+Error
+ProcessGDBRemote::WillResume ()
+{
+ m_continue_c_tids.clear();
+ m_continue_C_tids.clear();
+ m_continue_s_tids.clear();
+ m_continue_S_tids.clear();
+ return Error();
+}
+
+Error
+ProcessGDBRemote::DoResume ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::Resume()");
+
+ Listener listener ("gdb-remote.resume-packet-sent");
+ if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent))
+ {
+ listener.StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit);
+
+ const size_t num_threads = GetThreadList().GetSize();
+
+ StreamString continue_packet;
+ bool continue_packet_error = false;
+ if (m_gdb_comm.HasAnyVContSupport ())
+ {
+ if (m_continue_c_tids.size() == num_threads)
+ {
+ // All threads are continuing, just send a "c" packet
+ continue_packet.PutCString ("c");
+ }
+ else
+ {
+ continue_packet.PutCString ("vCont");
+
+ if (!m_continue_c_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('c'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";c:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_C_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('C'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_s_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('s'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";s:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_S_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('S'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (continue_packet_error)
+ continue_packet.GetString().clear();
+ }
+ }
+ else
+ continue_packet_error = true;
+
+ if (continue_packet_error)
+ {
+ // Either no vCont support, or we tried to use part of the vCont
+ // packet that wasn't supported by the remote GDB server.
+ // We need to try and make a simple packet that can do our continue
+ const size_t num_continue_c_tids = m_continue_c_tids.size();
+ const size_t num_continue_C_tids = m_continue_C_tids.size();
+ const size_t num_continue_s_tids = m_continue_s_tids.size();
+ const size_t num_continue_S_tids = m_continue_S_tids.size();
+ if (num_continue_c_tids > 0)
+ {
+ if (num_continue_c_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 1 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is continuing
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front());
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ }
+
+ if (continue_packet_error && num_continue_C_tids > 0)
+ {
+ if ((num_continue_C_tids + num_continue_c_tids) == num_threads &&
+ num_continue_C_tids > 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ const int continue_signo = m_continue_C_tids.front().second;
+ // Only one thread is continuing
+ if (num_continue_C_tids > 1)
+ {
+ // More that one thread with a signal, yet we don't have
+ // vCont support and we are being asked to resume each
+ // thread with a signal, we need to make sure they are
+ // all the same signal, or we can't issue the continue
+ // accurately with the current support...
+ if (num_continue_C_tids > 1)
+ {
+ continue_packet_error = false;
+ for (size_t i=1; i<m_continue_C_tids.size(); ++i)
+ {
+ if (m_continue_C_tids[i].second != continue_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ }
+ else
+ {
+ // Set the continue thread ID
+ continue_packet_error = false;
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first);
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads continuing with the same signo...
+ continue_packet.Printf("C%2.2x", continue_signo);
+ }
+ }
+ }
+
+ if (continue_packet_error && num_continue_s_tids > 0)
+ {
+ if (num_continue_s_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.PutChar ('s');
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 1 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is stepping
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front());
+ continue_packet.PutChar ('s');
+ continue_packet_error = false;
+ }
+ }
+
+ if (!continue_packet_error && num_continue_S_tids > 0)
+ {
+ if (num_continue_S_tids == num_threads)
+ {
+ const int step_signo = m_continue_S_tids.front().second;
+ // Are all threads trying to step with the same signal?
+ continue_packet_error = false;
+ if (num_continue_S_tids > 1)
+ {
+ for (size_t i=1; i<num_threads; ++i)
+ {
+ if (m_continue_S_tids[i].second != step_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads stepping with the same signo...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.Printf("S%2.2x", step_signo);
+ }
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 1 )
+ {
+ // Only one thread is stepping with signal
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first);
+ continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second);
+ continue_packet_error = false;
+ }
+ }
+ }
+
+ if (continue_packet_error)
+ {
+ error.SetErrorString ("can't make continue packet for this resume");
+ }
+ else
+ {
+ EventSP event_sp;
+ TimeValue timeout;
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (5);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_async_thread))
+ {
+ error.SetErrorString ("Trying to resume but the async thread is dead.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead.");
+ return error;
+ }
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize()));
+
+ if (listener.WaitForEvent (&timeout, event_sp) == false)
+ {
+ error.SetErrorString("Resume timed out.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Resume timed out.");
+ }
+ else if (event_sp->BroadcasterIs (&m_async_broadcaster))
+ {
+ error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+void
+ProcessGDBRemote::ClearThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+}
+
+bool
+ProcessGDBRemote::UpdateThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ bool sequence_mutex_unavailable = false;
+ m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable);
+ if (sequence_mutex_unavailable)
+ {
+ return false; // We just didn't get the list
+ }
+ return true;
+}
+
+bool
+ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ size_t num_thread_ids = m_thread_ids.size();
+ // The "m_thread_ids" thread ID list should always be updated after each stop
+ // reply packet, but in case it isn't, update it here.
+ if (num_thread_ids == 0)
+ {
+ if (!UpdateThreadIDList ())
+ return false;
+ num_thread_ids = m_thread_ids.size();
+ }
+
+ ThreadList old_thread_list_copy(old_thread_list);
+ if (num_thread_ids > 0)
+ {
+ for (size_t i=0; i<num_thread_ids; ++i)
+ {
+ tid_t tid = m_thread_ids[i];
+ ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
+ if (!thread_sp)
+ {
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+ }
+ else
+ {
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+ }
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+
+ // Whatever that is left in old_thread_list_copy are not
+ // present in new_thread_list. Remove non-existent threads from internal id table.
+ size_t old_num_thread_ids = old_thread_list_copy.GetSize(false);
+ for (size_t i=0; i<old_num_thread_ids; i++)
+ {
+ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex (i, false));
+ if (old_thread_sp)
+ {
+ lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID();
+ m_thread_id_to_index_id_map.erase(old_thread_id);
+ }
+ }
+
+ return true;
+}
+
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
+{
+ stop_packet.SetFilePos (0);
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ // This is a bit of a hack, but is is required. If we did exec, we
+ // need to clear our thread lists and also know to rebuild our dynamic
+ // register info before we lookup and threads and populate the expedited
+ // register values so we need to know this right away so we can cleanup
+ // and update our registers.
+ const uint32_t stop_id = GetStopID();
+ if (stop_id == 0)
+ {
+ // Our first stop, make sure we have a process ID, and also make
+ // sure we know about our registers
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ SetID (pid);
+ }
+ BuildDynamicRegisterInfo (true);
+ }
+ // Stop with signal and thread info
+ const uint8_t signo = stop_packet.GetHexU8();
+ std::string name;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ ThreadSP thread_sp;
+ ThreadGDBRemote *gdb_thread = NULL;
+
+ while (stop_packet.GetNameColonValue(name, value))
+ {
+ if (name.compare("metype") == 0)
+ {
+ // exception type in big endian hex
+ exc_type = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("medata") == 0)
+ {
+ // exception data in big endian hex
+ exc_data.push_back(Args::StringToUInt64 (value.c_str(), 0, 16));
+ }
+ else if (name.compare("thread") == 0)
+ {
+ // thread in big endian hex
+ lldb::tid_t tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ // m_thread_list_real does have its own mutex, but we need to
+ // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
+ // and the m_thread_list_real.AddThread(...) so it doesn't change on us
+ Mutex::Locker locker (m_thread_list_real.GetMutex ());
+ thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
+
+ if (!thread_sp)
+ {
+ // Create the thread if we need to
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+
+ m_thread_list_real.AddThread(thread_sp);
+ }
+ gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+
+ }
+ else if (name.compare("threads") == 0)
+ {
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // A comma separated list of all threads in the current
+ // process that includes the thread for this stop reply
+ // packet
+ size_t comma_pos;
+ lldb::tid_t tid;
+ while ((comma_pos = value.find(',')) != std::string::npos)
+ {
+ value[comma_pos] = '\0';
+ // thread in big endian hex
+ tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ value.erase(0, comma_pos + 1);
+
+ }
+ tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ }
+ else if (name.compare("hexname") == 0)
+ {
+ StringExtractor name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ thread_name.swap (value);
+ }
+ else if (name.compare("name") == 0)
+ {
+ thread_name.swap (value);
+ }
+ else if (name.compare("qaddr") == 0)
+ {
+ thread_dispatch_qaddr = Args::StringToUInt64 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("reason") == 0)
+ {
+ reason.swap(value);
+ }
+ else if (name.compare("description") == 0)
+ {
+ StringExtractor desc_extractor;
+ // Swap "value" over into "name_extractor"
+ desc_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ desc_extractor.GetHexByteString (thread_name);
+ }
+ else if (name.size() == 2 && ::isxdigit(name[0]) && ::isxdigit(name[1]))
+ {
+ // We have a register number that contains an expedited
+ // register value. Lets supply this register to our thread
+ // so it won't have to go and read it.
+ if (gdb_thread)
+ {
+ uint32_t reg = Args::StringToUInt32 (name.c_str(), UINT32_MAX, 16);
+
+ if (reg != UINT32_MAX)
+ {
+ StringExtractor reg_value_extractor;
+ // Swap "value" over into "reg_value_extractor"
+ reg_value_extractor.GetStringRef().swap(value);
+ if (!gdb_thread->PrivateSetRegisterValue (reg, reg_value_extractor))
+ {
+ Host::SetCrashDescriptionWithFormat("Setting thread register '%s' (decoded to %u (0x%x)) with value '%s' for stop packet: '%s'",
+ name.c_str(),
+ reg,
+ reg,
+ reg_value_extractor.GetStringRef().c_str(),
+ stop_packet.GetStringRef().c_str());
+ }
+ }
+ }
+ }
+ }
+
+ if (thread_sp)
+ {
+ // Clear the stop info just in case we don't set it to anything
+ thread_sp->SetStopInfo (StopInfoSP());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ gdb_thread->SetName (thread_name.empty() ? NULL : thread_name.c_str());
+ if (exc_type != 0)
+ {
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
+ exc_type,
+ exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ }
+ else
+ {
+ bool handled = false;
+ bool did_exec = false;
+ if (!reason.empty())
+ {
+ if (reason.compare("trace") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ handled = true;
+ }
+ else if (reason.compare("breakpoint") == 0)
+ {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+
+ }
+ else if (reason.compare("trap") == 0)
+ {
+ // Let the trap just use the standard signal stop reason below...
+ }
+ else if (reason.compare("watchpoint") == 0)
+ {
+ break_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ // TODO: locate the watchpoint somehow...
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
+ handled = true;
+ }
+ else if (reason.compare("exception") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
+ handled = true;
+ }
+ else if (reason.compare("exec") == 0)
+ {
+ did_exec = true;
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
+ }
+ }
+
+ if (signo && did_exec == false)
+ {
+ if (signo == SIGTRAP)
+ {
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ handled = true;
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ else
+ {
+ // If we were stepping then assume the stop was the result of the trace. If we were
+ // not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ else
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo));
+ }
+ }
+ if (!handled)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo));
+ }
+
+ if (!description.empty())
+ {
+ lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ if (stop_info_sp)
+ {
+ stop_info_sp->SetDescription (description.c_str());
+ }
+ else
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ }
+ }
+ }
+ }
+ return eStateStopped;
+ }
+ break;
+
+ case 'W':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void
+ProcessGDBRemote::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // Set the thread stop info. It might have a "threads" key whose value is
+ // a list of all thread IDs in the current process, so m_thread_ids might
+ // get set.
+ SetThreadStopInfo (m_last_stop_packet);
+ // Check to see if SetThreadStopInfo() filled in m_thread_ids?
+ if (m_thread_ids.empty())
+ {
+ // No, we need to fetch the thread list manually
+ UpdateThreadIDList();
+ }
+
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list_real.RefreshStateAfterStop();
+
+}
+
+Error
+ProcessGDBRemote::DoHalt (bool &caused_stop)
+{
+ Error error;
+
+ bool timed_out = false;
+ Mutex::Locker locker;
+
+ if (m_public_state.GetValue() == eStateAttaching)
+ {
+ // We are being asked to halt during an attach. We need to just close
+ // our file handle and debugserver will go away, and we can be done...
+ m_gdb_comm.Disconnect();
+ }
+ else
+ {
+ if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out))
+ {
+ if (timed_out)
+ error.SetErrorString("timed out sending interrupt packet");
+ else
+ error.SetErrorString("unknown error sending interrupt packet");
+ }
+
+ caused_stop = m_gdb_comm.GetInterruptWasSent ();
+ }
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDetach(bool keep_stopped)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
+
+ DisableAllBreakpointSites ();
+
+ m_thread_list.DiscardThreadPlans();
+
+ error = m_gdb_comm.Detach (keep_stopped);
+ if (log)
+ {
+ if (error.Success())
+ log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully");
+ else
+ log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>");
+ }
+
+ if (!error.Success())
+ return error;
+
+ // Sleep for one second to let the process get all detached...
+ StopAsyncThread ();
+
+ SetPrivateState (eStateDetached);
+ ResumePrivateStateThread();
+
+ //KillDebugserverProcess ();
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDestroy ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy()");
+
+ // There is a bug in older iOS debugservers where they don't shut down the process
+ // they are debugging properly. If the process is sitting at a breakpoint or an exception,
+ // this can cause problems with restarting. So we check to see if any of our threads are stopped
+ // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN
+ // destroy it again.
+ //
+ // Note, we don't have a good way to test the version of debugserver, but I happen to know that
+ // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of
+ // the debugservers with this bug are equal. There really should be a better way to test this!
+ //
+ // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and
+ // get called here to destroy again and we're still at a breakpoint or exception, then we should
+ // just do the straight-forward kill.
+ //
+ // And of course, if we weren't able to stop the process by the time we get here, it isn't
+ // necessary (or helpful) to do any of this.
+
+ if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning)
+ {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+
+ // FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
+ if (platform_sp
+ && platform_sp->GetName()
+ && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic())
+ {
+ if (m_destroy_tried_resuming)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again.");
+ }
+ else
+ {
+ // At present, the plans are discarded and the breakpoints disabled Process::Destroy,
+ // but we really need it to happen here and it doesn't matter if we do it twice.
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+
+ bool stop_looks_like_crash = false;
+ ThreadList &threads = GetThreadList();
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason == eStopReasonBreakpoint
+ || reason == eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.",
+ thread_sp->GetProtocolID(),
+ stop_info_sp->GetDescription());
+ stop_looks_like_crash = true;
+ break;
+ }
+ }
+ }
+
+ if (stop_looks_like_crash)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill.");
+ m_destroy_tried_resuming = true;
+
+ // If we are going to run again before killing, it would be good to suspend all the threads
+ // before resuming so they won't get into more trouble. Sadly, for the threads stopped with
+ // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do
+ // have to run the risk of letting those threads proceed a bit.
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason != eStopReasonBreakpoint
+ && reason != eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.",
+ thread_sp->GetProtocolID());
+ thread_sp->SetResumeState(eStateSuspended);
+ }
+ }
+ }
+ Resume ();
+ return Destroy();
+ }
+ }
+ }
+ }
+
+ // Interrupt if our inferior is running...
+ int exit_status = SIGABRT;
+ std::string exit_string;
+
+ if (m_gdb_comm.IsConnected())
+ {
+ if (m_public_state.GetValue() != eStateAttaching)
+ {
+
+ StringExtractorGDBRemote response;
+ bool send_async = true;
+ const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3);
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async))
+ {
+ char packet_cmd = response.GetChar(0);
+
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ {
+ SetLastStopPacket (response);
+ ClearThreadIDList ();
+ exit_status = response.GetHexU8();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str());
+ exit_string.assign("got unexpected response to k packet: ");
+ exit_string.append(response.GetStringRef());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ exit_string.assign("failed to send the k packet");
+ }
+
+ m_gdb_comm.SetPacketTimeout(old_packet_timeout);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ exit_string.assign ("killed or interrupted while attaching.");
+ }
+ }
+ else
+ {
+ // If we missed setting the exit status on the way out, do it here.
+ // NB set exit status can be called multiple times, the first one sets the status.
+ exit_string.assign("destroying when not connected to debugserver");
+ }
+
+ SetExitStatus(exit_status, exit_string.c_str());
+
+ StopAsyncThread ();
+ KillDebugserverProcess ();
+ return error;
+}
+
+void
+ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
+{
+ lldb_private::Mutex::Locker locker (m_last_stop_packet_mutex);
+ const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos;
+ if (did_exec)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec");
+
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+ BuildDynamicRegisterInfo (true);
+ m_gdb_comm.ResetDiscoverableSettings();
+ }
+ m_last_stop_packet = response;
+}
+
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessGDBRemote::IsAlive ()
+{
+ return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited;
+}
+
+addr_t
+ProcessGDBRemote::GetImageInfoAddress()
+{
+ return m_gdb_comm.GetShlibInfoAddr();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true))
+ {
+ if (response.IsNormalResponse())
+ {
+ error.Clear();
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support reading memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet);
+ }
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ StreamString packet;
+ packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
+ packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true))
+ {
+ if (response.IsOKResponse())
+ {
+ error.Clear();
+ return size;
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support writing memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str());
+ }
+ return 0;
+}
+
+lldb::addr_t
+ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ case eLazyBoolYes:
+ allocated_addr = m_gdb_comm.AllocateMemory (size, permissions);
+ if (allocated_addr != LLDB_INVALID_ADDRESS || supported == eLazyBoolYes)
+ return allocated_addr;
+
+ case eLazyBoolNo:
+ // Call mmap() to create memory in the inferior..
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
+ m_addr_to_mmap_size[allocated_addr] = size;
+ else
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ break;
+ }
+
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions));
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Error
+ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
+ MemoryRegionInfo &region_info)
+{
+
+ Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num)
+{
+
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after)
+{
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after));
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ // We should never be deallocating memory without allocating memory
+ // first so we should never get eLazyBoolCalculate
+ error.SetErrorString ("tried to deallocate memory without ever allocating memory");
+ break;
+
+ case eLazyBoolYes:
+ if (!m_gdb_comm.DeallocateMemory (addr))
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ break;
+
+ case eLazyBoolNo:
+ // Call munmap() to deallocate memory in the inferior..
+ {
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ }
+ break;
+ }
+
+ return error;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
+{
+ if (m_stdio_communication.IsConnected())
+ {
+ ConnectionStatus status;
+ m_stdio_communication.Write(src, src_len, status, NULL);
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ user_id_t site_id = bp_site->GetID();
+ const addr_t addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ if (bp_site->HardwarePreferred())
+ {
+ // Try and set hardware breakpoint, and if that fails, fall through
+ // and set a software breakpoint?
+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eHardware);
+ return error;
+ }
+ }
+ }
+
+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ return error;
+ }
+ }
+
+ return EnableSoftwareBreakpoint (bp_site);
+ }
+
+ if (log)
+ {
+ const char *err_string = error.AsCString();
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite () error for breakpoint at 0x%8.8" PRIx64 ": %s",
+ bp_site->GetLoadAddress(),
+ err_string ? err_string : "NULL");
+ }
+ // We shouldn't reach here on a successful breakpoint enable...
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ addr_t addr = bp_site->GetLoadAddress();
+ user_id_t site_id = bp_site->GetID();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ switch (bp_type)
+ {
+ case BreakpointSite::eSoftware:
+ error = DisableSoftwareBreakpoint (bp_site);
+ break;
+
+ case BreakpointSite::eHardware:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
+ error.SetErrorToGenericError();
+ break;
+
+ case BreakpointSite::eExternal:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
+ error.SetErrorToGenericError();
+ break;
+ }
+ if (error.Success())
+ bp_site->SetEnabled(false);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+// Pre-requisite: wp != NULL.
+static GDBStoppointType
+GetGDBStoppointType (Watchpoint *wp)
+{
+ assert(wp);
+ bool watch_read = wp->WatchpointRead();
+ bool watch_write = wp->WatchpointWrite();
+
+ // watch_read and watch_write cannot both be false.
+ assert(watch_read || watch_write);
+ if (watch_read && watch_write)
+ return eWatchpointReadWrite;
+ else if (watch_read)
+ return eWatchpointRead;
+ else // Must be watch_write, then.
+ return eWatchpointWrite;
+}
+
+Error
+ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SupportsGDBStoppointPacket (type))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ else
+ error.SetErrorString("watchpoints not supported");
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+
+ addr_t addr = wp->GetLoadAddress();
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr);
+
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr);
+ // See also 'class WatchpointSentry' within StopInfo.cpp.
+ // This disabling attempt might come from the user-supplied actions, we'll route it in order for
+ // the watchpoint object to intelligently process this action.
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+void
+ProcessGDBRemote::Clear()
+{
+ m_flags = 0;
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+}
+
+Error
+ProcessGDBRemote::DoSignal (int signo)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo);
+
+ if (!m_gdb_comm.SendAsyncSignal (signo))
+ error.SetErrorStringWithFormat("failed to send signal %i", signo);
+ return error;
+}
+
+Error
+ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url)
+{
+ ProcessLaunchInfo launch_info;
+ return StartDebugserverProcess(debugserver_url, launch_info);
+}
+
+Error
+ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+{
+ Error error;
+ if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ ProcessLaunchInfo debugserver_launch_info;
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile();
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ debugserver_file_spec.SetFile (env_debugserver_path, false);
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
+ {
+ debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
+ debugserver_exists = debugserver_file_spec.Exists();
+ if (debugserver_exists)
+ {
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ m_stdio_communication.Clear();
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ Args &debugserver_args = debugserver_launch_info.GetArguments();
+ char arg_cstr[PATH_MAX];
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--native-regs");
+ // make debugserver run in its own session so signals generated by
+ // special terminal key sequences (^C) don't affect debugserver
+ debugserver_args.AppendArgument("--setsid");
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
+// debugserver_args.AppendArgument("--log-flags=0x802e0e");
+
+ // We currently send down all arguments, attach pids, or attach
+ // process names in dedicated GDB server packets, so we don't need
+ // to pass them as arguments. This is currently because of all the
+ // things we need to setup prior to launching: the environment,
+ // current working dir, file actions, etc.
+#if 0
+ // Now append the program arguments
+ if (inferior_argv)
+ {
+ // Terminate the debugserver args so we can now append the inferior args
+ debugserver_args.AppendArgument("--");
+
+ for (int i = 0; inferior_argv[i] != NULL; ++i)
+ debugserver_args.AppendArgument (inferior_argv[i]);
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
+ debugserver_args.AppendArgument (arg_cstr);
+ }
+ else if (attach_name && attach_name[0])
+ {
+ if (wait_for_launch)
+ debugserver_args.AppendArgument ("--waitfor");
+ else
+ debugserver_args.AppendArgument ("--attach");
+ debugserver_args.AppendArgument (attach_name);
+ }
+#endif
+
+ ProcessLaunchInfo::FileAction file_action;
+
+ // Close STDIN, STDOUT and STDERR. We might need to redirect them
+ // to "/dev/null" if we run into any problems.
+ file_action.Close (STDIN_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+ file_action.Close (STDOUT_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+ file_action.Close (STDERR_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+
+ if (log)
+ {
+ StreamString strm;
+ debugserver_args.Dump (&strm);
+ log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
+ }
+
+ debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
+ debugserver_launch_info.SetUserID(process_info.GetUserID());
+
+ error = Host::LaunchProcess(debugserver_launch_info);
+
+ if (error.Success ())
+ m_debugserver_pid = debugserver_launch_info.GetProcessID();
+ else
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (error.Fail() || log)
+ error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME);
+ }
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ StartAsyncThread ();
+ }
+ return error;
+}
+
+bool
+ProcessGDBRemote::MonitorDebugserverProcess
+(
+ void *callback_baton,
+ lldb::pid_t debugserver_pid,
+ bool exited, // True if the process did exit
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ // The baton is a "ProcessGDBRemote *". Now this class might be gone
+ // and might not exist anymore, so we need to carefully try to get the
+ // target for this process first since we have a race condition when
+ // we are done running between getting the notice that the inferior
+ // process has died and the debugserver that was debugging this process.
+ // In our test suite, we are also continually running process after
+ // process, so we must be very careful to make sure:
+ // 1 - process object hasn't been deleted already
+ // 2 - that a new process object hasn't been recreated in its place
+
+ // "debugserver_pid" argument passed in is the process ID for
+ // debugserver that we are tracking...
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton;
+
+ // Get a shared pointer to the target that has a matching process pointer.
+ // This target could be gone, or the target could already have a new process
+ // object inside of it
+ TargetSP target_sp (Debugger::FindTargetWithProcess(process));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", callback_baton, debugserver_pid, signo, signo, exit_status);
+
+ if (target_sp)
+ {
+ // We found a process in a target that matches, but another thread
+ // might be in the process of launching a new process that will
+ // soon replace it, so get a shared pointer to the process so we
+ // can keep it alive.
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ // Now we have a shared pointer to the process that can't go away on us
+ // so we now make sure it was the same as the one passed in, and also make
+ // sure that our previous "process *" didn't get deleted and have a new
+ // "process *" created in its place with the same pointer. To verify this
+ // we make sure the process has our debugserver process ID. If we pass all
+ // of these tests, then we are sure that this process is the one we were
+ // looking for.
+ if (process_sp && process == process_sp.get() && process->m_debugserver_pid == debugserver_pid)
+ {
+ // Sleep for a half a second to make sure our inferior process has
+ // time to set its exit status before we set it incorrectly when
+ // both the debugserver and the inferior process shut down.
+ usleep (500000);
+ // If our process hasn't yet exited, debugserver might have died.
+ // If the process did exit, the we are reaping it.
+ const StateType state = process->GetState();
+
+ if (process->m_debugserver_pid != LLDB_INVALID_PROCESS_ID &&
+ state != eStateInvalid &&
+ state != eStateUnloaded &&
+ state != eStateExited &&
+ state != eStateDetached)
+ {
+ char error_str[1024];
+ if (signo)
+ {
+ const char *signal_cstr = process->GetUnixSignals().GetSignalAsCString (signo);
+ if (signal_cstr)
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
+ else
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
+ }
+ else
+ {
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
+ }
+
+ process->SetExitStatus (-1, error_str);
+ }
+ // Debugserver has exited we need to let our ProcessGDBRemote
+ // know that it no longer has a debugserver instance
+ process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+ }
+ return true;
+}
+
+void
+ProcessGDBRemote::KillDebugserverProcess ()
+{
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::kill (m_debugserver_pid, SIGINT);
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+}
+
+void
+ProcessGDBRemote::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+
+ Log::Callbacks log_callbacks = {
+ ProcessGDBRemoteLog::DisableLog,
+ ProcessGDBRemoteLog::EnableLog,
+ ProcessGDBRemoteLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessGDBRemote::GetPluginNameStatic(), log_callbacks);
+ }
+}
+
+void
+ProcessGDBRemote::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin (debugger,
+ GetGlobalPluginProperties()->GetValueProperties(),
+ ConstString ("Properties for the gdb-remote process plug-in."),
+ is_global_setting);
+ }
+}
+
+bool
+ProcessGDBRemote::StartAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (m_async_thread_state == eAsyncThreadNotStarted)
+ {
+ // 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;
+ }
+}
+
+void
+ProcessGDBRemote::StopAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (m_async_thread_state == eAsyncThreadRunning)
+ {
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // This will shut down the async thread.
+ 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);
+ }
+}
+
+
+void *
+ProcessGDBRemote::AsyncThread (void *arg)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote*) arg;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID());
+
+ Listener listener ("ProcessGDBRemote::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit);
+
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID());
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_sp->BroadcasterIs (&process->m_async_broadcaster))
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type);
+
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+
+ if (continue_packet)
+ {
+ const char *continue_cstr = (const char *)continue_packet->GetBytes ();
+ const size_t continue_cstr_len = continue_packet->GetByteSize ();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr);
+
+ if (::strstr (continue_cstr, "vAttach") == NULL)
+ process->SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ // We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
+ // The thread ID list might be contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply packet to the process
+ // using the process->SetLastStopPacket()...
+ process->ClearThreadIDList ();
+
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->SetLastStopPacket (response);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ process->SetLastStopPacket (response);
+ process->ClearThreadIDList();
+ response.SetFilePos(1);
+ process->SetExitStatus(response.GetHexU8(), NULL);
+ done = true;
+ break;
+
+ case eStateInvalid:
+ process->SetExitStatus(-1, "lost connection");
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID());
+ done = true;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ else if (event_sp->BroadcasterIs (&process->m_gdb_comm))
+ {
+ if (event_type & Communication::eBroadcastBitReadThreadDidExit)
+ {
+ process->SetExitStatus (-1, "lost connection");
+ done = true;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID());
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID());
+
+ process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+ return NULL;
+}
+
+const char *
+ProcessGDBRemote::GetDispatchQueueNameForThread
+(
+ addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name
+)
+{
+ dispatch_queue_name.clear();
+ if (thread_dispatch_qaddr != 0 && thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ // Cache the dispatch_queue_offsets_addr value so we don't always have
+ // to look it up
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ {
+ static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
+ const Symbol *dispatch_queue_offsets_symbol = NULL;
+ ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
+ ModuleSP module_sp(GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+
+ if (dispatch_queue_offsets_symbol == NULL)
+ {
+ ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
+ module_sp = GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+ }
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_target);
+
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+ }
+
+ uint8_t memory_buffer[8];
+ DataExtractor data (memory_buffer,
+ sizeof(memory_buffer),
+ m_target.GetArchitecture().GetByteOrder(),
+ m_target.GetArchitecture().GetAddressByteSize());
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label; // in version 1-3, offset to string; in version 4+, offset to a pointer to a string
+ uint16_t dqo_label_size; // in version 1-3, length of string; in version 4+, size of a (void*) in this process
+ } dispatch_queue_offsets;
+
+
+ Error error;
+ if (ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ lldb::offset_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (ReadMemory (thread_dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ if (dispatch_queue_offsets.dqo_version >= 4)
+ {
+ // libdispatch versions 4+, pointer to dispatch name is in the
+ // queue structure.
+ lldb::addr_t pointer_to_label_address = queue_addr + dispatch_queue_offsets.dqo_label;
+ if (ReadMemory (pointer_to_label_address, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t label_addr = data.GetAddress(&data_offset);
+ ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
+ }
+ }
+ else
+ {
+ // libdispatch versions 1-3, dispatch name is a fixed width char array
+ // in the queue structure.
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ dispatch_queue_name.resize(dispatch_queue_offsets.dqo_label_size, '\0');
+ size_t bytes_read = ReadMemory (label_addr, &dispatch_queue_name[0], dispatch_queue_offsets.dqo_label_size, error);
+ if (bytes_read < dispatch_queue_offsets.dqo_label_size)
+ dispatch_queue_name.erase (bytes_read);
+ }
+ }
+ }
+ }
+ }
+ if (dispatch_queue_name.empty())
+ return NULL;
+ return dispatch_queue_name.c_str();
+}
+
+//uint32_t
+//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
+//{
+// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver
+// // process and ask it for the list of processes. But if we are local, we can let the Host do it.
+// if (m_local_debugserver)
+// {
+// return Host::ListProcessesMatchingName (name, matches, pids);
+// }
+// else
+// {
+// // FIXME: Implement talking to the remote debugserver.
+// return 0;
+// }
+//
+//}
+//
+bool
+ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ // I don't think I have to do anything here, just make sure I notice the new thread when it starts to
+ // run so I can stop it if that's what I want to do.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Hit New Thread Notification breakpoint.");
+ return false;
+}
+
+
+bool
+ProcessGDBRemote::StartNoticingNewThreads()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Enabled noticing new thread breakpoint.");
+ m_thread_create_bp_sp->SetEnabled(true);
+ }
+ else
+ {
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp)
+ {
+ m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(m_target);
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID());
+ m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to create new thread notification breakpoint.");
+ }
+ }
+ }
+ return m_thread_create_bp_sp.get() != NULL;
+}
+
+bool
+ProcessGDBRemote::StopNoticingNewThreads()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Disabling new thread notification breakpoint.");
+
+ if (m_thread_create_bp_sp)
+ m_thread_create_bp_sp->SetEnabled(false);
+
+ return true;
+}
+
+lldb_private::DynamicLoader *
+ProcessGDBRemote::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL));
+ return m_dyld_ap.get();
+}
+
+
+class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet history",
+ "Dumps the packet history buffer. ",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketHistory ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ process->GetGDBRemote().DumpHistory(result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet send",
+ "Send a custom packet through the GDB remote protocol and print the answer. "
+ "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketSend ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ for (size_t i=0; i<argc; ++ i)
+ {
+ const char *packet_cstr = command.GetArgumentAtIndex(0);
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ std::string &response_str = response.GetStringRef();
+
+ if (strstr(packet_cstr, "qGetProfileData") != NULL)
+ {
+ response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response);
+ }
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "process plugin packet monitor",
+ "Send a qRcmd packet through the GDB remote protocol and print the response."
+ "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketMonitor ()
+ {
+ }
+
+ bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ if (command == NULL || command[0] == '\0')
+ {
+ result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ StreamString packet;
+ packet.PutCString("qRcmd,");
+ packet.PutBytesAsRawHex8(command, strlen(command));
+ const char *packet_cstr = packet.GetString().c_str();
+
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ const std::string &response_str = response.GetStringRef();
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin packet",
+ "Commands that deal with GDB remote packets.",
+ NULL)
+ {
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter)));
+ LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter)));
+ LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter)));
+ }
+
+ ~CommandObjectProcessGDBRemotePacket ()
+ {
+ }
+};
+
+class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcessGDBRemote (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin",
+ "A set of commands for operating on a ProcessGDBRemote process.",
+ "process plugin <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessGDBRemote ()
+ {
+ }
+};
+
+CommandObject *
+ProcessGDBRemote::GetPluginCommandObject()
+{
+ if (!m_command_sp)
+ m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 000000000000..e104b7191eab
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,396 @@
+//===-- ProcessGDBRemote.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_ProcessGDBRemote_h_
+#define liblldb_ProcessGDBRemote_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "GDBRemoteCommunicationClient.h"
+#include "Utility/StringExtractor.h"
+#include "GDBRemoteRegisterContext.h"
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessGDBRemote(lldb_private::Target& target, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessGDBRemote();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target,
+ bool plugin_specified_by_name);
+
+ virtual lldb_private::CommandObject *
+ GetPluginCommandObject();
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ const lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
+
+ virtual lldb_private::Error
+ DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithName (const char *process_name,
+ bool wait_for_launch,
+ const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt (bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach (bool keep_stopped);
+
+ virtual bool
+ DetachRequiresHalt() { return true; }
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr,
+ lldb_private::MemoryRegionInfo &region_info);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after);
+
+ virtual bool
+ StartNoticingNewThreads();
+
+ virtual bool
+ StopNoticingNewThreads();
+
+ GDBRemoteCommunicationClient &
+ GetGDBRemote()
+ {
+ return m_gdb_comm;
+ }
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunicationClient;
+ friend class GDBRemoteRegisterContext;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ void
+ Clear ( );
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url);
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info);
+
+ void
+ KillDebugserverProcess ();
+
+ void
+ BuildDynamicRegisterInfo (bool force);
+
+ void
+ SetLastStopPacket (const StringExtractorGDBRemote &response);
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ 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;
+ 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::Mutex m_async_thread_state_mutex;
+ typedef std::vector<lldb::tid_t> tid_collection;
+ typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping
+ tid_collection m_continue_c_tids; // 'c' for continue
+ tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
+ tid_collection m_continue_s_tids; // 's' for step
+ tid_sig_collection m_continue_S_tids; // 'S' for step with signal
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ MMapMap m_addr_to_mmap_size;
+ lldb::BreakpointSP m_thread_create_bp_sp;
+ bool m_waiting_for_attach;
+ bool m_destroy_tried_resuming;
+ lldb::CommandObjectSP m_command_sp;
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+ static bool
+ MonitorDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signo,
+ int exit_status);
+
+ lldb::StateType
+ SetThreadStopInfo (StringExtractor& stop_packet);
+
+ void
+ ClearThreadIDList ();
+
+ bool
+ UpdateThreadIDList ();
+
+ void
+ DidLaunchOrAttach ();
+
+ lldb_private::Error
+ ConnectToDebugserver (const char *host_port);
+
+ const char *
+ GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name);
+
+ static size_t
+ AttachInputReaderCallback (void *baton,
+ lldb_private::InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessGDBRemote only
+ //------------------------------------------------------------------
+ static bool
+ NewThreadNotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote);
+
+};
+
+#endif // liblldb_ProcessGDBRemote_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 000000000000..15b861feaa82
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,196 @@
+//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessGDBRemoteLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_lob_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && log->GetMask().Get() & mask)
+ return log;
+ return NULL;
+}
+
+void
+ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+
+ }
+ }
+
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ else
+ log->GetMask().Reset (flag_bits);
+ }
+
+ return;
+}
+
+Log *
+ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = GDBR_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString());
+}
+
+
+void
+ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 000000000000..93734067f133
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,57 @@
+//===-- ProcessGDBRemoteLog.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_ProcessGDBRemoteLog_h_
+#define liblldb_ProcessGDBRemoteLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define GDBR_LOG_VERBOSE (1u << 0)
+#define GDBR_LOG_PROCESS (1u << 1)
+#define GDBR_LOG_THREAD (1u << 2)
+#define GDBR_LOG_PACKETS (1u << 3)
+#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define GDBR_LOG_BREAKPOINTS (1u << 7)
+#define GDBR_LOG_WATCHPOINTS (1u << 8)
+#define GDBR_LOG_STEP (1u << 9)
+#define GDBR_LOG_COMM (1u << 10)
+#define GDBR_LOG_ASYNC (1u << 11)
+#define GDBR_LOG_ALL (UINT32_MAX)
+#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+
+class ProcessGDBRemoteLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static lldb_private::Log *
+ GetLogIfAnyCategoryIsSet (uint32_t mask);
+
+ static void
+ DisableLog (const char **categories, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessGDBRemoteLog_h_
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 000000000000..38fb84d66ef3
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,214 @@
+//===-- ThreadGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadGDBRemote.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
+{
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process.GetID(),
+ GetID());
+}
+
+ThreadGDBRemote::~ThreadGDBRemote ()
+{
+ ProcessSP process_sp(GetProcess());
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID,
+ GetID());
+ DestroyThread();
+}
+
+const char *
+ThreadGDBRemote::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+
+const char *
+ThreadGDBRemote::GetQueueName ()
+{
+ // Always re-fetch the dispatch queue name since it can change
+
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ return gdb_process->GetDispatchQueueNameForThread (m_thread_dispatch_qaddr, m_dispatch_queue_name);
+ }
+ }
+ return NULL;
+}
+
+void
+ThreadGDBRemote::WillResume (StateType resume_state)
+{
+ int signo = GetResumeSignal();
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ if (log)
+ log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state));
+
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (gdb_process->GetUnixSignals().SignalIsValid (signo))
+ gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_c_tids.push_back(tid);
+ break;
+
+ case eStateStepping:
+ if (gdb_process->GetUnixSignals().SignalIsValid (signo))
+ gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_s_tids.push_back(tid);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void
+ThreadGDBRemote::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The GDBRemoteRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+}
+
+bool
+ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadGDBRemote::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadGDBRemote::ShouldStop (bool &step_more)
+{
+ return true;
+}
+lldb::RegisterContextSP
+ThreadGDBRemote::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ const bool read_all_registers_at_once = false;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+
+ if (concrete_frame_idx == 0)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once));
+ }
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get());
+ assert (gdb_reg_ctx);
+ return gdb_reg_ctx->PrivateSetRegisterValue (reg, response);
+}
+
+bool
+ThreadGDBRemote::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ StringExtractorGDBRemote stop_packet;
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ if (gdb_process->GetGDBRemote().GetThreadStopInfo(GetProtocolID(), stop_packet))
+ return gdb_process->SetThreadStopInfo (stop_packet) == eStateStopped;
+ }
+ return false;
+}
+
+
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 000000000000..50a3f19c6505
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,107 @@
+//===-- ThreadGDBRemote.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_ThreadGDBRemote_h_
+#define liblldb_ThreadGDBRemote_h_
+
+#include <string>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class StringExtractor;
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public lldb_private::Thread
+{
+public:
+ ThreadGDBRemote (lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadGDBRemote ();
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+protected:
+
+ friend class ProcessGDBRemote;
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg,
+ StringExtractor &response);
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+
+ void
+ SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
+
+ virtual bool
+ CalculateStopInfo ();
+
+
+};
+
+#endif // liblldb_ThreadGDBRemote_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 000000000000..06e87eab33ce
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,211 @@
+//===-- DWARFAbbreviationDeclaration.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFAbbreviationDeclaration.h"
+
+#include "lldb/Core/dwarf.h"
+
+#include "DWARFFormValue.h"
+
+using namespace lldb_private;
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() :
+ m_code (InvalidCode),
+ m_tag (0),
+ m_has_children (0),
+ m_attributes()
+{
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children) :
+ m_code (InvalidCode),
+ m_tag (tag),
+ m_has_children (has_children),
+ m_attributes()
+{
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, lldb::offset_t* offset_ptr)
+{
+ return Extract(data, offset_ptr, data.GetULEB128(offset_ptr));
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code)
+{
+ m_code = code;
+ m_attributes.clear();
+ if (m_code)
+ {
+ m_tag = data.GetULEB128(offset_ptr);
+ m_has_children = data.GetU8(offset_ptr);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ dw_attr_t attr = data.GetULEB128(offset_ptr);
+ dw_form_t form = data.GetULEB128(offset_ptr);
+
+ if (attr && form)
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ else
+ break;
+ }
+
+ return m_tag != 0;
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = 0;
+ }
+
+ return false;
+}
+
+
+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;
+}
+
+
+
+bool
+DWARFAbbreviationDeclaration::IsValid()
+{
+ return m_code != 0 && m_tag != 0;
+}
+
+
+void
+DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx)
+{
+ m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely.
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ switch (attr)
+ {
+ case DW_AT_location:
+ case DW_AT_frame_base:
+ // Only add these if they are location expressions (have a single
+ // value) and not location lists (have a lists of location
+ // expressions which are only valid over specific address ranges)
+ if (DWARFFormValue::IsBlockForm(form))
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ // Don't add these attributes
+ if (i >= idx)
+ break;
+ // Fall through and add attribute
+ default:
+ // Add anything that isn't address related
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+ }
+ }
+}
+
+void
+DWARFAbbreviationDeclaration::CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len
+)
+{
+ m_code = InvalidCode;
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+ lldb::offset_t offset = debug_info_offset;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ dw_offset_t attr_offset = offset;
+ DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
+
+ if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len))
+ m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp));
+ else
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ }
+}
+
+
+uint32_t
+DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const
+{
+ uint32_t i;
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (i = 0; i < kNumAttributes; ++i)
+ {
+ if (m_attributes[i].get_attr() == attr)
+ return i;
+ }
+ return DW_INVALID_INDEX;
+}
+
+
+bool
+DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& rhs) const
+{
+ return Tag() == rhs.Tag()
+ && HasChildren() == rhs.HasChildren()
+ && Attributes() == rhs.Attributes();
+}
+
+#if 0
+DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const
+{
+ out_buff.Append32_as_ULEB128(Code());
+ out_buff.Append32_as_ULEB128(Tag());
+ out_buff.Append8(HasChildren());
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (uint32_t i = 0; i < kNumAttributes; ++i)
+ {
+ out_buff.Append32_as_ULEB128(m_attributes[i].attr());
+ out_buff.Append32_as_ULEB128(m_attributes[i].form());
+ }
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+}
+#endif // 0
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
new file mode 100644
index 000000000000..f462b7fc108d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
@@ -0,0 +1,81 @@
+//===-- DWARFAbbreviationDeclaration.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_DWARFAbbreviationDeclaration_h_
+#define liblldb_DWARFAbbreviationDeclaration_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFAttribute.h"
+
+class DWARFCompileUnit;
+
+class DWARFAbbreviationDeclaration
+{
+public:
+ enum { InvalidCode = 0 };
+ DWARFAbbreviationDeclaration();
+
+ // For hand crafting an abbreviation declaration
+ DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children);
+ void AddAttribute(const DWARFAttribute& attr)
+ {
+ m_attributes.push_back(attr);
+ }
+
+ dw_uleb128_t Code() const { return m_code; }
+ void SetCode(dw_uleb128_t code) { m_code = code; }
+ dw_tag_t Tag() const { return m_tag; }
+ bool HasChildren() const { return m_has_children; }
+ size_t NumAttributes() const { return m_attributes.size(); }
+ dw_attr_t GetAttrByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_attr() : 0; }
+ dw_form_t GetFormByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_form() : 0; }
+ bool GetAttrAndFormByIndex(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ if (m_attributes.size() > idx)
+ {
+ m_attributes[idx].get(attr, form);
+ return true;
+ }
+ attr = form = 0;
+ return false;
+ }
+
+ // idx is assumed to be valid when calling GetAttrAndFormByIndexUnchecked()
+ void GetAttrAndFormByIndexUnchecked(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ m_attributes[idx].get(attr, form);
+ }
+ dw_form_t GetFormByIndexUnchecked (uint32_t idx) const
+ {
+ return m_attributes[idx].get_form();
+ }
+ void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx);
+ void CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const lldb_private::DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len);
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr);
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code);
+// void Append(BinaryStreamBuf& out_buff) const;
+ bool IsValid();
+ void Dump(lldb_private::Stream *s) const;
+ bool operator == (const DWARFAbbreviationDeclaration& rhs) const;
+// DWARFAttribute::collection& Attributes() { return m_attributes; }
+ const DWARFAttribute::collection& Attributes() const { return m_attributes; }
+protected:
+ dw_uleb128_t m_code;
+ dw_tag_t m_tag;
+ uint8_t m_has_children;
+ DWARFAttribute::collection m_attributes;
+};
+
+#endif // liblldb_DWARFAbbreviationDeclaration_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
new file mode 100644
index 000000000000..8310b1dda5f1
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
@@ -0,0 +1,45 @@
+//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFAttribute_h_
+#define SymbolFileDWARF_DWARFAttribute_h_
+
+#include "DWARFDefines.h"
+#include <vector>
+
+class DWARFAttribute
+{
+public:
+ DWARFAttribute(dw_attr_t attr, dw_form_t form) :
+ m_attr_form ( attr << 16 | form )
+ {
+ }
+
+ void set(dw_attr_t attr, dw_form_t form) { m_attr_form = (attr << 16) | form; }
+ void set_attr(dw_attr_t attr) { m_attr_form = (m_attr_form & 0x0000ffffu) | (attr << 16); }
+ void set_form(dw_form_t form) { m_attr_form = (m_attr_form & 0xffff0000u) | form; }
+ dw_attr_t get_attr() const { return m_attr_form >> 16; }
+ dw_form_t get_form() const { return (dw_form_t)m_attr_form; }
+ void get(dw_attr_t& attr, dw_form_t& form) const
+ {
+ register uint32_t attr_form = m_attr_form;
+ attr = attr_form >> 16;
+ form = (dw_form_t)attr_form;
+ }
+ bool operator == (const DWARFAttribute& rhs) const { return m_attr_form == rhs.m_attr_form; }
+ typedef std::vector<DWARFAttribute> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+protected:
+ uint32_t m_attr_form; // Upper 16 bits is attribute, lower 16 bits is form
+};
+
+
+#endif // SymbolFileDWARF_DWARFAttribute_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 000000000000..493b3af6ecd1
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,1027 @@
+//===-- DWARFCompileUnit.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFCompileUnit.h"
+
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+#include "NameToDIE.h"
+#include "SymbolFileDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+
+extern int g_verbose;
+
+DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) :
+ m_dwarf2Data (dwarf2Data),
+ m_abbrevs (NULL),
+ m_user_data (NULL),
+ m_die_array (),
+ m_func_aranges_ap (),
+ m_base_addr (0),
+ m_offset (DW_INVALID_OFFSET),
+ m_length (0),
+ m_version (0),
+ m_addr_size (DWARFCompileUnit::GetDefaultAddressSize()),
+ m_producer (eProducerInvalid),
+ m_producer_version_major (0),
+ m_producer_version_minor (0),
+ m_producer_version_update (0)
+{
+}
+
+void
+DWARFCompileUnit::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_length = 0;
+ m_version = 0;
+ m_abbrevs = NULL;
+ m_addr_size = DWARFCompileUnit::GetDefaultAddressSize();
+ m_base_addr = 0;
+ m_die_array.clear();
+ m_func_aranges_ap.reset();
+ m_user_data = NULL;
+ m_producer = eProducerInvalid;
+}
+
+bool
+DWARFCompileUnit::Extract(const DataExtractor &debug_info, lldb::offset_t *offset_ptr)
+{
+ Clear();
+
+ m_offset = *offset_ptr;
+
+ if (debug_info.ValidOffset(*offset_ptr))
+ {
+ dw_offset_t abbr_offset;
+ const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev();
+ m_length = debug_info.GetU32(offset_ptr);
+ m_version = debug_info.GetU16(offset_ptr);
+ abbr_offset = debug_info.GetU32(offset_ptr);
+ m_addr_size = debug_info.GetU8 (offset_ptr);
+
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr != NULL)
+ {
+ m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
+ return true;
+ }
+
+ // reset the offset to where we tried to parse from if anything went wrong
+ *offset_ptr = m_offset;
+ }
+
+ return false;
+}
+
+
+dw_offset_t
+DWARFCompileUnit::Extract(lldb::offset_t offset, const DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs)
+{
+ Clear();
+
+ m_offset = offset;
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ m_length = debug_info_data.GetU32(&offset);
+ m_version = debug_info_data.GetU16(&offset);
+ bool abbrevs_OK = debug_info_data.GetU32(&offset) == abbrevs->GetOffset();
+ m_abbrevs = abbrevs;
+ m_addr_size = debug_info_data.GetU8 (&offset);
+
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (version_OK && addr_size_OK && abbrevs_OK && debug_info_data.ValidOffset(offset))
+ return offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+void
+DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die)
+{
+ if (m_die_array.size() > 1)
+ {
+ // std::vectors never get any smaller when resized to a smaller size,
+ // or when clear() or erase() are called, the size will report that it
+ // is smaller, but the memory allocated remains intact (call capacity()
+ // to see this). So we need to create a temporary vector and swap the
+ // contents which will cause just the internal pointers to be swapped
+ // so that when "tmp_array" goes out of scope, it will destroy the
+ // contents.
+
+ // Save at least the compile unit DIE
+ DWARFDebugInfoEntry::collection tmp_array;
+ m_die_array.swap(tmp_array);
+ if (keep_compile_unit_die)
+ m_die_array.push_back(tmp_array.front());
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseCompileUnitDIEsIfNeeded
+//
+// Parses a compile unit and indexes its DIEs if it hasn't already been
+// done.
+//----------------------------------------------------------------------
+size_t
+DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only)
+{
+ const size_t initial_die_array_size = m_die_array.size();
+ if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1)
+ return 0; // Already parsed
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )",
+ m_offset,
+ cu_die_only);
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ lldb::offset_t offset = GetFirstDIEOffset();
+ lldb::offset_t next_cu_offset = GetNextCompileUnitOffset();
+
+ DWARFDebugInfoEntry die;
+ // Keep a flat array of the DIE for binary lookup by DIE offset
+ if (!cu_die_only)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS));
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log,
+ "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+ }
+
+ uint32_t depth = 0;
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ const DataExtractor& debug_info_data = m_dwarf2Data->get_debug_info_data();
+ std::vector<uint32_t> die_index_stack;
+ 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());
+ while (offset < next_cu_offset &&
+ die.FastExtract (debug_info_data, this, fixed_form_sizes, &offset))
+ {
+// if (log)
+// log->Printf("0x%8.8x: %*.*s%s%s",
+// die.GetOffset(),
+// depth * 2, depth * 2, "",
+// DW_TAG_value_to_name (die.Tag()),
+// die.HasChildren() ? " *" : "");
+
+ const bool null_die = die.IsNULL();
+ if (depth == 0)
+ {
+ uint64_t base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (base_addr == LLDB_INVALID_ADDRESS)
+ base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_entry_pc, 0);
+ SetBaseAddress (base_addr);
+ if (initial_die_array_size == 0)
+ AddDIE (die);
+ if (cu_die_only)
+ return 1;
+ }
+ else
+ {
+ if (null_die)
+ {
+ if (prev_die_had_children)
+ {
+ // This will only happen if a DIE says is has children
+ // but all it contains is a NULL tag. Since we are removing
+ // the NULL DIEs from the list (saves up to 25% in C++ code),
+ // we need a way to let the DIE know that it actually doesn't
+ // have children.
+ if (!m_die_array.empty())
+ m_die_array.back().SetEmptyChildren(true);
+ }
+ }
+ else
+ {
+ die.SetParentIndex(m_die_array.size() - die_index_stack[depth-1]);
+
+ if (die_index_stack.back())
+ m_die_array[die_index_stack.back()].SetSiblingIndex(m_die_array.size()-die_index_stack.back());
+
+ // Only push the DIE if it isn't a NULL DIE
+ m_die_array.push_back(die);
+ }
+ }
+
+ if (null_die)
+ {
+ // NULL DIE.
+ if (!die_index_stack.empty())
+ die_index_stack.pop_back();
+
+ if (depth > 0)
+ --depth;
+ if (depth == 0)
+ break; // We are done with this compile unit!
+
+ prev_die_had_children = false;
+ }
+ else
+ {
+ die_index_stack.back() = m_die_array.size() - 1;
+ // Normal DIE
+ const bool die_has_children = die.HasChildren();
+ if (die_has_children)
+ {
+ die_index_stack.push_back(0);
+ ++depth;
+ }
+ prev_die_had_children = die_has_children;
+ }
+ }
+
+ // Give a little bit of info if we encounter corrupt DWARF (our offset
+ // should always terminate at or before the start of the next compilation
+ // unit header).
+ if (offset > next_cu_offset)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning ("DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8" PRIx64 "\n",
+ GetOffset(),
+ offset);
+ }
+
+ // Since std::vector objects will double their size, we really need to
+ // make a new array with the perfect size so we don't end up wasting
+ // space. So here we copy and swap to make sure we don't have any extra
+ // memory taken up.
+
+ if (m_die_array.size () < m_die_array.capacity())
+ {
+ DWARFDebugInfoEntry::collection exact_size_die_array (m_die_array.begin(), m_die_array.end());
+ exact_size_die_array.swap (m_die_array);
+ }
+ Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE));
+ if (log)
+ {
+ StreamString strm;
+ DWARFDebugInfoEntry::DumpDIECollection (strm, m_die_array);
+ log->PutCString (strm.GetString().c_str());
+ }
+
+ return m_die_array.size();
+}
+
+
+dw_offset_t
+DWARFCompileUnit::GetAbbrevOffset() const
+{
+ return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET;
+}
+
+
+
+bool
+DWARFCompileUnit::Verify(Stream *s) const
+{
+ const DataExtractor& debug_info = m_dwarf2Data->get_debug_info_data();
+ bool valid_offset = debug_info.ValidOffset(m_offset);
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset());
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+ bool verbose = s->GetVerbose();
+ if (valid_offset && length_OK && version_OK && addr_size_OK && abbr_offset_OK)
+ {
+ if (verbose)
+ s->Printf(" 0x%8.8x: OK\n", m_offset);
+ return true;
+ }
+ else
+ {
+ s->Printf(" 0x%8.8x: ", m_offset);
+
+ m_dwarf2Data->get_debug_info_data().Dump (s, m_offset, lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, 0);
+ s->EOL();
+ if (valid_offset)
+ {
+ if (!length_OK)
+ s->Printf(" The length (0x%8.8x) for this compile unit is too large for the .debug_info provided.\n", m_length);
+ if (!version_OK)
+ s->Printf(" The 16 bit compile unit header version is not supported.\n");
+ if (!abbr_offset_OK)
+ s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) is not valid.\n", GetAbbrevOffset());
+ if (!addr_size_OK)
+ s->Printf(" The address size is unsupported: 0x%2.2x\n", m_addr_size);
+ }
+ else
+ s->Printf(" The start offset of the compile unit header in the .debug_info is invalid.\n");
+ }
+ return false;
+}
+
+
+void
+DWARFCompileUnit::Dump(Stream *s) const
+{
+ s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at {0x%8.8x})\n",
+ m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset());
+}
+
+
+static uint8_t g_default_addr_size = 4;
+
+uint8_t
+DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu)
+{
+ if (cu)
+ return cu->GetAddressByteSize();
+ return DWARFCompileUnit::GetDefaultAddressSize();
+}
+
+uint8_t
+DWARFCompileUnit::GetDefaultAddressSize()
+{
+ return g_default_addr_size;
+}
+
+void
+DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size)
+{
+ g_default_addr_size = addr_size;
+}
+
+void
+DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges,
+ bool clear_dies_if_already_not_parsed)
+{
+ // This function is usually called if there in no .debug_aranges section
+ // in order to produce a compile unit level set of address ranges that
+ // is accurate. If the DIEs weren't parsed, then we don't want all dies for
+ // all compile units to stay loaded when they weren't needed. So we can end
+ // up parsing the DWARF and then throwing them all away to keep memory usage
+ // down.
+ const bool clear_dies = ExtractDIEsIfNeeded (false) > 1;
+
+ const DWARFDebugInfoEntry* die = DIE();
+ if (die)
+ die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges);
+
+ if (debug_aranges->IsEmpty())
+ {
+ // We got nothing from the functions, maybe we have a line tables only
+ // situation. Check the line tables and build the arange table from this.
+ SymbolContext sc;
+ sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this);
+ if (sc.comp_unit)
+ {
+ SymbolFileDWARFDebugMap *debug_map_sym_file = m_dwarf2Data->GetDebugMapSymfile();
+ if (debug_map_sym_file == NULL)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table)
+ {
+ LineTable::FileAddressRanges file_ranges;
+ const bool append = true;
+ const size_t num_ranges = line_table->GetContiguousFileAddressRanges (file_ranges, append);
+ for (uint32_t idx=0; idx<num_ranges; ++idx)
+ {
+ const LineTable::FileAddressRanges::Entry &range = file_ranges.GetEntryRef(idx);
+ debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ }
+ }
+ }
+ else
+ debug_map_sym_file->AddOSOARanges(dwarf2Data,debug_aranges);
+ }
+ }
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ ClearDIEs (true);
+
+}
+
+
+const DWARFDebugAranges &
+DWARFCompileUnit::GetFunctionAranges ()
+{
+ if (m_func_aranges_ap.get() == NULL)
+ {
+ m_func_aranges_ap.reset (new DWARFDebugAranges());
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log,
+ "DWARFCompileUnit::GetFunctionAranges() for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+ const DWARFDebugInfoEntry* die = DIE();
+ if (die)
+ die->BuildFunctionAddressRangeTable (m_dwarf2Data, this, m_func_aranges_ap.get());
+ const bool minimize = false;
+ m_func_aranges_ap->Sort(minimize);
+ }
+ return *m_func_aranges_ap.get();
+}
+
+bool
+DWARFCompileUnit::LookupAddress
+(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die_handle,
+ DWARFDebugInfoEntry** block_die_handle
+)
+{
+ bool success = false;
+
+ if (function_die_handle != NULL && DIE())
+ {
+
+ const DWARFDebugAranges &func_aranges = GetFunctionAranges ();
+
+ // Re-check the aranges auto pointer contents in case it was created above
+ if (!func_aranges.IsEmpty())
+ {
+ *function_die_handle = GetDIEPtr(func_aranges.FindAddress(address));
+ if (*function_die_handle != NULL)
+ {
+ success = true;
+ if (block_die_handle != NULL)
+ {
+ DWARFDebugInfoEntry* child = (*function_die_handle)->GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, m_dwarf2Data, this, NULL, block_die_handle))
+ break;
+ child = child->GetSibling();
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtr()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtr(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset == (*pos).GetOffset())
+ return &(*pos);
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtrContainingOffset()
+//
+// Get the DIE (Debug Information Entry) that contains the specified
+// .debug_info offset.
+//----------------------------------------------------------------------
+const DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtrContainingOffset(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset >= (*pos).GetOffset())
+ {
+ DWARFDebugInfoEntry::iterator next = pos + 1;
+ if (next != end)
+ {
+ if (die_offset < (*next).GetOffset())
+ return &(*pos);
+ }
+ }
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+
+
+size_t
+DWARFCompileUnit::AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& dies, uint32_t depth) const
+{
+ size_t old_size = dies.Size();
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = m_die_array.begin(); pos != end; ++pos)
+ {
+ if (pos->Tag() == tag)
+ dies.Append (&(*pos));
+ }
+
+ // Return the number of DIEs added to the collection
+ return dies.Size() - old_size;
+}
+
+//void
+//DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx)
+//{
+// m_global_die_indexes.push_back (die_idx);
+//}
+//
+//
+//void
+//DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die)
+//{
+// // Indexes to all file level global and static variables
+// m_global_die_indexes;
+//
+// if (m_die_array.empty())
+// return;
+//
+// const DWARFDebugInfoEntry* first_die = &m_die_array[0];
+// const DWARFDebugInfoEntry* end = first_die + m_die_array.size();
+// if (first_die <= die && die < end)
+// m_global_die_indexes.push_back (die - first_die);
+//}
+
+
+void
+DWARFCompileUnit::Index (const uint32_t cu_idx,
+ NameToDIE& func_basenames,
+ NameToDIE& func_fullnames,
+ NameToDIE& func_methods,
+ NameToDIE& func_selectors,
+ NameToDIE& objc_class_selectors,
+ NameToDIE& globals,
+ NameToDIE& types,
+ NameToDIE& namespaces)
+{
+ const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data();
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize());
+
+ Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log,
+ "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator begin = m_die_array.begin();
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry &die = *pos;
+
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_namespace:
+ case DW_TAG_variable:
+ case DW_TAG_unspecified_type:
+ break;
+
+ default:
+ continue;
+ }
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled_cstr = NULL;
+ bool is_declaration = false;
+ //bool is_artificial = false;
+ bool has_address = false;
+ bool has_location = false;
+ bool is_global_or_static_variable = false;
+
+ dw_offset_t specification_die_offset = DW_INVALID_OFFSET;
+ const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ for (uint32_t i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_declaration:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ is_declaration = form_value.Unsigned() != 0;
+ break;
+
+// case DW_AT_artificial:
+// if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+// is_artificial = form_value.Unsigned() != 0;
+// break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ mangled_cstr = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ has_address = true;
+ break;
+
+ case DW_AT_entry_pc:
+ has_address = true;
+ break;
+
+ case DW_AT_location:
+ has_location = true;
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die.GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we dont want the performance
+ // penalty of that right now.
+ is_global_or_static_variable = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ is_global_or_static_variable = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+
+ case DW_AT_specification:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ specification_die_offset = form_value.Reference(this);
+ break;
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ if (has_address)
+ {
+ if (name)
+ {
+ // Note, this check is also done in ParseMethodName, but since this is a hot loop, we do the
+ // simple inlined check outside the call.
+ ObjCLanguageRuntime::MethodName objc_method(name, true);
+ if (objc_method.IsValid(true))
+ {
+ ConstString objc_class_name_with_category (objc_method.GetClassNameWithCategory());
+ ConstString objc_selector_name (objc_method.GetSelector());
+ ConstString objc_fullname_no_category_name (objc_method.GetFullNameWithoutCategory(true));
+ ConstString objc_class_name_no_category (objc_method.GetClassName());
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ if (objc_class_name_with_category)
+ objc_class_selectors.Insert(objc_class_name_with_category, die.GetOffset());
+ if (objc_class_name_no_category && objc_class_name_no_category != objc_class_name_with_category)
+ objc_class_selectors.Insert(objc_class_name_no_category, die.GetOffset());
+ if (objc_selector_name)
+ func_selectors.Insert (objc_selector_name, die.GetOffset());
+ if (objc_fullname_no_category_name)
+ func_fullnames.Insert (objc_fullname_no_category_name, die.GetOffset());
+ }
+ // If we have a mangled name, then the DW_AT_name attribute
+ // is usually the method name without the class or any parameters
+ const DWARFDebugInfoEntry *parent = die.GetParent();
+ bool is_method = false;
+ if (parent)
+ {
+ dw_tag_t parent_tag = parent->Tag();
+ if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type)
+ {
+ is_method = true;
+ }
+ else
+ {
+ if (specification_die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *specification_die = m_dwarf2Data->DebugInfo()->GetDIEPtr (specification_die_offset, NULL);
+ if (specification_die)
+ {
+ parent = specification_die->GetParent();
+ if (parent)
+ {
+ parent_tag = parent->Tag();
+
+ if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type)
+ is_method = true;
+ }
+ }
+ }
+ }
+ }
+
+
+ if (is_method)
+ func_methods.Insert (ConstString(name), die.GetOffset());
+ else
+ func_basenames.Insert (ConstString(name), die.GetOffset());
+
+ if (!is_method && !mangled_cstr && !objc_method.IsValid(true))
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ }
+ if (mangled_cstr)
+ {
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (name && ::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ if (has_address)
+ {
+ if (name)
+ func_basenames.Insert (ConstString(name), die.GetOffset());
+ if (mangled_cstr)
+ {
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ else
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_unspecified_type:
+ if (name && is_declaration == false)
+ {
+ types.Insert (ConstString(name), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_namespace:
+ if (name)
+ namespaces.Insert (ConstString(name), die.GetOffset());
+ break;
+
+ case DW_TAG_variable:
+ if (name && has_location && is_global_or_static_variable)
+ {
+ globals.Insert (ConstString(name), die.GetOffset());
+ // Be sure to include variables by their mangled and demangled
+ // names if they have any since a variable can have a basename
+ // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled
+ // mangled name "(anonymous namespace)::i"...
+
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (mangled_cstr && name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ globals.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ globals.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+}
+
+bool
+DWARFCompileUnit::Supports_unnamed_objc_bitfields ()
+{
+ if (GetProducer() == eProducerClang)
+ {
+ const uint32_t major_version = GetProducerVersionMajor();
+ if (major_version > 425 || (major_version == 425 && GetProducerVersionUpdate() >= 13))
+ return true;
+ else
+ return false;
+ }
+ return true; // Assume all other compilers didn't have incorrect ObjC bitfield info
+}
+
+bool
+DWARFCompileUnit::Supports_DW_AT_APPLE_objc_complete_type ()
+{
+ if (GetProducer() == eProducerLLVMGCC)
+ return false;
+ return true;
+}
+
+bool
+DWARFCompileUnit::DW_AT_decl_file_attributes_are_invalid()
+{
+ // llvm-gcc makes completely invalid decl file attributes and won't ever
+ // be fixed, so we need to know to ignore these.
+ return GetProducer() == eProducerLLVMGCC;
+}
+
+void
+DWARFCompileUnit::ParseProducerInfo ()
+{
+ m_producer_version_major = UINT32_MAX;
+ m_producer_version_minor = UINT32_MAX;
+ m_producer_version_update = UINT32_MAX;
+
+ const DWARFDebugInfoEntry *die = GetCompileUnitDIEOnly();
+ if (die)
+ {
+
+ const char *producer_cstr = die->GetAttributeValueAsString(m_dwarf2Data, this, DW_AT_producer, NULL);
+ if (producer_cstr)
+ {
+ RegularExpression llvm_gcc_regex("^4\\.[012]\\.[01] \\(Based on Apple Inc\\. build [0-9]+\\) \\(LLVM build [\\.0-9]+\\)$");
+ if (llvm_gcc_regex.Execute (producer_cstr))
+ {
+ m_producer = eProducerLLVMGCC;
+ }
+ else if (strstr(producer_cstr, "clang"))
+ {
+ static RegularExpression g_clang_version_regex("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)");
+ RegularExpression::Match regex_match(3);
+ if (g_clang_version_regex.Execute (producer_cstr, &regex_match))
+ {
+ std::string str;
+ if (regex_match.GetMatchAtIndex (producer_cstr, 1, str))
+ m_producer_version_major = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ if (regex_match.GetMatchAtIndex (producer_cstr, 2, str))
+ m_producer_version_minor = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ if (regex_match.GetMatchAtIndex (producer_cstr, 3, str))
+ m_producer_version_update = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ }
+ m_producer = eProducerClang;
+ }
+ else if (strstr(producer_cstr, "GNU"))
+ m_producer = eProducerGCC;
+ }
+ }
+ if (m_producer == eProducerInvalid)
+ m_producer = eProcucerOther;
+}
+
+DWARFCompileUnit::Producer
+DWARFCompileUnit::GetProducer ()
+{
+ if (m_producer == eProducerInvalid)
+ ParseProducerInfo ();
+ return m_producer;
+}
+
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionMajor()
+{
+ if (m_producer_version_major == 0)
+ ParseProducerInfo ();
+ return m_producer_version_major;
+}
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionMinor()
+{
+ if (m_producer_version_minor == 0)
+ ParseProducerInfo ();
+ return m_producer_version_minor;
+}
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionUpdate()
+{
+ if (m_producer_version_update == 0)
+ ParseProducerInfo ();
+ return m_producer_version_update;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
new file mode 100644
index 000000000000..9fee0a2d2236
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,210 @@
+//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFCompileUnit_h_
+#define SymbolFileDWARF_DWARFCompileUnit_h_
+
+#include "DWARFDebugInfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+class NameToDIE;
+
+class DWARFCompileUnit
+{
+public:
+ enum Producer
+ {
+ eProducerInvalid = 0,
+ eProducerClang,
+ eProducerGCC,
+ eProducerLLVMGCC,
+ eProcucerOther
+ };
+
+ DWARFCompileUnit(SymbolFileDWARF* dwarf2Data);
+
+ bool Extract(const lldb_private::DataExtractor &debug_info, lldb::offset_t *offset_ptr);
+ dw_offset_t Extract(lldb::offset_t offset, const lldb_private::DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs);
+ size_t ExtractDIEsIfNeeded (bool cu_die_only);
+ bool LookupAddress(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& matching_dies, uint32_t depth = UINT32_MAX) const;
+ void Clear();
+ 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 */ }
+ 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. */ }
+ uint32_t GetLength() const { return m_length; }
+ uint16_t GetVersion() const { return m_version; }
+ const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; }
+ dw_offset_t GetAbbrevOffset() const;
+ uint8_t GetAddressByteSize() const { return m_addr_size; }
+ dw_addr_t GetBaseAddress() const { return m_base_addr; }
+ void ClearDIEs(bool keep_compile_unit_die);
+ void BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges,
+ bool clear_dies_if_already_not_parsed);
+
+ void
+ SetBaseAddress(dw_addr_t base_addr)
+ {
+ m_base_addr = base_addr;
+ }
+
+ const DWARFDebugInfoEntry*
+ GetCompileUnitDIEOnly()
+ {
+ ExtractDIEsIfNeeded (true);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ const DWARFDebugInfoEntry*
+ DIE()
+ {
+ ExtractDIEsIfNeeded (false);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ void
+ AddDIE (DWARFDebugInfoEntry& die)
+ {
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so lets pre-reserve half of that since
+ // we are now stripping the NULL tags.
+
+ // Only reserve the memory if we are adding children of
+ // the main compile unit DIE. The compile unit DIE is always
+ // the first entry, so if our size is 1, then we are adding
+ // the first compile unit child DIE and should reserve
+ // the memory.
+ if (m_die_array.empty())
+ m_die_array.reserve(GetDebugInfoSize() / 24);
+ m_die_array.push_back(die);
+ }
+
+ bool
+ HasDIEsParsed () const
+ {
+ return m_die_array.size() > 1;
+ }
+
+ DWARFDebugInfoEntry*
+ GetDIEAtIndexUnchecked (uint32_t idx)
+ {
+ return &m_die_array[idx];
+ }
+
+ DWARFDebugInfoEntry*
+ GetDIEPtr (dw_offset_t die_offset);
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrContainingOffset (dw_offset_t die_offset);
+
+ static uint8_t
+ GetAddressByteSize(const DWARFCompileUnit* cu);
+
+ static uint8_t
+ GetDefaultAddressSize();
+
+ static void
+ SetDefaultAddressSize(uint8_t addr_size);
+
+ void *
+ GetUserData() const
+ {
+ return m_user_data;
+ }
+
+ void
+ SetUserData(void *d)
+ {
+ m_user_data = d;
+ }
+
+ bool
+ Supports_DW_AT_APPLE_objc_complete_type ();
+
+ bool
+ DW_AT_decl_file_attributes_are_invalid();
+
+ bool
+ Supports_unnamed_objc_bitfields ();
+
+// void
+// AddGlobalDIEByIndex (uint32_t die_idx);
+//
+// void
+// AddGlobal (const DWARFDebugInfoEntry* die);
+//
+ void
+ Index (const uint32_t cu_idx,
+ NameToDIE& func_basenames,
+ NameToDIE& func_fullnames,
+ NameToDIE& func_methods,
+ NameToDIE& func_selectors,
+ NameToDIE& objc_class_selectors,
+ NameToDIE& globals,
+ NameToDIE& types,
+ NameToDIE& namespaces);
+
+ const DWARFDebugAranges &
+ GetFunctionAranges ();
+
+ SymbolFileDWARF*
+ GetSymbolFileDWARF () const
+ {
+ return m_dwarf2Data;
+ }
+
+ Producer
+ GetProducer ();
+
+ uint32_t
+ GetProducerVersionMajor();
+
+ uint32_t
+ GetProducerVersionMinor();
+
+ uint32_t
+ GetProducerVersionUpdate();
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ const DWARFAbbreviationDeclarationSet *m_abbrevs;
+ void * m_user_data;
+ DWARFDebugInfoEntry::collection m_die_array; // The compile unit debug information entry item
+ 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;
+ 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;
+
+ void
+ ParseProducerInfo ();
+private:
+ DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit);
+};
+
+#endif // SymbolFileDWARF_DWARFCompileUnit_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
new file mode 100644
index 000000000000..1beb75d33642
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
@@ -0,0 +1,62 @@
+//===-- DWARFDIECollection.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDIECollection.h"
+
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFDebugInfoEntry.h"
+
+using namespace lldb_private;
+using namespace std;
+
+bool
+DWARFDIECollection::Insert(const DWARFDebugInfoEntry *die)
+{
+ iterator end_pos = m_dies.end();
+ iterator insert_pos = upper_bound(m_dies.begin(), end_pos, die);
+ if (insert_pos != end_pos && (*insert_pos == die))
+ return false;
+ m_dies.insert(insert_pos, die);
+ return true;
+}
+
+void
+DWARFDIECollection::Append (const DWARFDebugInfoEntry *die)
+{
+ m_dies.push_back (die);
+}
+
+const DWARFDebugInfoEntry *
+DWARFDIECollection::GetDIEPtrAtIndex(uint32_t idx) const
+{
+ if (idx < m_dies.size())
+ return m_dies[idx];
+ return NULL;
+}
+
+
+size_t
+DWARFDIECollection::Size() const
+{
+ return m_dies.size();
+}
+
+void
+DWARFDIECollection::Dump(Stream *s, const char* title) const
+{
+ if (title && title[0] != '\0')
+ s->Printf( "%s\n", title);
+ const_iterator end_pos = m_dies.end();
+ const_iterator pos;
+ for (pos = m_dies.begin(); pos != end_pos; ++pos)
+ s->Printf( "0x%8.8x\n", (*pos)->GetOffset());
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
new file mode 100644
index 000000000000..173d0a5604d0
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
@@ -0,0 +1,51 @@
+//===-- DWARFDIECollection.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDIECollection_h_
+#define SymbolFileDWARF_DWARFDIECollection_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class DWARFDIECollection
+{
+public:
+ DWARFDIECollection() :
+ m_dies()
+ {
+ }
+ ~DWARFDIECollection()
+ {
+ }
+
+ void
+ Append (const DWARFDebugInfoEntry *die);
+
+ void
+ Dump(lldb_private::Stream *s, const char* title) const;
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrAtIndex(uint32_t idx) const;
+
+ bool
+ Insert(const DWARFDebugInfoEntry *die);
+
+ size_t
+ Size() const;
+
+protected:
+ typedef std::vector<const DWARFDebugInfoEntry *> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_dies; // Ordered list of die offsets
+};
+
+
+#endif // SymbolFileDWARF_DWARFDIECollection_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 000000000000..47657d5089b2
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,202 @@
+//===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAbbrev.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Clear()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Clear()
+{
+ m_idx_offset = 0;
+ m_decls.clear();
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Extract()
+//----------------------------------------------------------------------
+bool
+DWARFAbbreviationDeclarationSet::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr)
+{
+ const lldb::offset_t begin_offset = *offset_ptr;
+ m_offset = begin_offset;
+ Clear();
+ DWARFAbbreviationDeclaration abbrevDeclaration;
+ dw_uleb128_t prev_abbr_code = 0;
+ while (abbrevDeclaration.Extract(data, offset_ptr))
+ {
+ m_decls.push_back(abbrevDeclaration);
+ if (m_idx_offset == 0)
+ m_idx_offset = abbrevDeclaration.Code();
+ else
+ {
+ if (prev_abbr_code + 1 != abbrevDeclaration.Code())
+ m_idx_offset = UINT32_MAX; // Out of order indexes, we can't do O(1) lookups...
+ }
+ prev_abbr_code = abbrevDeclaration.Code();
+ }
+ return begin_offset != *offset_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Dump()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Dump(Stream *s) const
+{
+ std::for_each (m_decls.begin(), m_decls.end(), bind2nd(std::mem_fun_ref(&DWARFAbbreviationDeclaration::Dump),s));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclaration*
+DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const
+{
+ if (m_idx_offset == UINT32_MAX)
+ {
+ DWARFAbbreviationDeclarationCollConstIter pos;
+ DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+ for (pos = m_decls.begin(); pos != end; ++pos)
+ {
+ if (pos->Code() == abbrCode)
+ return &(*pos);
+ }
+ }
+ else
+ {
+ uint32_t idx = abbrCode - m_idx_offset;
+ if (idx < m_decls.size())
+ return &m_decls[idx];
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential()
+//
+// Append an abbreviation declaration with a sequential code for O(n)
+// lookups. Handy when creating an DWARFAbbreviationDeclarationSet.
+//----------------------------------------------------------------------
+dw_uleb128_t
+DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl)
+{
+ // Get the next abbreviation code based on our current array size
+ dw_uleb128_t code = m_decls.size()+1;
+
+ // Push the new declaration on the back
+ m_decls.push_back(abbrevDecl);
+
+ // Update the code for this new declaration
+ m_decls.back().SetCode(code);
+
+ return code; // return the new abbreviation code!
+}
+
+
+//----------------------------------------------------------------------
+// Encode
+//
+// Encode the abbreviation table onto the end of the buffer provided
+// into a byte representation as would be found in a ".debug_abbrev"
+// debug information section.
+//----------------------------------------------------------------------
+//void
+//DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) const
+//{
+// DWARFAbbreviationDeclarationCollConstIter pos;
+// DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+// for (pos = m_decls.begin(); pos != end; ++pos)
+// pos->Append(debug_abbrev_buf);
+// debug_abbrev_buf.Append8(0);
+//}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev constructor
+//----------------------------------------------------------------------
+DWARFDebugAbbrev::DWARFDebugAbbrev() :
+ m_abbrevCollMap(),
+ m_prev_abbr_offset_pos(m_abbrevCollMap.end())
+{
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Parse()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Parse(const DataExtractor& data)
+{
+ lldb::offset_t offset = 0;
+
+ while (data.ValidOffset(offset))
+ {
+ uint32_t initial_cu_offset = offset;
+ DWARFAbbreviationDeclarationSet abbrevDeclSet;
+
+ if (abbrevDeclSet.Extract(data, &offset))
+ m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
+ else
+ break;
+ }
+ m_prev_abbr_offset_pos = m_abbrevCollMap.end();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Dump()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Dump(Stream *s) const
+{
+ if (m_abbrevCollMap.empty())
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos)
+ {
+ s->Printf("Abbrev table for offset: 0x%8.8x\n", pos->first);
+ pos->second.Dump(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const
+{
+ DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ if (m_prev_abbr_offset_pos != end && m_prev_abbr_offset_pos->first == cu_abbr_offset)
+ return &(m_prev_abbr_offset_pos->second);
+ else
+ {
+ pos = m_abbrevCollMap.find(cu_abbr_offset);
+ m_prev_abbr_offset_pos = pos;
+ }
+
+ if (pos != m_abbrevCollMap.end())
+ return &(pos->second);
+ return NULL;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
new file mode 100644
index 000000000000..eba439928a2c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
@@ -0,0 +1,74 @@
+//===-- DWARFDebugAbbrev.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugAbbrev_h_
+#define SymbolFileDWARF_DWARFDebugAbbrev_h_
+
+#include <list>
+#include <map>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+#include "DWARFAbbreviationDeclaration.h"
+
+typedef std::vector<DWARFAbbreviationDeclaration> DWARFAbbreviationDeclarationColl;
+typedef DWARFAbbreviationDeclarationColl::iterator DWARFAbbreviationDeclarationCollIter;
+typedef DWARFAbbreviationDeclarationColl::const_iterator DWARFAbbreviationDeclarationCollConstIter;
+
+
+class DWARFAbbreviationDeclarationSet
+{
+public:
+ DWARFAbbreviationDeclarationSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_idx_offset(0),
+ m_decls()
+ {
+ }
+
+ DWARFAbbreviationDeclarationSet(dw_offset_t offset, uint32_t idx_offset) :
+ m_offset(offset),
+ m_idx_offset(idx_offset),
+ m_decls()
+ {
+ }
+
+ void Clear();
+ dw_offset_t GetOffset() const { return m_offset; }
+ void Dump(lldb_private::Stream *s) const;
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr);
+ //void Encode(BinaryStreamBuf& debug_abbrev_buf) const;
+ dw_uleb128_t AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl);
+
+ const DWARFAbbreviationDeclaration* GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const;
+private:
+ dw_offset_t m_offset;
+ uint32_t m_idx_offset;
+ std::vector<DWARFAbbreviationDeclaration> m_decls;
+};
+
+typedef std::map<dw_offset_t, DWARFAbbreviationDeclarationSet> DWARFAbbreviationDeclarationCollMap;
+typedef DWARFAbbreviationDeclarationCollMap::iterator DWARFAbbreviationDeclarationCollMapIter;
+typedef DWARFAbbreviationDeclarationCollMap::const_iterator DWARFAbbreviationDeclarationCollMapConstIter;
+
+
+class DWARFDebugAbbrev
+{
+public:
+ DWARFDebugAbbrev();
+ const DWARFAbbreviationDeclarationSet* GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const;
+ void Dump(lldb_private::Stream *s) const;
+ void Parse(const lldb_private::DataExtractor& data);
+protected:
+ DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
+ mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugAbbrev_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 000000000000..b1eb27299efb
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,274 @@
+//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugArangeSet.h"
+
+#include <assert.h>
+#include "lldb/Core/Stream.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugArangeSet::DWARFDebugArangeSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_arange_descriptors()
+{
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+}
+
+void
+DWARFDebugArangeSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+ m_arange_descriptors.clear();
+}
+
+void
+DWARFDebugArangeSet::SetHeader
+(
+ uint16_t version,
+ uint32_t cu_offset,
+ uint8_t addr_size,
+ uint8_t seg_size
+)
+{
+ m_header.version = version;
+ m_header.cu_offset = cu_offset;
+ m_header.addr_size = addr_size;
+ m_header.seg_size = seg_size;
+}
+
+void
+DWARFDebugArangeSet::Compact()
+{
+ if (m_arange_descriptors.empty())
+ return;
+
+ // Iterate through all arange descriptors and combine any ranges that
+ // overlap or have matching boundaries. The m_arange_descriptors are assumed
+ // to be in ascending order after being built by adding descriptors
+ // using the AddDescriptor method.
+ uint32_t i = 0;
+ while (i + 1 < m_arange_descriptors.size())
+ {
+ if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i+1].address)
+ {
+ // The current range ends at or exceeds the start of the next address range.
+ // Compute the max end address between the two and use that to make the new
+ // length.
+ const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i+1].end_address());
+ m_arange_descriptors[i].length = max_end_addr - m_arange_descriptors[i].address;
+ // Now remove the next entry as it was just combined with the previous one.
+ m_arange_descriptors.erase(m_arange_descriptors.begin()+i+1);
+ }
+ else
+ {
+ // Discontiguous address range, just proceed to the next one.
+ ++i;
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Compare function DWARFDebugArangeSet::Descriptor structures
+//----------------------------------------------------------------------
+static bool DescriptorLessThan (const DWARFDebugArangeSet::Descriptor& range1, const DWARFDebugArangeSet::Descriptor& range2)
+{
+ return range1.address < range2.address;
+}
+
+//----------------------------------------------------------------------
+// Add a range descriptor and keep things sorted so we can easily
+// compact the ranges before being saved or used.
+//----------------------------------------------------------------------
+void
+DWARFDebugArangeSet::AddDescriptor(const DWARFDebugArangeSet::Descriptor& range)
+{
+ if (m_arange_descriptors.empty())
+ {
+ m_arange_descriptors.push_back(range);
+ return;
+ }
+
+ DescriptorIter end = m_arange_descriptors.end();
+ DescriptorIter pos = lower_bound(m_arange_descriptors.begin(), end, range, DescriptorLessThan);
+ const dw_addr_t range_end_addr = range.end_address();
+ if (pos != end)
+ {
+ const dw_addr_t found_end_addr = pos->end_address();
+ if (range.address < pos->address)
+ {
+ if (range_end_addr < pos->address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (range_end_addr == pos->address)
+ {
+ // The top end of 'range' is the lower end of the entry
+ // pointed to by 'pos'. We can combine range with the
+ // entry we found by setting the starting address and
+ // increasing the length since they don't overlap.
+ pos->address = range.address;
+ pos->length += range.length;
+ }
+ else
+ {
+ // We can combine these two and make sure the largest end
+ // address is used to make end address.
+ pos->address = range.address;
+ pos->length = std::max(found_end_addr, range_end_addr) - pos->address;
+ }
+ }
+ else if (range.address == pos->address)
+ {
+ pos->length = std::max(pos->length, range.length);
+ }
+ }
+ else
+ {
+ // NOTE: 'pos' points to entry past the end which is ok for insert,
+ // don't use otherwise!!!
+ const dw_addr_t max_addr = m_arange_descriptors.back().end_address();
+ if (max_addr < range.address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (max_addr == range.address)
+ {
+ m_arange_descriptors.back().length += range.length;
+ }
+ else
+ {
+ m_arange_descriptors.back().length = std::max(max_addr, range_end_addr) - m_arange_descriptors.back().address;
+ }
+ }
+}
+
+bool
+DWARFDebugArangeSet::Extract(const DataExtractor &data, lldb::offset_t *offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_arange_descriptors.clear();
+ m_offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header consisting of: a
+ // 4-byte length containing the length of the set of entries for this
+ // compilation unit, not including the length field itself; a 2-byte
+ // version identifier containing the value 2 for DWARF Version 2; a
+ // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+ // containing the size in bytes of an address (or the offset portion of
+ // an address for segmented addressing) on the target system; and a
+ // 1-byte unsigned integer containing the size in bytes of a segment
+ // descriptor on the target system. This header is followed by a series
+ // of tuples. Each tuple consists of an address and a length, each in
+ // the size appropriate for an address on the target architecture.
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.cu_offset = data.GetU32(offset_ptr);
+ m_header.addr_size = data.GetU8(offset_ptr);
+ m_header.seg_size = data.GetU8(offset_ptr);
+
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - m_offset;
+ const uint32_t tuple_size = m_header.addr_size << 1;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = m_offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length));
+ assert(sizeof(arangeDescriptor.address) >= m_header.addr_size);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
+ arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.address || arangeDescriptor.length)
+ m_arange_descriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+
+ return !m_arange_descriptors.empty();
+ }
+ return false;
+}
+
+
+dw_offset_t
+DWARFDebugArangeSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+
+void
+DWARFDebugArangeSet::Dump(Stream *s) const
+{
+ s->Printf("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+ m_header.length ,m_header.version, m_header.cu_offset, m_header.addr_size, m_header.seg_size);
+
+ const uint32_t hex_width = m_header.addr_size * 2;
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_arange_descriptors.end();
+ for (pos = m_arange_descriptors.begin(); pos != end; ++pos)
+ s->Printf("[0x%*.*" PRIx64 " - 0x%*.*" PRIx64 ")\n",
+ hex_width, hex_width, pos->address,
+ hex_width, hex_width, pos->end_address());
+}
+
+
+class DescriptorContainsAddress
+{
+public:
+ DescriptorContainsAddress (dw_addr_t address) : m_address(address) {}
+ bool operator() (const DWARFDebugArangeSet::Descriptor& desc) const
+ {
+ return (m_address >= desc.address) && (m_address < (desc.address + desc.length));
+ }
+ private:
+ const dw_addr_t m_address;
+};
+
+dw_offset_t
+DWARFDebugArangeSet::FindAddress(dw_addr_t address) const
+{
+ DescriptorConstIter end = m_arange_descriptors.end();
+ DescriptorConstIter pos = std::find_if( m_arange_descriptors.begin(), end, // Range
+ DescriptorContainsAddress(address));// Predicate
+ if (pos != end)
+ return m_header.cu_offset;
+
+ return DW_INVALID_OFFSET;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
new file mode 100644
index 000000000000..19ec8d042e72
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,76 @@
+//===-- DWARFDebugArangeSet.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugArangeSet_h_
+#define SymbolFileDWARF_DWARFDebugArangeSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class SymbolFileDWARF;
+
+class DWARFDebugArangeSet
+{
+public:
+ struct Header
+ {
+ uint32_t length; // The total length of the entries for that set, not including the length field itself.
+ uint16_t version; // The DWARF version number
+ uint32_t cu_offset; // The offset from the beginning of the .debug_info section of the compilation unit entry referenced by the table.
+ uint8_t addr_size; // The size in bytes of an address on the target architecture. For segmented addressing, this is the size of the offset portion of the address
+ uint8_t seg_size; // The size in bytes of a segment descriptor on the target architecture. If the target system uses a flat address space, this value is 0.
+ };
+
+ struct Descriptor
+ {
+ dw_addr_t address;
+ dw_addr_t length;
+ dw_addr_t end_address() const { return address + length; }
+ };
+
+
+ DWARFDebugArangeSet();
+ void Clear();
+ void SetOffset(uint32_t offset) { m_offset = offset; }
+ void SetHeader(uint16_t version, uint32_t cu_offset, uint8_t addr_size, uint8_t seg_size);
+ void AddDescriptor(const DWARFDebugArangeSet::Descriptor& range);
+ void Compact();
+ bool Extract(const lldb_private::DataExtractor &data, lldb::offset_t *offset_ptr);
+ void Dump(lldb_private::Stream *s) const;
+ dw_offset_t GetCompileUnitDIEOffset() const { return m_header.cu_offset; }
+ dw_offset_t GetOffsetOfNextEntry() const;
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ size_t NumDescriptors() const { return m_arange_descriptors.size(); }
+ const Header& GetHeader() const { return m_header; }
+ const Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_arange_descriptors.size())
+ return &m_arange_descriptors[i];
+ return NULL;
+ }
+
+ const Descriptor &
+ GetDescriptorRef (uint32_t i) const
+ {
+ return m_arange_descriptors[i];
+ }
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ uint32_t m_offset;
+ Header m_header;
+ DescriptorColl m_arange_descriptors;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugArangeSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 000000000000..3b004c4b3890
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,177 @@
+//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAranges.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugAranges::DWARFDebugAranges() :
+ m_aranges()
+{
+}
+
+//----------------------------------------------------------------------
+// CountArangeDescriptors
+//----------------------------------------------------------------------
+class CountArangeDescriptors
+{
+public:
+ CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
+ {
+// printf("constructor CountArangeDescriptors()\n");
+ }
+ void operator() (const DWARFDebugArangeSet& set)
+ {
+ count += set.NumDescriptors();
+ }
+ uint32_t& count;
+};
+
+
+//----------------------------------------------------------------------
+// Extract
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
+{
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ lldb::offset_t offset = 0;
+
+ DWARFDebugArangeSet set;
+ Range range;
+ while (set.Extract(debug_aranges_data, &offset))
+ {
+ const uint32_t num_descriptors = set.NumDescriptors();
+ if (num_descriptors > 0)
+ {
+ const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset();
+
+ for (uint32_t i=0; i<num_descriptors; ++i)
+ {
+ const DWARFDebugArangeSet::Descriptor &descriptor = set.GetDescriptorRef(i);
+ m_aranges.Append(RangeToDIE::Entry (descriptor.address, descriptor.length, cu_offset));
+ }
+ }
+ set.Clear();
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Generate
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
+{
+ Clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ const bool clear_dies_if_already_not_parsed = true;
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ if (cu)
+ cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
+ }
+ }
+ return !IsEmpty();
+}
+
+
+void
+DWARFDebugAranges::Dump (Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ const size_t num_entries = m_aranges.GetSize();
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
+ if (entry)
+ log->Printf ("0x%8.8x: [0x%" PRIx64 " - 0x%" PRIx64 ")",
+ entry->data,
+ entry->GetRangeBase(),
+ entry->GetRangeEnd());
+ }
+}
+
+void
+DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
+{
+ if (high_pc > low_pc)
+ m_aranges.Append(RangeToDIE::Entry (low_pc, high_pc - low_pc, offset));
+}
+
+void
+DWARFDebugAranges::Sort (bool minimize)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
+ __PRETTY_FUNCTION__, this);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+ size_t orig_arange_size = 0;
+ if (log)
+ {
+ orig_arange_size = m_aranges.GetSize();
+ log->Printf ("DWARFDebugAranges::Sort(minimize = %u) with %" PRIu64 " entries", minimize, (uint64_t)orig_arange_size);
+ }
+
+ m_aranges.Sort();
+ m_aranges.CombineConsecutiveEntriesWithEqualData();
+
+ if (log)
+ {
+ if (minimize)
+ {
+ const size_t new_arange_size = m_aranges.GetSize();
+ const size_t delta = orig_arange_size - new_arange_size;
+ log->Printf ("DWARFDebugAranges::Sort() %" PRIu64 " entries after minimizing (%" PRIu64 " entries combined for %" PRIu64 " bytes saved)",
+ (uint64_t)new_arange_size,
+ (uint64_t)delta,
+ (uint64_t)delta * sizeof(Range));
+ }
+ Dump (log);
+ }
+}
+
+//----------------------------------------------------------------------
+// FindAddress
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugAranges::FindAddress(dw_addr_t address) const
+{
+ const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address);
+ if (entry)
+ return entry->data;
+ return DW_INVALID_OFFSET;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
new file mode 100644
index 000000000000..88db929226ab
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,94 @@
+//===-- DWARFDebugAranges.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugAranges_h_
+#define SymbolFileDWARF_DWARFDebugAranges_h_
+
+#include "DWARFDebugArangeSet.h"
+#include <list>
+
+#include "lldb/Core/RangeMap.h"
+
+class SymbolFileDWARF;
+
+class DWARFDebugAranges
+{
+protected:
+ typedef lldb_private::RangeDataArray<dw_addr_t, uint32_t, dw_offset_t, 1> RangeToDIE;
+
+public:
+ typedef RangeToDIE::Entry Range;
+ typedef std::vector<RangeToDIE::Entry> RangeColl;
+
+ DWARFDebugAranges();
+
+ void
+ Clear()
+ {
+ m_aranges.Clear();
+ }
+
+ bool
+ Extract(const lldb_private::DataExtractor &debug_aranges_data);
+
+ bool
+ Generate(SymbolFileDWARF* dwarf2Data);
+
+ // Use append range multiple times and then call sort
+ void
+ AppendRange (dw_offset_t cu_offset,
+ dw_addr_t low_pc,
+ dw_addr_t high_pc);
+
+ void
+ Sort (bool minimize);
+
+ const Range*
+ RangeAtIndex(uint32_t idx) const
+ {
+ return m_aranges.GetEntryAtIndex (idx);
+ }
+
+ void
+ Dump (lldb_private::Log *log) const;
+
+ dw_offset_t
+ FindAddress(dw_addr_t address) const;
+
+ bool
+ IsEmpty() const
+ {
+ return m_aranges.IsEmpty();
+ }
+ size_t
+ GetNumRanges() const
+ {
+ return m_aranges.GetSize();
+ }
+
+ dw_offset_t
+ OffsetAtIndex(uint32_t idx) const
+ {
+ const Range *range = m_aranges.GetEntryAtIndex (idx);
+ if (range)
+ return range->data;
+ return DW_INVALID_OFFSET;
+ }
+
+ static void
+ Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s);
+
+protected:
+
+
+ RangeToDIE m_aranges;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugAranges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
new file mode 100644
index 000000000000..4c76eed8166f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -0,0 +1,797 @@
+//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+#include <algorithm>
+#include <set>
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugInfo::DWARFDebugInfo() :
+ m_dwarf2Data(NULL),
+ m_compile_units(),
+ m_cu_aranges_ap ()
+{
+}
+
+//----------------------------------------------------------------------
+// SetDwarfData
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data)
+{
+ m_dwarf2Data = dwarf2Data;
+ m_compile_units.clear();
+}
+
+
+DWARFDebugAranges &
+DWARFDebugInfo::GetCompileUnitAranges ()
+{
+ if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+
+ m_cu_aranges_ap.reset (new DWARFDebugAranges());
+ const DataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data();
+ if (debug_aranges_data.GetByteSize() > 0)
+ {
+ if (log)
+ log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges",
+ m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
+ m_cu_aranges_ap->Extract (debug_aranges_data);
+
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing",
+ m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
+ const size_t num_compile_units = GetNumCompileUnits();
+ const bool clear_dies_if_already_not_parsed = true;
+ for (size_t idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
+ if (cu)
+ cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed);
+ }
+ }
+
+ const bool minimize = true;
+ m_cu_aranges_ap->Sort (minimize);
+ }
+ return *m_cu_aranges_ap.get();
+}
+
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::LookupAddress
+(
+ const dw_addr_t address,
+ const dw_offset_t hint_die_offset,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+
+ if (hint_die_offset != DW_INVALID_OFFSET)
+ cu_sp = GetCompileUnit(hint_die_offset);
+ else
+ {
+ DWARFDebugAranges &cu_aranges = GetCompileUnitAranges ();
+ const dw_offset_t cu_offset = cu_aranges.FindAddress (address);
+ cu_sp = GetCompileUnit(cu_offset);
+ }
+
+ if (cu_sp.get())
+ {
+ if (cu_sp->LookupAddress(address, function_die, block_die))
+ return true;
+ cu_sp.reset();
+ }
+ else
+ {
+ // The hint_die_offset may have been a pointer to the actual item that
+ // we are looking for
+ DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp);
+ if (die_ptr)
+ {
+ if (cu_sp.get())
+ {
+ if (function_die || block_die)
+ return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die);
+
+ // We only wanted the compile unit that contained this address
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void
+DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded()
+{
+ if (m_compile_units.empty())
+ {
+ if (m_dwarf2Data != NULL)
+ {
+ lldb::offset_t offset = 0;
+ const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data();
+ while (debug_info_data.ValidOffset(offset))
+ {
+ DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data));
+ // Out of memory?
+ if (cu_sp.get() == NULL)
+ break;
+
+ if (cu_sp->Extract(debug_info_data, &offset) == false)
+ break;
+
+ m_compile_units.push_back(cu_sp);
+
+ offset = cu_sp->GetNextCompileUnitOffset();
+ }
+ }
+ }
+}
+
+size_t
+DWARFDebugInfo::GetNumCompileUnits()
+{
+ ParseCompileUnitHeadersIfNeeded();
+ return m_compile_units.size();
+}
+
+DWARFCompileUnit*
+DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx)
+{
+ DWARFCompileUnit* cu = NULL;
+ if (idx < GetNumCompileUnits())
+ cu = m_compile_units[idx].get();
+ return cu;
+}
+
+bool
+DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const
+{
+ // Not a verify efficient function, but it is handy for use in assertions
+ // to make sure that a compile unit comes from a debug information file.
+ CompileUnitColl::const_iterator end_pos = m_compile_units.end();
+ CompileUnitColl::const_iterator pos;
+
+ for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->get() == cu)
+ return true;
+ }
+ return false;
+}
+
+
+static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b)
+{
+ return a->GetOffset() < b->GetOffset();
+}
+
+
+static int
+CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem)
+{
+ const dw_offset_t key_cu_offset = *(dw_offset_t*) key;
+ const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset();
+ if (key_cu_offset < cu_offset)
+ return -1;
+ if (key_cu_offset > cu_offset)
+ return 1;
+ return 0;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr)
+{
+ DWARFCompileUnitSP cu_sp;
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset);
+ if (match)
+ {
+ cu_sp = *match;
+ cu_idx = match - &m_compile_units[0];
+ }
+ }
+ if (idx_ptr)
+ *idx_ptr = cu_idx;
+ return cu_sp;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset)
+{
+ DWARFCompileUnitSP cu_sp;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ CompileUnitColl::const_iterator end_pos = m_compile_units.end();
+ CompileUnitColl::const_iterator pos;
+
+ for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
+ {
+ dw_offset_t cu_start_offset = (*pos)->GetOffset();
+ dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset();
+ if (cu_start_offset <= die_offset && die_offset < cu_end_offset)
+ {
+ cu_sp = *pos;
+ break;
+ }
+ }
+ }
+ return cu_sp;
+}
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+
+//----------------------------------------------------------------------
+// GetDIE()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtr(die_offset);
+ return NULL; // Not found in any compile units
+}
+
+DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle)
+{
+ assert (cu_handle);
+ DWARFDebugInfoEntry* die = NULL;
+ if (*cu_handle)
+ die = (*cu_handle)->GetDIEPtr(die_offset);
+
+ if (die == NULL)
+ {
+ DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp.get())
+ {
+ *cu_handle = cu_sp.get();
+ die = cu_sp->GetDIEPtr(die_offset);
+ }
+ }
+ if (die == NULL)
+ *cu_handle = NULL;
+ return die;
+}
+
+
+const DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtrContainingOffset(die_offset);
+
+ return NULL; // Not found in any compile units
+
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugInfo_ParseCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets parses all compile units and DIE's into an internate
+// representation for further modification.
+//----------------------------------------------------------------------
+
+static dw_offset_t
+DWARFDebugInfo_ParseCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData;
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ cu->AddDIE(*die);
+ }
+ else if (cu)
+ {
+ debug_info->AddCompileUnit(cu_sp);
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// AddCompileUnit
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu)
+{
+ m_compile_units.push_back(cu);
+}
+
+/*
+void
+DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die)
+{
+ m_die_array.push_back(die);
+}
+*/
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parses the .debug_info section and uses the .debug_abbrev section
+// and various other sections in the SymbolFileDWARF class and calls the
+// supplied callback function each time a compile unit header, or debug
+// information entry is successfully parsed. This function can be used
+// for different tasks such as parsing the file contents into a
+// structured data, dumping, verifying and much more.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData)
+{
+ if (dwarf2Data)
+ {
+ lldb::offset_t offset = 0;
+ uint32_t depth = 0;
+ DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data));
+ if (cu.get() == NULL)
+ return;
+ DWARFDebugInfoEntry die;
+
+ while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset))
+ {
+ const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
+
+ depth = 0;
+ // Call the callback function with no DIE pointer for the compile unit
+ // and get the offset that we are to continue to parse from
+ offset = callback(dwarf2Data, cu, NULL, offset, depth, userData);
+
+ // Make sure we are within our compile unit
+ if (offset < next_cu_offset)
+ {
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ bool done = false;
+ while (!done && die.Extract(dwarf2Data, cu.get(), &offset))
+ {
+ // Call the callback function with DIE pointer that falls within the compile unit
+ offset = callback(dwarf2Data, cu, &die, offset, depth, userData);
+
+ if (die.IsNULL())
+ {
+ if (depth)
+ --depth;
+ else
+ done = true; // We are done with this compile unit!
+ }
+ else if (die.HasChildren())
+ ++depth;
+ }
+ }
+
+ // Make sure the offset returned is valid, and if not stop parsing.
+ // Returning DW_INVALID_OFFSET from this callback is a good way to end
+ // all parsing
+ if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
+ break;
+
+ // See if during the callback anyone retained a copy of the compile
+ // unit other than ourselves and if so, let whomever did own the object
+ // and create a new one for our own use!
+ if (!cu.unique())
+ cu.reset(new DWARFCompileUnit(dwarf2Data));
+
+
+ // Make sure we start on a proper
+ offset = next_cu_offset;
+ }
+ }
+}
+
+typedef struct DumpInfo
+{
+ DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
+ strm(init_strm),
+ die_offset(off),
+ recurse_depth(depth),
+ found_depth(UINT32_MAX),
+ found_die(false),
+ ancestors()
+ {
+ }
+ Stream* strm;
+ const uint32_t die_offset;
+ const uint32_t recurse_depth;
+ uint32_t found_depth;
+ bool found_die;
+ std::vector<DWARFDebugInfoEntry> ancestors;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpInfo);
+} DumpInfo;
+
+//----------------------------------------------------------------------
+// DumpCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function dump DWARF information and obey recurse depth and
+// whether a single DIE is to be dumped (or all of the data).
+//----------------------------------------------------------------------
+static dw_offset_t DumpCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DumpInfo* dumpInfo = (DumpInfo*)userData;
+
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ Stream *s = dumpInfo->strm;
+ bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors);
+
+ if (die)
+ {
+ // Are we dumping everything?
+ if (dumpInfo->die_offset == DW_INVALID_OFFSET)
+ {
+ // Yes we are dumping everything. Obey our recurse level though
+ if (curr_depth < dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, *s, 0);
+ }
+ else
+ {
+ // We are dumping a specific DIE entry by offset
+ if (dumpInfo->die_offset == die->GetOffset())
+ {
+ // We found the DIE we were looking for, dump it!
+ if (show_parents)
+ {
+ s->SetIndentLevel(0);
+ const uint32_t num_ancestors = dumpInfo->ancestors.size();
+ if (num_ancestors > 0)
+ {
+ for (uint32_t i=0; i<num_ancestors-1; ++i)
+ {
+ dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0);
+ s->IndentMore();
+ }
+ }
+ }
+
+ dumpInfo->found_depth = curr_depth;
+
+ die->Dump(dwarf2Data, cu, *s, 0);
+
+ // Note that we found the DIE we were looking for
+ dumpInfo->found_die = true;
+
+ // Since we are dumping a single DIE, if there are no children we are done!
+ if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
+ return DW_INVALID_OFFSET; // Return an invalid address to end parsing
+ }
+ else if (dumpInfo->found_die)
+ {
+ // Are we done with all the children?
+ if (curr_depth <= dumpInfo->found_depth)
+ return DW_INVALID_OFFSET;
+
+ // We have already found our DIE and are printing it's children. Obey
+ // our recurse depth and return an invalid offset if we get done
+ // dumping all the the children
+ if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, *s, 0);
+ }
+ else if (dumpInfo->die_offset > die->GetOffset())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.back() = *die;
+ }
+ }
+
+ // Keep up with our indent level
+ if (die->IsNULL())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.pop_back();
+
+ if (curr_depth <= 1)
+ return cu->GetNextCompileUnitOffset();
+ else
+ s->IndentLess();
+ }
+ else if (die->HasChildren())
+ {
+ if (show_parents)
+ {
+ DWARFDebugInfoEntry null_die;
+ dumpInfo->ancestors.push_back(null_die);
+ }
+ s->IndentMore();
+ }
+ }
+ else
+ {
+ if (cu == NULL)
+ s->PutCString("NULL - cu");
+ // We have a compile unit, reset our indent level to zero just in case
+ s->SetIndentLevel(0);
+
+ // See if we are dumping everything?
+ 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
+ }
+ else
+ {
+ if (show_parents)
+ {
+ dumpInfo->ancestors.clear();
+ dumpInfo->ancestors.resize(1);
+ }
+
+ // 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())
+ {
+ // Not found, maybe the DIE offset provided wasn't correct?
+ // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
+ return DW_INVALID_OFFSET;
+ }
+ else
+ {
+ // See if the DIE is in this compile unit?
+ if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
+ {
+ // This DIE is in this compile unit!
+ if (s->GetVerbose())
+ cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
+
+ return next_offset;
+ // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE...
+ // return dumpInfo->die_offset;
+ }
+ else
+ {
+ // Skip to the next compile unit as the DIE isn't in the current one!
+ return cu->GetNextCompileUnitOffset();
+ }
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the information in the .debug_info section to the specified
+// ostream. If die_offset is valid, a single DIE will be dumped. If the
+// die_offset is invalid, all the DWARF information will be dumped. Both
+// cases will obey a "recurse_depth" or how deep to traverse into the
+// children of each DIE entry. A recurse_depth of zero will dump all
+// compile unit headers. A recurse_depth of 1 will dump all compile unit
+// headers and the DW_TAG_compile unit tags. A depth of 2 will also
+// dump all types and functions.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump
+(
+ Stream *s,
+ SymbolFileDWARF* dwarf2Data,
+ const uint32_t die_offset,
+ const uint32_t recurse_depth
+)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+ s->PutCString(".debug_info contents");
+ if (dwarf2Data->get_debug_info_data().GetByteSize() > 0)
+ {
+ if (die_offset == DW_INVALID_OFFSET)
+ s->PutCString(":\n");
+ else
+ {
+ s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
+ if (recurse_depth != UINT32_MAX)
+ s->Printf(" recursing %u levels deep.", recurse_depth);
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString(": < EMPTY >\n");
+ return;
+ }
+ DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
+}
+
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the contents of this DWARFDebugInfo object as has been parsed
+// and/or modified after it has been parsed.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+
+ s->PutCString("Dumping .debug_info section from internal representation\n");
+
+ CompileUnitColl::const_iterator pos;
+ uint32_t curr_depth = 0;
+ ParseCompileUnitHeadersIfNeeded();
+ for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos)
+ {
+ const DWARFCompileUnitSP& cu_sp = *pos;
+ DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo);
+
+ const DWARFDebugInfoEntry* die = cu_sp->DIE();
+ if (die)
+ die->Dump(m_dwarf2Data, cu_sp.get(), *s, recurse_depth);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// FindCallbackString
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function will find the die_offset of any items whose DW_AT_name
+// matches the given string
+//----------------------------------------------------------------------
+typedef struct FindCallbackStringInfoTag
+{
+ const char* name;
+ bool ignore_case;
+ RegularExpression* regex;
+ vector<dw_offset_t>& die_offsets;
+} FindCallbackStringInfo;
+
+static dw_offset_t FindCallbackString
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData;
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ if (die)
+ {
+ const char* die_name = die->GetName(dwarf2Data, cu);
+ if (die_name)
+ {
+ if (info->regex)
+ {
+ if (info->regex->Execute(die_name))
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ else
+ {
+ if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0)
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the entire name
+// and case sensitive searches are an option.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ if (name && name[0])
+ {
+ FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ }
+ return !die_offsets.empty();
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the supplied regular
+// expression.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ FindCallbackStringInfo info = { NULL, false, &re, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
new file mode 100644
index 000000000000..50a7ae76921f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -0,0 +1,89 @@
+//===-- DWARFDebugInfo.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugInfo_h_
+#define SymbolFileDWARF_DWARFDebugInfo_h_
+
+#include <vector>
+#include <map>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-private.h"
+#include "SymbolFileDWARF.h"
+
+typedef std::multimap<const char*, dw_offset_t, CStringCompareFunctionObject> CStringToDIEMap;
+typedef CStringToDIEMap::iterator CStringToDIEMapIter;
+typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter;
+
+typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP;
+
+class DWARFDebugInfo
+{
+public:
+ typedef dw_offset_t (*Callback)(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t depth,
+ void* userData);
+
+ DWARFDebugInfo();
+ void SetDwarfData(SymbolFileDWARF* dwarf2Data);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ const dw_offset_t cu_offset, // Can be valid (find in .debug_aranges), or DW_INVALID_OFFSET if we need to search manually
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ void AddCompileUnit(DWARFCompileUnitSP& cu);
+ size_t GetNumCompileUnits();
+ bool ContainsCompileUnit (const DWARFCompileUnit *cu) const;
+ DWARFCompileUnit* GetCompileUnitAtIndex(uint32_t idx);
+ DWARFCompileUnitSP GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr = NULL);
+ DWARFCompileUnitSP GetCompileUnitContainingDIE(dw_offset_t die_offset);
+
+ DWARFDebugInfoEntry* GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+ DWARFDebugInfoEntry* GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle);
+
+ const DWARFDebugInfoEntry* GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+
+ void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth);
+ static void Parse(SymbolFileDWARF* parser, Callback callback, void* userData);
+ static void Verify(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data, const uint32_t die_offset, const uint32_t recurse_depth);
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const;
+ bool Find(lldb_private::RegularExpression& re, std::vector<dw_offset_t>& die_offsets) const;
+
+ enum
+ {
+ eDumpFlag_Verbose = (1<<0), // Verbose dumping
+ eDumpFlag_ShowForm = (1<<1), // Show the DW_form type
+ eDumpFlag_ShowAncestors = (1<<2) // Show all parent DIEs when dumping single DIEs
+ };
+
+ DWARFDebugAranges &
+ GetCompileUnitAranges ();
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ typedef std::vector<DWARFCompileUnitSP> CompileUnitColl;
+ CompileUnitColl m_compile_units;
+ std::unique_ptr<DWARFDebugAranges> m_cu_aranges_ap; // A quick address to compile unit table
+
+private:
+ // All parsing needs to be done partially any managed by this class as accessors are called.
+ void ParseCompileUnitHeadersIfNeeded();
+
+ DISALLOW_COPY_AND_ASSIGN (DWARFDebugInfo);
+};
+
+#endif // SymbolFileDWARF_DWARFDebugInfo_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 000000000000..03c12e366f92
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,2317 @@
+//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugInfoEntry.h"
+
+#include <assert.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFCompileUnit.h"
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDeclContext.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationDescription.h"
+#include "DWARFLocationList.h"
+#include "DWARFDebugRanges.h"
+
+using namespace lldb_private;
+using namespace std;
+extern int g_verbose;
+
+
+
+DWARFDebugInfoEntry::Attributes::Attributes() :
+ m_infos()
+{
+}
+
+DWARFDebugInfoEntry::Attributes::~Attributes()
+{
+}
+
+
+uint32_t
+DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const
+{
+ collection::const_iterator end = m_infos.end();
+ collection::const_iterator beg = m_infos.begin();
+ collection::const_iterator pos;
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->attr == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT32_MAX;
+}
+
+void
+DWARFDebugInfoEntry::Attributes::Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form)
+{
+ Info info = { cu, attr_die_offset, attr, form };
+ m_infos.push_back(info);
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ContainsAttribute(dw_attr_t attr) const
+{
+ return FindAttributeIndex(attr) != UINT32_MAX;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
+{
+ uint32_t attr_index = FindAttributeIndex(attr);
+ if (attr_index != UINT32_MAX)
+ {
+ m_infos.erase(m_infos.begin() + attr_index);
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const
+{
+ form_value.SetForm(FormAtIndex(i));
+ lldb::offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+}
+
+uint64_t
+DWARFDebugInfoEntry::Attributes::FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const
+{
+ const uint32_t attr_idx = FindAttributeIndex (attr);
+ if (attr_idx != UINT32_MAX)
+ return FormValueAsUnsignedAtIndex (dwarf2Data, attr_idx, fail_value);
+ return fail_value;
+}
+
+uint64_t
+DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const
+{
+ DWARFFormValue form_value;
+ if (ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ return form_value.Reference(CompileUnitAtIndex(i));
+ return fail_value;
+}
+
+
+
+bool
+DWARFDebugInfoEntry::FastExtract
+(
+ const DataExtractor& debug_info_data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ lldb::offset_t *offset_ptr
+)
+{
+ m_offset = *offset_ptr;
+ m_parent_idx = 0;
+ m_sibling_idx = 0;
+ m_empty_children = false;
+ const uint64_t abbr_idx = debug_info_data.GetULEB128 (offset_ptr);
+ assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE));
+ m_abbr_idx = abbr_idx;
+
+ //assert (fixed_form_sizes); // For best performance this should be specified!
+
+ if (m_abbr_idx)
+ {
+ lldb::offset_t offset = *offset_ptr;
+
+ const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(m_abbr_idx);
+
+ if (abbrevDecl == NULL)
+ {
+ cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid abbreviation code %u, please file a bug and attach the file at the start of this error message",
+ m_offset,
+ (unsigned)abbr_idx);
+ // WE can't parse anymore if the DWARF is borked...
+ *offset_ptr = UINT32_MAX;
+ return false;
+ }
+ m_tag = abbrevDecl->Tag();
+ m_has_children = abbrevDecl->HasChildren();
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ register uint32_t i;
+ register dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ form = abbrevDecl->GetFormByIndexUnchecked(i);
+
+ const uint8_t fixed_skip_size = fixed_form_sizes [form];
+ if (fixed_skip_size)
+ offset += fixed_skip_size;
+ else
+ {
+ bool form_is_indirect = false;
+ do
+ {
+ form_is_indirect = false;
+ register uint32_t form_size = 0;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc :
+ case DW_FORM_block : form_size = debug_info_data.GetULEB128 (&offset); break;
+ case DW_FORM_block1 : form_size = debug_info_data.GetU8_unchecked (&offset); break;
+ case DW_FORM_block2 : form_size = debug_info_data.GetU16_unchecked (&offset);break;
+ case DW_FORM_block4 : form_size = debug_info_data.GetU32_unchecked (&offset);break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string :
+ debug_info_data.GetCStr (&offset);
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ form_size = cu->GetAddressByteSize();
+ break;
+ case DW_FORM_ref_addr :
+ 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
+ break;
+
+ // 0 sized form
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp :
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ case DW_FORM_ref_sig8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128 (&offset);
+ break;
+
+ case DW_FORM_indirect :
+ form_is_indirect = true;
+ form = debug_info_data.GetULEB128 (&offset);
+ break;
+
+ case DW_FORM_sec_offset :
+ if (cu->GetAddressByteSize () == 4)
+ debug_info_data.GetU32 (offset_ptr);
+ else
+ debug_info_data.GetU64 (offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = m_offset;
+ return false;
+ }
+ offset += form_size;
+
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = false;
+ return true; // NULL debug tag entry
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Extract
+//
+// Extract a debug info entry for a given compile unit from the
+// .debug_info and .debug_abbrev data within the SymbolFileDWARF class
+// starting at the given offset
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::Extract
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb::offset_t *offset_ptr
+)
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+// const DataExtractor& 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);
+ if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset))
+ {
+ m_offset = offset;
+
+ const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset);
+ assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE));
+ m_abbr_idx = abbr_idx;
+ if (abbr_idx)
+ {
+ const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbr_idx);
+
+ if (abbrevDecl)
+ {
+ m_tag = abbrevDecl->Tag();
+ m_has_children = abbrevDecl->HasChildren();
+
+ bool isCompileUnitTag = m_tag == DW_TAG_compile_unit;
+ if (cu && isCompileUnitTag)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(0);
+
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ 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))
+ {
+ if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned());
+ }
+ }
+ else
+ {
+ bool form_is_indirect = false;
+ do
+ {
+ form_is_indirect = false;
+ register uint32_t form_size = 0;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc :
+ case DW_FORM_block : form_size = debug_info_data.GetULEB128(&offset); break;
+ case DW_FORM_block1 : form_size = debug_info_data.GetU8(&offset); break;
+ case DW_FORM_block2 : form_size = debug_info_data.GetU16(&offset); break;
+ case DW_FORM_block4 : form_size = debug_info_data.GetU32(&offset); break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string : debug_info_data.GetCStr(&offset); break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ form_size = cu_addr_size;
+ break;
+ case DW_FORM_ref_addr :
+ if (cu->GetVersion() <= 2)
+ form_size = cu_addr_size;
+ else
+ form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet
+ break;
+
+ // 0 sized form
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp :
+ form_size = 4;
+ break;
+
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ case DW_FORM_ref_sig8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128(&offset);
+ break;
+
+ case DW_FORM_indirect :
+ form = debug_info_data.GetULEB128(&offset);
+ form_is_indirect = true;
+ break;
+
+ case DW_FORM_sec_offset :
+ if (cu->GetAddressByteSize () == 4)
+ debug_info_data.GetU32 (offset_ptr);
+ else
+ debug_info_data.GetU64 (offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = false;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DumpAncestry
+//
+// Dumps all of a debug information entries parents up until oldest and
+// all of it's attributes to the specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAncestry
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ Stream &s,
+ uint32_t recurse_depth
+) const
+{
+ const DWARFDebugInfoEntry* parent = GetParent();
+ if (parent && parent != oldest)
+ parent->DumpAncestry(dwarf2Data, cu, oldest, s, 0);
+ Dump(dwarf2Data, cu, s, recurse_depth);
+}
+
+//----------------------------------------------------------------------
+// Compare two DIE by comparing all their attributes values, and
+// following all DW_FORM_ref attributes and comparing their contents as
+// well (except for DW_AT_sibling attributes.
+//
+// DWARFDebugInfoEntry::CompareState compare_state;
+// int result = DWARFDebugInfoEntry::Compare(this, 0x00017ccb, 0x0001eb2b, compare_state, false, true);
+//----------------------------------------------------------------------
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// dw_offset_t a_die_offset,
+// dw_offset_t b_die_offset,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children
+//)
+//{
+// if (a_die_offset == b_die_offset)
+// return 0;
+//
+// DWARFCompileUnitSP a_cu_sp;
+// DWARFCompileUnitSP b_cu_sp;
+// const DWARFDebugInfoEntry* a_die = dwarf2Data->DebugInfo()->GetDIEPtr(a_die_offset, &a_cu_sp);
+// const DWARFDebugInfoEntry* b_die = dwarf2Data->DebugInfo()->GetDIEPtr(b_die_offset, &b_cu_sp);
+//
+// return Compare(dwarf2Data, a_cu_sp.get(), a_die, b_cu_sp.get(), b_die, compare_state, compare_siblings, compare_children);
+//}
+//
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children
+//)
+//{
+// if (a_die == b_die)
+// return 0;
+//
+// if (!compare_state.AddTypePair(a_die->GetOffset(), b_die->GetOffset()))
+// {
+// // We are already comparing both of these types, so let
+// // compares complete for the real result
+// return 0;
+// }
+//
+// //printf("DWARFDebugInfoEntry::Compare(0x%8.8x, 0x%8.8x)\n", a_die->GetOffset(), b_die->GetOffset());
+//
+// // Do we have two valid DIEs?
+// if (a_die && b_die)
+// {
+// // Both DIE are valid
+// int result = 0;
+//
+// const dw_tag_t a_tag = a_die->Tag();
+// const dw_tag_t b_tag = b_die->Tag();
+// if (a_tag == 0 && b_tag == 0)
+// return 0;
+//
+// //printf(" comparing tags: %s and %s\n", DW_TAG_value_to_name(a_tag), DW_TAG_value_to_name(b_tag));
+//
+// if (a_tag < b_tag)
+// return -1;
+// else if (a_tag > b_tag)
+// return 1;
+//
+// DWARFDebugInfoEntry::Attributes a_attrs;
+// DWARFDebugInfoEntry::Attributes b_attrs;
+// size_t a_attr_count = a_die->GetAttributes(dwarf2Data, a_cu, a_attrs);
+// size_t b_attr_count = b_die->GetAttributes(dwarf2Data, b_cu, b_attrs);
+// if (a_attr_count != b_attr_count)
+// {
+// a_attrs.RemoveAttribute(DW_AT_sibling);
+// b_attrs.RemoveAttribute(DW_AT_sibling);
+// }
+//
+// a_attr_count = a_attrs.Size();
+// b_attr_count = b_attrs.Size();
+//
+// DWARFFormValue a_form_value;
+// DWARFFormValue b_form_value;
+//
+// if (a_attr_count != b_attr_count)
+// {
+// uint32_t is_decl_index = a_attrs.FindAttributeIndex(DW_AT_declaration);
+// uint32_t a_name_index = UINT32_MAX;
+// uint32_t b_name_index = UINT32_MAX;
+// if (is_decl_index != UINT32_MAX)
+// {
+// if (a_attr_count == 2)
+// {
+// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+// }
+// }
+// else
+// {
+// is_decl_index = b_attrs.FindAttributeIndex(DW_AT_declaration);
+// if (is_decl_index != UINT32_MAX && a_attr_count == 2)
+// {
+// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+// }
+// }
+// if (a_name_index != UINT32_MAX && b_name_index != UINT32_MAX)
+// {
+// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, a_name_index, a_form_value) &&
+// b_attrs.ExtractFormValueAtIndex(dwarf2Data, b_name_index, b_form_value))
+// {
+// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, &dwarf2Data->get_debug_str_data());
+// if (result == 0)
+// {
+// a_attr_count = b_attr_count = 0;
+// compare_children = false;
+// }
+// }
+// }
+// }
+//
+// if (a_attr_count < b_attr_count)
+// return -1;
+// if (a_attr_count > b_attr_count)
+// return 1;
+//
+//
+// // The number of attributes are the same...
+// if (a_attr_count > 0)
+// {
+// const DataExtractor* debug_str_data_ptr = &dwarf2Data->get_debug_str_data();
+//
+// uint32_t i;
+// for (i=0; i<a_attr_count; ++i)
+// {
+// const dw_attr_t a_attr = a_attrs.AttributeAtIndex(i);
+// const dw_attr_t b_attr = b_attrs.AttributeAtIndex(i);
+// //printf(" comparing attributes\n\t\t0x%8.8x: %s %s\t\t0x%8.8x: %s %s\n",
+// // a_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(a_attrs.FormAtIndex(i)), DW_AT_value_to_name(a_attr),
+// // b_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(b_attrs.FormAtIndex(i)), DW_AT_value_to_name(b_attr));
+//
+// if (a_attr < b_attr)
+// return -1;
+// else if (a_attr > b_attr)
+// return 1;
+//
+// switch (a_attr)
+// {
+// // Since we call a form of GetAttributes which inlines the
+// // attributes from DW_AT_abstract_origin and DW_AT_specification
+// // we don't care if their values mismatch...
+// case DW_AT_abstract_origin:
+// case DW_AT_specification:
+// case DW_AT_sibling:
+// case DW_AT_containing_type:
+// //printf(" action = IGNORE\n");
+// result = 0;
+// break; // ignore
+//
+// default:
+// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, i, a_form_value) &&
+// b_attrs.ExtractFormValueAtIndex(dwarf2Data, i, b_form_value))
+// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, debug_str_data_ptr);
+// break;
+// }
+//
+// //printf("\t result = %i\n", result);
+//
+// if (result != 0)
+// {
+// // Attributes weren't equal, lets see if we care?
+// switch (a_attr)
+// {
+// case DW_AT_decl_file:
+// // TODO: add the ability to compare files in two different compile units
+// if (a_cu == b_cu)
+// {
+// //printf(" action = RETURN RESULT\n");
+// return result; // Only return the compare results when the compile units are the same and the decl_file attributes can be compared
+// }
+// else
+// {
+// result = 0;
+// //printf(" action = IGNORE\n");
+// }
+// break;
+//
+// default:
+// switch (a_attrs.FormAtIndex(i))
+// {
+// case DW_FORM_ref1:
+// case DW_FORM_ref2:
+// case DW_FORM_ref4:
+// case DW_FORM_ref8:
+// case DW_FORM_ref_udata:
+// case DW_FORM_ref_addr:
+// //printf(" action = COMPARE DIEs 0x%8.8x 0x%8.8x\n", (dw_offset_t)a_form_value.Reference(a_cu), (dw_offset_t)b_form_value.Reference(b_cu));
+// // These attribute values refer to other DIEs, so lets compare those instead of their DIE offsets...
+// result = Compare(dwarf2Data, a_form_value.Reference(a_cu), b_form_value.Reference(b_cu), compare_state, false, true);
+// if (result != 0)
+// return result;
+// break;
+//
+// default:
+// // We do care that they were different, return this result...
+// //printf(" action = RETURN RESULT\n");
+// return result;
+// }
+// }
+// }
+// }
+// }
+// //printf(" SUCCESS\n\t\t0x%8.8x: %s\n\t\t0x%8.8x: %s\n", a_die->GetOffset(), DW_TAG_value_to_name(a_tag), b_die->GetOffset(), DW_TAG_value_to_name(b_tag));
+//
+// if (compare_children)
+// {
+// bool a_has_children = a_die->HasChildren();
+// bool b_has_children = b_die->HasChildren();
+// if (a_has_children == b_has_children)
+// {
+// // Both either have kids or don't
+// if (a_has_children)
+// result = Compare( dwarf2Data,
+// a_cu, a_die->GetFirstChild(),
+// b_cu, b_die->GetFirstChild(),
+// compare_state, true, compare_children);
+// else
+// result = 0;
+// }
+// else if (!a_has_children)
+// result = -1; // A doesn't have kids, but B does
+// else
+// result = 1; // A has kids, but B doesn't
+// }
+//
+// if (compare_siblings)
+// {
+// result = Compare( dwarf2Data,
+// a_cu, a_die->GetSibling(),
+// b_cu, b_die->GetSibling(),
+// compare_state, true, compare_children);
+// }
+//
+// return result;
+// }
+//
+// if (a_die == NULL)
+// return -1; // a_die is NULL, yet b_die is non-NULL
+// else
+// return 1; // a_die is non-NULL, yet b_die is NULL
+//
+//}
+//
+//
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_a,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_b,
+// CompareState &compare_state
+//)
+//{
+//}
+
+//----------------------------------------------------------------------
+// GetDIENamesAndRanges
+//
+// Gets the valid address ranges for a given DIE by looking for a
+// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges
+// attributes.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetDIENamesAndRanges
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& ranges,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ DWARFExpression *frame_base
+) const
+{
+ if (dwarf2Data == NULL)
+ return false;
+
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ std::vector<dw_offset_t> die_offsets;
+ bool set_frame_base_loclist_addr = false;
+
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ if (!debug_info_data.ValidOffset(offset))
+ return false;
+
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ bool do_offset = false;
+
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ switch (attr)
+ {
+ case DW_AT_low_pc:
+ lo_pc = form_value.Unsigned();
+
+ if (do_offset)
+ hi_pc += lo_pc;
+ do_offset = false;
+ break;
+
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_high_pc:
+ hi_pc = form_value.Unsigned();
+ if (form_value.Form() != DW_FORM_addr)
+ {
+ if (lo_pc == LLDB_INVALID_ADDRESS)
+ do_offset = hi_pc != LLDB_INVALID_ADDRESS;
+ else
+ hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save on relocations
+ }
+ break;
+
+ case DW_AT_ranges:
+ {
+ const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(form_value.Unsigned(), ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.Slide(cu->GetBaseAddress());
+ }
+ break;
+
+ case DW_AT_name:
+ if (name == NULL)
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (mangled == NULL)
+ mangled = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_abstract_origin:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_specification:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_decl_file:
+ if (decl_file == 0)
+ decl_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_line:
+ if (decl_line == 0)
+ decl_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_column:
+ if (decl_column == 0)
+ decl_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_file:
+ if (call_file == 0)
+ call_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_line:
+ if (call_line == 0)
+ call_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_column:
+ if (call_column == 0)
+ call_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_frame_base:
+ if (frame_base)
+ {
+ if (form_value.BlockData())
+ {
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ frame_base->SetOpcodeData(debug_info_data, block_offset, block_length);
+ }
+ else
+ {
+ const DataExtractor &debug_loc_data = dwarf2Data->get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length);
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ assert (lo_pc >= cu->GetBaseAddress());
+ frame_base->SetLocationListSlide(lo_pc - cu->GetBaseAddress());
+ }
+ else
+ {
+ set_frame_base_loclist_addr = true;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (ranges.IsEmpty())
+ {
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc)
+ ranges.Append(DWARFDebugRanges::Range (lo_pc, hi_pc - lo_pc));
+ else
+ ranges.Append(DWARFDebugRanges::Range (lo_pc, 0));
+ }
+ }
+
+ if (set_frame_base_loclist_addr)
+ {
+ dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0);
+ assert (lowest_range_pc >= cu->GetBaseAddress());
+ frame_base->SetLocationListSlide (lowest_range_pc - cu->GetBaseAddress());
+ }
+
+ if (ranges.IsEmpty() || name == NULL || mangled == NULL)
+ {
+ std::vector<dw_offset_t>::const_iterator pos;
+ std::vector<dw_offset_t>::const_iterator end = die_offsets.end();
+ for (pos = die_offsets.begin(); pos != end; ++pos)
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = *pos;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ die = dwarf2Data->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetDIENamesAndRanges(dwarf2Data, cu_sp_ptr.get(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column);
+ }
+ }
+ }
+ return !ranges.IsEmpty();
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dumps a debug information entry and all of it's attributes to the
+// specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::Dump
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ Stream &s,
+ uint32_t recurse_depth
+) const
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ lldb::offset_t offset = m_offset;
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ s.Printf("\n0x%8.8x: ", m_offset);
+ s.Indent();
+ if (abbrCode != m_abbr_idx)
+ {
+ s.Printf( "error: DWARF has been modified\n");
+ }
+ else if (abbrCode)
+ {
+ const DWARFAbbreviationDeclaration* abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration (abbrCode);
+
+ if (abbrevDecl)
+ {
+ s.PutCString(DW_TAG_value_to_name(abbrevDecl->Tag()));
+ s.Printf( " [%u] %c\n", abbrCode, abbrevDecl->HasChildren() ? '*':' ');
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, form);
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ if (recurse_depth > 0 && child)
+ {
+ s.IndentMore();
+
+ while (child)
+ {
+ child->Dump(dwarf2Data, cu, s, recurse_depth-1);
+ child = child->GetSibling();
+ }
+ s.IndentLess();
+ }
+ }
+ else
+ s.Printf( "Abbreviation code note found in 'debug_abbrev' class for code: %u\n", abbrCode);
+ }
+ else
+ {
+ s.Printf( "NULL\n");
+ }
+ }
+}
+
+void
+DWARFDebugInfoEntry::DumpLocation
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ Stream &s
+) const
+{
+ const DWARFDebugInfoEntry *cu_die = cu->GetCompileUnitDIEOnly();
+ const char *cu_name = NULL;
+ if (cu_die != NULL)
+ cu_name = cu_die->GetName (dwarf2Data, cu);
+ const char *obj_file_name = NULL;
+ ObjectFile *obj_file = dwarf2Data->GetObjectFile();
+ if (obj_file)
+ obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString();
+ const char *die_name = GetName (dwarf2Data, cu);
+ s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)",
+ cu->GetOffset(),
+ GetOffset(),
+ die_name ? die_name : "",
+ cu_name ? cu_name : "<NULL>",
+ obj_file_name ? obj_file_name : "<NULL>");
+}
+
+//----------------------------------------------------------------------
+// DumpAttribute
+//
+// Dumps a debug information entry attribute along with it's form. Any
+// special display of attributes is done (disassemble location lists,
+// show enumeration values for attributes, etc).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAttribute
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DataExtractor& debug_info_data,
+ lldb::offset_t *offset_ptr,
+ Stream &s,
+ dw_attr_t attr,
+ dw_form_t form
+)
+{
+ bool verbose = s.GetVerbose();
+ bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm);
+
+ const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL;
+ if (verbose)
+ s.Offset (*offset_ptr);
+ else
+ s.Printf (" ");
+ s.Indent(DW_AT_value_to_name(attr));
+
+ if (show_form)
+ {
+ s.Printf( "[%s", DW_FORM_value_to_name(form));
+ }
+
+ DWARFFormValue form_value(form);
+
+ if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu))
+ return;
+
+ if (show_form)
+ {
+ if (form == DW_FORM_indirect)
+ {
+ s.Printf( " [%s]", DW_FORM_value_to_name(form_value.Form()));
+ }
+
+ s.PutCString("] ");
+ }
+
+ s.PutCString("( ");
+
+ // Always dump form value if verbose is enabled
+ if (verbose)
+ {
+ form_value.Dump(s, debug_str_data, cu);
+ }
+
+
+ // Check to see if we have any special attribute formatters
+ switch (attr)
+ {
+ case DW_AT_stmt_list:
+ if ( verbose ) s.PutCString(" ( ");
+ s.Printf( "0x%8.8" PRIx64, form_value.Unsigned());
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_language:
+ if ( verbose ) s.PutCString(" ( ");
+ s.PutCString(DW_LANG_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_encoding:
+ if ( verbose ) s.PutCString(" ( ");
+ s.PutCString(DW_ATE_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_data_member_location:
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+
+ // Location description is inlined in data in the form value
+ DataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned());
+ if ( verbose ) s.PutCString(" ( ");
+ print_dwarf_expression (s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false);
+ if ( verbose ) s.PutCString(" )");
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ uint64_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset);
+ }
+ else
+ {
+ if ( !verbose )
+ form_value.Dump(s, NULL, cu);
+ }
+ }
+ }
+ break;
+
+ 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);
+ // *ostrm_ptr << HEX32 << abstract_die_offset << " ( ";
+ if ( verbose ) s.PutCString(" ( ");
+ GetName(dwarf2Data, cu, abstract_die_offset, s);
+ if ( verbose ) s.PutCString(" )");
+ }
+ break;
+
+ case DW_AT_type:
+ {
+ uint64_t type_die_offset = form_value.Reference(cu);
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+ s.PutCString(" ( ");
+ AppendTypeName(dwarf2Data, cu, type_die_offset, s);
+ s.PutCString(" )");
+ }
+ break;
+
+ case DW_AT_ranges:
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ lldb::offset_t ranges_offset = form_value.Unsigned();
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ if (dwarf2Data)
+ DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), &ranges_offset, base_addr);
+ }
+ break;
+
+ default:
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ break;
+ }
+
+ s.PutCString(" )\n");
+}
+
+//----------------------------------------------------------------------
+// Get all attribute values for a given DIE, including following any
+// specification or abstract origin attributes and including those in
+// the results. Any duplicate attributes will have the first instance
+// take precedence (this can happen for declaration attributes).
+//----------------------------------------------------------------------
+size_t
+DWARFDebugInfoEntry::GetAttributes
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ DWARFDebugInfoEntry::Attributes& attributes,
+ uint32_t curr_depth
+) const
+{
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ if (fixed_form_sizes == NULL)
+ fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize());
+
+ 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);
+
+ // If we are tracking down DW_AT_specification or DW_AT_abstract_origin
+ // attributes, the depth will be non-zero. We need to omit certain
+ // attributes that don't make sense.
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ case DW_AT_declaration:
+ if (curr_depth > 0)
+ {
+ // This attribute doesn't make sense when combined with
+ // the DIE that references this DIE. We know a DIE is
+ // referencing this DIE because curr_depth is not zero
+ break;
+ }
+ // Fall through...
+ default:
+ attributes.Append(cu, offset, attr, form);
+ break;
+ }
+
+ if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))
+ {
+ form_value.SetForm(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = form_value.Reference(cu);
+ if (cu->ContainsDIEOffset(die_offset))
+ {
+ die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes, curr_depth + 1);
+ }
+ else
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu_sp_ptr.get(), fixed_form_sizes, attributes, curr_depth + 1);
+ }
+ }
+ }
+ else
+ {
+ const uint8_t fixed_skip_size = fixed_form_sizes [form];
+ if (fixed_skip_size)
+ offset += fixed_skip_size;
+ else
+ DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
+ }
+ }
+ }
+ else
+ {
+ attributes.Clear();
+ }
+ return attributes.Size();
+
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValue
+//
+// Get the value of an attribute and return the .debug_info offset of the
+// attribute if it was properly extracted into form_value, or zero
+// if we fail since an offset of zero is invalid for an attribute (it
+// would be a compile unit header).
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValue
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& form_value,
+ dw_offset_t* end_attr_offset_ptr
+) const
+{
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr);
+
+ if (attr_idx != DW_INVALID_INDEX)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ uint32_t idx=0;
+ while (idx<attr_idx)
+ DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetForm(abbrevDecl->GetFormByIndex(idx));
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ if (end_attr_offset_ptr)
+ *end_attr_offset_ptr = offset;
+ return attr_offset;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsString
+//
+// Get the value of an attribute as a string return it. The resulting
+// pointer to the string data exists within the supplied SymbolFileDWARF
+// and will only be available as long as the SymbolFileDWARF is still around
+// and it's content doesn't change.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetAttributeValueAsString
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsUnsigned
+//
+// Get the value of an attribute as unsigned and return it.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsUnsigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Unsigned();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsSigned
+//
+// Get the value of an attribute a signed value and return it.
+//----------------------------------------------------------------------
+int64_t
+DWARFDebugInfoEntry::GetAttributeValueAsSigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Signed();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsReference
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsReference
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Reference(cu);
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeHighPC
+//
+// Get the hi_pc, adding hi_pc to lo_pc when specified
+// as an <offset-from-low-pc>.
+//
+// Returns the hi_pc or fail_value.
+//----------------------------------------------------------------------
+dw_addr_t
+DWARFDebugInfoEntry::GetAttributeHighPC
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t lo_pc,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value))
+ {
+ dw_addr_t hi_pc = form_value.Unsigned();
+ if (form_value.Form() != DW_FORM_addr)
+ hi_pc += lo_pc; // DWARF4 can specify the hi_pc as an <offset-from-lowpc>
+ return hi_pc;
+ }
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeAddressRange
+//
+// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified
+// as an <offset-from-low-pc>.
+//
+// Returns true or sets lo_pc and hi_pc to fail_value.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetAttributeAddressRange
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t& lo_pc,
+ dw_addr_t& hi_pc,
+ uint64_t fail_value
+) const
+{
+ lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, fail_value);
+ if (lo_pc != fail_value)
+ {
+ hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, fail_value);
+ if (hi_pc != fail_value)
+ return true;
+ }
+ lo_pc = fail_value;
+ hi_pc = fail_value;
+ return false;
+}
+//----------------------------------------------------------------------
+// GetAttributeValueAsLocation
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValueAsLocation
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DataExtractor& location_data,
+ uint32_t &block_size
+) const
+{
+ block_size = 0;
+ DWARFFormValue form_value;
+
+ // Empty out data in case we don't find anything
+ location_data.Clear();
+ dw_offset_t end_addr_offset = DW_INVALID_OFFSET;
+ const dw_offset_t attr_offset = GetAttributeValue(dwarf2Data, cu, attr, form_value, &end_addr_offset);
+ if (attr_offset)
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ // We have an inlined location list in the .debug_info section
+ const DataExtractor& debug_info = dwarf2Data->get_debug_info_data();
+ dw_offset_t block_offset = blockData - debug_info.GetDataStart();
+ block_size = (end_addr_offset - attr_offset) - form_value.Unsigned();
+ location_data.SetData(debug_info, block_offset, block_size);
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ lldb::offset_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ assert(dwarf2Data->get_debug_loc_data().GetAddressByteSize() == cu->GetAddressByteSize());
+ return DWARFLocationList::Extract(dwarf2Data->get_debug_loc_data(), &debug_loc_offset, location_data);
+ }
+ }
+ }
+ return attr_offset;
+}
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute and return it if one exists,
+// else return NULL.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else
+ {
+ 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);
+ if (die)
+ return die->GetName(dwarf2Data, cu_sp_ptr.get());
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// GetMangledName
+//
+// Get value of the DW_AT_MIPS_linkage_name attribute and return it if
+// one exists, else return the value of the DW_AT_name attribute
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetMangledName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed
+) const
+{
+ const char* name = NULL;
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+
+ if (substitute_name_allowed && name == NULL)
+ {
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetPubname
+//
+// Get value the name for a DIE as it should appear for a
+// .debug_pubnames or .debug_pubtypes section.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetPubname
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ const char* name = NULL;
+ if (!dwarf2Data)
+ return name;
+
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
+ {
+ // 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);
+ if (die)
+ return die->GetPubname(dwarf2Data, cu_sp_ptr.get());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute for a debug information entry
+// that exists at offset "die_offset" and place that value into the
+// supplied stream object. If the DIE is a NULL object "NULL" is placed
+// into the stream, and if no DW_AT_name attribute exists for the DIE
+// then nothing is printed.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ Stream &s
+)
+{
+ if (dwarf2Data == NULL)
+ {
+ s.PutCString("NULL");
+ return false;
+ }
+
+ DWARFDebugInfoEntry die;
+ lldb::offset_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s.PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ {
+ const char* name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ {
+ s.PutCString(name);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendTypeName
+//
+// Follows the type name definition down through all needed tags to
+// end up with a fully qualified type name and dump the results to
+// the supplied stream. This is used to show the name of types given
+// a type identifier.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendTypeName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ Stream &s
+)
+{
+ if (dwarf2Data == NULL)
+ {
+ s.PutCString("NULL");
+ return false;
+ }
+
+ DWARFDebugInfoEntry die;
+ lldb::offset_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s.PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ const char* name = die.GetPubname(dwarf2Data, cu);
+ // if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ // name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ s.PutCString(name);
+ else
+ {
+ bool result = true;
+ const DWARFAbbreviationDeclaration* abbrevDecl = die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl == NULL)
+ return false;
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break; // print out a "[]" after printing the full type of the element below
+ case DW_TAG_base_type: s.PutCString("base "); break;
+ case DW_TAG_class_type: s.PutCString("class "); break;
+ case DW_TAG_const_type: s.PutCString("const "); break;
+ case DW_TAG_enumeration_type: s.PutCString("enum "); break;
+ case DW_TAG_file_type: s.PutCString("file "); break;
+ case DW_TAG_interface_type: s.PutCString("interface "); break;
+ case DW_TAG_packed_type: s.PutCString("packed "); break;
+ case DW_TAG_pointer_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_ptr_to_member_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_reference_type: break; // print out a '&' after printing the full type below
+ case DW_TAG_restrict_type: s.PutCString("restrict "); break;
+ case DW_TAG_set_type: s.PutCString("set "); break;
+ case DW_TAG_shared_type: s.PutCString("shared "); break;
+ case DW_TAG_string_type: s.PutCString("string "); break;
+ case DW_TAG_structure_type: s.PutCString("struct "); break;
+ case DW_TAG_subrange_type: s.PutCString("subrange "); break;
+ case DW_TAG_subroutine_type: s.PutCString("function "); break;
+ case DW_TAG_thrown_type: s.PutCString("thrown "); break;
+ case DW_TAG_union_type: s.PutCString("union "); break;
+ case DW_TAG_unspecified_type: s.PutCString("unspecified "); break;
+ case DW_TAG_volatile_type: s.PutCString("volatile "); break;
+ default:
+ return false;
+ }
+
+ // Follow the DW_AT_type if possible
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value))
+ {
+ uint64_t next_die_offset = form_value.Reference(cu);
+ result = AppendTypeName(dwarf2Data, cu, next_die_offset, s);
+ }
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: s.PutCString("[]"); break;
+ case DW_TAG_pointer_type: s.PutChar('*'); break;
+ case DW_TAG_ptr_to_member_type: s.PutChar('*'); break;
+ case DW_TAG_reference_type: s.PutChar('&'); break;
+ default:
+ break;
+ }
+ return result;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+DWARFDebugInfoEntry::Contains (const DWARFDebugInfoEntry *die) const
+{
+ if (die)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+ if (die_offset > GetOffset())
+ {
+ const DWARFDebugInfoEntry *sibling = GetSibling();
+ assert (sibling); // TODO: take this out
+ if (sibling)
+ return die_offset < sibling->GetOffset();
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// BuildAddressRangeTable
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_tag)
+ {
+ if (m_tag == DW_TAG_subprogram)
+ {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS))
+ {
+ /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc);
+ debug_aranges->AppendRange (cu->GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// BuildFunctionAddressRangeTable
+//
+// This function is very similar to the BuildAddressRangeTable function
+// except that the actual DIE offset for the function is placed in the
+// table instead of the compile unit offset (which is the way the
+// standard .debug_aranges section does it).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildFunctionAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_tag)
+ {
+ if (m_tag == DW_TAG_subprogram)
+ {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS))
+ {
+ // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY
+ debug_aranges->AppendRange (GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+void
+DWARFDebugInfoEntry::GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDIECollection &decl_context_dies) const
+{
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ if (parent_decl_ctx_die && parent_decl_ctx_die != this)
+ {
+ decl_context_dies.Append(parent_decl_ctx_die);
+ parent_decl_ctx_die->GetDeclContextDIEs (dwarf2Data, cu, decl_context_dies);
+ }
+}
+
+void
+DWARFDebugInfoEntry::GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDeclContext &dwarf_decl_ctx) const
+{
+ const dw_tag_t tag = Tag();
+ if (tag != DW_TAG_compile_unit)
+ {
+ dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu));
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ if (parent_decl_ctx_die && parent_decl_ctx_die != this)
+ {
+ if (parent_decl_ctx_die->Tag() != DW_TAG_compile_unit)
+ parent_decl_ctx_die->GetDWARFDeclContext (dwarf2Data, cu, dwarf_decl_ctx);
+ }
+ }
+}
+
+
+bool
+DWARFDebugInfoEntry::MatchesDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDeclContext &dwarf_decl_ctx) const
+{
+
+ DWARFDeclContext this_dwarf_decl_ctx;
+ GetDWARFDeclContext (dwarf2Data, cu, this_dwarf_decl_ctx);
+ return this_dwarf_decl_ctx == dwarf_decl_ctx;
+}
+
+const DWARFDebugInfoEntry *
+DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu) const
+{
+ DWARFDebugInfoEntry::Attributes attributes;
+ GetAttributes(dwarf2Data, cu, NULL, attributes);
+ return GetParentDeclContextDIE (dwarf2Data, cu, attributes);
+}
+
+const DWARFDebugInfoEntry *
+DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes) const
+{
+ const DWARFDebugInfoEntry * die = this;
+
+ while (die != NULL)
+ {
+ // If this is the original DIE that we are searching for a declaration
+ // for, then don't look in the cache as we don't want our own decl
+ // context to be our decl context...
+ if (die != this)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ dw_offset_t die_offset;
+
+ die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *spec_die = cu->GetDIEPtr (die_offset);
+ if (spec_die)
+ {
+ const DWARFDebugInfoEntry *spec_die_decl_ctx_die = spec_die->GetParentDeclContextDIE (dwarf2Data, cu);
+ if (spec_die_decl_ctx_die)
+ return spec_die_decl_ctx_die;
+ }
+ }
+
+ die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *abs_die = cu->GetDIEPtr (die_offset);
+ if (abs_die)
+ {
+ const DWARFDebugInfoEntry *abs_die_decl_ctx_die = abs_die->GetParentDeclContextDIE (dwarf2Data, cu);
+ if (abs_die_decl_ctx_die)
+ return abs_die_decl_ctx_die;
+ }
+ }
+
+ die = die->GetParent();
+ }
+ return NULL;
+}
+
+
+const char *
+DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ std::string &storage) const
+{
+ DWARFDebugInfoEntry::Attributes attributes;
+ GetAttributes(dwarf2Data, cu, NULL, attributes);
+ return GetQualifiedName (dwarf2Data, cu, attributes, storage);
+}
+
+const char*
+DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes,
+ std::string &storage) const
+{
+
+ const char *name = GetName (dwarf2Data, cu);
+
+ if (name)
+ {
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ storage.clear();
+ // TODO: change this to get the correct decl context parent....
+ while (parent_decl_ctx_die)
+ {
+ const dw_tag_t parent_tag = parent_decl_ctx_die->Tag();
+ switch (parent_tag)
+ {
+ case DW_TAG_namespace:
+ {
+ const char *namespace_name = parent_decl_ctx_die->GetName (dwarf2Data, cu);
+ if (namespace_name)
+ {
+ storage.insert (0, "::");
+ storage.insert (0, namespace_name);
+ }
+ else
+ {
+ storage.insert (0, "(anonymous namespace)::");
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu);
+ }
+ break;
+
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ {
+ const char *class_union_struct_name = parent_decl_ctx_die->GetName (dwarf2Data, cu);
+
+ if (class_union_struct_name)
+ {
+ storage.insert (0, "::");
+ storage.insert (0, class_union_struct_name);
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu);
+ }
+ break;
+
+ default:
+ parent_decl_ctx_die = NULL;
+ break;
+ }
+ }
+
+ if (storage.empty())
+ storage.append ("::");
+
+ storage.append (name);
+ }
+ if (storage.empty())
+ return NULL;
+ return storage.c_str();
+}
+
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::LookupAddress
+(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+ bool found_address = false;
+ if (m_tag)
+ {
+ bool check_children = false;
+ bool match_addr_range = false;
+ // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address);
+ switch (m_tag)
+ {
+ case DW_TAG_array_type : break;
+ case DW_TAG_class_type : check_children = true; break;
+ case DW_TAG_entry_point : break;
+ case DW_TAG_enumeration_type : break;
+ case DW_TAG_formal_parameter : break;
+ case DW_TAG_imported_declaration : break;
+ case DW_TAG_label : break;
+ case DW_TAG_lexical_block : check_children = true; match_addr_range = true; break;
+ case DW_TAG_member : break;
+ case DW_TAG_pointer_type : break;
+ case DW_TAG_reference_type : break;
+ case DW_TAG_compile_unit : match_addr_range = true; break;
+ case DW_TAG_string_type : break;
+ case DW_TAG_structure_type : check_children = true; break;
+ case DW_TAG_subroutine_type : break;
+ case DW_TAG_typedef : break;
+ case DW_TAG_union_type : break;
+ case DW_TAG_unspecified_parameters : break;
+ case DW_TAG_variant : break;
+ case DW_TAG_common_block : check_children = true; break;
+ case DW_TAG_common_inclusion : break;
+ case DW_TAG_inheritance : break;
+ case DW_TAG_inlined_subroutine : check_children = true; match_addr_range = true; break;
+ case DW_TAG_module : match_addr_range = true; break;
+ case DW_TAG_ptr_to_member_type : break;
+ case DW_TAG_set_type : break;
+ case DW_TAG_subrange_type : break;
+ case DW_TAG_with_stmt : break;
+ case DW_TAG_access_declaration : break;
+ case DW_TAG_base_type : break;
+ case DW_TAG_catch_block : match_addr_range = true; break;
+ case DW_TAG_const_type : break;
+ case DW_TAG_constant : break;
+ case DW_TAG_enumerator : break;
+ case DW_TAG_file_type : break;
+ case DW_TAG_friend : break;
+ case DW_TAG_namelist : break;
+ case DW_TAG_namelist_item : break;
+ case DW_TAG_packed_type : break;
+ case DW_TAG_subprogram : match_addr_range = true; break;
+ case DW_TAG_template_type_parameter : break;
+ case DW_TAG_template_value_parameter : break;
+ case DW_TAG_thrown_type : break;
+ case DW_TAG_try_block : match_addr_range = true; break;
+ case DW_TAG_variant_part : break;
+ case DW_TAG_variable : break;
+ case DW_TAG_volatile_type : break;
+ case DW_TAG_dwarf_procedure : break;
+ case DW_TAG_restrict_type : break;
+ case DW_TAG_interface_type : break;
+ case DW_TAG_namespace : check_children = true; break;
+ case DW_TAG_imported_module : break;
+ case DW_TAG_unspecified_type : break;
+ case DW_TAG_partial_unit : break;
+ case DW_TAG_imported_unit : break;
+ case DW_TAG_shared_type : break;
+ default: break;
+ }
+
+ if (match_addr_range)
+ {
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ dw_addr_t hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, LLDB_INVALID_ADDRESS);
+ if (hi_pc != LLDB_INVALID_ADDRESS)
+ {
+ // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc);
+ if ((lo_pc <= address) && (address < hi_pc))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (m_tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ }
+ else
+ { // compile units may not have a valid high/low pc when there
+ // are address gaps in subroutines so we must always search
+ // if there is no valid high and low PC
+ check_children = (m_tag == DW_TAG_compile_unit) && ((function_die != NULL) || (block_die != NULL));
+ }
+ }
+ else
+ {
+ dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
+ if (debug_ranges_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugRanges::RangeList ranges;
+ DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(debug_ranges_offset, ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.Slide (cu->GetBaseAddress());
+ if (ranges.FindEntryThatContains(address))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (m_tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ else
+ {
+ check_children = false;
+ }
+ }
+ }
+ }
+
+
+ if (check_children)
+ {
+ // printf("checking children\n");
+ DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, dwarf2Data, cu, function_die, block_die))
+ return true;
+ child = child->GetSibling();
+ }
+ }
+ }
+ return found_address;
+}
+
+const DWARFAbbreviationDeclaration*
+DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit *cu,
+ lldb::offset_t &offset) const
+{
+ if (dwarf2Data)
+ {
+ offset = GetOffset();
+
+ const DWARFAbbreviationDeclaration* abbrev_decl = cu->GetAbbreviations()->GetAbbreviationDeclaration (m_abbr_idx);
+ if (abbrev_decl)
+ {
+ // Make sure the abbreviation code still matches. If it doesn't and
+ // the DWARF data was mmap'ed, the backing file might have been modified
+ // which is bad news.
+ const uint64_t abbrev_code = dwarf2Data->get_debug_info_data().GetULEB128 (&offset);
+
+ if (abbrev_decl->Code() == abbrev_code)
+ return abbrev_decl;
+
+ dwarf2Data->GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("0x%8.8x: the DWARF debug information has been modified (abbrev code was %u, and is now %u)",
+ GetOffset(),
+ (uint32_t)abbrev_decl->Code(),
+ (uint32_t)abbrev_code);
+ }
+ }
+ offset = DW_INVALID_OFFSET;
+ return NULL;
+}
+
+
+bool
+DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b)
+{
+ return a.GetOffset() < b.GetOffset();
+}
+
+void
+DWARFDebugInfoEntry::DumpDIECollection (Stream &strm, DWARFDebugInfoEntry::collection &die_collection)
+{
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = die_collection.end();
+ strm.PutCString("\noffset parent sibling child\n");
+ strm.PutCString("-------- -------- -------- --------\n");
+ for (pos = die_collection.begin(); pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry& die_ref = *pos;
+ const DWARFDebugInfoEntry* p = die_ref.GetParent();
+ const DWARFDebugInfoEntry* s = die_ref.GetSibling();
+ const DWARFDebugInfoEntry* c = die_ref.GetFirstChild();
+ strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n",
+ die_ref.GetOffset(),
+ p ? p->GetOffset() : 0,
+ s ? s->GetOffset() : 0,
+ c ? c->GetOffset() : 0,
+ die_ref.Tag(),
+ DW_TAG_value_to_name(die_ref.Tag()),
+ die_ref.HasChildren() ? " *" : "");
+ }
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
index 000000000000..85f4109ae01a
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,457 @@
+//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugInfoEntry_h_
+#define SymbolFileDWARF_DWARFDebugInfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFAbbreviationDeclaration.h"
+#include "DWARFDebugRanges.h"
+#include <vector>
+#include <map>
+#include <set>
+
+typedef std::map<const DWARFDebugInfoEntry*, dw_addr_t> DIEToAddressMap;
+typedef DIEToAddressMap::iterator DIEToAddressMapIter;
+typedef DIEToAddressMap::const_iterator DIEToAddressMapConstIter;
+
+typedef std::map<dw_addr_t, const DWARFDebugInfoEntry*> AddressToDIEMap;
+typedef AddressToDIEMap::iterator AddressToDIEMapIter;
+typedef AddressToDIEMap::const_iterator AddressToDIEMapConstIter;
+
+
+typedef std::map<dw_offset_t, dw_offset_t> DIEToDIEMap;
+typedef DIEToDIEMap::iterator DIEToDIEMapIter;
+typedef DIEToDIEMap::const_iterator DIEToDIEMapConstIter;
+
+typedef std::map<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMap;
+typedef UInt32ToDIEMap::iterator UInt32ToDIEMapIter;
+typedef UInt32ToDIEMap::const_iterator UInt32ToDIEMapConstIter;
+
+typedef std::multimap<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMMap;
+typedef UInt32ToDIEMMap::iterator UInt32ToDIEMMapIter;
+typedef UInt32ToDIEMMap::const_iterator UInt32ToDIEMMapConstIter;
+
+class DWARFDeclContext;
+
+#define DIE_SIBLING_IDX_BITSIZE 31
+#define DIE_ABBR_IDX_BITSIZE 15
+
+class DWARFDebugInfoEntry
+{
+public:
+ typedef std::vector<DWARFDebugInfoEntry> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ typedef std::vector<dw_offset_t> offset_collection;
+ typedef offset_collection::iterator offset_collection_iterator;
+ typedef offset_collection::const_iterator offset_collection_const_iterator;
+
+ class Attributes
+ {
+ public:
+ Attributes();
+ ~Attributes();
+
+ void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form);
+ const DWARFCompileUnit * CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; }
+ dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; }
+ dw_attr_t AttributeAtIndex(uint32_t i) const { return m_infos[i].attr; }
+ dw_attr_t FormAtIndex(uint32_t i) const { return m_infos[i].form; }
+ bool ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const;
+ uint64_t FormValueAsUnsignedAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const;
+ uint64_t FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const;
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool ContainsAttribute(dw_attr_t attr) const;
+ bool RemoveAttribute(dw_attr_t attr);
+ void Clear() { m_infos.clear(); }
+ size_t Size() const { return m_infos.size(); }
+
+ protected:
+ struct Info
+ {
+ const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in case we have DW_FORM_ref_addr values
+ dw_offset_t die_offset;
+ dw_attr_t attr;
+ dw_form_t form;
+ };
+
+ typedef llvm::SmallVector<Info, 32> collection;
+ collection m_infos;
+ };
+
+ struct CompareState
+ {
+ CompareState() :
+ die_offset_pairs()
+ {
+ assert(sizeof(dw_offset_t)*2 == sizeof(uint64_t));
+ }
+
+ bool AddTypePair(dw_offset_t a, dw_offset_t b)
+ {
+ uint64_t a_b_offsets = (uint64_t)a << 32 | (uint64_t)b;
+ // Return true if this type was inserted, false otherwise
+ return die_offset_pairs.insert(a_b_offsets).second;
+ }
+ std::set< uint64_t > die_offset_pairs;
+ };
+
+ DWARFDebugInfoEntry():
+ m_offset (DW_INVALID_OFFSET),
+ m_parent_idx (0),
+ m_sibling_idx (0),
+ m_empty_children(false),
+ m_abbr_idx (0),
+ m_has_children (false),
+ m_tag (0)
+ {
+ }
+
+ void Clear ()
+ {
+ m_offset = DW_INVALID_OFFSET;
+ m_parent_idx = 0;
+ m_sibling_idx = 0;
+ m_empty_children = false;
+ m_abbr_idx = 0;
+ m_has_children = false;
+ m_tag = 0;
+ }
+
+ bool Contains (const DWARFDebugInfoEntry *die) const;
+
+ void BuildAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ void BuildFunctionAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ bool FastExtract(
+ const lldb_private::DataExtractor& debug_info_data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ lldb::offset_t* offset_ptr);
+
+ bool Extract(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb::offset_t* offset_ptr);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t GetAttributes(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ DWARFDebugInfoEntry::Attributes& attrs,
+ uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!!
+
+ dw_offset_t GetAttributeValue(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& formValue,
+ dw_offset_t* end_attr_offset_ptr = NULL) const;
+
+ const char* GetAttributeValueAsString(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const;
+
+ uint64_t GetAttributeValueAsUnsigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ uint64_t GetAttributeValueAsReference(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ int64_t GetAttributeValueAsSigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value) const;
+
+ dw_addr_t GetAttributeHighPC(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t lo_pc,
+ uint64_t fail_value) const;
+
+ bool GetAttributeAddressRange(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t& lo_pc,
+ dw_addr_t& hi_pc,
+ uint64_t fail_value) const;
+
+ dw_offset_t GetAttributeValueAsLocation(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ lldb_private::DataExtractor& data,
+ uint32_t &block_size) const;
+
+ const char* GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ const char* GetMangledName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed = true) const;
+
+ const char* GetPubname(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ static bool GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream &s);
+
+ static bool AppendTypeName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream &s);
+
+ const char * GetQualifiedName (
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ std::string &storage) const;
+
+ const char * GetQualifiedName (
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes,
+ std::string &storage) const;
+
+// static int Compare(
+// SymbolFileDWARF* dwarf2Data,
+// dw_offset_t a_die_offset,
+// dw_offset_t b_die_offset,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children);
+//
+// static int Compare(
+// SymbolFileDWARF* dwarf2Data,
+// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children);
+
+ static bool OffsetLessThan (
+ const DWARFDebugInfoEntry& a,
+ const DWARFDebugInfoEntry& b);
+
+ void Dump(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb_private::Stream &s,
+ uint32_t recurse_depth) const;
+
+ void DumpAncestry(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ lldb_private::Stream &s,
+ uint32_t recurse_depth) const;
+
+ static void DumpAttribute(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_info_data,
+ lldb::offset_t *offset_ptr,
+ lldb_private::Stream &s,
+ dw_attr_t attr,
+ dw_form_t form);
+ // This one dumps the comp unit name, objfile name and die offset for this die so the stream S.
+ void DumpLocation(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ lldb_private::Stream &s) const;
+
+ bool GetDIENamesAndRanges(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& rangeList,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ lldb_private::DWARFExpression *frame_base = NULL) const;
+
+ const DWARFAbbreviationDeclaration*
+ GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit *cu,
+ lldb::offset_t &offset) const;
+
+ dw_tag_t
+ Tag () const
+ {
+ return m_tag;
+ }
+
+ bool
+ IsNULL() const
+ {
+ return m_abbr_idx == 0;
+ }
+
+ dw_offset_t
+ GetOffset () const
+ {
+ return m_offset;
+ }
+
+ void
+ SetOffset (dw_offset_t offset)
+ {
+ m_offset = offset;
+ }
+
+ bool
+ HasChildren () const
+ {
+ return m_has_children;
+ }
+
+ void
+ SetHasChildren (bool b)
+ {
+ m_has_children = b;
+ }
+
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ DWARFDebugInfoEntry* GetParent() { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ const DWARFDebugInfoEntry* GetParent() const { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ DWARFDebugInfoEntry* GetSibling() { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ const DWARFDebugInfoEntry* GetSibling() const { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // we don't need to store our child pointer, if we have a child it will
+ // be the next entry in the list...
+ DWARFDebugInfoEntry* GetFirstChild() { return (HasChildren() && !m_empty_children) ? this + 1 : NULL; }
+ const DWARFDebugInfoEntry* GetFirstChild() const { return (HasChildren() && !m_empty_children) ? this + 1 : NULL; }
+
+
+ void GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDIECollection &decl_context_dies) const;
+
+ void GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDeclContext &dwarf_decl_ctx) const;
+
+
+ bool MatchesDWARFDeclContext(SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDeclContext &dwarf_decl_ctx) const;
+
+ const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu) const;
+ const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes) const;
+
+ void
+ SetParent (DWARFDebugInfoEntry* parent)
+ {
+ if (parent)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ m_parent_idx = this - parent;
+ }
+ else
+ m_parent_idx = 0;
+ }
+ void
+ SetSibling (DWARFDebugInfoEntry* sibling)
+ {
+ if (sibling)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ m_sibling_idx = sibling - this;
+ sibling->SetParent(GetParent());
+ }
+ else
+ m_sibling_idx = 0;
+ }
+
+ void
+ SetSiblingIndex (uint32_t idx)
+ {
+ m_sibling_idx = idx;
+ }
+
+ void
+ SetParentIndex (uint32_t idx)
+ {
+ m_parent_idx = idx;
+ }
+
+ bool
+ GetEmptyChildren () const
+ {
+ return m_empty_children;
+ }
+
+ void
+ SetEmptyChildren (bool b)
+ {
+ m_empty_children = b;
+ }
+
+ static void
+ DumpDIECollection (lldb_private::Stream &strm,
+ DWARFDebugInfoEntry::collection &die_collection);
+
+protected:
+ dw_offset_t m_offset; // Offset within the .debug_info of the start of this entry
+ uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. If zero this die has no parent
+ uint32_t m_sibling_idx:31, // How many to add to "this" to get the sibling.
+ m_empty_children:1; // If a DIE says it had children, yet it just contained a NULL tag, this will be set.
+ uint32_t m_abbr_idx:DIE_ABBR_IDX_BITSIZE,
+ m_has_children:1, // Set to 1 if this DIE has children
+ m_tag:16; // A copy of the DW_TAG value so we don't have to go through the compile unit abbrev table
+
+};
+
+#endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 000000000000..6c9336a08426
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1436 @@
+//===-- DWARFDebugLine.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugLine.h"
+
+//#define ENABLE_DEBUG_PRINTF // DO NOT LEAVE THIS DEFINED: DEBUG ONLY!!!
+#include <assert.h>
+
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+
+#include "SymbolFileDWARF.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse all information in the debug_line_data into an internal
+// representation.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data)
+{
+ m_lineTableMap.clear();
+ lldb::offset_t offset = 0;
+ LineTable::shared_ptr line_table_sp(new LineTable);
+ while (debug_line_data.ValidOffset(offset))
+ {
+ const lldb::offset_t debug_line_offset = offset;
+
+ if (line_table_sp.get() == NULL)
+ break;
+
+ if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get()))
+ {
+ // Make sure we don't don't loop infinitely
+ if (offset <= debug_line_offset)
+ break;
+ //DEBUG_PRINTF("m_lineTableMap[0x%8.8x] = line_table_sp\n", debug_line_offset);
+ m_lineTableMap[debug_line_offset] = line_table_sp;
+ line_table_sp.reset(new LineTable);
+ }
+ else
+ ++offset; // Try next byte in line table
+ }
+}
+
+void
+DWARFDebugLine::ParseIfNeeded(const DataExtractor& debug_line_data)
+{
+ if (m_lineTableMap.empty())
+ Parse(debug_line_data);
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::GetLineTable
+//----------------------------------------------------------------------
+DWARFDebugLine::LineTable::shared_ptr
+DWARFDebugLine::GetLineTable(const dw_offset_t offset) const
+{
+ DWARFDebugLine::LineTable::shared_ptr line_table_shared_ptr;
+ LineTableConstIter pos = m_lineTableMap.find(offset);
+ if (pos != m_lineTableMap.end())
+ line_table_shared_ptr = pos->second;
+ return line_table_shared_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DumpStateToFile
+//----------------------------------------------------------------------
+static void
+DumpStateToFile (dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ Log *log = (Log *)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // If the row is zero we are being called with the prologue only
+ state.prologue->Dump (log);
+ log->PutCString ("Address Line Column File");
+ log->PutCString ("------------------ ------ ------ ------");
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table
+ }
+ else
+ {
+ log->Printf( "0x%16.16" PRIx64 " %6u %6u %6u%s\n", state.address, state.line, state.column, state.file, state.end_sequence ? " END" : "");
+ }
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpLineTableRows
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpLineTableRows(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpStatementTable
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementTable(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset)
+{
+ if (debug_line_data.ValidOffset(debug_line_offset))
+ {
+ lldb::offset_t offset = debug_line_offset;
+ log->Printf( "----------------------------------------------------------------------\n"
+ "debug_line[0x%8.8x]\n"
+ "----------------------------------------------------------------------\n", debug_line_offset);
+
+ if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log))
+ return offset;
+ else
+ return debug_line_offset + 1; // Skip to next byte in .debug_line section
+ }
+
+ return DW_INVALID_OFFSET;
+}
+
+
+//----------------------------------------------------------------------
+// DumpOpcodes
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpOpcodes(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset, uint32_t dump_flags)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_data.GetByteSize() == 0)
+ {
+ log->Printf( "< EMPTY >\n");
+ return false;
+ }
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DumpStatementOpcodes
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementOpcodes(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset, uint32_t flags)
+{
+ lldb::offset_t offset = debug_line_offset;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ Prologue prologue;
+
+ if (ParsePrologue(debug_line_data, &offset, &prologue))
+ {
+ log->PutCString ("----------------------------------------------------------------------");
+ log->Printf ("debug_line[0x%8.8x]", debug_line_offset);
+ log->PutCString ("----------------------------------------------------------------------\n");
+ prologue.Dump (log);
+ }
+ else
+ {
+ offset = debug_line_offset;
+ log->Printf( "0x%8.8" PRIx64 ": skipping pad byte %2.2x", offset, debug_line_data.GetU8(&offset));
+ return offset;
+ }
+
+ Row row(prologue.default_is_stmt);
+ const dw_offset_t end_offset = debug_line_offset + prologue.total_length + sizeof(prologue.total_length);
+
+ assert(debug_line_data.ValidOffset(end_offset-1));
+
+ while (offset < end_offset)
+ {
+ const uint32_t op_offset = offset;
+ uint8_t opcode = debug_line_data.GetU8(&offset);
+ switch (opcode)
+ {
+ case 0: // Extended Opcodes always start with a zero opcode followed by
+ { // a uleb128 length so you can skip ones you don't know about
+
+ dw_offset_t ext_offset = offset;
+ dw_uleb128_t len = debug_line_data.GetULEB128(&offset);
+ dw_offset_t arg_size = len - (offset - ext_offset);
+ uint8_t sub_opcode = debug_line_data.GetU8(&offset);
+// if (verbose)
+// log->Printf( "Extended: <%u> %2.2x ", len, sub_opcode);
+
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence :
+ log->Printf( "0x%8.8x: DW_LNE_end_sequence", op_offset);
+ row.Dump(log);
+ row.Reset(prologue.default_is_stmt);
+ break;
+
+ case DW_LNE_set_address :
+ {
+ row.address = debug_line_data.GetMaxU64(&offset, arg_size);
+ log->Printf( "0x%8.8x: DW_LNE_set_address (0x%" PRIx64 ")", op_offset, row.address);
+ }
+ break;
+
+ case DW_LNE_define_file:
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(&offset);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(&offset);
+ fileEntry.mod_time = debug_line_data.GetULEB128(&offset);
+ fileEntry.length = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNE_define_file('%s', dir=%i, mod_time=0x%8.8x, length=%i )",
+ op_offset,
+ fileEntry.name.c_str(),
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length);
+ prologue.file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode);
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ offset += arg_size;
+ break;
+ }
+ }
+ break;
+
+ // Standard Opcodes
+ case DW_LNS_copy:
+ log->Printf( "0x%8.8x: DW_LNS_copy", op_offset);
+ row.Dump (log);
+ break;
+
+ case DW_LNS_advance_pc:
+ {
+ dw_uleb128_t addr_offset_n = debug_line_data.GetULEB128(&offset);
+ dw_uleb128_t addr_offset = addr_offset_n * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_advance_pc (0x%x)", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ {
+ dw_sleb128_t line_offset = debug_line_data.GetSLEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_advance_line (%i)", op_offset, line_offset);
+ row.line += line_offset;
+ }
+ break;
+
+ case DW_LNS_set_file:
+ row.file = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_file (%u)", op_offset, row.file);
+ break;
+
+ case DW_LNS_set_column:
+ row.column = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_column (%u)", op_offset, row.column);
+ break;
+
+ case DW_LNS_negate_stmt:
+ row.is_stmt = !row.is_stmt;
+ log->Printf( "0x%8.8x: DW_LNS_negate_stmt", op_offset);
+ break;
+
+ case DW_LNS_set_basic_block:
+ row.basic_block = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_basic_block", op_offset);
+ break;
+
+ case DW_LNS_const_add_pc:
+ {
+ uint8_t adjust_opcode = 255 - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_const_add_pc (0x%8.8" PRIx64 ")", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ {
+ uint16_t pc_offset = debug_line_data.GetU16(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_fixed_advance_pc (0x%4.4x)", op_offset, pc_offset);
+ row.address += pc_offset;
+ }
+ break;
+
+ case DW_LNS_set_prologue_end:
+ row.prologue_end = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_prologue_end", op_offset);
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ row.epilogue_begin = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_epilogue_begin", op_offset);
+ break;
+
+ case DW_LNS_set_isa:
+ row.isa = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_isa (%u)", op_offset, row.isa);
+ break;
+
+ // Special Opcodes
+ default:
+ if (opcode < prologue.opcode_base)
+ {
+ // We have an opcode that this parser doesn't know about, skip
+ // the number of ULEB128 numbers that is says to skip in the
+ // prologue's standard_opcode_lengths array
+ uint8_t n = prologue.standard_opcode_lengths[opcode-1];
+ log->Printf( "0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n);
+ while (n > 0)
+ {
+ debug_line_data.GetULEB128(&offset);
+ --n;
+ }
+ }
+ else
+ {
+ uint8_t adjust_opcode = opcode - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ int32_t line_offset = prologue.line_base + (adjust_opcode % prologue.line_range);
+ log->Printf("0x%8.8x: address += 0x%" PRIx64 ", line += %i\n", op_offset, (uint64_t)addr_offset, line_offset);
+ row.address += addr_offset;
+ row.line += line_offset;
+ row.Dump (log);
+ }
+ break;
+ }
+ }
+ return end_offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse the entire line table contents calling callback each time a
+// new prologue is parsed and every time a new row is to be added to
+// the line table.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData)
+{
+ lldb::offset_t offset = 0;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ if (!ParseStatementTable(debug_line_data, &offset, callback, userData))
+ ++offset; // Skip to next byte in .debug_line section
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParsePrologue(const DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, Prologue* prologue)
+{
+ const lldb::offset_t prologue_offset = *offset_ptr;
+
+ //DEBUG_PRINTF("0x%8.8x: ParsePrologue()\n", *offset_ptr);
+
+ prologue->Clear();
+ uint32_t i;
+ const char * s;
+ prologue->total_length = debug_line_data.GetU32(offset_ptr);
+ prologue->version = debug_line_data.GetU16(offset_ptr);
+ if (prologue->version != 2)
+ return false;
+
+ prologue->prologue_length = debug_line_data.GetU32(offset_ptr);
+ const lldb::offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr;
+ prologue->min_inst_length = debug_line_data.GetU8(offset_ptr);
+ 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);
+ prologue->opcode_base = debug_line_data.GetU8(offset_ptr);
+
+ prologue->standard_opcode_lengths.reserve(prologue->opcode_base-1);
+
+ for (i=1; i<prologue->opcode_base; ++i)
+ {
+ uint8_t op_len = debug_line_data.GetU8(offset_ptr);
+ prologue->standard_opcode_lengths.push_back(op_len);
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(offset_ptr);
+ if (s && s[0])
+ prologue->include_directories.push_back(s);
+ else
+ break;
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ const char* name = debug_line_data.GetCStr( offset_ptr );
+ if (name && name[0])
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = name;
+ fileEntry.dir_idx = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.mod_time = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.length = debug_line_data.GetULEB128( offset_ptr );
+ prologue->file_names.push_back(fileEntry);
+ }
+ else
+ break;
+ }
+
+ if (*offset_ptr != end_prologue_offset)
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: parsing line table prologue at 0x%8.8" PRIx64 " should have ended at 0x%8.8" PRIx64 " but it ended ad 0x%8.8" PRIx64 "\n",
+ prologue_offset,
+ end_prologue_offset,
+ *offset_ptr);
+ }
+ return end_prologue_offset;
+}
+
+bool
+DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
+ const DataExtractor& debug_line_data,
+ const char *cu_comp_dir,
+ dw_offset_t stmt_list,
+ FileSpecList &support_files)
+{
+ lldb::offset_t offset = stmt_list + 4; // Skip the total length
+ const char * s;
+ uint32_t version = debug_line_data.GetU16(&offset);
+ if (version != 2)
+ return false;
+
+ const dw_offset_t end_prologue_offset = debug_line_data.GetU32(&offset) + offset;
+ // Skip instruction length, default is stmt, line base, line range and
+ // opcode base, and all opcode lengths
+ offset += 4;
+ const uint8_t opcode_base = debug_line_data.GetU8(&offset);
+ offset += opcode_base - 1;
+ std::vector<std::string> include_directories;
+ include_directories.push_back(""); // Directory at index zero doesn't exist
+ while (offset < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(&offset);
+ if (s && s[0])
+ include_directories.push_back(s);
+ else
+ break;
+ }
+ std::string fullpath;
+ std::string remapped_fullpath;
+ while (offset < end_prologue_offset)
+ {
+ const char* path = debug_line_data.GetCStr( &offset );
+ if (path && path[0])
+ {
+ uint32_t dir_idx = debug_line_data.GetULEB128( &offset );
+ debug_line_data.Skip_LEB128(&offset); // Skip mod_time
+ debug_line_data.Skip_LEB128(&offset); // Skip length
+
+ if (path[0] == '/')
+ {
+ // The path starts with a directory delimiter, so we are done.
+ if (module_sp->RemapSourceFile (path, fullpath))
+ support_files.Append(FileSpec (fullpath.c_str(), false));
+ else
+ support_files.Append(FileSpec (path, false));
+ }
+ else
+ {
+ if (dir_idx > 0 && dir_idx < include_directories.size())
+ {
+ if (cu_comp_dir && include_directories[dir_idx][0] != '/')
+ {
+ fullpath = cu_comp_dir;
+
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += include_directories[dir_idx];
+
+ }
+ else
+ fullpath = include_directories[dir_idx];
+ }
+ else if (cu_comp_dir && cu_comp_dir[0])
+ {
+ fullpath = cu_comp_dir;
+ }
+
+ if (!fullpath.empty())
+ {
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ }
+ fullpath += path;
+ if (module_sp->RemapSourceFile (fullpath.c_str(), remapped_fullpath))
+ support_files.Append(FileSpec (remapped_fullpath.c_str(), false));
+ else
+ support_files.Append(FileSpec (fullpath.c_str(), false));
+ }
+
+ }
+ }
+
+ if (offset != end_prologue_offset)
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "warning: parsing line table prologue at 0x%8.8x should have ended at 0x%8.8x but it ended ad 0x%8.8" PRIx64 "\n",
+ stmt_list,
+ end_prologue_offset,
+ offset);
+ }
+ return end_prologue_offset;
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a single line table (prologue and all rows) and call the
+// callback function once for the prologue (row in state will be zero)
+// and each time a row is to be added to the line table.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable
+(
+ const DataExtractor& debug_line_data,
+ lldb::offset_t* offset_ptr,
+ DWARFDebugLine::State::Callback callback,
+ void* userData
+)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_LINE));
+ Prologue::shared_ptr prologue(new Prologue());
+
+
+ const dw_offset_t debug_line_offset = *offset_ptr;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])",
+ debug_line_offset);
+
+ if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get()))
+ {
+ if (log)
+ log->Error ("failed to parse DWARF line table prologue");
+ // Restore our offset and return false to indicate failure!
+ *offset_ptr = debug_line_offset;
+ return false;
+ }
+
+ if (log)
+ prologue->Dump (log);
+
+ const dw_offset_t end_offset = debug_line_offset + prologue->total_length + sizeof(prologue->total_length);
+
+ State state(prologue, log, callback, userData);
+
+ while (*offset_ptr < end_offset)
+ {
+ //DEBUG_PRINTF("0x%8.8x: ", *offset_ptr);
+ uint8_t opcode = debug_line_data.GetU8(offset_ptr);
+
+ if (opcode == 0)
+ {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ lldb::offset_t ext_offset = *offset_ptr;
+ dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr);
+ dw_offset_t arg_size = len - (*offset_ptr - ext_offset);
+
+ //DEBUG_PRINTF("Extended: <%2u> ", len);
+ uint8_t sub_opcode = debug_line_data.GetU8(offset_ptr);
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ state.end_sequence = true;
+ state.AppendRowToMatrix(*offset_ptr);
+ state.Reset();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // 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);
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number representing
+ // the directory index of the directory in which the file was found. The
+ // third is an unsigned LEB128 number representing the time of last
+ // modification of the file. The fourth is an unsigned LEB128 number
+ // representing the length in bytes of the file. The time and length
+ // fields may contain LEB128(0) if the information is not available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(offset_ptr);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.length = debug_line_data.GetULEB128(offset_ptr);
+ state.prologue->file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ (*offset_ptr) += arg_size;
+ break;
+ }
+ }
+ else if (opcode < prologue->opcode_base)
+ {
+ switch (opcode)
+ {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers. Then set
+ // the basic_block register to false.
+ state.AppendRowToMatrix(*offset_ptr);
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length;
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ state.line += debug_line_data.GetSLEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ state.file = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.column = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ state.is_stmt = !state.is_stmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.basic_block = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint8_t adjust_opcode = 255 - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ state.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ state.address += debug_line_data.GetU16(offset_ptr);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ state.prologue_end = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.epilogue_begin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.isa = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ uint8_t i;
+ assert (opcode - 1 < prologue->standard_opcode_lengths.size());
+ const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1];
+ for (i=0; i<opcode_length; ++i)
+ debug_line_data.Skip_LEB128(offset_ptr);
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Special Opcodes
+
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) + (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) * minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ uint8_t adjust_opcode = opcode - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ int32_t line_offset = prologue->line_base + (adjust_opcode % prologue->line_range);
+ state.line += line_offset;
+ state.address += addr_offset;
+ state.AppendRowToMatrix(*offset_ptr);
+ }
+ }
+
+ state.Finalize( *offset_ptr );
+
+ return end_offset;
+}
+
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseStatementTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ DWARFDebugLine::LineTable* line_table = (DWARFDebugLine::LineTable*)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table, so lets keep a reference to
+ // the prologue using the supplied shared pointer
+ line_table->prologue = state.prologue;
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ // We have a new row, lets append it
+ line_table->AppendRow(state);
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a line table at offset and populate the LineTable class with
+// the prologue and all rows.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable(const DataExtractor& debug_line_data, lldb::offset_t *offset_ptr, LineTable* line_table)
+{
+ return ParseStatementTable(debug_line_data, offset_ptr, ParseStatementTableCallback, line_table);
+}
+
+
+inline bool
+DWARFDebugLine::Prologue::IsValid() const
+{
+ return SymbolFileDWARF::SupportedVersion(version);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Prologue::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Prologue::Dump(Log *log)
+{
+ uint32_t i;
+
+ log->Printf( "Line table prologue:");
+ log->Printf( " total_length: 0x%8.8x", total_length);
+ log->Printf( " version: %u", version);
+ log->Printf( "prologue_length: 0x%8.8x", prologue_length);
+ log->Printf( "min_inst_length: %u", min_inst_length);
+ log->Printf( "default_is_stmt: %u", default_is_stmt);
+ log->Printf( " line_base: %i", line_base);
+ log->Printf( " line_range: %u", line_range);
+ log->Printf( " opcode_base: %u", opcode_base);
+
+ for (i=0; i<standard_opcode_lengths.size(); ++i)
+ {
+ log->Printf( "standard_opcode_lengths[%s] = %u", DW_LNS_value_to_name(i+1), standard_opcode_lengths[i]);
+ }
+
+ if (!include_directories.empty())
+ {
+ for (i=0; i<include_directories.size(); ++i)
+ {
+ log->Printf( "include_directories[%3u] = '%s'", i+1, include_directories[i].c_str());
+ }
+ }
+
+ if (!file_names.empty())
+ {
+ log->PutCString (" Dir Mod Time File Len File Name");
+ log->PutCString (" ---- ---------- ---------- ---------------------------");
+ for (i=0; i<file_names.size(); ++i)
+ {
+ const FileNameEntry& fileEntry = file_names[i];
+ log->Printf ("file_names[%3u] %4u 0x%8.8x 0x%8.8x %s",
+ i+1,
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length,
+ fileEntry.name.c_str());
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue::Append
+//
+// Append the contents of the prologue to the binary stream buffer
+//----------------------------------------------------------------------
+//void
+//DWARFDebugLine::Prologue::Append(BinaryStreamBuf& buff) const
+//{
+// uint32_t i;
+//
+// buff.Append32(total_length);
+// buff.Append16(version);
+// buff.Append32(prologue_length);
+// buff.Append8(min_inst_length);
+// buff.Append8(default_is_stmt);
+// buff.Append8(line_base);
+// buff.Append8(line_range);
+// buff.Append8(opcode_base);
+//
+// for (i=0; i<standard_opcode_lengths.size(); ++i)
+// buff.Append8(standard_opcode_lengths[i]);
+//
+// for (i=0; i<include_directories.size(); ++i)
+// buff.AppendCStr(include_directories[i].c_str());
+// buff.Append8(0); // Terminate the include directory section with empty string
+//
+// for (i=0; i<file_names.size(); ++i)
+// {
+// buff.AppendCStr(file_names[i].name.c_str());
+// buff.Append32_as_ULEB128(file_names[i].dir_idx);
+// buff.Append32_as_ULEB128(file_names[i].mod_time);
+// buff.Append32_as_ULEB128(file_names[i].length);
+// }
+// buff.Append8(0); // Terminate the file names section with empty string
+//}
+
+
+bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, std::string& path, std::string& directory) const
+{
+ uint32_t idx = file_idx - 1; // File indexes are 1 based...
+ if (idx < file_names.size())
+ {
+ path = file_names[idx].name;
+ uint32_t dir_idx = file_names[idx].dir_idx - 1;
+ if (dir_idx < include_directories.size())
+ directory = include_directories[dir_idx];
+ else
+ directory.clear();
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::LineTable::Dump(Log *log) const
+{
+ if (prologue.get())
+ prologue->Dump (log);
+
+ if (!rows.empty())
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ Row::const_iterator pos = rows.begin();
+ Row::const_iterator end = rows.end();
+ while (pos != end)
+ {
+ (*pos).Dump (log);
+ ++pos;
+ }
+ }
+}
+
+
+void
+DWARFDebugLine::LineTable::AppendRow(const DWARFDebugLine::Row& state)
+{
+ rows.push_back(state);
+}
+
+
+
+//----------------------------------------------------------------------
+// Compare function for the binary search in DWARFDebugLine::LineTable::LookupAddress()
+//----------------------------------------------------------------------
+static bool FindMatchingAddress (const DWARFDebugLine::Row& row1, const DWARFDebugLine::Row& row2)
+{
+ return row1.address < row2.address;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::LookupAddress
+//----------------------------------------------------------------------
+uint32_t
+DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const
+{
+ uint32_t index = UINT32_MAX;
+ if (!rows.empty())
+ {
+ // Use the lower_bound algorithm to perform a binary search since we know
+ // that our line table data is ordered by address.
+ DWARFDebugLine::Row row;
+ row.address = address;
+ Row::const_iterator begin_pos = rows.begin();
+ Row::const_iterator end_pos = rows.end();
+ Row::const_iterator pos = lower_bound(begin_pos, end_pos, row, FindMatchingAddress);
+ if (pos == end_pos)
+ {
+ if (address < cu_high_pc)
+ return rows.size()-1;
+ }
+ else
+ {
+ // Rely on fact that we are using a std::vector and we can do
+ // pointer arithmetic to find the row index (which will be one less
+ // that what we found since it will find the first position after
+ // the current address) since std::vector iterators are just
+ // pointers to the container type.
+ index = pos - begin_pos;
+ if (pos->address > address)
+ {
+ if (index > 0)
+ --index;
+ else
+ index = UINT32_MAX;
+ }
+ }
+ }
+ return index; // Failed to find address
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Row
+//----------------------------------------------------------------------
+DWARFDebugLine::Row::Row(bool default_is_stmt) :
+ address(0),
+ line(1),
+ column(0),
+ file(1),
+ is_stmt(default_is_stmt),
+ basic_block(false),
+ end_sequence(false),
+ prologue_end(false),
+ epilogue_begin(false),
+ isa(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Called after a row is appended to the matrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::PostAppend()
+{
+ basic_block = false;
+ prologue_end = false;
+ epilogue_begin = false;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Reset(bool default_is_stmt)
+{
+ address = 0;
+ line = 1;
+ column = 0;
+ file = 1;
+ is_stmt = default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+ isa = 0;
+}
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Dump(Log *log) const
+{
+ log->Printf( "0x%16.16" PRIx64 " %6u %6u %6u %3u %s%s%s%s%s",
+ address,
+ line,
+ column,
+ file,
+ isa,
+ is_stmt ? " is_stmt" : "",
+ basic_block ? " basic_block" : "",
+ prologue_end ? " prologue_end" : "",
+ epilogue_begin ? " epilogue_begin" : "",
+ end_sequence ? " end_sequence" : "");
+}
+
+//----------------------------------------------------------------------
+// Compare function LineTable structures
+//----------------------------------------------------------------------
+static bool AddressLessThan (const DWARFDebugLine::Row& a, const DWARFDebugLine::Row& b)
+{
+ return a.address < b.address;
+}
+
+
+
+// Insert a row at the correct address if the addresses can be out of
+// order which can only happen when we are linking a line table that
+// may have had it's contents rearranged.
+void
+DWARFDebugLine::Row::Insert(Row::collection& state_coll, const Row& state)
+{
+ // If we don't have anything yet, or if the address of the last state in our
+ // line table is less than the current one, just append the current state
+ if (state_coll.empty() || AddressLessThan(state_coll.back(), state))
+ {
+ state_coll.push_back(state);
+ }
+ else
+ {
+ // Do a binary search for the correct entry
+ pair<Row::iterator, Row::iterator> range(equal_range(state_coll.begin(), state_coll.end(), state, AddressLessThan));
+
+ // If the addresses are equal, we can safely replace the previous entry
+ // with the current one if the one it is replacing is an end_sequence entry.
+ // We currently always place an extra end sequence when ever we exit a valid
+ // address range for a function in case the functions get rearranged by
+ // optimizations or by order specifications. These extra end sequences will
+ // disappear by getting replaced with valid consecutive entries within a
+ // compile unit if there are no gaps.
+ if (range.first == range.second)
+ {
+ state_coll.insert(range.first, state);
+ }
+ else
+ {
+ if ((distance(range.first, range.second) == 1) && range.first->end_sequence == true)
+ {
+ *range.first = state;
+ }
+ else
+ {
+ state_coll.insert(range.second, state);
+ }
+ }
+ }
+}
+
+void
+DWARFDebugLine::Row::Dump(Log *log, const Row::collection& state_coll)
+{
+ std::for_each (state_coll.begin(), state_coll.end(), bind2nd(std::mem_fun_ref(&Row::Dump),log));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::State
+//----------------------------------------------------------------------
+DWARFDebugLine::State::State(Prologue::shared_ptr& p, Log *l, DWARFDebugLine::State::Callback cb, void* userData) :
+ Row (p->default_is_stmt),
+ prologue (p),
+ log (l),
+ callback (cb),
+ callbackUserData (userData),
+ row (StartParsingLineTable)
+{
+ // Call the callback with the initial row state of zero for the prologue
+ if (callback)
+ callback(0, *this, callbackUserData);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Reset()
+{
+ Row::Reset(prologue->default_is_stmt);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::AppendRowToMatrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset)
+{
+ // Each time we are to add an entry into the line table matrix
+ // call the callback function so that someone can do something with
+ // the current state of the state machine (like build a line table
+ // or dump the line table!)
+ if (log)
+ {
+ if (row == 0)
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ }
+ Dump (log);
+ }
+
+ ++row; // Increase the row number before we call our callback for a real row
+ if (callback)
+ callback(offset, *this, callbackUserData);
+ PostAppend();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Finalize
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Finalize(dw_offset_t offset)
+{
+ // Call the callback with a special row state when we are done parsing a
+ // line table
+ row = DoneParsingLineTable;
+ if (callback)
+ callback(offset, *this, callbackUserData);
+}
+
+//void
+//DWARFDebugLine::AppendLineTableData
+//(
+// const DWARFDebugLine::Prologue* prologue,
+// const DWARFDebugLine::Row::collection& state_coll,
+// const uint32_t addr_size,
+// BinaryStreamBuf &debug_line_data
+//)
+//{
+// if (state_coll.empty())
+// {
+// // We have no entries, just make an empty line table
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+// }
+// else
+// {
+// DWARFDebugLine::Row::const_iterator pos;
+// Row::const_iterator end = state_coll.end();
+// bool default_is_stmt = prologue->default_is_stmt;
+// const DWARFDebugLine::Row reset_state(default_is_stmt);
+// const DWARFDebugLine::Row* prev_state = &reset_state;
+// const int32_t max_line_increment_for_special_opcode = prologue->MaxLineIncrementForSpecialOpcode();
+// for (pos = state_coll.begin(); pos != end; ++pos)
+// {
+// const DWARFDebugLine::Row& curr_state = *pos;
+// int32_t line_increment = 0;
+// dw_addr_t addr_offset = curr_state.address - prev_state->address;
+// dw_addr_t addr_advance = (addr_offset) / prologue->min_inst_length;
+// line_increment = (int32_t)(curr_state.line - prev_state->line);
+//
+// // If our previous state was the reset state, then let's emit the
+// // address to keep GDB's DWARF parser happy. If we don't start each
+// // sequence with a DW_LNE_set_address opcode, the line table won't
+// // get slid properly in GDB.
+//
+// if (prev_state == &reset_state)
+// {
+// debug_line_data.Append8(0); // Extended opcode
+// debug_line_data.Append32_as_ULEB128(addr_size + 1); // Length of opcode bytes
+// debug_line_data.Append8(DW_LNE_set_address);
+// debug_line_data.AppendMax64(curr_state.address, addr_size);
+// addr_advance = 0;
+// }
+//
+// if (prev_state->file != curr_state.file)
+// {
+// debug_line_data.Append8(DW_LNS_set_file);
+// debug_line_data.Append32_as_ULEB128(curr_state.file);
+// }
+//
+// if (prev_state->column != curr_state.column)
+// {
+// debug_line_data.Append8(DW_LNS_set_column);
+// debug_line_data.Append32_as_ULEB128(curr_state.column);
+// }
+//
+// // Don't do anything fancy if we are at the end of a sequence
+// // as we don't want to push any extra rows since the DW_LNE_end_sequence
+// // will push a row itself!
+// if (curr_state.end_sequence)
+// {
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push the end sequence on!
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+//
+// prev_state = &reset_state;
+// }
+// else
+// {
+// if (line_increment || addr_advance)
+// {
+// if (line_increment > max_line_increment_for_special_opcode)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// line_increment = 0;
+// }
+//
+// uint32_t special_opcode = (line_increment >= prologue->line_base) ? ((line_increment - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+// if (special_opcode > 255)
+// {
+// // Both the address and line won't fit in one special opcode
+// // check to see if just the line advance will?
+// uint32_t special_opcode_line = ((line_increment >= prologue->line_base) && (line_increment != 0)) ?
+// ((line_increment - prologue->line_base) + prologue->opcode_base) : 256;
+//
+//
+// if (special_opcode_line > 255)
+// {
+// // Nope, the line advance won't fit by itself, check the address increment by itself
+// uint32_t special_opcode_addr = addr_advance ?
+// ((0 - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+//
+// if (special_opcode_addr > 255)
+// {
+// // Neither the address nor the line will fit in a
+// // special opcode, we must manually enter both then
+// // do a DW_LNS_copy to push a row (special opcode
+// // automatically imply a new row is pushed)
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push a row onto the line table manually
+// debug_line_data.Append8(DW_LNS_copy);
+//
+// }
+// else
+// {
+// // The address increment alone will fit into a special opcode
+// // so modify our line change, then issue a special opcode
+// // for the address increment and it will push a row into the
+// // line table
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_addr);
+// }
+// }
+// else
+// {
+// // The line change alone will fit into a special opcode
+// // so modify our address increment first, then issue a
+// // special opcode for the line change and it will push
+// // a row into the line table
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_line);
+// }
+// }
+// else
+// {
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode);
+// }
+// }
+// prev_state = &curr_state;
+// }
+// }
+// }
+//}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
new file mode 100644
index 000000000000..cfa8654ed9ba
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
@@ -0,0 +1,225 @@
+//===-- DWARFDebugLine.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugLine_h_
+#define SymbolFileDWARF_DWARFDebugLine_h_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+
+class SymbolFileDWARF;
+class DWARFDebugInfoEntry;
+
+//----------------------------------------------------------------------
+// DWARFDebugLine
+//----------------------------------------------------------------------
+class DWARFDebugLine
+{
+public:
+ //------------------------------------------------------------------
+ // FileNameEntry
+ //------------------------------------------------------------------
+ struct FileNameEntry
+ {
+ FileNameEntry() :
+ name(),
+ dir_idx(0),
+ mod_time(0),
+ length(0)
+ {
+ }
+
+ std::string name;
+ dw_sleb128_t dir_idx;
+ dw_sleb128_t mod_time;
+ dw_sleb128_t length;
+
+ };
+
+ //------------------------------------------------------------------
+ // Prologue
+ //------------------------------------------------------------------
+ struct Prologue
+ {
+
+ Prologue() :
+ total_length(0),
+ version(0),
+ prologue_length(0),
+ min_inst_length(0),
+ default_is_stmt(0),
+ line_base(0),
+ line_range(0),
+ opcode_base(0),
+ standard_opcode_lengths(),
+ include_directories(),
+ file_names()
+ {
+ }
+
+ typedef std::shared_ptr<Prologue> shared_ptr;
+
+ uint32_t total_length; // The size in bytes of the statement information for this compilation unit (not including the total_length field itself).
+ 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 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.
+ uint8_t opcode_base; // The number assigned to the first special opcode.
+ std::vector<uint8_t> standard_opcode_lengths;
+ std::vector<std::string> include_directories;
+ std::vector<FileNameEntry> file_names;
+
+ // Length of the prologue in bytes
+ uint32_t Length() const { return prologue_length + sizeof(total_length) + sizeof(version) + sizeof(prologue_length); }
+ // Length of the line table data in bytes (not including the prologue)
+ uint32_t StatementTableLength() const { return total_length + sizeof(total_length) - Length(); }
+ int32_t MaxLineIncrementForSpecialOpcode() const { return line_base + (int8_t)line_range - 1; }
+ bool IsValid() const;
+// void Append(BinaryStreamBuf& buff) const;
+ void Dump (lldb_private::Log *log);
+ void Clear()
+ {
+ total_length = version = prologue_length = min_inst_length = line_base = line_range = opcode_base = 0;
+ line_base = 0;
+ standard_opcode_lengths.clear();
+ include_directories.clear();
+ file_names.clear();
+ }
+ bool GetFile(uint32_t file_idx, std::string& file, std::string& dir) const;
+
+ };
+
+ // Standard .debug_line state machine structure
+ struct Row
+ {
+ typedef std::vector<Row> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ Row(bool default_is_stmt = false);
+ virtual ~Row() {}
+ void PostAppend ();
+ void Reset(bool default_is_stmt);
+ void Dump(lldb_private::Log *log) const;
+ static void Insert(Row::collection& state_coll, const Row& state);
+ static void Dump(lldb_private::Log *log, const Row::collection& state_coll);
+
+ dw_addr_t address; // The program-counter value corresponding to a machine instruction generated by the compiler.
+ uint32_t line; // An unsigned integer indicating a source line number. Lines are numbered beginning at 1. The compiler may emit the value 0 in cases where an instruction cannot be attributed to any source line.
+ uint16_t column; // An unsigned integer indicating a column number within a source line. Columns are numbered beginning at 1. The value 0 is reserved to indicate that a statement begins at the 'left edge' of the line.
+ uint16_t file; // An unsigned integer indicating the identity of the source file corresponding to a machine instruction.
+ uint8_t is_stmt:1, // A boolean indicating that the current instruction is the beginning of a statement.
+ basic_block:1, // A boolean indicating that the current instruction is the beginning of a basic block.
+ end_sequence:1, // A boolean indicating that the current address is that of the first byte after the end of a sequence of target machine instructions.
+ prologue_end:1, // A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an entry breakpoint of a function.
+ epilogue_begin:1;// A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an exit breakpoint of a function.
+ uint32_t isa; // An unsigned integer whose value encodes the applicable instruction set architecture for the current instruction.
+ };
+
+
+ //------------------------------------------------------------------
+ // LineTable
+ //------------------------------------------------------------------
+ struct LineTable
+ {
+ typedef std::shared_ptr<LineTable> shared_ptr;
+
+ LineTable() :
+ prologue(),
+ rows()
+ {
+ }
+
+ void AppendRow(const DWARFDebugLine::Row& state);
+ void Clear()
+ {
+ prologue.reset();
+ rows.clear();
+ }
+
+ uint32_t LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const;
+ void Dump(lldb_private::Log *log) const;
+
+ Prologue::shared_ptr prologue;
+ Row::collection rows;
+ };
+
+ //------------------------------------------------------------------
+ // State
+ //------------------------------------------------------------------
+ struct State : public Row
+ {
+ typedef void (*Callback)(dw_offset_t offset, const State& state, void* userData);
+
+ // Special row codes used when calling the callback
+ enum
+ {
+ StartParsingLineTable = 0,
+ DoneParsingLineTable = -1
+ };
+
+ State (Prologue::shared_ptr& prologue_sp,
+ lldb_private::Log *log,
+ Callback callback,
+ void* userData);
+
+ void
+ AppendRowToMatrix (dw_offset_t offset);
+
+ void
+ Finalize (dw_offset_t offset);
+
+ void
+ Reset ();
+
+ Prologue::shared_ptr prologue;
+ lldb_private::Log *log;
+ Callback callback; // Callback function that gets called each time an entry is to be added to the matrix
+ void* callbackUserData;
+ int row; // The row number that starts at zero for the prologue, and increases for each row added to the matrix
+ private:
+ DISALLOW_COPY_AND_ASSIGN (State);
+ };
+
+ static bool DumpOpcodes(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET, uint32_t dump_flags = 0); // If line_offset is invalid, dump everything
+ static bool DumpLineTableRows(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET); // If line_offset is invalid, dump everything
+ static bool ParseSupportFiles(const lldb::ModuleSP &module_sp, const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files);
+ static bool ParsePrologue(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, Prologue* prologue);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, State::Callback callback, void* userData);
+ static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset);
+ static dw_offset_t DumpStatementOpcodes(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset, uint32_t flags);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t *offset_ptr, LineTable* line_table);
+ static void Parse(const lldb_private::DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData);
+// static void AppendLineTableData(const DWARFDebugLine::Prologue* prologue, const DWARFDebugLine::Row::collection& state_coll, const uint32_t addr_size, BinaryStreamBuf &debug_line_data);
+
+ DWARFDebugLine() :
+ m_lineTableMap()
+ {
+ }
+
+ void Parse(const lldb_private::DataExtractor& debug_line_data);
+ void ParseIfNeeded(const lldb_private::DataExtractor& debug_line_data);
+ LineTable::shared_ptr GetLineTable(const dw_offset_t offset) const;
+
+protected:
+ typedef std::map<dw_offset_t, LineTable::shared_ptr> LineTableMap;
+ typedef LineTableMap::iterator LineTableIter;
+ typedef LineTableMap::const_iterator LineTableConstIter;
+
+ LineTableMap m_lineTableMap;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugLine_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
new file mode 100644
index 000000000000..60ace9e82290
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
@@ -0,0 +1,48 @@
+//===-- DWARFDebugMacinfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfo.h"
+
+#include "DWARFDebugMacinfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfo::DWARFDebugMacinfo()
+{
+}
+
+DWARFDebugMacinfo::~DWARFDebugMacinfo()
+{
+}
+
+void
+DWARFDebugMacinfo::Dump(Stream *s, const DataExtractor& macinfo_data, lldb::offset_t offset)
+{
+ DWARFDebugMacinfoEntry maninfo_entry;
+ if (macinfo_data.GetByteSize() == 0)
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+ if (offset == LLDB_INVALID_OFFSET)
+ {
+ offset = 0;
+ while (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+ else
+ {
+ if (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
new file mode 100644
index 000000000000..5f3b437d964f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
@@ -0,0 +1,29 @@
+//===-- DWARFDebugMacinfo.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugMacinfo_h_
+#define SymbolFileDWARF_DWARFDebugMacinfo_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfo
+{
+public:
+ DWARFDebugMacinfo();
+
+ ~DWARFDebugMacinfo();
+
+ static void
+ Dump (lldb_private::Stream *s,
+ const lldb_private::DataExtractor& macinfo_data,
+ lldb::offset_t offset = LLDB_INVALID_OFFSET);
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugMacinfo_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
new file mode 100644
index 000000000000..5cd9cb6be474
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
@@ -0,0 +1,132 @@
+//===-- DWARFDebugMacinfoEntry.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfoEntry.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfoEntry::DWARFDebugMacinfoEntry() :
+ m_type_code(0),
+ m_line(0),
+ m_op2()
+{
+ m_op2.cstr = NULL;
+}
+
+DWARFDebugMacinfoEntry::~DWARFDebugMacinfoEntry()
+{
+}
+
+const char*
+DWARFDebugMacinfoEntry::GetCString() const
+{
+ switch (m_type_code)
+ {
+ case 0:
+ case DW_MACINFO_start_file:
+ case DW_MACINFO_end_file:
+ return NULL;
+ default:
+ break;
+ }
+ return m_op2.cstr;
+}
+
+
+
+void
+DWARFDebugMacinfoEntry::Dump(Stream *s) const
+{
+ if (m_type_code)
+ {
+ s->PutCString(DW_MACINFO_value_to_name(m_type_code));
+
+ switch (m_type_code)
+ {
+ case DW_MACINFO_define:
+ s->Printf(" line:%u #define %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_undef:
+ s->Printf(" line:%u #undef %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ default:
+ s->Printf(" line:%u str: '%s'\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_start_file:
+ s->Printf(" line:%u file index: '%u'\n", (uint32_t)m_line, (uint32_t)m_op2.file_idx);
+ break;
+
+ case DW_MACINFO_end_file:
+ break;
+ }
+ }
+ else
+ {
+ s->PutCString(" END\n");
+ }
+}
+
+
+bool
+DWARFDebugMacinfoEntry::Extract(const DataExtractor& mac_info_data, lldb::offset_t* offset_ptr)
+{
+ if (mac_info_data.ValidOffset(*offset_ptr))
+ {
+ m_type_code = mac_info_data.GetU8(offset_ptr);
+
+ switch (m_type_code)
+ {
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ // 2 operands:
+ // Arg 1: operand encodes the line number of the source line on which
+ // the relevant defining or undefining pre-processor directives
+ // appeared.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Arg 2: define string
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+
+ case DW_MACINFO_start_file:
+ // 2 operands:
+ // Op 1: line number of the source line on which the inclusion
+ // pre-processor directive occurred.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Op 2: a source file name index to a file number in the statement
+ // information table for the relevant compilation unit.
+ m_op2.file_idx = mac_info_data.GetULEB128(offset_ptr);
+ break;
+
+ case 0: // End of list
+ case DW_MACINFO_end_file:
+ // No operands
+ m_line = DW_INVALID_OFFSET;
+ m_op2.cstr = NULL;
+ break;
+ default:
+ // Vendor specific entries always have a ULEB128 and a string
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+ }
+ return true;
+ }
+ else
+ m_type_code = 0;
+
+ return false;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
new file mode 100644
index 000000000000..46fd44a22a63
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
@@ -0,0 +1,57 @@
+//===-- DWARFDebugMacinfoEntry.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
+#define SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfoEntry
+{
+public:
+ DWARFDebugMacinfoEntry();
+
+ ~DWARFDebugMacinfoEntry();
+
+ uint8_t
+ TypeCode() const
+ {
+ return m_type_code;
+ }
+
+ uint8_t
+ GetLineNumber() const
+ {
+ return m_line;
+ }
+
+ void
+ Dump(lldb_private::Stream *s) const;
+
+ const char*
+ GetCString() const;
+
+ bool
+ Extract(const lldb_private::DataExtractor& mac_info_data,
+ lldb::offset_t* offset_ptr);
+
+protected:
+
+private:
+ uint8_t m_type_code;
+ dw_uleb128_t m_line;
+ union
+ {
+ dw_uleb128_t file_idx;
+ const char* cstr;
+ } m_op2;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
new file mode 100644
index 000000000000..3e511007a1ec
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -0,0 +1,296 @@
+//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnames.h"
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+DWARFDebugPubnames::DWARFDebugPubnames() :
+ m_sets()
+{
+}
+
+bool
+DWARFDebugPubnames::Extract(const DataExtractor& data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")",
+ (uint64_t)data.GetByteSize());
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
+ if (log)
+ log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize());
+
+ if (data.ValidOffset(0))
+ {
+ lldb::offset_t offset = 0;
+
+ DWARFDebugPubnamesSet set;
+ while (data.ValidOffset(offset))
+ {
+ if (set.Extract(data, &offset))
+ {
+ m_sets.push_back(set);
+ offset = set.GetOffsetOfNextEntry();
+ }
+ else
+ break;
+ }
+ if (log)
+ Dump (log);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::GeneratePubnames (data = %p)",
+ dwarf2Data);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
+ if (log)
+ log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data);
+
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+
+ const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data();
+
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize());
+
+ bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
+
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) +
+ cu->AppendDIEsWithTag (DW_TAG_variable, dies);
+
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ bool add_die = false;
+ const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die->Tag();
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ mangled = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ if (tag == DW_TAG_subprogram)
+ add_die = true;
+ break;
+
+ case DW_AT_location:
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die->GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we don't want the performance
+ // penalty of that right now.
+ add_die = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ add_die = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (add_die && (name || mangled))
+ {
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ cu->ClearDIEs (true);
+ }
+ }
+ if (m_sets.empty())
+ return false;
+ if (log)
+ Dump (log);
+ return true;
+}
+
+bool
+DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
+{
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL);
+
+ if (name)
+ {
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+ }
+ }
+ return !m_sets.empty();
+}
+
+void
+DWARFDebugPubnames::Dump(Log *s) const
+{
+ if (m_sets.empty())
+ s->PutCString("< EMPTY >\n");
+ else
+ {
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ (*pos).Dump(s);
+ }
+}
+
+bool
+DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(name, ignore_case, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
+
+bool
+DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(regex, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
new file mode 100644
index 000000000000..09eb80ab3006
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
@@ -0,0 +1,38 @@
+//===-- DWARFDebugPubnames.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugPubnames_h_
+#define SymbolFileDWARF_DWARFDebugPubnames_h_
+
+#include "SymbolFileDWARF.h"
+
+#include <list>
+
+#include "DWARFDebugPubnamesSet.h"
+
+class DWARFDebugPubnames
+{
+public:
+ DWARFDebugPubnames();
+ bool Extract(const lldb_private::DataExtractor& data);
+ bool GeneratePubnames(SymbolFileDWARF* dwarf2Data);
+ bool GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data);
+
+ void Dump(lldb_private::Log *s) const;
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ bool Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+protected:
+ typedef std::list<DWARFDebugPubnamesSet> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_sets;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnames_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
new file mode 100644
index 000000000000..2df8d525f03f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
@@ -0,0 +1,166 @@
+//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnamesSet.h"
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Log.h"
+
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+}
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t cu_die_length) :
+ m_offset(debug_aranges_offset),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+ m_header.length = 10; // set the length to only include the header right for now
+ m_header.version = 2; // The DWARF version number
+ m_header.die_offset = cu_die_offset;// compile unit .debug_info offset
+ m_header.die_length = cu_die_length;// compile unit .debug_info length
+}
+
+void
+DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, const char* name)
+{
+ if (name && name[0])
+ {
+ // Adjust our header length
+ m_header.length += strlen(name) + 1 + sizeof(dw_offset_t);
+ Descriptor pubnameDesc(cu_rel_offset, name);
+ m_descriptors.push_back(pubnameDesc);
+ }
+}
+
+void
+DWARFDebugPubnamesSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 10;
+ m_header.version = 2;
+ m_header.die_offset = DW_INVALID_OFFSET;
+ m_header.die_length = 0;
+ m_descriptors.clear();
+}
+
+
+//----------------------------------------------------------------------
+// InitNameIndexes
+//----------------------------------------------------------------------
+void
+DWARFDebugPubnamesSet::InitNameIndexes() const
+{
+ // Create the name index vector to be able to quickly search by name
+ const size_t count = m_descriptors.size();
+ for (uint32_t idx = 0; idx < count; ++idx)
+ {
+ const char* name = m_descriptors[idx].name.c_str();
+ if (name && name[0])
+ m_name_to_descriptor_index.insert(cstr_to_index_mmap::value_type(name, idx));
+ }
+}
+
+
+bool
+DWARFDebugPubnamesSet::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_descriptors.clear();
+ m_offset = *offset_ptr;
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.die_offset = data.GetU32(offset_ptr);
+ m_header.die_length = data.GetU32(offset_ptr);
+
+ Descriptor pubnameDesc;
+ while (data.ValidOffset(*offset_ptr))
+ {
+ pubnameDesc.offset = data.GetU32(offset_ptr);
+
+ if (pubnameDesc.offset)
+ {
+ const char* name = data.GetCStr(offset_ptr);
+ if (name && name[0])
+ {
+ pubnameDesc.name = name;
+ m_descriptors.push_back(pubnameDesc);
+ }
+ }
+ else
+ break; // We are done if we get a zero 4 byte offset
+ }
+
+ return !m_descriptors.empty();
+ }
+ return false;
+}
+
+dw_offset_t
+DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+void
+DWARFDebugPubnamesSet::Dump(Log *log) const
+{
+ log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, die_offset = 0x%8.8x, die_length = 0x%8.8x",
+ m_header.length,
+ m_header.version,
+ m_header.die_offset,
+ m_header.die_length);
+
+ bool verbose = log->GetVerbose();
+
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if (verbose)
+ log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, m_header.die_offset, pos->offset + m_header.die_offset, pos->name.c_str());
+ else
+ log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, pos->name.c_str());
+ }
+}
+
+
+void
+DWARFDebugPubnamesSet::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ if (!m_descriptors.empty() && m_name_to_descriptor_index.empty())
+ InitNameIndexes();
+
+ std::pair<cstr_to_index_mmap::const_iterator, cstr_to_index_mmap::const_iterator> range(m_name_to_descriptor_index.equal_range(name));
+ for (cstr_to_index_mmap::const_iterator pos = range.first; pos != range.second; ++pos)
+ die_offset_coll.push_back(m_header.die_offset + m_descriptors[(*pos).second].offset);
+}
+
+void
+DWARFDebugPubnamesSet::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if ( regex.Execute(pos->name.c_str()) )
+ die_offset_coll.push_back(m_header.die_offset + pos->offset);
+ }
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
new file mode 100644
index 000000000000..941c83e58a44
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
@@ -0,0 +1,99 @@
+//===-- DWARFDebugPubnamesSet.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <string>
+#include <vector>
+#if __cplusplus >= 201103L
+#include <unordered_map>
+#else
+#include <ext/hash_map>
+#endif
+
+class DWARFDebugPubnamesSet
+{
+public:
+ struct Header
+ {
+ uint32_t length; // length of the set of entries for this compilation unit, not including the length field itself
+ uint16_t version; // The DWARF version number
+ uint32_t die_offset; // compile unit .debug_info offset
+ uint32_t die_length; // compile unit .debug_info length
+ Header() :
+ length(10),
+ version(2),
+ die_offset(DW_INVALID_OFFSET),
+ die_length(0)
+ {
+ }
+ };
+
+ struct Descriptor
+ {
+ Descriptor() :
+ offset(),
+ name()
+ {
+ }
+
+ Descriptor(dw_offset_t the_offset, const char *the_name) :
+ offset(the_offset),
+ name(the_name ? the_name : "")
+ {
+ }
+
+ dw_offset_t offset;
+ std::string name;
+ };
+
+ DWARFDebugPubnamesSet();
+ DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t die_length);
+ dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset) { m_offset = offset; }
+ DWARFDebugPubnamesSet::Header& GetHeader() { return m_header; }
+ const DWARFDebugPubnamesSet::Header& GetHeader() const { return m_header; }
+ const DWARFDebugPubnamesSet::Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_descriptors.size())
+ return &m_descriptors[i];
+ return NULL;
+ }
+ uint32_t NumDescriptors() const { return m_descriptors.size(); }
+ void AddDescriptor(dw_offset_t cu_rel_offset, const char* name);
+ void Clear();
+ bool Extract(const lldb_private::DataExtractor& debug_pubnames_data, lldb::offset_t *offset_ptr);
+ void Dump(lldb_private::Log *s) const;
+ void InitNameIndexes() const;
+ void Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ void Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+ dw_offset_t GetOffsetOfNextEntry() const;
+
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ dw_offset_t m_offset;
+ Header m_header;
+#if __cplusplus >= 201103L
+ typedef std::unordered_multimap<const char*, uint32_t, std::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+#else
+ typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+#endif
+ DescriptorColl m_descriptors;
+ mutable cstr_to_index_mmap m_name_to_descriptor_index;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
new file mode 100644
index 000000000000..461b17fc3aba
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -0,0 +1,192 @@
+//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugRanges.h"
+#include "SymbolFileDWARF.h"
+#include "lldb/Core/Stream.h"
+#include <assert.h>
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugRanges::DWARFDebugRanges() :
+ m_range_map()
+{
+}
+
+DWARFDebugRanges::~DWARFDebugRanges()
+{
+}
+
+void
+DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data)
+{
+ RangeList range_list;
+ lldb::offset_t offset = 0;
+ dw_offset_t debug_ranges_offset = offset;
+ while (Extract(dwarf2Data, &offset, range_list))
+ {
+ m_range_map[debug_ranges_offset] = range_list;
+ debug_ranges_offset = offset;
+ }
+}
+
+//void
+//DWARFDebugRanges::RangeList::AddOffset(dw_addr_t offset)
+//{
+// if (!ranges.empty())
+// {
+// Range::iterator pos = ranges.begin();
+// Range::iterator end_pos = ranges.end();
+// for (pos = ranges.begin(); pos != end_pos; ++pos)
+// {
+// // assert for unsigned overflows
+// assert (~pos->begin_offset >= offset);
+// assert (~pos->end_offset >= offset);
+// pos->begin_offset += offset;
+// pos->end_offset += offset;
+// }
+// }
+//}
+//
+//void
+//DWARFDebugRanges::RangeList::SubtractOffset(dw_addr_t offset)
+//{
+// if (!ranges.empty())
+// {
+// Range::iterator pos = ranges.begin();
+// Range::iterator end_pos = ranges.end();
+// for (pos = ranges.begin(); pos != end_pos; ++pos)
+// {
+// assert (pos->begin_offset >= offset);
+// assert (pos->end_offset >= offset);
+// pos->begin_offset -= offset;
+// pos->end_offset -= offset;
+// }
+// }
+//}
+//
+//
+//const DWARFDebugRanges::Range*
+//DWARFDebugRanges::RangeList::RangeAtIndex(size_t i) const
+//{
+// if (i < ranges.size())
+// return &ranges[i];
+// return NULL;
+//}
+
+bool
+DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data, lldb::offset_t *offset_ptr, RangeList &range_list)
+{
+ range_list.Clear();
+
+ lldb::offset_t range_offset = *offset_ptr;
+ const DataExtractor& debug_ranges_data = dwarf2Data->get_debug_ranges_data();
+ uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
+
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ if (!begin && !end)
+ {
+ // End of range list
+ break;
+ }
+ // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits
+ // of ones
+ switch (addr_size)
+ {
+ case 2:
+ if (begin == 0xFFFFull)
+ begin = LLDB_INVALID_ADDRESS;
+ break;
+
+ case 4:
+ if (begin == 0xFFFFFFFFull)
+ begin = LLDB_INVALID_ADDRESS;
+ break;
+
+ case 8:
+ break;
+
+ default:
+ assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size.");
+ break;
+ }
+
+ // Filter out empty ranges
+ if (begin < end)
+ range_list.Append(Range(begin, end - begin));
+ }
+
+ // Make sure we consumed at least something
+ return range_offset != *offset_ptr;
+}
+
+
+void
+DWARFDebugRanges::Dump(Stream &s, const DataExtractor& debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr)
+{
+ uint32_t addr_size = s.GetAddressByteSize();
+ bool verbose = s.GetVerbose();
+
+ dw_addr_t base_addr = cu_base_addr;
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits
+ // of ones
+ if (begin == 0xFFFFFFFFull && addr_size == 4)
+ begin = LLDB_INVALID_ADDRESS;
+
+ s.Indent();
+ if (verbose)
+ {
+ s.AddressRange(begin, end, sizeof (dw_addr_t), " offsets = ");
+ }
+
+
+ if (begin == 0 && end == 0)
+ {
+ s.PutCString(" End");
+ break;
+ }
+ else if (begin == LLDB_INVALID_ADDRESS)
+ {
+ // A base address selection entry
+ base_addr = end;
+ s.Address(base_addr, sizeof (dw_addr_t), " Base address = ");
+ }
+ else
+ {
+ // Convert from offset to an address
+ dw_addr_t begin_addr = begin + base_addr;
+ dw_addr_t end_addr = end + base_addr;
+
+ s.AddressRange(begin_addr, end_addr, sizeof (dw_addr_t), verbose ? " ==> addrs = " : NULL);
+ }
+ }
+}
+
+bool
+DWARFDebugRanges::FindRanges(dw_offset_t debug_ranges_offset, RangeList& range_list) const
+{
+ range_map_const_iterator pos = m_range_map.find(debug_ranges_offset);
+ if (pos != m_range_map.end())
+ {
+ range_list = pos->second;
+ return true;
+ }
+ return false;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
new file mode 100644
index 000000000000..40899abe9c25
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
@@ -0,0 +1,46 @@
+//===-- DWARFDebugRanges.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugRanges_h_
+#define SymbolFileDWARF_DWARFDebugRanges_h_
+
+#include "SymbolFileDWARF.h"
+
+#include <map>
+#include <vector>
+
+#include "lldb/Core/RangeMap.h"
+
+class DWARFDebugRanges
+{
+public:
+ typedef lldb_private::RangeArray<dw_addr_t, dw_addr_t, 2> RangeList;
+ typedef RangeList::Entry Range;
+
+ DWARFDebugRanges();
+ ~DWARFDebugRanges();
+ void Extract(SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream &s, const lldb_private::DataExtractor& debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr);
+ bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const;
+
+protected:
+
+ bool
+ Extract (SymbolFileDWARF* dwarf2Data,
+ lldb::offset_t *offset_ptr,
+ RangeList &range_list);
+
+ typedef std::map<dw_offset_t, RangeList> range_map;
+ typedef range_map::iterator range_map_iterator;
+ typedef range_map::const_iterator range_map_const_iterator;
+ range_map m_range_map;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugRanges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
new file mode 100644
index 000000000000..abf69190c93c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -0,0 +1,104 @@
+//===-- DWARFDeclContext.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDeclContext.h"
+
+const char *
+DWARFDeclContext::GetQualifiedName () const
+{
+ if (m_qualified_name.empty())
+ {
+ // The declaration context array for a class named "foo" in namespace
+ // "a::b::c" will be something like:
+ // [0] DW_TAG_class_type "foo"
+ // [1] DW_TAG_namespace "c"
+ // [2] DW_TAG_namespace "b"
+ // [3] DW_TAG_namespace "a"
+ if (!m_entries.empty())
+ {
+ if (m_entries.size() == 1)
+ {
+ if (m_entries[0].name)
+ {
+ m_qualified_name.append("::");
+ m_qualified_name.append(m_entries[0].name);
+ }
+ }
+ else
+ {
+ collection::const_reverse_iterator pos;
+ collection::const_reverse_iterator begin = m_entries.rbegin();
+ collection::const_reverse_iterator end = m_entries.rend();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos != begin)
+ m_qualified_name.append("::");
+ if (pos->name == NULL)
+ {
+ if (pos->tag == DW_TAG_namespace)
+ m_qualified_name.append ("(anonymous namespace)");
+ else if (pos->tag == DW_TAG_class_type)
+ m_qualified_name.append ("(anonymous class)");
+ else if (pos->tag == DW_TAG_structure_type)
+ m_qualified_name.append ("(anonymous struct)");
+ else if (pos->tag == DW_TAG_union_type)
+ m_qualified_name.append ("(anonymous union)");
+ else
+ m_qualified_name.append ("(anonymous)");
+ }
+ else
+ m_qualified_name.append(pos->name);
+ }
+ }
+ }
+ }
+ if (m_qualified_name.empty())
+ return NULL;
+ return m_qualified_name.c_str();
+}
+
+
+bool
+DWARFDeclContext::operator==(const DWARFDeclContext& rhs) const
+{
+ if (m_entries.size() != rhs.m_entries.size())
+ return false;
+
+ collection::const_iterator pos;
+ collection::const_iterator begin = m_entries.begin();
+ collection::const_iterator end = m_entries.end();
+
+ collection::const_iterator rhs_pos;
+ collection::const_iterator rhs_begin = rhs.m_entries.begin();
+ // The two entry arrays have the same size
+
+ // First compare the tags before we do expensize name compares
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos)
+ {
+ if (pos->tag != rhs_pos->tag)
+ {
+ // Check for DW_TAG_structure_type and DW_TAG_class_type as they are often
+ // used interchangeably in GCC
+ if (pos->tag == DW_TAG_structure_type && rhs_pos->tag == DW_TAG_class_type)
+ continue;
+ if (pos->tag == DW_TAG_class_type && rhs_pos->tag == DW_TAG_structure_type)
+ continue;
+ return false;
+ }
+ }
+ // The tags all match, now compare the names
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos)
+ {
+ if (!pos->NameMatches (*rhs_pos))
+ return false;
+ }
+ // All tags and names match
+ return true;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
new file mode 100644
index 000000000000..accd3446317a
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -0,0 +1,109 @@
+//===-- DWARFDeclContext.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDeclContext_h_
+#define SymbolFileDWARF_DWARFDeclContext_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+// Project includes
+#include "DWARFDefines.h"
+
+//----------------------------------------------------------------------
+// DWARFDeclContext
+//
+// A class that represents a declaration context all the way down to a
+// DIE. This is useful when trying to find a DIE in one DWARF to a DIE
+// in another DWARF file.
+//----------------------------------------------------------------------
+
+class DWARFDeclContext
+{
+public:
+ struct Entry
+ {
+ Entry () :
+ tag(0),
+ name(NULL)
+ {
+ }
+ Entry (dw_tag_t t, const char *n) :
+ tag(t),
+ name(n)
+ {
+ }
+
+ bool
+ NameMatches (const Entry& rhs) const
+ {
+ if (name == rhs.name)
+ return true;
+ else if (name && rhs.name)
+ return strcmp(name, rhs.name) == 0;
+ return false;
+ }
+
+ // Test operator
+ operator bool() const
+ {
+ return tag != 0;
+ }
+
+ dw_tag_t tag;
+ const char *name;
+ };
+
+ DWARFDeclContext () :
+ m_entries()
+ {
+ }
+
+ void
+ AppendDeclContext (dw_tag_t tag, const char *name)
+ {
+ m_entries.push_back(Entry(tag, name));
+ }
+
+ bool
+ operator ==(const DWARFDeclContext& rhs) const;
+
+ uint32_t
+ GetSize() const
+ {
+ return m_entries.size();
+ }
+
+ Entry &
+ operator[] (uint32_t idx)
+ {
+ // "idx" must be valid
+ return m_entries[idx];
+ }
+
+ const Entry &
+ operator[] (uint32_t idx) const
+ {
+ // "idx" must be valid
+ return m_entries[idx];
+ }
+
+ const char *
+ GetQualifiedName () const;
+
+protected:
+ typedef std::vector<Entry> collection;
+ collection m_entries;
+ mutable std::string m_qualified_name;
+};
+
+#endif // SymbolFileDWARF_DWARFDeclContext_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
new file mode 100644
index 000000000000..fe4093bc130e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
@@ -0,0 +1,497 @@
+//===-- DWARFDefines.c ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDefines.h"
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include "lldb/Core/ConstString.h"
+
+namespace lldb_private {
+
+const char *
+DW_TAG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+
+ if (val == 0)
+ return "NULL";
+
+ const char *llvmstr = llvm::dwarf::TagString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CHILDREN_value_to_name (uint8_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ChildrenString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_AT_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::AttributeString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_FORM_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::FormEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_OP_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::OperationEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+DRC_class
+DW_OP_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x03: return DRC_ONEOPERAND;
+ case 0x06: return DRC_ZEROOPERANDS;
+ case 0x08: return DRC_ONEOPERAND;
+ case 0x09: return DRC_ONEOPERAND;
+ case 0x0a: return DRC_ONEOPERAND;
+ case 0x0b: return DRC_ONEOPERAND;
+ case 0x0c: return DRC_ONEOPERAND;
+ case 0x0d: return DRC_ONEOPERAND;
+ case 0x0e: return DRC_ONEOPERAND;
+ case 0x0f: return DRC_ONEOPERAND;
+ case 0x10: return DRC_ONEOPERAND;
+ case 0x11: return DRC_ONEOPERAND;
+ case 0x12: return DRC_ZEROOPERANDS;
+ case 0x13: return DRC_ZEROOPERANDS;
+ case 0x14: return DRC_ZEROOPERANDS;
+ case 0x15: return DRC_ONEOPERAND;
+ case 0x16: return DRC_ZEROOPERANDS;
+ case 0x17: return DRC_ZEROOPERANDS;
+ case 0x18: return DRC_ZEROOPERANDS;
+ case 0x19: return DRC_ZEROOPERANDS;
+ case 0x1a: return DRC_ZEROOPERANDS;
+ case 0x1b: return DRC_ZEROOPERANDS;
+ case 0x1c: return DRC_ZEROOPERANDS;
+ case 0x1d: return DRC_ZEROOPERANDS;
+ case 0x1e: return DRC_ZEROOPERANDS;
+ case 0x1f: return DRC_ZEROOPERANDS;
+ case 0x20: return DRC_ZEROOPERANDS;
+ case 0x21: return DRC_ZEROOPERANDS;
+ case 0x22: return DRC_ZEROOPERANDS;
+ case 0x23: return DRC_ONEOPERAND;
+ case 0x24: return DRC_ZEROOPERANDS;
+ case 0x25: return DRC_ZEROOPERANDS;
+ case 0x26: return DRC_ZEROOPERANDS;
+ case 0x27: return DRC_ZEROOPERANDS;
+ case 0x2f: return DRC_ONEOPERAND;
+ case 0x28: return DRC_ONEOPERAND;
+ case 0x29: return DRC_ZEROOPERANDS;
+ case 0x2a: return DRC_ZEROOPERANDS;
+ case 0x2b: return DRC_ZEROOPERANDS;
+ case 0x2c: return DRC_ZEROOPERANDS;
+ case 0x2d: return DRC_ZEROOPERANDS;
+ case 0x2e: return DRC_ZEROOPERANDS;
+ case 0x30: return DRC_ZEROOPERANDS;
+ case 0x31: return DRC_ZEROOPERANDS;
+ case 0x32: return DRC_ZEROOPERANDS;
+ case 0x33: return DRC_ZEROOPERANDS;
+ case 0x34: return DRC_ZEROOPERANDS;
+ case 0x35: return DRC_ZEROOPERANDS;
+ case 0x36: return DRC_ZEROOPERANDS;
+ case 0x37: return DRC_ZEROOPERANDS;
+ case 0x38: return DRC_ZEROOPERANDS;
+ case 0x39: return DRC_ZEROOPERANDS;
+ case 0x3a: return DRC_ZEROOPERANDS;
+ case 0x3b: return DRC_ZEROOPERANDS;
+ case 0x3c: return DRC_ZEROOPERANDS;
+ case 0x3d: return DRC_ZEROOPERANDS;
+ case 0x3e: return DRC_ZEROOPERANDS;
+ case 0x3f: return DRC_ZEROOPERANDS;
+ case 0x40: return DRC_ZEROOPERANDS;
+ case 0x41: return DRC_ZEROOPERANDS;
+ case 0x42: return DRC_ZEROOPERANDS;
+ case 0x43: return DRC_ZEROOPERANDS;
+ case 0x44: return DRC_ZEROOPERANDS;
+ case 0x45: return DRC_ZEROOPERANDS;
+ case 0x46: return DRC_ZEROOPERANDS;
+ case 0x47: return DRC_ZEROOPERANDS;
+ case 0x48: return DRC_ZEROOPERANDS;
+ case 0x49: return DRC_ZEROOPERANDS;
+ case 0x4a: return DRC_ZEROOPERANDS;
+ case 0x4b: return DRC_ZEROOPERANDS;
+ case 0x4c: return DRC_ZEROOPERANDS;
+ case 0x4d: return DRC_ZEROOPERANDS;
+ case 0x4e: return DRC_ZEROOPERANDS;
+ case 0x4f: return DRC_ZEROOPERANDS;
+ case 0x50: return DRC_ZEROOPERANDS;
+ case 0x51: return DRC_ZEROOPERANDS;
+ case 0x52: return DRC_ZEROOPERANDS;
+ case 0x53: return DRC_ZEROOPERANDS;
+ case 0x54: return DRC_ZEROOPERANDS;
+ case 0x55: return DRC_ZEROOPERANDS;
+ case 0x56: return DRC_ZEROOPERANDS;
+ case 0x57: return DRC_ZEROOPERANDS;
+ case 0x58: return DRC_ZEROOPERANDS;
+ case 0x59: return DRC_ZEROOPERANDS;
+ case 0x5a: return DRC_ZEROOPERANDS;
+ case 0x5b: return DRC_ZEROOPERANDS;
+ case 0x5c: return DRC_ZEROOPERANDS;
+ case 0x5d: return DRC_ZEROOPERANDS;
+ case 0x5e: return DRC_ZEROOPERANDS;
+ case 0x5f: return DRC_ZEROOPERANDS;
+ case 0x60: return DRC_ZEROOPERANDS;
+ case 0x61: return DRC_ZEROOPERANDS;
+ case 0x62: return DRC_ZEROOPERANDS;
+ case 0x63: return DRC_ZEROOPERANDS;
+ case 0x64: return DRC_ZEROOPERANDS;
+ case 0x65: return DRC_ZEROOPERANDS;
+ case 0x66: return DRC_ZEROOPERANDS;
+ case 0x67: return DRC_ZEROOPERANDS;
+ case 0x68: return DRC_ZEROOPERANDS;
+ case 0x69: return DRC_ZEROOPERANDS;
+ case 0x6a: return DRC_ZEROOPERANDS;
+ case 0x6b: return DRC_ZEROOPERANDS;
+ case 0x6c: return DRC_ZEROOPERANDS;
+ case 0x6d: return DRC_ZEROOPERANDS;
+ case 0x6e: return DRC_ZEROOPERANDS;
+ case 0x6f: return DRC_ZEROOPERANDS;
+ case 0x70: return DRC_ONEOPERAND;
+ case 0x71: return DRC_ONEOPERAND;
+ case 0x72: return DRC_ONEOPERAND;
+ case 0x73: return DRC_ONEOPERAND;
+ case 0x74: return DRC_ONEOPERAND;
+ case 0x75: return DRC_ONEOPERAND;
+ case 0x76: return DRC_ONEOPERAND;
+ case 0x77: return DRC_ONEOPERAND;
+ case 0x78: return DRC_ONEOPERAND;
+ case 0x79: return DRC_ONEOPERAND;
+ case 0x7a: return DRC_ONEOPERAND;
+ case 0x7b: return DRC_ONEOPERAND;
+ case 0x7c: return DRC_ONEOPERAND;
+ case 0x7d: return DRC_ONEOPERAND;
+ case 0x7e: return DRC_ONEOPERAND;
+ case 0x7f: return DRC_ONEOPERAND;
+ case 0x80: return DRC_ONEOPERAND;
+ case 0x81: return DRC_ONEOPERAND;
+ case 0x82: return DRC_ONEOPERAND;
+ case 0x83: return DRC_ONEOPERAND;
+ case 0x84: return DRC_ONEOPERAND;
+ case 0x85: return DRC_ONEOPERAND;
+ case 0x86: return DRC_ONEOPERAND;
+ case 0x87: return DRC_ONEOPERAND;
+ case 0x88: return DRC_ONEOPERAND;
+ case 0x89: return DRC_ONEOPERAND;
+ case 0x8a: return DRC_ONEOPERAND;
+ case 0x8b: return DRC_ONEOPERAND;
+ case 0x8c: return DRC_ONEOPERAND;
+ case 0x8d: return DRC_ONEOPERAND;
+ case 0x8e: return DRC_ONEOPERAND;
+ case 0x8f: return DRC_ONEOPERAND;
+ case 0x90: return DRC_ONEOPERAND;
+ case 0x91: return DRC_ONEOPERAND;
+ case 0x92: return DRC_TWOOPERANDS;
+ case 0x93: return DRC_ONEOPERAND;
+ case 0x94: return DRC_ONEOPERAND;
+ case 0x95: return DRC_ONEOPERAND;
+ case 0x96: return DRC_ZEROOPERANDS;
+ case 0x97: return DRC_DWARFv3 | DRC_ZEROOPERANDS;
+ case 0x98: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x99: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x9a: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0xf0: return DRC_ZEROOPERANDS; /* DW_OP_APPLE_uninit */
+ case 0xe0: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+const char *
+DW_ATE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::AttributeEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ACCESS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+
+ const char *llvmstr = llvm::dwarf::AccessibilityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_VIS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::VisibilityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_VIRTUALITY_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::VirtualityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LANG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LanguageString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ID_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::CaseString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ConventionString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_INL_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::InlineCodeString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ORD_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ArrayOrderString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_DSC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::DiscriminantString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LNS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LNStandardString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LNE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LNExtendedString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_MACINFO_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::MacinfoString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CFA_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::CallFrameString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+DW_TAG_CategoryEnum
+get_tag_category (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type : return TagCategoryType;
+ case DW_TAG_class_type : return TagCategoryType;
+ case DW_TAG_entry_point : return TagCategoryProgram;
+ case DW_TAG_enumeration_type : return TagCategoryType;
+ case DW_TAG_formal_parameter : return TagCategoryVariable;
+ case DW_TAG_imported_declaration : return TagCategoryProgram;
+ case DW_TAG_label : return TagCategoryProgram;
+ case DW_TAG_lexical_block : return TagCategoryProgram;
+ case DW_TAG_member : return TagCategoryType;
+ case DW_TAG_pointer_type : return TagCategoryType;
+ case DW_TAG_reference_type : return TagCategoryType;
+ case DW_TAG_compile_unit : return TagCategoryProgram;
+ case DW_TAG_string_type : return TagCategoryType;
+ case DW_TAG_structure_type : return TagCategoryType;
+ case DW_TAG_subroutine_type : return TagCategoryType;
+ case DW_TAG_typedef : return TagCategoryType;
+ case DW_TAG_union_type : return TagCategoryType;
+ case DW_TAG_unspecified_parameters : return TagCategoryVariable;
+ case DW_TAG_variant : return TagCategoryType;
+ case DW_TAG_common_block : return TagCategoryProgram;
+ case DW_TAG_common_inclusion : return TagCategoryProgram;
+ case DW_TAG_inheritance : return TagCategoryType;
+ case DW_TAG_inlined_subroutine : return TagCategoryProgram;
+ case DW_TAG_module : return TagCategoryProgram;
+ case DW_TAG_ptr_to_member_type : return TagCategoryType;
+ case DW_TAG_set_type : return TagCategoryType;
+ case DW_TAG_subrange_type : return TagCategoryType;
+ case DW_TAG_with_stmt : return TagCategoryProgram;
+ case DW_TAG_access_declaration : return TagCategoryProgram;
+ case DW_TAG_base_type : return TagCategoryType;
+ case DW_TAG_catch_block : return TagCategoryProgram;
+ case DW_TAG_const_type : return TagCategoryType;
+ case DW_TAG_constant : return TagCategoryVariable;
+ case DW_TAG_enumerator : return TagCategoryType;
+ case DW_TAG_file_type : return TagCategoryType;
+ case DW_TAG_friend : return TagCategoryType;
+ case DW_TAG_namelist : return TagCategoryVariable;
+ case DW_TAG_namelist_item : return TagCategoryVariable;
+ case DW_TAG_packed_type : return TagCategoryType;
+ case DW_TAG_subprogram : return TagCategoryProgram;
+ case DW_TAG_template_type_parameter : return TagCategoryType;
+ case DW_TAG_template_value_parameter : return TagCategoryType;
+ case DW_TAG_thrown_type : return TagCategoryType;
+ case DW_TAG_try_block : return TagCategoryProgram;
+ case DW_TAG_variant_part : return TagCategoryType;
+ case DW_TAG_variable : return TagCategoryVariable;
+ case DW_TAG_volatile_type : return TagCategoryType;
+ case DW_TAG_dwarf_procedure : return TagCategoryProgram;
+ case DW_TAG_restrict_type : return TagCategoryType;
+ case DW_TAG_interface_type : return TagCategoryType;
+ case DW_TAG_namespace : return TagCategoryProgram;
+ case DW_TAG_imported_module : return TagCategoryProgram;
+ case DW_TAG_unspecified_type : return TagCategoryType;
+ case DW_TAG_partial_unit : return TagCategoryProgram;
+ case DW_TAG_imported_unit : return TagCategoryProgram;
+ case DW_TAG_shared_type : return TagCategoryType;
+ default: break;
+ }
+ return TagCategoryProgram;
+}
+
+} // namespace lldb_private
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
new file mode 100644
index 000000000000..e37aefb27a72
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
@@ -0,0 +1,116 @@
+//===-- DWARFDefines.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDefines_h_
+#define SymbolFileDWARF_DWARFDefines_h_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "lldb/Core/dwarf.h"
+
+namespace lldb_private {
+
+typedef uint32_t DRC_class; // Holds DRC_* class bitfields
+
+enum DW_TAG_Category
+{
+ TagCategoryVariable,
+ TagCategoryType,
+ TagCategoryProgram,
+ kNumTagCategories
+};
+
+typedef enum DW_TAG_Category DW_TAG_CategoryEnum;
+
+const char *DW_TAG_value_to_name (uint32_t val);
+
+DW_TAG_CategoryEnum get_tag_category (uint16_t tag);
+
+const char *DW_CHILDREN_value_to_name (uint8_t val);
+
+const char *DW_AT_value_to_name (uint32_t val);
+
+const char *DW_FORM_value_to_name (uint32_t val);
+
+const char *DW_OP_value_to_name (uint32_t val);
+
+DRC_class DW_OP_value_to_class (uint32_t val);
+
+const char *DW_ATE_value_to_name (uint32_t val);
+
+const char *DW_ACCESS_value_to_name (uint32_t val);
+
+const char *DW_VIS_value_to_name (uint32_t val);
+
+const char *DW_VIRTUALITY_value_to_name (uint32_t val);
+
+const char *DW_LANG_value_to_name (uint32_t val);
+
+const char *DW_ID_value_to_name (uint32_t val);
+
+const char *DW_CC_value_to_name (uint32_t val);
+
+const char *DW_INL_value_to_name (uint32_t val);
+
+const char *DW_ORD_value_to_name (uint32_t val);
+
+const char *DW_DSC_value_to_name (uint32_t val);
+
+const char *DW_LNS_value_to_name (uint32_t val);
+
+const char *DW_LNE_value_to_name (uint32_t val);
+
+const char *DW_MACINFO_value_to_name (uint32_t val);
+
+const char *DW_CFA_value_to_name (uint32_t val);
+
+const char *DW_GNU_EH_PE_value_to_name (uint32_t val);
+
+/* These DRC are entirely our own construction,
+ although they are derived from various comments in the DWARF standard.
+ Most of these are not useful to the parser, but the DW_AT and DW_FORM
+ classes should prove to be usable in some fashion. */
+
+#define DRC_0x65 0x1
+#define DRC_ADDRESS 0x2
+#define DRC_BLOCK 0x4
+#define DRC_CONSTANT 0x8
+#define DRC_DWARFv3 0x10
+#define DRC_FLAG 0x20
+#define DRC_INDIRECT_SPECIAL 0x40
+#define DRC_LINEPTR 0x80
+#define DRC_LOCEXPR 0x100
+#define DRC_LOCLISTPTR 0x200
+#define DRC_MACPTR 0x400
+#define DRC_ONEOPERAND 0x800
+#define DRC_OPERANDONE_1BYTE_DELTA 0x1000
+#define DRC_OPERANDONE_2BYTE_DELTA 0x2000
+#define DRC_OPERANDONE_4BYTE_DELTA 0x4000
+#define DRC_OPERANDONE_ADDRESS 0x8000
+#define DRC_OPERANDONE_BLOCK 0x10000
+#define DRC_OPERANDONE_SLEB128_OFFSET 0x20000
+#define DRC_OPERANDONE_ULEB128_OFFSET 0x40000
+#define DRC_OPERANDONE_ULEB128_REGISTER 0x80000
+#define DRC_OPERANDTWO_BLOCK 0x100000
+#define DRC_OPERANDTWO_SLEB128_OFFSET 0x200000
+#define DRC_OPERANDTWO_ULEB128_OFFSET 0x400000
+#define DRC_OPERANDTWO_ULEB128_REGISTER 0x800000
+#define DRC_OPERNADONE_ULEB128_REGISTER 0x1000000
+#define DRC_RANGELISTPTR 0x2000000
+#define DRC_REFERENCE 0x4000000
+#define DRC_STRING 0x8000000
+#define DRC_TWOOPERANDS 0x10000000
+#define DRC_VENDOR_GNU 0x20000000
+#define DRC_VENDOR_MIPS 0x40000000
+#define DRC_ZEROOPERANDS 0x80000000
+
+} // namespace lldb_private
+
+
+#endif // SymbolFileDWARF_DWARFDefines_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
new file mode 100644
index 000000000000..6113a146c93d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,599 @@
+//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Stream.h"
+
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+
+class DWARFCompileUnit;
+
+using namespace lldb_private;
+
+
+static uint8_t g_form_sizes_addr4[] =
+{
+ 0, // 0x00 unused
+ 4, // 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
+ 4, // 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
+ 4, // 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
+
+};
+
+static uint8_t
+g_form_sizes_addr8[] =
+{
+ 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
+ 4, // 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
+ 4, // 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)
+{
+ switch (addr_size)
+ {
+ case 4: return g_form_sizes_addr4;
+ case 8: return g_form_sizes_addr8;
+ }
+ return NULL;
+}
+
+DWARFFormValue::DWARFFormValue(dw_form_t form) :
+ m_form(form),
+ m_value()
+{
+}
+
+bool
+DWARFFormValue::ExtractValue(const DataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu)
+{
+ bool indirect = false;
+ bool is_block = false;
+ m_value.data = NULL;
+ // 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_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;
+ case DW_FORM_data4: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr);
+ // Set the string value to also be the data for inlined cstr form values only
+ // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form
+ // values;
+ m_value.data = (uint8_t*)m_value.value.cstr; break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break;
+ case DW_FORM_block1: m_value.value.uval = data.GetU8(offset_ptr); is_block = true; break;
+ 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_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_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;
+ case DW_FORM_ref8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_ref_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
+ case DW_FORM_indirect:
+ m_form = data.GetULEB128(offset_ptr);
+ indirect = true;
+ break;
+
+ case DW_FORM_sec_offset: m_value.value.uval = data.GetU32(offset_ptr); 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:
+ return false;
+ break;
+ }
+ } while (indirect);
+
+ if (is_block)
+ {
+ m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
+ if (m_value.data != NULL)
+ {
+ *offset_ptr += m_value.value.uval;
+ }
+ }
+
+ return true;
+}
+
+bool
+DWARFFormValue::SkipValue(const DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const
+{
+ return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu);
+}
+
+bool
+DWARFFormValue::SkipValue(dw_form_t form, const DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu)
+{
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc:
+ case DW_FORM_block: { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block1: { dw_uleb128_t size = debug_info_data.GetU8(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block2: { dw_uleb128_t size = debug_info_data.GetU16(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block4: { dw_uleb128_t size = debug_info_data.GetU32(offset_ptr); *offset_ptr += size; } return true;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.GetCStr(offset_ptr);
+ return true;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ return true;
+
+ case DW_FORM_ref_addr:
+ if (cu->GetVersion() <= 2)
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ else
+ *offset_ptr += 4;// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
+ return true;
+
+ // 0 bytes values (implied from DW_FORM)
+ case DW_FORM_flag_present:
+ return true;
+
+ // 1 byte values
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ *offset_ptr += 1;
+ return true;
+
+ // 2 byte values
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ *offset_ptr += 2;
+ return true;
+
+ // 32 bit for DWARF 32, 64 for DWARF 64
+ case DW_FORM_sec_offset:
+ *offset_ptr += 4;
+ return true;
+
+ // 4 byte values
+ case DW_FORM_strp:
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ *offset_ptr += 4;
+ return true;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ debug_info_data.Skip_LEB128(offset_ptr);
+ return true;
+
+ case DW_FORM_indirect:
+ {
+ dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr);
+ return DWARFFormValue::SkipValue (indirect_form,
+ debug_info_data,
+ offset_ptr,
+ cu);
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+void
+DWARFFormValue::Dump(Stream &s, const DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const
+{
+ uint64_t uvalue = Unsigned();
+ bool cu_relative_offset = false;
+
+ bool verbose = s.GetVerbose();
+
+ switch (m_form)
+ {
+ case DW_FORM_addr: s.Address(uvalue, sizeof (uint64_t)); break;
+ case DW_FORM_flag:
+ case DW_FORM_data1: s.PutHex8(uvalue); break;
+ case DW_FORM_data2: s.PutHex16(uvalue); break;
+ case DW_FORM_sec_offset:
+ case DW_FORM_data4: s.PutHex32(uvalue); break;
+ case DW_FORM_ref_sig8:
+ case DW_FORM_data8: s.PutHex64(uvalue); break;
+ case DW_FORM_string: s.QuotedCString(AsCString(NULL)); break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (uvalue > 0)
+ {
+ switch (m_form)
+ {
+ case DW_FORM_exprloc:
+ case DW_FORM_block: s.Printf("<0x%" PRIx64 "> ", uvalue); break;
+ case DW_FORM_block1: s.Printf("<0x%2.2x> ", (uint8_t)uvalue); break;
+ case DW_FORM_block2: s.Printf("<0x%4.4x> ", (uint16_t)uvalue); break;
+ case DW_FORM_block4: s.Printf("<0x%8.8x> ", (uint32_t)uvalue); break;
+ default: break;
+ }
+
+ const uint8_t* data_ptr = m_value.data;
+ if (data_ptr)
+ {
+ const uint8_t* end_data_ptr = data_ptr + uvalue; // uvalue contains size of block
+ while (data_ptr < end_data_ptr)
+ {
+ s.Printf("%2.2x ", *data_ptr);
+ ++data_ptr;
+ }
+ }
+ else
+ s.PutCString("NULL");
+ }
+ break;
+
+ case DW_FORM_sdata: s.PutSLEB128(uvalue); break;
+ case DW_FORM_udata: s.PutULEB128(uvalue); break;
+ case DW_FORM_strp:
+ if (debug_str_data)
+ {
+ if (verbose)
+ s.Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
+
+ const char* dbg_str = AsCString(debug_str_data);
+ if (dbg_str)
+ s.QuotedCString(dbg_str);
+ }
+ else
+ {
+ s.PutHex32(uvalue);
+ }
+ break;
+
+ case DW_FORM_ref_addr:
+ {
+ if (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
+ break;
+ }
+ case DW_FORM_ref1: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%2.2x", (uint8_t)uvalue); break;
+ case DW_FORM_ref2: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%4.4x", (uint16_t)uvalue); break;
+ case DW_FORM_ref4: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%4.4x", (uint32_t)uvalue); break;
+ case DW_FORM_ref8: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%8.8" PRIx64, uvalue); break;
+ case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%" PRIx64, uvalue); break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling this function
+ case DW_FORM_indirect: s.PutCString("DW_FORM_indirect"); break;
+ case DW_FORM_flag_present: break;
+ default:
+ s.Printf("DW_FORM(0x%4.4x)", m_form);
+ break;
+ }
+
+ if (cu_relative_offset)
+ {
+ if (verbose)
+ s.PutCString(" => ");
+
+ s.Printf("{0x%8.8" PRIx64 "}", (uvalue + (cu ? cu->GetOffset() : 0)));
+ }
+}
+
+const char*
+DWARFFormValue::AsCString(const DataExtractor* debug_str_data_ptr) const
+{
+ if (IsInlinedCStr())
+ return m_value.value.cstr;
+ else if (debug_str_data_ptr)
+ return debug_str_data_ptr->PeekCStr(m_value.value.uval);
+ return NULL;
+}
+
+uint64_t
+DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
+{
+ uint64_t die_offset = m_value.value.uval;
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ die_offset += (cu ? cu->GetOffset() : 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return die_offset;
+}
+
+uint64_t
+DWARFFormValue::Reference (dw_offset_t base_offset) const
+{
+ uint64_t die_offset = m_value.value.uval;
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ die_offset += base_offset;
+ break;
+
+ default:
+ break;
+ }
+
+ 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
+{
+ if (!IsInlinedCStr())
+ return m_value.data;
+ return NULL;
+}
+
+
+bool
+DWARFFormValue::IsBlockForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFFormValue::IsDataForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ return true;
+ }
+ return false;
+}
+
+int
+DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DataExtractor* debug_str_data_ptr)
+{
+ dw_form_t a_form = a_value.Form();
+ dw_form_t b_form = b_value.Form();
+ if (a_form < b_form)
+ return -1;
+ if (a_form > b_form)
+ return 1;
+ switch (a_form)
+ {
+ case DW_FORM_addr:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_sec_offset:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ {
+ uint64_t a = a_value.Unsigned();
+ uint64_t b = b_value.Unsigned();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_sdata:
+ {
+ int64_t a = a_value.Signed();
+ int64_t b = b_value.Signed();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ {
+ const char *a_string = a_value.AsCString(debug_str_data_ptr);
+ const char *b_string = b_value.AsCString(debug_str_data_ptr);
+ if (a_string == b_string)
+ return 0;
+ else if (a_string && b_string)
+ return strcmp(a_string, b_string);
+ else if (a_string == NULL)
+ return -1; // A string is NULL, and B is valid
+ else
+ return 1; // A string valid, and B is NULL
+ }
+
+
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_exprloc:
+ {
+ uint64_t a_len = a_value.Unsigned();
+ uint64_t b_len = b_value.Unsigned();
+ if (a_len < b_len)
+ return -1;
+ if (a_len > b_len)
+ return 1;
+ // The block lengths are the same
+ return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned());
+ }
+ break;
+
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ 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);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_indirect:
+ assert(!"This shouldn't happen after the form has been extracted...");
+ break;
+
+ default:
+ assert(!"Unhandled DW_FORM");
+ break;
+ }
+ return -1;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
new file mode 100644
index 000000000000..4c400b2df58e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -0,0 +1,81 @@
+//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFFormValue_h_
+#define SymbolFileDWARF_DWARFFormValue_h_
+
+#include <stddef.h> // for NULL
+
+class DWARFCompileUnit;
+
+class DWARFFormValue
+{
+public:
+ typedef struct ValueTypeTag
+ {
+ ValueTypeTag() :
+ value(),
+ data(NULL)
+ {
+ value.uval = 0;
+ }
+
+ union
+ {
+ uint64_t uval;
+ int64_t sval;
+ const char* cstr;
+ } value;
+ const uint8_t* data;
+ } ValueType;
+
+ enum
+ {
+ eValueTypeInvalid = 0,
+ eValueTypeUnsigned,
+ eValueTypeSigned,
+ eValueTypeCStr,
+ eValueTypeBlock
+ };
+
+ DWARFFormValue(dw_form_t form = 0);
+ 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::DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const;
+ bool ExtractValue(const lldb_private::DataExtractor& data,
+ lldb::offset_t* offset_ptr,
+ const DWARFCompileUnit* cu);
+ bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; }
+ const uint8_t* BlockData() const;
+ uint64_t Reference(const DWARFCompileUnit* cu) 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::DataExtractor* debug_str_data_ptr) const;
+ bool SkipValue(const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const;
+ static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu);
+// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& 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::DataExtractor* debug_str_data_ptr);
+protected:
+ dw_form_t m_form; // Form for this value
+ ValueType m_value; // Contains all data for the form
+};
+
+
+#endif // SymbolFileDWARF_DWARFFormValue_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
new file mode 100644
index 000000000000..fdc07836b88d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
@@ -0,0 +1,172 @@
+//===-- DWARFLocationDescription.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationDescription.h"
+#include "DWARFDefines.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb_private;
+
+static int print_dwarf_exp_op (Stream &s, const DataExtractor& data, lldb::offset_t *offset_ptr, int address_size, int dwarf_ref_size);
+
+int
+print_dwarf_expression (Stream &s,
+ const DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression)
+{
+ int op_count = 0;
+ lldb::offset_t offset = 0;
+ while (data.ValidOffset(offset))
+ {
+ if (location_expression && op_count > 0)
+ {
+ // err (baton, "Dwarf location expressions may only have one operand!");
+ return 1;
+ }
+ if (op_count > 0)
+ {
+ s.PutCString(", ");
+ }
+ if (print_dwarf_exp_op (s, data, &offset, address_size, dwarf_ref_size) == 1)
+ return 1;
+ op_count++;
+ }
+
+ return 0;
+}
+
+static int
+print_dwarf_exp_op (Stream &s,
+ const DataExtractor& data,
+ lldb::offset_t *offset_ptr,
+ int address_size,
+ int dwarf_ref_size)
+{
+ uint8_t opcode = data.GetU8(offset_ptr);
+ DRC_class opcode_class;
+ uint64_t uint;
+ int64_t sint;
+
+ int size;
+
+ opcode_class = DW_OP_value_to_class (opcode) & (~DRC_DWARFv3);
+
+ s.Printf("%s ", DW_OP_value_to_name (opcode));
+
+ /* Does this take zero parameters? If so we can shortcut this function. */
+ if (opcode_class == DRC_ZEROOPERANDS)
+ return 0;
+
+ if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx)
+ {
+ uint = data.GetULEB128(offset_ptr);
+ sint = data.GetSLEB128(offset_ptr);
+ s.Printf("%" PRIu64 " %" PRIi64, uint, sint);
+ return 0;
+ }
+ if (opcode_class != DRC_ONEOPERAND)
+ {
+ s.Printf("UNKNOWN OP %u", opcode);
+ return 1;
+ }
+
+ switch (opcode)
+ {
+ case DW_OP_addr: size = address_size; break;
+ case DW_OP_const1u: size = 1; break;
+ case DW_OP_const1s: size = -1; break;
+ case DW_OP_const2u: size = 2; break;
+ case DW_OP_const2s: size = -2; break;
+ case DW_OP_const4u: size = 4; break;
+ case DW_OP_const4s: size = -4; break;
+ case DW_OP_const8u: size = 8; break;
+ case DW_OP_const8s: size = -8; break;
+ case DW_OP_constu: size = 128; break;
+ case DW_OP_consts: size = -128; break;
+ case DW_OP_fbreg: size = -128; break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ size = -128; break;
+ case DW_OP_pick:
+ size = 1; break;
+ case DW_OP_deref_size:
+ size = 1; break;
+ case DW_OP_xderef_size:
+ size = 1; break;
+ case DW_OP_plus_uconst:
+ size = 128; break;
+ case DW_OP_skip:
+ size = -2; break;
+ case DW_OP_bra:
+ size = -2; break;
+ case DW_OP_call2:
+ size = 2; break;
+ case DW_OP_call4:
+ size = 4; break;
+ case DW_OP_call_ref:
+ size = dwarf_ref_size; break;
+ case DW_OP_piece:
+ size = 128; break;
+ case DW_OP_regx:
+ size = 128; break;
+ default:
+ s.Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode);
+ return 1;
+ }
+
+ switch (size)
+ {
+ case -1: sint = (int8_t) data.GetU8(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -2: sint = (int16_t) data.GetU16(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -4: sint = (int32_t) data.GetU32(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -8: sint = (int64_t) data.GetU64(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -128: sint = data.GetSLEB128(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case 1: uint = data.GetU8(offset_ptr); s.Printf("0x%2.2" PRIx64, uint); break;
+ case 2: uint = data.GetU16(offset_ptr); s.Printf("0x%4.4" PRIx64, uint); break;
+ case 4: uint = data.GetU32(offset_ptr); s.Printf("0x%8.8" PRIx64, uint); break;
+ case 8: uint = data.GetU64(offset_ptr); s.Printf("0x%16.16" PRIx64, uint); break;
+ case 128: uint = data.GetULEB128(offset_ptr); s.Printf("0x%" PRIx64, uint); break;
+ }
+
+ return 0;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
new file mode 100644
index 000000000000..ff7c907e921c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
@@ -0,0 +1,24 @@
+//===-- DWARFLocationDescription.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFLocationDescription_h_
+#define SymbolFileDWARF_DWARFLocationDescription_h_
+
+#include "SymbolFileDWARF.h"
+
+int
+print_dwarf_expression (lldb_private::Stream &s,
+ const lldb_private::DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression);
+
+
+
+#endif // SymbolFileDWARF_DWARFLocationDescription_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
new file mode 100644
index 000000000000..dad5691267df
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
@@ -0,0 +1,94 @@
+//===-- DWARFLocationList.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationList.h"
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFLocationDescription.h"
+
+using namespace lldb_private;
+
+dw_offset_t
+DWARFLocationList::Dump(Stream &s, const DWARFCompileUnit* cu, const DataExtractor& debug_loc_data, lldb::offset_t offset)
+{
+ uint64_t start_addr, end_addr;
+ uint32_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
+ s.SetAddressByteSize(DWARFCompileUnit::GetAddressByteSize(cu));
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ start_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+ end_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ s.PutCString("\n ");
+ s.Indent();
+ if (cu)
+ s.AddressRange (start_addr + base_addr,
+ end_addr + base_addr,
+ cu->GetAddressByteSize(),
+ NULL,
+ ": ");
+ uint32_t loc_length = debug_loc_data.GetU16(&offset);
+
+ DataExtractor locationData(debug_loc_data, offset, loc_length);
+ // if ( dump_flags & DWARFDebugInfo::eDumpFlag_Verbose ) *ostrm_ptr << " ( ";
+ print_dwarf_expression (s, locationData, addr_size, 4, false);
+ offset += loc_length;
+ }
+
+ return offset;
+}
+
+bool
+DWARFLocationList::Extract(const DataExtractor& debug_loc_data, lldb::offset_t* offset_ptr, DataExtractor& location_list_data)
+{
+ // Initialize with no data just in case we don't find anything
+ location_list_data.Clear();
+
+ size_t loc_list_length = Size(debug_loc_data, *offset_ptr);
+ if (loc_list_length > 0)
+ {
+ location_list_data.SetData(debug_loc_data, *offset_ptr, loc_list_length);
+ *offset_ptr += loc_list_length;
+ return true;
+ }
+
+ return false;
+}
+
+size_t
+DWARFLocationList::Size(const DataExtractor& debug_loc_data, lldb::offset_t offset)
+{
+ const dw_offset_t debug_loc_offset = offset;
+
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ dw_addr_t start_addr = debug_loc_data.GetAddress(&offset);
+ dw_addr_t end_addr = debug_loc_data.GetAddress(&offset);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ uint16_t loc_length = debug_loc_data.GetU16(&offset);
+ offset += loc_length;
+ }
+
+ if (offset > debug_loc_offset)
+ return offset - debug_loc_offset;
+ return 0;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
new file mode 100644
index 000000000000..85e11d90b36b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
@@ -0,0 +1,34 @@
+//===-- DWARFLocationList.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFLocationList_h_
+#define SymbolFileDWARF_DWARFLocationList_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFLocationList
+{
+public:
+ static dw_offset_t
+ Dump (lldb_private::Stream &s,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t offset);
+
+ static bool
+ Extract (const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t* offset_ptr,
+ lldb_private::DataExtractor& location_list_data);
+
+ static size_t
+ Size (const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t offset);
+
+};
+#endif // SymbolFileDWARF_DWARFLocationList_h_
diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
new file mode 100644
index 000000000000..c31cbaf3ca20
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
@@ -0,0 +1,933 @@
+//===-- HashedNameToDIE.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_HashedNameToDIE_h_
+#define SymbolFileDWARF_HashedNameToDIE_h_
+
+#include <vector>
+
+#include "DWARFDefines.h"
+#include "DWARFFormValue.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/MappedHash.h"
+
+
+class SymbolFileDWARF;
+class DWARFCompileUnit;
+class DWARFDebugInfoEntry;
+
+struct DWARFMappedHash
+{
+ struct DIEInfo
+ {
+ dw_offset_t offset; // The DIE offset
+ dw_tag_t tag;
+ uint32_t type_flags; // Any flags for this DIEInfo
+ uint32_t qualified_name_hash; // A 32 bit hash of the fully qualified name
+
+ DIEInfo () :
+ offset (DW_INVALID_OFFSET),
+ tag (0),
+ type_flags (0),
+ qualified_name_hash (0)
+ {
+ }
+
+ DIEInfo (dw_offset_t o, dw_tag_t t, uint32_t f, uint32_t h) :
+ offset(o),
+ tag (t),
+ type_flags (f),
+ qualified_name_hash (h)
+ {
+ }
+
+ void
+ Clear()
+ {
+ offset = DW_INVALID_OFFSET;
+ tag = 0;
+ type_flags = 0;
+ qualified_name_hash = 0;
+ }
+ };
+
+ typedef std::vector<DIEInfo> DIEInfoArray;
+ typedef std::vector<uint32_t> DIEArray;
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ const dw_tag_t tag,
+ DIEArray &die_offsets)
+ {
+ if (tag == 0)
+ {
+ ExtractDIEArray (die_info_array, die_offsets);
+ }
+ else
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ bool tag_matches = die_tag == 0 || tag == die_tag;
+ if (!tag_matches)
+ {
+ if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
+ }
+ if (tag_matches)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ const dw_tag_t tag,
+ const uint32_t qualified_name_hash,
+ DIEArray &die_offsets)
+ {
+ if (tag == 0)
+ {
+ ExtractDIEArray (die_info_array, die_offsets);
+ }
+ else
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ if (qualified_name_hash != die_info_array[i].qualified_name_hash)
+ continue;
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ bool tag_matches = die_tag == 0 || tag == die_tag;
+ if (!tag_matches)
+ {
+ if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
+ }
+ if (tag_matches)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+
+ enum AtomType
+ {
+ eAtomTypeNULL = 0u,
+ eAtomTypeDIEOffset = 1u, // DIE offset, check form for encoding
+ eAtomTypeCUOffset = 2u, // DIE offset of the compiler unit header that contains the item in question
+ eAtomTypeTag = 3u, // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2
+ eAtomTypeNameFlags = 4u, // Flags from enum NameFlags
+ eAtomTypeTypeFlags = 5u, // Flags from enum TypeFlags,
+ eAtomTypeQualNameHash = 6u // A 32 bit hash of the full qualified name (since all hash entries are basename only)
+ // For example a type like "std::vector<int>::iterator" would have a name of "iterator"
+ // and a 32 bit hash for "std::vector<int>::iterator" to allow us to not have to pull
+ // in debug info for a type when we know the fully qualified name.
+ };
+
+ // Bit definitions for the eAtomTypeTypeFlags flags
+ enum TypeFlags
+ {
+ // Always set for C++, only set for ObjC if this is the
+ // @implementation for class
+ eTypeFlagClassIsImplementation = ( 1u << 1 )
+ };
+
+
+ static void
+ ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array,
+ bool return_implementation_only_if_available,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ {
+ if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation)
+ {
+ if (return_implementation_only_if_available)
+ {
+ // We found the one true definiton for this class, so
+ // only return that
+ die_offsets.clear();
+ die_offsets.push_back (die_info_array[i].offset);
+ return;
+ }
+ else
+ {
+ // Put the one true definition as the first entry so it
+ // matches first
+ die_offsets.insert (die_offsets.begin(), die_info_array[i].offset);
+ }
+ }
+ else
+ {
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+ }
+
+ static void
+ ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array,
+ uint32_t type_flag_mask,
+ uint32_t type_flag_value,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+
+ struct Atom
+ {
+ uint16_t type;
+ dw_form_t form;
+
+ Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) :
+ type (t),
+ form (f)
+ {
+ }
+ };
+
+ typedef std::vector<Atom> AtomArray;
+
+ static uint32_t
+ GetTypeFlags (SymbolFileDWARF *dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* die);
+
+
+ static const char *
+ GetAtomTypeName (uint16_t atom)
+ {
+ switch (atom)
+ {
+ case eAtomTypeNULL: return "NULL";
+ case eAtomTypeDIEOffset: return "die-offset";
+ case eAtomTypeCUOffset: return "cu-offset";
+ case eAtomTypeTag: return "die-tag";
+ case eAtomTypeNameFlags: return "name-flags";
+ case eAtomTypeTypeFlags: return "type-flags";
+ case eAtomTypeQualNameHash: return "qualified-name-hash";
+ }
+ return "<invalid>";
+ }
+ struct Prologue
+ {
+ // DIE offset base so die offsets in hash_data can be CU relative
+ dw_offset_t die_base_offset;
+ AtomArray atoms;
+ uint32_t atom_mask;
+ size_t min_hash_data_byte_size;
+ bool hash_data_has_fixed_byte_size;
+
+ Prologue (dw_offset_t _die_base_offset = 0) :
+ die_base_offset (_die_base_offset),
+ atoms(),
+ atom_mask (0),
+ min_hash_data_byte_size(0),
+ hash_data_has_fixed_byte_size(true)
+ {
+ // Define an array of DIE offsets by first defining an array,
+ // and then define the atom type for the array, in this case
+ // we have an array of DIE offsets
+ AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
+ }
+
+ virtual ~Prologue()
+ {
+ }
+
+ void
+ ClearAtoms ()
+ {
+ hash_data_has_fixed_byte_size = true;
+ min_hash_data_byte_size = 0;
+ atom_mask = 0;
+ atoms.clear();
+ }
+
+ bool
+ ContainsAtom (AtomType atom_type) const
+ {
+ return (atom_mask & (1u << atom_type)) != 0;
+ }
+
+ virtual void
+ Clear ()
+ {
+ die_base_offset = 0;
+ ClearAtoms ();
+ }
+
+ void
+ AppendAtom (AtomType type, dw_form_t form)
+ {
+ atoms.push_back (Atom(type, form));
+ atom_mask |= 1u << type;
+ switch (form)
+ {
+ case DW_FORM_indirect:
+ case DW_FORM_exprloc:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ assert (!"Unhandled atom form");
+ break;
+
+ case DW_FORM_string:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_sec_offset:
+ min_hash_data_byte_size += 1;
+ break;
+
+ case DW_FORM_block2:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ min_hash_data_byte_size += 2;
+ break;
+
+ case DW_FORM_block4:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ case DW_FORM_strp:
+ min_hash_data_byte_size += 4;
+ break;
+
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ min_hash_data_byte_size += 8;
+ break;
+
+ }
+ }
+
+// void
+// Dump (std::ostream* ostrm_ptr);
+
+ lldb::offset_t
+ Read (const lldb_private::DataExtractor &data,
+ lldb::offset_t offset)
+ {
+ ClearAtoms ();
+
+ die_base_offset = data.GetU32 (&offset);
+
+ const uint32_t atom_count = data.GetU32 (&offset);
+ if (atom_count == 0x00060003u)
+ {
+ // Old format, deal with contents of old pre-release format
+ while (data.GetU32(&offset))
+ /* do nothing */;
+
+ // Hardcode to the only known value for now.
+ AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
+ }
+ else
+ {
+ for (uint32_t i=0; i<atom_count; ++i)
+ {
+ AtomType type = (AtomType)data.GetU16 (&offset);
+ dw_form_t form = (dw_form_t)data.GetU16 (&offset);
+ AppendAtom (type, form);
+ }
+ }
+ return offset;
+ }
+
+// virtual void
+// Write (BinaryStreamBuf &s);
+
+ size_t
+ GetByteSize () const
+ {
+ // Add an extra count to the atoms size for the zero termination Atom that gets
+ // written to disk
+ return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom);
+ }
+
+ size_t
+ GetMinumumHashDataByteSize () const
+ {
+ return min_hash_data_byte_size;
+ }
+
+ bool
+ HashDataHasFixedByteSize() const
+ {
+ return hash_data_has_fixed_byte_size;
+ }
+ };
+
+ struct Header : public MappedHash::Header<Prologue>
+ {
+ Header (dw_offset_t _die_base_offset = 0)
+ {
+ }
+
+ virtual
+ ~Header()
+ {
+ }
+
+ virtual size_t
+ GetByteSize (const HeaderData &header_data)
+ {
+ return header_data.GetByteSize();
+ }
+
+ // virtual void
+ // Dump (std::ostream* ostrm_ptr);
+ //
+ virtual lldb::offset_t
+ Read (lldb_private::DataExtractor &data, lldb::offset_t offset)
+ {
+ offset = MappedHash::Header<Prologue>::Read (data, offset);
+ if (offset != UINT32_MAX)
+ {
+ offset = header_data.Read (data, offset);
+ }
+ return offset;
+ }
+
+ bool
+ Read (const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ DIEInfo &hash_data) const
+ {
+ const size_t num_atoms = header_data.atoms.size();
+ if (num_atoms == 0)
+ return false;
+
+ for (size_t i=0; i<num_atoms; ++i)
+ {
+ DWARFFormValue form_value (header_data.atoms[i].form);
+
+ if (!form_value.ExtractValue(data, offset_ptr, NULL))
+ return false;
+
+ switch (header_data.atoms[i].type)
+ {
+ case eAtomTypeDIEOffset: // DIE offset, check form for encoding
+ hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset);
+ break;
+
+ case eAtomTypeTag: // DW_TAG value for the DIE
+ hash_data.tag = (dw_tag_t)form_value.Unsigned ();
+
+ case eAtomTypeTypeFlags: // Flags from enum TypeFlags
+ hash_data.type_flags = (uint32_t)form_value.Unsigned ();
+ break;
+
+ case eAtomTypeQualNameHash: // Flags from enum TypeFlags
+ hash_data.qualified_name_hash = form_value.Unsigned ();
+ break;
+
+ default:
+ // We can always skip atomes we don't know about
+ break;
+ }
+ }
+ return true;
+ }
+
+ void
+ Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
+ {
+ const size_t num_atoms = header_data.atoms.size();
+ for (size_t i=0; i<num_atoms; ++i)
+ {
+ if (i > 0)
+ strm.PutCString (", ");
+
+ DWARFFormValue form_value (header_data.atoms[i].form);
+ switch (header_data.atoms[i].type)
+ {
+ case eAtomTypeDIEOffset: // DIE offset, check form for encoding
+ strm.Printf ("{0x%8.8x}", hash_data.offset);
+ break;
+
+ case eAtomTypeTag: // DW_TAG value for the DIE
+ {
+ const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
+ if (tag_cstr)
+ strm.PutCString (tag_cstr);
+ else
+ strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
+ }
+ break;
+
+ case eAtomTypeTypeFlags: // Flags from enum TypeFlags
+ strm.Printf ("0x%2.2x", hash_data.type_flags);
+ if (hash_data.type_flags)
+ {
+ strm.PutCString (" (");
+ if (hash_data.type_flags & eTypeFlagClassIsImplementation)
+ strm.PutCString (" implementation");
+ strm.PutCString (" )");
+ }
+ break;
+
+ case eAtomTypeQualNameHash: // Flags from enum TypeFlags
+ strm.Printf ("0x%8.8x", hash_data.qualified_name_hash);
+ break;
+
+ default:
+ strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
+ break;
+ }
+ }
+ }
+ };
+
+// class ExportTable
+// {
+// public:
+// ExportTable ();
+//
+// void
+// AppendNames (DWARFDebugPubnamesSet &pubnames_set,
+// StringTable &string_table);
+//
+// void
+// AppendNamesEntry (SymbolFileDWARF *dwarf2Data,
+// const DWARFCompileUnit* cu,
+// const DWARFDebugInfoEntry* die,
+// StringTable &string_table);
+//
+// void
+// AppendTypesEntry (DWARFData *dwarf2Data,
+// const DWARFCompileUnit* cu,
+// const DWARFDebugInfoEntry* die,
+// StringTable &string_table);
+//
+// size_t
+// Save (BinaryStreamBuf &names_data, const StringTable &string_table);
+//
+// void
+// AppendName (const char *name,
+// uint32_t die_offset,
+// StringTable &string_table,
+// dw_offset_t name_debug_str_offset = DW_INVALID_OFFSET); // If "name" has already been looked up, then it can be supplied
+// void
+// AppendType (const char *name,
+// uint32_t die_offset,
+// StringTable &string_table);
+//
+//
+// protected:
+// struct Entry
+// {
+// uint32_t hash;
+// uint32_t str_offset;
+// uint32_t die_offset;
+// };
+//
+// // Map uniqued .debug_str offset to the corresponding DIE offsets
+// typedef std::map<uint32_t, DIEInfoArray> NameInfo;
+// // Map a name hash to one or more name infos
+// typedef std::map<uint32_t, NameInfo> BucketEntry;
+//
+// static uint32_t
+// GetByteSize (const NameInfo &name_info);
+//
+// typedef std::vector<BucketEntry> BucketEntryColl;
+// typedef std::vector<Entry> EntryColl;
+// EntryColl m_entries;
+//
+// };
+
+
+ // A class for reading and using a saved hash table from a block of data
+ // in memory
+ class MemoryTable : public MappedHash::MemoryTable<uint32_t, DWARFMappedHash::Header, DIEInfoArray>
+ {
+ public:
+
+ MemoryTable (lldb_private::DataExtractor &table_data,
+ const lldb_private::DataExtractor &string_table,
+ const char *name) :
+ MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
+ m_data (table_data),
+ m_string_table (string_table),
+ m_name (name)
+ {
+ }
+
+ virtual
+ ~MemoryTable ()
+ {
+ }
+
+ virtual const char *
+ GetStringForKeyType (KeyType key) const
+ {
+ // The key in the DWARF table is the .debug_str offset for the string
+ return m_string_table.PeekCStr (key);
+ }
+
+ virtual bool
+ ReadHashData (uint32_t hash_data_offset,
+ HashData &hash_data) const
+ {
+ lldb::offset_t offset = hash_data_offset;
+ offset += 4; // Skip string table offset that contains offset of hash name in .debug_str
+ const uint32_t count = m_data.GetU32 (&offset);
+ if (count > 0)
+ {
+ hash_data.resize(count);
+ for (uint32_t i=0; i<count; ++i)
+ {
+ if (!m_header.Read(m_data, &offset, hash_data[i]))
+ return false;
+ }
+ }
+ else
+ hash_data.clear();
+ return true;
+ }
+
+ virtual Result
+ GetHashDataForName (const char *name,
+ lldb::offset_t* hash_data_offset_ptr,
+ Pair &pair) const
+ {
+ pair.key = m_data.GetU32 (hash_data_offset_ptr);
+ pair.value.clear();
+
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (pair.key == 0)
+ return eResultEndOfHashData;
+
+ // There definitely should be a string for this string offset, if
+ // there isn't, there is something wrong, return and error
+ const char *strp_cstr = m_string_table.PeekCStr (pair.key);
+ if (strp_cstr == NULL)
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+
+ const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
+ {
+ // We have at least one HashData entry, and we have enough
+ // data to parse at leats "count" HashData enties.
+
+ // First make sure the entire C string matches...
+ const bool match = strcmp (name, strp_cstr) == 0;
+
+ if (!match && m_header.header_data.HashDataHasFixedByteSize())
+ {
+ // If the string doesn't match and we have fixed size data,
+ // we can just add the total byte size of all HashData objects
+ // to the hash data offset and be done...
+ *hash_data_offset_ptr += min_total_hash_data_size;
+ }
+ else
+ {
+ // If the string does match, or we don't have fixed size data
+ // then we need to read the hash data as a stream. If the
+ // string matches we also append all HashData objects to the
+ // value array.
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
+ {
+ // Only happend the HashData if the string matched...
+ if (match)
+ pair.value.push_back (die_info);
+ }
+ else
+ {
+ // Something went wrong while reading the data
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+ }
+ // Return the correct response depending on if the string matched
+ // or not...
+ if (match)
+ return eResultKeyMatch; // The key (cstring) matches and we have lookup results!
+ else
+ return eResultKeyMismatch; // The key doesn't match, this function will get called
+ // again for the next key/value or the key terminator
+ // which in our case is a zero .debug_str offset.
+ }
+ else
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+
+ virtual Result
+ AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex,
+ lldb::offset_t* hash_data_offset_ptr,
+ Pair &pair) const
+ {
+ pair.key = m_data.GetU32 (hash_data_offset_ptr);
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (pair.key == 0)
+ return eResultEndOfHashData;
+
+ // There definitely should be a string for this string offset, if
+ // there isn't, there is something wrong, return and error
+ const char *strp_cstr = m_string_table.PeekCStr (pair.key);
+ if (strp_cstr == NULL)
+ return eResultError;
+
+ const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
+ {
+ const bool match = regex.Execute(strp_cstr);
+
+ if (!match && m_header.header_data.HashDataHasFixedByteSize())
+ {
+ // If the regex doesn't match and we have fixed size data,
+ // we can just add the total byte size of all HashData objects
+ // to the hash data offset and be done...
+ *hash_data_offset_ptr += min_total_hash_data_size;
+ }
+ else
+ {
+ // If the string does match, or we don't have fixed size data
+ // then we need to read the hash data as a stream. If the
+ // string matches we also append all HashData objects to the
+ // value array.
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
+ {
+ // Only happend the HashData if the string matched...
+ if (match)
+ pair.value.push_back (die_info);
+ }
+ else
+ {
+ // Something went wrong while reading the data
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+ }
+ // Return the correct response depending on if the string matched
+ // or not...
+ if (match)
+ return eResultKeyMatch; // The key (cstring) matches and we have lookup results!
+ else
+ return eResultKeyMismatch; // The key doesn't match, this function will get called
+ // again for the next key/value or the key terminator
+ // which in our case is a zero .debug_str offset.
+ }
+ else
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+
+ size_t
+ AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex,
+ DIEInfoArray &die_info_array) const
+ {
+ const uint32_t hash_count = m_header.hashes_count;
+ Pair pair;
+ for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
+ {
+ lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
+ while (hash_data_offset != UINT32_MAX)
+ {
+ const lldb::offset_t prev_hash_data_offset = hash_data_offset;
+ Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
+ if (prev_hash_data_offset == hash_data_offset)
+ break;
+
+ // Check the result of getting our hash data
+ switch (hash_result)
+ {
+ case eResultKeyMatch:
+ case eResultKeyMismatch:
+ // Whether we matches or not, it doesn't matter, we
+ // keep looking.
+ break;
+
+ case eResultEndOfHashData:
+ case eResultError:
+ hash_data_offset = UINT32_MAX;
+ break;
+ }
+ }
+ }
+ die_info_array.swap (pair.value);
+ return die_info_array.size();
+ }
+
+ size_t
+ AppendAllDIEsInRange (const uint32_t die_offset_start,
+ const uint32_t die_offset_end,
+ DIEInfoArray &die_info_array) const
+ {
+ const uint32_t hash_count = m_header.hashes_count;
+ for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
+ {
+ bool done = false;
+ lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
+ while (!done && hash_data_offset != UINT32_MAX)
+ {
+ KeyType key = m_data.GetU32 (&hash_data_offset);
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (key == 0)
+ break;
+
+ const uint32_t count = m_data.GetU32 (&hash_data_offset);
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, &hash_data_offset, die_info))
+ {
+ if (die_info.offset == 0)
+ done = true;
+ if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
+ die_info_array.push_back(die_info);
+ }
+ }
+ }
+ }
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByName (const char *name, DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByNameAndTag (const char *name,
+ const dw_tag_t tag,
+ DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByNameAndTagAndQualifiedNameHash (const char *name,
+ const dw_tag_t tag,
+ const uint32_t qualified_name_hash,
+ DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ {
+ if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
+ {
+ // If we have two atoms, then we have the DIE offset and
+ // the type flags so we can find the objective C class
+ // efficiently.
+ DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
+ UINT32_MAX,
+ eTypeFlagClassIsImplementation,
+ die_offsets);
+ }
+ else
+ {
+ // We don't only want the one true definition, so try and see
+ // what we can find, and only return class or struct DIEs.
+ // If we do have the full implementation, then return it alone,
+ // else return all possible matches.
+ const bool return_implementation_only_if_available = true;
+ DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
+ return_implementation_only_if_available,
+ die_offsets);
+ }
+ }
+ return die_offsets.size();
+ }
+
+ size_t
+ FindByName (const char *name, DIEInfoArray &die_info_array)
+ {
+ Pair kv_pair;
+ size_t old_size = die_info_array.size();
+ if (Find (name, kv_pair))
+ {
+ die_info_array.swap(kv_pair.value);
+ return die_info_array.size() - old_size;
+ }
+ return 0;
+ }
+
+ protected:
+ const lldb_private::DataExtractor &m_data;
+ const lldb_private::DataExtractor &m_string_table;
+ std::string m_name;
+ };
+};
+
+
+#endif // SymbolFileDWARF_HashedNameToDIE_h_
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
new file mode 100644
index 000000000000..27fa261813bb
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -0,0 +1,232 @@
+//===-- LogChannelDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LogChannelDWARF.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// when the one and only logging channel is abled, then this will be non NULL.
+static LogChannelDWARF* g_log_channel = NULL;
+
+LogChannelDWARF::LogChannelDWARF () :
+ LogChannel ()
+{
+}
+
+LogChannelDWARF::~LogChannelDWARF ()
+{
+}
+
+
+void
+LogChannelDWARF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ LogChannelDWARF::CreateInstance);
+}
+
+void
+LogChannelDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (LogChannelDWARF::CreateInstance);
+}
+
+LogChannel*
+LogChannelDWARF::CreateInstance ()
+{
+ return new LogChannelDWARF ();
+}
+
+lldb_private::ConstString
+LogChannelDWARF::GetPluginNameStatic()
+{
+ return SymbolFileDWARF::GetPluginNameStatic();
+}
+
+const char *
+LogChannelDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF log channel for debugging plug-in issues.";
+}
+
+lldb_private::ConstString
+LogChannelDWARF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+LogChannelDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+
+void
+LogChannelDWARF::Delete ()
+{
+ g_log_channel = NULL;
+}
+
+
+void
+LogChannelDWARF::Disable (const char **categories, Stream *feedback_strm)
+{
+ if (m_log_ap.get() == NULL)
+ return;
+
+ uint32_t flag_bits = m_log_ap->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0) flag_bits &= ~DWARF_LOG_ALL;
+ else if (::strcasecmp (arg, "info") == 0) flag_bits &= ~DWARF_LOG_DEBUG_INFO;
+ else if (::strcasecmp (arg, "line") == 0) flag_bits &= ~DWARF_LOG_DEBUG_LINE;
+ else if (::strcasecmp (arg, "pubnames") == 0) flag_bits &= ~DWARF_LOG_DEBUG_PUBNAMES;
+ else if (::strcasecmp (arg, "pubtypes") == 0) flag_bits &= ~DWARF_LOG_DEBUG_PUBTYPES;
+ else if (::strcasecmp (arg, "aranges") == 0) flag_bits &= ~DWARF_LOG_DEBUG_ARANGES;
+ else if (::strcasecmp (arg, "lookups") == 0) flag_bits &= ~DWARF_LOG_LOOKUPS;
+ else if (::strcasecmp (arg, "map") == 0) flag_bits &= ~DWARF_LOG_DEBUG_MAP;
+ else if (::strcasecmp (arg, "default") == 0) flag_bits &= ~DWARF_LOG_DEFAULT;
+ else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits &= ~DWARF_LOG_TYPE_COMPLETION;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListCategories (feedback_strm);
+ }
+ }
+
+ if (flag_bits == 0)
+ Delete ();
+ else
+ m_log_ap->GetMask().Reset (flag_bits);
+
+ return;
+}
+
+bool
+LogChannelDWARF::Enable
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories // The categories to enable within this logging stream, if empty, enable default set
+)
+{
+ Delete ();
+
+ if (m_log_ap)
+ m_log_ap->SetStream(log_stream_sp);
+ else
+ m_log_ap.reset(new Log (log_stream_sp));
+
+ g_log_channel = this;
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0) flag_bits |= DWARF_LOG_ALL;
+ else if (::strcasecmp (arg, "info") == 0) flag_bits |= DWARF_LOG_DEBUG_INFO;
+ else if (::strcasecmp (arg, "line") == 0) flag_bits |= DWARF_LOG_DEBUG_LINE;
+ else if (::strcasecmp (arg, "pubnames") == 0) flag_bits |= DWARF_LOG_DEBUG_PUBNAMES;
+ else if (::strcasecmp (arg, "pubtypes") == 0) flag_bits |= DWARF_LOG_DEBUG_PUBTYPES;
+ else if (::strcasecmp (arg, "aranges") == 0) flag_bits |= DWARF_LOG_DEBUG_ARANGES;
+ else if (::strcasecmp (arg, "lookups") == 0) flag_bits |= DWARF_LOG_LOOKUPS;
+ else if (::strcasecmp (arg, "map") == 0) flag_bits |= DWARF_LOG_DEBUG_MAP;
+ else if (::strcasecmp (arg, "default") == 0) flag_bits |= DWARF_LOG_DEFAULT;
+ else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits |= DWARF_LOG_TYPE_COMPLETION;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = DWARF_LOG_DEFAULT;
+ m_log_ap->GetMask().Reset(flag_bits);
+ m_log_ap->GetOptions().Reset(log_options);
+ return m_log_ap.get() != NULL;
+}
+
+void
+LogChannelDWARF::ListCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " info - log the parsing if .debug_info\n"
+ " line - log the parsing if .debug_line\n"
+ " pubnames - log the parsing if .debug_pubnames\n"
+ " pubtypes - log the parsing if .debug_pubtypes\n"
+ " lookups - log any lookups that happen by name, regex, or address\n"
+ " completion - log struct/unions/class type completions\n"
+ " map - log insertions of object files into DWARF debug maps\n",
+ SymbolFileDWARF::GetPluginNameStatic().GetCString());
+}
+
+Log *
+LogChannelDWARF::GetLog ()
+{
+ if (g_log_channel)
+ return g_log_channel->m_log_ap.get();
+
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAll (uint32_t mask)
+{
+ if (g_log_channel && g_log_channel->m_log_ap.get())
+ {
+ if (g_log_channel->m_log_ap->GetMask().AllSet(mask))
+ return g_log_channel->m_log_ap.get();
+ }
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAny (uint32_t mask)
+{
+ if (g_log_channel && g_log_channel->m_log_ap.get())
+ {
+ if (g_log_channel->m_log_ap->GetMask().AnySet(mask))
+ return g_log_channel->m_log_ap.get();
+ }
+ return NULL;
+}
+
+void
+LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...)
+{
+ if (g_log_channel)
+ {
+ Log *log = g_log_channel->m_log_ap.get();
+ if (log && log->GetMask().AnySet(mask))
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
new file mode 100644
index 000000000000..2091a8414f58
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -0,0 +1,89 @@
+//===-- LogChannelDWARF.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_LogChannelDWARF_h_
+#define SymbolFileDWARF_LogChannelDWARF_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define DWARF_LOG_VERBOSE (1u << 0)
+#define DWARF_LOG_DEBUG_INFO (1u << 1)
+#define DWARF_LOG_DEBUG_LINE (1u << 2)
+#define DWARF_LOG_DEBUG_PUBNAMES (1u << 3)
+#define DWARF_LOG_DEBUG_PUBTYPES (1u << 4)
+#define DWARF_LOG_DEBUG_ARANGES (1u << 5)
+#define DWARF_LOG_LOOKUPS (1u << 6)
+#define DWARF_LOG_TYPE_COMPLETION (1u << 7)
+#define DWARF_LOG_DEBUG_MAP (1u << 8)
+#define DWARF_LOG_ALL (UINT32_MAX)
+#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
+
+class LogChannelDWARF : public lldb_private::LogChannel
+{
+public:
+ LogChannelDWARF ();
+
+ virtual
+ ~LogChannelDWARF ();
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::LogChannel *
+ CreateInstance ();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ Disable (const char** categories, lldb_private::Stream *feedback_strm);
+
+ void
+ Delete ();
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories); // The categories to enable within this logging stream, if empty, enable default set
+
+ virtual void
+ ListCategories (lldb_private::Stream *strm);
+
+ static lldb_private::Log *
+ GetLog ();
+
+ static lldb_private::Log *
+ GetLogIfAll (uint32_t mask);
+
+ static lldb_private::Log *
+ GetLogIfAny (uint32_t mask);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // SymbolFileDWARF_LogChannelDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
new file mode 100644
index 000000000000..5514469d0758
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -0,0 +1,87 @@
+//===-- NameToDIE.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NameToDIE.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "SymbolFileDWARF.h"
+using namespace lldb;
+using namespace lldb_private;
+
+void
+NameToDIE::Finalize()
+{
+ m_map.Sort ();
+ m_map.SizeToFit ();
+}
+
+void
+NameToDIE::Insert (const ConstString& name, uint32_t die_offset)
+{
+ m_map.Append(name.GetCString(), die_offset);
+}
+
+size_t
+NameToDIE::Find (const ConstString &name, DIEArray &info_array) const
+{
+ return m_map.GetValues (name.GetCString(), info_array);
+}
+
+size_t
+NameToDIE::Find (const RegularExpression& regex, DIEArray &info_array) const
+{
+ return m_map.GetValues (regex, info_array);
+}
+
+size_t
+NameToDIE::FindAllEntriesForCompileUnit (uint32_t cu_offset,
+ uint32_t cu_end_offset,
+ DIEArray &info_array) const
+{
+ const size_t initial_size = info_array.size();
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ const uint32_t die_offset = m_map.GetValueAtIndexUnchecked(i);
+ if (cu_offset < die_offset && die_offset < cu_end_offset)
+ info_array.push_back (die_offset);
+ }
+ return info_array.size() - initial_size;
+}
+
+void
+NameToDIE::Dump (Stream *s)
+{
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ const char *cstr = m_map.GetCStringAtIndex(i);
+ s->Printf("%p: {0x%8.8x} \"%s\"\n", cstr, m_map.GetValueAtIndexUnchecked(i), cstr);
+ }
+}
+
+void
+NameToDIE::ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const
+{
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ if (!callback(m_map.GetCStringAtIndexUnchecked(i),
+ m_map.GetValueAtIndexUnchecked (i)))
+ break;
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/source/Plugins/SymbolFile/DWARF/NameToDIE.h
new file mode 100644
index 000000000000..f9a12736bf9e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.h
@@ -0,0 +1,65 @@
+//===-- NameToDIE.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_NameToDIE_h_
+#define SymbolFileDWARF_NameToDIE_h_
+
+#include "lldb/Core/UniqueCStringMap.h"
+
+#include <functional>
+
+#include "lldb/lldb-defines.h"
+
+class SymbolFileDWARF;
+
+typedef std::vector<uint32_t> DIEArray;
+
+class NameToDIE
+{
+public:
+ NameToDIE () :
+ m_map()
+ {
+ }
+
+ ~NameToDIE ()
+ {
+ }
+
+ void
+ Dump (lldb_private::Stream *s);
+
+ void
+ Insert (const lldb_private::ConstString& name, uint32_t die_offset);
+
+ void
+ Finalize();
+
+ size_t
+ Find (const lldb_private::ConstString &name,
+ DIEArray &info_array) const;
+
+ size_t
+ Find (const lldb_private::RegularExpression& regex,
+ DIEArray &info_array) const;
+
+ size_t
+ FindAllEntriesForCompileUnit (uint32_t cu_offset,
+ uint32_t cu_end_offset,
+ DIEArray &info_array) const;
+
+ void
+ ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const;
+
+protected:
+ lldb_private::UniqueCStringMap<uint32_t> m_map;
+
+};
+
+#endif // SymbolFileDWARF_NameToDIE_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
new file mode 100644
index 000000000000..f265af837eef
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -0,0 +1,7973 @@
+//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+// Other libraries and framework includes
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Sema/DeclSpec.h"
+
+#include "llvm/Support/Casting.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDebugLine.h"
+#include "DWARFDebugPubnames.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDeclContext.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationList.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+
+#include <map>
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+#define DIE_IS_BEING_PARSED ((lldb_private::Type*)1)
+
+using namespace lldb;
+using namespace lldb_private;
+
+//static inline bool
+//child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag)
+//{
+// switch (tag)
+// {
+// default:
+// break;
+// case DW_TAG_subprogram:
+// case DW_TAG_inlined_subroutine:
+// case DW_TAG_class_type:
+// case DW_TAG_structure_type:
+// case DW_TAG_union_type:
+// return true;
+// }
+// return false;
+//}
+//
+static AccessType
+DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility)
+{
+ switch (dwarf_accessibility)
+ {
+ case DW_ACCESS_public: return eAccessPublic;
+ case DW_ACCESS_private: return eAccessPrivate;
+ case DW_ACCESS_protected: return eAccessProtected;
+ default: break;
+ }
+ return eAccessNone;
+}
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+
+class DIEStack
+{
+public:
+
+ void Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+ {
+ m_dies.push_back (DIEInfo(cu, die));
+ }
+
+
+ void LogDIEs (Log *log, SymbolFileDWARF *dwarf)
+ {
+ StreamString log_strm;
+ const size_t n = m_dies.size();
+ log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n);
+ for (size_t i=0; i<n; i++)
+ {
+ DWARFCompileUnit *cu = m_dies[i].cu;
+ const DWARFDebugInfoEntry *die = m_dies[i].die;
+ std::string qualified_name;
+ die->GetQualifiedName(dwarf, cu, qualified_name);
+ log_strm.Printf ("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n",
+ (uint64_t)i,
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ qualified_name.c_str());
+ }
+ log->PutCString(log_strm.GetData());
+ }
+ void Pop ()
+ {
+ m_dies.pop_back();
+ }
+
+ class ScopedPopper
+ {
+ public:
+ ScopedPopper (DIEStack &die_stack) :
+ m_die_stack (die_stack),
+ m_valid (false)
+ {
+ }
+
+ void
+ Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+ {
+ m_valid = true;
+ m_die_stack.Push (cu, die);
+ }
+
+ ~ScopedPopper ()
+ {
+ if (m_valid)
+ m_die_stack.Pop();
+ }
+
+
+
+ protected:
+ DIEStack &m_die_stack;
+ bool m_valid;
+ };
+
+protected:
+ struct DIEInfo {
+ DIEInfo (DWARFCompileUnit *c, const DWARFDebugInfoEntry *d) :
+ cu(c),
+ die(d)
+ {
+ }
+ DWARFCompileUnit *cu;
+ const DWARFDebugInfoEntry *die;
+ };
+ typedef std::vector<DIEInfo> Stack;
+ Stack m_dies;
+};
+#endif
+
+void
+SymbolFileDWARF::Initialize()
+{
+ LogChannelDWARF::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+ LogChannelDWARF::Initialize();
+}
+
+
+lldb_private::ConstString
+SymbolFileDWARF::GetPluginNameStatic()
+{
+ static ConstString g_name("dwarf");
+ return g_name;
+}
+
+const char *
+SymbolFileDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader.";
+}
+
+
+SymbolFile*
+SymbolFileDWARF::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARF(obj_file);
+}
+
+TypeList *
+SymbolFileDWARF::GetTypeList ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetTypeList();
+ return m_obj_file->GetModule()->GetTypeList();
+
+}
+void
+SymbolFileDWARF::GetTypes (DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset,
+ uint32_t type_mask,
+ TypeSet &type_set)
+{
+ if (cu)
+ {
+ if (die)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+
+ if (die_offset >= max_die_offset)
+ return;
+
+ if (die_offset >= min_die_offset)
+ {
+ const dw_tag_t tag = die->Tag();
+
+ bool add_type = false;
+
+ switch (tag)
+ {
+ case DW_TAG_array_type: add_type = (type_mask & eTypeClassArray ) != 0; break;
+ case DW_TAG_unspecified_type:
+ case DW_TAG_base_type: add_type = (type_mask & eTypeClassBuiltin ) != 0; break;
+ case DW_TAG_class_type: add_type = (type_mask & eTypeClassClass ) != 0; break;
+ case DW_TAG_structure_type: add_type = (type_mask & eTypeClassStruct ) != 0; break;
+ case DW_TAG_union_type: add_type = (type_mask & eTypeClassUnion ) != 0; break;
+ case DW_TAG_enumeration_type: add_type = (type_mask & eTypeClassEnumeration ) != 0; break;
+ case DW_TAG_subroutine_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine: add_type = (type_mask & eTypeClassFunction ) != 0; break;
+ case DW_TAG_pointer_type: add_type = (type_mask & eTypeClassPointer ) != 0; break;
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_reference_type: add_type = (type_mask & eTypeClassReference ) != 0; break;
+ case DW_TAG_typedef: add_type = (type_mask & eTypeClassTypedef ) != 0; break;
+ case DW_TAG_ptr_to_member_type: add_type = (type_mask & eTypeClassMemberPointer ) != 0; break;
+ }
+
+ if (add_type)
+ {
+ const bool assert_not_being_parsed = true;
+ Type *type = ResolveTypeUID (cu, die, assert_not_being_parsed);
+ if (type)
+ {
+ if (type_set.find(type) == type_set.end())
+ type_set.insert(type);
+ }
+ }
+ }
+
+ for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild();
+ child_die != NULL;
+ child_die = child_die->GetSibling())
+ {
+ GetTypes (cu, child_die, min_die_offset, max_die_offset, type_mask, type_set);
+ }
+ }
+ }
+}
+
+size_t
+SymbolFileDWARF::GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ TypeList &type_list)
+
+{
+ TypeSet type_set;
+
+ CompileUnit *comp_unit = NULL;
+ DWARFCompileUnit* dwarf_cu = NULL;
+ if (sc_scope)
+ comp_unit = sc_scope->CalculateSymbolContextCompileUnit();
+
+ if (comp_unit)
+ {
+ dwarf_cu = GetDWARFCompileUnit(comp_unit);
+ if (dwarf_cu == 0)
+ return 0;
+ GetTypes (dwarf_cu,
+ dwarf_cu->DIE(),
+ dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ type_mask,
+ type_set);
+ }
+ else
+ {
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ const size_t num_cus = info->GetNumCompileUnits();
+ for (size_t cu_idx=0; cu_idx<num_cus; ++cu_idx)
+ {
+ dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu)
+ {
+ GetTypes (dwarf_cu,
+ dwarf_cu->DIE(),
+ 0,
+ UINT32_MAX,
+ type_mask,
+ type_set);
+ }
+ }
+ }
+ }
+// if (m_using_apple_tables)
+// {
+// DWARFMappedHash::MemoryTable *apple_types = m_apple_types_ap.get();
+// if (apple_types)
+// {
+// apple_types->ForEach([this, &type_set, apple_types, type_mask](const DWARFMappedHash::DIEInfoArray &die_info_array) -> bool {
+//
+// for (auto die_info: die_info_array)
+// {
+// bool add_type = TagMatchesTypeMask (type_mask, 0);
+// if (!add_type)
+// {
+// dw_tag_t tag = die_info.tag;
+// if (tag == 0)
+// {
+// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_info.offset, NULL);
+// tag = die->Tag();
+// }
+// add_type = TagMatchesTypeMask (type_mask, tag);
+// }
+// if (add_type)
+// {
+// Type *type = ResolveTypeUID(die_info.offset);
+//
+// if (type_set.find(type) == type_set.end())
+// type_set.insert(type);
+// }
+// }
+// return true; // Keep iterating
+// });
+// }
+// }
+// else
+// {
+// if (!m_indexed)
+// Index ();
+//
+// m_type_index.ForEach([this, &type_set, type_mask](const char *name, uint32_t die_offset) -> bool {
+//
+// bool add_type = TagMatchesTypeMask (type_mask, 0);
+//
+// if (!add_type)
+// {
+// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_offset, NULL);
+// if (die)
+// {
+// const dw_tag_t tag = die->Tag();
+// add_type = TagMatchesTypeMask (type_mask, tag);
+// }
+// }
+//
+// if (add_type)
+// {
+// Type *type = ResolveTypeUID(die_offset);
+//
+// if (type_set.find(type) == type_set.end())
+// type_set.insert(type);
+// }
+// return true; // Keep iterating
+// });
+// }
+
+ std::set<ClangASTType> clang_type_set;
+ size_t num_types_added = 0;
+ for (Type *type : type_set)
+ {
+ ClangASTType clang_type = type->GetClangForwardType();
+ if (clang_type_set.find(clang_type) == clang_type_set.end())
+ {
+ clang_type_set.insert(clang_type);
+ type_list.Insert (type->shared_from_this());
+ ++num_types_added;
+ }
+ }
+ return num_types_added;
+}
+
+
+//----------------------------------------------------------------------
+// Gets the first parent that is a lexical block, function or inlined
+// subroutine, or compile unit.
+//----------------------------------------------------------------------
+static const DWARFDebugInfoEntry *
+GetParentSymbolContextDIE(const DWARFDebugInfoEntry *child_die)
+{
+ const DWARFDebugInfoEntry *die;
+ for (die = child_die->GetParent(); die != NULL; die = die->GetParent())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ return die;
+ }
+ }
+ return NULL;
+}
+
+
+SymbolFileDWARF::SymbolFileDWARF(ObjectFile* objfile) :
+ SymbolFile (objfile),
+ UserID (0), // Used by SymbolFileDWARFDebugMap to when this class parses .o files to contain the .o file index/ID
+ m_debug_map_module_wp (),
+ m_debug_map_symfile (NULL),
+ m_clang_tu_decl (NULL),
+ m_flags(),
+ m_data_debug_abbrev (),
+ m_data_debug_aranges (),
+ m_data_debug_frame (),
+ m_data_debug_info (),
+ m_data_debug_line (),
+ m_data_debug_loc (),
+ m_data_debug_ranges (),
+ m_data_debug_str (),
+ m_data_apple_names (),
+ m_data_apple_types (),
+ m_data_apple_namespaces (),
+ m_abbr(),
+ m_info(),
+ m_line(),
+ m_apple_names_ap (),
+ m_apple_types_ap (),
+ m_apple_namespaces_ap (),
+ m_apple_objc_ap (),
+ m_function_basename_index(),
+ m_function_fullname_index(),
+ m_function_method_index(),
+ m_function_selector_index(),
+ m_objc_class_selectors_index(),
+ m_global_index(),
+ m_type_index(),
+ m_namespace_index(),
+ m_indexed (false),
+ m_is_external_ast_source (false),
+ m_using_apple_tables (false),
+ m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate),
+ m_ranges(),
+ m_unique_ast_type_map ()
+{
+}
+
+SymbolFileDWARF::~SymbolFileDWARF()
+{
+ if (m_is_external_ast_source)
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ module_sp->GetClangASTContext().RemoveExternalSource ();
+ }
+}
+
+static const ConstString &
+GetDWARFMachOSegmentName ()
+{
+ static ConstString g_dwarf_section_name ("__DWARF");
+ return g_dwarf_section_name;
+}
+
+UniqueDWARFASTTypeMap &
+SymbolFileDWARF::GetUniqueDWARFASTTypeMap ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetUniqueDWARFASTTypeMap ();
+ return m_unique_ast_type_map;
+}
+
+ClangASTContext &
+SymbolFileDWARF::GetClangASTContext ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetClangASTContext ();
+
+ ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext();
+ if (!m_is_external_ast_source)
+ {
+ m_is_external_ast_source = true;
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl,
+ SymbolFileDWARF::CompleteObjCInterfaceDecl,
+ SymbolFileDWARF::FindExternalVisibleDeclsByName,
+ SymbolFileDWARF::LayoutRecordType,
+ this));
+ ast.SetExternalSource (ast_source_ap);
+ }
+ return ast;
+}
+
+void
+SymbolFileDWARF::InitializeObject()
+{
+ // Install our external AST source callbacks so we can complete Clang types.
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ {
+ const SectionList *section_list = module_sp->GetSectionList();
+
+ const Section* section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get();
+
+ // Memory map the DWARF mach-o segment so we have everything mmap'ed
+ // to keep our heap memory usage down.
+ if (section)
+ m_obj_file->MemoryMapSectionData(section, m_dwarf_data);
+ }
+ get_apple_names_data();
+ if (m_data_apple_names.GetByteSize() > 0)
+ {
+ m_apple_names_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_names, get_debug_str_data(), ".apple_names"));
+ if (m_apple_names_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_names_ap.reset();
+ }
+ get_apple_types_data();
+ if (m_data_apple_types.GetByteSize() > 0)
+ {
+ m_apple_types_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_types, get_debug_str_data(), ".apple_types"));
+ if (m_apple_types_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_types_ap.reset();
+ }
+
+ get_apple_namespaces_data();
+ if (m_data_apple_namespaces.GetByteSize() > 0)
+ {
+ m_apple_namespaces_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_namespaces, get_debug_str_data(), ".apple_namespaces"));
+ if (m_apple_namespaces_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_namespaces_ap.reset();
+ }
+
+ get_apple_objc_data();
+ if (m_data_apple_objc.GetByteSize() > 0)
+ {
+ m_apple_objc_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_objc, get_debug_str_data(), ".apple_objc"));
+ if (m_apple_objc_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_objc_ap.reset();
+ }
+}
+
+bool
+SymbolFileDWARF::SupportedVersion(uint16_t version)
+{
+ return version == 2 || version == 3 || version == 4;
+}
+
+uint32_t
+SymbolFileDWARF::CalculateAbilities ()
+{
+ uint32_t abilities = 0;
+ if (m_obj_file != NULL)
+ {
+ const Section* section = NULL;
+ const SectionList *section_list = m_obj_file->GetSectionList();
+ if (section_list == NULL)
+ return 0;
+
+ uint64_t debug_abbrev_file_size = 0;
+ uint64_t debug_info_file_size = 0;
+ uint64_t debug_line_file_size = 0;
+
+ section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get();
+
+ if (section)
+ section_list = &section->GetChildren ();
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugInfo, true).get();
+ if (section != NULL)
+ {
+ debug_info_file_size = section->GetFileSize();
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugAbbrev, true).get();
+ if (section)
+ debug_abbrev_file_size = section->GetFileSize();
+ else
+ m_flags.Set (flagsGotDebugAbbrevData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugAranges, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugArangesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugFrame, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugFrameData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugLine, true).get();
+ if (section)
+ debug_line_file_size = section->GetFileSize();
+ else
+ m_flags.Set (flagsGotDebugLineData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugLoc, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugLocData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugMacInfo, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugMacInfoData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubNames, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugPubNamesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubTypes, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugPubTypesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugRanges, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugRangesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugStrData);
+ }
+ else
+ {
+ const char *symfile_dir_cstr = m_obj_file->GetFileSpec().GetDirectory().GetCString();
+ if (symfile_dir_cstr)
+ {
+ if (strcasestr(symfile_dir_cstr, ".dsym"))
+ {
+ if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo)
+ {
+ // We have a dSYM file that didn't have a any debug info.
+ // If the string table has a size of 1, then it was made from
+ // an executable with no debug info, or from an executable that
+ // was stripped.
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get();
+ if (section && section->GetFileSize() == 1)
+ {
+ m_obj_file->GetModule()->ReportWarning ("empty dSYM file detected, dSYM was created with an executable with no debug info.");
+ }
+ }
+ }
+ }
+ }
+
+ if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
+ abilities |= CompileUnits | Functions | Blocks | GlobalVariables | LocalVariables | VariableTypes;
+
+ if (debug_line_file_size > 0)
+ abilities |= LineTables;
+ }
+ return abilities;
+}
+
+const DataExtractor&
+SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, SectionType sect_type, DataExtractor &data)
+{
+ if (m_flags.IsClear (got_flag))
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ m_flags.Set (got_flag);
+ const SectionList *section_list = module_sp->GetSectionList();
+ if (section_list)
+ {
+ SectionSP section_sp (section_list->FindSectionByType(sect_type, true));
+ if (section_sp)
+ {
+ // See if we memory mapped the DWARF segment?
+ if (m_dwarf_data.GetByteSize())
+ {
+ data.SetData(m_dwarf_data, section_sp->GetOffset (), section_sp->GetFileSize());
+ }
+ else
+ {
+ if (m_obj_file->ReadSectionData (section_sp.get(), data) == 0)
+ data.Clear();
+ }
+ }
+ }
+ }
+ return data;
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_abbrev_data()
+{
+ return GetCachedSectionData (flagsGotDebugAbbrevData, eSectionTypeDWARFDebugAbbrev, m_data_debug_abbrev);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_aranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugArangesData, eSectionTypeDWARFDebugAranges, m_data_debug_aranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_frame_data()
+{
+ return GetCachedSectionData (flagsGotDebugFrameData, eSectionTypeDWARFDebugFrame, m_data_debug_frame);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_info_data()
+{
+ return GetCachedSectionData (flagsGotDebugInfoData, eSectionTypeDWARFDebugInfo, m_data_debug_info);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_line_data()
+{
+ return GetCachedSectionData (flagsGotDebugLineData, eSectionTypeDWARFDebugLine, m_data_debug_line);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_loc_data()
+{
+ return GetCachedSectionData (flagsGotDebugLocData, eSectionTypeDWARFDebugLoc, m_data_debug_loc);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_ranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugRangesData, eSectionTypeDWARFDebugRanges, m_data_debug_ranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_str_data()
+{
+ return GetCachedSectionData (flagsGotDebugStrData, eSectionTypeDWARFDebugStr, m_data_debug_str);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_names_data()
+{
+ return GetCachedSectionData (flagsGotAppleNamesData, eSectionTypeDWARFAppleNames, m_data_apple_names);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_types_data()
+{
+ return GetCachedSectionData (flagsGotAppleTypesData, eSectionTypeDWARFAppleTypes, m_data_apple_types);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_namespaces_data()
+{
+ return GetCachedSectionData (flagsGotAppleNamespacesData, eSectionTypeDWARFAppleNamespaces, m_data_apple_namespaces);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_objc_data()
+{
+ return GetCachedSectionData (flagsGotAppleObjCData, eSectionTypeDWARFAppleObjC, m_data_apple_objc);
+}
+
+
+DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev()
+{
+ if (m_abbr.get() == NULL)
+ {
+ const DataExtractor &debug_abbrev_data = get_debug_abbrev_data();
+ if (debug_abbrev_data.GetByteSize() > 0)
+ {
+ m_abbr.reset(new DWARFDebugAbbrev());
+ if (m_abbr.get())
+ m_abbr->Parse(debug_abbrev_data);
+ }
+ }
+ return m_abbr.get();
+}
+
+const DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev() const
+{
+ return m_abbr.get();
+}
+
+
+DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo()
+{
+ if (m_info.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_info_data().GetByteSize() > 0)
+ {
+ m_info.reset(new DWARFDebugInfo());
+ if (m_info.get())
+ {
+ m_info->SetDwarfData(this);
+ }
+ }
+ }
+ return m_info.get();
+}
+
+const DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo() const
+{
+ return m_info.get();
+}
+
+DWARFCompileUnit*
+SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ if (GetDebugMapSymfile ())
+ {
+ // The debug map symbol file made the compile units for this DWARF
+ // file which is .o file with DWARF in it, and we should have
+ // only 1 compile unit which is at offset zero in the DWARF.
+ // TODO: modify to support LTO .o files where each .o file might
+ // have multiple DW_TAG_compile_unit tags.
+ return info->GetCompileUnit(0).get();
+ }
+ else
+ {
+ // Just a normal DWARF file whose user ID for the compile unit is
+ // the DWARF offset itself
+ return info->GetCompileUnit((dw_offset_t)comp_unit->GetID()).get();
+ }
+ }
+ return NULL;
+}
+
+
+DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges()
+{
+ if (m_ranges.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_ranges_data().GetByteSize() > 0)
+ {
+ m_ranges.reset(new DWARFDebugRanges());
+ if (m_ranges.get())
+ m_ranges->Extract(this);
+ }
+ }
+ return m_ranges.get();
+}
+
+const DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges() const
+{
+ return m_ranges.get();
+}
+
+lldb::CompUnitSP
+SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
+{
+ CompUnitSP cu_sp;
+ if (dwarf_cu)
+ {
+ CompileUnit *comp_unit = (CompileUnit*)dwarf_cu->GetUserData();
+ if (comp_unit)
+ {
+ // We already parsed this compile unit, had out a shared pointer to it
+ cu_sp = comp_unit->shared_from_this();
+ }
+ else
+ {
+ if (GetDebugMapSymfile ())
+ {
+ // Let the debug map create the compile unit
+ cu_sp = m_debug_map_symfile->GetCompileUnit(this);
+ dwarf_cu->SetUserData(cu_sp.get());
+ }
+ else
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ {
+ const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly ();
+ if (cu_die)
+ {
+ const char * cu_die_name = cu_die->GetName(this, dwarf_cu);
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
+ LanguageType cu_language = (LanguageType)cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
+ if (cu_die_name)
+ {
+ std::string ramapped_file;
+ FileSpec cu_file_spec;
+
+ if (cu_die_name[0] == '/' || cu_comp_dir == NULL || cu_comp_dir[0] == '\0')
+ {
+ // If we have a full path to the compile unit, we don't need to resolve
+ // the file. This can be expensive e.g. when the source files are NFS mounted.
+ if (module_sp->RemapSourceFile(cu_die_name, ramapped_file))
+ cu_file_spec.SetFile (ramapped_file.c_str(), false);
+ else
+ cu_file_spec.SetFile (cu_die_name, false);
+ }
+ else
+ {
+ std::string fullpath(cu_comp_dir);
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += cu_die_name;
+ if (module_sp->RemapSourceFile (fullpath.c_str(), ramapped_file))
+ cu_file_spec.SetFile (ramapped_file.c_str(), false);
+ else
+ cu_file_spec.SetFile (fullpath.c_str(), false);
+ }
+
+ cu_sp.reset(new CompileUnit (module_sp,
+ dwarf_cu,
+ cu_file_spec,
+ MakeUserID(dwarf_cu->GetOffset()),
+ cu_language));
+ if (cu_sp)
+ {
+ dwarf_cu->SetUserData(cu_sp.get());
+
+ // Figure out the compile unit index if we weren't given one
+ if (cu_idx == UINT32_MAX)
+ DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx);
+
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return cu_sp;
+}
+
+uint32_t
+SymbolFileDWARF::GetNumCompileUnits()
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ return info->GetNumCompileUnits();
+ return 0;
+}
+
+CompUnitSP
+SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP cu_sp;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu)
+ cu_sp = ParseCompileUnit(dwarf_cu, cu_idx);
+ }
+ return cu_sp;
+}
+
+static void
+AddRangesToBlock (Block& block,
+ DWARFDebugRanges::RangeList& ranges,
+ addr_t block_base_addr)
+{
+ const size_t num_ranges = ranges.GetSize();
+ for (size_t i = 0; i<num_ranges; ++i)
+ {
+ const DWARFDebugRanges::Range &range = ranges.GetEntryRef (i);
+ const addr_t range_base = range.GetRangeBase();
+ assert (range_base >= block_base_addr);
+ block.AddRange(Block::Range (range_base - block_base_addr, range.GetByteSize()));;
+ }
+ block.FinalizeRanges ();
+}
+
+
+Function *
+SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die)
+{
+ DWARFDebugRanges::RangeList func_ranges;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ DWARFExpression frame_base;
+
+ assert (die->Tag() == DW_TAG_subprogram);
+
+ if (die->Tag() != DW_TAG_subprogram)
+ return NULL;
+
+ if (die->GetDIENamesAndRanges (this,
+ dwarf_cu,
+ name,
+ mangled,
+ func_ranges,
+ decl_file,
+ decl_line,
+ decl_column,
+ call_file,
+ call_line,
+ call_column,
+ &frame_base))
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range;
+ lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase (0);
+ lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd (0);
+ if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, module_sp->GetSectionList());
+ if (func_range.GetBaseAddress().IsValid())
+ func_range.SetByteSize(highest_func_addr - lowest_func_addr);
+ }
+
+ if (func_range.GetBaseAddress().IsValid())
+ {
+ Mangled func_name;
+ if (mangled)
+ func_name.SetValue(ConstString(mangled), true);
+ else if (name)
+ func_name.SetValue(ConstString(name), false);
+
+ FunctionSP func_sp;
+ std::unique_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration (sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
+ decl_line,
+ decl_column));
+
+ // Supply the type _only_ if it has already been parsed
+ Type *func_type = m_die_to_type.lookup (die);
+
+ assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
+
+ if (FixupAddress (func_range.GetBaseAddress()))
+ {
+ const user_id_t func_user_id = MakeUserID(die->GetOffset());
+ func_sp.reset(new Function (sc.comp_unit,
+ MakeUserID(func_user_id), // UserID is the DIE offset
+ MakeUserID(func_user_id),
+ func_name,
+ func_type,
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ if (frame_base.IsValid())
+ func_sp->GetFrameBaseExpression() = frame_base;
+ sc.comp_unit->AddFunction(func_sp);
+ return func_sp.get();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+bool
+SymbolFileDWARF::FixupAddress (Address &addr)
+{
+ SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile ();
+ if (debug_map_symfile)
+ {
+ return debug_map_symfile->LinkOSOAddress(addr);
+ }
+ // This is a normal DWARF file, no address fixups need to happen
+ return true;
+}
+lldb::LanguageType
+SymbolFileDWARF::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly();
+ if (die)
+ {
+ const uint32_t language = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
+ if (language)
+ return (lldb::LanguageType)language;
+ }
+ }
+ return eLanguageTypeUnknown;
+}
+
+size_t
+SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ size_t functions_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ DWARFDIECollection function_dies;
+ const size_t num_functions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies);
+ size_t func_idx;
+ for (func_idx = 0; func_idx < num_functions; ++func_idx)
+ {
+ const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx);
+ if (sc.comp_unit->FindFunctionByUID (MakeUserID(die->GetOffset())).get() == NULL)
+ {
+ if (ParseCompileUnitFunction(sc, dwarf_cu, die))
+ ++functions_added;
+ }
+ }
+ //FixupTypes();
+ }
+ return functions_added;
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+
+ if (cu_die)
+ {
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
+ dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+
+ // All file indexes in DWARF are one based and a file of index zero is
+ // supposed to be the compile unit itself.
+ support_files.Append (*sc.comp_unit);
+
+ return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files);
+ }
+ }
+ return false;
+}
+
+struct ParseDWARFLineTableCallbackInfo
+{
+ LineTable* line_table;
+ std::unique_ptr<LineSequence> sequence_ap;
+};
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ ParseDWARFLineTableCallbackInfo* info = (ParseDWARFLineTableCallbackInfo*)userData;
+ LineTable* line_table = info->line_table;
+
+ // If this is our first time here, we need to create a
+ // sequence container.
+ if (!info->sequence_ap.get())
+ {
+ info->sequence_ap.reset(line_table->CreateLineSequenceContainer());
+ assert(info->sequence_ap.get());
+ }
+ line_table->AppendLineEntryToSequence (info->sequence_ap.get(),
+ state.address,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ if (state.end_sequence)
+ {
+ // First, put the current sequence into the line table.
+ line_table->InsertSequence(info->sequence_ap.get());
+ // Then, empty it to prepare for the next sequence.
+ info->sequence_ap->Clear();
+ }
+ }
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ if (sc.comp_unit->GetLineTable() != NULL)
+ return true;
+
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+ if (dwarf_cu_die)
+ {
+ const dw_offset_t cu_line_offset = dwarf_cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+ if (cu_line_offset != DW_INVALID_OFFSET)
+ {
+ std::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit));
+ if (line_table_ap.get())
+ {
+ ParseDWARFLineTableCallbackInfo info;
+ info.line_table = line_table_ap.get();
+ lldb::offset_t offset = cu_line_offset;
+ DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info);
+ if (m_debug_map_symfile)
+ {
+ // We have an object file that has a line table with addresses
+ // that are not linked. We need to link the line table and convert
+ // the addresses that are relative to the .o file into addresses
+ // for the main executable.
+ sc.comp_unit->SetLineTable (m_debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get()));
+ }
+ else
+ {
+ sc.comp_unit->SetLineTable(line_table_ap.release());
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks
+(
+ const SymbolContext& sc,
+ Block *parent_block,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ addr_t subprogram_low_pc,
+ uint32_t depth
+)
+{
+ size_t blocks_added = 0;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ {
+ Block *block = NULL;
+ if (tag == DW_TAG_subprogram)
+ {
+ // Skip any DW_TAG_subprogram DIEs that are inside
+ // of a normal or inlined functions. These will be
+ // parsed on their own as separate entities.
+
+ if (depth > 0)
+ break;
+
+ block = parent_block;
+ }
+ else
+ {
+ BlockSP block_sp(new Block (MakeUserID(die->GetOffset())));
+ parent_block->AddChild(block_sp);
+ block = block_sp.get();
+ }
+ DWARFDebugRanges::RangeList ranges;
+ const char *name = NULL;
+ const char *mangled_name = NULL;
+
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ if (die->GetDIENamesAndRanges (this,
+ dwarf_cu,
+ name,
+ mangled_name,
+ ranges,
+ decl_file, decl_line, decl_column,
+ call_file, call_line, call_column))
+ {
+ if (tag == DW_TAG_subprogram)
+ {
+ assert (subprogram_low_pc == LLDB_INVALID_ADDRESS);
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ }
+ else if (tag == DW_TAG_inlined_subroutine)
+ {
+ // We get called here for inlined subroutines in two ways.
+ // The first time is when we are making the Function object
+ // for this inlined concrete instance. Since we're creating a top level block at
+ // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we need to
+ // adjust the containing address.
+ // The second time is when we are parsing the blocks inside the function that contains
+ // the inlined concrete instance. Since these will be blocks inside the containing "real"
+ // function the offset will be for that function.
+ if (subprogram_low_pc == LLDB_INVALID_ADDRESS)
+ {
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ }
+ }
+
+ AddRangesToBlock (*block, ranges, subprogram_low_pc);
+
+ if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL))
+ {
+ std::unique_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
+ decl_line, decl_column));
+
+ std::unique_ptr<Declaration> call_ap;
+ if (call_file != 0 || call_line != 0 || call_column != 0)
+ call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file),
+ call_line, call_column));
+
+ block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get());
+ }
+
+ ++blocks_added;
+
+ if (die->HasChildren())
+ {
+ blocks_added += ParseFunctionBlocks (sc,
+ block,
+ dwarf_cu,
+ die->GetFirstChild(),
+ subprogram_low_pc,
+ depth + 1);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Only parse siblings of the block if we are not at depth zero. A depth
+ // of zero indicates we are currently parsing the top level
+ // DW_TAG_subprogram DIE
+
+ if (depth == 0)
+ die = NULL;
+ else
+ die = die->GetSibling();
+ }
+ return blocks_added;
+}
+
+bool
+SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ const dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ {
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ const char *name = NULL;
+ Type *lldb_type = NULL;
+ ClangASTType clang_type;
+ uint64_t uval64 = 0;
+ bool uval64_valid = false;
+ if (num_attributes > 0)
+ {
+ DWARFFormValue form_value;
+ for (size_t i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_type:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu);
+ lldb_type = ResolveTypeUID(type_die_offset);
+ if (lldb_type)
+ clang_type = lldb_type->GetClangForwardType();
+ }
+ break;
+
+ case DW_AT_const_value:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ uval64_valid = true;
+ uval64 = form_value.Unsigned();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ clang::ASTContext *ast = GetClangASTContext().getASTContext();
+ if (!clang_type)
+ clang_type = GetClangASTContext().GetBasicType(eBasicTypeVoid);
+
+ if (clang_type)
+ {
+ bool is_signed = false;
+ if (name && name[0])
+ template_param_infos.names.push_back(name);
+ else
+ template_param_infos.names.push_back(NULL);
+
+ if (tag == DW_TAG_template_value_parameter &&
+ lldb_type != NULL &&
+ clang_type.IsIntegerType (is_signed) &&
+ uval64_valid)
+ {
+ llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed);
+ template_param_infos.args.push_back (clang::TemplateArgument (*ast,
+ llvm::APSInt(apint),
+ clang_type.GetQualType()));
+ }
+ else
+ {
+ template_param_infos.args.push_back (clang::TemplateArgument (clang_type.GetQualType()));
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+ }
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+SymbolFileDWARF::ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+
+ if (parent_die == NULL)
+ return false;
+
+ Args template_parameter_names;
+ for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild();
+ die != NULL;
+ die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ ParseTemplateDIE (dwarf_cu, die, template_param_infos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (template_param_infos.args.empty())
+ return false;
+ return template_param_infos.args.size() == template_param_infos.names.size();
+}
+
+clang::ClassTemplateDecl *
+SymbolFileDWARF::ParseClassTemplateDecl (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *parent_name,
+ int tag_decl_kind,
+ const ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ if (template_param_infos.IsValid())
+ {
+ std::string template_basename(parent_name);
+ template_basename.erase (template_basename.find('<'));
+ ClangASTContext &ast = GetClangASTContext();
+
+ return ast.CreateClassTemplateDecl (decl_ctx,
+ access_type,
+ template_basename.c_str(),
+ tag_decl_kind,
+ template_param_infos);
+ }
+ return NULL;
+}
+
+class SymbolFileDWARF::DelayedAddObjCClassProperty
+{
+public:
+ DelayedAddObjCClassProperty
+ (
+ const ClangASTType &class_opaque_type,
+ const char *property_name,
+ const ClangASTType &property_opaque_type, // The property type is only required if you don't have an ivar decl
+ clang::ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name,
+ const char *property_getter_name,
+ uint32_t property_attributes,
+ const ClangASTMetadata *metadata
+ ) :
+ m_class_opaque_type (class_opaque_type),
+ m_property_name (property_name),
+ m_property_opaque_type (property_opaque_type),
+ m_ivar_decl (ivar_decl),
+ m_property_setter_name (property_setter_name),
+ m_property_getter_name (property_getter_name),
+ m_property_attributes (property_attributes)
+ {
+ if (metadata != NULL)
+ {
+ m_metadata_ap.reset(new ClangASTMetadata());
+ *m_metadata_ap = *metadata;
+ }
+ }
+
+ DelayedAddObjCClassProperty (const DelayedAddObjCClassProperty &rhs)
+ {
+ *this = rhs;
+ }
+
+ DelayedAddObjCClassProperty& operator= (const DelayedAddObjCClassProperty &rhs)
+ {
+ m_class_opaque_type = rhs.m_class_opaque_type;
+ m_property_name = rhs.m_property_name;
+ m_property_opaque_type = rhs.m_property_opaque_type;
+ m_ivar_decl = rhs.m_ivar_decl;
+ m_property_setter_name = rhs.m_property_setter_name;
+ m_property_getter_name = rhs.m_property_getter_name;
+ m_property_attributes = rhs.m_property_attributes;
+
+ if (rhs.m_metadata_ap.get())
+ {
+ m_metadata_ap.reset (new ClangASTMetadata());
+ *m_metadata_ap = *rhs.m_metadata_ap;
+ }
+ return *this;
+ }
+
+ bool
+ Finalize()
+ {
+ return m_class_opaque_type.AddObjCClassProperty (m_property_name,
+ m_property_opaque_type,
+ m_ivar_decl,
+ m_property_setter_name,
+ m_property_getter_name,
+ m_property_attributes,
+ m_metadata_ap.get());
+ }
+private:
+ ClangASTType m_class_opaque_type;
+ const char *m_property_name;
+ ClangASTType m_property_opaque_type;
+ clang::ObjCIvarDecl *m_ivar_decl;
+ const char *m_property_setter_name;
+ const char *m_property_getter_name;
+ uint32_t m_property_attributes;
+ std::unique_ptr<ClangASTMetadata> m_metadata_ap;
+};
+
+struct BitfieldInfo
+{
+ uint64_t bit_size;
+ uint64_t bit_offset;
+
+ BitfieldInfo () :
+ bit_size (LLDB_INVALID_ADDRESS),
+ bit_offset (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ bool IsValid ()
+ {
+ return (bit_size != LLDB_INVALID_ADDRESS) &&
+ (bit_offset != LLDB_INVALID_ADDRESS);
+ }
+};
+
+
+bool
+SymbolFileDWARF::ClassOrStructIsVirtual (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die)
+{
+ if (parent_die)
+ {
+ for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+ bool check_virtuality = false;
+ switch (tag)
+ {
+ case DW_TAG_inheritance:
+ case DW_TAG_subprogram:
+ check_virtuality = true;
+ break;
+ default:
+ break;
+ }
+ if (check_virtuality)
+ {
+ if (die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_virtuality, 0) != 0)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseChildMembers
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ ClangASTType &class_clang_type,
+ const LanguageType class_language,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ DWARFDIECollection& member_function_dies,
+ DelayedPropertyList& delayed_properties,
+ AccessType& default_accessibility,
+ bool &is_a_class,
+ LayoutInfo &layout_info
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t count = 0;
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ uint32_t member_idx = 0;
+ BitfieldInfo last_field_info;
+
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_member:
+ case DW_TAG_APPLE_property:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ //DWARFExpression location;
+ const char *name = NULL;
+ const char *prop_name = NULL;
+ const char *prop_getter_name = NULL;
+ const char *prop_setter_name = NULL;
+ uint32_t prop_attributes = 0;
+
+
+ bool is_artificial = false;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ AccessType accessibility = eAccessNone;
+ uint32_t member_byte_offset = UINT32_MAX;
+ size_t byte_size = 0;
+ size_t bit_offset = 0;
+ size_t bit_size = 0;
+ bool is_external = false; // On DW_TAG_members, this means the member is static
+ uint32_t i;
+ for (i=0; i<num_attributes && !is_artificial; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_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_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;
+ case DW_AT_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate(NULL, // ExecutionContext *
+ NULL, // ClangExpressionVariableList *
+ NULL, // ClangExpressionDeclMap *
+ NULL, // RegisterContext *
+ debug_info_data,
+ block_offset,
+ block_length,
+ eRegisterKindDWARF,
+ &initialValue,
+ memberOffset,
+ NULL))
+ {
+ member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
+ }
+ }
+ else
+ {
+ // With DWARF 3 and later, if the value is an integer constant,
+ // this form value is the offset in bytes from the beginning
+ // of the containing entity.
+ member_byte_offset = form_value.Unsigned();
+ }
+ break;
+
+ case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType (form_value.Unsigned()); break;
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_APPLE_property_name: prop_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_getter: prop_getter_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_setter: prop_setter_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_attribute: prop_attributes = form_value.Unsigned(); break;
+ case DW_AT_external: is_external = form_value.Boolean(); break;
+
+ default:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_mutable:
+ case DW_AT_visibility:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ if (prop_name)
+ {
+ ConstString fixed_getter;
+ ConstString fixed_setter;
+
+ // Check if the property getter/setter were provided as full
+ // names. We want basenames, so we extract them.
+
+ if (prop_getter_name && prop_getter_name[0] == '-')
+ {
+ ObjCLanguageRuntime::MethodName prop_getter_method(prop_getter_name, true);
+ prop_getter_name = prop_getter_method.GetSelector().GetCString();
+ }
+
+ if (prop_setter_name && prop_setter_name[0] == '-')
+ {
+ ObjCLanguageRuntime::MethodName prop_setter_method(prop_setter_name, true);
+ prop_setter_name = prop_setter_method.GetSelector().GetCString();
+ }
+
+ // If the names haven't been provided, they need to be
+ // filled in.
+
+ if (!prop_getter_name)
+ {
+ prop_getter_name = prop_name;
+ }
+ if (!prop_setter_name && prop_name[0] && !(prop_attributes & DW_APPLE_PROPERTY_readonly))
+ {
+ StreamString ss;
+
+ ss.Printf("set%c%s:",
+ toupper(prop_name[0]),
+ &prop_name[1]);
+
+ fixed_setter.SetCString(ss.GetData());
+ prop_setter_name = fixed_setter.GetCString();
+ }
+ }
+
+ // Clang has a DWARF generation bug where sometimes it
+ // represents fields that are references with bad byte size
+ // and bit size/offset information such as:
+ //
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_bit_size( 0x40 )
+ // DW_AT_bit_offset( 0xffffffffffffffc0 )
+ //
+ // So check the bit offset to make sure it is sane, and if
+ // the values are not sane, remove them. If we don't do this
+ // then we will end up with a crash if we try to use this
+ // type in an expression when clang becomes unhappy with its
+ // recycled debug info.
+
+ if (bit_offset > 128)
+ {
+ bit_size = 0;
+ bit_offset = 0;
+ }
+
+ // FIXME: Make Clang ignore Objective-C accessibility for expressions
+ if (class_language == eLanguageTypeObjC ||
+ class_language == eLanguageTypeObjC_plus_plus)
+ accessibility = eAccessNone;
+
+ if (member_idx == 0 && !is_artificial && name && (strstr (name, "_vptr$") == name))
+ {
+ // Not all compilers will mark the vtable pointer
+ // member as artificial (llvm-gcc). We can't have
+ // the virtual members in our classes otherwise it
+ // throws off all child offsets since we end up
+ // having and extra pointer sized member in our
+ // class layouts.
+ is_artificial = true;
+ }
+
+ // Handle static members
+ if (is_external && member_byte_offset == UINT32_MAX)
+ {
+ Type *var_type = ResolveTypeUID(encoding_uid);
+
+ if (var_type)
+ {
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+ class_clang_type.AddVariableToRecordType (name,
+ var_type->GetClangLayoutType(),
+ accessibility);
+ }
+ break;
+ }
+
+ if (is_artificial == false)
+ {
+ Type *member_type = ResolveTypeUID(encoding_uid);
+
+ clang::FieldDecl *field_decl = NULL;
+ if (tag == DW_TAG_member)
+ {
+ if (member_type)
+ {
+ if (accessibility == eAccessNone)
+ accessibility = default_accessibility;
+ member_accessibilities.push_back(accessibility);
+
+ BitfieldInfo this_field_info;
+
+ this_field_info.bit_size = bit_size;
+
+ if (member_byte_offset != UINT32_MAX || bit_size != 0)
+ {
+ /////////////////////////////////////////////////////////////
+ // How to locate a field given the DWARF debug information
+ //
+ // AT_byte_size indicates the size of the word in which the
+ // bit offset must be interpreted.
+ //
+ // AT_data_member_location indicates the byte offset of the
+ // word from the base address of the structure.
+ //
+ // AT_bit_offset indicates how many bits into the word
+ // (according to the host endianness) the low-order bit of
+ // the field starts. AT_bit_offset can be negative.
+ //
+ // AT_bit_size indicates the size of the field in bits.
+ /////////////////////////////////////////////////////////////
+
+ this_field_info.bit_offset = 0;
+
+ this_field_info.bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
+
+ if (GetObjectFile()->GetByteOrder() == eByteOrderLittle)
+ {
+ this_field_info.bit_offset += byte_size * 8;
+ this_field_info.bit_offset -= (bit_offset + bit_size);
+ }
+ else
+ {
+ this_field_info.bit_offset += bit_offset;
+ }
+ }
+
+ // If the member to be emitted did not start on a character boundary and there is
+ // empty space between the last field and this one, then we need to emit an
+ // anonymous member filling up the space up to its start. There are three cases
+ // here:
+ //
+ // 1 If the previous member ended on a character boundary, then we can emit an
+ // anonymous member starting at the most recent character boundary.
+ //
+ // 2 If the previous member did not end on a character boundary and the distance
+ // from the end of the previous member to the current member is less than a
+ // word width, then we can emit an anonymous member starting right after the
+ // previous member and right before this member.
+ //
+ // 3 If the previous member did not end on a character boundary and the distance
+ // from the end of the previous member to the current member is greater than
+ // or equal a word width, then we act as in Case 1.
+
+ const uint64_t character_width = 8;
+ const uint64_t word_width = 32;
+
+ if (this_field_info.IsValid())
+ {
+ // Objective-C has invalid DW_AT_bit_offset values in older versions
+ // of clang, so we have to be careful and only insert unnammed bitfields
+ // if we have a new enough clang.
+ bool detect_unnamed_bitfields = true;
+
+ if (class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus)
+ detect_unnamed_bitfields = dwarf_cu->Supports_unnamed_objc_bitfields ();
+
+ if (detect_unnamed_bitfields)
+ {
+ BitfieldInfo anon_field_info;
+
+ if ((this_field_info.bit_offset % character_width) != 0) // not char aligned
+ {
+ uint64_t last_field_end = 0;
+
+ if (last_field_info.IsValid())
+ last_field_end = last_field_info.bit_offset + last_field_info.bit_size;
+
+ if (this_field_info.bit_offset != last_field_end)
+ {
+ if (((last_field_end % character_width) == 0) || // case 1
+ (this_field_info.bit_offset - last_field_end >= word_width)) // case 3
+ {
+ anon_field_info.bit_size = this_field_info.bit_offset % character_width;
+ anon_field_info.bit_offset = this_field_info.bit_offset - anon_field_info.bit_size;
+ }
+ else // case 2
+ {
+ anon_field_info.bit_size = this_field_info.bit_offset - last_field_end;
+ anon_field_info.bit_offset = last_field_end;
+ }
+ }
+ }
+
+ if (anon_field_info.IsValid())
+ {
+ clang::FieldDecl *unnamed_bitfield_decl = class_clang_type.AddFieldToRecordType (NULL,
+ GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width),
+ accessibility,
+ anon_field_info.bit_size);
+
+ layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset));
+ }
+ }
+ }
+
+ ClangASTType member_clang_type = member_type->GetClangLayoutType();
+
+ {
+ // Older versions of clang emit array[0] and array[1] in the same way (<rdar://problem/12566646>).
+ // If the current field is at the end of the structure, then there is definitely no room for extra
+ // elements and we override the type to array[0].
+
+ ClangASTType member_array_element_type;
+ uint64_t member_array_size;
+ bool member_array_is_incomplete;
+
+ if (member_clang_type.IsArrayType(&member_array_element_type,
+ &member_array_size,
+ &member_array_is_incomplete) &&
+ !member_array_is_incomplete)
+ {
+ uint64_t parent_byte_size = parent_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, UINT64_MAX);
+
+ if (member_byte_offset >= parent_byte_size)
+ {
+ if (member_array_size != 1)
+ {
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64,
+ MakeUserID(die->GetOffset()),
+ name,
+ encoding_uid,
+ MakeUserID(parent_die->GetOffset()));
+ }
+
+ member_clang_type = GetClangASTContext().CreateArrayType(member_array_element_type, 0, false);
+ }
+ }
+ }
+
+ field_decl = class_clang_type.AddFieldToRecordType (name,
+ member_clang_type,
+ accessibility,
+ bit_size);
+
+ GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset()));
+
+ if (this_field_info.IsValid())
+ {
+ layout_info.field_offsets.insert(std::make_pair(field_decl, this_field_info.bit_offset));
+ last_field_info = this_field_info;
+ }
+ }
+ else
+ {
+ if (name)
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which was unable to be parsed",
+ MakeUserID(die->GetOffset()),
+ name,
+ encoding_uid);
+ else
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8" PRIx64 " which was unable to be parsed",
+ MakeUserID(die->GetOffset()),
+ encoding_uid);
+ }
+ }
+
+ if (prop_name != NULL)
+ {
+ clang::ObjCIvarDecl *ivar_decl = NULL;
+
+ if (field_decl)
+ {
+ ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl);
+ assert (ivar_decl != NULL);
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID (MakeUserID(die->GetOffset()));
+ delayed_properties.push_back(DelayedAddObjCClassProperty(class_clang_type,
+ prop_name,
+ member_type->GetClangLayoutType(),
+ ivar_decl,
+ prop_setter_name,
+ prop_getter_name,
+ prop_attributes,
+ &metadata));
+
+ if (ivar_decl)
+ GetClangASTContext().SetMetadataAsUserID (ivar_decl, MakeUserID(die->GetOffset()));
+ }
+ }
+ }
+ ++member_idx;
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ // Let the type parsing code handle this one for us.
+ member_function_dies.Append (die);
+ break;
+
+ case DW_TAG_inheritance:
+ {
+ is_a_class = true;
+ if (default_accessibility == eAccessNone)
+ default_accessibility = eAccessPrivate;
+ // TODO: implement DW_TAG_inheritance type parsing
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ AccessType accessibility = default_accessibility;
+ bool is_virtual = false;
+ bool is_base_of_class = true;
+ off_t member_byte_offset = 0;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate (NULL,
+ NULL,
+ NULL,
+ NULL,
+ debug_info_data,
+ block_offset,
+ block_length,
+ eRegisterKindDWARF,
+ &initialValue,
+ memberOffset,
+ NULL))
+ {
+ member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
+ }
+ }
+ else
+ {
+ // With DWARF 3 and later, if the value is an integer constant,
+ // this form value is the offset in bytes from the beginning
+ // of the containing entity.
+ member_byte_offset = form_value.Unsigned();
+ }
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
+ break;
+
+ case DW_AT_virtuality:
+ is_virtual = form_value.Boolean();
+ break;
+
+ case DW_AT_sibling:
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ Type *base_class_type = ResolveTypeUID(encoding_uid);
+ assert(base_class_type);
+
+ ClangASTType base_class_clang_type = base_class_type->GetClangFullType();
+ assert (base_class_clang_type);
+ if (class_language == eLanguageTypeObjC)
+ {
+ class_clang_type.SetObjCSuperClass(base_class_clang_type);
+ }
+ else
+ {
+ base_classes.push_back (base_class_clang_type.CreateBaseClassSpecifier (accessibility,
+ is_virtual,
+ is_base_of_class));
+
+ if (is_virtual)
+ {
+ layout_info.vbase_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
+ }
+ else
+ {
+ layout_info.base_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return count;
+}
+
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info && UserIDMatches(type_uid))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die)
+ return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL);
+ }
+ return NULL;
+}
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid)
+{
+ if (UserIDMatches(type_uid))
+ return GetClangDeclContextForDIEOffset (sc, type_uid);
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID (lldb::user_id_t type_uid)
+{
+ if (UserIDMatches(type_uid))
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ const bool assert_not_being_parsed = true;
+ return ResolveTypeUID (cu_sp.get(), type_die, assert_not_being_parsed);
+ }
+ }
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed)
+{
+ if (die != NULL)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, cu));
+
+ // We might be coming in in the middle of a type tree (a class
+ // withing a class, an enum within a class), so parse any needed
+ // parent DIEs before we get to this one...
+ const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die);
+ switch (decl_ctx_die->Tag())
+ {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ // Get the type, which could be a forward declaration
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent forward type for 0x%8.8x",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, cu),
+ decl_ctx_die->GetOffset());
+//
+// Type *parent_type = ResolveTypeUID (cu, decl_ctx_die, assert_not_being_parsed);
+// if (child_requires_parent_class_union_or_struct_to_be_completed(die->Tag()))
+// {
+// if (log)
+// GetObjectFile()->GetModule()->LogMessage (log,
+// "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent full type for 0x%8.8x since die is a function",
+// die->GetOffset(),
+// DW_TAG_value_to_name(die->Tag()),
+// die->GetName(this, cu),
+// decl_ctx_die->GetOffset());
+// // Ask the type to complete itself if it already hasn't since if we
+// // want a function (method or static) from a class, the class must
+// // create itself and add it's own methods and class functions.
+// if (parent_type)
+// parent_type->GetClangFullType();
+// }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return ResolveType (cu, die);
+ }
+ return NULL;
+}
+
+// This function is used when SymbolFileDWARFDebugMap owns a bunch of
+// SymbolFileDWARF objects to detect if this DWARF file is the one that
+// can resolve a clang_type.
+bool
+SymbolFileDWARF::HasForwardDeclForClangType (const ClangASTType &clang_type)
+{
+ ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers();
+ const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType());
+ return die != NULL;
+}
+
+
+bool
+SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
+{
+ // We have a struct/union/class/enum that needs to be fully resolved.
+ ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers();
+ const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType());
+ if (die == NULL)
+ {
+ // We have already resolved this type...
+ return true;
+ }
+ // Once we start resolving this type, remove it from the forward declaration
+ // map in case anyone child members or other types require this type to get resolved.
+ // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition
+ // are done.
+ m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType());
+
+
+ // Disable external storage for this type so we don't get anymore
+ // clang::ExternalASTSource queries for this type.
+ clang_type.SetHasExternalStorage (false);
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+
+ DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIE (die->GetOffset()).get();
+ Type *type = m_die_to_type.lookup (die);
+
+ const dw_tag_t tag = die->Tag();
+
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION));
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log,
+ "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...",
+ MakeUserID(die->GetOffset()),
+ DW_TAG_value_to_name(tag),
+ type->GetName().AsCString());
+
+ }
+ assert (clang_type);
+ DWARFDebugInfoEntry::Attributes attributes;
+
+ switch (tag)
+ {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ LayoutInfo layout_info;
+
+ {
+ if (die->HasChildren())
+ {
+
+ LanguageType class_language = eLanguageTypeUnknown;
+ if (clang_type.IsObjCObjectOrInterfaceType())
+ {
+ class_language = eLanguageTypeObjC;
+ // For objective C we don't start the definition when
+ // the class is created.
+ clang_type.StartTagDeclarationDefinition ();
+ }
+
+ int tag_decl_kind = -1;
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = eAccessPrivate;
+ }
+
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ std::vector<clang::CXXBaseSpecifier *> base_classes;
+ std::vector<int> member_accessibilities;
+ bool is_a_class = false;
+ // Parse members and base classes first
+ DWARFDIECollection member_function_dies;
+
+ DelayedPropertyList delayed_properties;
+ ParseChildMembers (sc,
+ dwarf_cu,
+ die,
+ clang_type,
+ class_language,
+ base_classes,
+ member_accessibilities,
+ member_function_dies,
+ delayed_properties,
+ default_accessibility,
+ is_a_class,
+ layout_info);
+
+ // Now parse any methods if there were any...
+ size_t num_functions = member_function_dies.Size();
+ if (num_functions > 0)
+ {
+ for (size_t i=0; i<num_functions; ++i)
+ {
+ ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i));
+ }
+ }
+
+ if (class_language == eLanguageTypeObjC)
+ {
+ std::string class_str (clang_type.GetTypeName());
+ if (!class_str.empty())
+ {
+
+ DIEArray method_die_offsets;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_objc_ap.get())
+ m_apple_objc_ap->FindByName(class_str.c_str(), method_die_offsets);
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ ConstString class_name (class_str.c_str());
+ m_objc_class_selectors_index.Find (class_name, method_die_offsets);
+ }
+
+ if (!method_die_offsets.empty())
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+
+ DWARFCompileUnit* method_cu = NULL;
+ const size_t num_matches = method_die_offsets.size();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = method_die_offsets[i];
+ DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu);
+
+ if (method_die)
+ ResolveType (method_cu, method_die);
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_objc accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, class_str.c_str());
+ }
+ }
+ }
+ }
+
+ for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end();
+ pi != pe;
+ ++pi)
+ pi->Finalize();
+ }
+ }
+
+ // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we
+ // need to tell the clang type it is actually a class.
+ if (class_language != eLanguageTypeObjC)
+ {
+ if (is_a_class && tag_decl_kind != clang::TTK_Class)
+ clang_type.SetTagTypeKind (clang::TTK_Class);
+ }
+
+ // Since DW_TAG_structure_type gets used for both classes
+ // and structures, we may need to set any DW_TAG_member
+ // fields to have a "private" access if none was specified.
+ // When we parsed the child members we tracked that actual
+ // accessibility value for each DW_TAG_member in the
+ // "member_accessibilities" array. If the value for the
+ // member is zero, then it was set to the "default_accessibility"
+ // which for structs was "public". Below we correct this
+ // by setting any fields to "private" that weren't correctly
+ // set.
+ if (is_a_class && !member_accessibilities.empty())
+ {
+ // This is a class and all members that didn't have
+ // their access specified are private.
+ clang_type.SetDefaultAccessForRecordFields (eAccessPrivate,
+ &member_accessibilities.front(),
+ member_accessibilities.size());
+ }
+
+ if (!base_classes.empty())
+ {
+ clang_type.SetBaseClassesForClassType (&base_classes.front(),
+ base_classes.size());
+
+ // Clang will copy each CXXBaseSpecifier in "base_classes"
+ // so we have to free them all.
+ ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(),
+ base_classes.size());
+ }
+ }
+ }
+
+ clang_type.BuildIndirectFields ();
+ clang_type.CompleteTagDeclarationDefinition ();
+
+ if (!layout_info.field_offsets.empty() ||
+ !layout_info.base_offsets.empty() ||
+ !layout_info.vbase_offsets.empty() )
+ {
+ if (type)
+ layout_info.bit_size = type->GetByteSize() * 8;
+ if (layout_info.bit_size == 0)
+ layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8;
+
+ clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl();
+ if (record_decl)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])",
+ clang_type.GetOpaqueQualType(),
+ record_decl,
+ layout_info.bit_size,
+ layout_info.alignment,
+ (uint32_t)layout_info.field_offsets.size(),
+ (uint32_t)layout_info.base_offsets.size(),
+ (uint32_t)layout_info.vbase_offsets.size());
+
+ uint32_t idx;
+ {
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end();
+ for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)pos->second,
+ pos->first->getNameAsString().c_str());
+ }
+ }
+
+ {
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end();
+ for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] = { byte_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)base_pos->second.getQuantity(),
+ base_pos->first->getNameAsString().c_str());
+ }
+ }
+ {
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos, vbase_end = layout_info.vbase_offsets.end();
+ for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end; ++vbase_pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)vbase_pos->second.getQuantity(),
+ vbase_pos->first->getNameAsString().c_str());
+ }
+ }
+ }
+ m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
+ }
+ }
+ }
+
+ return clang_type;
+
+ case DW_TAG_enumeration_type:
+ clang_type.StartTagDeclarationDefinition ();
+ if (die->HasChildren())
+ {
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ bool is_signed = false;
+ clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), dwarf_cu, die);
+ }
+ clang_type.CompleteTagDeclarationDefinition ();
+ return clang_type;
+
+ default:
+ assert(false && "not a forward clang type decl!");
+ break;
+ }
+ return false;
+}
+
+Type*
+SymbolFileDWARF::ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed)
+{
+ if (type_die != NULL)
+ {
+ Type *type = m_die_to_type.lookup (type_die);
+
+ if (type == NULL)
+ type = GetTypeForDIE (dwarf_cu, type_die).get();
+
+ if (assert_not_being_parsed)
+ {
+ if (type != DIE_IS_BEING_PARSED)
+ return type;
+
+ GetObjectFile()->GetModule()->ReportError ("Parsing a die that is being parsed die: 0x%8.8x: %s %s",
+ type_die->GetOffset(),
+ DW_TAG_value_to_name(type_die->Tag()),
+ type_die->GetName(this, dwarf_cu));
+
+ }
+ else
+ return type;
+ }
+ return NULL;
+}
+
+CompileUnit*
+SymbolFileDWARF::GetCompUnitForDWARFCompUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
+{
+ // Check if the symbol vendor already knows about this compile unit?
+ if (dwarf_cu->GetUserData() == NULL)
+ {
+ // The symbol vendor doesn't know about this compile unit, we
+ // need to parse and add it to the symbol vendor object.
+ return ParseCompileUnit(dwarf_cu, cu_idx).get();
+ }
+ return (CompileUnit*)dwarf_cu->GetUserData();
+}
+
+bool
+SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc)
+{
+ sc.Clear(false);
+ // Check if the symbol vendor already knows about this compile unit?
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(func_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, func_die);
+
+ if (sc.function)
+ {
+ sc.module_sp = sc.function->CalculateSymbolContextModule();
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)",
+ so_addr.GetSection().get(),
+ so_addr.GetOffset(),
+ resolve_scope);
+ uint32_t resolved = 0;
+ if (resolve_scope & ( eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextBlock |
+ eSymbolContextLineEntry))
+ {
+ lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr);
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get();
+ if (dwarf_cu)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ if (sc.comp_unit)
+ {
+ resolved |= eSymbolContextCompUnit;
+
+ bool force_check_line_table = false;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, &block_die);
+ }
+ else
+ {
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, NULL);
+ }
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die);
+ }
+ else
+ {
+ // We might have had a compile unit that had discontiguous
+ // address ranges where the gaps are symbols that don't have
+ // any debug info. Discontiguous compile unit address ranges
+ // should only happen when there aren't other functions from
+ // other compile units in these gaps. This helps keep the size
+ // of the aranges down.
+ force_check_line_table = true;
+ }
+
+ if (sc.function != NULL)
+ {
+ resolved |= eSymbolContextFunction;
+
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ Block& block = sc.function->GetBlock (true);
+
+ if (block_die != NULL)
+ sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset()));
+ else
+ sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset()));
+ if (sc.block)
+ resolved |= eSymbolContextBlock;
+ }
+ }
+ }
+
+ if ((resolve_scope & eSymbolContextLineEntry) || force_check_line_table)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table != NULL)
+ {
+ // And address that makes it into this function should be in terms
+ // of this debug file if there is no debug map, or it will be an
+ // address in the .o file which needs to be fixed up to be in terms
+ // of the debug map executable. Either way, calling FixupAddress()
+ // will work for us.
+ Address exe_so_addr (so_addr);
+ if (FixupAddress(exe_so_addr))
+ {
+ if (line_table->FindLineEntryByAddress (exe_so_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ }
+ }
+
+ if (force_check_line_table && !(resolved & eSymbolContextLineEntry))
+ {
+ // We might have had a compile unit that had discontiguous
+ // address ranges where the gaps are symbols that don't have
+ // any debug info. Discontiguous compile unit address ranges
+ // should only happen when there aren't other functions from
+ // other compile units in these gaps. This helps keep the size
+ // of the aranges down.
+ sc.comp_unit = NULL;
+ resolved &= ~eSymbolContextCompUnit;
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8x: compile unit %u failed to create a valid lldb_private::CompileUnit class.",
+ cu_offset,
+ cu_idx);
+ }
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
+
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx;
+ DWARFCompileUnit* dwarf_cu = NULL;
+
+ for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx)
+ {
+ CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ const bool full_match = file_spec.GetDirectory();
+ bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Equal(file_spec, *dc_cu, full_match);
+ if (check_inlines || file_spec_matches_cu_file_spec)
+ {
+ SymbolContext sc (m_obj_file->GetModule());
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ if (sc.comp_unit)
+ {
+ uint32_t file_idx = UINT32_MAX;
+
+ // If we are looking for inline functions only and we don't
+ // find it in the support files, we are done.
+ if (check_inlines)
+ {
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true);
+ if (file_idx == UINT32_MAX)
+ continue;
+ }
+
+ if (line != 0)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != NULL && line != 0)
+ {
+ // We will have already looked up the file index if
+ // we are searching for inline entries.
+ if (!check_inlines)
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true);
+
+ if (file_idx != UINT32_MAX)
+ {
+ uint32_t found_line;
+ uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, false, &sc.line_entry);
+ found_line = sc.line_entry.line;
+
+ while (line_idx != UINT32_MAX)
+ {
+ sc.function = NULL;
+ sc.block = NULL;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ if (file_vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL);
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ Block& block = sc.function->GetBlock (true);
+
+ if (block_die != NULL)
+ sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset()));
+ else
+ sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset()));
+ }
+ }
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry);
+ }
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+
+ if (!check_inlines)
+ break;
+ }
+ }
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+void
+SymbolFileDWARF::Index ()
+{
+ if (m_indexed)
+ return;
+ m_indexed = true;
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::Index (%s)",
+ GetObjectFile()->GetFileSpec().GetFilename().AsCString());
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ bool clear_dies = dwarf_cu->ExtractDIEsIfNeeded (false) > 1;
+
+ dwarf_cu->Index (cu_idx,
+ m_function_basename_index,
+ m_function_fullname_index,
+ m_function_method_index,
+ m_function_selector_index,
+ m_objc_class_selectors_index,
+ m_global_index,
+ m_type_index,
+ m_namespace_index);
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ dwarf_cu->ClearDIEs (true);
+ }
+
+ m_function_basename_index.Finalize();
+ m_function_fullname_index.Finalize();
+ m_function_method_index.Finalize();
+ m_function_selector_index.Finalize();
+ m_objc_class_selectors_index.Finalize();
+ m_global_index.Finalize();
+ m_type_index.Finalize();
+ m_namespace_index.Finalize();
+
+#if defined (ENABLE_DEBUG_PRINTF)
+ StreamFile s(stdout, false);
+ s.Printf ("DWARF index for '%s':",
+ GetObjectFile()->GetFileSpec().GetPath().c_str());
+ s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s);
+ s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s);
+ s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s);
+ s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s);
+ s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s);
+ s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s);
+ s.Printf("\nTypes:\n"); m_type_index.Dump (&s);
+ s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s);
+#endif
+ }
+}
+
+bool
+SymbolFileDWARF::NamespaceDeclMatchesThisSymbolFile (const ClangNamespaceDecl *namespace_decl)
+{
+ if (namespace_decl == NULL)
+ {
+ // Invalid namespace decl which means we aren't matching only things
+ // in this symbol file, so return true to indicate it matches this
+ // symbol file.
+ return true;
+ }
+
+ clang::ASTContext *namespace_ast = namespace_decl->GetASTContext();
+
+ if (namespace_ast == NULL)
+ return true; // No AST in the "namespace_decl", return true since it
+ // could then match any symbol file, including this one
+
+ if (namespace_ast == GetClangASTContext().getASTContext())
+ return true; // The ASTs match, return true
+
+ // The namespace AST was valid, and it does not match...
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Valid namespace does not match symbol file");
+
+ return false;
+}
+
+bool
+SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* die)
+{
+ // No namespace specified, so the answesr i
+ if (namespace_decl == NULL)
+ return true;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ const DWARFDebugInfoEntry *decl_ctx_die = NULL;
+ clang::DeclContext *die_clang_decl_ctx = GetClangDeclContextContainingDIE (cu, die, &decl_ctx_die);
+ if (decl_ctx_die)
+ {
+ clang::NamespaceDecl *clang_namespace_decl = namespace_decl->GetNamespaceDecl();
+
+ if (clang_namespace_decl)
+ {
+ if (decl_ctx_die->Tag() != DW_TAG_namespace)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent is not a namespace");
+ return false;
+ }
+
+ if (clang_namespace_decl == die_clang_decl_ctx)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ // We have a namespace_decl that was not NULL but it contained
+ // a NULL "clang::NamespaceDecl", so this means the global namespace
+ // So as long the the contained decl context DIE isn't a namespace
+ // we should be ok.
+ if (decl_ctx_die->Tag() != DW_TAG_namespace)
+ return true;
+ }
+ }
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent doesn't exist");
+
+ return false;
+}
+uint32_t
+SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)",
+ name.GetCString(),
+ namespace_decl,
+ append,
+ max_matches);
+ }
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ const char *base_name_start;
+ const char *base_name_end = NULL;
+
+ if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end))
+ base_name_start = name_cstr;
+
+ m_apple_names_ap->FindByName (base_name_start, die_offsets);
+ }
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.Find (name, die_offsets);
+ }
+
+ const size_t num_die_matches = die_offsets.size();
+ if (num_die_matches)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule();
+ assert (sc.module_sp);
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ bool done = false;
+ for (size_t i=0; i<num_die_matches && !done; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ switch (die->Tag())
+ {
+ default:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_try_block:
+ case DW_TAG_catch_block:
+ break;
+
+ case DW_TAG_variable:
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ done = true;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, name.GetCString());
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = variables.GetSize() - original_size;
+ if (log && num_matches > 0)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u",
+ name.GetCString(),
+ namespace_decl,
+ append,
+ max_matches,
+ num_matches);
+ }
+ return num_matches;
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)",
+ regex.GetText(),
+ append,
+ max_matches);
+ }
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex (regex, hash_data_array))
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ }
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.Find (regex, die_offsets);
+ }
+
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule();
+ assert (sc.module_sp);
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ const size_t num_matches = die_offsets.size();
+ 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];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for regex '%s')\n",
+ die_offset, regex.GetText());
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+bool
+SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset,
+ DWARFCompileUnit *&dwarf_cu,
+ SymbolContextList& sc_list)
+{
+ const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ return ResolveFunction (dwarf_cu, die, sc_list);
+}
+
+
+bool
+SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ SymbolContextList& sc_list)
+{
+ SymbolContext sc;
+
+ if (die == NULL)
+ return false;
+
+ // If we were passed a die that is not a function, just return false...
+ if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine)
+ return false;
+
+ const DWARFDebugInfoEntry* inlined_die = NULL;
+ if (die->Tag() == DW_TAG_inlined_subroutine)
+ {
+ inlined_die = die;
+
+ while ((die = die->GetParent()) != NULL)
+ {
+ if (die->Tag() == DW_TAG_subprogram)
+ break;
+ }
+ }
+ assert (die->Tag() == DW_TAG_subprogram);
+ if (GetFunction (cu, die, sc))
+ {
+ Address addr;
+ // Parse all blocks if needed
+ if (inlined_die)
+ {
+ sc.block = sc.function->GetBlock (true).FindBlockByID (MakeUserID(inlined_die->GetOffset()));
+ assert (sc.block != NULL);
+ if (sc.block->GetStartAddress (addr) == false)
+ addr.Clear();
+ }
+ else
+ {
+ sc.block = NULL;
+ addr = sc.function->GetAddressRange().GetBaseAddress();
+ }
+
+ if (addr.IsValid())
+ {
+ sc_list.Append(sc);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+SymbolFileDWARF::FindFunctions (const ConstString &name,
+ const NameToDIE &name_to_die,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ if (name_to_die.Find (name, die_offsets))
+ {
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+
+void
+SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
+ const NameToDIE &name_to_die,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ if (name_to_die.Find (regex, die_offsets))
+ {
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+
+void
+SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
+ const DWARFMappedHash::MemoryTable &memory_table,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (memory_table.AppendAllDIEsThatMatchingRegex (regex, hash_data_array))
+ {
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+void
+SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets,
+ SymbolContextList& sc_list)
+{
+ const size_t num_matches = die_offsets.size();
+ if (num_matches)
+ {
+ SymbolContext sc;
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ ResolveFunction (die_offset, dwarf_cu, sc_list);
+ }
+ }
+}
+
+bool
+SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die,
+ const DWARFCompileUnit *dwarf_cu,
+ uint32_t name_type_mask,
+ const char *partial_name,
+ const char *base_name_start,
+ const char *base_name_end)
+{
+ // If we are looking only for methods, throw away all the ones that are or aren't in C++ classes:
+ if (name_type_mask == eFunctionNameTypeMethod || name_type_mask == eFunctionNameTypeBase)
+ {
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset());
+ if (!containing_decl_ctx)
+ return false;
+
+ bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind());
+
+ if (name_type_mask == eFunctionNameTypeMethod)
+ {
+ if (is_cxx_method == false)
+ return false;
+ }
+
+ if (name_type_mask == eFunctionNameTypeBase)
+ {
+ if (is_cxx_method == true)
+ return false;
+ }
+ }
+
+ // Now we need to check whether the name we got back for this type matches the extra specifications
+ // that were in the name we're looking up:
+ if (base_name_start != partial_name || *base_name_end != '\0')
+ {
+ // First see if the stuff to the left matches the full name. To do that let's see if
+ // we can pull out the mips linkage name attribute:
+
+ Mangled best_name;
+ DWARFDebugInfoEntry::Attributes attributes;
+ DWARFFormValue form_value;
+ die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ uint32_t idx = attributes.FindAttributeIndex(DW_AT_MIPS_linkage_name);
+ if (idx == UINT32_MAX)
+ idx = attributes.FindAttributeIndex(DW_AT_linkage_name);
+ if (idx != UINT32_MAX)
+ {
+ if (attributes.ExtractFormValueAtIndex(this, idx, form_value))
+ {
+ const char *mangled_name = form_value.AsCString(&get_debug_str_data());
+ if (mangled_name)
+ best_name.SetValue (ConstString(mangled_name), true);
+ }
+ }
+
+ if (!best_name)
+ {
+ idx = attributes.FindAttributeIndex(DW_AT_name);
+ if (idx != UINT32_MAX && attributes.ExtractFormValueAtIndex(this, idx, form_value))
+ {
+ const char *name = form_value.AsCString(&get_debug_str_data());
+ best_name.SetValue (ConstString(name), false);
+ }
+ }
+
+ if (best_name.GetDemangledName())
+ {
+ const char *demangled = best_name.GetDemangledName().GetCString();
+ if (demangled)
+ {
+ std::string name_no_parens(partial_name, base_name_end - partial_name);
+ const char *partial_in_demangled = strstr (demangled, name_no_parens.c_str());
+ if (partial_in_demangled == NULL)
+ return false;
+ else
+ {
+ // Sort out the case where our name is something like "Process::Destroy" and the match is
+ // "SBProcess::Destroy" - that shouldn't be a match. We should really always match on
+ // namespace boundaries...
+
+ if (partial_name[0] == ':' && partial_name[1] == ':')
+ {
+ // The partial name was already on a namespace boundary so all matches are good.
+ return true;
+ }
+ else if (partial_in_demangled == demangled)
+ {
+ // They both start the same, so this is an good match.
+ return true;
+ }
+ else
+ {
+ if (partial_in_demangled - demangled == 1)
+ {
+ // Only one character difference, can't be a namespace boundary...
+ return false;
+ }
+ else if (*(partial_in_demangled - 1) == ':' && *(partial_in_demangled - 2) == ':')
+ {
+ // We are on a namespace boundary, so this is also good.
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+uint32_t
+SymbolFileDWARF::FindFunctions (const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (name = '%s')",
+ name.AsCString());
+
+ // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
+ assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list)",
+ name.GetCString(),
+ name_type_mask,
+ append);
+ }
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ // If name is empty then we won't find anything.
+ if (name.IsEmpty())
+ return 0;
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+
+ const char *name_cstr = name.GetCString();
+
+ const uint32_t original_size = sc_list.GetSize();
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ DWARFCompileUnit *dwarf_cu = NULL;
+ std::set<const DWARFDebugInfoEntry *> resolved_dies;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+
+ DIEArray die_offsets;
+
+ uint32_t num_matches = 0;
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ {
+ // If they asked for the full name, match what they typed. At some point we may
+ // want to canonicalize this (strip double spaces, etc. For now, we just add all the
+ // dies that we find by exact match.
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ }
+
+ if (name_type_mask & eFunctionNameTypeSelector)
+ {
+ if (namespace_decl && *namespace_decl)
+ return 0; // no selectors in namespaces
+
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+ // Now make sure these are actually ObjC methods. In this case we can simply look up the name,
+ // and if it is an ObjC method name, we're good.
+
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ const char *die_name = die->GetName(this, dwarf_cu);
+ if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name))
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase)
+ {
+ // The apple_names table stores just the "base name" of C++ methods in the table. So we have to
+ // extract the base name, look that up, and if there is any other information in the name we were
+ // passed in we have to post-filter based on that.
+
+ // FIXME: Arrange the logic above so that we don't calculate the base name twice:
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ {
+ bool keep_die = true;
+ if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod))
+ {
+ // We are looking for either basenames or methods, so we need to
+ // trim out the ones we won't want by looking at the type
+ SymbolContext sc;
+ if (sc_list.GetLastContext(sc))
+ {
+ if (sc.block)
+ {
+ // We have an inlined function
+ }
+ else if (sc.function)
+ {
+ Type *type = sc.function->GetType();
+
+ clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID());
+ if (decl_ctx->isRecord())
+ {
+ if (name_type_mask & eFunctionNameTypeBase)
+ {
+ sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
+ keep_die = false;
+ }
+ }
+ else
+ {
+ if (name_type_mask & eFunctionNameTypeMethod)
+ {
+ sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
+ keep_die = false;
+ }
+ }
+ }
+ }
+ }
+ if (keep_die)
+ resolved_dies.insert(die);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ die_offsets.clear();
+ }
+ }
+ }
+ else
+ {
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ {
+ FindFunctions (name, m_function_fullname_index, sc_list);
+
+ // Temporary workaround for global/anonymous namespace functions on linux
+#if defined (__linux__)
+ // If we didn't find any functions in the global namespace try
+ // looking in the basename index but ignore any returned
+ // functions that have a namespace (ie. mangled names starting with
+ // '_ZN') but keep functions which have an anonymous namespace
+ if (sc_list.GetSize() == 0)
+ {
+ SymbolContextList temp_sc_list;
+ FindFunctions (name, m_function_basename_index, temp_sc_list);
+ if (!namespace_decl)
+ {
+ SymbolContext sc;
+ for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++)
+ {
+ if (temp_sc_list.GetContextAtIndex(i, sc))
+ {
+ ConstString mangled_name = sc.GetFunctionName(Mangled::ePreferMangled);
+ ConstString demangled_name = sc.GetFunctionName(Mangled::ePreferDemangled);
+ if (strncmp(mangled_name.GetCString(), "_ZN", 3) ||
+ !strncmp(demangled_name.GetCString(), "(anonymous namespace)", 21))
+ {
+ sc_list.Append(sc);
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ DIEArray die_offsets;
+ DWARFCompileUnit *dwarf_cu = NULL;
+
+ if (name_type_mask & eFunctionNameTypeBase)
+ {
+ uint32_t num_base = m_function_basename_index.Find(name, die_offsets);
+ for (uint32_t i = 0; i < num_base; i++)
+ {
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if (name_type_mask & eFunctionNameTypeMethod)
+ {
+ if (namespace_decl && *namespace_decl)
+ return 0; // no methods in namespaces
+
+ uint32_t num_base = m_function_method_index.Find(name, die_offsets);
+ {
+ for (uint32_t i = 0; i < num_base; i++)
+ {
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl))
+ {
+ FindFunctions (name, m_function_selector_index, sc_list);
+ }
+
+ }
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = sc_list.GetSize() - original_size;
+
+ if (log && num_matches > 0)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list) => %u",
+ name.GetCString(),
+ name_type_mask,
+ append,
+ num_matches);
+ }
+ return num_matches;
+}
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (regex=\"%s\", append=%u, sc_list)",
+ regex.GetText(),
+ append);
+ }
+
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = sc_list.GetSize();
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ FindFunctions (regex, *m_apple_names_ap, sc_list);
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ FindFunctions (regex, m_function_basename_index, sc_list);
+
+ FindFunctions (regex, m_function_fullname_index, sc_list);
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARF::FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ TypeList& types)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ if (namespace_decl)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)",
+ name.GetCString(),
+ namespace_decl->GetNamespaceDecl(),
+ namespace_decl->GetQualifiedName().c_str(),
+ append,
+ max_matches);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)",
+ name.GetCString(),
+ append,
+ max_matches);
+ }
+ }
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ m_apple_types_ap->FindByName (name_cstr, die_offsets);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (name, die_offsets);
+ }
+
+ const size_t num_die_matches = die_offsets.size();
+
+ if (num_die_matches)
+ {
+ const uint32_t initial_types_size = types.GetSize();
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_die_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ Type *matching_type = ResolveType (dwarf_cu, die);
+ if (matching_type)
+ {
+ // We found a type pointer, now find the shared pointer form our type list
+ types.InsertUnique (matching_type->shared_from_this());
+ if (types.GetSize() >= max_matches)
+ break;
+ }
+ }
+ 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, name.GetCString());
+ }
+ }
+
+ }
+ const uint32_t num_matches = types.GetSize() - initial_types_size;
+ if (log && num_matches)
+ {
+ if (namespace_decl)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u",
+ name.GetCString(),
+ namespace_decl->GetNamespaceDecl(),
+ namespace_decl->GetQualifiedName().c_str(),
+ append,
+ max_matches,
+ num_matches);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u",
+ name.GetCString(),
+ append,
+ max_matches,
+ num_matches);
+ }
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+
+ClangNamespaceDecl
+SymbolFileDWARF::FindNamespace (const SymbolContext& sc,
+ const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindNamespace (sc, name=\"%s\")",
+ name.GetCString());
+ }
+
+ if (!NamespaceDeclMatchesThisSymbolFile(parent_namespace_decl))
+ return ClangNamespaceDecl();
+
+ ClangNamespaceDecl namespace_decl;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DIEArray die_offsets;
+
+ // Index if we already haven't to make sure the compile units
+ // get indexed and make their global DIE index list
+ if (m_using_apple_tables)
+ {
+ if (m_apple_namespaces_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ m_apple_namespaces_ap->FindByName (name_cstr, die_offsets);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_namespace_index.Find (name, die_offsets);
+ }
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ const size_t num_matches = die_offsets.size();
+ 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];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ if (parent_namespace_decl && !DIEIsInNamespace (parent_namespace_decl, dwarf_cu, die))
+ continue;
+
+ clang::NamespaceDecl *clang_namespace_decl = ResolveNamespaceDIE (dwarf_cu, die);
+ if (clang_namespace_decl)
+ {
+ namespace_decl.SetASTContext (GetClangASTContext().getASTContext());
+ namespace_decl.SetNamespaceDecl (clang_namespace_decl);
+ break;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_namespaces accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, name.GetCString());
+ }
+ }
+
+ }
+ }
+ }
+ if (log && namespace_decl.GetNamespaceDecl())
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"",
+ name.GetCString(),
+ namespace_decl.GetNamespaceDecl(),
+ namespace_decl.GetQualifiedName().c_str());
+ }
+
+ return namespace_decl;
+}
+
+uint32_t
+SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, TypeList& types)
+{
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = types.GetSize();
+
+ const uint32_t num_die_offsets = die_offsets.size();
+ // Parse all of the types we found from the pubtypes matches
+ uint32_t i;
+ uint32_t num_matches = 0;
+ for (i = 0; i < num_die_offsets; ++i)
+ {
+ Type *matching_type = ResolveTypeUID (die_offsets[i]);
+ if (matching_type)
+ {
+ // We found a type pointer, now find the shared pointer form our type list
+ types.InsertUnique (matching_type->shared_from_this());
+ ++num_matches;
+ if (num_matches >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return types.GetSize() - original_size;
+}
+
+
+size_t
+SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
+ clang::DeclContext *containing_decl_ctx,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ bool skip_artificial,
+ bool &is_static,
+ TypeList* type_list,
+ std::vector<ClangASTType>& function_param_types,
+ std::vector<clang::ParmVarDecl*>& function_param_decls,
+ unsigned &type_quals,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ size_t arg_idx = 0;
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_formal_parameter:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ dw_offset_t param_type_die_offset = DW_INVALID_OFFSET;
+ bool is_artificial = false;
+ // one of None, Auto, Register, Extern, Static, PrivateExtern
+
+ clang::StorageClass storage = clang::SC_None;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_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_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_location:
+ // if (form_value.BlockData())
+ // {
+ // const DataExtractor& debug_info_data = debug_info();
+ // uint32_t block_length = form_value.Unsigned();
+ // DataExtractor location(debug_info_data, form_value.BlockData() - debug_info_data.GetDataStart(), block_length);
+ // }
+ // else
+ // {
+ // }
+ // break;
+ case DW_AT_const_value:
+ case DW_AT_default_value:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_is_optional:
+ case DW_AT_segment:
+ case DW_AT_variable_parameter:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ bool skip = false;
+ if (skip_artificial)
+ {
+ if (is_artificial)
+ {
+ // In order to determine if a C++ member function is
+ // "const" we have to look at the const-ness of "this"...
+ // Ugly, but that
+ if (arg_idx == 0)
+ {
+ if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()))
+ {
+ // Often times compilers omit the "this" name for the
+ // specification DIEs, so we can't rely upon the name
+ // being in the formal parameter DIE...
+ if (name == NULL || ::strcmp(name, "this")==0)
+ {
+ Type *this_type = ResolveTypeUID (param_type_die_offset);
+ if (this_type)
+ {
+ uint32_t encoding_mask = this_type->GetEncodingMask();
+ if (encoding_mask & Type::eEncodingIsPointerUID)
+ {
+ is_static = false;
+
+ if (encoding_mask & (1u << Type::eEncodingIsConstUID))
+ type_quals |= clang::Qualifiers::Const;
+ if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
+ type_quals |= clang::Qualifiers::Volatile;
+ }
+ }
+ }
+ }
+ }
+ skip = true;
+ }
+ else
+ {
+
+ // HACK: Objective C formal parameters "self" and "_cmd"
+ // are not marked as artificial in the DWARF...
+ CompileUnit *comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+ if (comp_unit)
+ {
+ switch (comp_unit->GetLanguage())
+ {
+ case eLanguageTypeObjC:
+ case eLanguageTypeObjC_plus_plus:
+ if (name && name[0] && (strcmp (name, "self") == 0 || strcmp (name, "_cmd") == 0))
+ skip = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (!skip)
+ {
+ Type *type = ResolveTypeUID(param_type_die_offset);
+ if (type)
+ {
+ function_param_types.push_back (type->GetClangForwardType());
+
+ clang::ParmVarDecl *param_var_decl = GetClangASTContext().CreateParameterDeclaration (name,
+ type->GetClangForwardType(),
+ storage);
+ assert(param_var_decl);
+ function_param_decls.push_back(param_var_decl);
+
+ GetClangASTContext().SetMetadataAsUserID (param_var_decl, MakeUserID(die->GetOffset()));
+ }
+ }
+ }
+ arg_idx++;
+ }
+ break;
+
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ ParseTemplateDIE (dwarf_cu, die,template_param_infos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return arg_idx;
+}
+
+size_t
+SymbolFileDWARF::ParseChildEnumerators
+(
+ const SymbolContext& sc,
+ lldb_private::ClangASTType &clang_type,
+ bool is_signed,
+ uint32_t enumerator_byte_size,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t enumerators_added = 0;
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ if (tag == DW_TAG_enumerator)
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ int64_t enum_value = 0;
+ Declaration decl;
+
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_const_value:
+ got_value = true;
+ if (is_signed)
+ enum_value = form_value.Signed();
+ else
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_description:
+ default:
+ 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_sibling:
+ break;
+ }
+ }
+ }
+
+ if (name && name[0] && got_value)
+ {
+ clang_type.AddEnumerationValueToEnumerationType (clang_type.GetEnumerationIntegerType(),
+ decl,
+ name,
+ enum_value,
+ enumerator_byte_size * 8);
+ ++enumerators_added;
+ }
+ }
+ }
+ }
+ return enumerators_added;
+}
+
+void
+SymbolFileDWARF::ParseChildArrayInfo
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride
+)
+{
+ if (parent_die == NULL)
+ return;
+
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_subrange_type:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_child_attributes > 0)
+ {
+ uint64_t num_elements = 0;
+ uint64_t lower_bound = 0;
+ uint64_t upper_bound = 0;
+ bool upper_bound_valid = false;
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_name:
+ break;
+
+ case DW_AT_count:
+ num_elements = form_value.Unsigned();
+ break;
+
+ case DW_AT_bit_stride:
+ bit_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_stride:
+ byte_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_lower_bound:
+ lower_bound = form_value.Unsigned();
+ break;
+
+ case DW_AT_upper_bound:
+ upper_bound_valid = true;
+ upper_bound = form_value.Unsigned();
+ break;
+
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_accessibility:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ case DW_AT_threads_scaled:
+ case DW_AT_type:
+ case DW_AT_visibility:
+ break;
+ }
+ }
+ }
+
+ if (num_elements == 0)
+ {
+ if (upper_bound_valid && upper_bound >= lower_bound)
+ num_elements = upper_bound - lower_bound + 1;
+ }
+
+ element_orders.push_back (num_elements);
+ }
+ }
+ break;
+ }
+ }
+}
+
+TypeSP
+SymbolFileDWARF::GetTypeForDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry* die)
+{
+ TypeSP type_sp;
+ if (die != NULL)
+ {
+ assert(dwarf_cu != NULL);
+ Type *type_ptr = m_die_to_type.lookup (die);
+ if (type_ptr == NULL)
+ {
+ CompileUnit* lldb_cu = GetCompUnitForDWARFCompUnit(dwarf_cu);
+ assert (lldb_cu);
+ SymbolContext sc(lldb_cu);
+ type_sp = ParseType(sc, dwarf_cu, die, NULL);
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ // Grab the existing type from the master types lists
+ type_sp = type_ptr->shared_from_this();
+ }
+
+ }
+ return type_sp;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+ return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL);
+ }
+ return NULL;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIEOffset (const SymbolContext &sc, dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(die_offset, &cu_sp);
+ if (die)
+ return GetClangDeclContextForDIE (sc, cu_sp.get(), die);
+ }
+ }
+ return NULL;
+}
+
+clang::NamespaceDecl *
+SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry *die)
+{
+ if (die && die->Tag() == DW_TAG_namespace)
+ {
+ // See if we already parsed this namespace DIE and associated it with a
+ // uniqued namespace declaration
+ clang::NamespaceDecl *namespace_decl = static_cast<clang::NamespaceDecl *>(m_die_to_decl_ctx[die]);
+ if (namespace_decl)
+ return namespace_decl;
+ else
+ {
+ const char *namespace_name = die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL);
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, NULL);
+ namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, containing_decl_ctx);
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ {
+ if (namespace_name)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)",
+ GetClangASTContext().getASTContext(),
+ MakeUserID(die->GetOffset()),
+ namespace_name,
+ namespace_decl,
+ namespace_decl->getOriginalNamespace());
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)",
+ GetClangASTContext().getASTContext(),
+ MakeUserID(die->GetOffset()),
+ namespace_decl,
+ namespace_decl->getOriginalNamespace());
+ }
+ }
+
+ if (namespace_decl)
+ LinkDeclContextToDIE((clang::DeclContext*)namespace_decl, die);
+ return namespace_decl;
+ }
+ }
+ return NULL;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIE (const SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ clang::DeclContext *clang_decl_ctx = GetCachedClangDeclContextForDIE (die);
+ if (clang_decl_ctx)
+ return clang_decl_ctx;
+ // If this DIE has a specification, or an abstract origin, then trace to those.
+
+ dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ return GetClangDeclContextForDIEOffset (sc, die_offset);
+
+ die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ return GetClangDeclContextForDIEOffset (sc, die_offset);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "SymbolFileDWARF::GetClangDeclContextForDIE (die = 0x%8.8x) %s '%s'", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), die->GetName(this, cu));
+ // This is the DIE we want. Parse it, then query our map.
+ bool assert_not_being_parsed = true;
+ ResolveTypeUID (cu, die, assert_not_being_parsed);
+
+ clang_decl_ctx = GetCachedClangDeclContextForDIE (die);
+
+ return clang_decl_ctx;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die, const DWARFDebugInfoEntry **decl_ctx_die_copy)
+{
+ if (m_clang_tu_decl == NULL)
+ m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl();
+
+ const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die);
+
+ if (decl_ctx_die_copy)
+ *decl_ctx_die_copy = decl_ctx_die;
+
+ if (decl_ctx_die)
+ {
+
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find (decl_ctx_die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+
+ switch (decl_ctx_die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ return m_clang_tu_decl;
+
+ case DW_TAG_namespace:
+ return ResolveNamespaceDIE (cu, decl_ctx_die);
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ Type* type = ResolveType (cu, decl_ctx_die);
+ if (type)
+ {
+ clang::DeclContext *decl_ctx = type->GetClangForwardType().GetDeclContextForType ();
+ if (decl_ctx)
+ {
+ LinkDeclContextToDIE (decl_ctx, decl_ctx_die);
+ if (decl_ctx)
+ return decl_ctx;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return m_clang_tu_decl;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ if (cu && die)
+ {
+ const DWARFDebugInfoEntry * const decl_die = die;
+
+ while (die != NULL)
+ {
+ // If this is the original DIE that we are searching for a declaration
+ // for, then don't look in the cache as we don't want our own decl
+ // context to be our decl context...
+ if (decl_die != die)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnit *spec_cu = cu;
+ const DWARFDebugInfoEntry *spec_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &spec_cu);
+ const DWARFDebugInfoEntry *spec_die_decl_ctx_die = GetDeclContextDIEContainingDIE (spec_cu, spec_die);
+ if (spec_die_decl_ctx_die)
+ return spec_die_decl_ctx_die;
+ }
+
+ die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnit *abs_cu = cu;
+ const DWARFDebugInfoEntry *abs_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &abs_cu);
+ const DWARFDebugInfoEntry *abs_die_decl_ctx_die = GetDeclContextDIEContainingDIE (abs_cu, abs_die);
+ if (abs_die_decl_ctx_die)
+ return abs_die_decl_ctx_die;
+ }
+
+ die = die->GetParent();
+ }
+ }
+ return NULL;
+}
+
+
+Symbol *
+SymbolFileDWARF::GetObjCClassSymbol (const ConstString &objc_class_name)
+{
+ Symbol *objc_class_symbol = NULL;
+ if (m_obj_file)
+ {
+ Symtab *symtab = m_obj_file->GetSymtab ();
+ if (symtab)
+ {
+ objc_class_symbol = symtab->FindFirstSymbolWithNameAndType (objc_class_name,
+ eSymbolTypeObjCClass,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+ }
+ }
+ return objc_class_symbol;
+}
+
+// Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If they don't
+// then we can end up looking through all class types for a complete type and never find
+// the full definition. We need to know if this attribute is supported, so we determine
+// this here and cache th result. We also need to worry about the debug map DWARF file
+// if we are doing darwin DWARF in .o file debugging.
+bool
+SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu)
+{
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate)
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type())
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ else
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type())
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ break;
+ }
+ }
+ }
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo && GetDebugMapSymfile ())
+ return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type (this);
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+// 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.
+TypeSP
+SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const ConstString &type_name,
+ bool must_be_implementation)
+{
+
+ TypeSP type_sp;
+
+ if (!type_name || (must_be_implementation && !GetObjCClassSymbol (type_name)))
+ return type_sp;
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const char *name_cstr = type_name.GetCString();
+ m_apple_types_ap->FindCompleteObjCClassByName (name_cstr, die_offsets, must_be_implementation);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (type_name, die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+ 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)
+ {
+ switch (type_die->Tag())
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ try_resolving_type = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (try_resolving_type)
+ {
+ if (must_be_implementation && type_cu->Supports_DW_AT_APPLE_objc_complete_type())
+ try_resolving_type = type_die->GetAttributeValueAsUnsigned (this, type_cu, DW_AT_APPLE_objc_complete_type, 0);
+
+ if (try_resolving_type)
+ {
+ 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(dwarf_cu->GetOffset()),
+ m_obj_file->GetFileSpec().GetFilename().AsCString(),
+ MakeUserID(type_die->GetOffset()),
+ MakeUserID(type_cu->GetOffset()));
+
+ if (die)
+ m_die_to_type[die] = resolved_type;
+ type_sp = resolved_type->shared_from_this();
+ break;
+ }
+ }
+ }
+ }
+ 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;
+}
+
+
+//----------------------------------------------------------------------
+// This function helps to ensure that the declaration contexts match for
+// two different DIEs. Often times debug information will refer to a
+// forward declaration of a type (the equivalent of "struct my_struct;".
+// There will often be a declaration of that type elsewhere that has the
+// full definition. When we go looking for the full type "my_struct", we
+// will find one or more matches in the accelerator tables and we will
+// then need to make sure the type was in the same declaration context
+// as the original DIE. This function can efficiently compare two DIEs
+// and will return true when the declaration context matches, and false
+// when they don't.
+//----------------------------------------------------------------------
+bool
+SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1,
+ DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2)
+{
+ if (die1 == die2)
+ return true;
+
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // You can't and shouldn't call this function with a compile unit from
+ // two different SymbolFileDWARF instances.
+ assert (DebugInfo()->ContainsCompileUnit (cu1));
+ assert (DebugInfo()->ContainsCompileUnit (cu2));
+#endif
+
+ DWARFDIECollection decl_ctx_1;
+ DWARFDIECollection decl_ctx_2;
+ //The declaration DIE stack is a stack of the declaration context
+ // DIEs all the way back to the compile unit. If a type "T" is
+ // declared inside a class "B", and class "B" is declared inside
+ // a class "A" and class "A" is in a namespace "lldb", and the
+ // namespace is in a compile unit, there will be a stack of DIEs:
+ //
+ // [0] DW_TAG_class_type for "B"
+ // [1] DW_TAG_class_type for "A"
+ // [2] DW_TAG_namespace for "lldb"
+ // [3] DW_TAG_compile_unit for the source file.
+ //
+ // We grab both contexts and make sure that everything matches
+ // all the way back to the compiler unit.
+
+ // First lets grab the decl contexts for both DIEs
+ die1->GetDeclContextDIEs (this, cu1, decl_ctx_1);
+ die2->GetDeclContextDIEs (this, cu2, decl_ctx_2);
+ // Make sure the context arrays have the same size, otherwise
+ // we are done
+ const size_t count1 = decl_ctx_1.Size();
+ const size_t count2 = decl_ctx_2.Size();
+ if (count1 != count2)
+ return false;
+
+ // Make sure the DW_TAG values match all the way back up the the
+ // compile unit. If they don't, then we are done.
+ const DWARFDebugInfoEntry *decl_ctx_die1;
+ const DWARFDebugInfoEntry *decl_ctx_die2;
+ size_t i;
+ for (i=0; i<count1; i++)
+ {
+ decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i);
+ decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i);
+ if (decl_ctx_die1->Tag() != decl_ctx_die2->Tag())
+ return false;
+ }
+#if defined LLDB_CONFIGURATION_DEBUG
+
+ // Make sure the top item in the decl context die array is always
+ // DW_TAG_compile_unit. If it isn't then something went wrong in
+ // the DWARFDebugInfoEntry::GetDeclContextDIEs() function...
+ assert (decl_ctx_1.GetDIEPtrAtIndex (count1 - 1)->Tag() == DW_TAG_compile_unit);
+
+#endif
+ // Always skip the compile unit when comparing by only iterating up to
+ // "count - 1". Here we compare the names as we go.
+ for (i=0; i<count1 - 1; i++)
+ {
+ decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i);
+ decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i);
+ const char *name1 = decl_ctx_die1->GetName(this, cu1);
+ const char *name2 = decl_ctx_die2->GetName(this, cu2);
+ // If the string was from a DW_FORM_strp, then the pointer will often
+ // be the same!
+ if (name1 == name2)
+ continue;
+
+ // Name pointers are not equal, so only compare the strings
+ // if both are not NULL.
+ if (name1 && name2)
+ {
+ // If the strings don't compare, we are done...
+ if (strcmp(name1, name2) != 0)
+ return false;
+ }
+ else
+ {
+ // One name was NULL while the other wasn't
+ return false;
+ }
+ }
+ // We made it through all of the checks and the declaration contexts
+ // are equal.
+ 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 > 1)
+ {
+ 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(dwarf_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)
+{
+ TypeSP type_sp;
+
+ const uint32_t dwarf_decl_ctx_count = dwarf_decl_ctx.GetSize();
+ if (dwarf_decl_ctx_count > 0)
+ {
+ const ConstString type_name(dwarf_decl_ctx[0].name);
+ const dw_tag_t tag = dwarf_decl_ctx[0].tag;
+
+ if (type_name)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS));
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s')",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName());
+ }
+
+ 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)
+ {
+ const char *qualified_name = dwarf_decl_ctx.GetQualifiedName();
+ const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name);
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()");
+ m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), 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(), 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();
+
+
+ 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!
+ const dw_tag_t type_tag = type_die->Tag();
+ // Make sure the tags match
+ if (type_tag == 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_tag)
+ {
+ case DW_TAG_class_type:
+ // We had a "class foo", see if we ended up with a "struct foo { ... };"
+ try_resolving_type = (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 = (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)
+ {
+ DWARFDeclContext type_dwarf_decl_ctx;
+ type_die->GetDWARFDeclContext (this, type_cu, type_dwarf_decl_ctx);
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') trying die=0x%8.8x (%s)",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName(),
+ type_die->GetOffset(),
+ type_dwarf_decl_ctx.GetQualifiedName());
+ }
+
+ // Make sure the decl contexts match all the way up
+ if (dwarf_decl_ctx == type_dwarf_decl_ctx)
+ {
+ Type *resolved_type = ResolveType (type_cu, type_die, false);
+ if (resolved_type && resolved_type != DIE_IS_BEING_PARSED)
+ {
+ type_sp = resolved_type->shared_from_this();
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ std::string qualified_name;
+ type_die->GetQualifiedName(this, type_cu, qualified_name);
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') ignoring die=0x%8.8x (%s)",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName(),
+ 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;
+}
+
+bool
+SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
+ Type *class_type,
+ DWARFCompileUnit* src_cu,
+ const DWARFDebugInfoEntry *src_class_die,
+ DWARFCompileUnit* dst_cu,
+ const DWARFDebugInfoEntry *dst_class_die,
+ llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures)
+{
+ if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die)
+ return false;
+ if (src_class_die->Tag() != dst_class_die->Tag())
+ return false;
+
+ // We need to complete the class type so we can get all of the method types
+ // parsed so we can then unique those types to their equivalent counterparts
+ // in "dst_cu" and "dst_class_die"
+ class_type->GetClangFullType();
+
+ const DWARFDebugInfoEntry *src_die;
+ const DWARFDebugInfoEntry *dst_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die_artificial;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die_artificial;
+ for (src_die = src_class_die->GetFirstChild(); src_die != NULL; src_die = src_die->GetSibling())
+ {
+ if (src_die->Tag() == DW_TAG_subprogram)
+ {
+ // Make sure this is a declaration and not a concrete instance by looking
+ // for DW_AT_declaration set to 1. Sometimes concrete function instances
+ // are placed inside the class definitions and shouldn't be included in
+ // the list of things are are tracking here.
+ if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_declaration, 0) == 1)
+ {
+ const char *src_name = src_die->GetMangledName (src_symfile, src_cu);
+ if (src_name)
+ {
+ ConstString src_const_name(src_name);
+ if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_artificial, 0))
+ src_name_to_die_artificial.Append(src_const_name.GetCString(), src_die);
+ else
+ src_name_to_die.Append(src_const_name.GetCString(), src_die);
+ }
+ }
+ }
+ }
+ for (dst_die = dst_class_die->GetFirstChild(); dst_die != NULL; dst_die = dst_die->GetSibling())
+ {
+ if (dst_die->Tag() == DW_TAG_subprogram)
+ {
+ // Make sure this is a declaration and not a concrete instance by looking
+ // for DW_AT_declaration set to 1. Sometimes concrete function instances
+ // are placed inside the class definitions and shouldn't be included in
+ // the list of things are are tracking here.
+ if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_declaration, 0) == 1)
+ {
+ const char *dst_name = dst_die->GetMangledName (this, dst_cu);
+ if (dst_name)
+ {
+ ConstString dst_const_name(dst_name);
+ if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_artificial, 0))
+ dst_name_to_die_artificial.Append(dst_const_name.GetCString(), dst_die);
+ else
+ dst_name_to_die.Append(dst_const_name.GetCString(), dst_die);
+ }
+ }
+ }
+ }
+ const uint32_t src_size = src_name_to_die.GetSize ();
+ const uint32_t dst_size = dst_name_to_die.GetSize ();
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_TYPE_COMPLETION));
+
+ // Is everything kosher so we can go through the members at top speed?
+ bool fast_path = true;
+
+ if (src_size != dst_size)
+ {
+ if (src_size != 0 && dst_size != 0)
+ {
+ if (log)
+ log->Printf("warning: trying to unique class DIE 0x%8.8x to 0x%8.8x, but they didn't have the same size (src=%d, dst=%d)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_size,
+ dst_size);
+ }
+
+ fast_path = false;
+ }
+
+ uint32_t idx;
+
+ if (fast_path)
+ {
+ for (idx = 0; idx < src_size; ++idx)
+ {
+ src_die = src_name_to_die.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx);
+
+ if (src_die->Tag() != dst_die->Tag())
+ {
+ if (log)
+ log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) tags didn't match 0x%8.8x (%s)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_die->GetOffset(),
+ DW_TAG_value_to_name(src_die->Tag()),
+ dst_die->GetOffset(),
+ DW_TAG_value_to_name(src_die->Tag()));
+ fast_path = false;
+ }
+
+ const char *src_name = src_die->GetMangledName (src_symfile, src_cu);
+ const char *dst_name = dst_die->GetMangledName (this, dst_cu);
+
+ // Make sure the names match
+ if (src_name == dst_name || (strcmp (src_name, dst_name) == 0))
+ continue;
+
+ if (log)
+ log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) names didn't match 0x%8.8x (%s)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_die->GetOffset(),
+ src_name,
+ dst_die->GetOffset(),
+ dst_name);
+
+ fast_path = false;
+ }
+ }
+
+ // Now do the work of linking the DeclContexts and Types.
+ if (fast_path)
+ {
+ // We can do this quickly. Just run across the tables index-for-index since
+ // we know each node has matching names and tags.
+ for (idx = 0; idx < src_size; ++idx)
+ {
+ src_die = src_name_to_die.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx);
+
+ clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ }
+ else
+ {
+ // We must do this slowly. For each member of the destination, look
+ // up a member in the source with the same name, check its tag, and
+ // unique them if everything matches up. Report failures.
+
+ if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty())
+ {
+ src_name_to_die.Sort();
+
+ for (idx = 0; idx < dst_size; ++idx)
+ {
+ const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
+ src_die = src_name_to_die.Find(dst_name, NULL);
+
+ if (src_die && (src_die->Tag() == dst_die->Tag()))
+ {
+ clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset());
+
+ failures.push_back(dst_die);
+ }
+ }
+ }
+ }
+
+ const uint32_t src_size_artificial = src_name_to_die_artificial.GetSize ();
+ const uint32_t dst_size_artificial = dst_name_to_die_artificial.GetSize ();
+
+ UniqueCStringMap<const DWARFDebugInfoEntry *> name_to_die_artificial_not_in_src;
+
+ if (src_size_artificial && dst_size_artificial)
+ {
+ dst_name_to_die_artificial.Sort();
+
+ for (idx = 0; idx < src_size_artificial; ++idx)
+ {
+ const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx);
+ src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL);
+
+ if (dst_die)
+ {
+ // Both classes have the artificial types, link them
+ clang::DeclContext *src_decl_ctx = m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ }
+ }
+
+ if (dst_size_artificial)
+ {
+ for (idx = 0; idx < dst_size_artificial; ++idx)
+ {
+ const char *dst_name_artificial = dst_name_to_die_artificial.GetCStringAtIndex(idx);
+ dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked (idx);
+ if (log)
+ log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial);
+
+ failures.push_back(dst_die);
+ }
+ }
+
+ return (failures.size() != 0);
+}
+
+TypeSP
+SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new_ptr)
+{
+ TypeSP type_sp;
+
+ if (type_is_new_ptr)
+ *type_is_new_ptr = false;
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+ static DIEStack g_die_stack;
+ DIEStack::ScopedPopper scoped_die_logger(g_die_stack);
+#endif
+
+ AccessType accessibility = eAccessNone;
+ if (die != NULL)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ {
+ const DWARFDebugInfoEntry *context_die;
+ clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die);
+
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')",
+ die->GetOffset(),
+ context,
+ context_die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+ scoped_die_logger.Push (dwarf_cu, die);
+ g_die_stack.LogDIEs(log, this);
+#endif
+ }
+//
+// Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+// if (log && dwarf_cu)
+// {
+// StreamString s;
+// die->DumpLocation (this, dwarf_cu, s);
+// GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData());
+//
+// }
+
+ Type *type_ptr = m_die_to_type.lookup (die);
+ TypeList* type_list = GetTypeList();
+ if (type_ptr == NULL)
+ {
+ ClangASTContext &ast = GetClangASTContext();
+ if (type_is_new_ptr)
+ *type_is_new_ptr = true;
+
+ const dw_tag_t tag = die->Tag();
+
+ bool is_forward_declaration = false;
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *type_name_cstr = NULL;
+ ConstString type_name_const_str;
+ Type::ResolveState resolve_state = Type::eResolveStateUnresolved;
+ uint64_t byte_size = 0;
+ Declaration decl;
+
+ Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
+ ClangASTType clang_type;
+
+ dw_attr_t attr;
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_unspecified_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ uint32_t encoding = 0;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_name:
+
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ // Work around a bug in llvm-gcc where they give a name to a reference type which doesn't
+ // include the "&"...
+ if (tag == DW_TAG_reference_type)
+ {
+ if (strchr (type_name_cstr, '&') == NULL)
+ type_name_cstr = NULL;
+ }
+ if (type_name_cstr)
+ type_name_const_str.SetCString(type_name_cstr);
+ 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;
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8x\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid);
+
+ switch (tag)
+ {
+ default:
+ break;
+
+ case DW_TAG_unspecified_type:
+ if (strcmp(type_name_cstr, "nullptr_t") == 0 ||
+ strcmp(type_name_cstr, "decltype(nullptr)") == 0 )
+ {
+ resolve_state = Type::eResolveStateFull;
+ clang_type = ast.GetBasicType(eBasicTypeNullPtr);
+ break;
+ }
+ // Fall through to base type below in case we can handle the type there...
+
+ case DW_TAG_base_type:
+ resolve_state = Type::eResolveStateFull;
+ clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr,
+ encoding,
+ byte_size * 8);
+ break;
+
+ case DW_TAG_pointer_type: encoding_data_type = Type::eEncodingIsPointerUID; break;
+ case DW_TAG_reference_type: encoding_data_type = Type::eEncodingIsLValueReferenceUID; break;
+ case DW_TAG_rvalue_reference_type: encoding_data_type = Type::eEncodingIsRValueReferenceUID; break;
+ case DW_TAG_typedef: encoding_data_type = Type::eEncodingIsTypedefUID; break;
+ case DW_TAG_const_type: encoding_data_type = Type::eEncodingIsConstUID; break;
+ case DW_TAG_restrict_type: encoding_data_type = Type::eEncodingIsRestrictUID; break;
+ case DW_TAG_volatile_type: encoding_data_type = Type::eEncodingIsVolatileUID; break;
+ }
+
+ if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL)
+ {
+ bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus);
+
+ if (translation_unit_is_objc)
+ {
+ if (type_name_cstr != NULL)
+ {
+ static ConstString g_objc_type_name_id("id");
+ static ConstString g_objc_type_name_Class("Class");
+ static ConstString g_objc_type_name_selector("SEL");
+
+ if (type_name_const_str == g_objc_type_name_id)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'id' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+
+ }
+ else if (type_name_const_str == g_objc_type_name_Class)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'Class' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCClass);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ else if (type_name_const_str == g_objc_type_name_selector)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'selector' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCSel);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ }
+ else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID)
+ {
+ // Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id".
+
+ DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid);
+
+ if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type)
+ {
+ if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL))
+ {
+ if (!strcmp(struct_name, "objc_object"))
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is 'objc_object*', which we overrode to 'id'.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ encoding_uid,
+ encoding_data_type,
+ &decl,
+ clang_type,
+ resolve_state));
+
+ m_die_to_type[die] = type_sp.get();
+
+// Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false);
+// if (encoding_type != NULL)
+// {
+// if (encoding_type != DIE_IS_BEING_PARSED)
+// type_sp->SetEncodingType(encoding_type);
+// else
+// m_indirect_fixups.push_back(type_sp.get());
+// }
+ }
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+ bool byte_size_valid = false;
+
+ LanguageType class_language = eLanguageTypeUnknown;
+ bool is_complete_objc_class = false;
+ //bool struct_is_class = false;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file:
+ if (dwarf_cu->DW_AT_decl_file_attributes_are_invalid())
+ {
+ // llvm-gcc outputs invalid DW_AT_decl_file attributes that always
+ // point to the compile unit file, so we clear this invalid value
+ // so that we can still unique types efficiently.
+ decl.SetFile(FileSpec ("<invalid>", false));
+ }
+ else
+ 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_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_byte_size:
+ byte_size = form_value.Unsigned();
+ byte_size_valid = true;
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
+ break;
+
+ case DW_AT_declaration:
+ is_forward_declaration = form_value.Boolean();
+ break;
+
+ case DW_AT_APPLE_runtime_class:
+ class_language = (LanguageType)form_value.Signed();
+ break;
+
+ case DW_AT_APPLE_objc_complete_type:
+ is_complete_objc_class = form_value.Signed();
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ UniqueDWARFASTType unique_ast_entry;
+
+ // Only try and unique the type if it has a name.
+ if (type_name_const_str &&
+ GetUniqueDWARFASTTypeMap().Find (type_name_const_str,
+ this,
+ dwarf_cu,
+ die,
+ decl,
+ byte_size_valid ? byte_size : -1,
+ unique_ast_entry))
+ {
+ // We have already parsed this type or from another
+ // compile unit. GCC loves to use the "one definition
+ // rule" which can result in multiple definitions
+ // of the same class over and over in each compile
+ // unit.
+ type_sp = unique_ast_entry.m_type_sp;
+ if (type_sp)
+ {
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ int tag_decl_kind = -1;
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = eAccessPrivate;
+ }
+
+ if (byte_size_valid && byte_size == 0 && type_name_cstr &&
+ die->HasChildren() == false &&
+ sc.comp_unit->GetLanguage() == eLanguageTypeObjC)
+ {
+ // Work around an issue with clang at the moment where
+ // forward declarations for objective C classes are emitted
+ // as:
+ // DW_TAG_structure_type [2]
+ // DW_AT_name( "ForwardObjcClass" )
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_decl_file( "..." )
+ // DW_AT_decl_line( 1 )
+ //
+ // Note that there is no DW_AT_declaration and there are
+ // no children, and the byte size is zero.
+ is_forward_declaration = true;
+ }
+
+ if (class_language == eLanguageTypeObjC ||
+ class_language == eLanguageTypeObjC_plus_plus)
+ {
+ if (!is_complete_objc_class && Supports_DW_AT_APPLE_objc_complete_type(dwarf_cu))
+ {
+ // We have a valid eSymbolTypeObjCClass class symbol whose
+ // name matches the current objective C class that we
+ // are trying to find and this DIE isn't the complete
+ // definition (we checked is_complete_objc_class above and
+ // know it is false), so the real definition is in here somewhere
+ type_sp = FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true);
+
+ if (!type_sp && GetDebugMapSymfile ())
+ {
+ // We weren't able to find a full declaration in
+ // this DWARF, see if we have a declaration anywhere
+ // else...
+ type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true);
+ }
+
+ if (type_sp)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64,
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr,
+ type_sp->GetID());
+ }
+
+ // We found a real definition for this type elsewhere
+ // so lets use it and cache the fact that we found
+ // a complete type for this die
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+ }
+
+
+ if (is_forward_declaration)
+ {
+ // We have a forward declaration to a type and we need
+ // to try and find a full declaration. We look in the
+ // current type index just in case we have a forward
+ // declaration followed by an actual declarations in the
+ // DWARF. If this fails, we need to look elsewhere...
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type",
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr);
+ }
+
+ DWARFDeclContext die_decl_ctx;
+ die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx);
+
+ //type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, type_name_const_str);
+ type_sp = FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+
+ if (!type_sp && GetDebugMapSymfile ())
+ {
+ // We weren't able to find a full declaration in
+ // this DWARF, see if we have a declaration anywhere
+ // else...
+ type_sp = m_debug_map_symfile->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+ }
+
+ if (type_sp)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64,
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr,
+ type_sp->GetID());
+ }
+
+ // We found a real definition for this type elsewhere
+ // so lets use it and cache the fact that we found
+ // a complete type for this die
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+ assert (tag_decl_kind != -1);
+ bool clang_type_was_created = false;
+ clang_type.SetClangType(ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die));
+ if (!clang_type)
+ {
+ const DWARFDebugInfoEntry *decl_ctx_die;
+
+ clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
+ if (accessibility == eAccessNone && decl_ctx)
+ {
+ // Check the decl context that contains this class/struct/union.
+ // If it is a class we must give it an accessability.
+ const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind();
+ if (DeclKindIsCXXClass (containing_decl_kind))
+ accessibility = default_accessibility;
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+ metadata.SetIsDynamicCXXType(ClassOrStructIsVirtual (dwarf_cu, die));
+
+ if (type_name_cstr && strchr (type_name_cstr, '<'))
+ {
+ ClangASTContext::TemplateParameterInfos template_param_infos;
+ if (ParseTemplateParameterInfos (dwarf_cu, die, template_param_infos))
+ {
+ clang::ClassTemplateDecl *class_template_decl = ParseClassTemplateDecl (decl_ctx,
+ accessibility,
+ type_name_cstr,
+ tag_decl_kind,
+ template_param_infos);
+
+ clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx,
+ class_template_decl,
+ tag_decl_kind,
+ template_param_infos);
+ clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl);
+ clang_type_was_created = true;
+
+ GetClangASTContext().SetMetadata (class_template_decl, metadata);
+ GetClangASTContext().SetMetadata (class_specialization_decl, metadata);
+ }
+ }
+
+ if (!clang_type_was_created)
+ {
+ clang_type_was_created = true;
+ clang_type = ast.CreateRecordType (decl_ctx,
+ accessibility,
+ type_name_cstr,
+ tag_decl_kind,
+ class_language,
+ &metadata);
+ }
+ }
+
+ // Store a forward declaration to this class type in case any
+ // parameters in any class methods need it for the clang
+ // types for function prototypes.
+ LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die);
+ type_sp.reset (new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateForward));
+
+ type_sp->SetIsCompleteObjCClass(is_complete_objc_class);
+
+
+ // Add our type to the unique type map so we don't
+ // end up creating many copies of the same type over
+ // and over in the ASTContext for our module
+ unique_ast_entry.m_type_sp = type_sp;
+ unique_ast_entry.m_symfile = this;
+ unique_ast_entry.m_cu = dwarf_cu;
+ unique_ast_entry.m_die = die;
+ unique_ast_entry.m_declaration = decl;
+ unique_ast_entry.m_byte_size = byte_size;
+ GetUniqueDWARFASTTypeMap().Insert (type_name_const_str,
+ unique_ast_entry);
+
+ if (is_forward_declaration && die->HasChildren())
+ {
+ // Check to see if the DIE actually has a definition, some version of GCC will
+ // emit DIEs with DW_AT_declaration set to true, but yet still have subprogram,
+ // members, or inheritance, so we can't trust it
+ const DWARFDebugInfoEntry *child_die = die->GetFirstChild();
+ while (child_die)
+ {
+ switch (child_die->Tag())
+ {
+ case DW_TAG_inheritance:
+ case DW_TAG_subprogram:
+ case DW_TAG_member:
+ case DW_TAG_APPLE_property:
+ child_die = NULL;
+ is_forward_declaration = false;
+ break;
+ default:
+ child_die = child_die->GetSibling();
+ break;
+ }
+ }
+ }
+
+ if (!is_forward_declaration)
+ {
+ // Always start the definition for a class type so that
+ // if the class has child classes or types that require
+ // the class to be created for use as their decl contexts
+ // the class will be ready to accept these child definitions.
+ if (die->HasChildren() == false)
+ {
+ // No children for this struct/union/class, lets finish it
+ clang_type.StartTagDeclarationDefinition ();
+ clang_type.CompleteTagDeclarationDefinition ();
+
+ if (tag == DW_TAG_structure_type) // this only applies in C
+ {
+ clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl();
+
+ if (record_decl)
+ {
+ LayoutInfo layout_info;
+
+ layout_info.alignment = 0;
+ layout_info.bit_size = 0;
+
+ m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
+ }
+ }
+ }
+ else if (clang_type_was_created)
+ {
+ // Start the definition if the class is not objective C since
+ // the underlying decls respond to isCompleteDefinition(). Objective
+ // C decls dont' respond to isCompleteDefinition() so we can't
+ // start the declaration definition right away. For C++ classs/union/structs
+ // we want to start the definition in case the class is needed as the
+ // declaration context for a contained class or type without the need
+ // to complete that type..
+
+ if (class_language != eLanguageTypeObjC &&
+ class_language != eLanguageTypeObjC_plus_plus)
+ clang_type.StartTagDeclarationDefinition ();
+
+ // Leave this as a forward declaration until we need
+ // to know the details of the type. lldb_private::Type
+ // will automatically call the SymbolFile virtual function
+ // "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition(Type *)"
+ // When the definition needs to be defined.
+ m_forward_decl_die_to_clang_type[die] = clang_type.GetOpaqueQualType();
+ m_forward_decl_clang_type_to_die[clang_type.RemoveFastQualifiers().GetOpaqueQualType()] = die;
+ clang_type.SetHasExternalStorage (true);
+ }
+ }
+
+ }
+ break;
+
+ case DW_TAG_enumeration_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ lldb::user_id_t encoding_uid = DW_INVALID_OFFSET;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_name:
+ 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_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;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_stride:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ ClangASTType enumerator_clang_type;
+ clang_type.SetClangType (ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die));
+ if (!clang_type)
+ {
+ if (encoding_uid != DW_INVALID_OFFSET)
+ {
+ Type *enumerator_type = ResolveTypeUID(encoding_uid);
+ if (enumerator_type)
+ enumerator_clang_type = enumerator_type->GetClangFullType();
+ }
+
+ if (!enumerator_clang_type)
+ enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL,
+ DW_ATE_signed,
+ byte_size * 8);
+
+ clang_type = ast.CreateEnumerationType (type_name_cstr,
+ GetClangDeclContextContainingDIE (dwarf_cu, die, NULL),
+ decl,
+ enumerator_clang_type);
+ }
+ else
+ {
+ enumerator_clang_type = clang_type.GetEnumerationIntegerType ();
+ }
+
+ LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die);
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ encoding_uid,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateForward));
+
+ clang_type.StartTagDeclarationDefinition ();
+ if (die->HasChildren())
+ {
+ SymbolContext cu_sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ bool is_signed = false;
+ enumerator_clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), dwarf_cu, die);
+ }
+ clang_type.CompleteTagDeclarationDefinition ();
+ }
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ //const char *mangled = NULL;
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ bool is_variadic = false;
+ bool is_inline = false;
+ bool is_static = false;
+ bool is_virtual = false;
+ bool is_explicit = false;
+ bool is_artificial = false;
+ dw_offset_t specification_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t abstract_origin_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t object_pointer_die_offset = DW_INVALID_OFFSET;
+
+ unsigned type_quals = 0;
+ clang::StorageClass storage = clang::SC_None;//, Extern, Static, PrivateExtern
+
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+
+ 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_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;
+ case DW_AT_virtuality: is_virtual = form_value.Boolean(); break;
+ case DW_AT_explicit: is_explicit = form_value.Boolean(); break;
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+
+
+ case DW_AT_external:
+ if (form_value.Unsigned())
+ {
+ if (storage == clang::SC_None)
+ storage = clang::SC_Extern;
+ else
+ storage = clang::SC_PrivateExtern;
+ }
+ break;
+
+ case DW_AT_specification:
+ specification_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_abstract_origin:
+ abstract_origin_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_object_pointer:
+ object_pointer_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_address_class:
+ case DW_AT_calling_convention:
+ case DW_AT_data_location:
+ case DW_AT_elemental:
+ case DW_AT_entry_pc:
+ case DW_AT_frame_base:
+ case DW_AT_high_pc:
+ case DW_AT_low_pc:
+ case DW_AT_prototyped:
+ case DW_AT_pure:
+ case DW_AT_ranges:
+ case DW_AT_recursive:
+ case DW_AT_return_addr:
+ case DW_AT_segment:
+ case DW_AT_start_scope:
+ case DW_AT_static_link:
+ case DW_AT_trampoline:
+ case DW_AT_visibility:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ std::string object_pointer_name;
+ if (object_pointer_die_offset != DW_INVALID_OFFSET)
+ {
+ // Get the name from the object pointer die
+ StreamString s;
+ if (DWARFDebugInfoEntry::GetName (this, dwarf_cu, object_pointer_die_offset, s))
+ {
+ object_pointer_name.assign(s.GetData());
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ ClangASTType return_clang_type;
+ Type *func_type = NULL;
+
+ if (type_die_offset != DW_INVALID_OFFSET)
+ func_type = ResolveTypeUID(type_die_offset);
+
+ if (func_type)
+ return_clang_type = func_type->GetClangForwardType();
+ else
+ return_clang_type = ast.GetBasicType(eBasicTypeVoid);
+
+
+ std::vector<ClangASTType> function_param_types;
+ std::vector<clang::ParmVarDecl*> function_param_decls;
+
+ // Parse the function children for the parameters
+
+ const DWARFDebugInfoEntry *decl_ctx_die = NULL;
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
+ const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind();
+
+ const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind);
+ // Start off static. This will be set to false in ParseChildParameters(...)
+ // if we find a "this" paramters as the first parameter
+ if (is_cxx_method)
+ is_static = true;
+ ClangASTContext::TemplateParameterInfos template_param_infos;
+
+ if (die->HasChildren())
+ {
+ bool skip_artificial = true;
+ ParseChildParameters (sc,
+ containing_decl_ctx,
+ dwarf_cu,
+ die,
+ skip_artificial,
+ is_static,
+ type_list,
+ function_param_types,
+ function_param_decls,
+ type_quals,
+ template_param_infos);
+ }
+
+ // clang_type will get the function prototype clang type after this call
+ clang_type = ast.CreateFunctionType (return_clang_type,
+ function_param_types.data(),
+ function_param_types.size(),
+ is_variadic,
+ type_quals);
+
+ bool ignore_containing_context = false;
+
+ if (type_name_cstr)
+ {
+ bool type_handled = false;
+ if (tag == DW_TAG_subprogram)
+ {
+ ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true);
+ if (objc_method.IsValid(true))
+ {
+ SymbolContext empty_sc;
+ ClangASTType class_opaque_type;
+ ConstString class_name(objc_method.GetClassName());
+ if (class_name)
+ {
+ TypeList types;
+ TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false));
+
+ if (complete_objc_class_type_sp)
+ {
+ ClangASTType type_clang_forward_type = complete_objc_class_type_sp->GetClangForwardType();
+ if (type_clang_forward_type.IsObjCObjectOrInterfaceType ())
+ class_opaque_type = type_clang_forward_type;
+ }
+ }
+
+ if (class_opaque_type)
+ {
+ // If accessibility isn't set to anything valid, assume public for
+ // now...
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+
+ clang::ObjCMethodDecl *objc_method_decl = class_opaque_type.AddMethodToObjCObjectType (type_name_cstr,
+ clang_type,
+ accessibility,
+ is_artificial);
+ type_handled = objc_method_decl != NULL;
+ if (type_handled)
+ {
+ LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(objc_method_decl), die);
+ GetClangASTContext().SetMetadataAsUserID (objc_method_decl, MakeUserID(die->GetOffset()));
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), please file a bug and attach the file at the start of this error message",
+ die->GetOffset(),
+ tag,
+ DW_TAG_value_to_name(tag));
+ }
+ }
+ }
+ else if (is_cxx_method)
+ {
+ // Look at the parent of this DIE and see if is is
+ // a class or struct and see if this is actually a
+ // C++ method
+ Type *class_type = ResolveType (dwarf_cu, decl_ctx_die);
+ if (class_type)
+ {
+ if (class_type->GetID() != MakeUserID(decl_ctx_die->GetOffset()))
+ {
+ // We uniqued the parent class of this function to another class
+ // so we now need to associate all dies under "decl_ctx_die" to
+ // DIEs in the DIE for "class_type"...
+ SymbolFileDWARF *class_symfile = NULL;
+ DWARFCompileUnitSP class_type_cu_sp;
+ const DWARFDebugInfoEntry *class_type_die = NULL;
+
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile)
+ {
+ class_symfile = debug_map_symfile->GetSymbolFileByOSOIndex(SymbolFileDWARFDebugMap::GetOSOIndexFromUserID(class_type->GetID()));
+ class_type_die = class_symfile->DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp);
+ }
+ else
+ {
+ class_symfile = this;
+ class_type_die = DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp);
+ }
+ if (class_type_die)
+ {
+ llvm::SmallVector<const DWARFDebugInfoEntry *, 0> failures;
+
+ CopyUniqueClassMethodTypes (class_symfile,
+ class_type,
+ class_type_cu_sp.get(),
+ class_type_die,
+ dwarf_cu,
+ decl_ctx_die,
+ failures);
+
+ // FIXME do something with these failures that's smarter than
+ // just dropping them on the ground. Unfortunately classes don't
+ // like having stuff added to them after their definitions are
+ // complete...
+
+ type_ptr = m_die_to_type[die];
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ break;
+ }
+ }
+ }
+
+ if (specification_die_offset != DW_INVALID_OFFSET)
+ {
+ // We have a specification which we are going to base our function
+ // prototype off of, so we need this type to be completed so that the
+ // m_die_to_decl_ctx for the method in the specification has a valid
+ // clang decl context.
+ class_type->GetClangForwardType();
+ // If we have a specification, then the function type should have been
+ // made with the specification and not with this die.
+ DWARFCompileUnitSP spec_cu_sp;
+ const DWARFDebugInfoEntry* spec_die = DebugInfo()->GetDIEPtr(specification_die_offset, &spec_cu_sp);
+ clang::DeclContext *spec_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, spec_die);
+ if (spec_clang_decl_ctx)
+ {
+ LinkDeclContextToDIE(spec_clang_decl_ctx, die);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x) has no decl\n",
+ MakeUserID(die->GetOffset()),
+ specification_die_offset);
+ }
+ type_handled = true;
+ }
+ else if (abstract_origin_die_offset != DW_INVALID_OFFSET)
+ {
+ // We have a specification which we are going to base our function
+ // prototype off of, so we need this type to be completed so that the
+ // m_die_to_decl_ctx for the method in the abstract origin has a valid
+ // clang decl context.
+ class_type->GetClangForwardType();
+
+ DWARFCompileUnitSP abs_cu_sp;
+ const DWARFDebugInfoEntry* abs_die = DebugInfo()->GetDIEPtr(abstract_origin_die_offset, &abs_cu_sp);
+ clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, abs_die);
+ if (abs_clang_decl_ctx)
+ {
+ LinkDeclContextToDIE (abs_clang_decl_ctx, die);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x) has no decl\n",
+ MakeUserID(die->GetOffset()),
+ abstract_origin_die_offset);
+ }
+ type_handled = true;
+ }
+ else
+ {
+ ClangASTType class_opaque_type = class_type->GetClangForwardType();
+ if (class_opaque_type.IsCXXClassType ())
+ {
+ if (class_opaque_type.IsBeingDefined ())
+ {
+ // Neither GCC 4.2 nor clang++ currently set a valid accessibility
+ // in the DWARF for C++ methods... Default to public for now...
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+
+ if (!is_static && !die->HasChildren())
+ {
+ // We have a C++ member function with no children (this pointer!)
+ // and clang will get mad if we try and make a function that isn't
+ // well formed in the DWARF, so we will just skip it...
+ type_handled = true;
+ }
+ else
+ {
+ clang::CXXMethodDecl *cxx_method_decl;
+ // REMOVE THE CRASH DESCRIPTION BELOW
+ Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s",
+ type_name_cstr,
+ class_type->GetName().GetCString(),
+ MakeUserID(die->GetOffset()),
+ m_obj_file->GetFileSpec().GetPath().c_str());
+
+ const bool is_attr_used = false;
+
+ cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr,
+ clang_type,
+ accessibility,
+ is_virtual,
+ is_static,
+ is_inline,
+ is_explicit,
+ is_attr_used,
+ is_artificial);
+
+ type_handled = cxx_method_decl != NULL;
+
+ if (type_handled)
+ {
+ LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die);
+
+ Host::SetCrashDescription (NULL);
+
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+
+ if (!object_pointer_name.empty())
+ {
+ metadata.SetObjectPtrName(object_pointer_name.c_str());
+ if (log)
+ log->Printf ("Setting object pointer name: %s on method object %p.\n",
+ object_pointer_name.c_str(),
+ cxx_method_decl);
+ }
+ GetClangASTContext().SetMetadata (cxx_method_decl, metadata);
+ }
+ else
+ {
+ ignore_containing_context = true;
+ }
+ }
+ }
+ else
+ {
+ // We were asked to parse the type for a method in a class, yet the
+ // class hasn't been asked to complete itself through the
+ // clang::ExternalASTSource protocol, so we need to just have the
+ // class complete itself and do things the right way, then our
+ // DIE should then have an entry in the m_die_to_type map. First
+ // we need to modify the m_die_to_type so it doesn't think we are
+ // trying to parse this DIE anymore...
+ m_die_to_type[die] = NULL;
+
+ // Now we get the full type to force our class type to complete itself
+ // using the clang::ExternalASTSource protocol which will parse all
+ // base classes and all methods (including the method for this DIE).
+ class_type->GetClangFullType();
+
+ // The type for this DIE should have been filled in the function call above
+ type_ptr = m_die_to_type[die];
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ break;
+ }
+
+ // FIXME This is fixing some even uglier behavior but we really need to
+ // uniq the methods of each class as well as the class itself.
+ // <rdar://problem/11240464>
+ type_handled = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!type_handled)
+ {
+ // We just have a function that isn't part of a class
+ clang::FunctionDecl *function_decl = ast.CreateFunctionDeclaration (ignore_containing_context ? GetClangASTContext().GetTranslationUnitDecl() : containing_decl_ctx,
+ type_name_cstr,
+ clang_type,
+ storage,
+ is_inline);
+
+// if (template_param_infos.GetSize() > 0)
+// {
+// clang::FunctionTemplateDecl *func_template_decl = ast.CreateFunctionTemplateDecl (containing_decl_ctx,
+// function_decl,
+// type_name_cstr,
+// template_param_infos);
+//
+// ast.CreateFunctionTemplateSpecializationInfo (function_decl,
+// func_template_decl,
+// template_param_infos);
+// }
+ // Add the decl to our DIE to decl context map
+ assert (function_decl);
+ LinkDeclContextToDIE(function_decl, die);
+ if (!function_param_decls.empty())
+ ast.SetFunctionParameters (function_decl,
+ &function_param_decls.front(),
+ function_param_decls.size());
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+
+ if (!object_pointer_name.empty())
+ {
+ metadata.SetObjectPtrName(object_pointer_name.c_str());
+ if (log)
+ log->Printf ("Setting object pointer name: %s on function object %p.",
+ object_pointer_name.c_str(),
+ function_decl);
+ }
+ GetClangASTContext().SetMetadata (function_decl, metadata);
+ }
+ }
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ 0,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateFull));
+ assert(type_sp.get());
+ }
+ break;
+
+ case DW_TAG_array_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
+ int64_t first_index = 0;
+ uint32_t byte_stride = 0;
+ uint32_t bit_stride = 0;
+ bool is_vector = false;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ 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_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;
+ case DW_AT_GNU_vector: is_vector = form_value.Boolean(); 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;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_ordering:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ Type *element_type = ResolveTypeUID(type_die_offset);
+
+ if (element_type)
+ {
+ std::vector<uint64_t> element_orders;
+ ParseChildArrayInfo(sc, dwarf_cu, die, first_index, element_orders, byte_stride, bit_stride);
+ if (byte_stride == 0 && bit_stride == 0)
+ 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)
+ {
+ 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;
+ }
+ ConstString empty_name;
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ empty_name,
+ array_element_bit_stride / 8,
+ NULL,
+ type_die_offset,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateFull));
+ type_sp->SetEncodingType (element_type);
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_ptr_to_member_type:
+ {
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+
+ if (num_attributes > 0) {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_type:
+ type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_containing_type:
+ containing_type_die_offset = form_value.Reference(dwarf_cu); break;
+ }
+ }
+ }
+
+ Type *pointee_type = ResolveTypeUID(type_die_offset);
+ Type *class_type = ResolveTypeUID(containing_type_die_offset);
+
+ ClangASTType pointee_clang_type = pointee_type->GetClangForwardType();
+ ClangASTType class_clang_type = class_type->GetClangLayoutType();
+
+ clang_type = pointee_clang_type.CreateMemberPointerType(class_clang_type);
+
+ byte_size = clang_type.GetByteSize();
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ NULL,
+ clang_type,
+ Type::eResolveStateForward));
+ }
+
+ break;
+ }
+ default:
+ GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and attach the file at the start of this error message",
+ die->GetOffset(),
+ tag,
+ DW_TAG_value_to_name(tag));
+ break;
+ }
+
+ if (type_sp.get())
+ {
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t sc_parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+
+ SymbolContextScope * symbol_context_scope = NULL;
+ if (sc_parent_tag == DW_TAG_compile_unit)
+ {
+ symbol_context_scope = sc.comp_unit;
+ }
+ else if (sc.function != NULL)
+ {
+ symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+
+ if (symbol_context_scope != NULL)
+ {
+ type_sp->SetSymbolContextScope(symbol_context_scope);
+ }
+
+ // We are ready to put this type into the uniqued list up at the module level
+ type_list->Insert (type_sp);
+
+ m_die_to_type[die] = type_sp.get();
+ }
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ }
+ }
+ return type_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseTypes
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children
+)
+{
+ size_t types_added = 0;
+ while (die != NULL)
+ {
+ bool type_is_new = false;
+ if (ParseType(sc, dwarf_cu, die, &type_is_new).get())
+ {
+ if (type_is_new)
+ ++types_added;
+ }
+
+ if (parse_children && die->HasChildren())
+ {
+ if (die->Tag() == DW_TAG_subprogram)
+ {
+ SymbolContext child_sc(sc);
+ child_sc.function = sc.comp_unit->FindFunctionByUID(MakeUserID(die->GetOffset())).get();
+ types_added += ParseTypes(child_sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+ else
+ types_added += ParseTypes(sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return types_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ assert(sc.comp_unit && sc.function);
+ size_t functions_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (function_die)
+ {
+ ParseFunctionBlocks(sc, &sc.function->GetBlock (false), dwarf_cu, function_die, LLDB_INVALID_ADDRESS, 0);
+ }
+ }
+
+ return functions_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseTypes (const SymbolContext &sc)
+{
+ // At least a compile unit must be valid
+ assert(sc.comp_unit);
+ size_t types_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ if (sc.function)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *func_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (func_die && func_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, func_die->GetFirstChild(), true, true);
+ }
+ }
+ else
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->DIE();
+ if (dwarf_cu_die && dwarf_cu_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, dwarf_cu_die->GetFirstChild(), true, true);
+ }
+ }
+ }
+
+ return types_added;
+}
+
+size_t
+SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc)
+{
+ if (sc.comp_unit != NULL)
+ {
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ if (sc.function)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnitContainingDIE(sc.function->GetID()).get();
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID());
+
+ dw_addr_t func_lo_pc = function_die->GetAttributeValueAsUnsigned (this, dwarf_cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (func_lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ const size_t num_variables = ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true);
+
+ // Let all blocks know they have parse all their variables
+ sc.function->GetBlock (false).SetDidParseVariables (true, true);
+ return num_variables;
+ }
+ }
+ else if (sc.comp_unit)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()).get();
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ uint32_t vars_added = 0;
+ VariableListSP variables (sc.comp_unit->GetVariableList(false));
+
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variables);
+
+ DWARFCompileUnit* match_dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ DIEArray die_offsets;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (m_apple_names_ap->AppendAllDIEsInRange (dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ hash_data_array))
+ {
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ }
+ }
+ }
+ else
+ {
+ // Index if we already haven't to make sure the compile units
+ // get indexed and make their global DIE index list
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.FindAllEntriesForCompileUnit (dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+ 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];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &match_dwarf_cu);
+ if (die)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, LLDB_INVALID_ADDRESS));
+ if (var_sp)
+ {
+ variables->AddVariableIfUnique (var_sp);
+ ++vars_added;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x)\n", die_offset);
+ }
+ }
+
+ }
+ }
+ }
+ return vars_added;
+ }
+ }
+ return 0;
+}
+
+
+VariableSP
+SymbolFileDWARF::ParseVariableDIE
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ 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!
+
+ const dw_tag_t tag = die->Tag();
+
+ if ((tag == DW_TAG_variable) ||
+ (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter && sc.function))
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ const char *mangled = NULL;
+ Declaration decl;
+ uint32_t i;
+ lldb::user_id_t type_uid = LLDB_INVALID_UID;
+ DWARFExpression location;
+ bool is_external = false;
+ bool is_artificial = false;
+ bool location_is_const_value_data = false;
+ bool has_explicit_location = false;
+ //AccessType accessibility = eAccessNone;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ 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_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_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.
+ if (!has_explicit_location)
+ {
+ location_is_const_value_data = true;
+ // The constant value will be either a block, a data value or a string.
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ if (DWARFFormValue::IsBlockForm(form_value.Form()))
+ {
+ // Retrieve the value as a block expression.
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ location.CopyOpcodeData(debug_info_data, block_offset, block_length);
+ }
+ 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());
+ uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
+ uint32_t data_length = fixed_form_sizes[form_value.Form()];
+ location.CopyOpcodeData(debug_info_data, data_offset, data_length);
+ }
+ else
+ {
+ // 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());
+ uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
+ uint32_t data_length = fixed_form_sizes[form_value.Form()];
+ location.CopyOpcodeData(debug_info_data, data_offset, data_length);
+ }
+ else
+ {
+ const char *str = form_value.AsCString(&debug_info_data);
+ uint32_t string_offset = str - (const char *)debug_info_data.GetDataStart();
+ uint32_t string_length = strlen(str) + 1;
+ location.CopyOpcodeData(debug_info_data, string_offset, string_length);
+ }
+ }
+ }
+ break;
+ case DW_AT_location:
+ {
+ location_is_const_value_data = false;
+ has_explicit_location = true;
+ if (form_value.BlockData())
+ {
+ const DataExtractor& debug_info_data = get_debug_info_data();
+
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ location.CopyOpcodeData(get_debug_info_data(), block_offset, block_length);
+ }
+ else
+ {
+ const DataExtractor& debug_loc_data = get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ location.CopyOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length);
+ assert (func_low_pc != LLDB_INVALID_ADDRESS);
+ location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress());
+ }
+ }
+ }
+ break;
+
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_segment:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ case DW_AT_specification:
+ break;
+ }
+ }
+ }
+
+ ValueType scope = eValueTypeInvalid;
+
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ SymbolContextScope * symbol_context_scope = NULL;
+
+ // DWARF doesn't specify if a DW_TAG_variable is a local, global
+ // or static variable, so we have to do a little digging by
+ // looking at the location of a varaible to see if it contains
+ // a DW_OP_addr opcode _somewhere_ in the definition. I say
+ // somewhere because clang likes to combine small global variables
+ // into the same symbol and have locations like:
+ // DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
+ // So if we don't have a DW_TAG_formal_parameter, we can look at
+ // the location to see if it contains a DW_OP_addr opcode, and
+ // then we can correctly classify our variables.
+ if (tag == DW_TAG_formal_parameter)
+ scope = eValueTypeVariableArgument;
+ else
+ {
+ bool op_error = false;
+ // Check if the location has a DW_OP_addr with any address value...
+ lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
+ if (!location_is_const_value_data)
+ {
+ location_DW_OP_addr = location.GetLocation_DW_OP_addr (0, op_error);
+ if (op_error)
+ {
+ StreamString strm;
+ location.DumpLocationForAddress (&strm, eDescriptionLevelFull, 0, 0, NULL);
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8x: %s has an invalid location: %s", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), strm.GetString().c_str());
+ }
+ }
+
+ if (location_DW_OP_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (is_external)
+ scope = eValueTypeVariableGlobal;
+ else
+ scope = eValueTypeVariableStatic;
+
+
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile ();
+
+ if (debug_map_symfile)
+ {
+ // When leaving the DWARF in the .o files on darwin,
+ // when we have a global variable that wasn't initialized,
+ // the .o file might not have allocated a virtual
+ // address for the global variable. In this case it will
+ // have created a symbol for the global variable
+ // that is undefined/data and external and the value will
+ // be the byte size of the variable. When we do the
+ // address map in SymbolFileDWARFDebugMap we rely on
+ // having an address, we need to do some magic here
+ // so we can get the correct address for our global
+ // variable. The address for all of these entries
+ // will be zero, and there will be an undefined symbol
+ // in this object file, and the executable will have
+ // a matching symbol with a good address. So here we
+ // dig up the correct address and replace it in the
+ // location for the variable, and set the variable's
+ // symbol context scope to be that of the main executable
+ // so the file address will resolve correctly.
+ bool linked_oso_file_addr = false;
+ if (is_external && location_DW_OP_addr == 0)
+ {
+ // we have a possible uninitialized extern global
+ ConstString const_name(mangled ? mangled : name);
+ ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile();
+ if (debug_map_objfile)
+ {
+ Symtab *debug_map_symtab = debug_map_objfile->GetSymtab();
+ if (debug_map_symtab)
+ {
+ Symbol *exe_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType (const_name,
+ eSymbolTypeData,
+ Symtab::eDebugYes,
+ Symtab::eVisibilityExtern);
+ if (exe_symbol)
+ {
+ if (exe_symbol->ValueIsAddress())
+ {
+ const addr_t exe_file_addr = exe_symbol->GetAddress().GetFileAddress();
+ if (exe_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (location.Update_DW_OP_addr (exe_file_addr))
+ {
+ linked_oso_file_addr = true;
+ symbol_context_scope = exe_symbol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!linked_oso_file_addr)
+ {
+ // The DW_OP_addr is not zero, but it contains a .o file address which
+ // needs to be linked up correctly.
+ const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr);
+ if (exe_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ // Update the file address for this variable
+ location.Update_DW_OP_addr (exe_file_addr);
+ }
+ else
+ {
+ // Variable didn't make it into the final executable
+ return var_sp;
+ }
+ }
+ }
+ }
+ else
+ {
+ scope = eValueTypeVariableLocal;
+ }
+ }
+
+ if (symbol_context_scope == NULL)
+ {
+ switch (parent_tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function)
+ {
+ symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+ break;
+
+ default:
+ symbol_context_scope = sc.comp_unit;
+ break;
+ }
+ }
+
+ if (symbol_context_scope)
+ {
+ var_sp.reset (new Variable (MakeUserID(die->GetOffset()),
+ name,
+ mangled,
+ SymbolFileTypeSP (new SymbolFileType(*this, type_uid)),
+ scope,
+ symbol_context_scope,
+ &decl,
+ location,
+ is_external,
+ is_artificial));
+
+ var_sp->SetLocationIsConstantValueData (location_is_const_value_data);
+ }
+ else
+ {
+ // Not ready to parse this variable yet. It might be a global
+ // or static variable that is in a function scope and the function
+ // in the symbol context wasn't filled in yet
+ return var_sp;
+ }
+ }
+ // Cache var_sp even if NULL (the variable was just a specification or
+ // was missing vital information to be able to be displayed in the debugger
+ // (missing location due to optimization, etc)) so we don't re-parse
+ // this DIE over and over later...
+ m_die_to_variable_sp[die] = var_sp;
+ }
+ return var_sp;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::FindBlockContainingSpecification (dw_offset_t func_die_offset,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **result_die_cu_handle)
+{
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ DWARFDebugInfo* info = DebugInfo();
+
+ const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint(func_die_offset, result_die_cu_handle);
+ if (die)
+ {
+ assert (*result_die_cu_handle);
+ return FindBlockContainingSpecification (*result_die_cu_handle, die, spec_block_die_offset, result_die_cu_handle);
+ }
+ return NULL;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::FindBlockContainingSpecification(DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **result_die_cu_handle)
+{
+ if (die)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ {
+ if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset)
+ {
+ *result_die_cu_handle = dwarf_cu;
+ return die;
+ }
+
+ if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET) == spec_block_die_offset)
+ {
+ *result_die_cu_handle = dwarf_cu;
+ return die;
+ }
+ }
+ break;
+ }
+
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); child_die != NULL; child_die = child_die->GetSibling())
+ {
+ const DWARFDebugInfoEntry *result_die = FindBlockContainingSpecification (dwarf_cu,
+ child_die,
+ spec_block_die_offset,
+ result_die_cu_handle);
+ if (result_die)
+ return result_die;
+ }
+ }
+
+ *result_die_cu_handle = NULL;
+ return NULL;
+}
+
+size_t
+SymbolFileDWARF::ParseVariables
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const lldb::addr_t func_low_pc,
+ const DWARFDebugInfoEntry *orig_die,
+ bool parse_siblings,
+ bool parse_children,
+ VariableList* cc_variable_list
+)
+{
+ if (orig_die == NULL)
+ return 0;
+
+ VariableListSP variable_list_sp;
+
+ size_t vars_added = 0;
+ const DWARFDebugInfoEntry *die = orig_die;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ // Check to see if we have already parsed this variable or constant?
+ if (m_die_to_variable_sp[die])
+ {
+ if (cc_variable_list)
+ cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]);
+ }
+ else
+ {
+ // We haven't already parsed it, lets do that now.
+ if ((tag == DW_TAG_variable) ||
+ (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter && sc.function))
+ {
+ if (variable_list_sp.get() == NULL)
+ {
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ switch (parent_tag)
+ {
+ case DW_TAG_compile_unit:
+ if (sc.comp_unit != NULL)
+ {
+ variable_list_sp = sc.comp_unit->GetVariableList(false);
+ if (variable_list_sp.get() == NULL)
+ {
+ variable_list_sp.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variable_list_sp);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("parent 0x%8.8" PRIx64 " %s with no valid compile unit in symbol context for 0x%8.8" PRIx64 " %s.\n",
+ MakeUserID(sc_parent_die->GetOffset()),
+ DW_TAG_value_to_name (parent_tag),
+ MakeUserID(orig_die->GetOffset()),
+ DW_TAG_value_to_name (orig_die->Tag()));
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function != NULL)
+ {
+ // Check to see if we already have parsed the variables for the given scope
+
+ Block *block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (block == NULL)
+ {
+ // This must be a specification or abstract origin with
+ // a concrete block couterpart in the current function. We need
+ // to find the concrete block so we can correctly add the
+ // variable to it
+ DWARFCompileUnit *concrete_block_die_cu = dwarf_cu;
+ const DWARFDebugInfoEntry *concrete_block_die = FindBlockContainingSpecification (sc.function->GetID(),
+ sc_parent_die->GetOffset(),
+ &concrete_block_die_cu);
+ if (concrete_block_die)
+ block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(concrete_block_die->GetOffset()));
+ }
+
+ if (block != NULL)
+ {
+ const bool can_create = false;
+ variable_list_sp = block->GetBlockVariableList (can_create);
+ if (variable_list_sp.get() == NULL)
+ {
+ variable_list_sp.reset(new VariableList());
+ block->SetVariableList(variable_list_sp);
+ }
+ }
+ }
+ break;
+
+ default:
+ GetObjectFile()->GetModule()->ReportError ("didn't find appropriate parent DIE for variable list for 0x%8.8" PRIx64 " %s.\n",
+ MakeUserID(orig_die->GetOffset()),
+ DW_TAG_value_to_name (orig_die->Tag()));
+ break;
+ }
+ }
+
+ if (variable_list_sp)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, func_low_pc));
+ if (var_sp)
+ {
+ variable_list_sp->AddVariableIfUnique (var_sp);
+ if (cc_variable_list)
+ cc_variable_list->AddVariableIfUnique (var_sp);
+ ++vars_added;
+ }
+ }
+ }
+ }
+
+ bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
+
+ if (!skip_children && parse_children && die->HasChildren())
+ {
+ vars_added += ParseVariables(sc, dwarf_cu, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return vars_added;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+SymbolFileDWARF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARF::CompleteTagDecl (void *baton, clang::TagDecl *decl)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+}
+
+void
+SymbolFileDWARF::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+}
+
+void
+SymbolFileDWARF::DumpIndexes ()
+{
+ StreamFile s(stdout, false);
+
+ s.Printf ("DWARF index for (%s) '%s':",
+ GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(),
+ GetObjectFile()->GetFileSpec().GetPath().c_str());
+ s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s);
+ s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s);
+ s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s);
+ s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s);
+ s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s);
+ s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s);
+ s.Printf("\nTypes:\n"); m_type_index.Dump (&s);
+ s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s);
+}
+
+void
+SymbolFileDWARF::SearchDeclContext (const clang::DeclContext *decl_context,
+ const char *name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results)
+{
+ DeclContextToDIEMap::iterator iter = m_decl_ctx_to_die.find(decl_context);
+
+ if (iter == m_decl_ctx_to_die.end())
+ return;
+
+ for (DIEPointerSet::iterator pos = iter->second.begin(), end = iter->second.end(); pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry *context_die = *pos;
+
+ if (!results)
+ return;
+
+ DWARFDebugInfo* info = DebugInfo();
+
+ DIEArray die_offsets;
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ m_apple_types_ap->FindByName (name, die_offsets);
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (ConstString(name), die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+ if (num_matches)
+ {
+ for (size_t i = 0; i < num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die->GetParent() != context_die)
+ continue;
+
+ Type *matching_type = ResolveType (dwarf_cu, die);
+
+ clang::QualType qual_type = matching_type->GetClangForwardType().GetQualType();
+
+ if (const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()))
+ {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ results->push_back(tag_decl);
+ }
+ else if (const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(qual_type.getTypePtr()))
+ {
+ clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ results->push_back(typedef_decl);
+ }
+ }
+ }
+ }
+}
+
+void
+SymbolFileDWARF::FindExternalVisibleDeclsByName (void *baton,
+ const clang::DeclContext *decl_context,
+ clang::DeclarationName decl_name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results)
+{
+
+ switch (decl_context->getDeclKind())
+ {
+ case clang::Decl::Namespace:
+ case clang::Decl::TranslationUnit:
+ {
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ symbol_file_dwarf->SearchDeclContext (decl_context, decl_name.getAsString().c_str(), results);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool
+SymbolFileDWARF::LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ return symbol_file_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets);
+}
+
+
+bool
+SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl,
+ uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl);
+ bool success = false;
+ base_offsets.clear();
+ vbase_offsets.clear();
+ if (pos != m_record_decl_to_layout_map.end())
+ {
+ bit_size = pos->second.bit_size;
+ alignment = pos->second.alignment;
+ field_offsets.swap(pos->second.field_offsets);
+ base_offsets.swap (pos->second.base_offsets);
+ vbase_offsets.swap (pos->second.vbase_offsets);
+ m_record_decl_to_layout_map.erase(pos);
+ success = true;
+ }
+ else
+ {
+ bit_size = 0;
+ alignment = 0;
+ field_offsets.clear();
+ }
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i",
+ record_decl,
+ bit_size,
+ alignment,
+ (uint32_t)field_offsets.size(),
+ (uint32_t)base_offsets.size(),
+ (uint32_t)vbase_offsets.size(),
+ success);
+ return success;
+}
+
+
+SymbolFileDWARFDebugMap *
+SymbolFileDWARF::GetDebugMapSymfile ()
+{
+ if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired())
+ {
+ lldb::ModuleSP module_sp (m_debug_map_module_wp.lock());
+ if (module_sp)
+ {
+ SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
+ if (sym_vendor)
+ m_debug_map_symfile = (SymbolFileDWARFDebugMap *)sym_vendor->GetSymbolFile();
+ }
+ }
+ return m_debug_map_symfile;
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
new file mode 100644
index 000000000000..b6c6d94782db
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -0,0 +1,622 @@
+//===-- SymbolFileDWARF.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_SymbolFileDWARF_h_
+#define SymbolFileDWARF_SymbolFileDWARF_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+
+// Other libraries and framework includes
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+// Project includes
+#include "DWARFDefines.h"
+#include "HashedNameToDIE.h"
+#include "NameToDIE.h"
+#include "UniqueDWARFASTType.h"
+
+//----------------------------------------------------------------------
+// Forward Declarations for this DWARF plugin
+//----------------------------------------------------------------------
+class DebugMapModule;
+class DWARFAbbreviationDeclaration;
+class DWARFAbbreviationDeclarationSet;
+class DWARFileUnit;
+class DWARFDebugAbbrev;
+class DWARFDebugAranges;
+class DWARFDebugInfo;
+class DWARFDebugInfoEntry;
+class DWARFDebugLine;
+class DWARFDebugPubnames;
+class DWARFDebugRanges;
+class DWARFDeclContext;
+class DWARFDIECollection;
+class DWARFFormValue;
+class SymbolFileDWARFDebugMap;
+
+class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID
+{
+public:
+ friend class SymbolFileDWARFDebugMap;
+ friend class DebugMapModule;
+ friend class DWARFCompileUnit;
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARF(lldb_private::ObjectFile* ofile);
+ virtual ~SymbolFileDWARF();
+
+ virtual uint32_t CalculateAbilities ();
+ virtual void InitializeObject();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID(lldb::user_id_t type_uid);
+ virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+
+ virtual lldb_private::Type* ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed = true);
+ virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid);
+
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+ virtual lldb_private::TypeList *
+ GetTypeList ();
+ virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+ virtual lldb_private::ClangASTContext &
+ GetClangASTContext ();
+
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+
+
+ //------------------------------------------------------------------
+ // ClangASTContext callbacks for external source lookups.
+ //------------------------------------------------------------------
+ static void
+ CompleteTagDecl (void *baton, clang::TagDecl *);
+
+ static void
+ CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *);
+
+ static void
+ FindExternalVisibleDeclsByName (void *baton,
+ const clang::DeclContext *DC,
+ clang::DeclarationName Name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results);
+
+ static bool
+ LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+ bool
+ LayoutRecordType (const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+ struct LayoutInfo
+ {
+ LayoutInfo () :
+ bit_size(0),
+ alignment(0),
+ field_offsets(),
+ base_offsets(),
+ vbase_offsets()
+ {
+ }
+ uint64_t bit_size;
+ uint64_t alignment;
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> field_offsets;
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
+ };
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ // Approach 2 - count + accessor
+ // Index compile units would scan the initial compile units and register
+ // them with the module. This would only be done on demand if and only if
+ // the compile units were needed.
+ //virtual size_t GetCompUnitCount() = 0;
+ //virtual CompUnitSP GetCompUnitAtIndex(size_t cu_idx) = 0;
+
+ const lldb_private::DataExtractor& get_debug_abbrev_data ();
+ const lldb_private::DataExtractor& get_debug_aranges_data ();
+ const lldb_private::DataExtractor& get_debug_frame_data ();
+ const lldb_private::DataExtractor& get_debug_info_data ();
+ const lldb_private::DataExtractor& get_debug_line_data ();
+ const lldb_private::DataExtractor& get_debug_loc_data ();
+ const lldb_private::DataExtractor& get_debug_ranges_data ();
+ const lldb_private::DataExtractor& get_debug_str_data ();
+ const lldb_private::DataExtractor& get_apple_names_data ();
+ const lldb_private::DataExtractor& get_apple_types_data ();
+ const lldb_private::DataExtractor& get_apple_namespaces_data ();
+ const lldb_private::DataExtractor& get_apple_objc_data ();
+
+
+ DWARFDebugAbbrev* DebugAbbrev();
+ const DWARFDebugAbbrev* DebugAbbrev() const;
+
+ DWARFDebugInfo* DebugInfo();
+ const DWARFDebugInfo* DebugInfo() const;
+
+ DWARFDebugRanges* DebugRanges();
+ const DWARFDebugRanges* DebugRanges() const;
+
+ const lldb_private::DataExtractor&
+ GetCachedSectionData (uint32_t got_flag,
+ lldb::SectionType sect_type,
+ lldb_private::DataExtractor &data);
+
+ static bool
+ SupportedVersion(uint16_t version);
+
+ clang::DeclContext *
+ GetCachedClangDeclContextForDIE (const DWARFDebugInfoEntry *die)
+ {
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+ else
+ return NULL;
+ }
+
+ clang::DeclContext *
+ GetClangDeclContextForDIE (const lldb_private::SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIEOffset (const lldb_private::SymbolContext &sc, dw_offset_t die_offset);
+
+ clang::DeclContext *
+ GetClangDeclContextContainingDIE (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const DWARFDebugInfoEntry **decl_ctx_die);
+
+ clang::DeclContext *
+ GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset);
+
+ const DWARFDebugInfoEntry *
+ GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ void
+ SearchDeclContext (const clang::DeclContext *decl_context,
+ const char *name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results);
+
+ lldb_private::Flags&
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags&
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ bool
+ HasForwardDeclForClangType (const lldb_private::ClangASTType &clang_type);
+
+protected:
+
+ enum
+ {
+ flagsGotDebugAbbrevData = (1 << 0),
+ flagsGotDebugArangesData = (1 << 1),
+ flagsGotDebugFrameData = (1 << 2),
+ flagsGotDebugInfoData = (1 << 3),
+ flagsGotDebugLineData = (1 << 4),
+ flagsGotDebugLocData = (1 << 5),
+ flagsGotDebugMacInfoData = (1 << 6),
+ flagsGotDebugPubNamesData = (1 << 7),
+ flagsGotDebugPubTypesData = (1 << 8),
+ flagsGotDebugRangesData = (1 << 9),
+ flagsGotDebugStrData = (1 << 10),
+ flagsGotAppleNamesData = (1 << 11),
+ flagsGotAppleTypesData = (1 << 12),
+ flagsGotAppleNamespacesData = (1 << 13),
+ flagsGotAppleObjCData = (1 << 14)
+ };
+
+ bool NamespaceDeclMatchesThisSymbolFile (const lldb_private::ClangNamespaceDecl *namespace_decl);
+
+ bool DIEIsInNamespace (const lldb_private::ClangNamespaceDecl *namespace_decl,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry* die);
+
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF);
+ lldb::CompUnitSP ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx);
+ DWARFCompileUnit* GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit);
+ DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu);
+ lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* dwarf_cu, uint32_t cu_idx = UINT32_MAX);
+ bool GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc);
+ lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die);
+ size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc,
+ lldb_private::Block *parent_block,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb::addr_t subprogram_low_pc,
+ uint32_t depth);
+ size_t ParseTypes (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children);
+ lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new);
+ lldb_private::Type* ResolveTypeUID (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed);
+
+ lldb::VariableSP ParseVariableDIE(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb::addr_t func_low_pc);
+
+ size_t ParseVariables(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const lldb::addr_t func_low_pc,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children,
+ lldb_private::VariableList* cc_variable_list = NULL);
+
+ class DelayedAddObjCClassProperty;
+ typedef std::vector <DelayedAddObjCClassProperty> DelayedPropertyList;
+
+ bool ClassOrStructIsVirtual (
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die);
+
+ size_t ParseChildMembers(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::ClangASTType &class_clang_type,
+ const lldb::LanguageType class_language,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ DWARFDIECollection& member_function_dies,
+ DelayedPropertyList& delayed_properties,
+ lldb::AccessType &default_accessibility,
+ bool &is_a_class,
+ LayoutInfo &layout_info);
+
+ size_t ParseChildParameters(
+ const lldb_private::SymbolContext& sc,
+ clang::DeclContext *containing_decl_ctx,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ bool skip_artificial,
+ bool &is_static,
+ lldb_private::TypeList* type_list,
+ std::vector<lldb_private::ClangASTType>& function_args,
+ std::vector<clang::ParmVarDecl*>& function_param_decls,
+ unsigned &type_quals,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ size_t ParseChildEnumerators(
+ const lldb_private::SymbolContext& sc,
+ lldb_private::ClangASTType &clang_type,
+ bool is_signed,
+ uint32_t enumerator_byte_size,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *enum_die);
+
+ void ParseChildArrayInfo(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride);
+
+ // Given a die_offset, figure out the symbol context representing that die.
+ bool ResolveFunction (dw_offset_t offset,
+ DWARFCompileUnit *&dwarf_cu,
+ lldb_private::SymbolContextList& sc_list);
+
+ bool ResolveFunction (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::SymbolContextList& sc_list);
+
+ bool FunctionDieMatchesPartialName (
+ const DWARFDebugInfoEntry* die,
+ const DWARFCompileUnit *dwarf_cu,
+ uint32_t name_type_mask,
+ const char *partial_name,
+ const char *base_name_start,
+ const char *base_name_end);
+
+ void FindFunctions(
+ const lldb_private::ConstString &name,
+ const NameToDIE &name_to_die,
+ lldb_private::SymbolContextList& sc_list);
+
+ void FindFunctions (
+ const lldb_private::RegularExpression &regex,
+ const NameToDIE &name_to_die,
+ lldb_private::SymbolContextList& sc_list);
+
+ void FindFunctions (
+ const lldb_private::RegularExpression &regex,
+ 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);
+
+ lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE (
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::ConstString &type_name,
+ bool must_be_implementation);
+
+ bool Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu);
+
+ lldb::TypeSP FindCompleteObjCDefinitionType (const lldb_private::ConstString &type_name,
+ bool header_definition_ok);
+
+ lldb_private::Symbol * GetObjCClassSymbol (const lldb_private::ConstString &objc_class_name);
+
+ void ParseFunctions (const DIEArray &die_offsets,
+ lldb_private::SymbolContextList& sc_list);
+ lldb::TypeSP GetTypeForDIE (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry* die);
+
+ uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, lldb_private::TypeList& types);
+
+ void Index();
+
+ void DumpIndexes();
+
+ void SetDebugMapModule (const lldb::ModuleSP &module_sp)
+ {
+ m_debug_map_module_wp = module_sp;
+ }
+
+ SymbolFileDWARFDebugMap *
+ GetDebugMapSymfile ();
+
+ const DWARFDebugInfoEntry *
+ FindBlockContainingSpecification (dw_offset_t func_die_offset,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **dwarf_cu_handle);
+
+ const DWARFDebugInfoEntry *
+ FindBlockContainingSpecification (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **dwarf_cu_handle);
+
+ clang::NamespaceDecl *
+ ResolveNamespaceDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die);
+
+ UniqueDWARFASTTypeMap &
+ GetUniqueDWARFASTTypeMap ();
+
+ void LinkDeclContextToDIE (clang::DeclContext *decl_ctx,
+ const DWARFDebugInfoEntry *die)
+ {
+ m_die_to_decl_ctx[die] = decl_ctx;
+ // There can be many DIEs for a single decl context
+ m_decl_ctx_to_die[decl_ctx].insert(die);
+ }
+
+ bool
+ UserIDMatches (lldb::user_id_t uid) const
+ {
+ const lldb::user_id_t high_uid = uid & 0xffffffff00000000ull;
+ if (high_uid)
+ return high_uid == GetID();
+ return true;
+ }
+
+ lldb::user_id_t
+ MakeUserID (dw_offset_t die_offset) const
+ {
+ return GetID() | die_offset;
+ }
+
+ static bool
+ DeclKindIsCXXClass (clang::Decl::Kind decl_kind)
+ {
+ switch (decl_kind)
+ {
+ case clang::Decl::CXXRecord:
+ case clang::Decl::ClassTemplateSpecialization:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ bool
+ ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ bool
+ ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ clang::ClassTemplateDecl *
+ ParseClassTemplateDecl (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *parent_name,
+ int tag_decl_kind,
+ const lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ bool
+ DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1,
+ DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2);
+
+ bool
+ ClassContainsSelector (DWARFCompileUnit *dwarf_cu,
+ const DWARFDebugInfoEntry *class_die,
+ const lldb_private::ConstString &selector);
+
+ bool
+ CopyUniqueClassMethodTypes (SymbolFileDWARF *class_symfile,
+ lldb_private::Type *class_type,
+ DWARFCompileUnit* src_cu,
+ const DWARFDebugInfoEntry *src_class_die,
+ DWARFCompileUnit* dst_cu,
+ const DWARFDebugInfoEntry *dst_class_die,
+ llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures);
+
+ bool
+ FixupAddress (lldb_private::Address &addr);
+
+ typedef std::set<lldb_private::Type *> TypeSet;
+
+ void
+ GetTypes (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset,
+ uint32_t type_mask,
+ TypeSet &type_set);
+
+ lldb::ModuleWP m_debug_map_module_wp;
+ SymbolFileDWARFDebugMap * m_debug_map_symfile;
+ clang::TranslationUnitDecl * m_clang_tu_decl;
+ lldb_private::Flags m_flags;
+ lldb_private::DataExtractor m_dwarf_data;
+ lldb_private::DataExtractor m_data_debug_abbrev;
+ lldb_private::DataExtractor m_data_debug_aranges;
+ lldb_private::DataExtractor m_data_debug_frame;
+ lldb_private::DataExtractor m_data_debug_info;
+ lldb_private::DataExtractor m_data_debug_line;
+ lldb_private::DataExtractor m_data_debug_loc;
+ lldb_private::DataExtractor m_data_debug_ranges;
+ lldb_private::DataExtractor m_data_debug_str;
+ lldb_private::DataExtractor m_data_apple_names;
+ lldb_private::DataExtractor m_data_apple_types;
+ lldb_private::DataExtractor m_data_apple_namespaces;
+ lldb_private::DataExtractor m_data_apple_objc;
+
+ // The unique pointer items below are generated on demand if and when someone accesses
+ // them through a non const version of this class.
+ std::unique_ptr<DWARFDebugAbbrev> m_abbr;
+ std::unique_ptr<DWARFDebugInfo> m_info;
+ std::unique_ptr<DWARFDebugLine> m_line;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap;
+ NameToDIE m_function_basename_index; // All concrete functions
+ NameToDIE m_function_fullname_index; // All concrete functions
+ NameToDIE m_function_method_index; // All inlined functions
+ NameToDIE m_function_selector_index; // All method names for functions of classes
+ NameToDIE m_objc_class_selectors_index; // Given a class name, find all selectors for the class
+ NameToDIE m_global_index; // Global and static variables
+ NameToDIE m_type_index; // All type DIE offsets
+ NameToDIE m_namespace_index; // All type DIE offsets
+ bool m_indexed:1,
+ m_is_external_ast_source:1,
+ m_using_apple_tables:1;
+ lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+
+ std::unique_ptr<DWARFDebugRanges> m_ranges;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ typedef llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> DIEPointerSet;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap;
+ typedef llvm::DenseMap<const clang::DeclContext *, DIEPointerSet> DeclContextToDIEMap;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> DIEToVariableSP;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::clang_type_t> DIEToClangType;
+ typedef llvm::DenseMap<lldb::clang_type_t, const DWARFDebugInfoEntry *> ClangTypeToDIE;
+ typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> RecordDeclToLayoutMap;
+ DIEToDeclContextMap m_die_to_decl_ctx;
+ DeclContextToDIEMap m_decl_ctx_to_die;
+ DIEToTypePtr m_die_to_type;
+ DIEToVariableSP m_die_to_variable_sp;
+ DIEToClangType m_forward_decl_die_to_clang_type;
+ ClangTypeToDIE m_forward_decl_clang_type_to_die;
+ RecordDeclToLayoutMap m_record_decl_to_layout_map;
+};
+
+#endif // SymbolFileDWARF_SymbolFileDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
new file mode 100644
index 000000000000..a0430e3d52b6
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -0,0 +1,1586 @@
+//===-- SymbolFileDWARFDebugMap.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARFDebugMap.h"
+
+#include "DWARFDebugAranges.h"
+
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+
+//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT
+#if defined(DEBUG_OSO_DMAP)
+#include "lldb/Core/StreamFile.h"
+#endif
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Subclass lldb_private::Module so we can intercept the "Module::GetObjectFile()"
+// (so we can fixup the object file sections) and also for "Module::GetSymbolVendor()"
+// (so we can fixup the symbol file id.
+
+
+
+
+const SymbolFileDWARFDebugMap::FileRangeMap &
+SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile)
+{
+ if (file_range_map_valid)
+ return file_range_map;
+
+ file_range_map_valid = true;
+
+ Module *oso_module = exe_symfile->GetModuleByCompUnitInfo (this);
+ if (!oso_module)
+ return file_range_map;
+
+ ObjectFile *oso_objfile = oso_module->GetObjectFile();
+ if (!oso_objfile)
+ return file_range_map;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP));
+ if (log)
+ {
+ ConstString object_name (oso_module->GetObjectName());
+ log->Printf("%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')",
+ this,
+ oso_module->GetSpecificationDescription().c_str());
+ }
+
+
+ std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos;
+ if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos))
+ {
+ for (auto comp_unit_info : cu_infos)
+ {
+ Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab();
+ ModuleSP oso_module_sp (oso_objfile->GetModule());
+ Symtab *oso_symtab = oso_objfile->GetSymtab();
+
+ ///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction;
+ //SectionList *oso_sections = oso_objfile->Sections();
+ // Now we need to make sections that map from zero based object
+ // file addresses to where things eneded up in the main executable.
+
+ assert (comp_unit_info->first_symbol_index != UINT32_MAX);
+ // End index is one past the last valid symbol index
+ const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1;
+ for (uint32_t idx = comp_unit_info->first_symbol_index + 2; // Skip the N_SO and N_OSO
+ idx < oso_end_idx;
+ ++idx)
+ {
+ Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx);
+ if (exe_symbol)
+ {
+ if (exe_symbol->IsDebug() == false)
+ continue;
+
+ switch (exe_symbol->GetType())
+ {
+ default:
+ break;
+
+ case eSymbolTypeCode:
+ {
+ // For each N_FUN, or function that we run into in the debug map
+ // we make a new section that we add to the sections found in the
+ // .o file. This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable.
+
+ // First we find the original symbol in the .o file's symbol table
+ Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeCode,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+ if (oso_fun_symbol)
+ {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange (this,
+ exe_symbol->GetAddress().GetFileAddress(),
+ oso_fun_symbol->GetAddress().GetFileAddress(),
+ std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize()));
+
+ }
+ }
+ break;
+
+ case eSymbolTypeData:
+ {
+ // For each N_GSYM we remap the address for the global by making
+ // a new section that we add to the sections found in the .o file.
+ // This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable. We
+ // initially set the section size to be 1 byte, but will need to
+ // fix up these addresses further after all globals have been
+ // parsed to span the gaps, or we can find the global variable
+ // sizes from the DWARF info as we are parsing.
+
+ // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file
+ Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeData,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+
+ if (exe_symbol && oso_gsym_symbol &&
+ exe_symbol->ValueIsAddress() &&
+ oso_gsym_symbol->ValueIsAddress())
+ {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange (this,
+ exe_symbol->GetAddress().GetFileAddress(),
+ oso_gsym_symbol->GetAddress().GetFileAddress(),
+ std::min<addr_t>(exe_symbol->GetByteSize(), oso_gsym_symbol->GetByteSize()));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ exe_symfile->FinalizeOSOFileRanges (this);
+ // We don't need the symbols anymore for the .o files
+ oso_objfile->ClearSymtab();
+ }
+ }
+ return file_range_map;
+}
+
+
+class DebugMapModule : public Module
+{
+public:
+ DebugMapModule (const ModuleSP &exe_module_sp,
+ uint32_t cu_idx,
+ const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const ConstString *object_name,
+ off_t object_offset,
+ const TimeValue *object_mod_time_ptr) :
+ Module (file_spec, arch, object_name, object_offset, object_mod_time_ptr),
+ m_exe_module_wp (exe_module_sp),
+ m_cu_idx (cu_idx)
+ {
+ }
+
+ virtual
+ ~DebugMapModule ()
+ {
+ }
+
+
+ virtual SymbolVendor*
+ GetSymbolVendor(bool can_create = true, lldb_private::Stream *feedback_strm = NULL)
+ {
+ // Scope for locker
+ if (m_symfile_ap.get() || can_create == false)
+ return m_symfile_ap.get();
+
+ ModuleSP exe_module_sp (m_exe_module_wp.lock());
+ if (exe_module_sp)
+ {
+ // Now get the object file outside of a locking scope
+ ObjectFile *oso_objfile = GetObjectFile ();
+ if (oso_objfile)
+ {
+ Mutex::Locker locker (m_mutex);
+ SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm);
+ if (symbol_vendor)
+ {
+ // Set a a pointer to this class to set our OSO DWARF file know
+ // that the DWARF is being used along with a debug map and that
+ // it will have the remapped sections that we do below.
+ SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symbol_vendor->GetSymbolFile());
+
+ if (!oso_symfile)
+ return NULL;
+
+ ObjectFile *exe_objfile = exe_module_sp->GetObjectFile();
+ SymbolVendor *exe_sym_vendor = exe_module_sp->GetSymbolVendor();
+
+ if (exe_objfile && exe_sym_vendor)
+ {
+ if (oso_symfile->GetNumCompileUnits() == 1)
+ {
+ oso_symfile->SetDebugMapModule(exe_module_sp);
+ // Set the ID of the symbol file DWARF to the index of the OSO
+ // shifted left by 32 bits to provide a unique prefix for any
+ // UserID's that get created in the symbol file.
+ oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull);
+ }
+ else
+ {
+ oso_symfile->SetID (UINT64_MAX);
+ }
+ }
+ return symbol_vendor;
+ }
+ }
+ }
+ return NULL;
+ }
+
+protected:
+ ModuleWP m_exe_module_wp;
+ const uint32_t m_cu_idx;
+};
+
+void
+SymbolFileDWARFDebugMap::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARFDebugMap::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolFileDWARFDebugMap::GetPluginNameStatic()
+{
+ static ConstString g_name("dwarf-debugmap");
+ return g_name;
+}
+
+const char *
+SymbolFileDWARFDebugMap::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader (debug map).";
+}
+
+SymbolFile*
+SymbolFileDWARFDebugMap::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARFDebugMap (obj_file);
+}
+
+
+SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap (ObjectFile* ofile) :
+ SymbolFile(ofile),
+ m_flags(),
+ m_compile_unit_infos(),
+ m_func_indexes(),
+ m_glob_indexes(),
+ m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate)
+{
+}
+
+
+SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap()
+{
+}
+
+void
+SymbolFileDWARFDebugMap::InitializeObject()
+{
+ // Install our external AST source callbacks so we can complete Clang types.
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl,
+ SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl,
+ NULL,
+ SymbolFileDWARFDebugMap::LayoutRecordType,
+ this));
+
+ GetClangASTContext().SetExternalSource (ast_source_ap);
+}
+
+void
+SymbolFileDWARFDebugMap::InitOSO()
+{
+ if (m_flags.test(kHaveInitializedOSOs))
+ return;
+
+ m_flags.set(kHaveInitializedOSOs);
+
+ // If the object file has been stripped, there is no sense in looking further
+ // as all of the debug symbols for the debug map will not be available
+ if (m_obj_file->IsStripped())
+ return;
+
+ // Also make sure the file type is some sort of executable. Core files, debug
+ // info files (dSYM), object files (.o files), and stub libraries all can
+ switch (m_obj_file->GetType())
+ {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeUnknown:
+ return;
+
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeSharedLibrary:
+ break;
+ }
+
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP));
+
+ std::vector<uint32_t> oso_indexes;
+ // When a mach-o symbol is encoded, the n_type field is encoded in bits
+ // 23:16, and the n_desc field is encoded in bits 15:0.
+ //
+ // To find all N_OSO entries that are part of the DWARF + debug map
+ // we find only object file symbols with the flags value as follows:
+ // bits 23:16 == 0x66 (N_OSO)
+ // bits 15: 0 == 0x0001 (specifies this is a debug map object file)
+ const uint32_t k_oso_symbol_flags_value = 0x660001u;
+
+ const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithTypeAndFlagsValue(eSymbolTypeObjectFile, k_oso_symbol_flags_value, oso_indexes);
+
+ if (oso_index_count > 0)
+ {
+ symtab->AppendSymbolIndexesWithType (eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes);
+ symtab->AppendSymbolIndexesWithType (eSymbolTypeData, Symtab::eDebugYes, Symtab::eVisibilityAny, m_glob_indexes);
+
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ symtab->SortSymbolIndexesByValue(m_glob_indexes, true);
+
+ for (uint32_t sym_idx : m_func_indexes)
+ {
+ const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
+ lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t byte_size = symbol->GetByteSize();
+ DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
+ m_debug_map.Append(debug_map_entry);
+ }
+ for (uint32_t sym_idx : m_glob_indexes)
+ {
+ const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
+ lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t byte_size = symbol->GetByteSize();
+ DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
+ m_debug_map.Append(debug_map_entry);
+ }
+ m_debug_map.Sort();
+
+ m_compile_unit_infos.resize(oso_index_count);
+
+ for (uint32_t i=0; i<oso_index_count; ++i)
+ {
+ const uint32_t so_idx = oso_indexes[i] - 1;
+ const uint32_t oso_idx = oso_indexes[i];
+ const Symbol *so_symbol = symtab->SymbolAtIndex(so_idx);
+ const Symbol *oso_symbol = symtab->SymbolAtIndex(oso_idx);
+ if (so_symbol &&
+ oso_symbol &&
+ so_symbol->GetType() == eSymbolTypeSourceFile &&
+ oso_symbol->GetType() == eSymbolTypeObjectFile)
+ {
+ m_compile_unit_infos[i].so_file.SetFile(so_symbol->GetName().AsCString(), false);
+ m_compile_unit_infos[i].oso_path = oso_symbol->GetName();
+ TimeValue oso_mod_time;
+ oso_mod_time.OffsetWithSeconds(oso_symbol->GetAddress().GetOffset());
+ m_compile_unit_infos[i].oso_mod_time = oso_mod_time;
+ uint32_t sibling_idx = so_symbol->GetSiblingIndex();
+ // The sibling index can't be less that or equal to the current index "i"
+ if (sibling_idx <= i)
+ {
+ m_obj_file->GetModule()->ReportError ("N_SO in symbol with UID %u has invalid sibling in debug map, please file a bug and attach the binary listed in this error", so_symbol->GetID());
+ }
+ else
+ {
+ const Symbol* last_symbol = symtab->SymbolAtIndex (sibling_idx - 1);
+ m_compile_unit_infos[i].first_symbol_index = so_idx;
+ m_compile_unit_infos[i].last_symbol_index = sibling_idx - 1;
+ m_compile_unit_infos[i].first_symbol_id = so_symbol->GetID();
+ m_compile_unit_infos[i].last_symbol_id = last_symbol->GetID();
+
+ if (log)
+ log->Printf("Initialized OSO 0x%8.8x: file=%s", i, oso_symbol->GetName().GetCString());
+ }
+ }
+ else
+ {
+ if (oso_symbol == NULL)
+ m_obj_file->GetModule()->ReportError ("N_OSO symbol[%u] can't be found, please file a bug and attach the binary listed in this error", oso_idx);
+ else if (so_symbol == NULL)
+ m_obj_file->GetModule()->ReportError ("N_SO not found for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_idx);
+ else if (so_symbol->GetType() != eSymbolTypeSourceFile)
+ m_obj_file->GetModule()->ReportError ("N_SO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", so_symbol->GetType(), oso_idx);
+ else if (oso_symbol->GetType() != eSymbolTypeSourceFile)
+ m_obj_file->GetModule()->ReportError ("N_OSO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_symbol->GetType(), oso_idx);
+ }
+ }
+ }
+ }
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByOSOIndex (uint32_t oso_idx)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ if (oso_idx < cu_count)
+ return GetModuleByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ if (!comp_unit_info->oso_sp)
+ {
+ auto pos = m_oso_map.find (comp_unit_info->oso_path);
+ if (pos != m_oso_map.end())
+ {
+ comp_unit_info->oso_sp = pos->second;
+ }
+ else
+ {
+ ObjectFile *obj_file = GetObjectFile();
+ comp_unit_info->oso_sp.reset (new OSOInfo());
+ m_oso_map[comp_unit_info->oso_path] = comp_unit_info->oso_sp;
+ const char *oso_path = comp_unit_info->oso_path.GetCString();
+ FileSpec oso_file (oso_path, false);
+ ConstString oso_object;
+ if (oso_file.Exists())
+ {
+ TimeValue oso_mod_time (oso_file.GetModificationTime());
+ if (oso_mod_time != comp_unit_info->oso_mod_time)
+ {
+ obj_file->GetModule()->ReportError ("debug map object file '%s' has changed (actual time is 0x%" PRIx64 ", debug map time is 0x%" PRIx64 ") since this executable was linked, file will be ignored",
+ oso_file.GetPath().c_str(),
+ oso_mod_time.GetAsSecondsSinceJan1_1970(),
+ comp_unit_info->oso_mod_time.GetAsSecondsSinceJan1_1970());
+ return NULL;
+ }
+
+ }
+ else
+ {
+ const bool must_exist = true;
+
+ if (!ObjectFile::SplitArchivePathWithObject (oso_path,
+ oso_file,
+ oso_object,
+ must_exist))
+ {
+ return NULL;
+ }
+ }
+ // Always create a new module for .o files. Why? Because we
+ // use the debug map, to add new sections to each .o file and
+ // even though a .o file might not have changed, the sections
+ // that get added to the .o file can change.
+ comp_unit_info->oso_sp->module_sp.reset (new DebugMapModule (obj_file->GetModule(),
+ GetCompUnitInfoIndex(comp_unit_info),
+ oso_file,
+ m_obj_file->GetModule()->GetArchitecture(),
+ oso_object ? &oso_object : NULL,
+ 0,
+ oso_object ? &comp_unit_info->oso_mod_time : NULL));
+ }
+ }
+ if (comp_unit_info->oso_sp)
+ return comp_unit_info->oso_sp->module_sp.get();
+ return NULL;
+}
+
+
+bool
+SymbolFileDWARFDebugMap::GetFileSpecForSO (uint32_t oso_idx, FileSpec &file_spec)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ {
+ if (m_compile_unit_infos[oso_idx].so_file)
+ {
+ file_spec = m_compile_unit_infos[oso_idx].so_file;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex (uint32_t oso_idx)
+{
+ Module *oso_module = GetModuleByOSOIndex (oso_idx);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFile (const SymbolContext& sc)
+{
+ CompileUnitInfo *comp_unit_info = GetCompUnitInfo (sc);
+ if (comp_unit_info)
+ return GetSymbolFileByCompUnitInfo (comp_unit_info);
+ return NULL;
+}
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info)
+{
+ if (!m_compile_unit_infos.empty())
+ {
+ const CompileUnitInfo *first_comp_unit_info = &m_compile_unit_infos.front();
+ const CompileUnitInfo *last_comp_unit_info = &m_compile_unit_infos.back();
+ if (first_comp_unit_info <= comp_unit_info && comp_unit_info <= last_comp_unit_info)
+ return comp_unit_info - first_comp_unit_info;
+ }
+ return UINT32_MAX;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex (uint32_t oso_idx)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ return GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file)
+{
+ if (sym_file && sym_file->GetPluginName() == SymbolFileDWARF::GetPluginNameStatic())
+ return (SymbolFileDWARF *)sym_file;
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ {
+ SymbolVendor *sym_vendor = oso_module->GetSymbolVendor();
+ if (sym_vendor)
+ return GetSymbolFileAsSymbolFileDWARF (sym_vendor->GetSymbolFile());
+ }
+ return NULL;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::CalculateAbilities ()
+{
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ const uint32_t oso_index_count = GetNumCompileUnits();
+ if (oso_index_count > 0)
+ {
+ InitOSO();
+ if (!m_compile_unit_infos.empty())
+ {
+ return SymbolFile::CompileUnits |
+ SymbolFile::Functions |
+ SymbolFile::Blocks |
+ SymbolFile::GlobalVariables |
+ SymbolFile::LocalVariables |
+ SymbolFile::VariableTypes |
+ SymbolFile::LineTables ;
+ }
+ }
+ return 0;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetNumCompileUnits()
+{
+ InitOSO ();
+ return m_compile_unit_infos.size();
+}
+
+
+CompUnitSP
+SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP comp_unit_sp;
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ if (cu_idx < cu_count)
+ {
+ Module *oso_module = GetModuleByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_module)
+ {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO (cu_idx, so_file_spec))
+ {
+ // User zero as the ID to match the compile unit at offset
+ // zero in each .o file since each .o file can only have
+ // one compile unit for now.
+ lldb::user_id_t cu_id = 0;
+ m_compile_unit_infos[cu_idx].compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(),
+ NULL,
+ so_file_spec,
+ cu_id,
+ eLanguageTypeUnknown));
+
+ if (m_compile_unit_infos[cu_idx].compile_unit_sp)
+ {
+ // Let our symbol vendor know about this compile unit
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex (cu_idx, m_compile_unit_infos[cu_idx].compile_unit_sp);
+ }
+ }
+ }
+ comp_unit_sp = m_compile_unit_infos[cu_idx].compile_unit_sp;
+ }
+
+ return comp_unit_sp;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompUnitInfo (const SymbolContext& sc)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (sc.comp_unit == m_compile_unit_infos[i].compile_unit_sp.get())
+ return &m_compile_unit_infos[i];
+ }
+ return NULL;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::GetCompUnitInfosForModule (const lldb_private::Module *module, std::vector<CompileUnitInfo *>& cu_infos)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (module == GetModuleByCompUnitInfo (&m_compile_unit_infos[i]))
+ cu_infos.push_back (&m_compile_unit_infos[i]);
+ }
+ return cu_infos.size();
+}
+
+lldb::LanguageType
+SymbolFileDWARFDebugMap::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitLanguage (sc);
+ return eLanguageTypeUnknown;
+}
+
+size_t
+SymbolFileDWARFDebugMap::ParseCompileUnitFunctions (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitFunctions (sc);
+ return 0;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitLineTable (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitLineTable (sc);
+ return false;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitSupportFiles (sc, support_files);
+ return false;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseFunctionBlocks (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseTypes (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseTypes (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseVariablesForContext (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseVariablesForContext (sc);
+ return 0;
+}
+
+
+
+Type*
+SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->ResolveTypeUID (type_uid);
+ return NULL;
+}
+
+bool
+SymbolFileDWARFDebugMap::ResolveClangOpaqueTypeDefinition (ClangASTType& clang_type)
+{
+ // We have a struct/union/class/enum that needs to be fully resolved.
+ return false;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const Address& exe_so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ uint32_t resolved_flags = 0;
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ const addr_t exe_file_addr = exe_so_addr.GetFileAddress();
+
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains (exe_file_addr);
+ if (debug_map_entry)
+ {
+
+ sc.symbol = symtab->SymbolAtIndex(debug_map_entry->data.GetExeSymbolIndex());
+
+ if (sc.symbol != NULL)
+ {
+ resolved_flags |= eSymbolContextSymbol;
+
+ uint32_t oso_idx = 0;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithID (sc.symbol->GetID(), &oso_idx);
+ if (comp_unit_info)
+ {
+ comp_unit_info->GetFileRangeMap(this);
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ {
+ lldb::addr_t oso_file_addr = exe_file_addr - debug_map_entry->GetRangeBase() + debug_map_entry->data.GetOSOFileAddress();
+ Address oso_so_addr;
+ if (oso_module->ResolveFileAddress(oso_file_addr, oso_so_addr))
+ {
+ resolved_flags |= oso_module->GetSymbolVendor()->ResolveSymbolContext (oso_so_addr, resolve_scope, sc);
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ const uint32_t initial = sc_list.GetSize();
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ // If we are checking for inlines, then we need to look through all
+ // compile units no matter if "file_spec" matches.
+ bool resolve = check_inlines;
+
+ if (!resolve)
+ {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO (i, so_file_spec))
+ {
+ // Match the full path if the incoming file_spec has a directory (not just a basename)
+ const bool full_match = file_spec.GetDirectory();
+ resolve = FileSpec::Equal (file_spec, so_file_spec, full_match);
+ }
+ }
+ if (resolve)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i);
+ if (oso_dwarf)
+ oso_dwarf->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::PrivateFindGlobalVariables
+(
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ const std::vector<uint32_t> &indexes, // Indexes into the symbol table that match "name"
+ uint32_t max_matches,
+ VariableList& variables
+)
+{
+ const uint32_t original_size = variables.GetSize();
+ const size_t match_count = indexes.size();
+ for (size_t i=0; i<match_count; ++i)
+ {
+ uint32_t oso_idx;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ {
+ if (oso_dwarf->FindGlobalVariables(name, namespace_decl, true, max_matches, variables))
+ if (variables.GetSize() > max_matches)
+ break;
+ }
+ }
+ }
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ uint32_t total_matches = 0;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (name,
+ namespace_decl,
+ true,
+ max_matches,
+ variables);
+ if (oso_matches > 0)
+ {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ break;
+
+ // Update the max matches for any subsequent calls to find globals
+ // in any other object files with DWARF
+ max_matches -= oso_matches;
+ }
+ }
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ uint32_t total_matches = 0;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (regex,
+ true,
+ max_matches,
+ variables);
+ if (oso_matches > 0)
+ {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ break;
+
+ // Update the max matches for any subsequent calls to find globals
+ // in any other object files with DWARF
+ max_matches -= oso_matches;
+ }
+ }
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const uint32_t symbol_idx = *symbol_idx_ptr;
+
+ if (symbol_idx < comp_unit_info->first_symbol_index)
+ return -1;
+
+ if (symbol_idx <= comp_unit_info->last_symbol_index)
+ return 0;
+
+ return 1;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolWithID (user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const user_id_t symbol_id = *symbol_idx_ptr;
+
+ if (symbol_id < comp_unit_info->first_symbol_id)
+ return -1;
+
+ if (symbol_id <= comp_unit_info->last_symbol_id)
+ return 0;
+
+ return 1;
+}
+
+
+SymbolFileDWARFDebugMap::CompileUnitInfo*
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr)
+{
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = NULL;
+ if (oso_index_count)
+ {
+ comp_unit_info = (CompileUnitInfo*)bsearch(&symbol_idx,
+ &m_compile_unit_infos[0],
+ m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithIndex);
+ }
+
+ if (oso_idx_ptr)
+ {
+ if (comp_unit_info != NULL)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo*
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID (user_id_t symbol_id, uint32_t *oso_idx_ptr)
+{
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = NULL;
+ if (oso_index_count)
+ {
+ comp_unit_info = (CompileUnitInfo*)::bsearch (&symbol_id,
+ &m_compile_unit_infos[0],
+ m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithID);
+ }
+
+ if (oso_idx_ptr)
+ {
+ if (comp_unit_info != NULL)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+
+static void
+RemoveFunctionsWithModuleNotEqualTo (const ModuleSP &module_sp, SymbolContextList &sc_list, uint32_t start_idx)
+{
+ // We found functions in .o files. Not all functions in the .o files
+ // will have made it into the final output file. The ones that did
+ // make it into the final output file will have a section whose module
+ // matches the module from the ObjectFile for this SymbolFile. When
+ // the modules don't match, then we have something that was in a
+ // .o file, but doesn't map to anything in the final executable.
+ uint32_t i=start_idx;
+ while (i < sc_list.GetSize())
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.function)
+ {
+ const SectionSP section_sp (sc.function->GetAddressRange().GetBaseAddress().GetSection());
+ if (section_sp->GetModule() != module_sp)
+ {
+ sc_list.RemoveContextAtIndex(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
+ name.GetCString());
+
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ uint32_t oso_idx = 0;
+ SymbolFileDWARF *oso_dwarf;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ uint32_t sc_idx = sc_list.GetSize();
+ if (oso_dwarf->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, true, sc_list))
+ {
+ RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
+ }
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ uint32_t oso_idx = 0;
+ SymbolFileDWARF *oso_dwarf;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ uint32_t sc_idx = sc_list.GetSize();
+
+ if (oso_dwarf->FindFunctions(regex, include_inlines, true, sc_list))
+ {
+ RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
+ }
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+SymbolFileDWARFDebugMap::GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ TypeList &type_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)",
+ type_mask);
+
+
+ uint32_t initial_size = type_list.GetSize();
+ SymbolFileDWARF *oso_dwarf = NULL;
+ if (sc_scope)
+ {
+ SymbolContext sc;
+ sc_scope->CalculateSymbolContext(&sc);
+
+ CompileUnitInfo *cu_info = GetCompUnitInfo (sc);
+ if (cu_info)
+ {
+ oso_dwarf = GetSymbolFileByCompUnitInfo (cu_info);
+ if (oso_dwarf)
+ oso_dwarf->GetTypes (sc_scope, type_mask, type_list);
+ }
+ }
+ else
+ {
+ uint32_t oso_idx = 0;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ oso_dwarf->GetTypes (sc_scope, type_mask, type_list);
+ }
+ }
+ return type_list.GetSize() - initial_size;
+}
+
+
+TypeSP
+SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx)
+{
+ TypeSP type_sp;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+ if (type_sp)
+ break;
+ }
+ return type_sp;
+}
+
+
+
+bool
+SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso)
+{
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate)
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (skip_dwarf_oso != oso_dwarf && oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(NULL))
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ break;
+ }
+ }
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+TypeSP
+SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const ConstString &type_name,
+ bool must_be_implementation)
+{
+ TypeSP type_sp;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation);
+ if (type_sp)
+ break;
+ }
+ return type_sp;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindTypes
+(
+ const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ TypeList& types
+)
+{
+ if (!append)
+ types.Clear();
+
+ const uint32_t initial_types_size = types.GetSize();
+ SymbolFileDWARF *oso_dwarf;
+
+ if (sc.comp_unit)
+ {
+ oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types);
+ }
+ else
+ {
+ uint32_t oso_idx = 0;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types);
+ }
+
+ return types.GetSize() - initial_types_size;
+}
+
+//
+//uint32_t
+//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+// if (oso_dwarf)
+// return oso_dwarf->FindTypes (sc, regex, append, max_matches, encoding, udt_uid, types);
+// return 0;
+//}
+
+
+ClangNamespaceDecl
+SymbolFileDWARFDebugMap::FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const ClangNamespaceDecl *parent_namespace_decl)
+{
+ ClangNamespaceDecl matching_namespace;
+ SymbolFileDWARF *oso_dwarf;
+
+ if (sc.comp_unit)
+ {
+ oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl);
+ }
+ else
+ {
+ for (uint32_t oso_idx = 0;
+ ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL);
+ ++oso_idx)
+ {
+ matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl);
+
+ if (matching_namespace)
+ break;
+ }
+ }
+
+ return matching_namespace;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SymbolFileDWARFDebugMap::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::CompUnitSP
+SymbolFileDWARFDebugMap::GetCompileUnit (SymbolFileDWARF *oso_dwarf)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ if (!m_compile_unit_infos[cu_idx].compile_unit_sp)
+ m_compile_unit_infos[cu_idx].compile_unit_sp = ParseCompileUnitAtIndex (cu_idx);
+
+ return m_compile_unit_infos[cu_idx].compile_unit_sp;
+ }
+ }
+ }
+ assert(!"this shouldn't happen");
+ return lldb::CompUnitSP();
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ return &m_compile_unit_infos[cu_idx];
+ }
+ }
+ }
+ return NULL;
+}
+
+
+void
+SymbolFileDWARFDebugMap::SetCompileUnit (SymbolFileDWARF *oso_dwarf, const CompUnitSP &cu_sp)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ if (m_compile_unit_infos[cu_idx].compile_unit_sp)
+ {
+ assert (m_compile_unit_infos[cu_idx].compile_unit_sp.get() == cu_sp.get());
+ }
+ else
+ {
+ m_compile_unit_infos[cu_idx].compile_unit_sp = cu_sp;
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp);
+ }
+ }
+ }
+ }
+}
+
+
+void
+SymbolFileDWARFDebugMap::CompleteTagDecl (void *baton, clang::TagDecl *decl)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ {
+ SymbolFileDWARF *oso_dwarf;
+
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->HasForwardDeclForClangType (clang_type))
+ {
+ oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+ return;
+ }
+ }
+ }
+}
+
+void
+SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ {
+ SymbolFileDWARF *oso_dwarf;
+
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->HasForwardDeclForClangType (clang_type))
+ {
+ oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+ return;
+ }
+ }
+ }
+}
+
+bool
+SymbolFileDWARFDebugMap::LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets))
+ return true;
+ }
+ return false;
+}
+
+
+
+clang::DeclContext*
+SymbolFileDWARFDebugMap::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->GetClangDeclContextContainingTypeUID (type_uid);
+ return NULL;
+}
+
+clang::DeclContext*
+SymbolFileDWARFDebugMap::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->GetClangDeclContextForTypeUID (sc, type_uid);
+ return NULL;
+}
+
+bool
+SymbolFileDWARFDebugMap::AddOSOFileRange (CompileUnitInfo *cu_info,
+ lldb::addr_t exe_file_addr,
+ lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size)
+{
+ const uint32_t debug_map_idx = m_debug_map.FindEntryIndexThatContains(exe_file_addr);
+ if (debug_map_idx != UINT32_MAX)
+ {
+ DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(exe_file_addr);
+ debug_map_entry->data.SetOSOFileAddress(oso_file_addr);
+ cu_info->file_range_map.Append(FileRangeMap::Entry(oso_file_addr, oso_byte_size, exe_file_addr));
+ return true;
+ }
+ return false;
+}
+
+void
+SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (CompileUnitInfo *cu_info)
+{
+ cu_info->file_range_map.Sort();
+#if defined(DEBUG_OSO_DMAP)
+ const FileRangeMap &oso_file_range_map = cu_info->GetFileRangeMap(this);
+ const size_t n = oso_file_range_map.GetSize();
+ printf ("SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (cu_info = %p) %s\n",
+ cu_info,
+ cu_info->oso_sp->module_sp->GetFileSpec().GetPath().c_str());
+ for (size_t i=0; i<n; ++i)
+ {
+ const FileRangeMap::Entry &entry = oso_file_range_map.GetEntryRef(i);
+ printf ("oso [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") ==> exe [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n",
+ entry.GetRangeBase(), entry.GetRangeEnd(),
+ entry.data, entry.data + entry.GetByteSize());
+ }
+#endif
+}
+
+lldb::addr_t
+SymbolFileDWARFDebugMap::LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr)
+{
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_symfile);
+ if (cu_info)
+ {
+ const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry)
+ {
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry)
+ {
+ const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset;
+ return exe_file_addr;
+ }
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+SymbolFileDWARFDebugMap::LinkOSOAddress (Address &addr)
+{
+ // Make sure this address hasn't been fixed already
+ Module *exe_module = GetObjectFile()->GetModule().get();
+ Module *addr_module = addr.GetModule().get();
+ if (addr_module == exe_module)
+ return true; // Address is already in terms of the main executable module
+
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (GetSymbolFileAsSymbolFileDWARF(addr_module->GetSymbolVendor()->GetSymbolFile()));
+ if (cu_info)
+ {
+ const lldb::addr_t oso_file_addr = addr.GetFileAddress();
+ const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry)
+ {
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry)
+ {
+ const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset;
+ return exe_module->ResolveFileAddress(exe_file_addr, addr);
+ }
+ }
+ }
+ return true;
+}
+
+LineTable *
+SymbolFileDWARFDebugMap::LinkOSOLineTable (SymbolFileDWARF *oso_dwarf, LineTable *line_table)
+{
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_dwarf);
+ if (cu_info)
+ return line_table->LinkLineTable(cu_info->GetFileRangeMap(this));
+ return NULL;
+}
+
+size_t
+SymbolFileDWARFDebugMap::AddOSOARanges (SymbolFileDWARF* dwarf2Data, DWARFDebugAranges* debug_aranges)
+{
+ size_t num_line_entries_added = 0;
+ if (debug_aranges && dwarf2Data)
+ {
+ CompileUnitInfo *compile_unit_info = GetCompileUnitInfo(dwarf2Data);
+ if (compile_unit_info)
+ {
+ const FileRangeMap &file_range_map = compile_unit_info->GetFileRangeMap(this);
+ for (size_t idx = 0;
+ idx < file_range_map.GetSize();
+ idx++)
+ {
+ const FileRangeMap::Entry* entry = file_range_map.GetEntryAtIndex(idx);
+ if (entry)
+ {
+ printf ("[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", entry->GetRangeBase(), entry->GetRangeEnd());
+ debug_aranges->AppendRange(dwarf2Data->GetID(), entry->GetRangeBase(), entry->GetRangeEnd());
+ num_line_entries_added++;
+ }
+ }
+ }
+ }
+ return num_line_entries_added;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
new file mode 100644
index 000000000000..06330b98dc19
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -0,0 +1,420 @@
+//===-- SymbolFileDWARFDebugMap.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
+#define SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
+
+
+#include <vector>
+#include <bitset>
+
+#include "clang/AST/CharUnits.h"
+
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+#include "UniqueDWARFASTType.h"
+
+class SymbolFileDWARF;
+class DWARFCompileUnit;
+class DWARFDebugAranges;
+class DWARFDebugInfoEntry;
+class DWARFDeclContext;
+class DebugMapModule;
+
+class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile
+{
+public:
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile);
+ virtual ~ SymbolFileDWARFDebugMap ();
+
+ virtual uint32_t CalculateAbilities ();
+
+ virtual void InitializeObject();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits ();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index);
+
+ virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid);
+ virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+ virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+
+ //------------------------------------------------------------------
+ // ClangASTContext callbacks for external source lookups.
+ //------------------------------------------------------------------
+ static void
+ CompleteTagDecl (void *baton, clang::TagDecl *);
+
+ static void
+ CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *);
+
+ static bool
+ LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ enum
+ {
+ kHaveInitializedOSOs = (1 << 0),
+ kNumFlags
+ };
+
+ friend class DWARFCompileUnit;
+ friend class SymbolFileDWARF;
+ friend class DebugMapModule;
+ struct OSOInfo
+ {
+ lldb::ModuleSP module_sp;
+
+ OSOInfo() :
+ module_sp ()
+ {
+ }
+ };
+
+ typedef std::shared_ptr<OSOInfo> OSOInfoSP;
+
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> FileRangeMap;
+
+ //------------------------------------------------------------------
+ // Class specific types
+ //------------------------------------------------------------------
+ struct CompileUnitInfo
+ {
+ lldb_private::FileSpec so_file;
+ lldb_private::ConstString oso_path;
+ lldb_private::TimeValue oso_mod_time;
+ OSOInfoSP oso_sp;
+ lldb::CompUnitSP compile_unit_sp;
+ uint32_t first_symbol_index;
+ uint32_t last_symbol_index;
+ uint32_t first_symbol_id;
+ uint32_t last_symbol_id;
+ FileRangeMap file_range_map;
+ bool file_range_map_valid;
+
+
+ CompileUnitInfo() :
+ so_file (),
+ oso_path (),
+ oso_mod_time (),
+ oso_sp (),
+ compile_unit_sp (),
+ first_symbol_index (UINT32_MAX),
+ last_symbol_index (UINT32_MAX),
+ first_symbol_id (UINT32_MAX),
+ last_symbol_id (UINT32_MAX),
+ file_range_map (),
+ file_range_map_valid (false)
+ {
+ }
+
+ const FileRangeMap &
+ GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile);
+ };
+
+ //------------------------------------------------------------------
+ // Protected Member Functions
+ //------------------------------------------------------------------
+ void
+ InitOSO ();
+
+ static uint32_t
+ GetOSOIndexFromUserID (lldb::user_id_t uid)
+ {
+ return (uint32_t)((uid >> 32ull) - 1ull);
+ }
+
+ static SymbolFileDWARF *
+ GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file);
+
+ bool
+ GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec);
+
+ CompileUnitInfo *
+ GetCompUnitInfo (const lldb_private::SymbolContext& sc);
+
+ size_t
+ GetCompUnitInfosForModule (const lldb_private::Module *oso_module,
+ std::vector<CompileUnitInfo *>& cu_infos);
+
+ lldb_private::Module *
+ GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::Module *
+ GetModuleByOSOIndex (uint32_t oso_idx);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByOSOIndex (uint32_t oso_idx);
+
+ uint32_t
+ GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *
+ GetSymbolFile (const lldb_private::SymbolContext& sc);
+
+ SymbolFileDWARF *
+ GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *
+ GetSymbolFileByOSOIndex (uint32_t oso_idx);
+
+ CompileUnitInfo *
+ GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr);
+
+ CompileUnitInfo *
+ GetCompileUnitInfoForSymbolWithID (lldb::user_id_t symbol_id, uint32_t *oso_idx_ptr);
+
+ static int
+ SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ static int
+ SymbolContainsSymbolWithID (lldb::user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ uint32_t
+ PrivateFindGlobalVariables (const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ const std::vector<uint32_t> &name_symbol_indexes,
+ uint32_t max_matches,
+ lldb_private::VariableList& variables);
+
+
+ void
+ SetCompileUnit (SymbolFileDWARF *oso_dwarf, const lldb::CompUnitSP &cu_sp);
+
+ lldb::CompUnitSP
+ GetCompileUnit (SymbolFileDWARF *oso_dwarf);
+
+ CompileUnitInfo *
+ GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf);
+
+ lldb::TypeSP
+ FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx);
+
+ bool
+ Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso);
+
+ lldb::TypeSP
+ FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const lldb_private::ConstString &type_name,
+ bool must_be_implementation);
+
+
+ UniqueDWARFASTTypeMap &
+ GetUniqueDWARFASTTypeMap ()
+ {
+ return m_unique_ast_type_map;
+ }
+
+
+ //------------------------------------------------------------------
+ // OSOEntry
+ //------------------------------------------------------------------
+ class OSOEntry
+ {
+ public:
+
+ OSOEntry () :
+ m_exe_sym_idx (UINT32_MAX),
+ m_oso_file_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ OSOEntry (uint32_t exe_sym_idx,
+ lldb::addr_t oso_file_addr) :
+ m_exe_sym_idx (exe_sym_idx),
+ m_oso_file_addr (oso_file_addr)
+ {
+ }
+
+ uint32_t
+ GetExeSymbolIndex () const
+ {
+ return m_exe_sym_idx;
+ }
+
+ bool
+ operator < (const OSOEntry &rhs) const
+ {
+ return m_exe_sym_idx < rhs.m_exe_sym_idx;
+ }
+
+ lldb::addr_t
+ GetOSOFileAddress () const
+ {
+ return m_oso_file_addr;
+ }
+
+ void
+ SetOSOFileAddress (lldb::addr_t oso_file_addr)
+ {
+ m_oso_file_addr = oso_file_addr;
+ }
+ protected:
+ uint32_t m_exe_sym_idx;
+ lldb::addr_t m_oso_file_addr;
+ };
+
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap;
+
+ //------------------------------------------------------------------
+ // Member Variables
+ //------------------------------------------------------------------
+ std::bitset<kNumFlags> m_flags;
+ std::vector<CompileUnitInfo> m_compile_unit_infos;
+ std::vector<uint32_t> m_func_indexes; // Sorted by address
+ std::vector<uint32_t> m_glob_indexes;
+ std::map<lldb_private::ConstString, OSOInfoSP> m_oso_map;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+ DebugMap m_debug_map;
+
+ //------------------------------------------------------------------
+ // When an object file from the debug map gets parsed in
+ // SymbolFileDWARF, it needs to tell the debug map about the object
+ // files addresses by calling this function once for each N_FUN,
+ // N_GSYM and N_STSYM and after all entries in the debug map have
+ // been matched up, FinalizeOSOFileRanges() should be called.
+ //------------------------------------------------------------------
+ bool
+ AddOSOFileRange (CompileUnitInfo *cu_info,
+ lldb::addr_t exe_file_addr,
+ lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size);
+
+ //------------------------------------------------------------------
+ // Called after calling AddOSOFileRange() for each object file debug
+ // map entry to finalize the info for the unlinked compile unit.
+ //------------------------------------------------------------------
+ void
+ FinalizeOSOFileRanges (CompileUnitInfo *cu_info);
+
+ //------------------------------------------------------------------
+ /// Convert \a addr from a .o file address, to an executable address.
+ ///
+ /// @param[in] addr
+ /// A section offset address from a .o file
+ ///
+ /// @return
+ /// Returns true if \a addr was converted to be an executable
+ /// section/offset address, false otherwise.
+ //------------------------------------------------------------------
+ bool
+ LinkOSOAddress (lldb_private::Address &addr);
+
+ //------------------------------------------------------------------
+ /// Convert a .o file "file address" to an executable "file address".
+ ///
+ /// @param[in] oso_symfile
+ /// The DWARF symbol file that contains \a oso_file_addr
+ ///
+ /// @param[in] oso_file_addr
+ /// A .o file "file address" to convert.
+ ///
+ /// @return
+ /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the
+ /// linked executable, otherwise a valid "file address" from the
+ /// linked executable that contains the debug map.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr);
+
+ //------------------------------------------------------------------
+ /// Given a line table full of lines with "file adresses" that are
+ /// for a .o file represented by \a oso_symfile, link a new line table
+ /// and return it.
+ ///
+ /// @param[in] oso_symfile
+ /// The DWARF symbol file that produced the \a line_table
+ ///
+ /// @param[in] addr
+ /// A section offset address from a .o file
+ ///
+ /// @return
+ /// Returns a valid line table full of linked addresses, or NULL
+ /// if none of the line table adresses exist in the main
+ /// executable.
+ //------------------------------------------------------------------
+ lldb_private::LineTable *
+ LinkOSOLineTable (SymbolFileDWARF *oso_symfile,
+ lldb_private::LineTable *line_table);
+
+ size_t
+ AddOSOARanges (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges);
+};
+
+#endif // #ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
new file mode 100644
index 000000000000..94044c0feb30
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
@@ -0,0 +1,94 @@
+//===-- UniqueDWARFASTType.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniqueDWARFASTType.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Symbol/Declaration.h"
+
+#include "DWARFDebugInfoEntry.h"
+
+bool
+UniqueDWARFASTTypeList::Find
+(
+ SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry
+) const
+{
+ collection::const_iterator pos, end = m_collection.end();
+ for (pos = m_collection.begin(); pos != end; ++pos)
+ {
+ // Make sure the tags match
+ if (pos->m_die->Tag() == die->Tag())
+ {
+ // Validate byte sizes of both types only if both are valid.
+ if (pos->m_byte_size < 0 || byte_size < 0 || pos->m_byte_size == byte_size)
+ {
+ // Make sure the file and line match
+ if (pos->m_declaration == decl)
+ {
+ // The type has the same name, and was defined on the same
+ // file and line. Now verify all of the parent DIEs match.
+ const DWARFDebugInfoEntry *parent_arg_die = die->GetParent();
+ const DWARFDebugInfoEntry *parend_pos_die = pos->m_die->GetParent();
+ bool match = true;
+ bool done = false;
+ while (!done && match && parent_arg_die && parend_pos_die)
+ {
+ if (parent_arg_die->Tag() == parend_pos_die->Tag())
+ {
+ const dw_tag_t tag = parent_arg_die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_namespace:
+ {
+ const char *parent_arg_die_name = parent_arg_die->GetName(symfile, cu);
+ if (parent_arg_die_name == NULL) // Anonymous (i.e. no-name) struct
+ {
+ match = false;
+ }
+ else
+ {
+ const char *parent_pos_die_name = parend_pos_die->GetName(pos->m_symfile, pos->m_cu);
+ if (parent_pos_die_name == NULL || strcmp (parent_arg_die_name, parent_pos_die_name))
+ match = false;
+ }
+ }
+ break;
+
+ case DW_TAG_compile_unit:
+ done = true;
+ break;
+ }
+ }
+ parent_arg_die = parent_arg_die->GetParent();
+ parend_pos_die = parend_pos_die->GetParent();
+ }
+
+ if (match)
+ {
+ entry = *pos;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
new file mode 100644
index 000000000000..c85e175235ca
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
@@ -0,0 +1,175 @@
+//===-- UniqueDWARFASTType.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UniqueDWARFASTType_h_
+#define lldb_UniqueDWARFASTType_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
+// Project includes
+#include "lldb/Symbol/Declaration.h"
+
+class DWARFCompileUnit;
+class DWARFDebugInfoEntry;
+class SymbolFileDWARF;
+
+class UniqueDWARFASTType
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ UniqueDWARFASTType () :
+ m_type_sp (),
+ m_symfile (NULL),
+ m_cu (NULL),
+ m_die (NULL),
+ m_declaration (),
+ m_byte_size (-1) // Set to negative value to make sure we have a valid value
+ {
+ }
+
+ UniqueDWARFASTType (lldb::TypeSP &type_sp,
+ SymbolFileDWARF *symfile,
+ DWARFCompileUnit *cu,
+ DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ int32_t byte_size) :
+ m_type_sp (type_sp),
+ m_symfile (symfile),
+ m_cu (cu),
+ m_die (die),
+ m_declaration (decl),
+ m_byte_size (byte_size)
+ {
+ }
+
+ UniqueDWARFASTType (const UniqueDWARFASTType &rhs) :
+ m_type_sp (rhs.m_type_sp),
+ m_symfile (rhs.m_symfile),
+ m_cu (rhs.m_cu),
+ m_die (rhs.m_die),
+ m_declaration (rhs.m_declaration),
+ m_byte_size (rhs.m_byte_size)
+ {
+ }
+
+ ~UniqueDWARFASTType()
+ {
+ }
+
+ UniqueDWARFASTType &
+ operator= (const UniqueDWARFASTType &rhs)
+ {
+ if (this != &rhs)
+ {
+ m_type_sp = rhs.m_type_sp;
+ m_symfile = rhs.m_symfile;
+ m_cu = rhs.m_cu;
+ m_die = rhs.m_die;
+ m_declaration = rhs.m_declaration;
+ m_byte_size = rhs.m_byte_size;
+ }
+ return *this;
+ }
+
+ lldb::TypeSP m_type_sp;
+ SymbolFileDWARF *m_symfile;
+ const DWARFCompileUnit *m_cu;
+ const DWARFDebugInfoEntry *m_die;
+ lldb_private::Declaration m_declaration;
+ int32_t m_byte_size;
+};
+
+class UniqueDWARFASTTypeList
+{
+public:
+ UniqueDWARFASTTypeList () :
+ m_collection()
+ {
+ }
+
+ ~UniqueDWARFASTTypeList ()
+ {
+ }
+
+ uint32_t
+ GetSize()
+ {
+ return (uint32_t)m_collection.size();
+ }
+
+ void
+ Append (const UniqueDWARFASTType &entry)
+ {
+ m_collection.push_back (entry);
+ }
+
+ bool
+ Find (SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry) const;
+
+protected:
+ typedef std::vector<UniqueDWARFASTType> collection;
+ collection m_collection;
+};
+
+class UniqueDWARFASTTypeMap
+{
+public:
+ UniqueDWARFASTTypeMap () :
+ m_collection ()
+ {
+ }
+
+ ~UniqueDWARFASTTypeMap ()
+ {
+ }
+
+ void
+ Insert (const lldb_private::ConstString &name,
+ const UniqueDWARFASTType &entry)
+ {
+ m_collection[name.GetCString()].Append (entry);
+ }
+
+ bool
+ Find (const lldb_private::ConstString &name,
+ SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry) const
+ {
+ const char *unique_name_cstr = name.GetCString();
+ collection::const_iterator pos = m_collection.find (unique_name_cstr);
+ if (pos != m_collection.end())
+ {
+ return pos->second.Find (symfile, cu, die, decl, byte_size, entry);
+ }
+ return false;
+ }
+
+protected:
+ // A unique name string should be used
+ typedef llvm::DenseMap<const char *, UniqueDWARFASTTypeList> collection;
+ collection m_collection;
+};
+
+#endif // lldb_UniqueDWARFASTType_h_
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
new file mode 100644
index 000000000000..9beba517ec83
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -0,0 +1,407 @@
+//===-- SymbolFileSymtab.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileSymtab.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileSymtab::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileSymtab::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolFileSymtab::GetPluginNameStatic()
+{
+ static ConstString g_name("symtab");
+ return g_name;
+}
+
+const char *
+SymbolFileSymtab::GetPluginDescriptionStatic()
+{
+ return "Reads debug symbols from an object file's symbol table.";
+}
+
+
+SymbolFile*
+SymbolFileSymtab::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileSymtab(obj_file);
+}
+
+size_t
+SymbolFileSymtab::GetTypes (SymbolContextScope *sc_scope, uint32_t type_mask, lldb_private::TypeList &type_list)
+{
+ return 0;
+}
+
+SymbolFileSymtab::SymbolFileSymtab(ObjectFile* obj_file) :
+ SymbolFile(obj_file),
+ m_source_indexes(),
+ m_func_indexes(),
+ m_code_indexes(),
+ m_objc_class_name_to_index ()
+{
+}
+
+SymbolFileSymtab::~SymbolFileSymtab()
+{
+}
+
+ClangASTContext &
+SymbolFileSymtab::GetClangASTContext ()
+{
+ ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext();
+
+ return ast;
+}
+
+uint32_t
+SymbolFileSymtab::CalculateAbilities ()
+{
+ uint32_t abilities = 0;
+ if (m_obj_file)
+ {
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ //----------------------------------------------------------------------
+ // The snippet of code below will get the indexes the module symbol
+ // table entries that are code, data, or function related (debug info),
+ // sort them by value (address) and dump the sorted symbols.
+ //----------------------------------------------------------------------
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes))
+ {
+ abilities |= CompileUnits;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ abilities |= Functions;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny, m_code_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_code_indexes, true);
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeData, m_data_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_data_indexes, true);
+ abilities |= GlobalVariables;
+ }
+
+ lldb_private::Symtab::IndexCollection objc_class_indexes;
+ if (symtab->AppendSymbolIndexesWithType (eSymbolTypeObjCClass, objc_class_indexes))
+ {
+ symtab->AppendSymbolNamesToMap (objc_class_indexes,
+ true,
+ true,
+ m_objc_class_name_to_index);
+ m_objc_class_name_to_index.Sort();
+ }
+ }
+ }
+ return abilities;
+}
+
+uint32_t
+SymbolFileSymtab::GetNumCompileUnits()
+{
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ return 0;
+
+ // If we have any source file symbols we will logically orgnize the object symbols
+ // using these.
+ return m_source_indexes.size();
+}
+
+CompUnitSP
+SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx)
+{
+ CompUnitSP cu_sp;
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (idx < m_source_indexes.size())
+ {
+ const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]);
+ if (cu_symbol)
+ cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetMangled().GetName().AsCString(), 0, eLanguageTypeUnknown));
+ }
+ return cu_sp;
+}
+
+lldb::LanguageType
+SymbolFileSymtab::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ return eLanguageTypeUnknown;
+}
+
+
+size_t
+SymbolFileSymtab::ParseCompileUnitFunctions (const SymbolContext &sc)
+{
+ size_t num_added = 0;
+ // We must at least have a valid compile unit
+ assert (sc.comp_unit != NULL);
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ const Symbol *curr_symbol = NULL;
+ const Symbol *next_symbol = NULL;
+// const char *prefix = m_obj_file->SymbolPrefix();
+// if (prefix == NULL)
+// prefix == "";
+//
+// const uint32_t prefix_len = strlen(prefix);
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ {
+ // The only time we will have a user ID of zero is when we don't have
+ // and source file symbols and we declare one compile unit for the
+ // entire object file
+ if (!m_func_indexes.empty())
+ {
+
+ }
+
+ if (!m_code_indexes.empty())
+ {
+// StreamFile s(stdout);
+// symtab->Dump(&s, m_code_indexes);
+
+ uint32_t idx = 0; // Index into the indexes
+ const uint32_t num_indexes = m_code_indexes.size();
+ for (idx = 0; idx < num_indexes; ++idx)
+ {
+ uint32_t symbol_idx = m_code_indexes[idx];
+ curr_symbol = symtab->SymbolAtIndex(symbol_idx);
+ if (curr_symbol)
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range(curr_symbol->GetAddress(), 0);
+ if (func_range.GetBaseAddress().IsSectionOffset())
+ {
+ uint32_t symbol_size = curr_symbol->GetByteSize();
+ if (symbol_size != 0 && !curr_symbol->GetSizeIsSibling())
+ func_range.SetByteSize(symbol_size);
+ else if (idx + 1 < num_indexes)
+ {
+ next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]);
+ if (next_symbol)
+ {
+ func_range.SetByteSize(next_symbol->GetAddress().GetOffset() - curr_symbol->GetAddress().GetOffset());
+ }
+ }
+
+ FunctionSP func_sp(new Function(sc.comp_unit,
+ symbol_idx, // UserID is the DIE offset
+ LLDB_INVALID_UID, // We don't have any type info for this function
+ curr_symbol->GetMangled(), // Linker/mangled name
+ NULL, // no return type for a code symbol...
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ sc.comp_unit->AddFunction(func_sp);
+ ++num_added;
+ }
+ }
+ }
+ }
+
+ }
+ }
+ else
+ {
+ // We assume we
+ }
+ return num_added;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ return false;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ return false;
+}
+
+size_t
+SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseTypes (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseVariablesForContext (const SymbolContext& sc)
+{
+ return 0;
+}
+
+Type*
+SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ return NULL;
+}
+
+bool
+SymbolFileSymtab::ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_opaque_type)
+{
+ return false;
+}
+
+ClangNamespaceDecl
+SymbolFileSymtab::FindNamespace (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl)
+{
+ return ClangNamespaceDecl();
+}
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ if (m_obj_file->GetSymtab() == NULL)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ sc.symbol = m_obj_file->GetSymtab()->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ return resolved_flags;
+}
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (name = '%s')",
+ name.GetCString());
+ // If we ever support finding STABS or COFF debug info symbols,
+ // we will need to add support here. We are not trying to find symbols
+ // here, just "lldb_private::Function" objects that come from complete
+ // debug information. Any symbol queries should go through the symbol
+ // table itself in the module's object file.
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (regex = '%s')",
+ regex.GetText());
+ // If we ever support finding STABS or COFF debug info symbols,
+ // we will need to add support here. We are not trying to find symbols
+ // here, just "lldb_private::Function" objects that come from complete
+ // debug information. Any symbol queries should go through the symbol
+ // table itself in the module's object file.
+ return 0;
+}
+
+static int CountMethodArgs(const char *method_signature)
+{
+ int num_args = 0;
+
+ for (const char *colon_pos = strchr(method_signature, ':');
+ colon_pos != NULL;
+ colon_pos = strchr(colon_pos + 1, ':'))
+ {
+ num_args++;
+ }
+
+ return num_args;
+}
+
+uint32_t
+SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ lldb_private::TypeList& types)
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SymbolFileSymtab::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileSymtab::GetPluginVersion()
+{
+ return 1;
+}
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
new file mode 100644
index 000000000000..914efe6eb3c2
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -0,0 +1,142 @@
+//===-- SymbolFileSymtab.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_SymbolFileSymtab_h_
+#define liblldb_SymbolFileSymtab_h_
+
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/Symtab.h"
+#include <vector>
+
+class SymbolFileSymtab : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileSymtab(lldb_private::ObjectFile* obj_file);
+
+ virtual
+ ~SymbolFileSymtab();
+
+ virtual uint32_t CalculateAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetNumCompileUnits();
+
+ virtual lldb::CompUnitSP
+ ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual lldb::LanguageType
+ ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+
+ virtual size_t
+ ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseTypes (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type*
+ ResolveTypeUID(lldb::user_id_t type_uid);
+
+ virtual bool
+ ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindTypes (const lldb_private::SymbolContext& sc,const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+
+ virtual size_t
+ GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ typedef std::map<lldb_private::ConstString, lldb::TypeSP> TypeMap;
+
+ lldb_private::Symtab::IndexCollection m_source_indexes;
+ lldb_private::Symtab::IndexCollection m_func_indexes;
+ lldb_private::Symtab::IndexCollection m_code_indexes;
+ lldb_private::Symtab::IndexCollection m_data_indexes;
+ lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index;
+ TypeMap m_objc_class_types;
+
+ lldb_private::ClangASTContext &
+ GetClangASTContext ();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileSymtab);
+};
+
+
+#endif // liblldb_SymbolFileSymtab_h_
diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
new file mode 100644
index 000000000000..6500aabdcea3
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
@@ -0,0 +1,199 @@
+//===-- SymbolVendorELF.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolVendorELF.h"
+
+//#include <libxml/parser.h>
+// #include <libxml/tree.h>
+#include <string.h>
+
+// #include <AvailabilityMacros.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SymbolVendorELF constructor
+//----------------------------------------------------------------------
+SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) :
+ SymbolVendor (module_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendorELF::~SymbolVendorELF()
+{
+}
+
+void
+SymbolVendorELF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolVendorELF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolVendorELF::GetPluginNameStatic()
+{
+ static ConstString g_name("ELF");
+ return g_name;
+}
+
+const char *
+SymbolVendorELF::GetPluginDescriptionStatic()
+{
+ return "Symbol vendor for ELF that looks for dSYM files that match executables.";
+}
+
+
+
+//----------------------------------------------------------------------
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol
+// vendors to allow for complex debug information file setups, and to
+// also allow for finding separate debug information files.
+//----------------------------------------------------------------------
+SymbolVendor*
+SymbolVendorELF::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
+{
+ if (!module_sp)
+ return NULL;
+
+ ObjectFile *obj_file = module_sp->GetObjectFile();
+ if (!obj_file)
+ return NULL;
+
+ static ConstString obj_file_elf("elf");
+ ConstString obj_name = obj_file->GetPluginName();
+ if (obj_name != obj_file_elf)
+ return NULL;
+
+ lldb_private::UUID uuid;
+ if (!obj_file->GetUUID (&uuid))
+ return NULL;
+
+ // Get the .gnu_debuglink file (if specified).
+ FileSpecList file_spec_list = obj_file->GetDebugSymbolFilePaths();
+
+ // If the module specified a filespec, use it first.
+ FileSpec debug_symbol_fspec (module_sp->GetSymbolFileFileSpec());
+ if (debug_symbol_fspec)
+ file_spec_list.Insert (0, debug_symbol_fspec);
+
+ // If we have no debug symbol files, then nothing to do.
+ if (file_spec_list.IsEmpty())
+ return NULL;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolVendorELF::CreateInstance (module = %s)",
+ module_sp->GetFileSpec().GetPath().c_str());
+
+ for (size_t idx = 0; idx < file_spec_list.GetSize(); ++idx)
+ {
+ ModuleSpec module_spec;
+ const FileSpec fspec = file_spec_list.GetFileSpecAtIndex (idx);
+
+ module_spec.GetFileSpec() = obj_file->GetFileSpec();
+ module_spec.GetFileSpec().ResolvePath();
+ module_spec.GetSymbolFileSpec() = fspec;
+ module_spec.GetUUID() = uuid;
+ FileSpec dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
+ if (dsym_fspec)
+ {
+ DataBufferSP dsym_file_data_sp;
+ lldb::offset_t dsym_file_data_offset = 0;
+ ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
+ if (dsym_objfile_sp)
+ {
+ // This objfile is for debugging purposes. Sadly, ObjectFileELF won't be able
+ // to figure this out consistently as the symbol file may not have stripped the
+ // code sections, etc.
+ dsym_objfile_sp->SetType (ObjectFile::eTypeDebugInfo);
+
+ SymbolVendorELF* symbol_vendor = new SymbolVendorELF(module_sp);
+ if (symbol_vendor)
+ {
+ // Get the module unified section list and add our debug sections to that.
+ SectionList *module_section_list = module_sp->GetSectionList();
+ SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
+
+ static const SectionType g_sections[] =
+ {
+ eSectionTypeDWARFDebugAranges,
+ eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugFrame,
+ eSectionTypeDWARFDebugLine,
+ eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugMacInfo,
+ eSectionTypeDWARFDebugPubNames,
+ eSectionTypeDWARFDebugPubTypes,
+ eSectionTypeDWARFDebugRanges,
+ eSectionTypeELFSymbolTable,
+ };
+ for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx)
+ {
+ SectionType section_type = g_sections[idx];
+ SectionSP section_sp (objfile_section_list->FindSectionByType (section_type, true));
+ if (section_sp)
+ {
+ SectionSP module_section_sp (module_section_list->FindSectionByType (section_type, true));
+ if (module_section_sp)
+ module_section_list->ReplaceSection (module_section_sp->GetID(), section_sp);
+ else
+ module_section_list->AddSection (section_sp);
+ }
+ }
+
+ symbol_vendor->AddSymbolFileRepresentation (dsym_objfile_sp);
+ return symbol_vendor;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+SymbolVendorELF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolVendorELF::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h
new file mode 100644
index 000000000000..acd62b6cc3ab
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h
@@ -0,0 +1,58 @@
+//===-- SymbolVendorELF.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_SymbolVendorELF_h_
+#define liblldb_SymbolVendorELF_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+class SymbolVendorELF : public lldb_private::SymbolVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolVendor*
+ CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendorELF (const lldb::ModuleSP &module_sp);
+
+ virtual
+ ~SymbolVendorELF();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendorELF);
+};
+
+#endif // liblldb_SymbolVendorELF_h_
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
new file mode 100644
index 000000000000..c93dea9b5d3c
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -0,0 +1,670 @@
+//===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindAssemblyInstEmulation.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+//-----------------------------------------------------------------------------------------------
+// UnwindAssemblyInstEmulation method definitions
+//-----------------------------------------------------------------------------------------------
+
+bool
+UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range,
+ Thread& thread,
+ UnwindPlan& unwind_plan)
+{
+ if (range.GetByteSize() > 0 &&
+ range.GetBaseAddress().IsValid() &&
+ m_inst_emulator_ap.get())
+ {
+
+ // The the instruction emulation subclass setup the unwind plan for the
+ // first instruction.
+ m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);
+
+ // CreateFunctionEntryUnwind should have created the first row. If it
+ // doesn't, then we are done.
+ if (unwind_plan.GetRowCount() == 0)
+ return false;
+
+ ExecutionContext exe_ctx;
+ thread.CalculateExecutionContext(exe_ctx);
+ DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
+ NULL,
+ NULL,
+ exe_ctx,
+ range));
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (disasm_sp)
+ {
+
+ m_range_ptr = &range;
+ m_thread_ptr = &thread;
+ m_unwind_plan_ptr = &unwind_plan;
+
+ const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
+ const bool show_address = true;
+ const bool show_bytes = true;
+ m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(),
+ unwind_plan.GetInitialCFARegister(),
+ m_cfa_reg_info);
+
+ m_fp_is_cfa = false;
+ m_register_values.clear();
+ m_pushed_regs.clear();
+
+ // Initialize the CFA with a known value. In the 32 bit case
+ // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
+ // We use the address byte size to be safe for any future addresss sizes
+ m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
+ RegisterValue cfa_reg_value;
+ cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
+ SetRegisterValue (m_cfa_reg_info, cfa_reg_value);
+
+ const InstructionList &inst_list = disasm_sp->GetInstructionList ();
+ const size_t num_instructions = inst_list.GetSize();
+
+ if (num_instructions > 0)
+ {
+ Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
+ const addr_t base_addr = inst->GetAddress().GetFileAddress();
+
+ // Make a copy of the current instruction Row and save it in m_curr_row
+ // so we can add updates as we process the instructions.
+ UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ if (last_row.get())
+ *newrow = *last_row.get();
+ m_curr_row.reset(newrow);
+
+ // Once we've seen the initial prologue instructions complete, save a
+ // copy of the CFI at that point into prologue_completed_row for possible
+ // use later.
+ int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update
+
+ bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
+
+ bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate
+
+ bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
+
+ UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+
+ // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
+ // quick reference during instruction parsing.
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+ RegisterInfo pc_reg_info;
+ if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
+ pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
+ else
+ pc_reg_num = LLDB_INVALID_REGNUM;
+
+ // cache the return address register number (in whatever register numbering this UnwindPlan uses) for
+ // quick reference during instruction parsing.
+ uint32_t ra_reg_num = LLDB_INVALID_REGNUM;
+ RegisterInfo ra_reg_info;
+ if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info))
+ ra_reg_num = ra_reg_info.kinds[unwind_plan.GetRegisterKind()];
+ else
+ ra_reg_num = LLDB_INVALID_REGNUM;
+
+ for (size_t idx=0; idx<num_instructions; ++idx)
+ {
+ m_curr_row_modified = false;
+ m_curr_insn_restored_a_register = false;
+ inst = inst_list.GetInstructionAtIndex (idx).get();
+ if (inst)
+ {
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL);
+ log->PutCString (strm.GetData());
+ }
+
+ m_inst_emulator_ap->SetInstruction (inst->GetOpcode(),
+ inst->GetAddress(),
+ exe_ctx.GetTargetPtr());
+
+ m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
+
+ // Were there any changes to the CFI while evaluating this instruction?
+ if (m_curr_row_modified)
+ {
+ reinstate_prologue_next_instruction = false;
+ m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+ // Append the new row
+ unwind_plan.AppendRow (m_curr_row);
+
+ // Allocate a new Row for m_curr_row, copy the current state into it
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ m_curr_row.reset(newrow);
+
+ // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
+ // Set instructions_since_last_prologue_insn to a very high number so we don't append
+ // any of these epilogue instructions to our prologue_complete row.
+ if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
+ instructions_since_last_prologue_insn = 0;
+ else
+ instructions_since_last_prologue_insn = 99;
+
+ UnwindPlan::Row::RegisterLocation pc_regloc;
+ UnwindPlan::Row::RegisterLocation ra_regloc;
+
+ // While parsing the instructions of this function, if we've ever
+ // seen the return address register (aka lr on arm) in a non-IsSame() state,
+ // it has been saved on the stack. If it's evern back to IsSame(), we've
+ // executed an epilogue.
+ if (ra_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
+ && !ra_regloc.IsSame())
+ {
+ return_address_register_has_been_saved = true;
+ }
+
+ // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
+ // after this instruction completes executing.
+ // If there are any instructions past this, there must have been flow control over this
+ // epilogue so we'll reinstate the original prologue setup instructions.
+ if (prologue_completed_row.get()
+ && pc_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
+ && pc_regloc.IsSame())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
+ reinstate_prologue_next_instruction = true;
+ }
+ else if (prologue_completed_row.get()
+ && return_address_register_has_been_saved
+ && ra_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
+ && ra_regloc.IsSame())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
+ last_instruction_restored_return_addr_reg = true;
+ }
+ }
+ else
+ {
+ // If the previous instruction was a return-to-caller (epilogue), and we're still executing
+ // instructions in this function, there must be a code path that jumps over that epilogue.
+ // Also detect the case where we epilogue & branch imm to another function (tail-call opt)
+ // instead of a normal pop lr-into-pc exit.
+ // Reinstate the frame setup from the prologue.
+ if (reinstate_prologue_next_instruction
+ || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *prologue_completed_row.get();
+ m_curr_row.reset(newrow);
+ m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+ unwind_plan.AppendRow(m_curr_row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ m_curr_row.reset(newrow);
+
+ reinstate_prologue_next_instruction = false;
+ last_instruction_restored_return_addr_reg = false;
+ m_curr_insn_is_branch_immediate = false;
+ }
+
+ // clear both of these if either one wasn't set
+ if (last_instruction_restored_return_addr_reg)
+ {
+ last_instruction_restored_return_addr_reg = false;
+ }
+ if (m_curr_insn_is_branch_immediate)
+ {
+ m_curr_insn_is_branch_immediate = false;
+ }
+
+ // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
+ // in a row.
+ if (instructions_since_last_prologue_insn++ < 8)
+ {
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ prologue_completed_row.reset(newrow);
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
+ }
+ }
+ }
+ }
+ }
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ }
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
+ strm.Printf ("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize());
+ unwind_plan.Dump(strm, &thread, base_addr);
+ log->PutCString (strm.GetData());
+ }
+ return unwind_plan.GetRowCount() > 0;
+ }
+ return false;
+}
+
+bool
+UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
+ Thread& thread,
+ UnwindPlan &unwind_plan)
+{
+ return false;
+}
+
+bool
+UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
+ const ExecutionContext &exe_ctx,
+ Address& first_non_prologue_insn)
+{
+ return false;
+}
+
+UnwindAssembly *
+UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
+{
+ std::unique_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
+ // Make sure that all prologue instructions are handled
+ if (inst_emulator_ap.get())
+ return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol in UnwindAssemblyParser_x86
+//------------------------------------------------------------------
+ConstString
+UnwindAssemblyInstEmulation::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+UnwindAssemblyInstEmulation::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+UnwindAssemblyInstEmulation::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+UnwindAssemblyInstEmulation::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+UnwindAssemblyInstEmulation::GetPluginNameStatic()
+{
+ static ConstString g_name("inst-emulation");
+ return g_name;
+}
+
+const char *
+UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
+{
+ return "Instruction emulation based unwind information.";
+}
+
+
+uint64_t
+UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
+{
+ uint32_t reg_kind, reg_num;
+ if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
+ return (uint64_t)reg_kind << 24 | reg_num;
+ return 0ull;
+}
+
+void
+UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
+{
+ m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
+}
+
+bool
+UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
+{
+ const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
+ RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
+ if (pos != m_register_values.end())
+ {
+ reg_value = pos->second;
+ return true; // We had a real value that comes from an opcode that wrote
+ // to it...
+ }
+ // We are making up a value that is recognizable...
+ reg_value.SetUInt(reg_id, reg_info.byte_size);
+ return false;
+}
+
+
+size_t
+UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64 ", dst = %p, dst_len = %" PRIu64 ", context = ",
+ addr,
+ dst,
+ (uint64_t)dst_len);
+ context.Dump(strm, instruction);
+ log->PutCString (strm.GetData ());
+ }
+ memset (dst, 0, dst_len);
+ return dst_len;
+}
+
+size_t
+UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t dst_len)
+{
+ if (baton && dst && dst_len)
+ return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
+ return 0;
+}
+
+size_t
+UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t dst_len)
+{
+ DataExtractor data (dst,
+ dst_len,
+ instruction->GetArchitecture ().GetByteOrder(),
+ instruction->GetArchitecture ().GetAddressByteSize());
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+
+ strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory (");
+ data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
+ strm.PutCString (", context = ");
+ context.Dump(strm, instruction);
+ log->PutCString (strm.GetData());
+ }
+
+ const bool can_replace = true;
+ const bool cant_replace = false;
+
+ switch (context.type)
+ {
+ default:
+ case EmulateInstruction::eContextInvalid:
+ case EmulateInstruction::eContextReadOpcode:
+ case EmulateInstruction::eContextImmediate:
+ case EmulateInstruction::eContextAdjustBaseRegister:
+ case EmulateInstruction::eContextRegisterPlusOffset:
+ case EmulateInstruction::eContextAdjustPC:
+ case EmulateInstruction::eContextRegisterStore:
+ case EmulateInstruction::eContextRegisterLoad:
+ case EmulateInstruction::eContextRelativeBranchImmediate:
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
+ case EmulateInstruction::eContextSupervisorCall:
+ case EmulateInstruction::eContextTableBranchReadMemory:
+ case EmulateInstruction::eContextWriteRegisterRandomBits:
+ case EmulateInstruction::eContextWriteMemoryRandomBits:
+ case EmulateInstruction::eContextArithmetic:
+ case EmulateInstruction::eContextAdvancePC:
+ case EmulateInstruction::eContextReturnFromException:
+ case EmulateInstruction::eContextPopRegisterOffStack:
+ case EmulateInstruction::eContextAdjustStackPointer:
+ break;
+
+ case EmulateInstruction::eContextPushRegisterOnStack:
+ {
+ uint32_t reg_num = LLDB_INVALID_REGNUM;
+ bool is_return_address_reg = false;
+ const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
+ if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
+ {
+ reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
+ if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
+ is_return_address_reg = true;
+ }
+ else
+ {
+ assert (!"unhandled case, add code to handle this!");
+ }
+
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
+ {
+ m_pushed_regs[reg_num] = addr;
+ const int32_t offset = addr - m_initial_sp;
+ m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
+ m_curr_row_modified = true;
+ if (is_return_address_reg)
+ {
+ // This push was pushing the return address register,
+ // so this is also how we will unwind the PC...
+ RegisterInfo pc_reg_info;
+ if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
+ {
+ uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
+ if (pc_reg_num != LLDB_INVALID_REGNUM)
+ {
+ m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
+ m_curr_row_modified = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ }
+
+ return dst_len;
+}
+
+bool
+UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+
+ if (baton && reg_info)
+ return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
+ return false;
+}
+bool
+UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ bool synthetic = GetRegisterValue (*reg_info, reg_value);
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ log->PutCString(strm.GetData());
+ }
+ return true;
+}
+
+bool
+UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ if (baton && reg_info)
+ return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
+ return false;
+}
+bool
+UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ strm.PutCString (", context = ");
+ context.Dump(strm, instruction);
+ log->PutCString(strm.GetData());
+ }
+
+ const bool must_replace = true;
+ SetRegisterValue (*reg_info, reg_value);
+
+ switch (context.type)
+ {
+ case EmulateInstruction::eContextInvalid:
+ case EmulateInstruction::eContextReadOpcode:
+ case EmulateInstruction::eContextImmediate:
+ case EmulateInstruction::eContextAdjustBaseRegister:
+ case EmulateInstruction::eContextRegisterPlusOffset:
+ case EmulateInstruction::eContextAdjustPC:
+ case EmulateInstruction::eContextRegisterStore:
+ case EmulateInstruction::eContextRegisterLoad:
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
+ case EmulateInstruction::eContextSupervisorCall:
+ case EmulateInstruction::eContextTableBranchReadMemory:
+ case EmulateInstruction::eContextWriteRegisterRandomBits:
+ case EmulateInstruction::eContextWriteMemoryRandomBits:
+ case EmulateInstruction::eContextArithmetic:
+ case EmulateInstruction::eContextAdvancePC:
+ case EmulateInstruction::eContextReturnFromException:
+ case EmulateInstruction::eContextPushRegisterOnStack:
+// {
+// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+// if (reg_num != LLDB_INVALID_REGNUM)
+// {
+// const bool can_replace_only_if_unspecified = true;
+//
+// m_curr_row.SetRegisterLocationToUndefined (reg_num,
+// can_replace_only_if_unspecified,
+// can_replace_only_if_unspecified);
+// m_curr_row_modified = true;
+// }
+// }
+ break;
+
+ case EmulateInstruction::eContextRelativeBranchImmediate:
+ {
+
+ {
+ m_curr_insn_is_branch_immediate = true;
+ }
+ }
+ break;
+
+ case EmulateInstruction::eContextPopRegisterOffStack:
+ {
+ const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+ m_curr_row_modified = true;
+ m_curr_insn_restored_a_register = true;
+ }
+ }
+ break;
+
+ case EmulateInstruction::eContextSetFramePointer:
+ if (!m_fp_is_cfa)
+ {
+ m_fp_is_cfa = true;
+ m_cfa_reg_info = *reg_info;
+ const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+ assert (cfa_reg_num != LLDB_INVALID_REGNUM);
+ m_curr_row->SetCFARegister(cfa_reg_num);
+ m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
+ }
+ break;
+
+ case EmulateInstruction::eContextAdjustStackPointer:
+ // If we have created a frame using the frame pointer, don't follow
+ // subsequent adjustments to the stack pointer.
+ if (!m_fp_is_cfa)
+ {
+ m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
+ }
+ break;
+ }
+ return true;
+}
+
+
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
new file mode 100644
index 000000000000..6a02f0a55104
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -0,0 +1,185 @@
+//===-- UnwindAssemblyInstEmulation.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_UnwindAssemblyInstEmulation_h_
+#define liblldb_UnwindAssemblyInstEmulation_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly
+{
+public:
+
+ virtual
+ ~UnwindAssemblyInstEmulation ()
+ {
+ }
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ GetFastUnwindPlan (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan &unwind_plan);
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (lldb_private::AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Address& first_non_prologue_insn);
+
+ static lldb_private::UnwindAssembly *
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+
+ static size_t
+ ReadMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ static bool
+ WriteRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+
+// size_t
+// ReadMemory (lldb_private::EmulateInstruction *instruction,
+// const lldb_private::EmulateInstruction::Context &context,
+// lldb::addr_t addr,
+// void *dst,
+// size_t length);
+
+ size_t
+ WriteMemory (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ bool
+ ReadRegister (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ bool
+ WriteRegister (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ // Call CreateInstance to get an instance of this class
+ UnwindAssemblyInstEmulation (const lldb_private::ArchSpec &arch,
+ lldb_private::EmulateInstruction *inst_emulator) :
+ UnwindAssembly (arch),
+ m_inst_emulator_ap (inst_emulator),
+ m_range_ptr (NULL),
+ m_thread_ptr (NULL),
+ m_unwind_plan_ptr (NULL),
+ m_curr_row (),
+ m_cfa_reg_info (),
+ m_fp_is_cfa (false),
+ m_register_values (),
+ m_pushed_regs(),
+ m_curr_row_modified (false),
+ m_curr_insn_is_branch_immediate (false),
+ m_curr_insn_restored_a_register (false)
+ {
+ if (m_inst_emulator_ap.get())
+ {
+ m_inst_emulator_ap->SetBaton (this);
+ m_inst_emulator_ap->SetCallbacks (ReadMemory, WriteMemory, ReadRegister, WriteRegister);
+ }
+ }
+
+ static uint64_t
+ MakeRegisterKindValuePair (const lldb_private::RegisterInfo &reg_info);
+
+ void
+ SetRegisterValue (const lldb_private::RegisterInfo &reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ bool
+ GetRegisterValue (const lldb_private::RegisterInfo &reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ std::unique_ptr<lldb_private::EmulateInstruction> m_inst_emulator_ap;
+ lldb_private::AddressRange* m_range_ptr;
+ lldb_private::Thread* m_thread_ptr;
+ lldb_private::UnwindPlan* m_unwind_plan_ptr;
+ lldb_private::UnwindPlan::RowSP m_curr_row;
+ typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
+ uint64_t m_initial_sp;
+ lldb_private::RegisterInfo m_cfa_reg_info;
+ bool m_fp_is_cfa;
+ typedef std::map<uint64_t, lldb_private::RegisterValue> RegisterValueMap;
+ RegisterValueMap m_register_values;
+ PushedRegisterToAddrMap m_pushed_regs;
+
+ // While processing the instruction stream, we need to communicate some state change
+ // information up to the higher level loop that makes decisions about how to push
+ // the unwind instructions for the UnwindPlan we're constructing.
+
+ // The instruction we're processing updated the UnwindPlan::Row contents
+ bool m_curr_row_modified;
+ // The instruction we're examining is a branch immediate instruction
+ bool m_curr_insn_is_branch_immediate;
+ // The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
+ bool m_curr_insn_restored_a_register;
+};
+
+#endif // liblldb_UnwindAssemblyInstEmulation_h_
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
new file mode 100644
index 000000000000..d491683f6875
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -0,0 +1,973 @@
+//===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindAssembly-x86.h"
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum CPU {
+ k_i386,
+ k_x86_64
+};
+
+enum i386_register_numbers {
+ k_machine_eax = 0,
+ k_machine_ecx = 1,
+ k_machine_edx = 2,
+ k_machine_ebx = 3,
+ k_machine_esp = 4,
+ k_machine_ebp = 5,
+ k_machine_esi = 6,
+ k_machine_edi = 7,
+ k_machine_eip = 8
+};
+
+enum x86_64_register_numbers {
+ k_machine_rax = 0,
+ k_machine_rcx = 1,
+ k_machine_rdx = 2,
+ k_machine_rbx = 3,
+ k_machine_rsp = 4,
+ k_machine_rbp = 5,
+ k_machine_rsi = 6,
+ k_machine_rdi = 7,
+ k_machine_r8 = 8,
+ k_machine_r9 = 9,
+ k_machine_r10 = 10,
+ k_machine_r11 = 11,
+ k_machine_r12 = 12,
+ k_machine_r13 = 13,
+ k_machine_r14 = 14,
+ k_machine_r15 = 15,
+ k_machine_rip = 16
+};
+
+struct regmap_ent {
+ const char *name;
+ int machine_regno;
+ int lldb_regno;
+};
+
+static struct regmap_ent i386_register_map[] = {
+ {"eax", k_machine_eax, -1},
+ {"ecx", k_machine_ecx, -1},
+ {"edx", k_machine_edx, -1},
+ {"ebx", k_machine_ebx, -1},
+ {"esp", k_machine_esp, -1},
+ {"ebp", k_machine_ebp, -1},
+ {"esi", k_machine_esi, -1},
+ {"edi", k_machine_edi, -1},
+ {"eip", k_machine_eip, -1}
+};
+
+const int size_of_i386_register_map = sizeof (i386_register_map) / sizeof (struct regmap_ent);
+
+static int i386_register_map_initialized = 0;
+
+static struct regmap_ent x86_64_register_map[] = {
+ {"rax", k_machine_rax, -1},
+ {"rcx", k_machine_rcx, -1},
+ {"rdx", k_machine_rdx, -1},
+ {"rbx", k_machine_rbx, -1},
+ {"rsp", k_machine_rsp, -1},
+ {"rbp", k_machine_rbp, -1},
+ {"rsi", k_machine_rsi, -1},
+ {"rdi", k_machine_rdi, -1},
+ {"r8", k_machine_r8, -1},
+ {"r9", k_machine_r9, -1},
+ {"r10", k_machine_r10, -1},
+ {"r11", k_machine_r11, -1},
+ {"r12", k_machine_r12, -1},
+ {"r13", k_machine_r13, -1},
+ {"r14", k_machine_r14, -1},
+ {"r15", k_machine_r15, -1},
+ {"rip", k_machine_rip, -1}
+};
+
+const int size_of_x86_64_register_map = sizeof (x86_64_register_map) / sizeof (struct regmap_ent);
+
+static int x86_64_register_map_initialized = 0;
+
+//-----------------------------------------------------------------------------------------------
+// AssemblyParse_x86 local-file class definition & implementation functions
+//-----------------------------------------------------------------------------------------------
+
+class AssemblyParse_x86 {
+public:
+
+ AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func);
+
+ ~AssemblyParse_x86 ();
+
+ bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
+
+ bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
+
+ bool find_first_non_prologue_insn (Address &address);
+
+private:
+ enum { kMaxInstructionByteSize = 32 };
+
+ bool nonvolatile_reg_p (int machine_regno);
+ bool push_rbp_pattern_p ();
+ bool push_0_pattern_p ();
+ bool mov_rsp_rbp_pattern_p ();
+ bool sub_rsp_pattern_p (int& amount);
+ bool push_reg_p (int& regno);
+ bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
+ bool ret_pattern_p ();
+ uint32_t extract_4 (uint8_t *b);
+ bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
+ bool instruction_length (Address addr, int &length);
+
+ const ExecutionContext m_exe_ctx;
+
+ AddressRange m_func_bounds;
+
+ Address m_cur_insn;
+ uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
+
+ int m_machine_ip_regnum;
+ int m_machine_sp_regnum;
+ int m_machine_fp_regnum;
+
+ int m_lldb_ip_regnum;
+ int m_lldb_sp_regnum;
+ int m_lldb_fp_regnum;
+
+ int m_wordsize;
+ int m_cpu;
+ ArchSpec m_arch;
+ ::LLVMDisasmContextRef m_disasm_context;
+
+ DISALLOW_COPY_AND_ASSIGN (AssemblyParse_x86);
+};
+
+AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) :
+ m_exe_ctx (exe_ctx),
+ m_func_bounds(func),
+ m_cur_insn (),
+ m_machine_ip_regnum (LLDB_INVALID_REGNUM),
+ m_machine_sp_regnum (LLDB_INVALID_REGNUM),
+ m_machine_fp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_ip_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_sp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_fp_regnum (LLDB_INVALID_REGNUM),
+ m_wordsize (-1),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+ int *initialized_flag = NULL;
+ if (cpu == k_i386)
+ {
+ m_machine_ip_regnum = k_machine_eip;
+ m_machine_sp_regnum = k_machine_esp;
+ m_machine_fp_regnum = k_machine_ebp;
+ m_wordsize = 4;
+ initialized_flag = &i386_register_map_initialized;
+ }
+ else
+ {
+ m_machine_ip_regnum = k_machine_rip;
+ m_machine_sp_regnum = k_machine_rsp;
+ m_machine_fp_regnum = k_machine_rbp;
+ m_wordsize = 8;
+ initialized_flag = &x86_64_register_map_initialized;
+ }
+
+ // we only look at prologue - it will be complete earlier than 512 bytes into func
+ if (m_func_bounds.GetByteSize() == 0)
+ m_func_bounds.SetByteSize(512);
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (thread && *initialized_flag == 0)
+ {
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ struct regmap_ent *ent;
+ int count, i;
+ if (cpu == k_i386)
+ {
+ ent = i386_register_map;
+ count = size_of_i386_register_map;
+ }
+ else
+ {
+ ent = x86_64_register_map;
+ count = size_of_x86_64_register_map;
+ }
+ for (i = 0; i < count; i++, ent++)
+ {
+ const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName (ent->name);
+ if (ri)
+ ent->lldb_regno = ri->kinds[eRegisterKindLLDB];
+ }
+ *initialized_flag = 1;
+ }
+ }
+
+ // on initial construction we may not have a Thread so these have to remain
+ // uninitialized until we can get a RegisterContext to set up the register map table
+ if (*initialized_flag == 1)
+ {
+ uint32_t lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_sp_regnum, lldb_regno))
+ m_lldb_sp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_fp_regnum, lldb_regno))
+ m_lldb_fp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_ip_regnum, lldb_regno))
+ m_lldb_ip_regnum = lldb_regno;
+ }
+
+ m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
+ (void*)this,
+ /*TagType=*/1,
+ NULL,
+ NULL);
+}
+
+AssemblyParse_x86::~AssemblyParse_x86 ()
+{
+ ::LLVMDisasmDispose(m_disasm_context);
+}
+
+// This function expects an x86 native register number (i.e. the bits stripped out of the
+// actual instruction), not an lldb register number.
+
+bool
+AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
+{
+ if (m_cpu == k_i386)
+ {
+ switch (machine_regno) {
+ case k_machine_ebx:
+ case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention
+ case k_machine_esi:
+ case k_machine_edi:
+ case k_machine_esp:
+ return true;
+ default:
+ return false;
+ }
+ }
+ if (m_cpu == k_x86_64)
+ {
+ switch (machine_regno) {
+ case k_machine_rbx:
+ case k_machine_rsp:
+ case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention
+ case k_machine_r12:
+ case k_machine_r13:
+ case k_machine_r14:
+ case k_machine_r15:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+
+// Macro to detect if this is a REX mode prefix byte.
+#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
+
+// The high bit which should be added to the source register number (the "R" bit)
+#define REX_W_SRCREG(opcode) (((opcode) & 0x4) >> 2)
+
+// The high bit which should be added to the destination register number (the "B" bit)
+#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
+
+// pushq %rbp [0x55]
+bool AssemblyParse_x86::push_rbp_pattern_p () {
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0x55)
+ return true;
+ return false;
+}
+
+// pushq $0 ; the first instruction in start() [0x6a 0x00]
+bool AssemblyParse_x86::push_0_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0x6a && *(p + 1) == 0x0)
+ return true;
+ return false;
+}
+
+// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
+// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
+bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+ if (*(p) == 0x8b && *(p + 1) == 0xec)
+ return true;
+ if (*(p) == 0x89 && *(p + 1) == 0xe5)
+ return true;
+ return false;
+}
+
+// subq $0x20, %rsp
+bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) {
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+ // 8-bit immediate operand
+ if (*p == 0x83 && *(p + 1) == 0xec) {
+ amount = (int8_t) *(p + 2);
+ return true;
+ }
+ // 32-bit immediate operand
+ if (*p == 0x81 && *(p + 1) == 0xec) {
+ amount = (int32_t) extract_4 (p + 2);
+ return true;
+ }
+ // Not handled: [0x83 0xc4] for imm8 with neg values
+ // [0x81 0xc4] for imm32 with neg values
+ return false;
+}
+
+// pushq %rbx
+// pushl $ebx
+bool AssemblyParse_x86::push_reg_p (int& regno) {
+ uint8_t *p = m_cur_insn_bytes;
+ int regno_prefix_bit = 0;
+ // If we have a rex prefix byte, check to see if a B bit is set
+ if (m_wordsize == 8 && *p == 0x41) {
+ regno_prefix_bit = 1 << 3;
+ p++;
+ }
+ if (*p >= 0x50 && *p <= 0x57) {
+ regno = (*p - 0x50) | regno_prefix_bit;
+ return true;
+ }
+ return false;
+}
+
+// Look for an instruction sequence storing a nonvolatile register
+// on to the stack frame.
+
+// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
+// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
+bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) {
+ uint8_t *p = m_cur_insn_bytes;
+ int src_reg_prefix_bit = 0;
+ int target_reg_prefix_bit = 0;
+
+ if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) {
+ src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
+ target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
+ if (target_reg_prefix_bit == 1) {
+ // rbp/ebp don't need a prefix bit - we know this isn't the
+ // reg we care about.
+ return false;
+ }
+ p++;
+ }
+
+ if (*p == 0x89) {
+ /* Mask off the 3-5 bits which indicate the destination register
+ if this is a ModR/M byte. */
+ int opcode_destreg_masked_out = *(p + 1) & (~0x38);
+
+ /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
+ and three bits between them, e.g. 01nnn101
+ We're looking for a destination of ebp-disp8 or ebp-disp32. */
+ int immsize;
+ if (opcode_destreg_masked_out == 0x45)
+ immsize = 2;
+ else if (opcode_destreg_masked_out == 0x85)
+ immsize = 4;
+ else
+ return false;
+
+ int offset = 0;
+ if (immsize == 2)
+ offset = (int8_t) *(p + 2);
+ if (immsize == 4)
+ offset = (uint32_t) extract_4 (p + 2);
+ if (offset > 0)
+ return false;
+
+ regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
+ rbp_offset = offset > 0 ? offset : -offset;
+ return true;
+ }
+ return false;
+}
+
+// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
+bool
+AssemblyParse_x86::ret_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
+ return true;
+ return false;
+}
+
+uint32_t
+AssemblyParse_x86::extract_4 (uint8_t *b)
+{
+ uint32_t v = 0;
+ for (int i = 3; i >= 0; i--)
+ v = (v << 8) | b[i];
+ return v;
+}
+
+bool
+AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
+{
+ struct regmap_ent *ent;
+ int count, i;
+ if (m_cpu == k_i386)
+ {
+ ent = i386_register_map;
+ count = size_of_i386_register_map;
+ }
+ else
+ {
+ ent = x86_64_register_map;
+ count = size_of_x86_64_register_map;
+ }
+ for (i = 0; i < count; i++, ent++)
+ {
+ if (ent->machine_regno == machine_regno)
+ if (ent->lldb_regno != -1)
+ {
+ lldb_regno = ent->lldb_regno;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+AssemblyParse_x86::instruction_length (Address addr, int &length)
+{
+ const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize();
+ llvm::SmallVector <uint8_t, 32> opcode_data;
+ opcode_data.resize (max_op_byte_size);
+
+ if (!addr.IsValid())
+ return false;
+
+ const bool prefer_file_cache = true;
+ Error error;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(), max_op_byte_size, error) == -1)
+ {
+ return false;
+ }
+
+ char out_string[512];
+ const addr_t pc = addr.GetFileAddress();
+ const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context,
+ opcode_data.data(),
+ max_op_byte_size,
+ pc, // PC value
+ out_string,
+ sizeof(out_string));
+
+ length = inst_size;
+ return true;
+}
+
+
+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;
+ UnwindPlan::Row::RegisterLocation initial_regloc;
+ Error error;
+
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ unwind_plan.SetPlanValidAddressRange (m_func_bounds);
+ unwind_plan.SetRegisterKind (eRegisterKindLLDB);
+
+ // At the start of the function, find the CFA by adding wordsize to the SP register
+ row->SetOffset (current_func_text_offset);
+ row->SetCFARegister (m_lldb_sp_regnum);
+ row->SetCFAOffset (m_wordsize);
+
+ // caller's stack pointer value before the call insn is the CFA address
+ initial_regloc.SetIsCFAPlusOffset (0);
+ row->SetRegisterInfo (m_lldb_sp_regnum, initial_regloc);
+
+ // saved instruction pointer can be found at CFA - wordsize.
+ current_sp_bytes_offset_from_cfa = m_wordsize;
+ initial_regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
+ row->SetRegisterInfo (m_lldb_ip_regnum, initial_regloc);
+
+ unwind_plan.AppendRow (row);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ const bool prefer_file_cache = true;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
+ {
+ 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
+
+ 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) == -1)
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ // 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 ())
+ {
+ goto loopnext;
+ }
+
+ if (push_reg_p (machine_regno))
+ {
+ current_sp_bytes_offset_from_cfa += m_wordsize;
+ if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ }
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
+ 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;
+ }
+
+ if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
+ {
+ if (machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+ 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;
+ }
+ }
+
+ if (sub_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa += stack_offset;
+ 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);
+ }
+ goto loopnext;
+ }
+
+ if (ret_pattern_p ())
+ {
+ // 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;
+ }
+
+ // 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.
+
+ non_prologue_insn_count++;
+loopnext:
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ current_func_text_offset += insn_len;
+ }
+
+ // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
+ // epilogue. We're looking for the sequence
+
+ // [ 0x5d ] mov %rbp, %rsp
+ // [ 0xc3 ] ret
+ // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
+
+ // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
+ // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
+
+ uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
+ Address end_of_fun(m_func_bounds.GetBaseAddress());
+ end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+
+ if (m_func_bounds.GetByteSize() > 7)
+ {
+ uint8_t bytebuf[7];
+ Address last_seven_bytes(end_of_fun);
+ last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
+ if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, error) != -1)
+ {
+ if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov, ret
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 6;
+ }
+ }
+ } else if (m_func_bounds.GetByteSize() > 2)
+ {
+ uint8_t bytebuf[2];
+ Address last_two_bytes(end_of_fun);
+ last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
+ if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, error) != -1)
+ {
+ if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ }
+ }
+
+ 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);
+
+ // 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);
+
+ // saved instruction pointer can be found at CFA - wordsize
+ epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
+ epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+
+ unwind_plan.AppendRow (epi_row);
+ }
+
+ unwind_plan.SetSourceName ("assembly insn profiling");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+
+ return true;
+}
+
+/* The "fast unwind plan" is valid for functions that follow the usual convention of
+ using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
+ push %rbp [0x55]
+ mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
+*/
+
+bool
+AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
+{
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ UnwindPlan::Row::RegisterLocation pc_reginfo;
+ UnwindPlan::Row::RegisterLocation sp_reginfo;
+ UnwindPlan::Row::RegisterLocation fp_reginfo;
+ unwind_plan.SetRegisterKind (eRegisterKindLLDB);
+
+ if (!func.GetBaseAddress().IsValid())
+ return false;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ uint8_t bytebuf[4];
+ Error error;
+ const bool prefer_file_cache = true;
+ if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf, sizeof (bytebuf), error) == -1)
+ return false;
+
+ uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
+ uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};
+ int prologue_size;
+
+ if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0)
+ {
+ prologue_size = sizeof (i386_prologue);
+ }
+ else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0)
+ {
+ prologue_size = sizeof (x86_64_prologue);
+ }
+ else
+ {
+ return false;
+ }
+
+ pc_reginfo.SetAtCFAPlusOffset (-m_wordsize);
+ row->SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo);
+
+ sp_reginfo.SetIsCFAPlusOffset (0);
+ row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
+
+ // Zero instructions into the function
+ row->SetCFARegister (m_lldb_sp_regnum);
+ row->SetCFAOffset (m_wordsize);
+ row->SetOffset (0);
+ unwind_plan.AppendRow (row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ // push %rbp has executed - stack moved, rbp now saved
+ row->SetCFAOffset (2 * m_wordsize);
+ fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
+ row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
+ row->SetOffset (1);
+ unwind_plan.AppendRow (row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ // mov %rsp, %rbp has executed
+ row->SetCFARegister (m_lldb_fp_regnum);
+ row->SetCFAOffset (2 * m_wordsize);
+ row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
+ unwind_plan.AppendRow (row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ unwind_plan.SetPlanValidAddressRange (func);
+ unwind_plan.SetSourceName ("fast unwind assembly profiling");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
+{
+ m_cur_insn = m_func_bounds.GetBaseAddress ();
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ const bool prefer_file_cache = true;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
+ {
+ Error error;
+ int insn_len, offset, regno;
+ if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
+ {
+ // An error parsing the instruction, i.e. probably data/garbage - stop scanning
+ break;
+ }
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1)
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
+ || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
+ {
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ continue;
+ }
+
+ // Unknown non-prologue instruction - stop scanning
+ break;
+ }
+
+ address = m_cur_insn;
+ return true;
+}
+
+
+
+
+
+
+//-----------------------------------------------------------------------------------------------
+// UnwindAssemblyParser_x86 method definitions
+//-----------------------------------------------------------------------------------------------
+
+UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
+ lldb_private::UnwindAssembly(arch),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+}
+
+
+UnwindAssembly_x86::~UnwindAssembly_x86 ()
+{
+}
+
+bool
+UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (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_non_call_site_unwind_plan (unwind_plan);
+}
+
+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);
+}
+
+bool
+UnwindAssembly_x86::FirstNonPrologueInsn (AddressRange& func, const ExecutionContext &exe_ctx, Address& first_non_prologue_insn)
+{
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
+}
+
+UnwindAssembly *
+UnwindAssembly_x86::CreateInstance (const ArchSpec &arch)
+{
+ const llvm::Triple::ArchType cpu = arch.GetMachine ();
+ if (cpu == llvm::Triple::x86)
+ return new UnwindAssembly_x86 (arch, k_i386);
+ else if (cpu == llvm::Triple::x86_64)
+ return new UnwindAssembly_x86 (arch, k_x86_64);
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol in UnwindAssemblyParser_x86
+//------------------------------------------------------------------
+
+ConstString
+UnwindAssembly_x86::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+
+uint32_t
+UnwindAssembly_x86::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+UnwindAssembly_x86::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+UnwindAssembly_x86::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+UnwindAssembly_x86::GetPluginNameStatic()
+{
+ static ConstString g_name("x86");
+ return g_name;
+}
+
+const char *
+UnwindAssembly_x86::GetPluginDescriptionStatic()
+{
+ return "i386 and x86_64 assembly language profiler plugin.";
+}
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
new file mode 100644
index 000000000000..eebaa7b6c803
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
@@ -0,0 +1,73 @@
+//===-- UnwindAssembly-x86.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_UnwindAssembly_x86_h_
+#define liblldb_UnwindAssembly_x86_h_
+
+#include "llvm-c/Disassembler.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+class UnwindAssembly_x86 : public lldb_private::UnwindAssembly
+{
+public:
+
+ ~UnwindAssembly_x86 ();
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ GetFastUnwindPlan (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan &unwind_plan);
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (lldb_private::AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Address& first_non_prologue_insn);
+
+ static lldb_private::UnwindAssembly *
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ UnwindAssembly_x86 (const lldb_private::ArchSpec &arch, int cpu);
+
+ int m_cpu;
+ lldb_private::ArchSpec m_arch;
+};
+
+
+#endif // liblldb_UnwindAssembly_x86_h_
diff --git a/source/Symbol/Block.cpp b/source/Symbol/Block.cpp
new file mode 100644
index 000000000000..4ab86e54bf68
--- /dev/null
+++ b/source/Symbol/Block.cpp
@@ -0,0 +1,631 @@
+//===-- Block.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/Symbol/Block.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Block::Block(lldb::user_id_t uid) :
+ UserID(uid),
+ m_parent_scope (NULL),
+ m_children (),
+ m_ranges (),
+ m_inlineInfoSP (),
+ m_variable_list_sp (),
+ m_parsed_block_info (false),
+ m_parsed_block_variables (false),
+ m_parsed_child_blocks (false)
+{
+}
+
+Block::~Block ()
+{
+}
+
+void
+Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Target *target) const
+{
+ *s << "id = " << ((const UserID&)*this);
+
+ size_t num_ranges = m_ranges.GetSize();
+ if (num_ranges > 0)
+ {
+
+ addr_t base_addr = LLDB_INVALID_ADDRESS;
+ if (target)
+ base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(target);
+ if (base_addr == LLDB_INVALID_ADDRESS)
+ base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
+
+ s->Printf(", range%s = ", num_ranges > 1 ? "s" : "");
+ for (size_t i=0; i<num_ranges; ++i)
+ {
+ const Range &range = m_ranges.GetEntryRef(i);
+ s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
+ }
+ }
+
+ if (m_inlineInfoSP.get() != NULL)
+ {
+ bool show_fullpaths = (level == eDescriptionLevelVerbose);
+ m_inlineInfoSP->Dump(s, show_fullpaths);
+ }
+}
+
+void
+Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
+{
+ if (depth < 0)
+ {
+ Block *parent = GetParent();
+ if (parent)
+ {
+ // We have a depth that is less than zero, print our parent blocks
+ // first
+ parent->Dump(s, base_addr, depth + 1, show_context);
+ }
+ }
+
+ s->Printf("%p: ", this);
+ s->Indent();
+ *s << "Block" << ((const UserID&)*this);
+ const Block* parent_block = GetParent();
+ if (parent_block)
+ {
+ s->Printf(", parent = {0x%8.8" PRIx64 "}", parent_block->GetID());
+ }
+ if (m_inlineInfoSP.get() != NULL)
+ {
+ bool show_fullpaths = false;
+ m_inlineInfoSP->Dump(s, show_fullpaths);
+ }
+
+ if (!m_ranges.IsEmpty())
+ {
+ *s << ", ranges =";
+
+ size_t num_ranges = m_ranges.GetSize();
+ for (size_t i=0; i<num_ranges; ++i)
+ {
+ const Range &range = m_ranges.GetEntryRef(i);
+ if (parent_block != NULL && parent_block->Contains(range) == false)
+ *s << '!';
+ else
+ *s << ' ';
+ s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
+ }
+ }
+ s->EOL();
+
+ if (depth > 0)
+ {
+ s->IndentMore();
+
+ if (m_variable_list_sp.get())
+ {
+ m_variable_list_sp->Dump(s, show_context);
+ }
+
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ (*pos)->Dump(s, base_addr, depth - 1, show_context);
+
+ s->IndentLess();
+ }
+
+}
+
+
+Block *
+Block::FindBlockByID (user_id_t block_id)
+{
+ if (block_id == GetID())
+ return this;
+
+ Block *matching_block = NULL;
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ {
+ matching_block = (*pos)->FindBlockByID (block_id);
+ if (matching_block)
+ break;
+ }
+ return matching_block;
+}
+
+void
+Block::CalculateSymbolContext (SymbolContext* sc)
+{
+ if (m_parent_scope)
+ m_parent_scope->CalculateSymbolContext(sc);
+ sc->block = this;
+}
+
+lldb::ModuleSP
+Block::CalculateSymbolContextModule ()
+{
+ if (m_parent_scope)
+ return m_parent_scope->CalculateSymbolContextModule ();
+ return lldb::ModuleSP();
+}
+
+CompileUnit *
+Block::CalculateSymbolContextCompileUnit ()
+{
+ if (m_parent_scope)
+ return m_parent_scope->CalculateSymbolContextCompileUnit ();
+ return NULL;
+}
+
+Function *
+Block::CalculateSymbolContextFunction ()
+{
+ if (m_parent_scope)
+ return m_parent_scope->CalculateSymbolContextFunction ();
+ return NULL;
+}
+
+Block *
+Block::CalculateSymbolContextBlock ()
+{
+ return this;
+}
+
+void
+Block::DumpSymbolContext(Stream *s)
+{
+ Function *function = CalculateSymbolContextFunction();
+ if (function)
+ function->DumpSymbolContext(s);
+ s->Printf(", Block{0x%8.8" PRIx64 "}", GetID());
+}
+
+void
+Block::DumpAddressRanges (Stream *s, lldb::addr_t base_addr)
+{
+ if (!m_ranges.IsEmpty())
+ {
+ size_t num_ranges = m_ranges.GetSize();
+ for (size_t i=0; i<num_ranges; ++i)
+ {
+ const Range &range = m_ranges.GetEntryRef(i);
+ s->AddressRange(base_addr + range.GetRangeBase(), base_addr + range.GetRangeEnd(), 4);
+ }
+ }
+}
+
+bool
+Block::Contains (addr_t range_offset) const
+{
+ return m_ranges.FindEntryThatContains(range_offset) != NULL;
+}
+
+bool
+Block::Contains (const Block *block) const
+{
+ if (this == block)
+ return false; // This block doesn't contain itself...
+
+ // Walk the parent chain for "block" and see if any if them match this block
+ const Block *block_parent;
+ for (block_parent = block->GetParent();
+ block_parent != NULL;
+ block_parent = block_parent->GetParent())
+ {
+ if (this == block_parent)
+ return true; // One of the parents of "block" is this object!
+ }
+ return false;
+}
+
+bool
+Block::Contains (const Range& range) const
+{
+ return m_ranges.FindEntryThatContains (range) != NULL;
+}
+
+Block *
+Block::GetParent () const
+{
+ if (m_parent_scope)
+ return m_parent_scope->CalculateSymbolContextBlock();
+ return NULL;
+}
+
+Block *
+Block::GetContainingInlinedBlock ()
+{
+ if (GetInlinedFunctionInfo())
+ return this;
+ return GetInlinedParent ();
+}
+
+Block *
+Block::GetInlinedParent ()
+{
+ Block *parent_block = GetParent ();
+ if (parent_block)
+ {
+ if (parent_block->GetInlinedFunctionInfo())
+ return parent_block;
+ else
+ return parent_block->GetInlinedParent();
+ }
+ return NULL;
+}
+
+
+bool
+Block::GetRangeContainingOffset (const addr_t offset, Range &range)
+{
+ const Range *range_ptr = m_ranges.FindEntryThatContains (offset);
+ if (range_ptr)
+ {
+ range = *range_ptr;
+ return true;
+ }
+ range.Clear();
+ return false;
+}
+
+
+bool
+Block::GetRangeContainingAddress (const Address& addr, AddressRange &range)
+{
+ Function *function = CalculateSymbolContextFunction();
+ if (function)
+ {
+ const AddressRange &func_range = function->GetAddressRange();
+ if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
+ {
+ const addr_t addr_offset = addr.GetOffset();
+ const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
+ if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
+ {
+ addr_t offset = addr_offset - func_offset;
+
+ const Range *range_ptr = m_ranges.FindEntryThatContains (offset);
+
+ if (range_ptr)
+ {
+ range.GetBaseAddress() = func_range.GetBaseAddress();
+ range.GetBaseAddress().SetOffset(func_offset + range_ptr->GetRangeBase());
+ range.SetByteSize(range_ptr->GetByteSize());
+ return true;
+ }
+ }
+ }
+ }
+ range.Clear();
+ return false;
+}
+
+bool
+Block::GetRangeContainingLoadAddress (lldb::addr_t load_addr, Target &target, AddressRange &range)
+{
+ Address load_address;
+ load_address.SetLoadAddress(load_addr, &target);
+ AddressRange containing_range;
+ return GetRangeContainingAddress(load_address, containing_range);
+}
+
+
+uint32_t
+Block::GetRangeIndexContainingAddress (const Address& addr)
+{
+ Function *function = CalculateSymbolContextFunction();
+ if (function)
+ {
+ const AddressRange &func_range = function->GetAddressRange();
+ if (addr.GetSection() == func_range.GetBaseAddress().GetSection())
+ {
+ const addr_t addr_offset = addr.GetOffset();
+ const addr_t func_offset = func_range.GetBaseAddress().GetOffset();
+ if (addr_offset >= func_offset && addr_offset < func_offset + func_range.GetByteSize())
+ {
+ addr_t offset = addr_offset - func_offset;
+ return m_ranges.FindEntryIndexThatContains (offset);
+ }
+ }
+ }
+ return UINT32_MAX;
+}
+
+bool
+Block::GetRangeAtIndex (uint32_t range_idx, AddressRange &range)
+{
+ if (range_idx < m_ranges.GetSize())
+ {
+ Function *function = CalculateSymbolContextFunction();
+ if (function)
+ {
+ const Range &vm_range = m_ranges.GetEntryRef(range_idx);
+ range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress();
+ range.GetBaseAddress().Slide(vm_range.GetRangeBase ());
+ range.SetByteSize (vm_range.GetByteSize());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Block::GetStartAddress (Address &addr)
+{
+ if (m_ranges.IsEmpty())
+ return false;
+
+ Function *function = CalculateSymbolContextFunction();
+ if (function)
+ {
+ addr = function->GetAddressRange().GetBaseAddress();
+ addr.Slide(m_ranges.GetEntryRef(0).GetRangeBase ());
+ return true;
+ }
+ return false;
+}
+
+void
+Block::FinalizeRanges ()
+{
+ m_ranges.Sort();
+ m_ranges.CombineConsecutiveRanges ();
+}
+
+void
+Block::AddRange (const Range& range)
+{
+ Block *parent_block = GetParent ();
+ if (parent_block && !parent_block->Contains(range))
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));
+ if (log)
+ {
+ ModuleSP module_sp (m_parent_scope->CalculateSymbolContextModule());
+ Function *function = m_parent_scope->CalculateSymbolContextFunction();
+ const addr_t function_file_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ const addr_t block_start_addr = function_file_addr + range.GetRangeBase ();
+ const addr_t block_end_addr = function_file_addr + range.GetRangeEnd ();
+ Type *func_type = function->GetType();
+
+ const Declaration &func_decl = func_type->GetDeclaration();
+ if (func_decl.GetLine())
+ {
+ log->Printf ("warning: %s:%u block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s",
+ func_decl.GetFile().GetPath().c_str(),
+ func_decl.GetLine(),
+ GetID(),
+ (uint32_t)m_ranges.GetSize(),
+ block_start_addr,
+ block_end_addr,
+ parent_block->GetID(),
+ function->GetID(),
+ module_sp->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ log->Printf ("warning: block {0x%8.8" PRIx64 "} has range[%u] [0x%" PRIx64 " - 0x%" PRIx64 ") which is not contained in parent block {0x%8.8" PRIx64 "} in function {0x%8.8" PRIx64 "} from %s",
+ GetID(),
+ (uint32_t)m_ranges.GetSize(),
+ block_start_addr,
+ block_end_addr,
+ parent_block->GetID(),
+ function->GetID(),
+ module_sp->GetFileSpec().GetPath().c_str());
+ }
+ }
+ parent_block->AddRange (range);
+ }
+ m_ranges.Append(range);
+}
+
+// Return the current number of bytes that this object occupies in memory
+size_t
+Block::MemorySize() const
+{
+ size_t mem_size = sizeof(Block) + m_ranges.GetSize() * sizeof(Range);
+ if (m_inlineInfoSP.get())
+ mem_size += m_inlineInfoSP->MemorySize();
+ if (m_variable_list_sp.get())
+ mem_size += m_variable_list_sp->MemorySize();
+ return mem_size;
+
+}
+
+void
+Block::AddChild(const BlockSP &child_block_sp)
+{
+ if (child_block_sp)
+ {
+ child_block_sp->SetParentScope (this);
+ m_children.push_back (child_block_sp);
+ }
+}
+
+void
+Block::SetInlinedFunctionInfo(const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
+{
+ m_inlineInfoSP.reset(new InlineFunctionInfo(name, mangled, decl_ptr, call_decl_ptr));
+}
+
+
+
+VariableListSP
+Block::GetBlockVariableList (bool can_create)
+{
+ if (m_parsed_block_variables == false)
+ {
+ if (m_variable_list_sp.get() == NULL && can_create)
+ {
+ m_parsed_block_variables = true;
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ assert(sc.module_sp);
+ sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
+ }
+ }
+ return m_variable_list_sp;
+}
+
+uint32_t
+Block::AppendBlockVariables (bool can_create,
+ bool get_child_block_variables,
+ bool stop_if_child_block_is_inlined_function,
+ VariableList *variable_list)
+{
+ uint32_t num_variables_added = 0;
+ VariableList *block_var_list = GetBlockVariableList (can_create).get();
+ if (block_var_list)
+ {
+ num_variables_added += block_var_list->GetSize();
+ variable_list->AddVariables (block_var_list);
+ }
+
+ if (get_child_block_variables)
+ {
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ {
+ Block *child_block = pos->get();
+ if (stop_if_child_block_is_inlined_function == false ||
+ child_block->GetInlinedFunctionInfo() == NULL)
+ {
+ num_variables_added += child_block->AppendBlockVariables (can_create,
+ get_child_block_variables,
+ stop_if_child_block_is_inlined_function,
+ variable_list);
+ }
+ }
+ }
+ return num_variables_added;
+}
+
+uint32_t
+Block::AppendVariables
+(
+ bool can_create,
+ bool get_parent_variables,
+ bool stop_if_block_is_inlined_function,
+ VariableList *variable_list
+)
+{
+ uint32_t num_variables_added = 0;
+ VariableListSP variable_list_sp(GetBlockVariableList(can_create));
+
+ bool is_inlined_function = GetInlinedFunctionInfo() != NULL;
+ if (variable_list_sp.get())
+ {
+ num_variables_added = variable_list_sp->GetSize();
+ variable_list->AddVariables(variable_list_sp.get());
+ }
+
+ if (get_parent_variables)
+ {
+ if (stop_if_block_is_inlined_function && is_inlined_function)
+ return num_variables_added;
+
+ Block* parent_block = GetParent();
+ if (parent_block)
+ num_variables_added += parent_block->AppendVariables (can_create, get_parent_variables, stop_if_block_is_inlined_function, variable_list);
+ }
+ return num_variables_added;
+}
+
+clang::DeclContext *
+Block::GetClangDeclContext()
+{
+ SymbolContext sc;
+
+ CalculateSymbolContext (&sc);
+
+ if (!sc.module_sp)
+ return NULL;
+
+ SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
+
+ if (!sym_vendor)
+ return NULL;
+
+ SymbolFile *sym_file = sym_vendor->GetSymbolFile();
+
+ if (!sym_file)
+ return NULL;
+
+ return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
+}
+
+void
+Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
+{
+ m_parsed_block_info = b;
+ if (set_children)
+ {
+ m_parsed_child_blocks = true;
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ (*pos)->SetBlockInfoHasBeenParsed (b, true);
+ }
+}
+
+void
+Block::SetDidParseVariables (bool b, bool set_children)
+{
+ m_parsed_block_variables = b;
+ if (set_children)
+ {
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ (*pos)->SetDidParseVariables (b, true);
+ }
+}
+
+
+Block *
+Block::GetSibling() const
+{
+ if (m_parent_scope)
+ {
+ Block *parent_block = GetParent();
+ if (parent_block)
+ return parent_block->GetSiblingForChild (this);
+ }
+ return NULL;
+}
+// A parent of child blocks can be asked to find a sibling block given
+// one of its child blocks
+Block *
+Block::GetSiblingForChild (const Block *child_block) const
+{
+ if (!m_children.empty())
+ {
+ collection::const_iterator pos, end = m_children.end();
+ for (pos = m_children.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == child_block)
+ {
+ if (++pos != end)
+ return pos->get();
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp
new file mode 100644
index 000000000000..5ba9c6a8d796
--- /dev/null
+++ b/source/Symbol/ClangASTContext.cpp
@@ -0,0 +1,2291 @@
+//===-- ClangASTContext.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/Symbol/ClangASTContext.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+
+// Clang headers like to use NDEBUG inside of them to enable/disable debug
+// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// or another. This is bad because it means that if clang was built in release
+// mode, it assumes that you are building in release mode which is not always
+// the case. You can end up with functions that are defined as empty in header
+// files when NDEBUG is not defined, and this can cause link errors with the
+// clang .a files that you have since you might be missing functions in the .a
+// file. So we have to define NDEBUG when including clang headers to avoid any
+// mismatches. This is covered by rdar://problem/8691220
+
+#if !defined(NDEBUG) && !defined(LLVM_NDEBUG_OFF)
+#define LLDB_DEFINED_NDEBUG_FOR_CLANG
+#define NDEBUG
+// Need to include assert.h so it is as clang would expect it to be (disabled)
+#include <assert.h>
+#endif
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Frontend/FrontendOptions.h"
+#include "clang/Frontend/LangStandard.h"
+
+#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG
+#undef NDEBUG
+#undef LLDB_DEFINED_NDEBUG_FOR_CLANG
+// Need to re-include assert.h so it is as _we_ would expect it to be (enabled)
+#include <assert.h>
+#endif
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Expression/ASTDumper.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/VerifyDecl.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+#include <stdio.h>
+
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace llvm;
+using namespace clang;
+
+clang::AccessSpecifier
+ClangASTContext::ConvertAccessTypeToAccessSpecifier (AccessType access)
+{
+ switch (access)
+ {
+ default: break;
+ case eAccessNone: return AS_none;
+ case eAccessPublic: return AS_public;
+ case eAccessPrivate: return AS_private;
+ case eAccessProtected: return AS_protected;
+ }
+ return AS_none;
+}
+
+
+static void
+ParseLangArgs
+(
+ LangOptions &Opts,
+ InputKind IK
+)
+{
+ // FIXME: Cleanup per-file based stuff.
+
+ // Set some properties which depend soley on the input kind; it would be nice
+ // to move these to the language standard, and have the driver resolve the
+ // input kind + language standard.
+ if (IK == IK_Asm) {
+ Opts.AsmPreprocessor = 1;
+ } else if (IK == IK_ObjC ||
+ IK == IK_ObjCXX ||
+ IK == IK_PreprocessedObjC ||
+ IK == IK_PreprocessedObjCXX) {
+ Opts.ObjC1 = Opts.ObjC2 = 1;
+ }
+
+ LangStandard::Kind LangStd = LangStandard::lang_unspecified;
+
+ if (LangStd == LangStandard::lang_unspecified) {
+ // Based on the base language, pick one.
+ switch (IK) {
+ case IK_None:
+ case IK_AST:
+ case IK_LLVM_IR:
+ assert (!"Invalid input kind!");
+ case IK_OpenCL:
+ LangStd = LangStandard::lang_opencl;
+ break;
+ case IK_CUDA:
+ LangStd = LangStandard::lang_cuda;
+ break;
+ case IK_Asm:
+ case IK_C:
+ case IK_PreprocessedC:
+ case IK_ObjC:
+ case IK_PreprocessedObjC:
+ LangStd = LangStandard::lang_gnu99;
+ break;
+ case IK_CXX:
+ case IK_PreprocessedCXX:
+ case IK_ObjCXX:
+ case IK_PreprocessedObjCXX:
+ LangStd = LangStandard::lang_gnucxx98;
+ break;
+ }
+ }
+
+ const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
+ Opts.LineComment = Std.hasLineComments();
+ Opts.C99 = Std.isC99();
+ Opts.CPlusPlus = Std.isCPlusPlus();
+ Opts.CPlusPlus11 = Std.isCPlusPlus11();
+ Opts.Digraphs = Std.hasDigraphs();
+ Opts.GNUMode = Std.isGNUMode();
+ Opts.GNUInline = !Std.isC99();
+ Opts.HexFloats = Std.hasHexFloats();
+ Opts.ImplicitInt = Std.hasImplicitInt();
+
+ Opts.WChar = true;
+
+ // OpenCL has some additional defaults.
+ if (LangStd == LangStandard::lang_opencl) {
+ Opts.OpenCL = 1;
+ Opts.AltiVec = 1;
+ Opts.CXXOperatorNames = 1;
+ Opts.LaxVectorConversions = 1;
+ }
+
+ // OpenCL and C++ both have bool, true, false keywords.
+ Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
+
+// if (Opts.CPlusPlus)
+// Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
+//
+// if (Args.hasArg(OPT_fobjc_gc_only))
+// Opts.setGCMode(LangOptions::GCOnly);
+// else if (Args.hasArg(OPT_fobjc_gc))
+// Opts.setGCMode(LangOptions::HybridGC);
+//
+// if (Args.hasArg(OPT_print_ivar_layout))
+// Opts.ObjCGCBitmapPrint = 1;
+//
+// if (Args.hasArg(OPT_faltivec))
+// Opts.AltiVec = 1;
+//
+// if (Args.hasArg(OPT_pthread))
+// Opts.POSIXThreads = 1;
+//
+// llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility,
+// "default");
+// if (Vis == "default")
+ Opts.setValueVisibilityMode(DefaultVisibility);
+// else if (Vis == "hidden")
+// Opts.setVisibilityMode(LangOptions::Hidden);
+// else if (Vis == "protected")
+// Opts.setVisibilityMode(LangOptions::Protected);
+// else
+// Diags.Report(diag::err_drv_invalid_value)
+// << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
+
+// Opts.OverflowChecking = Args.hasArg(OPT_ftrapv);
+
+ // Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
+ // is specified, or -std is set to a conforming mode.
+ Opts.Trigraphs = !Opts.GNUMode;
+// if (Args.hasArg(OPT_trigraphs))
+// Opts.Trigraphs = 1;
+//
+// Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
+// OPT_fno_dollars_in_identifiers,
+// !Opts.AsmPreprocessor);
+// Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
+// Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
+// Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
+// if (Args.hasArg(OPT_fno_lax_vector_conversions))
+// Opts.LaxVectorConversions = 0;
+// Opts.Exceptions = Args.hasArg(OPT_fexceptions);
+// Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
+// Opts.Blocks = Args.hasArg(OPT_fblocks);
+// Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
+// Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
+// Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
+// Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
+// Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
+// Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
+// Opts.AccessControl = Args.hasArg(OPT_faccess_control);
+// Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
+// Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno);
+// Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
+// Diags);
+// Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
+// Opts.ObjCConstantStringClass = getLastArgValue(Args,
+// OPT_fconstant_string_class);
+// Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
+// Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
+// Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
+// Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
+// Opts.Static = Args.hasArg(OPT_static_define);
+ Opts.OptimizeSize = 0;
+
+ // FIXME: Eliminate this dependency.
+// unsigned Opt =
+// Args.hasArg(OPT_Os) ? 2 : getLastArgIntValue(Args, OPT_O, 0, Diags);
+// Opts.Optimize = Opt != 0;
+ unsigned Opt = 0;
+
+ // This is the __NO_INLINE__ define, which just depends on things like the
+ // optimization level and -fno-inline, not actually whether the backend has
+ // inlining enabled.
+ //
+ // FIXME: This is affected by other options (-fno-inline).
+ Opts.NoInlineDefine = !Opt;
+
+// unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags);
+// switch (SSP) {
+// default:
+// Diags.Report(diag::err_drv_invalid_value)
+// << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP;
+// break;
+// case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break;
+// case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break;
+// case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break;
+// }
+}
+
+
+ClangASTContext::ClangASTContext (const char *target_triple) :
+ m_target_triple(),
+ m_ast_ap(),
+ m_language_options_ap(),
+ m_source_manager_ap(),
+ m_diagnostics_engine_ap(),
+ m_target_options_rp(),
+ m_target_info_ap(),
+ m_identifier_table_ap(),
+ m_selector_table_ap(),
+ m_builtins_ap(),
+ m_callback_tag_decl (NULL),
+ m_callback_objc_decl (NULL),
+ m_callback_baton (NULL),
+ m_pointer_byte_size (0)
+
+{
+ if (target_triple && target_triple[0])
+ SetTargetTriple (target_triple);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ClangASTContext::~ClangASTContext()
+{
+ m_builtins_ap.reset();
+ m_selector_table_ap.reset();
+ m_identifier_table_ap.reset();
+ m_target_info_ap.reset();
+ m_target_options_rp.reset();
+ m_diagnostics_engine_ap.reset();
+ m_source_manager_ap.reset();
+ m_language_options_ap.reset();
+ m_ast_ap.reset();
+}
+
+
+void
+ClangASTContext::Clear()
+{
+ m_ast_ap.reset();
+ m_language_options_ap.reset();
+ m_source_manager_ap.reset();
+ m_diagnostics_engine_ap.reset();
+ m_target_options_rp.reset();
+ m_target_info_ap.reset();
+ m_identifier_table_ap.reset();
+ m_selector_table_ap.reset();
+ m_builtins_ap.reset();
+ m_pointer_byte_size = 0;
+}
+
+const char *
+ClangASTContext::GetTargetTriple ()
+{
+ return m_target_triple.c_str();
+}
+
+void
+ClangASTContext::SetTargetTriple (const char *target_triple)
+{
+ Clear();
+ m_target_triple.assign(target_triple);
+}
+
+void
+ClangASTContext::SetArchitecture (const ArchSpec &arch)
+{
+ SetTargetTriple(arch.GetTriple().str().c_str());
+}
+
+bool
+ClangASTContext::HasExternalSource ()
+{
+ ASTContext *ast = getASTContext();
+ if (ast)
+ return ast->getExternalSource () != NULL;
+ return false;
+}
+
+void
+ClangASTContext::SetExternalSource (llvm::OwningPtr<ExternalASTSource> &ast_source_ap)
+{
+ ASTContext *ast = getASTContext();
+ if (ast)
+ {
+ ast->setExternalSource (ast_source_ap);
+ ast->getTranslationUnitDecl()->setHasExternalLexicalStorage(true);
+ //ast->getTranslationUnitDecl()->setHasExternalVisibleStorage(true);
+ }
+}
+
+void
+ClangASTContext::RemoveExternalSource ()
+{
+ ASTContext *ast = getASTContext();
+
+ if (ast)
+ {
+ llvm::OwningPtr<ExternalASTSource> empty_ast_source_ap;
+ ast->setExternalSource (empty_ast_source_ap);
+ ast->getTranslationUnitDecl()->setHasExternalLexicalStorage(false);
+ //ast->getTranslationUnitDecl()->setHasExternalVisibleStorage(false);
+ }
+}
+
+
+
+ASTContext *
+ClangASTContext::getASTContext()
+{
+ if (m_ast_ap.get() == NULL)
+ {
+ m_ast_ap.reset(new ASTContext (*getLanguageOptions(),
+ *getSourceManager(),
+ getTargetInfo(),
+ *getIdentifierTable(),
+ *getSelectorTable(),
+ *getBuiltinContext(),
+ 0));
+
+ if ((m_callback_tag_decl || m_callback_objc_decl) && m_callback_baton)
+ {
+ m_ast_ap->getTranslationUnitDecl()->setHasExternalLexicalStorage();
+ //m_ast_ap->getTranslationUnitDecl()->setHasExternalVisibleStorage();
+ }
+
+ m_ast_ap->getDiagnostics().setClient(getDiagnosticConsumer(), false);
+ }
+ return m_ast_ap.get();
+}
+
+Builtin::Context *
+ClangASTContext::getBuiltinContext()
+{
+ if (m_builtins_ap.get() == NULL)
+ m_builtins_ap.reset (new Builtin::Context());
+ return m_builtins_ap.get();
+}
+
+IdentifierTable *
+ClangASTContext::getIdentifierTable()
+{
+ if (m_identifier_table_ap.get() == NULL)
+ m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), NULL));
+ return m_identifier_table_ap.get();
+}
+
+LangOptions *
+ClangASTContext::getLanguageOptions()
+{
+ if (m_language_options_ap.get() == NULL)
+ {
+ m_language_options_ap.reset(new LangOptions());
+ ParseLangArgs(*m_language_options_ap, IK_ObjCXX);
+// InitializeLangOptions(*m_language_options_ap, IK_ObjCXX);
+ }
+ return m_language_options_ap.get();
+}
+
+SelectorTable *
+ClangASTContext::getSelectorTable()
+{
+ if (m_selector_table_ap.get() == NULL)
+ m_selector_table_ap.reset (new SelectorTable());
+ return m_selector_table_ap.get();
+}
+
+clang::FileManager *
+ClangASTContext::getFileManager()
+{
+ if (m_file_manager_ap.get() == NULL)
+ {
+ clang::FileSystemOptions file_system_options;
+ m_file_manager_ap.reset(new clang::FileManager(file_system_options));
+ }
+ return m_file_manager_ap.get();
+}
+
+clang::SourceManager *
+ClangASTContext::getSourceManager()
+{
+ if (m_source_manager_ap.get() == NULL)
+ m_source_manager_ap.reset(new clang::SourceManager(*getDiagnosticsEngine(), *getFileManager()));
+ return m_source_manager_ap.get();
+}
+
+clang::DiagnosticsEngine *
+ClangASTContext::getDiagnosticsEngine()
+{
+ if (m_diagnostics_engine_ap.get() == NULL)
+ {
+ llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
+ m_diagnostics_engine_ap.reset(new DiagnosticsEngine(diag_id_sp, new DiagnosticOptions()));
+ }
+ return m_diagnostics_engine_ap.get();
+}
+
+class NullDiagnosticConsumer : public DiagnosticConsumer
+{
+public:
+ NullDiagnosticConsumer ()
+ {
+ m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+ }
+
+ void HandleDiagnostic (DiagnosticsEngine::Level DiagLevel, const Diagnostic &info)
+ {
+ if (m_log)
+ {
+ llvm::SmallVector<char, 32> diag_str(10);
+ info.FormatDiagnostic(diag_str);
+ diag_str.push_back('\0');
+ m_log->Printf("Compiler diagnostic: %s\n", diag_str.data());
+ }
+ }
+
+ DiagnosticConsumer *clone (DiagnosticsEngine &Diags) const
+ {
+ return new NullDiagnosticConsumer ();
+ }
+private:
+ Log * m_log;
+};
+
+DiagnosticConsumer *
+ClangASTContext::getDiagnosticConsumer()
+{
+ if (m_diagnostic_consumer_ap.get() == NULL)
+ m_diagnostic_consumer_ap.reset(new NullDiagnosticConsumer);
+
+ return m_diagnostic_consumer_ap.get();
+}
+
+TargetOptions *
+ClangASTContext::getTargetOptions()
+{
+ if (m_target_options_rp.getPtr() == NULL && !m_target_triple.empty())
+ {
+ m_target_options_rp.reset ();
+ m_target_options_rp = new TargetOptions();
+ if (m_target_options_rp.getPtr() != NULL)
+ m_target_options_rp->Triple = m_target_triple;
+ }
+ return m_target_options_rp.getPtr();
+}
+
+
+TargetInfo *
+ClangASTContext::getTargetInfo()
+{
+ // target_triple should be something like "x86_64-apple-macosx"
+ if (m_target_info_ap.get() == NULL && !m_target_triple.empty())
+ m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnosticsEngine(), getTargetOptions()));
+ return m_target_info_ap.get();
+}
+
+#pragma mark Basic Types
+
+static inline bool
+QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast, QualType qual_type)
+{
+ uint64_t qual_type_bit_size = ast->getTypeSize(qual_type);
+ if (qual_type_bit_size == bit_size)
+ return true;
+ return false;
+}
+ClangASTType
+ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (Encoding encoding, uint32_t bit_size)
+{
+ return ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (getASTContext(), encoding, bit_size);
+}
+
+ClangASTType
+ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (ASTContext *ast, Encoding encoding, uint32_t bit_size)
+{
+ if (!ast)
+ return ClangASTType();
+
+ switch (encoding)
+ {
+ case eEncodingInvalid:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy))
+ return ClangASTType (ast, ast->VoidPtrTy.getAsOpaquePtr());
+ break;
+
+ case eEncodingUint:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
+ return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
+ return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy))
+ return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy))
+ return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy))
+ return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty))
+ return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr());
+ break;
+
+ case eEncodingSint:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy))
+ return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy))
+ return ClangASTType (ast, ast->IntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy))
+ return ClangASTType (ast, ast->LongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy))
+ return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty))
+ return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr());
+ break;
+
+ case eEncodingIEEE754:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy))
+ return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy))
+ return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy))
+ return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr());
+ break;
+
+ case eEncodingVector:
+ // Sanity check that bit_size is a multiple of 8's.
+ if (bit_size && !(bit_size & 0x7u))
+ return ClangASTType (ast, ast->getExtVectorType (ast->UnsignedCharTy, bit_size/8).getAsOpaquePtr());
+ break;
+ }
+
+ return ClangASTType();
+}
+
+
+
+lldb::BasicType
+ClangASTContext::GetBasicTypeEnumeration (const ConstString &name)
+{
+ if (name)
+ {
+ typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
+ static TypeNameToBasicTypeMap g_type_map;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, [](){
+ // "void"
+ g_type_map.Append(ConstString("void").GetCString(), eBasicTypeVoid);
+
+ // "char"
+ g_type_map.Append(ConstString("char").GetCString(), eBasicTypeChar);
+ g_type_map.Append(ConstString("signed char").GetCString(), eBasicTypeSignedChar);
+ g_type_map.Append(ConstString("unsigned char").GetCString(), eBasicTypeUnsignedChar);
+ g_type_map.Append(ConstString("wchar_t").GetCString(), eBasicTypeWChar);
+ g_type_map.Append(ConstString("signed wchar_t").GetCString(), eBasicTypeSignedWChar);
+ g_type_map.Append(ConstString("unsigned wchar_t").GetCString(), eBasicTypeUnsignedWChar);
+ // "short"
+ g_type_map.Append(ConstString("short").GetCString(), eBasicTypeShort);
+ g_type_map.Append(ConstString("short int").GetCString(), eBasicTypeShort);
+ g_type_map.Append(ConstString("unsigned short").GetCString(), eBasicTypeUnsignedShort);
+ g_type_map.Append(ConstString("unsigned short int").GetCString(), eBasicTypeUnsignedShort);
+
+ // "int"
+ g_type_map.Append(ConstString("int").GetCString(), eBasicTypeInt);
+ g_type_map.Append(ConstString("signed int").GetCString(), eBasicTypeInt);
+ g_type_map.Append(ConstString("unsigned int").GetCString(), eBasicTypeUnsignedInt);
+ g_type_map.Append(ConstString("unsigned").GetCString(), eBasicTypeUnsignedInt);
+
+ // "long"
+ g_type_map.Append(ConstString("long").GetCString(), eBasicTypeLong);
+ g_type_map.Append(ConstString("long int").GetCString(), eBasicTypeLong);
+ g_type_map.Append(ConstString("unsigned long").GetCString(), eBasicTypeUnsignedLong);
+ g_type_map.Append(ConstString("unsigned long int").GetCString(), eBasicTypeUnsignedLong);
+
+ // "long long"
+ g_type_map.Append(ConstString("long long").GetCString(), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("long long int").GetCString(), eBasicTypeLongLong);
+ g_type_map.Append(ConstString("unsigned long long").GetCString(), eBasicTypeUnsignedLongLong);
+ g_type_map.Append(ConstString("unsigned long long int").GetCString(), eBasicTypeUnsignedLongLong);
+
+ // "int128"
+ g_type_map.Append(ConstString("__int128_t").GetCString(), eBasicTypeInt128);
+ g_type_map.Append(ConstString("__uint128_t").GetCString(), eBasicTypeUnsignedInt128);
+
+ // Miscelaneous
+ g_type_map.Append(ConstString("bool").GetCString(), eBasicTypeBool);
+ g_type_map.Append(ConstString("float").GetCString(), eBasicTypeFloat);
+ g_type_map.Append(ConstString("double").GetCString(), eBasicTypeDouble);
+ g_type_map.Append(ConstString("long double").GetCString(), eBasicTypeLongDouble);
+ g_type_map.Append(ConstString("id").GetCString(), eBasicTypeObjCID);
+ g_type_map.Append(ConstString("SEL").GetCString(), eBasicTypeObjCSel);
+ g_type_map.Append(ConstString("nullptr").GetCString(), eBasicTypeNullPtr);
+ g_type_map.Sort();
+ });
+
+ return g_type_map.Find(name.GetCString(), eBasicTypeInvalid);
+ }
+ return eBasicTypeInvalid;
+}
+
+ClangASTType
+ClangASTContext::GetBasicType (ASTContext *ast, const ConstString &name)
+{
+ if (ast)
+ {
+ lldb::BasicType basic_type = ClangASTContext::GetBasicTypeEnumeration (name);
+ return ClangASTContext::GetBasicType (ast, basic_type);
+ }
+ return ClangASTType();
+}
+
+uint32_t
+ClangASTContext::GetPointerByteSize ()
+{
+ if (m_pointer_byte_size == 0)
+ m_pointer_byte_size = GetBasicType(lldb::eBasicTypeVoid).GetPointerType().GetByteSize();
+ return m_pointer_byte_size;
+}
+
+ClangASTType
+ClangASTContext::GetBasicType (lldb::BasicType basic_type)
+{
+ return GetBasicType (getASTContext(), basic_type);
+}
+
+ClangASTType
+ClangASTContext::GetBasicType (ASTContext *ast, lldb::BasicType basic_type)
+{
+ if (ast)
+ {
+ clang_type_t clang_type = NULL;
+
+ switch (basic_type)
+ {
+ case eBasicTypeInvalid:
+ case eBasicTypeOther:
+ break;
+ case eBasicTypeVoid:
+ clang_type = ast->VoidTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeChar:
+ clang_type = ast->CharTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeSignedChar:
+ clang_type = ast->SignedCharTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedChar:
+ clang_type = ast->UnsignedCharTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeWChar:
+ clang_type = ast->getWCharType().getAsOpaquePtr();
+ break;
+ case eBasicTypeSignedWChar:
+ clang_type = ast->getSignedWCharType().getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedWChar:
+ clang_type = ast->getUnsignedWCharType().getAsOpaquePtr();
+ break;
+ case eBasicTypeChar16:
+ clang_type = ast->Char16Ty.getAsOpaquePtr();
+ break;
+ case eBasicTypeChar32:
+ clang_type = ast->Char32Ty.getAsOpaquePtr();
+ break;
+ case eBasicTypeShort:
+ clang_type = ast->ShortTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedShort:
+ clang_type = ast->UnsignedShortTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeInt:
+ clang_type = ast->IntTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedInt:
+ clang_type = ast->UnsignedIntTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeLong:
+ clang_type = ast->LongTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedLong:
+ clang_type = ast->UnsignedLongTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeLongLong:
+ clang_type = ast->LongLongTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedLongLong:
+ clang_type = ast->UnsignedLongLongTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeInt128:
+ clang_type = ast->Int128Ty.getAsOpaquePtr();
+ break;
+ case eBasicTypeUnsignedInt128:
+ clang_type = ast->UnsignedInt128Ty.getAsOpaquePtr();
+ break;
+ case eBasicTypeBool:
+ clang_type = ast->BoolTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeHalf:
+ clang_type = ast->HalfTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeFloat:
+ clang_type = ast->FloatTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeDouble:
+ clang_type = ast->DoubleTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeLongDouble:
+ clang_type = ast->LongDoubleTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeFloatComplex:
+ clang_type = ast->FloatComplexTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeDoubleComplex:
+ clang_type = ast->DoubleComplexTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeLongDoubleComplex:
+ clang_type = ast->LongDoubleComplexTy.getAsOpaquePtr();
+ break;
+ case eBasicTypeObjCID:
+ clang_type = ast->getObjCIdType().getAsOpaquePtr();
+ break;
+ case eBasicTypeObjCClass:
+ clang_type = ast->getObjCClassType().getAsOpaquePtr();
+ break;
+ case eBasicTypeObjCSel:
+ clang_type = ast->getObjCSelType().getAsOpaquePtr();
+ break;
+ case eBasicTypeNullPtr:
+ clang_type = ast->NullPtrTy.getAsOpaquePtr();
+ break;
+ }
+
+ if (clang_type)
+ return ClangASTType (ast, clang_type);
+ }
+ return ClangASTType();
+}
+
+
+ClangASTType
+ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size)
+{
+ ASTContext *ast = getASTContext();
+
+#define streq(a,b) strcmp(a,b) == 0
+ assert (ast != NULL);
+ if (ast)
+ {
+ switch (dw_ate)
+ {
+ default:
+ break;
+
+ case DW_ATE_address:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy))
+ return ClangASTType (ast, ast->VoidPtrTy.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_boolean:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->BoolTy))
+ return ClangASTType (ast, ast->BoolTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
+ return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
+ return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy))
+ return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_lo_user:
+ // This has been seen to mean DW_AT_complex_integer
+ if (type_name)
+ {
+ if (::strstr(type_name, "complex"))
+ {
+ ClangASTType complex_int_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("int", DW_ATE_signed, bit_size/2);
+ return ClangASTType (ast, ast->getComplexType (complex_int_clang_type.GetQualType()).getAsOpaquePtr());
+ }
+ }
+ break;
+
+ case DW_ATE_complex_float:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatComplexTy))
+ return ClangASTType (ast, ast->FloatComplexTy.getAsOpaquePtr());
+ else if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleComplexTy))
+ return ClangASTType (ast, ast->DoubleComplexTy.getAsOpaquePtr());
+ else if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleComplexTy))
+ return ClangASTType (ast, ast->LongDoubleComplexTy.getAsOpaquePtr());
+ else
+ {
+ ClangASTType complex_float_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("float", DW_ATE_float, bit_size/2);
+ return ClangASTType (ast, ast->getComplexType (complex_float_clang_type.GetQualType()).getAsOpaquePtr());
+ }
+ break;
+
+ case DW_ATE_float:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy))
+ return ClangASTType (ast, ast->FloatTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy))
+ return ClangASTType (ast, ast->DoubleTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy))
+ return ClangASTType (ast, ast->LongDoubleTy.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_signed:
+ if (type_name)
+ {
+ if (streq(type_name, "wchar_t") &&
+ QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy))
+ return ClangASTType (ast, ast->WCharTy.getAsOpaquePtr());
+ if (streq(type_name, "void") &&
+ QualTypeMatchesBitSize (bit_size, ast, ast->VoidTy))
+ return ClangASTType (ast, ast->VoidTy.getAsOpaquePtr());
+ if (strstr(type_name, "long long") &&
+ QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy))
+ return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr());
+ if (strstr(type_name, "long") &&
+ QualTypeMatchesBitSize (bit_size, ast, ast->LongTy))
+ return ClangASTType (ast, ast->LongTy.getAsOpaquePtr());
+ if (strstr(type_name, "short") &&
+ QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy))
+ return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr());
+ if (strstr(type_name, "char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy))
+ return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr());
+ }
+ if (strstr(type_name, "int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy))
+ return ClangASTType (ast, ast->IntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty))
+ return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr());
+ }
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy))
+ return ClangASTType (ast, ast->ShortTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy))
+ return ClangASTType (ast, ast->IntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy))
+ return ClangASTType (ast, ast->LongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy))
+ return ClangASTType (ast, ast->LongLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty))
+ return ClangASTType (ast, ast->Int128Ty.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_signed_char:
+ if (type_name)
+ {
+ if (streq(type_name, "signed char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy))
+ return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr());
+ }
+ }
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy))
+ return ClangASTType (ast, ast->CharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy))
+ return ClangASTType (ast, ast->SignedCharTy.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_unsigned:
+ if (type_name)
+ {
+ if (strstr(type_name, "long long"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy))
+ return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr());
+ }
+ else if (strstr(type_name, "long"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy))
+ return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr());
+ }
+ else if (strstr(type_name, "short"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
+ return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr());
+ }
+ else if (strstr(type_name, "char"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
+ return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
+ }
+ else if (strstr(type_name, "int"))
+ {
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy))
+ return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty))
+ return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr());
+ }
+ }
+ // We weren't able to match up a type name, just search by size
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
+ return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
+ return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy))
+ return ClangASTType (ast, ast->UnsignedIntTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy))
+ return ClangASTType (ast, ast->UnsignedLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy))
+ return ClangASTType (ast, ast->UnsignedLongLongTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty))
+ return ClangASTType (ast, ast->UnsignedInt128Ty.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_unsigned_char:
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy))
+ return ClangASTType (ast, ast->UnsignedCharTy.getAsOpaquePtr());
+ if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy))
+ return ClangASTType (ast, ast->UnsignedShortTy.getAsOpaquePtr());
+ break;
+
+ case DW_ATE_imaginary_float:
+ break;
+
+ case DW_ATE_UTF:
+ if (type_name)
+ {
+ if (streq(type_name, "char16_t"))
+ {
+ return ClangASTType (ast, ast->Char16Ty.getAsOpaquePtr());
+ }
+ else if (streq(type_name, "char32_t"))
+ {
+ return ClangASTType (ast, ast->Char32Ty.getAsOpaquePtr());
+ }
+ }
+ break;
+ }
+ }
+ // This assert should fire for anything that we don't catch above so we know
+ // to fix any issues we run into.
+ if (type_name)
+ {
+ Host::SystemLog (Host::eSystemLogError, "error: need to add support for DW_TAG_base_type '%s' encoded with DW_ATE = 0x%x, bit_size = %u\n", type_name, dw_ate, bit_size);
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogError, "error: need to add support for DW_TAG_base_type encoded with DW_ATE = 0x%x, bit_size = %u\n", dw_ate, bit_size);
+ }
+ return ClangASTType ();
+}
+
+ClangASTType
+ClangASTContext::GetUnknownAnyType(clang::ASTContext *ast)
+{
+ if (ast)
+ return ClangASTType (ast, ast->UnknownAnyTy.getAsOpaquePtr());
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTContext::GetCStringType (bool is_const)
+{
+ ASTContext *ast = getASTContext();
+ QualType char_type(ast->CharTy);
+
+ if (is_const)
+ char_type.addConst();
+
+ return ClangASTType (ast, ast->getPointerType(char_type).getAsOpaquePtr());
+}
+
+clang::DeclContext *
+ClangASTContext::GetTranslationUnitDecl (clang::ASTContext *ast)
+{
+ return ast->getTranslationUnitDecl();
+}
+
+ClangASTType
+ClangASTContext::CopyType (ASTContext *dst_ast,
+ ClangASTType src)
+{
+ FileSystemOptions file_system_options;
+ ASTContext *src_ast = src.GetASTContext();
+ FileManager file_manager (file_system_options);
+ ASTImporter importer(*dst_ast, file_manager,
+ *src_ast, file_manager,
+ false);
+
+ QualType dst (importer.Import(src.GetQualType()));
+
+ return ClangASTType (dst_ast, dst.getAsOpaquePtr());
+}
+
+
+clang::Decl *
+ClangASTContext::CopyDecl (ASTContext *dst_ast,
+ ASTContext *src_ast,
+ clang::Decl *source_decl)
+{
+ FileSystemOptions file_system_options;
+ FileManager file_manager (file_system_options);
+ ASTImporter importer(*dst_ast, file_manager,
+ *src_ast, file_manager,
+ false);
+
+ return importer.Import(source_decl);
+}
+
+bool
+ClangASTContext::AreTypesSame (ClangASTType type1,
+ ClangASTType type2,
+ bool ignore_qualifiers)
+{
+ ASTContext *ast = type1.GetASTContext();
+ if (ast != type2.GetASTContext())
+ return false;
+
+ if (type1.GetOpaqueQualType() == type2.GetOpaqueQualType())
+ return true;
+
+ QualType type1_qual = type1.GetQualType();
+ QualType type2_qual = type2.GetQualType();
+
+ if (ignore_qualifiers)
+ {
+ type1_qual = type1_qual.getUnqualifiedType();
+ type2_qual = type2_qual.getUnqualifiedType();
+ }
+
+ return ast->hasSameType (type1_qual, type2_qual);
+}
+
+
+ClangASTType
+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();
+ if (ast)
+ return ClangASTType (ast, ast->getTagDeclType(decl).getAsOpaquePtr());
+ return ClangASTType();
+}
+
+ClangASTType
+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();
+ if (ast)
+ return ClangASTType (ast, ast->getObjCInterfaceType(decl).getAsOpaquePtr());
+ return ClangASTType();
+}
+
+#pragma mark Structure, Unions, Classes
+
+ClangASTType
+ClangASTContext::CreateRecordType (DeclContext *decl_ctx,
+ AccessType access_type,
+ const char *name,
+ int kind,
+ LanguageType language,
+ ClangASTMetadata *metadata)
+{
+ ASTContext *ast = getASTContext();
+ assert (ast != NULL);
+
+ if (decl_ctx == NULL)
+ decl_ctx = ast->getTranslationUnitDecl();
+
+
+ if (language == eLanguageTypeObjC || language == eLanguageTypeObjC_plus_plus)
+ {
+ bool isForwardDecl = true;
+ bool isInternal = false;
+ return CreateObjCClass (name, decl_ctx, isForwardDecl, isInternal, metadata);
+ }
+
+ // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and
+ // we will need to update this code. I was told to currently always use
+ // the CXXRecordDecl class since we often don't know from debug information
+ // if something is struct or a class, so we default to always use the more
+ // complete definition just in case.
+ CXXRecordDecl *decl = CXXRecordDecl::Create (*ast,
+ (TagDecl::TagKind)kind,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ name && name[0] ? &ast->Idents.get(name) : NULL);
+
+ if (decl)
+ {
+ if (metadata)
+ SetMetadata(ast, decl, *metadata);
+
+ if (access_type != eAccessNone)
+ decl->setAccess (ConvertAccessTypeToAccessSpecifier (access_type));
+
+ if (decl_ctx)
+ decl_ctx->addDecl (decl);
+
+ return ClangASTType(ast, ast->getTagDeclType(decl).getAsOpaquePtr());
+ }
+ return ClangASTType();
+}
+
+static TemplateParameterList *
+CreateTemplateParameterList (ASTContext *ast,
+ const ClangASTContext::TemplateParameterInfos &template_param_infos,
+ llvm::SmallVector<NamedDecl *, 8> &template_param_decls)
+{
+ const bool parameter_pack = false;
+ const bool is_typename = false;
+ const unsigned depth = 0;
+ const size_t num_template_params = template_param_infos.GetSize();
+ for (size_t i=0; i<num_template_params; ++i)
+ {
+ const char *name = template_param_infos.names[i];
+
+ IdentifierInfo *identifier_info = NULL;
+ if (name && name[0])
+ identifier_info = &ast->Idents.get(name);
+ if (template_param_infos.args[i].getKind() == TemplateArgument::Integral)
+ {
+ template_param_decls.push_back (NonTypeTemplateParmDecl::Create (*ast,
+ ast->getTranslationUnitDecl(), // Is this the right decl context?, SourceLocation StartLoc,
+ SourceLocation(),
+ SourceLocation(),
+ depth,
+ i,
+ identifier_info,
+ template_param_infos.args[i].getIntegralType(),
+ parameter_pack,
+ NULL));
+
+ }
+ else
+ {
+ template_param_decls.push_back (TemplateTypeParmDecl::Create (*ast,
+ ast->getTranslationUnitDecl(), // Is this the right decl context?
+ SourceLocation(),
+ SourceLocation(),
+ depth,
+ i,
+ identifier_info,
+ is_typename,
+ parameter_pack));
+ }
+ }
+
+ TemplateParameterList *template_param_list = TemplateParameterList::Create (*ast,
+ SourceLocation(),
+ SourceLocation(),
+ &template_param_decls.front(),
+ template_param_decls.size(),
+ SourceLocation());
+ return template_param_list;
+}
+
+clang::FunctionTemplateDecl *
+ClangASTContext::CreateFunctionTemplateDecl (clang::DeclContext *decl_ctx,
+ clang::FunctionDecl *func_decl,
+ const char *name,
+ const TemplateParameterInfos &template_param_infos)
+{
+// /// \brief Create a function template node.
+ ASTContext *ast = getASTContext();
+
+ llvm::SmallVector<NamedDecl *, 8> template_param_decls;
+
+ TemplateParameterList *template_param_list = CreateTemplateParameterList (ast,
+ template_param_infos,
+ template_param_decls);
+ FunctionTemplateDecl *func_tmpl_decl = FunctionTemplateDecl::Create (*ast,
+ decl_ctx,
+ func_decl->getLocation(),
+ func_decl->getDeclName(),
+ template_param_list,
+ func_decl);
+
+ for (size_t i=0, template_param_decl_count = template_param_decls.size();
+ i < template_param_decl_count;
+ ++i)
+ {
+ // TODO: verify which decl context we should put template_param_decls into..
+ template_param_decls[i]->setDeclContext (func_decl);
+ }
+
+ return func_tmpl_decl;
+}
+
+void
+ClangASTContext::CreateFunctionTemplateSpecializationInfo (FunctionDecl *func_decl,
+ clang::FunctionTemplateDecl *func_tmpl_decl,
+ const TemplateParameterInfos &infos)
+{
+ TemplateArgumentList template_args (TemplateArgumentList::OnStack,
+ infos.args.data(),
+ infos.args.size());
+
+ func_decl->setFunctionTemplateSpecialization (func_tmpl_decl,
+ &template_args,
+ NULL);
+}
+
+
+ClassTemplateDecl *
+ClangASTContext::CreateClassTemplateDecl (DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *class_name,
+ int kind,
+ const TemplateParameterInfos &template_param_infos)
+{
+ ASTContext *ast = getASTContext();
+
+ ClassTemplateDecl *class_template_decl = NULL;
+ if (decl_ctx == NULL)
+ decl_ctx = ast->getTranslationUnitDecl();
+
+ IdentifierInfo &identifier_info = ast->Idents.get(class_name);
+ DeclarationName decl_name (&identifier_info);
+
+ clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
+
+ for (NamedDecl *decl : result)
+ {
+ class_template_decl = dyn_cast<clang::ClassTemplateDecl>(decl);
+ if (class_template_decl)
+ return class_template_decl;
+ }
+
+ llvm::SmallVector<NamedDecl *, 8> template_param_decls;
+
+ TemplateParameterList *template_param_list = CreateTemplateParameterList (ast,
+ template_param_infos,
+ template_param_decls);
+
+ CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create (*ast,
+ (TagDecl::TagKind)kind,
+ decl_ctx, // What decl context do we use here? TU? The actual decl context?
+ SourceLocation(),
+ SourceLocation(),
+ &identifier_info);
+
+ for (size_t i=0, template_param_decl_count = template_param_decls.size();
+ i < template_param_decl_count;
+ ++i)
+ {
+ template_param_decls[i]->setDeclContext (template_cxx_decl);
+ }
+
+ // With templated classes, we say that a class is templated with
+ // specializations, but that the bare class has no functions.
+ //template_cxx_decl->startDefinition();
+ //template_cxx_decl->completeDefinition();
+
+ class_template_decl = ClassTemplateDecl::Create (*ast,
+ decl_ctx, // What decl context do we use here? TU? The actual decl context?
+ SourceLocation(),
+ decl_name,
+ template_param_list,
+ template_cxx_decl,
+ NULL);
+
+ if (class_template_decl)
+ {
+ if (access_type != eAccessNone)
+ class_template_decl->setAccess (ConvertAccessTypeToAccessSpecifier (access_type));
+
+ //if (TagDecl *ctx_tag_decl = dyn_cast<TagDecl>(decl_ctx))
+ // CompleteTagDeclarationDefinition(GetTypeForDecl(ctx_tag_decl));
+
+ decl_ctx->addDecl (class_template_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(class_template_decl);
+#endif
+ }
+
+ return class_template_decl;
+}
+
+
+ClassTemplateSpecializationDecl *
+ClangASTContext::CreateClassTemplateSpecializationDecl (DeclContext *decl_ctx,
+ ClassTemplateDecl *class_template_decl,
+ int kind,
+ const TemplateParameterInfos &template_param_infos)
+{
+ ASTContext *ast = getASTContext();
+ ClassTemplateSpecializationDecl *class_template_specialization_decl = ClassTemplateSpecializationDecl::Create (*ast,
+ (TagDecl::TagKind)kind,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ class_template_decl,
+ &template_param_infos.args.front(),
+ template_param_infos.args.size(),
+ NULL);
+
+ class_template_specialization_decl->setSpecializationKind(TSK_ExplicitSpecialization);
+
+ return class_template_specialization_decl;
+}
+
+ClangASTType
+ClangASTContext::CreateClassTemplateSpecializationType (ClassTemplateSpecializationDecl *class_template_specialization_decl)
+{
+ if (class_template_specialization_decl)
+ {
+ ASTContext *ast = getASTContext();
+ if (ast)
+ return ClangASTType(ast, ast->getTagDeclType(class_template_specialization_decl).getAsOpaquePtr());
+ }
+ return ClangASTType();
+}
+
+static bool
+IsOperator (const char *name, OverloadedOperatorKind &op_kind)
+{
+ if (name == NULL || name[0] == '\0')
+ return false;
+
+#define OPERATOR_PREFIX "operator"
+#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1)
+
+ const char *post_op_name = NULL;
+
+ bool no_space = true;
+
+ if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH))
+ return false;
+
+ post_op_name = name + OPERATOR_PREFIX_LENGTH;
+
+ if (post_op_name[0] == ' ')
+ {
+ post_op_name++;
+ no_space = false;
+ }
+
+#undef OPERATOR_PREFIX
+#undef OPERATOR_PREFIX_LENGTH
+
+ // This is an operator, set the overloaded operator kind to invalid
+ // in case this is a conversion operator...
+ op_kind = NUM_OVERLOADED_OPERATORS;
+
+ switch (post_op_name[0])
+ {
+ default:
+ if (no_space)
+ return false;
+ break;
+ case 'n':
+ if (no_space)
+ return false;
+ if (strcmp (post_op_name, "new") == 0)
+ op_kind = OO_New;
+ else if (strcmp (post_op_name, "new[]") == 0)
+ op_kind = OO_Array_New;
+ break;
+
+ case 'd':
+ if (no_space)
+ return false;
+ if (strcmp (post_op_name, "delete") == 0)
+ op_kind = OO_Delete;
+ else if (strcmp (post_op_name, "delete[]") == 0)
+ op_kind = OO_Array_Delete;
+ break;
+
+ case '+':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Plus;
+ else if (post_op_name[2] == '\0')
+ {
+ if (post_op_name[1] == '=')
+ op_kind = OO_PlusEqual;
+ else if (post_op_name[1] == '+')
+ op_kind = OO_PlusPlus;
+ }
+ break;
+
+ case '-':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Minus;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_MinusEqual; break;
+ case '-': op_kind = OO_MinusMinus; break;
+ case '>': op_kind = OO_Arrow; break;
+ }
+ }
+ else if (post_op_name[3] == '\0')
+ {
+ if (post_op_name[2] == '*')
+ op_kind = OO_ArrowStar; break;
+ }
+ break;
+
+ case '*':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Star;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_StarEqual;
+ break;
+
+ case '/':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Slash;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_SlashEqual;
+ break;
+
+ case '%':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Percent;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_PercentEqual;
+ break;
+
+
+ case '^':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Caret;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_CaretEqual;
+ break;
+
+ case '&':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Amp;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_AmpEqual; break;
+ case '&': op_kind = OO_AmpAmp; break;
+ }
+ }
+ break;
+
+ case '|':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Pipe;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_PipeEqual; break;
+ case '|': op_kind = OO_PipePipe; break;
+ }
+ }
+ break;
+
+ case '~':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Tilde;
+ break;
+
+ case '!':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Exclaim;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_ExclaimEqual;
+ break;
+
+ case '=':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Equal;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_EqualEqual;
+ break;
+
+ case '<':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Less;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '<': op_kind = OO_LessLess; break;
+ case '=': op_kind = OO_LessEqual; break;
+ }
+ }
+ else if (post_op_name[3] == '\0')
+ {
+ if (post_op_name[2] == '=')
+ op_kind = OO_LessLessEqual;
+ }
+ break;
+
+ case '>':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Greater;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '>': op_kind = OO_GreaterGreater; break;
+ case '=': op_kind = OO_GreaterEqual; break;
+ }
+ }
+ else if (post_op_name[1] == '>' &&
+ post_op_name[2] == '=' &&
+ post_op_name[3] == '\0')
+ {
+ op_kind = OO_GreaterGreaterEqual;
+ }
+ break;
+
+ case ',':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Comma;
+ break;
+
+ case '(':
+ if (post_op_name[1] == ')' && post_op_name[2] == '\0')
+ op_kind = OO_Call;
+ break;
+
+ case '[':
+ if (post_op_name[1] == ']' && post_op_name[2] == '\0')
+ op_kind = OO_Subscript;
+ break;
+ }
+
+ return true;
+}
+
+static inline bool
+check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params)
+{
+ // Special-case call since it can take any number of operands
+ if(op_kind == OO_Call)
+ return true;
+
+ // The parameter count doens't include "this"
+ if (num_params == 0)
+ return unary;
+ if (num_params == 1)
+ return binary;
+ else
+ return false;
+}
+
+bool
+ClangASTContext::CheckOverloadedOperatorKindParameterCount (uint32_t op_kind, uint32_t num_params)
+{
+ switch (op_kind)
+ {
+ default:
+ break;
+ // C++ standard allows any number of arguments to new/delete
+ case OO_New:
+ case OO_Array_New:
+ case OO_Delete:
+ case OO_Array_Delete:
+ return true;
+ }
+
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) case OO_##Name: return check_op_param (op_kind, Unary, Binary, num_params);
+ switch (op_kind)
+ {
+#include "clang/Basic/OperatorKinds.def"
+ default: break;
+ }
+ return false;
+}
+
+clang::AccessSpecifier
+ClangASTContext::UnifyAccessSpecifiers (clang::AccessSpecifier lhs, clang::AccessSpecifier rhs)
+{
+ clang::AccessSpecifier ret = lhs;
+
+ // Make the access equal to the stricter of the field and the nested field's access
+ switch (ret)
+ {
+ case clang::AS_none:
+ break;
+ case clang::AS_private:
+ break;
+ case clang::AS_protected:
+ if (rhs == AS_private)
+ ret = AS_private;
+ break;
+ case clang::AS_public:
+ ret = rhs;
+ break;
+ }
+
+ return ret;
+}
+
+bool
+ClangASTContext::FieldIsBitfield (FieldDecl* field, uint32_t& bitfield_bit_size)
+{
+ return FieldIsBitfield(getASTContext(), field, bitfield_bit_size);
+}
+
+bool
+ClangASTContext::FieldIsBitfield
+(
+ ASTContext *ast,
+ FieldDecl* field,
+ uint32_t& bitfield_bit_size
+)
+{
+ if (ast == NULL || field == NULL)
+ return false;
+
+ if (field->isBitField())
+ {
+ Expr* bit_width_expr = field->getBitWidth();
+ if (bit_width_expr)
+ {
+ llvm::APSInt bit_width_apsint;
+ if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, *ast))
+ {
+ bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTContext::RecordHasFields (const RecordDecl *record_decl)
+{
+ if (record_decl == NULL)
+ return false;
+
+ if (!record_decl->field_empty())
+ return true;
+
+ // No fields, lets check this is a CXX record and check the base classes
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ if (RecordHasFields(base_class_decl))
+ return true;
+ }
+ }
+ return false;
+}
+
+#pragma mark Objective C Classes
+
+ClangASTType
+ClangASTContext::CreateObjCClass
+(
+ const char *name,
+ DeclContext *decl_ctx,
+ bool isForwardDecl,
+ bool isInternal,
+ ClangASTMetadata *metadata
+)
+{
+ ASTContext *ast = getASTContext();
+ assert (ast != NULL);
+ assert (name && name[0]);
+ if (decl_ctx == NULL)
+ decl_ctx = ast->getTranslationUnitDecl();
+
+ ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create (*ast,
+ decl_ctx,
+ SourceLocation(),
+ &ast->Idents.get(name),
+ NULL,
+ SourceLocation(),
+ /*isForwardDecl,*/
+ isInternal);
+
+ if (decl && metadata)
+ SetMetadata(ast, decl, *metadata);
+
+ return ClangASTType (ast, ast->getObjCInterfaceType(decl));
+}
+
+static inline bool
+BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
+{
+ return ClangASTContext::RecordHasFields(b->getType()->getAsCXXRecordDecl()) == false;
+}
+
+uint32_t
+ClangASTContext::GetNumBaseClasses (const CXXRecordDecl *cxx_record_decl, bool omit_empty_base_classes)
+{
+ uint32_t num_bases = 0;
+ if (cxx_record_decl)
+ {
+ if (omit_empty_base_classes)
+ {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ // Skip empty base classes
+ if (omit_empty_base_classes)
+ {
+ if (BaseSpecifierIsEmpty (base_class))
+ continue;
+ }
+ ++num_bases;
+ }
+ }
+ else
+ num_bases = cxx_record_decl->getNumBases();
+ }
+ return num_bases;
+}
+
+
+#pragma mark Namespace Declarations
+
+NamespaceDecl *
+ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, DeclContext *decl_ctx)
+{
+ NamespaceDecl *namespace_decl = NULL;
+ ASTContext *ast = getASTContext();
+ TranslationUnitDecl *translation_unit_decl = ast->getTranslationUnitDecl ();
+ if (decl_ctx == NULL)
+ decl_ctx = translation_unit_decl;
+
+ if (name)
+ {
+ IdentifierInfo &identifier_info = ast->Idents.get(name);
+ DeclarationName decl_name (&identifier_info);
+ clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name);
+ for (NamedDecl *decl : result)
+ {
+ namespace_decl = dyn_cast<clang::NamespaceDecl>(decl);
+ if (namespace_decl)
+ return namespace_decl;
+ }
+
+ namespace_decl = NamespaceDecl::Create(*ast,
+ decl_ctx,
+ false,
+ SourceLocation(),
+ SourceLocation(),
+ &identifier_info,
+ NULL);
+
+ decl_ctx->addDecl (namespace_decl);
+ }
+ else
+ {
+ if (decl_ctx == translation_unit_decl)
+ {
+ namespace_decl = translation_unit_decl->getAnonymousNamespace();
+ if (namespace_decl)
+ return namespace_decl;
+
+ namespace_decl = NamespaceDecl::Create(*ast,
+ decl_ctx,
+ false,
+ SourceLocation(),
+ SourceLocation(),
+ NULL,
+ NULL);
+ translation_unit_decl->setAnonymousNamespace (namespace_decl);
+ translation_unit_decl->addDecl (namespace_decl);
+ assert (namespace_decl == translation_unit_decl->getAnonymousNamespace());
+ }
+ else
+ {
+ NamespaceDecl *parent_namespace_decl = cast<NamespaceDecl>(decl_ctx);
+ if (parent_namespace_decl)
+ {
+ namespace_decl = parent_namespace_decl->getAnonymousNamespace();
+ if (namespace_decl)
+ return namespace_decl;
+ namespace_decl = NamespaceDecl::Create(*ast,
+ decl_ctx,
+ false,
+ SourceLocation(),
+ SourceLocation(),
+ NULL,
+ NULL);
+ parent_namespace_decl->setAnonymousNamespace (namespace_decl);
+ parent_namespace_decl->addDecl (namespace_decl);
+ assert (namespace_decl == parent_namespace_decl->getAnonymousNamespace());
+ }
+ else
+ {
+ // BAD!!!
+ }
+ }
+
+
+ if (namespace_decl)
+ {
+ // If we make it here, we are creating the anonymous namespace decl
+ // for the first time, so we need to do the using directive magic
+ // like SEMA does
+ UsingDirectiveDecl* using_directive_decl = UsingDirectiveDecl::Create (*ast,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ NestedNameSpecifierLoc(),
+ SourceLocation(),
+ namespace_decl,
+ decl_ctx);
+ using_directive_decl->setImplicit();
+ decl_ctx->addDecl(using_directive_decl);
+ }
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(namespace_decl);
+#endif
+ return namespace_decl;
+}
+
+
+#pragma mark Function Types
+
+FunctionDecl *
+ClangASTContext::CreateFunctionDeclaration (DeclContext *decl_ctx,
+ const char *name,
+ const ClangASTType &function_clang_type,
+ int storage,
+ bool is_inline)
+{
+ FunctionDecl *func_decl = NULL;
+ ASTContext *ast = getASTContext();
+ if (decl_ctx == NULL)
+ decl_ctx = ast->getTranslationUnitDecl();
+
+
+ const bool hasWrittenPrototype = true;
+ const bool isConstexprSpecified = false;
+
+ if (name && name[0])
+ {
+ func_decl = FunctionDecl::Create (*ast,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ DeclarationName (&ast->Idents.get(name)),
+ function_clang_type.GetQualType(),
+ NULL,
+ (FunctionDecl::StorageClass)storage,
+ is_inline,
+ hasWrittenPrototype,
+ isConstexprSpecified);
+ }
+ else
+ {
+ func_decl = FunctionDecl::Create (*ast,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ DeclarationName (),
+ function_clang_type.GetQualType(),
+ NULL,
+ (FunctionDecl::StorageClass)storage,
+ is_inline,
+ hasWrittenPrototype,
+ isConstexprSpecified);
+ }
+ if (func_decl)
+ decl_ctx->addDecl (func_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(func_decl);
+#endif
+
+ return func_decl;
+}
+
+ClangASTType
+ClangASTContext::CreateFunctionType (ASTContext *ast,
+ const ClangASTType& result_type,
+ const ClangASTType *args,
+ unsigned num_args,
+ bool is_variadic,
+ unsigned type_quals)
+{
+ assert (ast != NULL);
+ std::vector<QualType> qual_type_args;
+ for (unsigned i=0; i<num_args; ++i)
+ qual_type_args.push_back (args[i].GetQualType());
+
+ // TODO: Detect calling convention in DWARF?
+ FunctionProtoType::ExtProtoInfo proto_info;
+ proto_info.Variadic = is_variadic;
+ proto_info.ExceptionSpecType = EST_None;
+ proto_info.TypeQuals = type_quals;
+ proto_info.RefQualifier = RQ_None;
+ proto_info.NumExceptions = 0;
+ proto_info.Exceptions = NULL;
+
+ return ClangASTType (ast, ast->getFunctionType (result_type.GetQualType(),
+ qual_type_args,
+ proto_info).getAsOpaquePtr());
+}
+
+ParmVarDecl *
+ClangASTContext::CreateParameterDeclaration (const char *name, const ClangASTType &param_type, int storage)
+{
+ ASTContext *ast = getASTContext();
+ assert (ast != NULL);
+ return ParmVarDecl::Create(*ast,
+ ast->getTranslationUnitDecl(),
+ SourceLocation(),
+ SourceLocation(),
+ name && name[0] ? &ast->Idents.get(name) : NULL,
+ param_type.GetQualType(),
+ NULL,
+ (VarDecl::StorageClass)storage,
+ 0);
+}
+
+void
+ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl **params, unsigned num_params)
+{
+ if (function_decl)
+ function_decl->setParams (ArrayRef<ParmVarDecl*>(params, num_params));
+}
+
+
+#pragma mark Array Types
+
+ClangASTType
+ClangASTContext::CreateArrayType (const ClangASTType &element_type,
+ size_t element_count,
+ bool is_vector)
+{
+ if (element_type.IsValid())
+ {
+ ASTContext *ast = getASTContext();
+ assert (ast != NULL);
+
+ if (is_vector)
+ {
+ return ClangASTType (ast, ast->getExtVectorType(element_type.GetQualType(), element_count).getAsOpaquePtr());
+ }
+ else
+ {
+
+ llvm::APInt ap_element_count (64, element_count);
+ if (element_count == 0)
+ {
+ return ClangASTType (ast, ast->getIncompleteArrayType (element_type.GetQualType(),
+ ArrayType::Normal,
+ 0).getAsOpaquePtr());
+ }
+ else
+ {
+ return ClangASTType (ast, ast->getConstantArrayType (element_type.GetQualType(),
+ ap_element_count,
+ ArrayType::Normal,
+ 0).getAsOpaquePtr());
+ }
+ }
+ }
+ return ClangASTType();
+}
+
+
+
+#pragma mark Enumeration Types
+
+ClangASTType
+ClangASTContext::CreateEnumerationType
+(
+ const char *name,
+ DeclContext *decl_ctx,
+ const Declaration &decl,
+ const ClangASTType &integer_clang_type
+)
+{
+ // TODO: Do something intelligent with the Declaration object passed in
+ // like maybe filling in the SourceLocation with it...
+ ASTContext *ast = getASTContext();
+
+ // TODO: ask about these...
+// const bool IsScoped = false;
+// const bool IsFixed = false;
+
+ EnumDecl *enum_decl = EnumDecl::Create (*ast,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ name && name[0] ? &ast->Idents.get(name) : NULL,
+ NULL,
+ false, // IsScoped
+ false, // IsScopedUsingClassTag
+ false); // IsFixed
+
+
+ if (enum_decl)
+ {
+ // TODO: check if we should be setting the promotion type too?
+ enum_decl->setIntegerType(integer_clang_type.GetQualType());
+
+ enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
+
+ return ClangASTType (ast, ast->getTagDeclType(enum_decl).getAsOpaquePtr());
+ }
+ return ClangASTType();
+}
+
+// Disable this for now since I can't seem to get a nicely formatted float
+// out of the APFloat class without just getting the float, double or quad
+// and then using a formatted print on it which defeats the purpose. We ideally
+// would like to get perfect string values for any kind of float semantics
+// so we can support remote targets. The code below also requires a patch to
+// llvm::APInt.
+//bool
+//ClangASTContext::ConvertFloatValueToString (ASTContext *ast, clang_type_t clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str)
+//{
+// uint32_t count = 0;
+// bool is_complex = false;
+// if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex))
+// {
+// unsigned num_bytes_per_float = byte_size / count;
+// unsigned num_bits_per_float = num_bytes_per_float * 8;
+//
+// float_str.clear();
+// uint32_t i;
+// for (i=0; i<count; i++)
+// {
+// APInt ap_int(num_bits_per_float, bytes + i * num_bytes_per_float, (APInt::ByteOrder)apint_byte_order);
+// bool is_ieee = false;
+// APFloat ap_float(ap_int, is_ieee);
+// char s[1024];
+// unsigned int hex_digits = 0;
+// bool upper_case = false;
+//
+// if (ap_float.convertToHexString(s, hex_digits, upper_case, APFloat::rmNearestTiesToEven) > 0)
+// {
+// if (i > 0)
+// float_str.append(", ");
+// float_str.append(s);
+// if (i == 1 && is_complex)
+// float_str.append(1, 'i');
+// }
+// }
+// return !float_str.empty();
+// }
+// return false;
+//}
+
+
+ClangASTType
+ClangASTContext::GetFloatTypeFromBitSize (clang::ASTContext *ast,
+ size_t bit_size)
+{
+ if (ast)
+ {
+ if (bit_size == ast->getTypeSize(ast->FloatTy))
+ return ClangASTType(ast, ast->FloatTy.getAsOpaquePtr());
+ else if (bit_size == ast->getTypeSize(ast->DoubleTy))
+ return ClangASTType(ast, ast->DoubleTy.getAsOpaquePtr());
+ else if (bit_size == ast->getTypeSize(ast->LongDoubleTy))
+ return ClangASTType(ast, ast->LongDoubleTy.getAsOpaquePtr());
+ else if (bit_size == ast->getTypeSize(ast->HalfTy))
+ return ClangASTType(ast, ast->HalfTy.getAsOpaquePtr());
+ }
+ return ClangASTType();
+}
+
+bool
+ClangASTContext::GetCompleteDecl (clang::ASTContext *ast,
+ clang::Decl *decl)
+{
+ if (!decl)
+ return false;
+
+ ExternalASTSource *ast_source = ast->getExternalSource();
+
+ if (!ast_source)
+ return false;
+
+ if (clang::TagDecl *tag_decl = llvm::dyn_cast<clang::TagDecl>(decl))
+ {
+ if (tag_decl->isCompleteDefinition())
+ return true;
+
+ if (!tag_decl->hasExternalLexicalStorage())
+ return false;
+
+ ast_source->CompleteType(tag_decl);
+
+ return !tag_decl->getTypeForDecl()->isIncompleteType();
+ }
+ else if (clang::ObjCInterfaceDecl *objc_interface_decl = llvm::dyn_cast<clang::ObjCInterfaceDecl>(decl))
+ {
+ if (objc_interface_decl->getDefinition())
+ return true;
+
+ if (!objc_interface_decl->hasExternalLexicalStorage())
+ return false;
+
+ ast_source->CompleteType(objc_interface_decl);
+
+ return !objc_interface_decl->getTypeForDecl()->isIncompleteType();
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void
+ClangASTContext::SetMetadataAsUserID (const void *object,
+ user_id_t user_id)
+{
+ ClangASTMetadata meta_data;
+ meta_data.SetUserID (user_id);
+ SetMetadata (object, meta_data);
+}
+
+void
+ClangASTContext::SetMetadata (clang::ASTContext *ast,
+ const void *object,
+ ClangASTMetadata &metadata)
+{
+ ClangExternalASTSourceCommon *external_source =
+ static_cast<ClangExternalASTSourceCommon*>(ast->getExternalSource());
+
+ if (external_source)
+ external_source->SetMetadata(object, metadata);
+}
+
+ClangASTMetadata *
+ClangASTContext::GetMetadata (clang::ASTContext *ast,
+ const void *object)
+{
+ ClangExternalASTSourceCommon *external_source =
+ static_cast<ClangExternalASTSourceCommon*>(ast->getExternalSource());
+
+ if (external_source && external_source->HasMetadata(object))
+ return external_source->GetMetadata(object);
+ else
+ return NULL;
+}
+
+clang::DeclContext *
+ClangASTContext::GetAsDeclContext (clang::CXXMethodDecl *cxx_method_decl)
+{
+ return llvm::dyn_cast<clang::DeclContext>(cxx_method_decl);
+}
+
+clang::DeclContext *
+ClangASTContext::GetAsDeclContext (clang::ObjCMethodDecl *objc_method_decl)
+{
+ return llvm::dyn_cast<clang::DeclContext>(objc_method_decl);
+}
+
+
+bool
+ClangASTContext::GetClassMethodInfoForDeclContext (clang::DeclContext *decl_ctx,
+ lldb::LanguageType &language,
+ bool &is_instance_method,
+ ConstString &language_object_name)
+{
+ language_object_name.Clear();
+ language = eLanguageTypeUnknown;
+ is_instance_method = false;
+
+ if (decl_ctx)
+ {
+ if (clang::CXXMethodDecl *method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl_ctx))
+ {
+ if (method_decl->isStatic())
+ {
+ is_instance_method = false;
+ }
+ else
+ {
+ language_object_name.SetCString("this");
+ is_instance_method = true;
+ }
+ language = eLanguageTypeC_plus_plus;
+ return true;
+ }
+ else if (clang::ObjCMethodDecl *method_decl = llvm::dyn_cast<clang::ObjCMethodDecl>(decl_ctx))
+ {
+ // Both static and instance methods have a "self" object in objective C
+ language_object_name.SetCString("self");
+ if (method_decl->isInstanceMethod())
+ {
+ is_instance_method = true;
+ }
+ else
+ {
+ is_instance_method = false;
+ }
+ language = eLanguageTypeObjC;
+ return true;
+ }
+ else if (clang::FunctionDecl *function_decl = llvm::dyn_cast<clang::FunctionDecl>(decl_ctx))
+ {
+ ClangASTMetadata *metadata = GetMetadata (&decl_ctx->getParentASTContext(), function_decl);
+ if (metadata && metadata->HasObjectPtr())
+ {
+ language_object_name.SetCString (metadata->GetObjectPtrName());
+ language = eLanguageTypeObjC;
+ is_instance_method = true;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
diff --git a/source/Symbol/ClangASTImporter.cpp b/source/Symbol/ClangASTImporter.cpp
new file mode 100644
index 000000000000..152949620450
--- /dev/null
+++ b/source/Symbol/ClangASTImporter.cpp
@@ -0,0 +1,718 @@
+//===-- ClangASTImporter.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "llvm/Support/raw_ostream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangASTImporter.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+
+using namespace lldb_private;
+using namespace clang;
+
+ClangASTMetrics::Counters ClangASTMetrics::global_counters = { 0, 0, 0, 0, 0, 0 };
+ClangASTMetrics::Counters ClangASTMetrics::local_counters = { 0, 0, 0, 0, 0, 0 };
+
+void ClangASTMetrics::DumpCounters (Log *log, ClangASTMetrics::Counters &counters)
+{
+ log->Printf(" Number of visible Decl queries by name : %" PRIu64, counters.m_visible_query_count);
+ log->Printf(" Number of lexical Decl queries : %" PRIu64, counters.m_lexical_query_count);
+ log->Printf(" Number of imports initiated by LLDB : %" PRIu64, counters.m_lldb_import_count);
+ log->Printf(" Number of imports conducted by Clang : %" PRIu64, counters.m_clang_import_count);
+ log->Printf(" Number of Decls completed : %" PRIu64, counters.m_decls_completed_count);
+ log->Printf(" Number of records laid out : %" PRIu64, counters.m_record_layout_count);
+}
+
+void ClangASTMetrics::DumpCounters (Log *log)
+{
+ if (!log)
+ return;
+
+ log->Printf("== ClangASTMetrics output ==");
+ log->Printf("-- Global metrics --");
+ DumpCounters (log, global_counters);
+ log->Printf("-- Local metrics --");
+ DumpCounters (log, local_counters);
+}
+
+clang::QualType
+ClangASTImporter::CopyType (clang::ASTContext *dst_ast,
+ clang::ASTContext *src_ast,
+ clang::QualType type)
+{
+ MinionSP minion_sp (GetMinion(dst_ast, src_ast));
+
+ if (minion_sp)
+ return minion_sp->Import(type);
+
+ return QualType();
+}
+
+lldb::clang_type_t
+ClangASTImporter::CopyType (clang::ASTContext *dst_ast,
+ clang::ASTContext *src_ast,
+ lldb::clang_type_t type)
+{
+ return CopyType (dst_ast, src_ast, QualType::getFromOpaquePtr(type)).getAsOpaquePtr();
+}
+
+clang::Decl *
+ClangASTImporter::CopyDecl (clang::ASTContext *dst_ast,
+ clang::ASTContext *src_ast,
+ clang::Decl *decl)
+{
+ MinionSP minion_sp;
+
+ minion_sp = GetMinion(dst_ast, src_ast);
+
+ if (minion_sp)
+ {
+ clang::Decl *result = minion_sp->Import(decl);
+
+ if (!result)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ lldb::user_id_t user_id;
+ ClangASTMetadata *metadata = GetDeclMetadata(decl);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (NamedDecl *named_decl = dyn_cast<NamedDecl>(decl))
+ log->Printf(" [ClangASTImporter] WARNING: Failed to import a %s '%s', metadata 0x%" PRIx64,
+ decl->getDeclKindName(),
+ named_decl->getNameAsString().c_str(),
+ user_id);
+ else
+ log->Printf(" [ClangASTImporter] WARNING: Failed to import a %s, metadata 0x%" PRIx64,
+ decl->getDeclKindName(),
+ user_id);
+ }
+ }
+
+ return result;
+ }
+
+ return NULL;
+}
+
+lldb::clang_type_t
+ClangASTImporter::DeportType (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ lldb::clang_type_t type)
+{
+ MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
+
+ if (!minion_sp)
+ return NULL;
+
+ std::set<NamedDecl *> decls_to_deport;
+ std::set<NamedDecl *> decls_already_deported;
+
+ minion_sp->InitDeportWorkQueues(&decls_to_deport,
+ &decls_already_deported);
+
+ lldb::clang_type_t result = CopyType(dst_ctx, src_ctx, type);
+
+ minion_sp->ExecuteDeportWorkQueues();
+
+ if (!result)
+ return NULL;
+
+ return result;
+
+}
+
+clang::Decl *
+ClangASTImporter::DeportDecl (clang::ASTContext *dst_ctx,
+ clang::ASTContext *src_ctx,
+ clang::Decl *decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf(" [ClangASTImporter] DeportDecl called on (%sDecl*)%p from (ASTContext*)%p to (ASTContex*)%p",
+ decl->getDeclKindName(),
+ decl,
+ src_ctx,
+ dst_ctx);
+
+ MinionSP minion_sp (GetMinion (dst_ctx, src_ctx));
+
+ if (!minion_sp)
+ return NULL;
+
+ std::set<NamedDecl *> decls_to_deport;
+ std::set<NamedDecl *> decls_already_deported;
+
+ minion_sp->InitDeportWorkQueues(&decls_to_deport,
+ &decls_already_deported);
+
+ clang::Decl *result = CopyDecl(dst_ctx, src_ctx, decl);
+
+ minion_sp->ExecuteDeportWorkQueues();
+
+ if (!result)
+ return NULL;
+
+ if (log)
+ log->Printf(" [ClangASTImporter] DeportDecl deported (%sDecl*)%p to (%sDecl*)%p",
+ decl->getDeclKindName(),
+ decl,
+ result->getDeclKindName(),
+ result);
+
+ return result;
+}
+
+void
+ClangASTImporter::CompleteDecl (clang::Decl *decl)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf(" [ClangASTImporter] CompleteDecl called on (%sDecl*)%p",
+ decl->getDeclKindName(),
+ decl);
+
+ if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl))
+ {
+ if (!interface_decl->getDefinition())
+ {
+ interface_decl->startDefinition();
+ CompleteObjCInterfaceDecl(interface_decl);
+ }
+ }
+ else if (ObjCProtocolDecl *protocol_decl = dyn_cast<ObjCProtocolDecl>(decl))
+ {
+ if (!protocol_decl->getDefinition())
+ protocol_decl->startDefinition();
+ }
+ else if (TagDecl *tag_decl = dyn_cast<TagDecl>(decl))
+ {
+ if (!tag_decl->getDefinition() && !tag_decl->isBeingDefined())
+ {
+ tag_decl->startDefinition();
+ CompleteTagDecl(tag_decl);
+ tag_decl->setCompleteDefinition(true);
+ }
+ }
+ else
+ {
+ assert (0 && "CompleteDecl called on a Decl that can't be completed");
+ }
+}
+
+bool
+ClangASTImporter::CompleteTagDecl (clang::TagDecl *decl)
+{
+ ClangASTMetrics::RegisterDeclCompletion();
+
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ MinionSP minion_sp (GetMinion(&decl->getASTContext(), decl_origin.ctx));
+
+ if (minion_sp)
+ minion_sp->ImportDefinitionTo(decl, decl_origin.decl);
+
+ return true;
+}
+
+bool
+ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin_decl)
+{
+ ClangASTMetrics::RegisterDeclCompletion();
+
+ clang::ASTContext *origin_ast_ctx = &origin_decl->getASTContext();
+
+ if (!ClangASTContext::GetCompleteDecl(origin_ast_ctx, origin_decl))
+ return false;
+
+ MinionSP minion_sp (GetMinion(&decl->getASTContext(), origin_ast_ctx));
+
+ if (minion_sp)
+ minion_sp->ImportDefinitionTo(decl, origin_decl);
+
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl);
+
+ return true;
+}
+
+bool
+ClangASTImporter::CompleteObjCInterfaceDecl (clang::ObjCInterfaceDecl *interface_decl)
+{
+ ClangASTMetrics::RegisterDeclCompletion();
+
+ DeclOrigin decl_origin = GetDeclOrigin(interface_decl);
+
+ if (!decl_origin.Valid())
+ return false;
+
+ if (!ClangASTContext::GetCompleteDecl(decl_origin.ctx, decl_origin.decl))
+ return false;
+
+ MinionSP minion_sp (GetMinion(&interface_decl->getASTContext(), decl_origin.ctx));
+
+ if (minion_sp)
+ minion_sp->ImportDefinitionTo(interface_decl, decl_origin.decl);
+
+ return true;
+}
+
+bool
+ClangASTImporter::RequireCompleteType (clang::QualType type)
+{
+ if (type.isNull())
+ return false;
+
+ if (const TagType *tag_type = type->getAs<TagType>())
+ {
+ return CompleteTagDecl(tag_type->getDecl());
+ }
+ if (const ObjCObjectType *objc_object_type = type->getAs<ObjCObjectType>())
+ {
+ if (ObjCInterfaceDecl *objc_interface_decl = objc_object_type->getInterface())
+ return CompleteObjCInterfaceDecl(objc_interface_decl);
+ else
+ return false;
+ }
+ if (const ArrayType *array_type = type->getAsArrayTypeUnsafe())
+ {
+ return RequireCompleteType(array_type->getElementType());
+ }
+ if (const AtomicType *atomic_type = type->getAs<AtomicType>())
+ {
+ return RequireCompleteType(atomic_type->getPointeeType());
+ }
+
+ return true;
+}
+
+ClangASTMetadata *
+ClangASTImporter::GetDeclMetadata (const clang::Decl *decl)
+{
+ DeclOrigin decl_origin = GetDeclOrigin(decl);
+
+ if (decl_origin.Valid())
+ return ClangASTContext::GetMetadata(decl_origin.ctx, decl_origin.decl);
+ else
+ return ClangASTContext::GetMetadata(&decl->getASTContext(), decl);
+}
+
+ClangASTImporter::DeclOrigin
+ClangASTImporter::GetDeclOrigin(const clang::Decl *decl)
+{
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ OriginMap::iterator iter = origins.find(decl);
+
+ if (iter != origins.end())
+ return iter->second;
+ else
+ return DeclOrigin();
+}
+
+void
+ClangASTImporter::SetDeclOrigin (const clang::Decl *decl, clang::Decl *original_decl)
+{
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ OriginMap &origins = context_md->m_origins;
+
+ OriginMap::iterator iter = origins.find(decl);
+
+ if (iter != origins.end())
+ {
+ iter->second.decl = original_decl;
+ iter->second.ctx = &original_decl->getASTContext();
+ }
+ else
+ {
+ origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl);
+ }
+}
+
+void
+ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl,
+ NamespaceMapSP &namespace_map)
+{
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ context_md->m_namespace_maps[decl] = namespace_map;
+}
+
+ClangASTImporter::NamespaceMapSP
+ClangASTImporter::GetNamespaceMap(const clang::NamespaceDecl *decl)
+{
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ NamespaceMetaMap &namespace_maps = context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator iter = namespace_maps.find(decl);
+
+ if (iter != namespace_maps.end())
+ return iter->second;
+ else
+ return NamespaceMapSP();
+}
+
+void
+ClangASTImporter::BuildNamespaceMap(const clang::NamespaceDecl *decl)
+{
+ assert (decl);
+ ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext());
+
+ const DeclContext *parent_context = decl->getDeclContext();
+ const NamespaceDecl *parent_namespace = dyn_cast<NamespaceDecl>(parent_context);
+ NamespaceMapSP parent_map;
+
+ if (parent_namespace)
+ parent_map = GetNamespaceMap(parent_namespace);
+
+ NamespaceMapSP new_map;
+
+ new_map.reset(new NamespaceMap);
+
+ if (context_md->m_map_completer)
+ {
+ std::string namespace_string = decl->getDeclName().getAsString();
+
+ context_md->m_map_completer->CompleteNamespaceMap (new_map, ConstString(namespace_string.c_str()), parent_map);
+ }
+
+ context_md->m_namespace_maps[decl] = new_map;
+}
+
+void
+ClangASTImporter::ForgetDestination (clang::ASTContext *dst_ast)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf(" [ClangASTImporter] Forgetting destination (ASTContext*)%p", dst_ast);
+
+ m_metadata_map.erase(dst_ast);
+}
+
+void
+ClangASTImporter::ForgetSource (clang::ASTContext *dst_ast, clang::ASTContext *src_ast)
+{
+ ASTContextMetadataSP md = MaybeGetContextMetadata (dst_ast);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ log->Printf(" [ClangASTImporter] Forgetting source->dest (ASTContext*)%p->(ASTContext*)%p", src_ast, dst_ast);
+
+ if (!md)
+ return;
+
+ md->m_minions.erase(src_ast);
+
+ for (OriginMap::iterator iter = md->m_origins.begin();
+ iter != md->m_origins.end();
+ )
+ {
+ if (iter->second.ctx == src_ast)
+ md->m_origins.erase(iter++);
+ else
+ ++iter;
+ }
+}
+
+ClangASTImporter::MapCompleter::~MapCompleter ()
+{
+ return;
+}
+
+void
+ClangASTImporter::Minion::InitDeportWorkQueues (std::set<clang::NamedDecl *> *decls_to_deport,
+ std::set<clang::NamedDecl *> *decls_already_deported)
+{
+ assert(!m_decls_to_deport); // TODO make debug only
+ assert(!m_decls_already_deported);
+
+ m_decls_to_deport = decls_to_deport;
+ m_decls_already_deported = decls_already_deported;
+}
+
+void
+ClangASTImporter::Minion::ExecuteDeportWorkQueues ()
+{
+ assert(m_decls_to_deport); // TODO make debug only
+ assert(m_decls_already_deported);
+
+ ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&getToContext());
+
+ while (!m_decls_to_deport->empty())
+ {
+ NamedDecl *decl = *m_decls_to_deport->begin();
+
+ m_decls_already_deported->insert(decl);
+ m_decls_to_deport->erase(decl);
+
+ DeclOrigin &origin = to_context_md->m_origins[decl];
+
+ assert (origin.ctx == m_source_ctx); // otherwise we should never have added this
+ // because it doesn't need to be deported
+
+ Decl *original_decl = to_context_md->m_origins[decl].decl;
+
+ ClangASTContext::GetCompleteDecl (m_source_ctx, original_decl);
+
+ if (TagDecl *tag_decl = dyn_cast<TagDecl>(decl))
+ {
+ if (TagDecl *original_tag_decl = dyn_cast<TagDecl>(original_decl))
+ if (original_tag_decl->isCompleteDefinition())
+ ImportDefinitionTo(tag_decl, original_tag_decl);
+
+ tag_decl->setHasExternalLexicalStorage(false);
+ tag_decl->setHasExternalVisibleStorage(false);
+ }
+ else if (ObjCInterfaceDecl *interface_decl = dyn_cast<ObjCInterfaceDecl>(decl))
+ {
+ interface_decl->setHasExternalLexicalStorage(false);
+ interface_decl->setHasExternalVisibleStorage(false);
+ }
+
+ to_context_md->m_origins.erase(decl);
+ }
+
+ m_decls_to_deport = NULL;
+ m_decls_already_deported = NULL;
+}
+
+void
+ClangASTImporter::Minion::ImportDefinitionTo (clang::Decl *to, clang::Decl *from)
+{
+ ASTImporter::Imported(from, to);
+
+ ObjCInterfaceDecl *to_objc_interface = dyn_cast<ObjCInterfaceDecl>(to);
+
+ /*
+ if (to_objc_interface)
+ to_objc_interface->startDefinition();
+
+ CXXRecordDecl *to_cxx_record = dyn_cast<CXXRecordDecl>(to);
+
+ if (to_cxx_record)
+ to_cxx_record->startDefinition();
+ */
+
+ ImportDefinition(from);
+
+ // If we're dealing with an Objective-C class, ensure that the inheritance has
+ // been set up correctly. The ASTImporter may not do this correctly if the
+ // class was originally sourced from symbols.
+
+ if (to_objc_interface)
+ {
+ do
+ {
+ ObjCInterfaceDecl *to_superclass = to_objc_interface->getSuperClass();
+
+ if (to_superclass)
+ break; // we're not going to override it if it's set
+
+ ObjCInterfaceDecl *from_objc_interface = dyn_cast<ObjCInterfaceDecl>(from);
+
+ if (!from_objc_interface)
+ break;
+
+ ObjCInterfaceDecl *from_superclass = from_objc_interface->getSuperClass();
+
+ if (!from_superclass)
+ break;
+
+ Decl *imported_from_superclass_decl = Import(from_superclass);
+
+ if (!imported_from_superclass_decl)
+ break;
+
+ ObjCInterfaceDecl *imported_from_superclass = dyn_cast<ObjCInterfaceDecl>(imported_from_superclass_decl);
+
+ if (!imported_from_superclass)
+ break;
+
+ if (!to_objc_interface->hasDefinition())
+ to_objc_interface->startDefinition();
+
+ to_objc_interface->setSuperClass(imported_from_superclass);
+ }
+ while (0);
+ }
+}
+
+clang::Decl *
+ClangASTImporter::Minion::Imported (clang::Decl *from, clang::Decl *to)
+{
+ ClangASTMetrics::RegisterClangImport();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ lldb::user_id_t user_id;
+ ClangASTMetadata *metadata = m_master.GetDeclMetadata(from);
+ if (metadata)
+ user_id = metadata->GetUserID();
+
+ if (NamedDecl *from_named_decl = dyn_cast<clang::NamedDecl>(from))
+ {
+ std::string name_string;
+ llvm::raw_string_ostream name_stream(name_string);
+ from_named_decl->printName(name_stream);
+ name_stream.flush();
+
+ log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p, named %s (from (Decl*)%p), metadata 0x%" PRIx64,
+ from->getDeclKindName(),
+ to,
+ name_string.c_str(),
+ from,
+ user_id);
+ }
+ else
+ {
+ log->Printf(" [ClangASTImporter] Imported (%sDecl*)%p (from (Decl*)%p), metadata 0x%" PRIx64,
+ from->getDeclKindName(),
+ to,
+ from,
+ user_id);
+ }
+ }
+
+ ASTContextMetadataSP to_context_md = m_master.GetContextMetadata(&to->getASTContext());
+ ASTContextMetadataSP from_context_md = m_master.MaybeGetContextMetadata(m_source_ctx);
+
+ if (from_context_md)
+ {
+ OriginMap &origins = from_context_md->m_origins;
+
+ OriginMap::iterator origin_iter = origins.find(from);
+
+ if (origin_iter != origins.end())
+ {
+ to_context_md->m_origins[to] = origin_iter->second;
+
+ MinionSP direct_completer = m_master.GetMinion(&to->getASTContext(), origin_iter->second.ctx);
+
+ if (direct_completer.get() != this)
+ direct_completer->ASTImporter::Imported(origin_iter->second.decl, to);
+
+ if (log)
+ log->Printf(" [ClangASTImporter] Propagated origin (Decl*)%p/(ASTContext*)%p from (ASTContext*)%p to (ASTContext*)%p",
+ origin_iter->second.decl,
+ origin_iter->second.ctx,
+ &from->getASTContext(),
+ &to->getASTContext());
+ }
+ else
+ {
+ if (m_decls_to_deport && m_decls_already_deported)
+ {
+ if (isa<TagDecl>(to) || isa<ObjCInterfaceDecl>(to))
+ {
+ NamedDecl *to_named_decl = dyn_cast<NamedDecl>(to);
+
+ if (!m_decls_already_deported->count(to_named_decl))
+ m_decls_to_deport->insert(to_named_decl);
+ }
+
+ }
+ to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from);
+
+ if (log)
+ log->Printf(" [ClangASTImporter] Decl has no origin information in (ASTContext*)%p",
+ &from->getASTContext());
+ }
+
+ if (clang::NamespaceDecl *to_namespace = dyn_cast<clang::NamespaceDecl>(to))
+ {
+ clang::NamespaceDecl *from_namespace = dyn_cast<clang::NamespaceDecl>(from);
+
+ NamespaceMetaMap &namespace_maps = from_context_md->m_namespace_maps;
+
+ NamespaceMetaMap::iterator namespace_map_iter = namespace_maps.find(from_namespace);
+
+ if (namespace_map_iter != namespace_maps.end())
+ to_context_md->m_namespace_maps[to_namespace] = namespace_map_iter->second;
+ }
+ }
+ else
+ {
+ to_context_md->m_origins[to] = DeclOrigin (m_source_ctx, from);
+
+ if (log)
+ log->Printf(" [ClangASTImporter] Sourced origin (Decl*)%p/(ASTContext*)%p into (ASTContext*)%p",
+ from,
+ m_source_ctx,
+ &to->getASTContext());
+ }
+
+ if (TagDecl *from_tag_decl = dyn_cast<TagDecl>(from))
+ {
+ TagDecl *to_tag_decl = dyn_cast<TagDecl>(to);
+
+ to_tag_decl->setHasExternalLexicalStorage();
+ to_tag_decl->setMustBuildLookupTable();
+
+ if (log)
+ log->Printf(" [ClangASTImporter] To is a TagDecl - attributes %s%s [%s->%s]",
+ (to_tag_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_tag_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (from_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"),
+ (to_tag_decl->isCompleteDefinition() ? "complete" : "incomplete"));
+ }
+
+ if (isa<NamespaceDecl>(from))
+ {
+ NamespaceDecl *to_namespace_decl = dyn_cast<NamespaceDecl>(to);
+
+ m_master.BuildNamespaceMap(to_namespace_decl);
+
+ to_namespace_decl->setHasExternalVisibleStorage();
+ }
+
+ if (isa<ObjCInterfaceDecl>(from))
+ {
+ ObjCInterfaceDecl *to_interface_decl = dyn_cast<ObjCInterfaceDecl>(to);
+
+ to_interface_decl->setHasExternalLexicalStorage();
+ to_interface_decl->setHasExternalVisibleStorage();
+
+ /*to_interface_decl->setExternallyCompleted();*/
+
+ if (log)
+ log->Printf(" [ClangASTImporter] To is an ObjCInterfaceDecl - attributes %s%s%s",
+ (to_interface_decl->hasExternalLexicalStorage() ? " Lexical" : ""),
+ (to_interface_decl->hasExternalVisibleStorage() ? " Visible" : ""),
+ (to_interface_decl->hasDefinition() ? " HasDefinition" : ""));
+ }
+
+ return clang::ASTImporter::Imported(from, to);
+}
diff --git a/source/Symbol/ClangASTType.cpp b/source/Symbol/ClangASTType.cpp
new file mode 100644
index 000000000000..2e7c0790fe57
--- /dev/null
+++ b/source/Symbol/ClangASTType.cpp
@@ -0,0 +1,6486 @@
+//===-- ClangASTType.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/Symbol/ClangASTType.h"
+
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/RecordLayout.h"
+#include "clang/AST/Type.h"
+
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/VerifyDecl.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+
+#include <mutex>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+using namespace llvm;
+
+static bool
+GetCompleteQualType (ASTContext *ast, QualType qual_type, bool allow_completion = true)
+{
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::ConstantArray:
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ {
+ const ArrayType *array_type = dyn_cast<ArrayType>(qual_type.getTypePtr());
+
+ if (array_type)
+ return GetCompleteQualType (ast, array_type->getElementType(), allow_completion);
+ }
+ break;
+
+ case clang::Type::Record:
+ case clang::Type::Enum:
+ {
+ const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ {
+ if (tag_decl->isCompleteDefinition())
+ return true;
+
+ if (!allow_completion)
+ return false;
+
+ if (tag_decl->hasExternalLexicalStorage())
+ {
+ if (ast)
+ {
+ ExternalASTSource *external_ast_source = ast->getExternalSource();
+ if (external_ast_source)
+ {
+ external_ast_source->CompleteType(tag_decl);
+ return !tag_type->isIncompleteType();
+ }
+ }
+ }
+ return false;
+ }
+ }
+
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ // We currently can't complete objective C types through the newly added ASTContext
+ // because it only supports TagDecl objects right now...
+ if (class_interface_decl)
+ {
+ if (class_interface_decl->getDefinition())
+ return true;
+
+ if (!allow_completion)
+ return false;
+
+ if (class_interface_decl->hasExternalLexicalStorage())
+ {
+ if (ast)
+ {
+ ExternalASTSource *external_ast_source = ast->getExternalSource();
+ if (external_ast_source)
+ {
+ external_ast_source->CompleteType (class_interface_decl);
+ return !objc_class_type->isIncompleteType();
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return GetCompleteQualType (ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType(), allow_completion);
+
+ case clang::Type::Elaborated:
+ return GetCompleteQualType (ast, cast<ElaboratedType>(qual_type)->getNamedType(), allow_completion);
+
+ case clang::Type::Paren:
+ return GetCompleteQualType (ast, cast<ParenType>(qual_type)->desugar(), allow_completion);
+
+ default:
+ break;
+ }
+
+ return true;
+}
+
+static ObjCIvarDecl::AccessControl
+ConvertAccessTypeToObjCIvarAccessControl (AccessType access)
+{
+ switch (access)
+ {
+ case eAccessNone: return ObjCIvarDecl::None;
+ case eAccessPublic: return ObjCIvarDecl::Public;
+ case eAccessPrivate: return ObjCIvarDecl::Private;
+ case eAccessProtected: return ObjCIvarDecl::Protected;
+ case eAccessPackage: return ObjCIvarDecl::Package;
+ }
+ return ObjCIvarDecl::None;
+}
+
+//----------------------------------------------------------------------
+// Tests
+//----------------------------------------------------------------------
+
+ClangASTType::ClangASTType (clang::ASTContext *ast,
+ clang::QualType qual_type) :
+ m_type (qual_type.getAsOpaquePtr()),
+ m_ast (ast)
+{
+}
+
+ClangASTType::~ClangASTType()
+{
+}
+
+//----------------------------------------------------------------------
+// Tests
+//----------------------------------------------------------------------
+
+bool
+ClangASTType::IsAggregateType () const
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ case clang::Type::ConstantArray:
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ case clang::Type::Record:
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ return true;
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsAggregateType();
+ case clang::Type::Typedef:
+ return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsAggregateType();
+ case clang::Type::Paren:
+ return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).IsAggregateType();
+ default:
+ break;
+ }
+ // The clang type does have a value
+ return false;
+}
+
+bool
+ClangASTType::IsArrayType (ClangASTType *element_type_ptr,
+ uint64_t *size,
+ bool *is_incomplete) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ default:
+ break;
+
+ case clang::Type::ConstantArray:
+ if (element_type_ptr)
+ element_type_ptr->SetClangType (m_ast, cast<ConstantArrayType>(qual_type)->getElementType());
+ if (size)
+ *size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULLONG_MAX);
+ return true;
+
+ case clang::Type::IncompleteArray:
+ if (element_type_ptr)
+ element_type_ptr->SetClangType (m_ast, cast<IncompleteArrayType>(qual_type)->getElementType());
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = true;
+ return true;
+
+ case clang::Type::VariableArray:
+ if (element_type_ptr)
+ element_type_ptr->SetClangType (m_ast, cast<VariableArrayType>(qual_type)->getElementType());
+ if (size)
+ *size = 0;
+ return true;
+
+ case clang::Type::DependentSizedArray:
+ if (element_type_ptr)
+ element_type_ptr->SetClangType (m_ast, cast<DependentSizedArrayType>(qual_type)->getElementType());
+ if (size)
+ *size = 0;
+ return true;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsArrayType (element_type_ptr,
+ size,
+ is_incomplete);
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsArrayType (element_type_ptr,
+ size,
+ is_incomplete);
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsArrayType (element_type_ptr,
+ size,
+ is_incomplete);
+ }
+ }
+ if (element_type_ptr)
+ element_type_ptr->Clear();
+ if (size)
+ *size = 0;
+ if (is_incomplete)
+ *is_incomplete = false;
+ return 0;
+}
+
+
+bool
+ClangASTType::IsCharType () const
+{
+ if (!IsValid())
+ return false;
+ return GetQualType().getUnqualifiedType()->isCharType();
+}
+
+
+bool
+ClangASTType::IsCompleteType () const
+{
+ if (!IsValid())
+ return false;
+ const bool allow_completion = false;
+ return GetCompleteQualType (m_ast, GetQualType(), allow_completion);
+}
+
+bool
+ClangASTType::IsConst() const
+{
+ return GetQualType().isConstQualified();
+}
+
+bool
+ClangASTType::IsCStringType (uint32_t &length) const
+{
+ ClangASTType pointee_or_element_clang_type;
+ length = 0;
+ Flags type_flags (GetTypeInfo (&pointee_or_element_clang_type));
+
+ if (!pointee_or_element_clang_type.IsValid())
+ return false;
+
+ if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer))
+ {
+ if (pointee_or_element_clang_type.IsCharType())
+ {
+ if (type_flags.Test (eTypeIsArray))
+ {
+ // We know the size of the array and it could be a C string
+ // since it is an array of characters
+ length = cast<ConstantArrayType>(GetCanonicalQualType().getTypePtr())->getSize().getLimitedValue();
+ }
+ return true;
+
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::IsFunctionType (bool *is_variadic_ptr) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ if (qual_type->isFunctionType())
+ {
+ if (is_variadic_ptr)
+ {
+ const clang::FunctionProtoType *function_proto_type = llvm::dyn_cast<clang::FunctionProtoType>(qual_type.getTypePtr());
+ if (function_proto_type)
+ *is_variadic_ptr = function_proto_type->isVariadic();
+ else
+ *is_variadic_ptr = false;
+ }
+ return true;
+ }
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ default:
+ break;
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionType();
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsFunctionType();
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsFunctionType();
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ if (reference_type)
+ return ClangASTType (m_ast, reference_type->getPointeeType()).IsFunctionType();
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+
+bool
+ClangASTType::IsFunctionPointerType () const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ if (qual_type->isFunctionPointerType())
+ return true;
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ default:
+ break;
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsFunctionPointerType();
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsFunctionPointerType();
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsFunctionPointerType();
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ if (reference_type)
+ return ClangASTType (m_ast, reference_type->getPointeeType()).IsFunctionPointerType();
+ }
+ break;
+ }
+ }
+ return false;
+
+}
+
+bool
+ClangASTType::IsIntegerType (bool &is_signed) const
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+ const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal());
+
+ if (builtin_type)
+ {
+ if (builtin_type->isInteger())
+ {
+ is_signed = builtin_type->isSignedInteger();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+ClangASTType::IsPointerType (ClangASTType *pointee_type) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ {
+ default:
+ break;
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ return true;
+ }
+ return false;
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_type)
+ pointee_type->SetClangType (m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::BlockPointer:
+ if (pointee_type)
+ pointee_type->SetClangType (m_ast, cast<BlockPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::Pointer:
+ if (pointee_type)
+ pointee_type->SetClangType (m_ast, cast<PointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::MemberPointer:
+ if (pointee_type)
+ pointee_type->SetClangType (m_ast, cast<MemberPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerType(pointee_type);
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsPointerType(pointee_type);
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsPointerType(pointee_type);
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+
+bool
+ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ {
+ default:
+ break;
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ return true;
+ }
+ return false;
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::BlockPointer:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<BlockPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::Pointer:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<PointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::MemberPointer:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<MemberPointerType>(qual_type)->getPointeeType());
+ return true;
+ case clang::Type::LValueReference:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ return true;
+ case clang::Type::RValueReference:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ return true;
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPointerOrReferenceType(pointee_type);
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsPointerOrReferenceType(pointee_type);
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsPointerOrReferenceType(pointee_type);
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+
+bool
+ClangASTType::IsReferenceType (ClangASTType *pointee_type) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+ switch (type_class)
+ {
+ case clang::Type::LValueReference:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ return true;
+ case clang::Type::RValueReference:
+ if (pointee_type)
+ pointee_type->SetClangType(m_ast, cast<LValueReferenceType>(qual_type)->desugar());
+ return true;
+ case clang::Type::Typedef:
+ return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsReferenceType(pointee_type);
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).IsReferenceType(pointee_type);
+ case clang::Type::Paren:
+ return ClangASTType(m_ast, cast<clang::ParenType>(qual_type)->desugar()).IsReferenceType(pointee_type);
+
+ default:
+ break;
+ }
+ }
+ if (pointee_type)
+ pointee_type->Clear();
+ return false;
+}
+
+bool
+ClangASTType::IsFloatingPointType (uint32_t &count, bool &is_complex) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal()))
+ {
+ clang::BuiltinType::Kind kind = BT->getKind();
+ if (kind >= BuiltinType::Float && kind <= BuiltinType::LongDouble)
+ {
+ count = 1;
+ is_complex = false;
+ return true;
+ }
+ }
+ else if (const ComplexType *CT = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal()))
+ {
+ if (ClangASTType (m_ast, CT->getElementType()).IsFloatingPointType (count, is_complex))
+ {
+ count = 2;
+ is_complex = true;
+ return true;
+ }
+ }
+ else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal()))
+ {
+ if (ClangASTType (m_ast, VT->getElementType()).IsFloatingPointType (count, is_complex))
+ {
+ count = VT->getNumElements();
+ is_complex = false;
+ return true;
+ }
+ }
+ }
+ count = 0;
+ is_complex = false;
+ return false;
+}
+
+
+bool
+ClangASTType::IsDefined() const
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type(GetQualType());
+ const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ return tag_decl->isCompleteDefinition();
+ return false;
+ }
+ else
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ if (class_interface_decl)
+ return class_interface_decl->getDefinition() != NULL;
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+ClangASTType::IsObjCClassType () const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ const ObjCObjectPointerType *obj_pointer_type = dyn_cast<ObjCObjectPointerType>(qual_type);
+
+ if (obj_pointer_type)
+ return obj_pointer_type->isObjCClassType();
+ }
+ return false;
+}
+
+bool
+ClangASTType::IsObjCObjectOrInterfaceType () const
+{
+ if (IsValid())
+ return GetCanonicalQualType()->isObjCObjectOrInterfaceType();
+ return false;
+}
+
+bool
+ClangASTType::IsPolymorphicClass () const
+{
+ if (IsValid())
+ {
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl)
+ {
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ return cxx_record_decl->isPolymorphic();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::IsPossibleDynamicType (ClangASTType *dynamic_pointee_type,
+ bool check_cplusplus,
+ bool check_objc) const
+{
+ QualType pointee_qual_type;
+ if (m_type)
+ {
+ QualType qual_type (GetCanonicalQualType());
+ bool success = false;
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ if (check_objc && cast<BuiltinType>(qual_type)->getKind() == BuiltinType::ObjCId)
+ {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetClangType(m_ast, m_type);
+ return true;
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (check_objc)
+ {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetClangType(m_ast, cast<ObjCObjectPointerType>(qual_type)->getPointeeType());
+ return true;
+ }
+ break;
+
+ case clang::Type::Pointer:
+ pointee_qual_type = cast<PointerType>(qual_type)->getPointeeType();
+ success = true;
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ pointee_qual_type = cast<ReferenceType>(qual_type)->getPointeeType();
+ success = true;
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast,
+ cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).IsPossibleDynamicType (dynamic_pointee_type,
+ check_cplusplus,
+ check_objc);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast,
+ cast<ElaboratedType>(qual_type)->getNamedType()).IsPossibleDynamicType (dynamic_pointee_type,
+ check_cplusplus,
+ check_objc);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast,
+ cast<ParenType>(qual_type)->desugar()).IsPossibleDynamicType (dynamic_pointee_type,
+ check_cplusplus,
+ check_objc);
+ default:
+ break;
+ }
+
+ if (success)
+ {
+ // Check to make sure what we are pointing too is a possible dynamic C++ type
+ // We currently accept any "void *" (in case we have a class that has been
+ // watered down to an opaque pointer) and virtual C++ classes.
+ const clang::Type::TypeClass pointee_type_class = pointee_qual_type.getCanonicalType()->getTypeClass();
+ switch (pointee_type_class)
+ {
+ case clang::Type::Builtin:
+ switch (cast<BuiltinType>(pointee_qual_type)->getKind())
+ {
+ case BuiltinType::UnknownAny:
+ case BuiltinType::Void:
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetClangType(m_ast, pointee_qual_type);
+ return true;
+
+ case BuiltinType::NullPtr:
+ case BuiltinType::Bool:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::BoundMember:
+ case BuiltinType::Half:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::BuiltinFn:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ break;
+ }
+ break;
+
+ case clang::Type::Record:
+ if (check_cplusplus)
+ {
+ CXXRecordDecl *cxx_record_decl = pointee_qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ bool is_complete = cxx_record_decl->isCompleteDefinition();
+
+ if (is_complete)
+ success = cxx_record_decl->isDynamicClass();
+ else
+ {
+ ClangASTMetadata *metadata = ClangASTContext::GetMetadata (m_ast, cxx_record_decl);
+ if (metadata)
+ success = metadata->GetIsDynamicCXXType();
+ else
+ {
+ is_complete = ClangASTType(m_ast, pointee_qual_type).GetCompleteType();
+ if (is_complete)
+ success = cxx_record_decl->isDynamicClass();
+ else
+ success = false;
+ }
+ }
+
+ if (success)
+ {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetClangType(m_ast, pointee_qual_type);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (check_objc)
+ {
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->SetClangType(m_ast, pointee_qual_type);
+ return true;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ if (dynamic_pointee_type)
+ dynamic_pointee_type->Clear();
+ return false;
+}
+
+
+bool
+ClangASTType::IsScalarType () const
+{
+ if (!IsValid())
+ return false;
+
+ return (GetTypeInfo (NULL) & eTypeIsScalar) != 0;
+}
+
+bool
+ClangASTType::IsTypedefType () const
+{
+ if (!IsValid())
+ return false;
+ return GetQualType()->getTypeClass() == clang::Type::Typedef;
+}
+
+bool
+ClangASTType::IsVoidType () const
+{
+ if (!IsValid())
+ return false;
+ return GetCanonicalQualType()->isVoidType();
+}
+
+bool
+ClangASTType::IsPointerToScalarType () const
+{
+ if (!IsValid())
+ return false;
+
+ return IsPointerType() && GetPointeeType().IsScalarType();
+}
+
+bool
+ClangASTType::IsArrayOfScalarType () const
+{
+ ClangASTType element_type;
+ if (IsArrayType(&element_type, NULL, NULL))
+ return element_type.IsScalarType();
+ return false;
+}
+
+
+bool
+ClangASTType::GetCXXClassName (std::string &class_name) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ class_name.assign (cxx_record_decl->getIdentifier()->getNameStart());
+ return true;
+ }
+ }
+ class_name.clear();
+ return false;
+}
+
+
+bool
+ClangASTType::IsCXXClassType () const
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+ if (qual_type->getAsCXXRecordDecl() != NULL)
+ return true;
+ return false;
+}
+
+bool
+ClangASTType::IsBeingDefined () const
+{
+ if (!IsValid())
+ return false;
+ QualType qual_type (GetCanonicalQualType());
+ const clang::TagType *tag_type = dyn_cast<clang::TagType>(qual_type);
+ if (tag_type)
+ return tag_type->isBeingDefined();
+ return false;
+}
+
+bool
+ClangASTType::IsObjCObjectPointerType (ClangASTType *class_type_ptr)
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+
+ if (qual_type->isObjCObjectPointerType())
+ {
+ if (class_type_ptr)
+ {
+ if (!qual_type->isObjCClassType() &&
+ !qual_type->isObjCIdType())
+ {
+ const ObjCObjectPointerType *obj_pointer_type = dyn_cast<ObjCObjectPointerType>(qual_type);
+ if (obj_pointer_type == NULL)
+ class_type_ptr->Clear();
+ else
+ class_type_ptr->SetClangType (m_ast, QualType(obj_pointer_type->getInterfaceType(), 0));
+ }
+ }
+ return true;
+ }
+ if (class_type_ptr)
+ class_type_ptr->Clear();
+ return false;
+}
+
+bool
+ClangASTType::GetObjCClassName (std::string &class_name)
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+
+ const ObjCObjectType *object_type = dyn_cast<ObjCObjectType>(qual_type);
+ if (object_type)
+ {
+ const ObjCInterfaceDecl *interface = object_type->getInterface();
+ if (interface)
+ {
+ class_name = interface->getNameAsString();
+ return true;
+ }
+ }
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Type Completion
+//----------------------------------------------------------------------
+
+bool
+ClangASTType::GetCompleteType () const
+{
+ if (!IsValid())
+ return false;
+ const bool allow_completion = true;
+ return GetCompleteQualType (m_ast, GetQualType(), allow_completion);
+}
+
+//----------------------------------------------------------------------
+// AST related queries
+//----------------------------------------------------------------------
+size_t
+ClangASTType::GetPointerByteSize () const
+{
+ if (m_ast)
+ return m_ast->getTypeSize(m_ast->VoidPtrTy) / 8;
+ return 0;
+}
+
+ConstString
+ClangASTType::GetConstQualifiedTypeName () const
+{
+ return GetConstTypeName ();
+}
+
+ConstString
+ClangASTType::GetConstTypeName () const
+{
+ if (IsValid())
+ {
+ std::string type_name (GetTypeName());
+ if (!type_name.empty())
+ return ConstString (type_name.c_str());
+ }
+ return ConstString("<invalid>");
+}
+
+std::string
+ClangASTType::GetTypeName () const
+{
+ std::string type_name;
+ if (IsValid())
+ {
+ PrintingPolicy printing_policy (m_ast->getPrintingPolicy());
+ QualType qual_type(GetQualType());
+ printing_policy.SuppressTagKeyword = true;
+ printing_policy.LangOpts.WChar = true;
+ const TypedefType *typedef_type = qual_type->getAs<TypedefType>();
+ if (typedef_type)
+ {
+ const TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ type_name = typedef_decl->getQualifiedNameAsString(printing_policy);
+ }
+ else
+ {
+ type_name = qual_type.getAsString(printing_policy);
+ }
+ }
+ return type_name;
+}
+
+
+uint32_t
+ClangASTType::GetTypeInfo (ClangASTType *pointee_or_element_clang_type) const
+{
+ if (!IsValid())
+ return 0;
+
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->Clear();
+
+ QualType qual_type (GetQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ {
+ const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal());
+
+ uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue;
+ switch (builtin_type->getKind())
+ {
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, m_ast->ObjCBuiltinClassTy);
+ builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
+ break;
+
+ case clang::BuiltinType::ObjCSel:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, m_ast->CharTy);
+ builtin_type_flags |= eTypeIsPointer | eTypeIsObjC;
+ break;
+
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ builtin_type_flags |= eTypeIsScalar;
+ if (builtin_type->isInteger())
+ {
+ builtin_type_flags |= eTypeIsInteger;
+ if (builtin_type->isSignedInteger())
+ builtin_type_flags |= eTypeIsSigned;
+ }
+ else if (builtin_type->isFloatingPoint())
+ builtin_type_flags |= eTypeIsFloat;
+ break;
+ default:
+ break;
+ }
+ return builtin_type_flags;
+ }
+
+ case clang::Type::BlockPointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, qual_type->getPointeeType());
+ return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock;
+
+ case clang::Type::Complex:
+ {
+ uint32_t complex_type_flags = eTypeIsBuiltIn | eTypeHasValue | eTypeIsComplex;
+ const ComplexType *complex_type = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal());
+ if (complex_type)
+ {
+ QualType complex_element_type (complex_type->getElementType());
+ if (complex_element_type->isIntegerType())
+ complex_type_flags |= eTypeIsFloat;
+ else if (complex_element_type->isFloatingType())
+ complex_type_flags |= eTypeIsInteger;
+ }
+ return complex_type_flags;
+ }
+ break;
+
+ case clang::Type::ConstantArray:
+ case clang::Type::DependentSizedArray:
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, cast<ArrayType>(qual_type.getTypePtr())->getElementType());
+ return eTypeHasChildren | eTypeIsArray;
+
+ case clang::Type::DependentName: return 0;
+ case clang::Type::DependentSizedExtVector: return eTypeHasChildren | eTypeIsVector;
+ case clang::Type::DependentTemplateSpecialization: return eTypeIsTemplate;
+ case clang::Type::Decltype: return 0;
+
+ case clang::Type::Enum:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, cast<EnumType>(qual_type)->getDecl()->getIntegerType());
+ return eTypeIsEnumeration | eTypeHasValue;
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTypeInfo (pointee_or_element_clang_type);
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetTypeInfo (pointee_or_element_clang_type);
+
+ case clang::Type::FunctionProto: return eTypeIsFuncPrototype | eTypeHasValue;
+ case clang::Type::FunctionNoProto: return eTypeIsFuncPrototype | eTypeHasValue;
+ case clang::Type::InjectedClassName: return 0;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, cast<ReferenceType>(qual_type.getTypePtr())->getPointeeType());
+ return eTypeHasChildren | eTypeIsReference | eTypeHasValue;
+
+ case clang::Type::MemberPointer: return eTypeIsPointer | eTypeIsMember | eTypeHasValue;
+
+ case clang::Type::ObjCObjectPointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, qual_type->getPointeeType());
+ return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer | eTypeHasValue;
+
+ case clang::Type::ObjCObject: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
+ case clang::Type::ObjCInterface: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
+
+ case clang::Type::Pointer:
+ if (pointee_or_element_clang_type)
+ pointee_or_element_clang_type->SetClangType(m_ast, qual_type->getPointeeType());
+ return eTypeHasChildren | eTypeIsPointer | eTypeHasValue;
+
+ case clang::Type::Record:
+ if (qual_type->getAsCXXRecordDecl())
+ return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus;
+ else
+ return eTypeHasChildren | eTypeIsStructUnion;
+ break;
+ case clang::Type::SubstTemplateTypeParm: return eTypeIsTemplate;
+ case clang::Type::TemplateTypeParm: return eTypeIsTemplate;
+ case clang::Type::TemplateSpecialization: return eTypeIsTemplate;
+
+ case clang::Type::Typedef:
+ return eTypeIsTypedef | ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTypeInfo (pointee_or_element_clang_type);
+ case clang::Type::TypeOfExpr: return 0;
+ case clang::Type::TypeOf: return 0;
+ case clang::Type::UnresolvedUsing: return 0;
+
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ {
+ uint32_t vector_type_flags = eTypeHasChildren | eTypeIsVector;
+ const VectorType *vector_type = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal());
+ if (vector_type)
+ {
+ if (vector_type->isIntegerType())
+ vector_type_flags |= eTypeIsFloat;
+ else if (vector_type->isFloatingType())
+ vector_type_flags |= eTypeIsInteger;
+ }
+ return vector_type_flags;
+ }
+ default: return 0;
+ }
+ return 0;
+}
+
+
+
+lldb::LanguageType
+ClangASTType::GetMinimumLanguage ()
+{
+ if (!IsValid())
+ return lldb::eLanguageTypeC;
+
+ // If the type is a reference, then resolve it to what it refers to first:
+ QualType qual_type (GetCanonicalQualType().getNonReferenceType());
+ if (qual_type->isAnyPointerType())
+ {
+ if (qual_type->isObjCObjectPointerType())
+ return lldb::eLanguageTypeObjC;
+
+ QualType pointee_type (qual_type->getPointeeType());
+ if (pointee_type->getPointeeCXXRecordDecl() != NULL)
+ return lldb::eLanguageTypeC_plus_plus;
+ if (pointee_type->isObjCObjectOrInterfaceType())
+ return lldb::eLanguageTypeObjC;
+ if (pointee_type->isObjCClassType())
+ return lldb::eLanguageTypeObjC;
+ if (pointee_type.getTypePtr() == m_ast->ObjCBuiltinIdTy.getTypePtr())
+ return lldb::eLanguageTypeObjC;
+ }
+ else
+ {
+ if (qual_type->isObjCObjectOrInterfaceType())
+ return lldb::eLanguageTypeObjC;
+ if (qual_type->getAsCXXRecordDecl())
+ return lldb::eLanguageTypeC_plus_plus;
+ switch (qual_type->getTypeClass())
+ {
+ default:
+ break;
+ case clang::Type::Builtin:
+ switch (cast<BuiltinType>(qual_type)->getKind())
+ {
+ default:
+ case BuiltinType::Void:
+ case BuiltinType::Bool:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ break;
+
+ case BuiltinType::NullPtr:
+ return eLanguageTypeC_plus_plus;
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ return eLanguageTypeObjC;
+
+ case BuiltinType::Dependent:
+ case BuiltinType::Overload:
+ case BuiltinType::BoundMember:
+ case BuiltinType::UnknownAny:
+ break;
+ }
+ break;
+ case clang::Type::Typedef:
+ return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetMinimumLanguage();
+ }
+ }
+ return lldb::eLanguageTypeC;
+}
+
+lldb::TypeClass
+ClangASTType::GetTypeClass () const
+{
+ if (!IsValid())
+ return lldb::eTypeClassInvalid;
+
+ QualType qual_type(GetQualType());
+
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::UnaryTransform: break;
+ case clang::Type::FunctionNoProto: return lldb::eTypeClassFunction;
+ case clang::Type::FunctionProto: return lldb::eTypeClassFunction;
+ case clang::Type::IncompleteArray: return lldb::eTypeClassArray;
+ case clang::Type::VariableArray: return lldb::eTypeClassArray;
+ case clang::Type::ConstantArray: return lldb::eTypeClassArray;
+ case clang::Type::DependentSizedArray: return lldb::eTypeClassArray;
+ case clang::Type::DependentSizedExtVector: return lldb::eTypeClassVector;
+ case clang::Type::ExtVector: return lldb::eTypeClassVector;
+ case clang::Type::Vector: return lldb::eTypeClassVector;
+ case clang::Type::Builtin: return lldb::eTypeClassBuiltin;
+ case clang::Type::ObjCObjectPointer: return lldb::eTypeClassObjCObjectPointer;
+ case clang::Type::BlockPointer: return lldb::eTypeClassBlockPointer;
+ case clang::Type::Pointer: return lldb::eTypeClassPointer;
+ case clang::Type::LValueReference: return lldb::eTypeClassReference;
+ case clang::Type::RValueReference: return lldb::eTypeClassReference;
+ case clang::Type::MemberPointer: return lldb::eTypeClassMemberPointer;
+ case clang::Type::Complex:
+ if (qual_type->isComplexType())
+ return lldb::eTypeClassComplexFloat;
+ else
+ return lldb::eTypeClassComplexInteger;
+ case clang::Type::ObjCObject: return lldb::eTypeClassObjCObject;
+ case clang::Type::ObjCInterface: return lldb::eTypeClassObjCInterface;
+ case clang::Type::Record:
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl->isUnion())
+ return lldb::eTypeClassUnion;
+ else if (record_decl->isStruct())
+ return lldb::eTypeClassStruct;
+ else
+ return lldb::eTypeClassClass;
+ }
+ break;
+ case clang::Type::Enum: return lldb::eTypeClassEnumeration;
+ case clang::Type::Typedef: return lldb::eTypeClassTypedef;
+ case clang::Type::UnresolvedUsing: break;
+ case clang::Type::Paren:
+ return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).GetTypeClass();
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTypeClass();
+
+ case clang::Type::Attributed: break;
+ case clang::Type::TemplateTypeParm: break;
+ case clang::Type::SubstTemplateTypeParm: break;
+ case clang::Type::SubstTemplateTypeParmPack:break;
+ case clang::Type::Auto: break;
+ case clang::Type::InjectedClassName: break;
+ case clang::Type::DependentName: break;
+ case clang::Type::DependentTemplateSpecialization: break;
+ case clang::Type::PackExpansion: break;
+
+ case clang::Type::TypeOfExpr: break;
+ case clang::Type::TypeOf: break;
+ case clang::Type::Decltype: break;
+ case clang::Type::TemplateSpecialization: break;
+ case clang::Type::Atomic: break;
+ }
+ // We don't know hot to display this type...
+ return lldb::eTypeClassOther;
+
+}
+
+void
+ClangASTType::SetClangType (clang::ASTContext *ast, clang::QualType qual_type)
+{
+ m_ast = ast;
+ m_type = qual_type.getAsOpaquePtr();
+}
+
+unsigned
+ClangASTType::GetTypeQualifiers() const
+{
+ if (IsValid())
+ return GetQualType().getQualifiers().getCVRQualifiers();
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Creating related types
+//----------------------------------------------------------------------
+
+ClangASTType
+ClangASTType::AddConstModifier () const
+{
+ if (m_type)
+ {
+ QualType result(GetQualType());
+ result.addConst();
+ return ClangASTType (m_ast, result);
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::AddRestrictModifier () const
+{
+ if (m_type)
+ {
+ QualType result(GetQualType());
+ result.getQualifiers().setRestrict (true);
+ return ClangASTType (m_ast, result);
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::AddVolatileModifier () const
+{
+ if (m_type)
+ {
+ QualType result(GetQualType());
+ result.getQualifiers().setVolatile (true);
+ return ClangASTType (m_ast, result);
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetArrayElementType (uint64_t& stride) const
+{
+ if (IsValid())
+ {
+ QualType qual_type(GetCanonicalQualType());
+
+ ClangASTType element_type (m_ast, qual_type.getTypePtr()->getArrayElementTypeNoTypeQual()->getCanonicalTypeUnqualified());
+
+ // TODO: the real stride will be >= this value.. find the real one!
+ stride = element_type.GetByteSize();
+
+ return element_type;
+
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetCanonicalType () const
+{
+ if (IsValid())
+ return ClangASTType (m_ast, GetCanonicalQualType());
+ return ClangASTType();
+}
+
+static QualType
+GetFullyUnqualifiedType_Impl (ASTContext *ast, QualType qual_type)
+{
+ if (qual_type->isPointerType())
+ qual_type = ast->getPointerType(GetFullyUnqualifiedType_Impl(ast, qual_type->getPointeeType()));
+ else
+ qual_type = qual_type.getUnqualifiedType();
+ qual_type.removeLocalConst();
+ qual_type.removeLocalRestrict();
+ qual_type.removeLocalVolatile();
+ return qual_type;
+}
+
+ClangASTType
+ClangASTType::GetFullyUnqualifiedType () const
+{
+ if (IsValid())
+ return ClangASTType(m_ast, GetFullyUnqualifiedType_Impl(m_ast, GetQualType()));
+ return ClangASTType();
+}
+
+
+int
+ClangASTType::GetFunctionArgumentCount () const
+{
+ if (IsValid())
+ {
+ const FunctionProtoType* func = dyn_cast<FunctionProtoType>(GetCanonicalQualType());
+ if (func)
+ return func->getNumArgs();
+ }
+ return -1;
+}
+
+ClangASTType
+ClangASTType::GetFunctionArgumentTypeAtIndex (size_t idx)
+{
+ if (IsValid())
+ {
+ const FunctionProtoType* func = dyn_cast<FunctionProtoType>(GetCanonicalQualType());
+ if (func)
+ {
+ const uint32_t num_args = func->getNumArgs();
+ if (idx < num_args)
+ return ClangASTType(m_ast, func->getArgType(idx));
+ }
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetFunctionReturnType () const
+{
+ if (IsValid())
+ {
+ QualType qual_type(GetCanonicalQualType());
+ const FunctionProtoType* func = dyn_cast<FunctionProtoType>(qual_type.getTypePtr());
+ if (func)
+ return ClangASTType(m_ast, func->getResultType());
+ }
+ return ClangASTType();
+}
+
+
+ClangASTType
+ClangASTType::GetLValueReferenceType () const
+{
+ if (IsValid())
+ {
+ return ClangASTType(m_ast, m_ast->getLValueReferenceType(GetQualType()));
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetRValueReferenceType () const
+{
+ if (IsValid())
+ {
+ return ClangASTType(m_ast, m_ast->getRValueReferenceType(GetQualType()));
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetNonReferenceType () const
+{
+ if (IsValid())
+ return ClangASTType(m_ast, GetQualType().getNonReferenceType());
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::CreateTypedefType (const char *typedef_name,
+ clang::DeclContext *decl_ctx) const
+{
+ if (IsValid() && typedef_name && typedef_name[0])
+ {
+ QualType qual_type (GetQualType());
+ if (decl_ctx == NULL)
+ decl_ctx = m_ast->getTranslationUnitDecl();
+ TypedefDecl *decl = TypedefDecl::Create (*m_ast,
+ decl_ctx,
+ SourceLocation(),
+ SourceLocation(),
+ &m_ast->Idents.get(typedef_name),
+ m_ast->getTrivialTypeSourceInfo(qual_type));
+
+ decl->setAccess(AS_public); // TODO respect proper access specifier
+
+ // Get a uniqued QualType for the typedef decl type
+ return ClangASTType (m_ast, m_ast->getTypedefType (decl));
+ }
+ return ClangASTType();
+
+}
+
+ClangASTType
+ClangASTType::GetPointeeType () const
+{
+ if (m_type)
+ {
+ QualType qual_type(GetQualType());
+ return ClangASTType (m_ast, qual_type.getTypePtr()->getPointeeType());
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetPointerType () const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ return ClangASTType(m_ast, m_ast->getObjCObjectPointerType(qual_type).getAsOpaquePtr());
+
+ default:
+ return ClangASTType(m_ast, m_ast->getPointerType(qual_type).getAsOpaquePtr());
+ }
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetTypedefedType () const
+{
+ if (IsValid())
+ {
+ const TypedefType *typedef_type = dyn_cast<TypedefType>(GetQualType());
+ if (typedef_type)
+ return ClangASTType (m_ast, typedef_type->getDecl()->getUnderlyingType());
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::RemoveFastQualifiers () const
+{
+ if (m_type)
+ {
+ QualType qual_type(GetQualType());
+ qual_type.getQualifiers().removeFastQualifiers();
+ return ClangASTType (m_ast, qual_type);
+ }
+ return ClangASTType();
+}
+
+
+//----------------------------------------------------------------------
+// Create related types using the current type's AST
+//----------------------------------------------------------------------
+
+ClangASTType
+ClangASTType::GetBasicTypeFromAST (lldb::BasicType basic_type) const
+{
+ if (IsValid())
+ return ClangASTContext::GetBasicType(m_ast, basic_type);
+ return ClangASTType();
+}
+//----------------------------------------------------------------------
+// Exploring the type
+//----------------------------------------------------------------------
+
+uint64_t
+ClangASTType::GetBitSize () const
+{
+ if (GetCompleteType ())
+ {
+ QualType qual_type(GetCanonicalQualType());
+ const uint32_t bit_size = m_ast->getTypeSize (qual_type);
+ if (bit_size == 0)
+ {
+ if (qual_type->isIncompleteArrayType())
+ return m_ast->getTypeSize (qual_type->getArrayElementTypeNoTypeQual()->getCanonicalTypeUnqualified());
+ }
+ if (qual_type->isObjCObjectOrInterfaceType())
+ return bit_size + m_ast->getTypeSize(m_ast->ObjCBuiltinClassTy);
+ return bit_size;
+ }
+ return 0;
+}
+
+uint64_t
+ClangASTType::GetByteSize () const
+{
+ return (GetBitSize () + 7) / 8;
+}
+
+size_t
+ClangASTType::GetTypeBitAlign () const
+{
+ if (GetCompleteType ())
+ return m_ast->getTypeAlign(GetQualType());
+ return 0;
+}
+
+
+lldb::Encoding
+ClangASTType::GetEncoding (uint64_t &count) const
+{
+ if (!IsValid())
+ return lldb::eEncodingInvalid;
+
+ count = 1;
+ QualType qual_type(GetCanonicalQualType());
+
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::UnaryTransform:
+ break;
+
+ case clang::Type::FunctionNoProto:
+ case clang::Type::FunctionProto:
+ break;
+
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ break;
+
+ case clang::Type::ConstantArray:
+ break;
+
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ // TODO: Set this to more than one???
+ break;
+
+ case clang::Type::Builtin:
+ switch (cast<BuiltinType>(qual_type)->getKind())
+ {
+ default: assert(0 && "Unknown builtin type!");
+ case BuiltinType::Void:
+ break;
+
+ case BuiltinType::Bool:
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Short:
+ case BuiltinType::Int:
+ case BuiltinType::Long:
+ case BuiltinType::LongLong:
+ case BuiltinType::Int128: return lldb::eEncodingSint;
+
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::WChar_U:
+ case BuiltinType::UShort:
+ case BuiltinType::UInt:
+ case BuiltinType::ULong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::UInt128: return lldb::eEncodingUint;
+
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble: return lldb::eEncodingIEEE754;
+
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCSel: return lldb::eEncodingUint;
+
+ case BuiltinType::NullPtr: return lldb::eEncodingUint;
+ }
+ break;
+ // All pointer types are represented as unsigned integer encodings.
+ // We may nee to add a eEncodingPointer if we ever need to know the
+ // difference
+ case clang::Type::ObjCObjectPointer:
+ case clang::Type::BlockPointer:
+ case clang::Type::Pointer:
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ case clang::Type::MemberPointer: return lldb::eEncodingUint;
+ case clang::Type::Complex:
+ {
+ lldb::Encoding encoding = lldb::eEncodingIEEE754;
+ if (qual_type->isComplexType())
+ encoding = lldb::eEncodingIEEE754;
+ else
+ {
+ const ComplexType *complex_type = qual_type->getAsComplexIntegerType();
+ if (complex_type)
+ encoding = ClangASTType(m_ast, complex_type->getElementType()).GetEncoding(count);
+ else
+ encoding = lldb::eEncodingSint;
+ }
+ count = 2;
+ return encoding;
+ }
+
+ case clang::Type::ObjCInterface: break;
+ case clang::Type::Record: break;
+ case clang::Type::Enum: return lldb::eEncodingSint;
+ case clang::Type::Typedef:
+ return ClangASTType(m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetEncoding(count);
+
+ case clang::Type::Elaborated:
+ return ClangASTType(m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetEncoding(count);
+
+ case clang::Type::Paren:
+ return ClangASTType(m_ast, cast<ParenType>(qual_type)->desugar()).GetEncoding(count);
+
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Attributed:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::Auto:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::Atomic:
+ break;
+
+ }
+ count = 0;
+ return lldb::eEncodingInvalid;
+}
+
+lldb::Format
+ClangASTType::GetFormat () const
+{
+ if (!IsValid())
+ return lldb::eFormatDefault;
+
+ QualType qual_type(GetCanonicalQualType());
+
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::UnaryTransform:
+ break;
+
+ case clang::Type::FunctionNoProto:
+ case clang::Type::FunctionProto:
+ break;
+
+ case clang::Type::IncompleteArray:
+ case clang::Type::VariableArray:
+ break;
+
+ case clang::Type::ConstantArray:
+ return lldb::eFormatVoid; // no value
+
+ case clang::Type::ExtVector:
+ case clang::Type::Vector:
+ break;
+
+ case clang::Type::Builtin:
+ switch (cast<BuiltinType>(qual_type)->getKind())
+ {
+ //default: assert(0 && "Unknown builtin type!");
+ case BuiltinType::UnknownAny:
+ case BuiltinType::Void:
+ case BuiltinType::BoundMember:
+ break;
+
+ case BuiltinType::Bool: return lldb::eFormatBoolean;
+ case BuiltinType::Char_S:
+ case BuiltinType::SChar:
+ case BuiltinType::WChar_S:
+ case BuiltinType::Char_U:
+ case BuiltinType::UChar:
+ case BuiltinType::WChar_U: return lldb::eFormatChar;
+ case BuiltinType::Char16: return lldb::eFormatUnicode16;
+ case BuiltinType::Char32: return lldb::eFormatUnicode32;
+ case BuiltinType::UShort: return lldb::eFormatUnsigned;
+ case BuiltinType::Short: return lldb::eFormatDecimal;
+ case BuiltinType::UInt: return lldb::eFormatUnsigned;
+ case BuiltinType::Int: return lldb::eFormatDecimal;
+ case BuiltinType::ULong: return lldb::eFormatUnsigned;
+ case BuiltinType::Long: return lldb::eFormatDecimal;
+ case BuiltinType::ULongLong: return lldb::eFormatUnsigned;
+ case BuiltinType::LongLong: return lldb::eFormatDecimal;
+ case BuiltinType::UInt128: return lldb::eFormatUnsigned;
+ case BuiltinType::Int128: return lldb::eFormatDecimal;
+ case BuiltinType::Float: return lldb::eFormatFloat;
+ case BuiltinType::Double: return lldb::eFormatFloat;
+ case BuiltinType::LongDouble: return lldb::eFormatFloat;
+ case BuiltinType::NullPtr:
+ case BuiltinType::Overload:
+ case BuiltinType::Dependent:
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ case BuiltinType::Half:
+ case BuiltinType::ARCUnbridgedCast:
+ case BuiltinType::PseudoObject:
+ case BuiltinType::BuiltinFn:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::OCLSampler:
+ return lldb::eFormatHex;
+ }
+ break;
+ case clang::Type::ObjCObjectPointer: return lldb::eFormatHex;
+ case clang::Type::BlockPointer: return lldb::eFormatHex;
+ case clang::Type::Pointer: return lldb::eFormatHex;
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference: return lldb::eFormatHex;
+ case clang::Type::MemberPointer: break;
+ case clang::Type::Complex:
+ {
+ if (qual_type->isComplexType())
+ return lldb::eFormatComplex;
+ else
+ return lldb::eFormatComplexInteger;
+ }
+ case clang::Type::ObjCInterface: break;
+ case clang::Type::Record: break;
+ case clang::Type::Enum: return lldb::eFormatEnum;
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetFormat();
+ case clang::Type::Auto:
+ return ClangASTType (m_ast, cast<AutoType>(qual_type)->desugar()).GetFormat();
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetFormat();
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetFormat();
+ case clang::Type::DependentSizedArray:
+ case clang::Type::DependentSizedExtVector:
+ case clang::Type::UnresolvedUsing:
+ case clang::Type::Attributed:
+ case clang::Type::TemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParm:
+ case clang::Type::SubstTemplateTypeParmPack:
+ case clang::Type::InjectedClassName:
+ case clang::Type::DependentName:
+ case clang::Type::DependentTemplateSpecialization:
+ case clang::Type::PackExpansion:
+ case clang::Type::ObjCObject:
+
+ case clang::Type::TypeOfExpr:
+ case clang::Type::TypeOf:
+ case clang::Type::Decltype:
+ case clang::Type::TemplateSpecialization:
+ case clang::Type::Atomic:
+ break;
+ }
+ // We don't know hot to display this type...
+ return lldb::eFormatBytes;
+}
+
+static bool
+ObjCDeclHasIVars (ObjCInterfaceDecl *class_interface_decl, bool check_superclass)
+{
+ while (class_interface_decl)
+ {
+ if (class_interface_decl->ivar_size() > 0)
+ return true;
+
+ if (check_superclass)
+ class_interface_decl = class_interface_decl->getSuperClass();
+ else
+ break;
+ }
+ return false;
+}
+
+uint32_t
+ClangASTType::GetNumChildren (bool omit_empty_base_classes) const
+{
+ if (!IsValid())
+ return 0;
+
+ uint32_t num_children = 0;
+ QualType qual_type(GetQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ switch (cast<BuiltinType>(qual_type)->getKind())
+ {
+ case BuiltinType::ObjCId: // child is Class
+ case BuiltinType::ObjCClass: // child is Class
+ num_children = 1;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case clang::Type::Complex: return 0;
+
+ case clang::Type::Record:
+ if (GetCompleteQualType (m_ast, qual_type))
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ if (omit_empty_base_classes)
+ {
+ // Check each base classes to see if it or any of its
+ // base classes contain any fields. This can help
+ // limit the noise in variable views by not having to
+ // show base classes that contain no members.
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+
+ // Skip empty base classes
+ if (ClangASTContext::RecordHasFields(base_class_decl) == false)
+ continue;
+
+ num_children++;
+ }
+ }
+ else
+ {
+ // Include all base classes
+ num_children += cxx_record_decl->getNumBases();
+ }
+
+ }
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field)
+ ++num_children;
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteQualType (m_ast, qual_type))
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ if (superclass_interface_decl)
+ {
+ if (omit_empty_base_classes)
+ {
+ if (ObjCDeclHasIVars (superclass_interface_decl, true))
+ ++num_children;
+ }
+ else
+ ++num_children;
+ }
+
+ num_children += class_interface_decl->ivar_size();
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ {
+ const ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(qual_type.getTypePtr());
+ QualType pointee_type = pointer_type->getPointeeType();
+ uint32_t num_pointee_children = ClangASTType (m_ast,pointee_type).GetNumChildren (omit_empty_base_classes);
+ // If this type points to a simple type, then it has 1 child
+ if (num_pointee_children == 0)
+ num_children = 1;
+ else
+ num_children = num_pointee_children;
+ }
+ break;
+
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ num_children = cast<VectorType>(qual_type.getTypePtr())->getNumElements();
+ break;
+
+ case clang::Type::ConstantArray:
+ num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
+ break;
+
+ case clang::Type::Pointer:
+ {
+ const PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ QualType pointee_type (pointer_type->getPointeeType());
+ uint32_t num_pointee_children = ClangASTType (m_ast,pointee_type).GetNumChildren (omit_empty_base_classes);
+ if (num_pointee_children == 0)
+ {
+ // We have a pointer to a pointee type that claims it has no children.
+ // We will want to look at
+ num_children = ClangASTType (m_ast, pointee_type).GetNumPointeeChildren();
+ }
+ else
+ num_children = num_pointee_children;
+ }
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ QualType pointee_type = reference_type->getPointeeType();
+ uint32_t num_pointee_children = ClangASTType (m_ast, pointee_type).GetNumChildren (omit_empty_base_classes);
+ // If this type points to a simple type, then it has 1 child
+ if (num_pointee_children == 0)
+ num_children = 1;
+ else
+ num_children = num_pointee_children;
+ }
+ break;
+
+
+ case clang::Type::Typedef:
+ num_children = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumChildren (omit_empty_base_classes);
+ break;
+
+ case clang::Type::Elaborated:
+ num_children = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumChildren (omit_empty_base_classes);
+ break;
+
+ case clang::Type::Paren:
+ num_children = ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetNumChildren (omit_empty_base_classes);
+ break;
+ default:
+ break;
+ }
+ return num_children;
+}
+
+lldb::BasicType
+ClangASTType::GetBasicTypeEnumeration () const
+{
+ if (IsValid())
+ {
+ QualType qual_type(GetQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ if (type_class == clang::Type::Builtin)
+ {
+ switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ {
+ case clang::BuiltinType::Void: return eBasicTypeVoid;
+ case clang::BuiltinType::Bool: return eBasicTypeBool;
+ case clang::BuiltinType::Char_S: return eBasicTypeSignedChar;
+ case clang::BuiltinType::Char_U: return eBasicTypeUnsignedChar;
+ case clang::BuiltinType::Char16: return eBasicTypeChar16;
+ case clang::BuiltinType::Char32: return eBasicTypeChar32;
+ case clang::BuiltinType::UChar: return eBasicTypeUnsignedChar;
+ case clang::BuiltinType::SChar: return eBasicTypeSignedChar;
+ case clang::BuiltinType::WChar_S: return eBasicTypeSignedWChar;
+ case clang::BuiltinType::WChar_U: return eBasicTypeUnsignedWChar;
+ case clang::BuiltinType::Short: return eBasicTypeShort;
+ case clang::BuiltinType::UShort: return eBasicTypeUnsignedShort;
+ case clang::BuiltinType::Int: return eBasicTypeInt;
+ case clang::BuiltinType::UInt: return eBasicTypeUnsignedInt;
+ case clang::BuiltinType::Long: return eBasicTypeLong;
+ case clang::BuiltinType::ULong: return eBasicTypeUnsignedLong;
+ case clang::BuiltinType::LongLong: return eBasicTypeLongLong;
+ case clang::BuiltinType::ULongLong: return eBasicTypeUnsignedLongLong;
+ case clang::BuiltinType::Int128: return eBasicTypeInt128;
+ case clang::BuiltinType::UInt128: return eBasicTypeUnsignedInt128;
+
+ case clang::BuiltinType::Half: return eBasicTypeHalf;
+ case clang::BuiltinType::Float: return eBasicTypeFloat;
+ case clang::BuiltinType::Double: return eBasicTypeDouble;
+ case clang::BuiltinType::LongDouble:return eBasicTypeLongDouble;
+
+ case clang::BuiltinType::NullPtr: return eBasicTypeNullPtr;
+ case clang::BuiltinType::ObjCId: return eBasicTypeObjCID;
+ case clang::BuiltinType::ObjCClass: return eBasicTypeObjCClass;
+ case clang::BuiltinType::ObjCSel: return eBasicTypeObjCSel;
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::BuiltinFn:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLImage1d:
+ case clang::BuiltinType::OCLImage1dArray:
+ case clang::BuiltinType::OCLImage1dBuffer:
+ case clang::BuiltinType::OCLImage2d:
+ case clang::BuiltinType::OCLImage2dArray:
+ case clang::BuiltinType::OCLImage3d:
+ case clang::BuiltinType::OCLSampler:
+ return eBasicTypeOther;
+ }
+ }
+ }
+ return eBasicTypeInvalid;
+}
+
+
+#pragma mark Aggregate Types
+
+uint32_t
+ClangASTType::GetNumDirectBaseClasses () const
+{
+ if (!IsValid())
+ return 0;
+
+ uint32_t count = 0;
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ count = cxx_record_decl->getNumBases();
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (GetCompleteType())
+ {
+ const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ if (class_interface_decl && class_interface_decl->getSuperClass())
+ count = 1;
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ const ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl && class_interface_decl->getSuperClass())
+ count = 1;
+ }
+ }
+ break;
+
+
+ case clang::Type::Typedef:
+ count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumDirectBaseClasses ();
+ break;
+
+ case clang::Type::Elaborated:
+ count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumDirectBaseClasses ();
+ break;
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumDirectBaseClasses ();
+
+ default:
+ break;
+ }
+ return count;
+}
+
+uint32_t
+ClangASTType::GetNumVirtualBaseClasses () const
+{
+ if (!IsValid())
+ return 0;
+
+ uint32_t count = 0;
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ count = cxx_record_decl->getNumVBases();
+ }
+ break;
+
+ case clang::Type::Typedef:
+ count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumVirtualBaseClasses();
+ break;
+
+ case clang::Type::Elaborated:
+ count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumVirtualBaseClasses();
+ break;
+
+ case clang::Type::Paren:
+ count = ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumVirtualBaseClasses();
+ break;
+
+ default:
+ break;
+ }
+ return count;
+}
+
+uint32_t
+ClangASTType::GetNumFields () const
+{
+ if (!IsValid())
+ return 0;
+
+ uint32_t count = 0;
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const RecordType *record_type = dyn_cast<RecordType>(qual_type.getTypePtr());
+ if (record_type)
+ {
+ RecordDecl *record_decl = record_type->getDecl();
+ if (record_decl)
+ {
+ uint32_t field_idx = 0;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field)
+ ++field_idx;
+ count = field_idx;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ count = ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumFields();
+ break;
+
+ case clang::Type::Elaborated:
+ count = ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumFields();
+ break;
+
+ case clang::Type::Paren:
+ count = ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumFields();
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (GetCompleteType())
+ {
+ const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+
+ if (class_interface_decl)
+ count = class_interface_decl->ivar_size();
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ count = class_interface_decl->ivar_size();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return count;
+}
+
+ClangASTType
+ClangASTType::GetDirectBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) const
+{
+ if (!IsValid())
+ return ClangASTType();
+
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ uint32_t curr_idx = 0;
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class, ++curr_idx)
+ {
+ if (curr_idx == idx)
+ {
+ if (bit_offset_ptr)
+ {
+ const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ if (base_class->isVirtual())
+ *bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ else
+ *bit_offset_ptr = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
+ }
+ return ClangASTType (m_ast, base_class->getType());
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (idx == 0 && GetCompleteType())
+ {
+ const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ if (class_interface_decl)
+ {
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ if (superclass_interface_decl)
+ {
+ if (bit_offset_ptr)
+ *bit_offset_ptr = 0;
+ return ClangASTType (m_ast, m_ast->getObjCInterfaceType(superclass_interface_decl));
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (idx == 0 && GetCompleteType())
+ {
+ const ObjCObjectType *objc_class_type = qual_type->getAsObjCQualifiedInterfaceType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ if (superclass_interface_decl)
+ {
+ if (bit_offset_ptr)
+ *bit_offset_ptr = 0;
+ return ClangASTType (m_ast, m_ast->getObjCInterfaceType(superclass_interface_decl));
+ }
+ }
+ }
+ }
+ break;
+
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetDirectBaseClassAtIndex (idx, bit_offset_ptr);
+
+ default:
+ break;
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::GetVirtualBaseClassAtIndex (size_t idx, uint32_t *bit_offset_ptr) const
+{
+ if (!IsValid())
+ return ClangASTType();
+
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ uint32_t curr_idx = 0;
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->vbases_begin(), base_class_end = cxx_record_decl->vbases_end();
+ base_class != base_class_end;
+ ++base_class, ++curr_idx)
+ {
+ if (curr_idx == idx)
+ {
+ if (bit_offset_ptr)
+ {
+ const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(cxx_record_decl);
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ *bit_offset_ptr = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+
+ }
+ return ClangASTType (m_ast, base_class->getType());
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetVirtualBaseClassAtIndex (idx, bit_offset_ptr);
+
+ default:
+ break;
+ }
+ return ClangASTType();
+}
+
+static clang_type_t
+GetObjCFieldAtIndex (clang::ASTContext *ast,
+ ObjCInterfaceDecl *class_interface_decl,
+ size_t idx,
+ std::string& name,
+ uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr)
+{
+ if (class_interface_decl)
+ {
+ if (idx < (class_interface_decl->ivar_size()))
+ {
+ ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ uint32_t ivar_idx = 0;
+
+ for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++ivar_idx)
+ {
+ if (ivar_idx == idx)
+ {
+ const ObjCIvarDecl* ivar_decl = *ivar_pos;
+
+ QualType ivar_qual_type(ivar_decl->getType());
+
+ name.assign(ivar_decl->getNameAsString());
+
+ if (bit_offset_ptr)
+ {
+ const ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl);
+ *bit_offset_ptr = interface_layout.getFieldOffset (ivar_idx);
+ }
+
+ const bool is_bitfield = ivar_pos->isBitField();
+
+ if (bitfield_bit_size_ptr)
+ {
+ *bitfield_bit_size_ptr = 0;
+
+ if (is_bitfield && ast)
+ {
+ Expr *bitfield_bit_size_expr = ivar_pos->getBitWidth();
+ llvm::APSInt bitfield_apsint;
+ if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *ast))
+ {
+ *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
+ }
+ }
+ }
+ if (is_bitfield_ptr)
+ *is_bitfield_ptr = is_bitfield;
+
+ return ivar_qual_type.getAsOpaquePtr();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+ClangASTType
+ClangASTType::GetFieldAtIndex (size_t idx,
+ std::string& name,
+ uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr) const
+{
+ if (!IsValid())
+ return ClangASTType();
+
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType())
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ uint32_t field_idx = 0;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx)
+ {
+ if (idx == field_idx)
+ {
+ // Print the member type if requested
+ // Print the member name and equal sign
+ name.assign(field->getNameAsString());
+
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ if (bit_offset_ptr)
+ {
+ const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ *bit_offset_ptr = record_layout.getFieldOffset (field_idx);
+ }
+
+ const bool is_bitfield = field->isBitField();
+
+ if (bitfield_bit_size_ptr)
+ {
+ *bitfield_bit_size_ptr = 0;
+
+ if (is_bitfield)
+ {
+ Expr *bitfield_bit_size_expr = field->getBitWidth();
+ llvm::APSInt bitfield_apsint;
+ if (bitfield_bit_size_expr && bitfield_bit_size_expr->EvaluateAsInt(bitfield_apsint, *m_ast))
+ {
+ *bitfield_bit_size_ptr = bitfield_apsint.getLimitedValue();
+ }
+ }
+ }
+ if (is_bitfield_ptr)
+ *is_bitfield_ptr = is_bitfield;
+
+ return ClangASTType (m_ast, field->getType());
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (GetCompleteType())
+ {
+ const ObjCObjectPointerType *objc_class_type = qual_type->getAsObjCInterfacePointerType();
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterfaceDecl();
+ return ClangASTType (m_ast, GetObjCFieldAtIndex(m_ast, class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr));
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ return ClangASTType (m_ast, GetObjCFieldAtIndex(m_ast, class_interface_decl, idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr));
+ }
+ }
+ break;
+
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).
+ GetFieldAtIndex (idx,
+ name,
+ bit_offset_ptr,
+ bitfield_bit_size_ptr,
+ is_bitfield_ptr);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).
+ GetFieldAtIndex (idx,
+ name,
+ bit_offset_ptr,
+ bitfield_bit_size_ptr,
+ is_bitfield_ptr);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).
+ GetFieldAtIndex (idx,
+ name,
+ bit_offset_ptr,
+ bitfield_bit_size_ptr,
+ is_bitfield_ptr);
+
+ default:
+ break;
+ }
+ return ClangASTType();
+}
+
+uint32_t
+ClangASTType::GetIndexOfFieldWithName (const char* name,
+ ClangASTType* field_clang_type_ptr,
+ uint64_t *bit_offset_ptr,
+ uint32_t *bitfield_bit_size_ptr,
+ bool *is_bitfield_ptr) const
+{
+ unsigned count = GetNumFields();
+ std::string field_name;
+ for (unsigned index = 0; index < count; index++)
+ {
+ ClangASTType field_clang_type (GetFieldAtIndex(index, field_name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr));
+ if (strcmp(field_name.c_str(), name) == 0)
+ {
+ if (field_clang_type_ptr)
+ *field_clang_type_ptr = field_clang_type;
+ return index;
+ }
+ }
+ return UINT32_MAX;
+}
+
+// If a pointer to a pointee type (the clang_type arg) says that it has no
+// children, then we either need to trust it, or override it and return a
+// different result. For example, an "int *" has one child that is an integer,
+// but a function pointer doesn't have any children. Likewise if a Record type
+// claims it has no children, then there really is nothing to show.
+uint32_t
+ClangASTType::GetNumPointeeChildren () const
+{
+ if (!IsValid())
+ return 0;
+
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Builtin:
+ switch (cast<clang::BuiltinType>(qual_type)->getKind())
+ {
+ case clang::BuiltinType::UnknownAny:
+ case clang::BuiltinType::Void:
+ case clang::BuiltinType::NullPtr:
+ case clang::BuiltinType::OCLEvent:
+ case clang::BuiltinType::OCLImage1d:
+ case clang::BuiltinType::OCLImage1dArray:
+ case clang::BuiltinType::OCLImage1dBuffer:
+ case clang::BuiltinType::OCLImage2d:
+ case clang::BuiltinType::OCLImage2dArray:
+ case clang::BuiltinType::OCLImage3d:
+ case clang::BuiltinType::OCLSampler:
+ return 0;
+ case clang::BuiltinType::Bool:
+ case clang::BuiltinType::Char_U:
+ case clang::BuiltinType::UChar:
+ case clang::BuiltinType::WChar_U:
+ case clang::BuiltinType::Char16:
+ case clang::BuiltinType::Char32:
+ case clang::BuiltinType::UShort:
+ case clang::BuiltinType::UInt:
+ case clang::BuiltinType::ULong:
+ case clang::BuiltinType::ULongLong:
+ case clang::BuiltinType::UInt128:
+ case clang::BuiltinType::Char_S:
+ case clang::BuiltinType::SChar:
+ case clang::BuiltinType::WChar_S:
+ case clang::BuiltinType::Short:
+ case clang::BuiltinType::Int:
+ case clang::BuiltinType::Long:
+ case clang::BuiltinType::LongLong:
+ case clang::BuiltinType::Int128:
+ case clang::BuiltinType::Float:
+ case clang::BuiltinType::Double:
+ case clang::BuiltinType::LongDouble:
+ case clang::BuiltinType::Dependent:
+ case clang::BuiltinType::Overload:
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ case clang::BuiltinType::ObjCSel:
+ case clang::BuiltinType::BoundMember:
+ case clang::BuiltinType::Half:
+ case clang::BuiltinType::ARCUnbridgedCast:
+ case clang::BuiltinType::PseudoObject:
+ case clang::BuiltinType::BuiltinFn:
+ return 1;
+ }
+ break;
+
+ case clang::Type::Complex: return 1;
+ case clang::Type::Pointer: return 1;
+ case clang::Type::BlockPointer: return 0; // If block pointers don't have debug info, then no children for them
+ case clang::Type::LValueReference: return 1;
+ case clang::Type::RValueReference: return 1;
+ case clang::Type::MemberPointer: return 0;
+ case clang::Type::ConstantArray: return 0;
+ case clang::Type::IncompleteArray: return 0;
+ case clang::Type::VariableArray: return 0;
+ case clang::Type::DependentSizedArray: return 0;
+ case clang::Type::DependentSizedExtVector: return 0;
+ case clang::Type::Vector: return 0;
+ case clang::Type::ExtVector: return 0;
+ case clang::Type::FunctionProto: return 0; // When we function pointers, they have no children...
+ case clang::Type::FunctionNoProto: return 0; // When we function pointers, they have no children...
+ case clang::Type::UnresolvedUsing: return 0;
+ case clang::Type::Paren: return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetNumPointeeChildren ();
+ case clang::Type::Typedef: return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumPointeeChildren ();
+ case clang::Type::Elaborated: return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumPointeeChildren ();
+ case clang::Type::TypeOfExpr: return 0;
+ case clang::Type::TypeOf: return 0;
+ case clang::Type::Decltype: return 0;
+ case clang::Type::Record: return 0;
+ case clang::Type::Enum: return 1;
+ case clang::Type::TemplateTypeParm: return 1;
+ case clang::Type::SubstTemplateTypeParm: return 1;
+ case clang::Type::TemplateSpecialization: return 1;
+ case clang::Type::InjectedClassName: return 0;
+ case clang::Type::DependentName: return 1;
+ case clang::Type::DependentTemplateSpecialization: return 1;
+ case clang::Type::ObjCObject: return 0;
+ case clang::Type::ObjCInterface: return 0;
+ case clang::Type::ObjCObjectPointer: return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+ClangASTType
+ClangASTType::GetChildClangTypeAtIndex (ExecutionContext *exe_ctx,
+ const char *parent_name,
+ size_t idx,
+ bool transparent_pointers,
+ bool omit_empty_base_classes,
+ bool ignore_array_bounds,
+ std::string& child_name,
+ uint32_t &child_byte_size,
+ int32_t &child_byte_offset,
+ uint32_t &child_bitfield_bit_size,
+ uint32_t &child_bitfield_bit_offset,
+ bool &child_is_base_class,
+ bool &child_is_deref_of_parent) const
+{
+ if (!IsValid())
+ return ClangASTType();
+
+ QualType parent_qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass();
+ child_bitfield_bit_size = 0;
+ child_bitfield_bit_offset = 0;
+ child_is_base_class = false;
+
+ const bool idx_is_valid = idx < GetNumChildren (omit_empty_base_classes);
+ uint32_t bit_offset;
+ switch (parent_type_class)
+ {
+ case clang::Type::Builtin:
+ if (idx_is_valid)
+ {
+ switch (cast<clang::BuiltinType>(parent_qual_type)->getKind())
+ {
+ case clang::BuiltinType::ObjCId:
+ case clang::BuiltinType::ObjCClass:
+ child_name = "isa";
+ child_byte_size = m_ast->getTypeSize(m_ast->ObjCBuiltinClassTy) / CHAR_BIT;
+ return ClangASTType (m_ast, m_ast->ObjCBuiltinClassTy);
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case clang::Type::Record:
+ if (idx_is_valid && GetCompleteType())
+ {
+ const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ uint32_t child_idx = 0;
+
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ // We might have base classes to print out first
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ const CXXRecordDecl *base_class_decl = NULL;
+
+ // Skip empty base classes
+ if (omit_empty_base_classes)
+ {
+ base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ if (ClangASTContext::RecordHasFields(base_class_decl) == false)
+ continue;
+ }
+
+ if (idx == child_idx)
+ {
+ if (base_class_decl == NULL)
+ base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+
+
+ if (base_class->isVirtual())
+ bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ else
+ bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
+
+ // Base classes should be a multiple of 8 bits in size
+ child_byte_offset = bit_offset/8;
+ ClangASTType base_class_clang_type(m_ast, base_class->getType());
+ child_name = base_class_clang_type.GetTypeName();
+ uint64_t base_class_clang_type_bit_size = base_class_clang_type.GetBitSize();
+
+ // Base classes bit sizes should be a multiple of 8 bits in size
+ assert (base_class_clang_type_bit_size % 8 == 0);
+ child_byte_size = base_class_clang_type_bit_size / 8;
+ child_is_base_class = true;
+ return base_class_clang_type;
+ }
+ // We don't increment the child index in the for loop since we might
+ // be skipping empty base classes
+ ++child_idx;
+ }
+ }
+ // Make sure index is in range...
+ uint32_t field_idx = 0;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx)
+ {
+ if (idx == child_idx)
+ {
+ // Print the member type if requested
+ // Print the member name and equal sign
+ child_name.assign(field->getNameAsString().c_str());
+
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ ClangASTType field_clang_type (m_ast, field->getType());
+ assert(field_idx < record_layout.getFieldCount());
+ child_byte_size = field_clang_type.GetByteSize();
+
+ // Figure out the field offset within the current struct/union/class type
+ bit_offset = record_layout.getFieldOffset (field_idx);
+ child_byte_offset = bit_offset / 8;
+ if (ClangASTContext::FieldIsBitfield (m_ast, *field, child_bitfield_bit_size))
+ child_bitfield_bit_offset = bit_offset % 8;
+
+ return field_clang_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (idx_is_valid && GetCompleteType())
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(parent_qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ uint32_t child_idx = 0;
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+
+ const ASTRecordLayout &interface_layout = m_ast->getASTObjCInterfaceLayout(class_interface_decl);
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+ if (superclass_interface_decl)
+ {
+ if (omit_empty_base_classes)
+ {
+ ClangASTType base_class_clang_type (m_ast, m_ast->getObjCInterfaceType(superclass_interface_decl));
+ if (base_class_clang_type.GetNumChildren(omit_empty_base_classes) > 0)
+ {
+ if (idx == 0)
+ {
+ QualType ivar_qual_type(m_ast->getObjCInterfaceType(superclass_interface_decl));
+
+
+ child_name.assign(superclass_interface_decl->getNameAsString().c_str());
+
+ std::pair<uint64_t, unsigned> ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
+
+ child_byte_size = ivar_type_info.first / 8;
+ child_byte_offset = 0;
+ child_is_base_class = true;
+
+ return ClangASTType (m_ast, ivar_qual_type);
+ }
+
+ ++child_idx;
+ }
+ }
+ else
+ ++child_idx;
+ }
+
+ const uint32_t superclass_idx = child_idx;
+
+ if (idx < (child_idx + class_interface_decl->ivar_size()))
+ {
+ ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+
+ for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos)
+ {
+ if (child_idx == idx)
+ {
+ ObjCIvarDecl* ivar_decl = *ivar_pos;
+
+ QualType ivar_qual_type(ivar_decl->getType());
+
+ child_name.assign(ivar_decl->getNameAsString().c_str());
+
+ std::pair<uint64_t, unsigned> ivar_type_info = m_ast->getTypeInfo(ivar_qual_type.getTypePtr());
+
+ child_byte_size = ivar_type_info.first / 8;
+
+ // Figure out the field offset within the current struct/union/class type
+ // For ObjC objects, we can't trust the bit offset we get from the Clang AST, since
+ // that doesn't account for the space taken up by unbacked properties, or from
+ // the changing size of base classes that are newer than this class.
+ // So if we have a process around that we can ask about this object, do so.
+ child_byte_offset = LLDB_INVALID_IVAR_OFFSET;
+ Process *process = NULL;
+ if (exe_ctx)
+ process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
+ if (objc_runtime != NULL)
+ {
+ ClangASTType parent_ast_type (m_ast, parent_qual_type);
+ child_byte_offset = objc_runtime->GetByteOffsetForIvar (parent_ast_type, ivar_decl->getNameAsString().c_str());
+ }
+ }
+
+ // Setting this to UINT32_MAX to make sure we don't compute it twice...
+ bit_offset = UINT32_MAX;
+
+ if (child_byte_offset == LLDB_INVALID_IVAR_OFFSET)
+ {
+ bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx);
+ child_byte_offset = bit_offset / 8;
+ }
+
+ // Note, the ObjC Ivar Byte offset is just that, it doesn't account for the bit offset
+ // of a bitfield within its containing object. So regardless of where we get the byte
+ // offset from, we still need to get the bit offset for bitfields from the layout.
+
+ if (ClangASTContext::FieldIsBitfield (m_ast, ivar_decl, child_bitfield_bit_size))
+ {
+ if (bit_offset == UINT32_MAX)
+ bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx);
+
+ child_bitfield_bit_offset = bit_offset % 8;
+ }
+ return ClangASTType (m_ast, ivar_qual_type);
+ }
+ ++child_idx;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ if (idx_is_valid)
+ {
+ ClangASTType pointee_clang_type (GetPointeeType());
+
+ if (transparent_pointers && pointee_clang_type.IsAggregateType())
+ {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ tmp_child_is_deref_of_parent);
+ }
+ else
+ {
+ child_is_deref_of_parent = true;
+ if (parent_name)
+ {
+ child_name.assign(1, '*');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0 && pointee_clang_type.GetCompleteType())
+ {
+ child_byte_size = pointee_clang_type.GetByteSize();
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Vector:
+ case clang::Type::ExtVector:
+ if (idx_is_valid)
+ {
+ const VectorType *array = cast<VectorType>(parent_qual_type.getTypePtr());
+ if (array)
+ {
+ ClangASTType element_type (m_ast, array->getElementType());
+ if (element_type.GetCompleteType())
+ {
+ char element_name[64];
+ ::snprintf (element_name, sizeof (element_name), "[%zu]", idx);
+ child_name.assign(element_name);
+ child_byte_size = element_type.GetByteSize();
+ child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
+ return element_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ConstantArray:
+ case clang::Type::IncompleteArray:
+ if (ignore_array_bounds || idx_is_valid)
+ {
+ const ArrayType *array = cast<ArrayType>(parent_qual_type.getTypePtr());
+ if (array)
+ {
+ ClangASTType element_type (m_ast, array->getElementType());
+ if (element_type.GetCompleteType())
+ {
+ char element_name[64];
+ ::snprintf (element_name, sizeof (element_name), "[%zu]", idx);
+ child_name.assign(element_name);
+ child_byte_size = element_type.GetByteSize();
+ child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
+ return element_type;
+ }
+ }
+ }
+ break;
+
+
+ case clang::Type::Pointer:
+ if (idx_is_valid)
+ {
+ ClangASTType pointee_clang_type (GetPointeeType());
+
+ // Don't dereference "void *" pointers
+ if (pointee_clang_type.IsVoidType())
+ return ClangASTType();
+
+ if (transparent_pointers && pointee_clang_type.IsAggregateType ())
+ {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ tmp_child_is_deref_of_parent);
+ }
+ else
+ {
+ child_is_deref_of_parent = true;
+
+ if (parent_name)
+ {
+ child_name.assign(1, '*');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0)
+ {
+ child_byte_size = pointee_clang_type.GetByteSize();
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ if (idx_is_valid)
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(parent_qual_type.getTypePtr());
+ ClangASTType pointee_clang_type (m_ast, reference_type->getPointeeType());
+ if (transparent_pointers && pointee_clang_type.IsAggregateType ())
+ {
+ child_is_deref_of_parent = false;
+ bool tmp_child_is_deref_of_parent = false;
+ return pointee_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ tmp_child_is_deref_of_parent);
+ }
+ else
+ {
+ if (parent_name)
+ {
+ child_name.assign(1, '&');
+ child_name += parent_name;
+ }
+
+ // We have a pointer to an simple type
+ if (idx == 0)
+ {
+ child_byte_size = pointee_clang_type.GetByteSize();
+ child_byte_offset = 0;
+ return pointee_clang_type;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ {
+ ClangASTType typedefed_clang_type (m_ast, cast<TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType());
+ return typedefed_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ }
+ break;
+
+ case clang::Type::Elaborated:
+ {
+ ClangASTType elaborated_clang_type (m_ast, cast<ElaboratedType>(parent_qual_type)->getNamedType());
+ return elaborated_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ }
+
+ case clang::Type::Paren:
+ {
+ ClangASTType paren_clang_type (m_ast, llvm::cast<clang::ParenType>(parent_qual_type)->desugar());
+ return paren_clang_type.GetChildClangTypeAtIndex (exe_ctx,
+ parent_name,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ ignore_array_bounds,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ }
+
+
+ default:
+ break;
+ }
+ return ClangASTType();
+}
+
+static inline bool
+BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
+{
+ return ClangASTContext::RecordHasFields(b->getType()->getAsCXXRecordDecl()) == false;
+}
+
+static uint32_t
+GetIndexForRecordBase
+(
+ const RecordDecl *record_decl,
+ const CXXBaseSpecifier *base_spec,
+ bool omit_empty_base_classes
+ )
+{
+ uint32_t child_idx = 0;
+
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+
+ // const char *super_name = record_decl->getNameAsCString();
+ // const char *base_name = base_spec->getType()->getAs<RecordType>()->getDecl()->getNameAsCString();
+ // printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name);
+ //
+ if (cxx_record_decl)
+ {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ if (omit_empty_base_classes)
+ {
+ if (BaseSpecifierIsEmpty (base_class))
+ continue;
+ }
+
+ // printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n", super_name, base_name,
+ // child_idx,
+ // base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString());
+ //
+ //
+ if (base_class == base_spec)
+ return child_idx;
+ ++child_idx;
+ }
+ }
+
+ return UINT32_MAX;
+}
+
+
+static uint32_t
+GetIndexForRecordChild (const RecordDecl *record_decl,
+ NamedDecl *canonical_decl,
+ bool omit_empty_base_classes)
+{
+ uint32_t child_idx = ClangASTContext::GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl),
+ omit_empty_base_classes);
+
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end();
+ field != field_end;
+ ++field, ++child_idx)
+ {
+ if (field->getCanonicalDecl() == canonical_decl)
+ return child_idx;
+ }
+
+ return UINT32_MAX;
+}
+
+// Look for a child member (doesn't include base classes, but it does include
+// their members) in the type hierarchy. Returns an index path into "clang_type"
+// on how to reach the appropriate member.
+//
+// class A
+// {
+// public:
+// int m_a;
+// int m_b;
+// };
+//
+// class B
+// {
+// };
+//
+// class C :
+// public B,
+// public A
+// {
+// };
+//
+// If we have a clang type that describes "class C", and we wanted to looked
+// "m_b" in it:
+//
+// With omit_empty_base_classes == false we would get an integer array back with:
+// { 1, 1 }
+// The first index 1 is the child index for "class A" within class C
+// The second index 1 is the child index for "m_b" within class A
+//
+// With omit_empty_base_classes == true we would get an integer array back with:
+// { 0, 1 }
+// The first index 0 is the child index for "class A" within class C (since class B doesn't have any members it doesn't count)
+// The second index 1 is the child index for "m_b" within class A
+
+size_t
+ClangASTType::GetIndexOfChildMemberWithName (const char *name,
+ bool omit_empty_base_classes,
+ std::vector<uint32_t>& child_indexes) const
+{
+ if (IsValid() && name && name[0])
+ {
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+
+ assert(record_decl);
+ uint32_t child_idx = 0;
+
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+
+ // Try and find a field that matches NAME
+ RecordDecl::field_iterator field, field_end;
+ StringRef name_sref(name);
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end();
+ field != field_end;
+ ++field, ++child_idx)
+ {
+ if (field->getName().equals (name_sref))
+ {
+ // We have to add on the number of base classes to this index!
+ child_indexes.push_back (child_idx + ClangASTContext::GetNumBaseClasses (cxx_record_decl, omit_empty_base_classes));
+ return child_indexes.size();
+ }
+ }
+
+ if (cxx_record_decl)
+ {
+ const RecordDecl *parent_record_decl = cxx_record_decl;
+
+ //printf ("parent = %s\n", parent_record_decl->getNameAsCString());
+
+ //const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl();
+ // Didn't find things easily, lets let clang do its thang...
+ IdentifierInfo & ident_ref = m_ast->Idents.get(name_sref);
+ DeclarationName decl_name(&ident_ref);
+
+ CXXBasePaths paths;
+ if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember,
+ decl_name.getAsOpaquePtr(),
+ paths))
+ {
+ CXXBasePaths::const_paths_iterator path, path_end = paths.end();
+ for (path = paths.begin(); path != path_end; ++path)
+ {
+ const size_t num_path_elements = path->size();
+ for (size_t e=0; e<num_path_elements; ++e)
+ {
+ CXXBasePathElement elem = (*path)[e];
+
+ child_idx = GetIndexForRecordBase (parent_record_decl, elem.Base, omit_empty_base_classes);
+ if (child_idx == UINT32_MAX)
+ {
+ child_indexes.clear();
+ return 0;
+ }
+ else
+ {
+ child_indexes.push_back (child_idx);
+ parent_record_decl = cast<RecordDecl>(elem.Base->getType()->getAs<RecordType>()->getDecl());
+ }
+ }
+ for (NamedDecl *path_decl : path->Decls)
+ {
+ child_idx = GetIndexForRecordChild (parent_record_decl, path_decl, omit_empty_base_classes);
+ if (child_idx == UINT32_MAX)
+ {
+ child_indexes.clear();
+ return 0;
+ }
+ else
+ {
+ child_indexes.push_back (child_idx);
+ }
+ }
+ }
+ return child_indexes.size();
+ }
+ }
+
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType ())
+ {
+ StringRef name_sref(name);
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ uint32_t child_idx = 0;
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+ ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+
+ for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx)
+ {
+ const ObjCIvarDecl* ivar_decl = *ivar_pos;
+
+ if (ivar_decl->getName().equals (name_sref))
+ {
+ if ((!omit_empty_base_classes && superclass_interface_decl) ||
+ ( omit_empty_base_classes && ObjCDeclHasIVars (superclass_interface_decl, true)))
+ ++child_idx;
+
+ child_indexes.push_back (child_idx);
+ return child_indexes.size();
+ }
+ }
+
+ if (superclass_interface_decl)
+ {
+ // The super class index is always zero for ObjC classes,
+ // so we push it onto the child indexes in case we find
+ // an ivar in our superclass...
+ child_indexes.push_back (0);
+
+ ClangASTType superclass_clang_type (m_ast, m_ast->getObjCInterfaceType(superclass_interface_decl));
+ if (superclass_clang_type.GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes))
+ {
+ // We did find an ivar in a superclass so just
+ // return the results!
+ return child_indexes.size();
+ }
+
+ // We didn't find an ivar matching "name" in our
+ // superclass, pop the superclass zero index that
+ // we pushed on above.
+ child_indexes.pop_back();
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ {
+ ClangASTType objc_object_clang_type (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
+ return objc_object_clang_type.GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+ }
+ break;
+
+
+ case clang::Type::ConstantArray:
+ {
+ // const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const uint64_t element_count = array->getSize().getLimitedValue();
+ //
+ // if (idx < element_count)
+ // {
+ // std::pair<uint64_t, unsigned> field_type_info = ast->getTypeInfo(array->getElementType());
+ //
+ // char element_name[32];
+ // ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx);
+ //
+ // child_name.assign(element_name);
+ // assert(field_type_info.first % 8 == 0);
+ // child_byte_size = field_type_info.first / 8;
+ // child_byte_offset = idx * child_byte_size;
+ // return array->getElementType().getAsOpaquePtr();
+ // }
+ }
+ break;
+
+ // case clang::Type::MemberPointerType:
+ // {
+ // MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
+ // QualType pointee_type = mem_ptr_type->getPointeeType();
+ //
+ // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ // {
+ // return GetIndexOfChildWithName (ast,
+ // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+ // name);
+ // }
+ // }
+ // break;
+ //
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ QualType pointee_type(reference_type->getPointeeType());
+ ClangASTType pointee_clang_type (m_ast, pointee_type);
+
+ if (pointee_clang_type.IsAggregateType ())
+ {
+ return pointee_clang_type.GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+ }
+ }
+ break;
+
+ case clang::Type::Pointer:
+ {
+ ClangASTType pointee_clang_type (GetPointeeType());
+
+ if (pointee_clang_type.IsAggregateType ())
+ {
+ return pointee_clang_type.GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildMemberWithName (name,
+ omit_empty_base_classes,
+ child_indexes);
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+
+// Get the index of the child of "clang_type" whose name matches. This function
+// doesn't descend into the children, but only looks one level deep and name
+// matches can include base class names.
+
+uint32_t
+ClangASTType::GetIndexOfChildWithName (const char *name, bool omit_empty_base_classes) const
+{
+ if (IsValid() && name && name[0])
+ {
+ QualType qual_type(GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+
+ assert(record_decl);
+ uint32_t child_idx = 0;
+
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+
+ if (cxx_record_decl)
+ {
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ // Skip empty base classes
+ CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+ if (omit_empty_base_classes && ClangASTContext::RecordHasFields(base_class_decl) == false)
+ continue;
+
+ ClangASTType base_class_clang_type (m_ast, base_class->getType());
+ std::string base_class_type_name (base_class_clang_type.GetTypeName());
+ if (base_class_type_name.compare (name) == 0)
+ return child_idx;
+ ++child_idx;
+ }
+ }
+
+ // Try and find a field that matches NAME
+ RecordDecl::field_iterator field, field_end;
+ StringRef name_sref(name);
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end();
+ field != field_end;
+ ++field, ++child_idx)
+ {
+ if (field->getName().equals (name_sref))
+ return child_idx;
+ }
+
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ if (GetCompleteType())
+ {
+ StringRef name_sref(name);
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ uint32_t child_idx = 0;
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+ ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
+ ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
+
+ for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx)
+ {
+ const ObjCIvarDecl* ivar_decl = *ivar_pos;
+
+ if (ivar_decl->getName().equals (name_sref))
+ {
+ if ((!omit_empty_base_classes && superclass_interface_decl) ||
+ ( omit_empty_base_classes && ObjCDeclHasIVars (superclass_interface_decl, true)))
+ ++child_idx;
+
+ return child_idx;
+ }
+ }
+
+ if (superclass_interface_decl)
+ {
+ if (superclass_interface_decl->getName().equals (name_sref))
+ return 0;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObjectPointer:
+ {
+ ClangASTType pointee_clang_type (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType());
+ return pointee_clang_type.GetIndexOfChildWithName (name, omit_empty_base_classes);
+ }
+ break;
+
+ case clang::Type::ConstantArray:
+ {
+ // const ConstantArrayType *array = cast<ConstantArrayType>(parent_qual_type.getTypePtr());
+ // const uint64_t element_count = array->getSize().getLimitedValue();
+ //
+ // if (idx < element_count)
+ // {
+ // std::pair<uint64_t, unsigned> field_type_info = ast->getTypeInfo(array->getElementType());
+ //
+ // char element_name[32];
+ // ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx);
+ //
+ // child_name.assign(element_name);
+ // assert(field_type_info.first % 8 == 0);
+ // child_byte_size = field_type_info.first / 8;
+ // child_byte_offset = idx * child_byte_size;
+ // return array->getElementType().getAsOpaquePtr();
+ // }
+ }
+ break;
+
+ // case clang::Type::MemberPointerType:
+ // {
+ // MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
+ // QualType pointee_type = mem_ptr_type->getPointeeType();
+ //
+ // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
+ // {
+ // return GetIndexOfChildWithName (ast,
+ // mem_ptr_type->getPointeeType().getAsOpaquePtr(),
+ // name);
+ // }
+ // }
+ // break;
+ //
+ case clang::Type::LValueReference:
+ case clang::Type::RValueReference:
+ {
+ const ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
+ ClangASTType pointee_type (m_ast, reference_type->getPointeeType());
+
+ if (pointee_type.IsAggregateType ())
+ {
+ return pointee_type.GetIndexOfChildWithName (name, omit_empty_base_classes);
+ }
+ }
+ break;
+
+ case clang::Type::Pointer:
+ {
+ const PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
+ ClangASTType pointee_type (m_ast, pointer_type->getPointeeType());
+
+ if (pointee_type.IsAggregateType ())
+ {
+ return pointee_type.GetIndexOfChildWithName (name, omit_empty_base_classes);
+ }
+ else
+ {
+ // if (parent_name)
+ // {
+ // child_name.assign(1, '*');
+ // child_name += parent_name;
+ // }
+ //
+ // // We have a pointer to an simple type
+ // if (idx == 0)
+ // {
+ // std::pair<uint64_t, unsigned> clang_type_info = ast->getTypeInfo(pointee_type);
+ // assert(clang_type_info.first % 8 == 0);
+ // child_byte_size = clang_type_info.first / 8;
+ // child_byte_offset = 0;
+ // return pointee_type.getAsOpaquePtr();
+ // }
+ }
+ }
+ break;
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<clang::ParenType>(qual_type)->desugar()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetIndexOfChildWithName (name, omit_empty_base_classes);
+
+ default:
+ break;
+ }
+ }
+ return UINT32_MAX;
+}
+
+
+size_t
+ClangASTType::GetNumTemplateArguments () const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ const ClassTemplateSpecializationDecl *template_decl = dyn_cast<ClassTemplateSpecializationDecl>(cxx_record_decl);
+ if (template_decl)
+ return template_decl->getTemplateArgs().size();
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetNumTemplateArguments();
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetNumTemplateArguments();
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetNumTemplateArguments();
+
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+ClangASTType
+ClangASTType::GetTemplateArgument (size_t arg_idx, lldb::TemplateArgumentKind &kind) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ const ClassTemplateSpecializationDecl *template_decl = dyn_cast<ClassTemplateSpecializationDecl>(cxx_record_decl);
+ if (template_decl && arg_idx < template_decl->getTemplateArgs().size())
+ {
+ const TemplateArgument &template_arg = template_decl->getTemplateArgs()[arg_idx];
+ switch (template_arg.getKind())
+ {
+ case clang::TemplateArgument::Null:
+ kind = eTemplateArgumentKindNull;
+ return ClangASTType();
+
+ case clang::TemplateArgument::Type:
+ kind = eTemplateArgumentKindType;
+ return ClangASTType(m_ast, template_arg.getAsType());
+
+ case clang::TemplateArgument::Declaration:
+ kind = eTemplateArgumentKindDeclaration;
+ return ClangASTType();
+
+ case clang::TemplateArgument::Integral:
+ kind = eTemplateArgumentKindIntegral;
+ return ClangASTType(m_ast, template_arg.getIntegralType());
+
+ case clang::TemplateArgument::Template:
+ kind = eTemplateArgumentKindTemplate;
+ return ClangASTType();
+
+ case clang::TemplateArgument::TemplateExpansion:
+ kind = eTemplateArgumentKindTemplateExpansion;
+ return ClangASTType();
+
+ case clang::TemplateArgument::Expression:
+ kind = eTemplateArgumentKindExpression;
+ return ClangASTType();
+
+ case clang::TemplateArgument::Pack:
+ kind = eTemplateArgumentKindPack;
+ return ClangASTType();
+
+ default:
+ assert (!"Unhandled TemplateArgument::ArgKind");
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetTemplateArgument (arg_idx, kind);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetTemplateArgument (arg_idx, kind);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetTemplateArgument (arg_idx, kind);
+
+ default:
+ break;
+ }
+ }
+ kind = eTemplateArgumentKindNull;
+ return ClangASTType ();
+}
+
+static bool
+IsOperator (const char *name, OverloadedOperatorKind &op_kind)
+{
+ if (name == NULL || name[0] == '\0')
+ return false;
+
+#define OPERATOR_PREFIX "operator"
+#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1)
+
+ const char *post_op_name = NULL;
+
+ bool no_space = true;
+
+ if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH))
+ return false;
+
+ post_op_name = name + OPERATOR_PREFIX_LENGTH;
+
+ if (post_op_name[0] == ' ')
+ {
+ post_op_name++;
+ no_space = false;
+ }
+
+#undef OPERATOR_PREFIX
+#undef OPERATOR_PREFIX_LENGTH
+
+ // This is an operator, set the overloaded operator kind to invalid
+ // in case this is a conversion operator...
+ op_kind = NUM_OVERLOADED_OPERATORS;
+
+ switch (post_op_name[0])
+ {
+ default:
+ if (no_space)
+ return false;
+ break;
+ case 'n':
+ if (no_space)
+ return false;
+ if (strcmp (post_op_name, "new") == 0)
+ op_kind = OO_New;
+ else if (strcmp (post_op_name, "new[]") == 0)
+ op_kind = OO_Array_New;
+ break;
+
+ case 'd':
+ if (no_space)
+ return false;
+ if (strcmp (post_op_name, "delete") == 0)
+ op_kind = OO_Delete;
+ else if (strcmp (post_op_name, "delete[]") == 0)
+ op_kind = OO_Array_Delete;
+ break;
+
+ case '+':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Plus;
+ else if (post_op_name[2] == '\0')
+ {
+ if (post_op_name[1] == '=')
+ op_kind = OO_PlusEqual;
+ else if (post_op_name[1] == '+')
+ op_kind = OO_PlusPlus;
+ }
+ break;
+
+ case '-':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Minus;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_MinusEqual; break;
+ case '-': op_kind = OO_MinusMinus; break;
+ case '>': op_kind = OO_Arrow; break;
+ }
+ }
+ else if (post_op_name[3] == '\0')
+ {
+ if (post_op_name[2] == '*')
+ op_kind = OO_ArrowStar; break;
+ }
+ break;
+
+ case '*':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Star;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_StarEqual;
+ break;
+
+ case '/':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Slash;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_SlashEqual;
+ break;
+
+ case '%':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Percent;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_PercentEqual;
+ break;
+
+
+ case '^':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Caret;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_CaretEqual;
+ break;
+
+ case '&':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Amp;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_AmpEqual; break;
+ case '&': op_kind = OO_AmpAmp; break;
+ }
+ }
+ break;
+
+ case '|':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Pipe;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '=': op_kind = OO_PipeEqual; break;
+ case '|': op_kind = OO_PipePipe; break;
+ }
+ }
+ break;
+
+ case '~':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Tilde;
+ break;
+
+ case '!':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Exclaim;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_ExclaimEqual;
+ break;
+
+ case '=':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Equal;
+ else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
+ op_kind = OO_EqualEqual;
+ break;
+
+ case '<':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Less;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '<': op_kind = OO_LessLess; break;
+ case '=': op_kind = OO_LessEqual; break;
+ }
+ }
+ else if (post_op_name[3] == '\0')
+ {
+ if (post_op_name[2] == '=')
+ op_kind = OO_LessLessEqual;
+ }
+ break;
+
+ case '>':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Greater;
+ else if (post_op_name[2] == '\0')
+ {
+ switch (post_op_name[1])
+ {
+ case '>': op_kind = OO_GreaterGreater; break;
+ case '=': op_kind = OO_GreaterEqual; break;
+ }
+ }
+ else if (post_op_name[1] == '>' &&
+ post_op_name[2] == '=' &&
+ post_op_name[3] == '\0')
+ {
+ op_kind = OO_GreaterGreaterEqual;
+ }
+ break;
+
+ case ',':
+ if (post_op_name[1] == '\0')
+ op_kind = OO_Comma;
+ break;
+
+ case '(':
+ if (post_op_name[1] == ')' && post_op_name[2] == '\0')
+ op_kind = OO_Call;
+ break;
+
+ case '[':
+ if (post_op_name[1] == ']' && post_op_name[2] == '\0')
+ op_kind = OO_Subscript;
+ break;
+ }
+
+ return true;
+}
+
+static inline bool
+check_op_param (uint32_t op_kind, bool unary, bool binary, uint32_t num_params)
+{
+ // Special-case call since it can take any number of operands
+ if(op_kind == OO_Call)
+ return true;
+
+ // The parameter count doens't include "this"
+ if (num_params == 0)
+ return unary;
+ if (num_params == 1)
+ return binary;
+ else
+ return false;
+}
+
+clang::RecordDecl *
+ClangASTType::GetAsRecordDecl () const
+{
+ const RecordType *record_type = dyn_cast<RecordType>(GetCanonicalQualType());
+ if (record_type)
+ return record_type->getDecl();
+ return NULL;
+}
+
+clang::CXXRecordDecl *
+ClangASTType::GetAsCXXRecordDecl () const
+{
+ return GetCanonicalQualType()->getAsCXXRecordDecl();
+}
+
+ObjCInterfaceDecl *
+ClangASTType::GetAsObjCInterfaceDecl () const
+{
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(GetCanonicalQualType());
+ if (objc_class_type)
+ return objc_class_type->getInterface();
+ return NULL;
+}
+
+clang::FieldDecl *
+ClangASTType::AddFieldToRecordType (const char *name,
+ const ClangASTType &field_clang_type,
+ AccessType access,
+ uint32_t bitfield_bit_size)
+{
+ if (!IsValid() || !field_clang_type.IsValid())
+ return NULL;
+
+ FieldDecl *field = NULL;
+
+ clang::Expr *bit_width = NULL;
+ if (bitfield_bit_size != 0)
+ {
+ APInt bitfield_bit_size_apint(m_ast->getTypeSize(m_ast->IntTy), bitfield_bit_size);
+ bit_width = new (*m_ast)IntegerLiteral (*m_ast, bitfield_bit_size_apint, m_ast->IntTy, SourceLocation());
+ }
+
+ RecordDecl *record_decl = GetAsRecordDecl ();
+ if (record_decl)
+ {
+ field = FieldDecl::Create (*m_ast,
+ record_decl,
+ SourceLocation(),
+ SourceLocation(),
+ name ? &m_ast->Idents.get(name) : NULL, // Identifier
+ field_clang_type.GetQualType(), // Field type
+ NULL, // TInfo *
+ bit_width, // BitWidth
+ false, // Mutable
+ ICIS_NoInit); // HasInit
+
+ if (!name)
+ {
+ // Determine whether this field corresponds to an anonymous
+ // struct or union.
+ if (const TagType *TagT = field->getType()->getAs<TagType>()) {
+ if (RecordDecl *Rec = dyn_cast<RecordDecl>(TagT->getDecl()))
+ if (!Rec->getDeclName()) {
+ Rec->setAnonymousStructOrUnion(true);
+ field->setImplicit();
+
+ }
+ }
+ }
+
+ if (field)
+ {
+ field->setAccess (ClangASTContext::ConvertAccessTypeToAccessSpecifier (access));
+
+ record_decl->addDecl(field);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(field);
+#endif
+ }
+ }
+ else
+ {
+ ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+
+ if (class_interface_decl)
+ {
+ const bool is_synthesized = false;
+
+ field_clang_type.GetCompleteType();
+
+ field = ObjCIvarDecl::Create (*m_ast,
+ class_interface_decl,
+ SourceLocation(),
+ SourceLocation(),
+ name ? &m_ast->Idents.get(name) : NULL, // Identifier
+ field_clang_type.GetQualType(), // Field type
+ NULL, // TypeSourceInfo *
+ ConvertAccessTypeToObjCIvarAccessControl (access),
+ bit_width,
+ is_synthesized);
+
+ if (field)
+ {
+ class_interface_decl->addDecl(field);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(field);
+#endif
+ }
+ }
+ }
+ return field;
+}
+
+void
+ClangASTType::BuildIndirectFields ()
+{
+ RecordDecl *record_decl = GetAsRecordDecl();
+
+ if (!record_decl)
+ return;
+
+ typedef llvm::SmallVector <IndirectFieldDecl *, 1> IndirectFieldVector;
+
+ IndirectFieldVector indirect_fields;
+ RecordDecl::field_iterator field_pos;
+ RecordDecl::field_iterator field_end_pos = record_decl->field_end();
+ RecordDecl::field_iterator last_field_pos = field_end_pos;
+ for (field_pos = record_decl->field_begin(); field_pos != field_end_pos; last_field_pos = field_pos++)
+ {
+ if (field_pos->isAnonymousStructOrUnion())
+ {
+ QualType field_qual_type = field_pos->getType();
+
+ const RecordType *field_record_type = field_qual_type->getAs<RecordType>();
+
+ if (!field_record_type)
+ continue;
+
+ RecordDecl *field_record_decl = field_record_type->getDecl();
+
+ if (!field_record_decl)
+ continue;
+
+ for (RecordDecl::decl_iterator di = field_record_decl->decls_begin(), de = field_record_decl->decls_end();
+ di != de;
+ ++di)
+ {
+ if (FieldDecl *nested_field_decl = dyn_cast<FieldDecl>(*di))
+ {
+ NamedDecl **chain = new (*m_ast) NamedDecl*[2];
+ chain[0] = *field_pos;
+ chain[1] = nested_field_decl;
+ IndirectFieldDecl *indirect_field = IndirectFieldDecl::Create(*m_ast,
+ record_decl,
+ SourceLocation(),
+ nested_field_decl->getIdentifier(),
+ nested_field_decl->getType(),
+ chain,
+ 2);
+
+ indirect_field->setImplicit();
+
+ indirect_field->setAccess(ClangASTContext::UnifyAccessSpecifiers(field_pos->getAccess(),
+ nested_field_decl->getAccess()));
+
+ indirect_fields.push_back(indirect_field);
+ }
+ else if (IndirectFieldDecl *nested_indirect_field_decl = dyn_cast<IndirectFieldDecl>(*di))
+ {
+ int nested_chain_size = nested_indirect_field_decl->getChainingSize();
+ NamedDecl **chain = new (*m_ast) NamedDecl*[nested_chain_size + 1];
+ chain[0] = *field_pos;
+
+ int chain_index = 1;
+ for (IndirectFieldDecl::chain_iterator nci = nested_indirect_field_decl->chain_begin(),
+ nce = nested_indirect_field_decl->chain_end();
+ nci < nce;
+ ++nci)
+ {
+ chain[chain_index] = *nci;
+ chain_index++;
+ }
+
+ IndirectFieldDecl *indirect_field = IndirectFieldDecl::Create(*m_ast,
+ record_decl,
+ SourceLocation(),
+ nested_indirect_field_decl->getIdentifier(),
+ nested_indirect_field_decl->getType(),
+ chain,
+ nested_chain_size + 1);
+
+ indirect_field->setImplicit();
+
+ indirect_field->setAccess(ClangASTContext::UnifyAccessSpecifiers(field_pos->getAccess(),
+ nested_indirect_field_decl->getAccess()));
+
+ indirect_fields.push_back(indirect_field);
+ }
+ }
+ }
+ }
+
+ // Check the last field to see if it has an incomplete array type as its
+ // last member and if it does, the tell the record decl about it
+ if (last_field_pos != field_end_pos)
+ {
+ if (last_field_pos->getType()->isIncompleteArrayType())
+ record_decl->hasFlexibleArrayMember();
+ }
+
+ for (IndirectFieldVector::iterator ifi = indirect_fields.begin(), ife = indirect_fields.end();
+ ifi < ife;
+ ++ifi)
+ {
+ record_decl->addDecl(*ifi);
+ }
+}
+
+clang::VarDecl *
+ClangASTType::AddVariableToRecordType (const char *name,
+ const ClangASTType &var_type,
+ AccessType access)
+{
+ clang::VarDecl *var_decl = NULL;
+
+ if (!IsValid() || !var_type.IsValid())
+ return NULL;
+
+ RecordDecl *record_decl = GetAsRecordDecl ();
+ if (record_decl)
+ {
+ var_decl = VarDecl::Create (*m_ast, // ASTContext &
+ record_decl, // DeclContext *
+ SourceLocation(), // SourceLocation StartLoc
+ SourceLocation(), // SourceLocation IdLoc
+ name ? &m_ast->Idents.get(name) : NULL, // IdentifierInfo *
+ var_type.GetQualType(), // Variable QualType
+ NULL, // TypeSourceInfo *
+ SC_Static); // StorageClass
+ if (var_decl)
+ {
+ var_decl->setAccess(ClangASTContext::ConvertAccessTypeToAccessSpecifier (access));
+ record_decl->addDecl(var_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(var_decl);
+#endif
+ }
+ }
+ return var_decl;
+}
+
+
+CXXMethodDecl *
+ClangASTType::AddMethodToCXXRecordType (const char *name,
+ const ClangASTType &method_clang_type,
+ lldb::AccessType access,
+ bool is_virtual,
+ bool is_static,
+ bool is_inline,
+ bool is_explicit,
+ bool is_attr_used,
+ bool is_artificial)
+{
+ if (!IsValid() || !method_clang_type.IsValid() || name == NULL || name[0] == '\0')
+ return NULL;
+
+ QualType record_qual_type(GetCanonicalQualType());
+
+ CXXRecordDecl *cxx_record_decl = record_qual_type->getAsCXXRecordDecl();
+
+ if (cxx_record_decl == NULL)
+ return NULL;
+
+ QualType method_qual_type (method_clang_type.GetQualType());
+
+ CXXMethodDecl *cxx_method_decl = NULL;
+
+ DeclarationName decl_name (&m_ast->Idents.get(name));
+
+ const clang::FunctionType *function_type = dyn_cast<FunctionType>(method_qual_type.getTypePtr());
+
+ if (function_type == NULL)
+ return NULL;
+
+ const FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(function_type));
+
+ if (!method_function_prototype)
+ return NULL;
+
+ unsigned int num_params = method_function_prototype->getNumArgs();
+
+ CXXDestructorDecl *cxx_dtor_decl(NULL);
+ CXXConstructorDecl *cxx_ctor_decl(NULL);
+
+ if (is_artificial)
+ return NULL; // skip everything artificial
+
+ if (name[0] == '~')
+ {
+ cxx_dtor_decl = CXXDestructorDecl::Create (*m_ast,
+ cxx_record_decl,
+ SourceLocation(),
+ DeclarationNameInfo (m_ast->DeclarationNames.getCXXDestructorName (m_ast->getCanonicalType (record_qual_type)), SourceLocation()),
+ method_qual_type,
+ NULL,
+ is_inline,
+ is_artificial);
+ cxx_method_decl = cxx_dtor_decl;
+ }
+ else if (decl_name == cxx_record_decl->getDeclName())
+ {
+ cxx_ctor_decl = CXXConstructorDecl::Create (*m_ast,
+ cxx_record_decl,
+ SourceLocation(),
+ DeclarationNameInfo (m_ast->DeclarationNames.getCXXConstructorName (m_ast->getCanonicalType (record_qual_type)), SourceLocation()),
+ method_qual_type,
+ NULL, // TypeSourceInfo *
+ is_explicit,
+ is_inline,
+ is_artificial,
+ false /*is_constexpr*/);
+ cxx_method_decl = cxx_ctor_decl;
+ }
+ else
+ {
+ clang::StorageClass SC = is_static ? SC_Static : SC_None;
+ OverloadedOperatorKind op_kind = NUM_OVERLOADED_OPERATORS;
+
+ if (IsOperator (name, op_kind))
+ {
+ if (op_kind != NUM_OVERLOADED_OPERATORS)
+ {
+ // Check the number of operator parameters. Sometimes we have
+ // seen bad DWARF that doesn't correctly describe operators and
+ // if we try to create a methed and add it to the class, clang
+ // will assert and crash, so we need to make sure things are
+ // acceptable.
+ if (!ClangASTContext::CheckOverloadedOperatorKindParameterCount (op_kind, num_params))
+ return NULL;
+ cxx_method_decl = CXXMethodDecl::Create (*m_ast,
+ cxx_record_decl,
+ SourceLocation(),
+ DeclarationNameInfo (m_ast->DeclarationNames.getCXXOperatorName (op_kind), SourceLocation()),
+ method_qual_type,
+ NULL, // TypeSourceInfo *
+ SC,
+ is_inline,
+ false /*is_constexpr*/,
+ SourceLocation());
+ }
+ else if (num_params == 0)
+ {
+ // Conversion operators don't take params...
+ cxx_method_decl = CXXConversionDecl::Create (*m_ast,
+ cxx_record_decl,
+ SourceLocation(),
+ DeclarationNameInfo (m_ast->DeclarationNames.getCXXConversionFunctionName (m_ast->getCanonicalType (function_type->getResultType())), SourceLocation()),
+ method_qual_type,
+ NULL, // TypeSourceInfo *
+ is_inline,
+ is_explicit,
+ false /*is_constexpr*/,
+ SourceLocation());
+ }
+ }
+
+ if (cxx_method_decl == NULL)
+ {
+ cxx_method_decl = CXXMethodDecl::Create (*m_ast,
+ cxx_record_decl,
+ SourceLocation(),
+ DeclarationNameInfo (decl_name, SourceLocation()),
+ method_qual_type,
+ NULL, // TypeSourceInfo *
+ SC,
+ is_inline,
+ false /*is_constexpr*/,
+ SourceLocation());
+ }
+ }
+
+ AccessSpecifier access_specifier = ClangASTContext::ConvertAccessTypeToAccessSpecifier (access);
+
+ cxx_method_decl->setAccess (access_specifier);
+ cxx_method_decl->setVirtualAsWritten (is_virtual);
+
+ if (is_attr_used)
+ cxx_method_decl->addAttr(::new (*m_ast) UsedAttr(SourceRange(), *m_ast));
+
+ // Populate the method decl with parameter decls
+
+ llvm::SmallVector<ParmVarDecl *, 12> params;
+
+ for (unsigned param_index = 0;
+ param_index < num_params;
+ ++param_index)
+ {
+ params.push_back (ParmVarDecl::Create (*m_ast,
+ cxx_method_decl,
+ SourceLocation(),
+ SourceLocation(),
+ NULL, // anonymous
+ method_function_prototype->getArgType(param_index),
+ NULL,
+ SC_None,
+ NULL));
+ }
+
+ cxx_method_decl->setParams (ArrayRef<ParmVarDecl*>(params));
+
+ cxx_record_decl->addDecl (cxx_method_decl);
+
+ // Sometimes the debug info will mention a constructor (default/copy/move),
+ // destructor, or assignment operator (copy/move) but there won't be any
+ // version of this in the code. So we check if the function was artificially
+ // generated and if it is trivial and this lets the compiler/backend know
+ // that it can inline the IR for these when it needs to and we can avoid a
+ // "missing function" error when running expressions.
+
+ if (is_artificial)
+ {
+ if (cxx_ctor_decl &&
+ ((cxx_ctor_decl->isDefaultConstructor() && cxx_record_decl->hasTrivialDefaultConstructor ()) ||
+ (cxx_ctor_decl->isCopyConstructor() && cxx_record_decl->hasTrivialCopyConstructor ()) ||
+ (cxx_ctor_decl->isMoveConstructor() && cxx_record_decl->hasTrivialMoveConstructor ()) ))
+ {
+ cxx_ctor_decl->setDefaulted();
+ cxx_ctor_decl->setTrivial(true);
+ }
+ else if (cxx_dtor_decl)
+ {
+ if (cxx_record_decl->hasTrivialDestructor())
+ {
+ cxx_dtor_decl->setDefaulted();
+ cxx_dtor_decl->setTrivial(true);
+ }
+ }
+ else if ((cxx_method_decl->isCopyAssignmentOperator() && cxx_record_decl->hasTrivialCopyAssignment()) ||
+ (cxx_method_decl->isMoveAssignmentOperator() && cxx_record_decl->hasTrivialMoveAssignment()))
+ {
+ cxx_method_decl->setDefaulted();
+ cxx_method_decl->setTrivial(true);
+ }
+ }
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(cxx_method_decl);
+#endif
+
+ // printf ("decl->isPolymorphic() = %i\n", cxx_record_decl->isPolymorphic());
+ // printf ("decl->isAggregate() = %i\n", cxx_record_decl->isAggregate());
+ // printf ("decl->isPOD() = %i\n", cxx_record_decl->isPOD());
+ // printf ("decl->isEmpty() = %i\n", cxx_record_decl->isEmpty());
+ // printf ("decl->isAbstract() = %i\n", cxx_record_decl->isAbstract());
+ // printf ("decl->hasTrivialConstructor() = %i\n", cxx_record_decl->hasTrivialConstructor());
+ // printf ("decl->hasTrivialCopyConstructor() = %i\n", cxx_record_decl->hasTrivialCopyConstructor());
+ // printf ("decl->hasTrivialCopyAssignment() = %i\n", cxx_record_decl->hasTrivialCopyAssignment());
+ // printf ("decl->hasTrivialDestructor() = %i\n", cxx_record_decl->hasTrivialDestructor());
+ return cxx_method_decl;
+}
+
+
+#pragma mark C++ Base Classes
+
+CXXBaseSpecifier *
+ClangASTType::CreateBaseClassSpecifier (AccessType access, bool is_virtual, bool base_of_class)
+{
+ if (IsValid())
+ return new CXXBaseSpecifier (SourceRange(),
+ is_virtual,
+ base_of_class,
+ ClangASTContext::ConvertAccessTypeToAccessSpecifier (access),
+ m_ast->getTrivialTypeSourceInfo (GetQualType()),
+ SourceLocation());
+ return NULL;
+}
+
+void
+ClangASTType::DeleteBaseClassSpecifiers (CXXBaseSpecifier **base_classes, unsigned num_base_classes)
+{
+ for (unsigned i=0; i<num_base_classes; ++i)
+ {
+ delete base_classes[i];
+ base_classes[i] = NULL;
+ }
+}
+
+bool
+ClangASTType::SetBaseClassesForClassType (CXXBaseSpecifier const * const *base_classes,
+ unsigned num_base_classes)
+{
+ if (IsValid())
+ {
+ CXXRecordDecl *cxx_record_decl = GetAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ cxx_record_decl->setBases(base_classes, num_base_classes);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::SetObjCSuperClass (const ClangASTType &superclass_clang_type)
+{
+ if (IsValid() && superclass_clang_type.IsValid())
+ {
+ ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ ObjCInterfaceDecl *super_interface_decl = superclass_clang_type.GetAsObjCInterfaceDecl ();
+ if (class_interface_decl && super_interface_decl)
+ {
+ class_interface_decl->setSuperClass(super_interface_decl);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::AddObjCClassProperty (const char *property_name,
+ const ClangASTType &property_clang_type,
+ ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name,
+ const char *property_getter_name,
+ uint32_t property_attributes,
+ ClangASTMetadata *metadata)
+{
+ if (!IsValid() || !property_clang_type.IsValid() || property_name == NULL || property_name[0] == '\0')
+ return false;
+
+ ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+
+ if (class_interface_decl)
+ {
+ ClangASTType property_clang_type_to_access;
+
+ if (property_clang_type.IsValid())
+ property_clang_type_to_access = property_clang_type;
+ else if (ivar_decl)
+ property_clang_type_to_access = ClangASTType (m_ast, ivar_decl->getType());
+
+ if (class_interface_decl && property_clang_type_to_access.IsValid())
+ {
+ clang::TypeSourceInfo *prop_type_source;
+ if (ivar_decl)
+ prop_type_source = m_ast->getTrivialTypeSourceInfo (ivar_decl->getType());
+ else
+ prop_type_source = m_ast->getTrivialTypeSourceInfo (property_clang_type.GetQualType());
+
+ ObjCPropertyDecl *property_decl = ObjCPropertyDecl::Create (*m_ast,
+ class_interface_decl,
+ SourceLocation(), // Source Location
+ &m_ast->Idents.get(property_name),
+ SourceLocation(), //Source Location for AT
+ SourceLocation(), //Source location for (
+ prop_type_source);
+
+ if (property_decl)
+ {
+ if (metadata)
+ ClangASTContext::SetMetadata(m_ast, property_decl, *metadata);
+
+ class_interface_decl->addDecl (property_decl);
+
+ Selector setter_sel, getter_sel;
+
+ if (property_setter_name != NULL)
+ {
+ std::string property_setter_no_colon(property_setter_name, strlen(property_setter_name) - 1);
+ clang::IdentifierInfo *setter_ident = &m_ast->Idents.get(property_setter_no_colon.c_str());
+ setter_sel = m_ast->Selectors.getSelector(1, &setter_ident);
+ }
+ else if (!(property_attributes & DW_APPLE_PROPERTY_readonly))
+ {
+ std::string setter_sel_string("set");
+ setter_sel_string.push_back(::toupper(property_name[0]));
+ setter_sel_string.append(&property_name[1]);
+ clang::IdentifierInfo *setter_ident = &m_ast->Idents.get(setter_sel_string.c_str());
+ setter_sel = m_ast->Selectors.getSelector(1, &setter_ident);
+ }
+ property_decl->setSetterName(setter_sel);
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_setter);
+
+ if (property_getter_name != NULL)
+ {
+ clang::IdentifierInfo *getter_ident = &m_ast->Idents.get(property_getter_name);
+ getter_sel = m_ast->Selectors.getSelector(0, &getter_ident);
+ }
+ else
+ {
+ clang::IdentifierInfo *getter_ident = &m_ast->Idents.get(property_name);
+ getter_sel = m_ast->Selectors.getSelector(0, &getter_ident);
+ }
+ property_decl->setGetterName(getter_sel);
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_getter);
+
+ if (ivar_decl)
+ property_decl->setPropertyIvarDecl (ivar_decl);
+
+ if (property_attributes & DW_APPLE_PROPERTY_readonly)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_readonly);
+ if (property_attributes & DW_APPLE_PROPERTY_readwrite)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_readwrite);
+ if (property_attributes & DW_APPLE_PROPERTY_assign)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_assign);
+ if (property_attributes & DW_APPLE_PROPERTY_retain)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_retain);
+ if (property_attributes & DW_APPLE_PROPERTY_copy)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_copy);
+ if (property_attributes & DW_APPLE_PROPERTY_nonatomic)
+ property_decl->setPropertyAttributes (clang::ObjCPropertyDecl::OBJC_PR_nonatomic);
+
+ if (!getter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(getter_sel))
+ {
+ const bool isInstance = true;
+ const bool isVariadic = false;
+ const bool isSynthesized = false;
+ const bool isImplicitlyDeclared = true;
+ const bool isDefined = false;
+ const ObjCMethodDecl::ImplementationControl impControl = ObjCMethodDecl::None;
+ const bool HasRelatedResultType = false;
+
+ ObjCMethodDecl *getter = ObjCMethodDecl::Create (*m_ast,
+ SourceLocation(),
+ SourceLocation(),
+ getter_sel,
+ property_clang_type_to_access.GetQualType(),
+ NULL,
+ class_interface_decl,
+ isInstance,
+ isVariadic,
+ isSynthesized,
+ isImplicitlyDeclared,
+ isDefined,
+ impControl,
+ HasRelatedResultType);
+
+ if (getter && metadata)
+ ClangASTContext::SetMetadata(m_ast, getter, *metadata);
+
+ getter->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(), ArrayRef<SourceLocation>());
+
+ class_interface_decl->addDecl(getter);
+ }
+
+ if (!setter_sel.isNull() && !class_interface_decl->lookupInstanceMethod(setter_sel))
+ {
+ QualType result_type = m_ast->VoidTy;
+
+ const bool isInstance = true;
+ const bool isVariadic = false;
+ const bool isSynthesized = false;
+ const bool isImplicitlyDeclared = true;
+ const bool isDefined = false;
+ const ObjCMethodDecl::ImplementationControl impControl = ObjCMethodDecl::None;
+ const bool HasRelatedResultType = false;
+
+ ObjCMethodDecl *setter = ObjCMethodDecl::Create (*m_ast,
+ SourceLocation(),
+ SourceLocation(),
+ setter_sel,
+ result_type,
+ NULL,
+ class_interface_decl,
+ isInstance,
+ isVariadic,
+ isSynthesized,
+ isImplicitlyDeclared,
+ isDefined,
+ impControl,
+ HasRelatedResultType);
+
+ if (setter && metadata)
+ ClangASTContext::SetMetadata(m_ast, setter, *metadata);
+
+ llvm::SmallVector<ParmVarDecl *, 1> params;
+
+ params.push_back (ParmVarDecl::Create (*m_ast,
+ setter,
+ SourceLocation(),
+ SourceLocation(),
+ NULL, // anonymous
+ property_clang_type_to_access.GetQualType(),
+ NULL,
+ SC_Auto,
+ NULL));
+
+ setter->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(params), ArrayRef<SourceLocation>());
+
+ class_interface_decl->addDecl(setter);
+ }
+
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::IsObjCClassTypeAndHasIVars (bool check_superclass) const
+{
+ ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl ();
+ if (class_interface_decl)
+ return ObjCDeclHasIVars (class_interface_decl, check_superclass);
+ return false;
+}
+
+
+ObjCMethodDecl *
+ClangASTType::AddMethodToObjCObjectType (const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]")
+ const ClangASTType &method_clang_type,
+ lldb::AccessType access,
+ bool is_artificial)
+{
+ if (!IsValid() || !method_clang_type.IsValid())
+ return NULL;
+
+ ObjCInterfaceDecl *class_interface_decl = GetAsObjCInterfaceDecl();
+
+ if (class_interface_decl == NULL)
+ return NULL;
+
+ const char *selector_start = ::strchr (name, ' ');
+ if (selector_start == NULL)
+ return NULL;
+
+ selector_start++;
+ llvm::SmallVector<IdentifierInfo *, 12> selector_idents;
+
+ size_t len = 0;
+ const char *start;
+ //printf ("name = '%s'\n", name);
+
+ unsigned num_selectors_with_args = 0;
+ for (start = selector_start;
+ start && *start != '\0' && *start != ']';
+ start += len)
+ {
+ len = ::strcspn(start, ":]");
+ bool has_arg = (start[len] == ':');
+ if (has_arg)
+ ++num_selectors_with_args;
+ selector_idents.push_back (&m_ast->Idents.get (StringRef (start, len)));
+ if (has_arg)
+ len += 1;
+ }
+
+
+ if (selector_idents.size() == 0)
+ return 0;
+
+ clang::Selector method_selector = m_ast->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0,
+ selector_idents.data());
+
+ QualType method_qual_type (method_clang_type.GetQualType());
+
+ // Populate the method decl with parameter decls
+ const clang::Type *method_type(method_qual_type.getTypePtr());
+
+ if (method_type == NULL)
+ return NULL;
+
+ const FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(method_type));
+
+ if (!method_function_prototype)
+ return NULL;
+
+
+ bool is_variadic = false;
+ bool is_synthesized = false;
+ bool is_defined = false;
+ ObjCMethodDecl::ImplementationControl imp_control = ObjCMethodDecl::None;
+
+ const unsigned num_args = method_function_prototype->getNumArgs();
+
+ if (num_args != num_selectors_with_args)
+ return NULL; // some debug information is corrupt. We are not going to deal with it.
+
+ ObjCMethodDecl *objc_method_decl = ObjCMethodDecl::Create (*m_ast,
+ SourceLocation(), // beginLoc,
+ SourceLocation(), // endLoc,
+ method_selector,
+ method_function_prototype->getResultType(),
+ NULL, // TypeSourceInfo *ResultTInfo,
+ GetDeclContextForType (),
+ name[0] == '-',
+ is_variadic,
+ is_synthesized,
+ true, // is_implicitly_declared; we force this to true because we don't have source locations
+ is_defined,
+ imp_control,
+ false /*has_related_result_type*/);
+
+
+ if (objc_method_decl == NULL)
+ return NULL;
+
+ if (num_args > 0)
+ {
+ llvm::SmallVector<ParmVarDecl *, 12> params;
+
+ for (unsigned param_index = 0; param_index < num_args; ++param_index)
+ {
+ params.push_back (ParmVarDecl::Create (*m_ast,
+ objc_method_decl,
+ SourceLocation(),
+ SourceLocation(),
+ NULL, // anonymous
+ method_function_prototype->getArgType(param_index),
+ NULL,
+ SC_Auto,
+ NULL));
+ }
+
+ objc_method_decl->setMethodParams(*m_ast, ArrayRef<ParmVarDecl*>(params), ArrayRef<SourceLocation>());
+ }
+
+ class_interface_decl->addDecl (objc_method_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(objc_method_decl);
+#endif
+
+ return objc_method_decl;
+}
+
+
+clang::DeclContext *
+ClangASTType::GetDeclContextForType () const
+{
+ if (!IsValid())
+ return NULL;
+
+ QualType qual_type(GetCanonicalQualType());
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::UnaryTransform: break;
+ case clang::Type::FunctionNoProto: break;
+ case clang::Type::FunctionProto: break;
+ case clang::Type::IncompleteArray: break;
+ case clang::Type::VariableArray: break;
+ case clang::Type::ConstantArray: break;
+ case clang::Type::DependentSizedArray: break;
+ case clang::Type::ExtVector: break;
+ case clang::Type::DependentSizedExtVector: break;
+ case clang::Type::Vector: break;
+ case clang::Type::Builtin: break;
+ case clang::Type::BlockPointer: break;
+ case clang::Type::Pointer: break;
+ case clang::Type::LValueReference: break;
+ case clang::Type::RValueReference: break;
+ case clang::Type::MemberPointer: break;
+ case clang::Type::Complex: break;
+ case clang::Type::ObjCObject: break;
+ case clang::Type::ObjCInterface: return cast<ObjCObjectType>(qual_type.getTypePtr())->getInterface();
+ case clang::Type::ObjCObjectPointer: return ClangASTType (m_ast, cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType()).GetDeclContextForType();
+ case clang::Type::Record: return cast<RecordType>(qual_type)->getDecl();
+ case clang::Type::Enum: return cast<EnumType>(qual_type)->getDecl();
+ case clang::Type::Typedef: return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).GetDeclContextForType();
+ case clang::Type::Elaborated: return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).GetDeclContextForType();
+ case clang::Type::Paren: return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).GetDeclContextForType();
+ case clang::Type::TypeOfExpr: break;
+ case clang::Type::TypeOf: break;
+ case clang::Type::Decltype: break;
+ //case clang::Type::QualifiedName: break;
+ case clang::Type::TemplateSpecialization: break;
+ case clang::Type::DependentTemplateSpecialization: break;
+ case clang::Type::TemplateTypeParm: break;
+ case clang::Type::SubstTemplateTypeParm: break;
+ case clang::Type::SubstTemplateTypeParmPack:break;
+ case clang::Type::PackExpansion: break;
+ case clang::Type::UnresolvedUsing: break;
+ case clang::Type::Attributed: break;
+ case clang::Type::Auto: break;
+ case clang::Type::InjectedClassName: break;
+ case clang::Type::DependentName: break;
+ case clang::Type::Atomic: break;
+ }
+ // No DeclContext in this type...
+ return NULL;
+}
+
+bool
+ClangASTType::SetDefaultAccessForRecordFields (int default_accessibility,
+ int *assigned_accessibilities,
+ size_t num_assigned_accessibilities)
+{
+ if (IsValid())
+ {
+ RecordDecl *record_decl = GetAsRecordDecl();
+ if (record_decl)
+ {
+ uint32_t field_idx;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0;
+ field != field_end;
+ ++field, ++field_idx)
+ {
+ // If no accessibility was assigned, assign the correct one
+ if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none)
+ field->setAccess ((AccessSpecifier)default_accessibility);
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+ClangASTType::SetHasExternalStorage (bool has_extern)
+{
+ if (!IsValid())
+ return false;
+
+ QualType qual_type (GetCanonicalQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Record:
+ {
+ CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+ if (cxx_record_decl)
+ {
+ cxx_record_decl->setHasExternalLexicalStorage (has_extern);
+ cxx_record_decl->setHasExternalVisibleStorage (has_extern);
+ return true;
+ }
+ }
+ break;
+
+ case clang::Type::Enum:
+ {
+ EnumDecl *enum_decl = cast<EnumType>(qual_type)->getDecl();
+ if (enum_decl)
+ {
+ enum_decl->setHasExternalLexicalStorage (has_extern);
+ enum_decl->setHasExternalVisibleStorage (has_extern);
+ return true;
+ }
+ }
+ break;
+
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ {
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+
+ if (class_interface_decl)
+ {
+ class_interface_decl->setHasExternalLexicalStorage (has_extern);
+ class_interface_decl->setHasExternalVisibleStorage (has_extern);
+ return true;
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ return ClangASTType (m_ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType()).SetHasExternalStorage (has_extern);
+
+ case clang::Type::Elaborated:
+ return ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).SetHasExternalStorage (has_extern);
+
+ case clang::Type::Paren:
+ return ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).SetHasExternalStorage (has_extern);
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+ClangASTType::SetTagTypeKind (int kind) const
+{
+ if (IsValid())
+ {
+ QualType tag_qual_type(GetQualType());
+ const clang::Type *clang_type = tag_qual_type.getTypePtr();
+ if (clang_type)
+ {
+ const TagType *tag_type = dyn_cast<TagType>(clang_type);
+ if (tag_type)
+ {
+ TagDecl *tag_decl = dyn_cast<TagDecl>(tag_type->getDecl());
+ if (tag_decl)
+ {
+ tag_decl->setTagKind ((TagDecl::TagKind)kind);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+#pragma mark TagDecl
+
+bool
+ClangASTType::StartTagDeclarationDefinition ()
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetQualType());
+ const clang::Type *t = qual_type.getTypePtr();
+ if (t)
+ {
+ const TagType *tag_type = dyn_cast<TagType>(t);
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ {
+ tag_decl->startDefinition();
+ return true;
+ }
+ }
+
+ const ObjCObjectType *object_type = dyn_cast<ObjCObjectType>(t);
+ if (object_type)
+ {
+ ObjCInterfaceDecl *interface_decl = object_type->getInterface();
+ if (interface_decl)
+ {
+ interface_decl->startDefinition();
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::CompleteTagDeclarationDefinition ()
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetQualType());
+
+ CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
+
+ if (cxx_record_decl)
+ {
+ cxx_record_decl->completeDefinition();
+
+ return true;
+ }
+
+ const EnumType *enum_type = dyn_cast<EnumType>(qual_type.getTypePtr());
+
+ if (enum_type)
+ {
+ EnumDecl *enum_decl = enum_type->getDecl();
+
+ if (enum_decl)
+ {
+ /// TODO This really needs to be fixed.
+
+ unsigned NumPositiveBits = 1;
+ unsigned NumNegativeBits = 0;
+
+ QualType promotion_qual_type;
+ // If the enum integer type is less than an integer in bit width,
+ // then we must promote it to an integer size.
+ if (m_ast->getTypeSize(enum_decl->getIntegerType()) < m_ast->getTypeSize(m_ast->IntTy))
+ {
+ if (enum_decl->getIntegerType()->isSignedIntegerType())
+ promotion_qual_type = m_ast->IntTy;
+ else
+ promotion_qual_type = m_ast->UnsignedIntTy;
+ }
+ else
+ promotion_qual_type = enum_decl->getIntegerType();
+
+ enum_decl->completeDefinition(enum_decl->getIntegerType(), promotion_qual_type, NumPositiveBits, NumNegativeBits);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+
+
+
+
+bool
+ClangASTType::AddEnumerationValueToEnumerationType (const ClangASTType &enumerator_clang_type,
+ const Declaration &decl,
+ const char *name,
+ int64_t enum_value,
+ uint32_t enum_value_bit_size)
+{
+ if (IsValid() && enumerator_clang_type.IsValid() && name && name[0])
+ {
+ QualType enum_qual_type (GetCanonicalQualType());
+
+ bool is_signed = false;
+ enumerator_clang_type.IsIntegerType (is_signed);
+ const clang::Type *clang_type = enum_qual_type.getTypePtr();
+ if (clang_type)
+ {
+ const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
+
+ if (enum_type)
+ {
+ llvm::APSInt enum_llvm_apsint(enum_value_bit_size, is_signed);
+ enum_llvm_apsint = enum_value;
+ EnumConstantDecl *enumerator_decl =
+ EnumConstantDecl::Create (*m_ast,
+ enum_type->getDecl(),
+ SourceLocation(),
+ name ? &m_ast->Idents.get(name) : NULL, // Identifier
+ enumerator_clang_type.GetQualType(),
+ NULL,
+ enum_llvm_apsint);
+
+ if (enumerator_decl)
+ {
+ enum_type->getDecl()->addDecl(enumerator_decl);
+
+#ifdef LLDB_CONFIGURATION_DEBUG
+ VerifyDecl(enumerator_decl);
+#endif
+
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+ClangASTType
+ClangASTType::GetEnumerationIntegerType () const
+{
+ QualType enum_qual_type (GetCanonicalQualType());
+ const clang::Type *clang_type = enum_qual_type.getTypePtr();
+ if (clang_type)
+ {
+ const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
+ if (enum_type)
+ {
+ EnumDecl *enum_decl = enum_type->getDecl();
+ if (enum_decl)
+ return ClangASTType (m_ast, enum_decl->getIntegerType());
+ }
+ }
+ return ClangASTType();
+}
+
+ClangASTType
+ClangASTType::CreateMemberPointerType (const ClangASTType &pointee_type) const
+{
+ if (IsValid() && pointee_type.IsValid())
+ {
+ return ClangASTType (m_ast, m_ast->getMemberPointerType (pointee_type.GetQualType(),
+ GetQualType().getTypePtr()));
+ }
+ return ClangASTType();
+}
+
+
+size_t
+ClangASTType::ConvertStringToFloatValue (const char *s, uint8_t *dst, size_t dst_size) const
+{
+ if (IsValid())
+ {
+ QualType qual_type (GetCanonicalQualType());
+ uint32_t count = 0;
+ bool is_complex = false;
+ if (IsFloatingPointType (count, is_complex))
+ {
+ // TODO: handle complex and vector types
+ if (count != 1)
+ return false;
+
+ StringRef s_sref(s);
+ APFloat ap_float(m_ast->getFloatTypeSemantics(qual_type), s_sref);
+
+ const uint64_t bit_size = m_ast->getTypeSize (qual_type);
+ const uint64_t byte_size = bit_size / 8;
+ if (dst_size >= byte_size)
+ {
+ if (bit_size == sizeof(float)*8)
+ {
+ float float32 = ap_float.convertToFloat();
+ ::memcpy (dst, &float32, byte_size);
+ return byte_size;
+ }
+ else if (bit_size >= 64)
+ {
+ llvm::APInt ap_int(ap_float.bitcastToAPInt());
+ ::memcpy (dst, ap_int.getRawData(), byte_size);
+ return byte_size;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+//----------------------------------------------------------------------
+// Dumping types
+//----------------------------------------------------------------------
+#define DEPTH_INCREMENT 2
+
+void
+ClangASTType::DumpValue (ExecutionContext *exe_ctx,
+ Stream *s,
+ lldb::Format format,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_byte_offset,
+ size_t data_byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ bool show_types,
+ bool show_summary,
+ bool verbose,
+ uint32_t depth)
+{
+ if (!IsValid())
+ return;
+
+ QualType qual_type(GetQualType());
+ switch (qual_type->getTypeClass())
+ {
+ case clang::Type::Record:
+ if (GetCompleteType ())
+ {
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ assert(record_decl);
+ uint32_t field_bit_offset = 0;
+ uint32_t field_byte_offset = 0;
+ const ASTRecordLayout &record_layout = m_ast->getASTRecordLayout(record_decl);
+ uint32_t child_idx = 0;
+
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+ if (cxx_record_decl)
+ {
+ // We might have base classes to print out first
+ CXXRecordDecl::base_class_const_iterator base_class, base_class_end;
+ for (base_class = cxx_record_decl->bases_begin(), base_class_end = cxx_record_decl->bases_end();
+ base_class != base_class_end;
+ ++base_class)
+ {
+ const CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
+
+ // Skip empty base classes
+ if (verbose == false && ClangASTContext::RecordHasFields(base_class_decl) == false)
+ continue;
+
+ if (base_class->isVirtual())
+ field_bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity() * 8;
+ else
+ field_bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity() * 8;
+ field_byte_offset = field_bit_offset / 8;
+ assert (field_bit_offset % 8 == 0);
+ if (child_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ QualType base_class_qual_type = base_class->getType();
+ std::string base_class_type_name(base_class_qual_type.getAsString());
+
+ // Indent and print the base class type name
+ s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "", base_class_type_name.c_str());
+
+ std::pair<uint64_t, unsigned> base_class_type_info = m_ast->getTypeInfo(base_class_qual_type);
+
+ // Dump the value of the member
+ ClangASTType base_clang_type(m_ast, base_class_qual_type);
+ base_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ base_clang_type.GetFormat(), // The format with which to display the member
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from
+ base_class_type_info.first / 8, // Size of this type in bytes
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have children
+
+ ++child_idx;
+ }
+ }
+ uint32_t field_idx = 0;
+ RecordDecl::field_iterator field, field_end;
+ for (field = record_decl->field_begin(), field_end = record_decl->field_end(); field != field_end; ++field, ++field_idx, ++child_idx)
+ {
+ // Print the starting squiggly bracket (if this is the
+ // first member) or comman (for member 2 and beyong) for
+ // the struct/union/class member.
+ if (child_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ // Indent
+ s->Printf("\n%*s", depth + DEPTH_INCREMENT, "");
+
+ QualType field_type = field->getType();
+ // Print the member type if requested
+ // Figure out the type byte size (field_type_info.first) and
+ // alignment (field_type_info.second) from the AST context.
+ std::pair<uint64_t, unsigned> field_type_info = m_ast->getTypeInfo(field_type);
+ assert(field_idx < record_layout.getFieldCount());
+ // Figure out the field offset within the current struct/union/class type
+ field_bit_offset = record_layout.getFieldOffset (field_idx);
+ field_byte_offset = field_bit_offset / 8;
+ uint32_t field_bitfield_bit_size = 0;
+ uint32_t field_bitfield_bit_offset = 0;
+ if (ClangASTContext::FieldIsBitfield (m_ast, *field, field_bitfield_bit_size))
+ field_bitfield_bit_offset = field_bit_offset % 8;
+
+ if (show_types)
+ {
+ std::string field_type_name(field_type.getAsString());
+ if (field_bitfield_bit_size > 0)
+ s->Printf("(%s:%u) ", field_type_name.c_str(), field_bitfield_bit_size);
+ else
+ s->Printf("(%s) ", field_type_name.c_str());
+ }
+ // Print the member name and equal sign
+ s->Printf("%s = ", field->getNameAsString().c_str());
+
+
+ // Dump the value of the member
+ ClangASTType field_clang_type (m_ast, field_type);
+ field_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ field_clang_type.GetFormat(), // The format with which to display the member
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset + field_byte_offset,// Offset into "data" where to grab value from
+ field_type_info.first / 8, // Size of this type in bytes
+ field_bitfield_bit_size, // Bitfield bit size
+ field_bitfield_bit_offset, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have children
+ }
+
+ // Indent the trailing squiggly bracket
+ if (child_idx > 0)
+ s->Printf("\n%*s}", depth, "");
+ }
+ return;
+
+ case clang::Type::Enum:
+ if (GetCompleteType ())
+ {
+ const EnumType *enum_type = cast<EnumType>(qual_type.getTypePtr());
+ const EnumDecl *enum_decl = enum_type->getDecl();
+ assert(enum_decl);
+ EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ lldb::offset_t offset = data_byte_offset;
+ const int64_t enum_value = data.GetMaxU64Bitfield(&offset, data_byte_size, bitfield_bit_size, bitfield_bit_offset);
+ for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos)
+ {
+ if (enum_pos->getInitVal() == enum_value)
+ {
+ s->Printf("%s", enum_pos->getNameAsString().c_str());
+ return;
+ }
+ }
+ // If we have gotten here we didn't get find the enumerator in the
+ // enum decl, so just print the integer.
+ s->Printf("%" PRIi64, enum_value);
+ }
+ return;
+
+ case clang::Type::ConstantArray:
+ {
+ const ConstantArrayType *array = cast<ConstantArrayType>(qual_type.getTypePtr());
+ bool is_array_of_characters = false;
+ QualType element_qual_type = array->getElementType();
+
+ const clang::Type *canonical_type = element_qual_type->getCanonicalTypeInternal().getTypePtr();
+ if (canonical_type)
+ is_array_of_characters = canonical_type->isCharType();
+
+ const uint64_t element_count = array->getSize().getLimitedValue();
+
+ std::pair<uint64_t, unsigned> field_type_info = m_ast->getTypeInfo(element_qual_type);
+
+ uint32_t element_idx = 0;
+ uint32_t element_offset = 0;
+ uint64_t element_byte_size = field_type_info.first / 8;
+ uint32_t element_stride = element_byte_size;
+
+ if (is_array_of_characters)
+ {
+ s->PutChar('"');
+ data.Dump(s, data_byte_offset, lldb::eFormatChar, element_byte_size, element_count, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ s->PutChar('"');
+ return;
+ }
+ else
+ {
+ ClangASTType element_clang_type(m_ast, element_qual_type);
+ lldb::Format element_format = element_clang_type.GetFormat();
+
+ for (element_idx = 0; element_idx < element_count; ++element_idx)
+ {
+ // Print the starting squiggly bracket (if this is the
+ // first member) or comman (for member 2 and beyong) for
+ // the struct/union/class member.
+ if (element_idx == 0)
+ s->PutChar('{');
+ else
+ s->PutChar(',');
+
+ // Indent and print the index
+ s->Printf("\n%*s[%u] ", depth + DEPTH_INCREMENT, "", element_idx);
+
+ // Figure out the field offset within the current struct/union/class type
+ element_offset = element_idx * element_stride;
+
+ // Dump the value of the member
+ element_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ element_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset + element_offset,// Offset into "data" where to grab value from
+ element_byte_size, // Size of this type in bytes
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth + DEPTH_INCREMENT); // Scope depth for any types that have children
+ }
+
+ // Indent the trailing squiggly bracket
+ if (element_idx > 0)
+ s->Printf("\n%*s}", depth, "");
+ }
+ }
+ return;
+
+ case clang::Type::Typedef:
+ {
+ QualType typedef_qual_type = cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType();
+
+ ClangASTType typedef_clang_type (m_ast, typedef_qual_type);
+ lldb::Format typedef_format = typedef_clang_type.GetFormat();
+ std::pair<uint64_t, unsigned> typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.first / 8;
+
+ return typedef_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ typedef_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ typedef_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset,// Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ }
+ break;
+
+ case clang::Type::Elaborated:
+ {
+ QualType elaborated_qual_type = cast<ElaboratedType>(qual_type)->getNamedType();
+ ClangASTType elaborated_clang_type (m_ast, elaborated_qual_type);
+ lldb::Format elaborated_format = elaborated_clang_type.GetFormat();
+ std::pair<uint64_t, unsigned> elaborated_type_info = m_ast->getTypeInfo(elaborated_qual_type);
+ uint64_t elaborated_byte_size = elaborated_type_info.first / 8;
+
+ return elaborated_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ elaborated_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ elaborated_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset,// Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ }
+ break;
+
+ case clang::Type::Paren:
+ {
+ QualType desugar_qual_type = cast<ParenType>(qual_type)->desugar();
+ ClangASTType desugar_clang_type (m_ast, desugar_qual_type);
+
+ lldb::Format desugar_format = desugar_clang_type.GetFormat();
+ std::pair<uint64_t, unsigned> desugar_type_info = m_ast->getTypeInfo(desugar_qual_type);
+ uint64_t desugar_byte_size = desugar_type_info.first / 8;
+
+ return desugar_clang_type.DumpValue (exe_ctx,
+ s, // Stream to dump to
+ desugar_format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ data_byte_offset, // Offset into "data" where to grab value from
+ desugar_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Bitfield bit size
+ bitfield_bit_offset,// Bitfield bit offset
+ show_types, // Boolean indicating if we should show the variable types
+ show_summary, // Boolean indicating if we should show a summary for the current type
+ verbose, // Verbose output?
+ depth); // Scope depth for any types that have children
+ }
+ break;
+
+ default:
+ // We are down the a scalar type that we just need to display.
+ data.Dump(s,
+ data_byte_offset,
+ format,
+ data_byte_size,
+ 1,
+ UINT32_MAX,
+ LLDB_INVALID_ADDRESS,
+ bitfield_bit_size,
+ bitfield_bit_offset);
+
+ if (show_summary)
+ DumpSummary (exe_ctx, s, data, data_byte_offset, data_byte_size);
+ break;
+ }
+}
+
+
+
+
+bool
+ClangASTType::DumpTypeValue (Stream *s,
+ lldb::Format format,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t byte_offset,
+ size_t byte_size,
+ uint32_t bitfield_bit_size,
+ uint32_t bitfield_bit_offset,
+ ExecutionContextScope *exe_scope)
+{
+ if (!IsValid())
+ return false;
+ if (IsAggregateType())
+ {
+ return false;
+ }
+ else
+ {
+ QualType qual_type(GetQualType());
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::Typedef:
+ {
+ QualType typedef_qual_type = cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType();
+ ClangASTType typedef_clang_type (m_ast, typedef_qual_type);
+ if (format == eFormatDefault)
+ format = typedef_clang_type.GetFormat();
+ std::pair<uint64_t, unsigned> typedef_type_info = m_ast->getTypeInfo(typedef_qual_type);
+ uint64_t typedef_byte_size = typedef_type_info.first / 8;
+
+ return typedef_clang_type.DumpTypeValue (s,
+ format, // The format with which to display the element
+ data, // Data buffer containing all bytes for this type
+ byte_offset, // Offset into "data" where to grab value from
+ typedef_byte_size, // Size of this type in bytes
+ bitfield_bit_size, // Size in bits of a bitfield value, if zero don't treat as a bitfield
+ bitfield_bit_offset, // Offset in bits of a bitfield value if bitfield_bit_size != 0
+ exe_scope);
+ }
+ break;
+
+ case clang::Type::Enum:
+ // If our format is enum or default, show the enumeration value as
+ // its enumeration string value, else just display it as requested.
+ if ((format == eFormatEnum || format == eFormatDefault) && GetCompleteType ())
+ {
+ const EnumType *enum_type = cast<EnumType>(qual_type.getTypePtr());
+ const EnumDecl *enum_decl = enum_type->getDecl();
+ assert(enum_decl);
+ EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
+ const bool is_signed = qual_type->isSignedIntegerOrEnumerationType();
+ lldb::offset_t offset = byte_offset;
+ if (is_signed)
+ {
+ const int64_t enum_svalue = data.GetMaxS64Bitfield (&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+ for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos)
+ {
+ if (enum_pos->getInitVal().getSExtValue() == enum_svalue)
+ {
+ s->PutCString (enum_pos->getNameAsString().c_str());
+ return true;
+ }
+ }
+ // If we have gotten here we didn't get find the enumerator in the
+ // enum decl, so just print the integer.
+ s->Printf("%" PRIi64, enum_svalue);
+ }
+ else
+ {
+ const uint64_t enum_uvalue = data.GetMaxU64Bitfield (&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+ for (enum_pos = enum_decl->enumerator_begin(), enum_end_pos = enum_decl->enumerator_end(); enum_pos != enum_end_pos; ++enum_pos)
+ {
+ if (enum_pos->getInitVal().getZExtValue() == enum_uvalue)
+ {
+ s->PutCString (enum_pos->getNameAsString().c_str());
+ return true;
+ }
+ }
+ // If we have gotten here we didn't get find the enumerator in the
+ // enum decl, so just print the integer.
+ s->Printf("%" PRIu64, enum_uvalue);
+ }
+ return true;
+ }
+ // format was not enum, just fall through and dump the value as requested....
+
+ default:
+ // We are down the a scalar type that we just need to display.
+ {
+ uint32_t item_count = 1;
+ // A few formats, we might need to modify our size and count for depending
+ // on how we are trying to display the value...
+ switch (format)
+ {
+ default:
+ case eFormatBoolean:
+ case eFormatBinary:
+ case eFormatComplex:
+ case eFormatCString: // NULL terminated C strings
+ case eFormatDecimal:
+ case eFormatEnum:
+ case eFormatHex:
+ case eFormatHexUppercase:
+ case eFormatFloat:
+ case eFormatOctal:
+ case eFormatOSType:
+ case eFormatUnsigned:
+ case eFormatPointer:
+ case eFormatVectorOfChar:
+ case eFormatVectorOfSInt8:
+ case eFormatVectorOfUInt8:
+ case eFormatVectorOfSInt16:
+ case eFormatVectorOfUInt16:
+ case eFormatVectorOfSInt32:
+ case eFormatVectorOfUInt32:
+ case eFormatVectorOfSInt64:
+ case eFormatVectorOfUInt64:
+ case eFormatVectorOfFloat32:
+ case eFormatVectorOfFloat64:
+ case eFormatVectorOfUInt128:
+ break;
+
+ case eFormatChar:
+ case eFormatCharPrintable:
+ case eFormatCharArray:
+ case eFormatBytes:
+ case eFormatBytesWithASCII:
+ item_count = byte_size;
+ byte_size = 1;
+ break;
+
+ case eFormatUnicode16:
+ item_count = byte_size / 2;
+ byte_size = 2;
+ break;
+
+ case eFormatUnicode32:
+ item_count = byte_size / 4;
+ byte_size = 4;
+ break;
+ }
+ return data.Dump (s,
+ byte_offset,
+ format,
+ byte_size,
+ item_count,
+ UINT32_MAX,
+ LLDB_INVALID_ADDRESS,
+ bitfield_bit_size,
+ bitfield_bit_offset,
+ exe_scope);
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+
+
+void
+ClangASTType::DumpSummary (ExecutionContext *exe_ctx,
+ Stream *s,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_byte_offset,
+ size_t data_byte_size)
+{
+ uint32_t length = 0;
+ if (IsCStringType (length))
+ {
+ if (exe_ctx)
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ lldb::offset_t offset = data_byte_offset;
+ lldb::addr_t pointer_addresss = data.GetMaxU64(&offset, data_byte_size);
+ std::vector<uint8_t> buf;
+ if (length > 0)
+ buf.resize (length);
+ else
+ buf.resize (256);
+
+ lldb_private::DataExtractor cstr_data(&buf.front(), buf.size(), process->GetByteOrder(), 4);
+ buf.back() = '\0';
+ size_t bytes_read;
+ size_t total_cstr_len = 0;
+ Error error;
+ while ((bytes_read = process->ReadMemory (pointer_addresss, &buf.front(), buf.size(), error)) > 0)
+ {
+ const size_t len = strlen((const char *)&buf.front());
+ if (len == 0)
+ break;
+ if (total_cstr_len == 0)
+ s->PutCString (" \"");
+ cstr_data.Dump(s, 0, lldb::eFormatChar, 1, len, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0);
+ total_cstr_len += len;
+ if (len < buf.size())
+ break;
+ pointer_addresss += total_cstr_len;
+ }
+ if (total_cstr_len > 0)
+ s->PutChar ('"');
+ }
+ }
+ }
+}
+
+void
+ClangASTType::DumpTypeDescription () const
+{
+ StreamFile s (stdout, false);
+ DumpTypeDescription (&s);
+ ClangASTMetadata *metadata = ClangASTContext::GetMetadata (m_ast, m_type);
+ if (metadata)
+ {
+ metadata->Dump (&s);
+ }
+}
+
+void
+ClangASTType::DumpTypeDescription (Stream *s) const
+{
+ if (IsValid())
+ {
+ QualType qual_type(GetQualType());
+
+ SmallVector<char, 1024> buf;
+ raw_svector_ostream llvm_ostrm (buf);
+
+ const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+ switch (type_class)
+ {
+ case clang::Type::ObjCObject:
+ case clang::Type::ObjCInterface:
+ {
+ GetCompleteType ();
+
+ const ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
+ assert (objc_class_type);
+ if (objc_class_type)
+ {
+ ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
+ if (class_interface_decl)
+ {
+ PrintingPolicy policy = m_ast->getPrintingPolicy();
+ class_interface_decl->print(llvm_ostrm, policy, s->GetIndentLevel());
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Typedef:
+ {
+ const TypedefType *typedef_type = qual_type->getAs<TypedefType>();
+ if (typedef_type)
+ {
+ const TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ std::string clang_typedef_name (typedef_decl->getQualifiedNameAsString());
+ if (!clang_typedef_name.empty())
+ {
+ s->PutCString ("typedef ");
+ s->PutCString (clang_typedef_name.c_str());
+ }
+ }
+ }
+ break;
+
+ case clang::Type::Elaborated:
+ ClangASTType (m_ast, cast<ElaboratedType>(qual_type)->getNamedType()).DumpTypeDescription(s);
+ return;
+
+ case clang::Type::Paren:
+ ClangASTType (m_ast, cast<ParenType>(qual_type)->desugar()).DumpTypeDescription(s);
+ return;
+
+ case clang::Type::Record:
+ {
+ GetCompleteType ();
+
+ const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
+ const RecordDecl *record_decl = record_type->getDecl();
+ const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
+
+ if (cxx_record_decl)
+ cxx_record_decl->print(llvm_ostrm, m_ast->getPrintingPolicy(), s->GetIndentLevel());
+ else
+ record_decl->print(llvm_ostrm, m_ast->getPrintingPolicy(), s->GetIndentLevel());
+ }
+ break;
+
+ default:
+ {
+ const TagType *tag_type = dyn_cast<TagType>(qual_type.getTypePtr());
+ if (tag_type)
+ {
+ TagDecl *tag_decl = tag_type->getDecl();
+ if (tag_decl)
+ tag_decl->print(llvm_ostrm, 0);
+ }
+ else
+ {
+ std::string clang_type_name(qual_type.getAsString());
+ if (!clang_type_name.empty())
+ s->PutCString (clang_type_name.c_str());
+ }
+ }
+ }
+
+ llvm_ostrm.flush();
+ if (buf.size() > 0)
+ {
+ s->Write (buf.data(), buf.size());
+ }
+ }
+}
+
+bool
+ClangASTType::GetValueAsScalar (const lldb_private::DataExtractor &data,
+ lldb::offset_t data_byte_offset,
+ size_t data_byte_size,
+ Scalar &value) const
+{
+ if (!IsValid())
+ return false;
+
+ if (IsAggregateType ())
+ {
+ return false; // Aggregate types don't have scalar values
+ }
+ else
+ {
+ uint64_t count = 0;
+ lldb::Encoding encoding = GetEncoding (count);
+
+ if (encoding == lldb::eEncodingInvalid || count != 1)
+ return false;
+
+ const uint64_t byte_size = GetByteSize();
+ lldb::offset_t offset = data_byte_offset;
+ switch (encoding)
+ {
+ case lldb::eEncodingInvalid:
+ break;
+ case lldb::eEncodingVector:
+ break;
+ case lldb::eEncodingUint:
+ if (byte_size <= sizeof(unsigned long long))
+ {
+ uint64_t uval64 = data.GetMaxU64 (&offset, byte_size);
+ if (byte_size <= sizeof(unsigned int))
+ {
+ value = (unsigned int)uval64;
+ return true;
+ }
+ else if (byte_size <= sizeof(unsigned long))
+ {
+ value = (unsigned long)uval64;
+ return true;
+ }
+ else if (byte_size <= sizeof(unsigned long long))
+ {
+ value = (unsigned long long )uval64;
+ return true;
+ }
+ else
+ value.Clear();
+ }
+ break;
+
+ case lldb::eEncodingSint:
+ if (byte_size <= sizeof(long long))
+ {
+ int64_t sval64 = data.GetMaxS64 (&offset, byte_size);
+ if (byte_size <= sizeof(int))
+ {
+ value = (int)sval64;
+ return true;
+ }
+ else if (byte_size <= sizeof(long))
+ {
+ value = (long)sval64;
+ return true;
+ }
+ else if (byte_size <= sizeof(long long))
+ {
+ value = (long long )sval64;
+ return true;
+ }
+ else
+ value.Clear();
+ }
+ break;
+
+ case lldb::eEncodingIEEE754:
+ if (byte_size <= sizeof(long double))
+ {
+ uint32_t u32;
+ uint64_t u64;
+ if (byte_size == sizeof(float))
+ {
+ if (sizeof(float) == sizeof(uint32_t))
+ {
+ u32 = data.GetU32(&offset);
+ value = *((float *)&u32);
+ return true;
+ }
+ else if (sizeof(float) == sizeof(uint64_t))
+ {
+ u64 = data.GetU64(&offset);
+ value = *((float *)&u64);
+ return true;
+ }
+ }
+ else
+ if (byte_size == sizeof(double))
+ {
+ if (sizeof(double) == sizeof(uint32_t))
+ {
+ u32 = data.GetU32(&offset);
+ value = *((double *)&u32);
+ return true;
+ }
+ else if (sizeof(double) == sizeof(uint64_t))
+ {
+ u64 = data.GetU64(&offset);
+ value = *((double *)&u64);
+ return true;
+ }
+ }
+ else
+ if (byte_size == sizeof(long double))
+ {
+ if (sizeof(long double) == sizeof(uint32_t))
+ {
+ u32 = data.GetU32(&offset);
+ value = *((long double *)&u32);
+ return true;
+ }
+ else if (sizeof(long double) == sizeof(uint64_t))
+ {
+ u64 = data.GetU64(&offset);
+ value = *((long double *)&u64);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::SetValueFromScalar (const Scalar &value, Stream &strm)
+{
+ // Aggregate types don't have scalar values
+ if (!IsAggregateType ())
+ {
+ strm.GetFlags().Set(Stream::eBinary);
+ uint64_t count = 0;
+ lldb::Encoding encoding = GetEncoding (count);
+
+ if (encoding == lldb::eEncodingInvalid || count != 1)
+ return false;
+
+ const uint64_t bit_width = GetBitSize();
+ // This function doesn't currently handle non-byte aligned assignments
+ if ((bit_width % 8) != 0)
+ return false;
+
+ const uint64_t byte_size = (bit_width + 7 ) / 8;
+ switch (encoding)
+ {
+ case lldb::eEncodingInvalid:
+ break;
+ case lldb::eEncodingVector:
+ break;
+ case lldb::eEncodingUint:
+ switch (byte_size)
+ {
+ case 1: strm.PutHex8(value.UInt()); return true;
+ case 2: strm.PutHex16(value.UInt()); return true;
+ case 4: strm.PutHex32(value.UInt()); return true;
+ case 8: strm.PutHex64(value.ULongLong()); return true;
+ default:
+ break;
+ }
+ break;
+
+ case lldb::eEncodingSint:
+ switch (byte_size)
+ {
+ case 1: strm.PutHex8(value.SInt()); return true;
+ case 2: strm.PutHex16(value.SInt()); return true;
+ case 4: strm.PutHex32(value.SInt()); return true;
+ case 8: strm.PutHex64(value.SLongLong()); return true;
+ default:
+ break;
+ }
+ break;
+
+ case lldb::eEncodingIEEE754:
+ if (byte_size <= sizeof(long double))
+ {
+ if (byte_size == sizeof(float))
+ {
+ strm.PutFloat(value.Float());
+ return true;
+ }
+ else
+ if (byte_size == sizeof(double))
+ {
+ strm.PutDouble(value.Double());
+ return true;
+ }
+ else
+ if (byte_size == sizeof(long double))
+ {
+ strm.PutDouble(value.LongDouble());
+ return true;
+ }
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::ReadFromMemory (lldb_private::ExecutionContext *exe_ctx,
+ lldb::addr_t addr,
+ AddressType address_type,
+ lldb_private::DataExtractor &data)
+{
+ if (!IsValid())
+ return false;
+
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ if (address_type == eAddressTypeFile)
+ return false;
+
+ if (!GetCompleteType())
+ return false;
+
+ const uint64_t byte_size = GetByteSize();
+ if (data.GetByteSize() < byte_size)
+ {
+ lldb::DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
+ data.SetData(data_sp);
+ }
+
+ uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size);
+ if (dst != NULL)
+ {
+ if (address_type == eAddressTypeHost)
+ {
+ if (addr == 0)
+ return false;
+ // The address is an address in this process, so just copy it
+ memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ return true;
+ }
+ else
+ {
+ Process *process = NULL;
+ if (exe_ctx)
+ process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ Error error;
+ return process->ReadMemory(addr, dst, byte_size, error) == byte_size;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ClangASTType::WriteToMemory (lldb_private::ExecutionContext *exe_ctx,
+ lldb::addr_t addr,
+ AddressType address_type,
+ StreamString &new_value)
+{
+ if (!IsValid())
+ return false;
+
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ if (address_type == eAddressTypeFile)
+ return false;
+
+ if (!GetCompleteType())
+ return false;
+
+ const uint64_t byte_size = GetByteSize();
+
+ if (byte_size > 0)
+ {
+ if (address_type == eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ memcpy ((void *)addr, new_value.GetData(), byte_size);
+ return true;
+ }
+ else
+ {
+ Process *process = NULL;
+ if (exe_ctx)
+ process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ Error error;
+ return process->WriteMemory(addr, new_value.GetData(), byte_size, error) == byte_size;
+ }
+ }
+ }
+ return false;
+}
+
+
+//CXXRecordDecl *
+//ClangASTType::GetAsCXXRecordDecl (lldb::clang_type_t opaque_clang_qual_type)
+//{
+// if (opaque_clang_qual_type)
+// return QualType::getFromOpaquePtr(opaque_clang_qual_type)->getAsCXXRecordDecl();
+// return NULL;
+//}
+
+bool
+lldb_private::operator == (const lldb_private::ClangASTType &lhs, const lldb_private::ClangASTType &rhs)
+{
+ return lhs.GetASTContext() == rhs.GetASTContext() && lhs.GetOpaqueQualType() == rhs.GetOpaqueQualType();
+}
+
+
+bool
+lldb_private::operator != (const lldb_private::ClangASTType &lhs, const lldb_private::ClangASTType &rhs)
+{
+ return lhs.GetASTContext() != rhs.GetASTContext() || lhs.GetOpaqueQualType() != rhs.GetOpaqueQualType();
+}
+
+
diff --git a/source/Symbol/ClangExternalASTSourceCallbacks.cpp b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
new file mode 100644
index 000000000000..b2328d6e5b42
--- /dev/null
+++ b/source/Symbol/ClangExternalASTSourceCallbacks.cpp
@@ -0,0 +1,163 @@
+//===-- ClangExternalASTSourceCallbacks.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/Symbol/ClangExternalASTSourceCallbacks.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Clang headers like to use NDEBUG inside of them to enable/disable debug
+// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing
+// or another. This is bad because it means that if clang was built in release
+// mode, it assumes that you are building in release mode which is not always
+// the case. You can end up with functions that are defined as empty in header
+// files when NDEBUG is not defined, and this can cause link errors with the
+// clang .a files that you have since you might be missing functions in the .a
+// file. So we have to define NDEBUG when including clang headers to avoid any
+// mismatches. This is covered by rdar://problem/8691220
+
+#if !defined(NDEBUG) && !defined(LLVM_NDEBUG_OFF)
+#define LLDB_DEFINED_NDEBUG_FOR_CLANG
+#define NDEBUG
+// Need to include assert.h so it is as clang would expect it to be (disabled)
+#include <assert.h>
+#endif
+
+#include "clang/AST/DeclBase.h"
+#include "clang/AST/DeclarationName.h"
+
+#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG
+#undef NDEBUG
+#undef LLDB_DEFINED_NDEBUG_FOR_CLANG
+// Need to re-include assert.h so it is as _we_ would expect it to be (enabled)
+#include <assert.h>
+#endif
+
+#include "lldb/Core/Log.h"
+
+using namespace clang;
+using namespace lldb_private;
+
+bool
+ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName
+(
+ const clang::DeclContext *decl_ctx,
+ clang::DeclarationName clang_decl_name
+)
+{
+ if (m_callback_find_by_name)
+ {
+ llvm::SmallVector <clang::NamedDecl *, 3> results;
+
+ m_callback_find_by_name (m_callback_baton, decl_ctx, clang_decl_name, &results);
+
+ SetExternalVisibleDeclsForName(decl_ctx, clang_decl_name, results);
+
+ return (results.size() != 0);
+ }
+
+ std::string decl_name (clang_decl_name.getAsString());
+
+ switch (clang_decl_name.getNameKind()) {
+ // Normal identifiers.
+ case clang::DeclarationName::Identifier:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"Identifier\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ if (clang_decl_name.getAsIdentifierInfo()->getBuiltinID() != 0)
+ {
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+ break;
+
+ case clang::DeclarationName::ObjCZeroArgSelector:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCZeroArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::ObjCOneArgSelector:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCOneArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::ObjCMultiArgSelector:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCMultiArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::CXXConstructorName:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXConstructorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+
+ case clang::DeclarationName::CXXDestructorName:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXDestructorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::CXXConversionFunctionName:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXConversionFunctionName\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::CXXOperatorName:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXOperatorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::CXXLiteralOperatorName:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXLiteralOperatorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+
+ case clang::DeclarationName::CXXUsingDirective:
+ //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXUsingDirective\", name = \"%s\")\n", decl_ctx, decl_name.c_str());
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+ }
+
+ SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name);
+ return false;
+}
+
+void
+ClangExternalASTSourceCallbacks::CompleteType (TagDecl *tag_decl)
+{
+ if (m_callback_tag_decl)
+ m_callback_tag_decl (m_callback_baton, tag_decl);
+}
+
+void
+ClangExternalASTSourceCallbacks::CompleteType (ObjCInterfaceDecl *objc_decl)
+{
+ if (m_callback_objc_decl)
+ m_callback_objc_decl (m_callback_baton, objc_decl);
+}
+
+bool
+ClangExternalASTSourceCallbacks::layoutRecordType(const clang::RecordDecl *Record,
+ uint64_t &Size,
+ uint64_t &Alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &FieldOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &BaseOffsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &VirtualBaseOffsets)
+{
+ if (m_callback_layout_record_type)
+ return m_callback_layout_record_type(m_callback_baton,
+ Record,
+ Size,
+ Alignment,
+ FieldOffsets,
+ BaseOffsets,
+ VirtualBaseOffsets);
+
+ return false;
+}
+
diff --git a/source/Symbol/ClangExternalASTSourceCommon.cpp b/source/Symbol/ClangExternalASTSourceCommon.cpp
new file mode 100644
index 000000000000..697dc7eec493
--- /dev/null
+++ b/source/Symbol/ClangExternalASTSourceCommon.cpp
@@ -0,0 +1,89 @@
+//===-- ClangExternalASTSourceCommon.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/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+#define ClangExternalASTSourceCommon_MAGIC (0x00112233aabbccddull)
+
+uint64_t g_TotalSizeOfMetadata = 0;
+
+ClangExternalASTSourceCommon::ClangExternalASTSourceCommon() : clang::ExternalASTSource()
+{
+ m_magic = ClangExternalASTSourceCommon_MAGIC;
+
+ g_TotalSizeOfMetadata += m_metadata.size();
+}
+
+ClangExternalASTSourceCommon::~ClangExternalASTSourceCommon()
+{
+ g_TotalSizeOfMetadata -= m_metadata.size();
+}
+
+ClangASTMetadata *
+ClangExternalASTSourceCommon::GetMetadata (const void *object)
+{
+ assert (m_magic == ClangExternalASTSourceCommon_MAGIC);
+
+ if (HasMetadata (object))
+ return &m_metadata[object];
+ else
+ return NULL;
+}
+
+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();
+ g_TotalSizeOfMetadata += (new_size - orig_size);
+}
+
+bool
+ClangExternalASTSourceCommon::HasMetadata (const void *object)
+{
+ assert (m_magic == ClangExternalASTSourceCommon_MAGIC);
+
+ return m_metadata.find(object) != m_metadata.end();
+}
+
+void
+ClangASTMetadata::Dump (Stream *s)
+{
+ lldb::user_id_t uid = GetUserID ();
+
+ if (uid != LLDB_INVALID_UID)
+ {
+ s->Printf ("uid=0x%" PRIx64, uid);
+ }
+
+ uint64_t isa_ptr = GetISAPtr ();
+ if (isa_ptr != 0)
+ {
+ s->Printf ("isa_ptr=0x%" PRIx64, isa_ptr);
+ }
+
+ const char *obj_ptr_name = GetObjectPtrName();
+ if (obj_ptr_name)
+ {
+ s->Printf ("obj_ptr_name=\"%s\" ", obj_ptr_name);
+ }
+
+ if (m_is_dynamic_cxx)
+ {
+ s->Printf ("is_dynamic_cxx=%i ", m_is_dynamic_cxx);
+ }
+ s->EOL();
+}
+
diff --git a/source/Symbol/ClangNamespaceDecl.cpp b/source/Symbol/ClangNamespaceDecl.cpp
new file mode 100644
index 000000000000..568b0263f0fe
--- /dev/null
+++ b/source/Symbol/ClangNamespaceDecl.cpp
@@ -0,0 +1,25 @@
+//===-- ClangNamespaceDecl.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/Symbol/ClangNamespaceDecl.h"
+
+#include "clang/AST/Decl.h"
+
+namespace lldb_private {
+
+std::string
+ClangNamespaceDecl::GetQualifiedName () const
+{
+ if (m_namespace_decl)
+ return m_namespace_decl->getQualifiedNameAsString();
+ return std::string();
+}
+
+
+}
diff --git a/source/Symbol/CompileUnit.cpp b/source/Symbol/CompileUnit.cpp
new file mode 100644
index 000000000000..751b09ec5a6b
--- /dev/null
+++ b/source/Symbol/CompileUnit.cpp
@@ -0,0 +1,464 @@
+//===-- CompileUnit.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/Symbol/CompileUnit.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Language.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const char *pathname, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
+ ModuleChild(module_sp),
+ FileSpec (pathname, false),
+ UserID(cu_sym_id),
+ m_user_data (user_data),
+ m_language (language),
+ m_flags (0),
+ m_functions (),
+ m_support_files (),
+ m_line_table_ap (),
+ m_variables()
+{
+ if (language != eLanguageTypeUnknown)
+ m_flags.Set(flagsParsedLanguage);
+ assert(module_sp);
+}
+
+CompileUnit::CompileUnit (const lldb::ModuleSP &module_sp, void *user_data, const FileSpec &fspec, const lldb::user_id_t cu_sym_id, lldb::LanguageType language) :
+ ModuleChild(module_sp),
+ FileSpec (fspec),
+ UserID(cu_sym_id),
+ m_user_data (user_data),
+ m_language (language),
+ m_flags (0),
+ m_functions (),
+ m_support_files (),
+ m_line_table_ap (),
+ m_variables()
+{
+ if (language != eLanguageTypeUnknown)
+ m_flags.Set(flagsParsedLanguage);
+ assert(module_sp);
+}
+
+CompileUnit::~CompileUnit ()
+{
+}
+
+void
+CompileUnit::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->comp_unit = this;
+ GetModule()->CalculateSymbolContext(sc);
+}
+
+ModuleSP
+CompileUnit::CalculateSymbolContextModule ()
+{
+ return GetModule();
+}
+
+CompileUnit *
+CompileUnit::CalculateSymbolContextCompileUnit ()
+{
+ return this;
+}
+
+void
+CompileUnit::DumpSymbolContext(Stream *s)
+{
+ GetModule()->DumpSymbolContext(s);
+ s->Printf(", CompileUnit{0x%8.8" PRIx64 "}", GetID());
+}
+
+
+void
+CompileUnit::GetDescription(Stream *s, lldb::DescriptionLevel level) const
+{
+ Language language(m_language);
+ *s << "id = " << (const UserID&)*this << ", file = \"" << (const FileSpec&)*this << "\", language = \"" << language << '"';
+}
+
+
+//----------------------------------------------------------------------
+// Dump the current contents of this object. No functions that cause on
+// demand parsing of functions, globals, statics are called, so this
+// is a good function to call to get an idea of the current contents of
+// the CompileUnit object.
+//----------------------------------------------------------------------
+void
+CompileUnit::Dump(Stream *s, bool show_context) const
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ *s << "CompileUnit" << (const UserID&)*this
+ << ", language = \"" << (const Language&)*this
+ << "\", file = '" << (const FileSpec&)*this << "'\n";
+
+// m_types.Dump(s);
+
+ if (m_variables.get())
+ {
+ s->IndentMore();
+ m_variables->Dump(s, show_context);
+ s->IndentLess();
+ }
+
+ if (!m_functions.empty())
+ {
+ s->IndentMore();
+ std::vector<FunctionSP>::const_iterator pos;
+ std::vector<FunctionSP>::const_iterator end = m_functions.end();
+ for (pos = m_functions.begin(); pos != end; ++pos)
+ {
+ (*pos)->Dump(s, show_context);
+ }
+
+ s->IndentLess();
+ s->EOL();
+ }
+}
+
+//----------------------------------------------------------------------
+// Add a function to this compile unit
+//----------------------------------------------------------------------
+void
+CompileUnit::AddFunction(FunctionSP& funcSP)
+{
+ // TODO: order these by address
+ m_functions.push_back(funcSP);
+}
+
+FunctionSP
+CompileUnit::GetFunctionAtIndex (size_t idx)
+{
+ FunctionSP funcSP;
+ if (idx < m_functions.size())
+ funcSP = m_functions[idx];
+ return funcSP;
+}
+
+//----------------------------------------------------------------------
+// Find functions using the a Mangled::Tokens token list. This
+// function currently implements an interative approach designed to find
+// all instances of certain functions. It isn't designed to the the
+// quickest way to lookup functions as it will need to iterate through
+// all functions and see if they match, though it does provide a powerful
+// and context sensitive way to search for all functions with a certain
+// name, all functions in a namespace, or all functions of a template
+// type. See Mangled::Tokens::Parse() comments for more information.
+//
+// The function prototype will need to change to return a list of
+// results. It was originally used to help debug the Mangled class
+// and the Mangled::Tokens::MatchesQuery() function and it currently
+// will print out a list of matching results for the functions that
+// are currently in this compile unit.
+//
+// A FindFunctions method should be called prior to this that takes
+// a regular function name (const char * or ConstString as a parameter)
+// before resorting to this slower but more complete function. The
+// other FindFunctions method should be able to take advantage of any
+// accelerator tables available in the debug information (which is
+// parsed by the SymbolFile parser plug-ins and registered with each
+// Module).
+//----------------------------------------------------------------------
+//void
+//CompileUnit::FindFunctions(const Mangled::Tokens& tokens)
+//{
+// if (!m_functions.empty())
+// {
+// Stream s(stdout);
+// std::vector<FunctionSP>::const_iterator pos;
+// std::vector<FunctionSP>::const_iterator end = m_functions.end();
+// for (pos = m_functions.begin(); pos != end; ++pos)
+// {
+// const ConstString& demangled = (*pos)->Mangled().Demangled();
+// if (demangled)
+// {
+// const Mangled::Tokens& func_tokens = (*pos)->Mangled().GetTokens();
+// if (func_tokens.MatchesQuery (tokens))
+// s << "demangled MATCH found: " << demangled << "\n";
+// }
+// }
+// }
+//}
+
+FunctionSP
+CompileUnit::FindFunctionByUID (lldb::user_id_t func_uid)
+{
+ FunctionSP funcSP;
+ if (!m_functions.empty())
+ {
+ std::vector<FunctionSP>::const_iterator pos;
+ std::vector<FunctionSP>::const_iterator end = m_functions.end();
+ for (pos = m_functions.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetID() == func_uid)
+ {
+ funcSP = *pos;
+ break;
+ }
+ }
+ }
+ return funcSP;
+}
+
+
+lldb::LanguageType
+CompileUnit::GetLanguage()
+{
+ if (m_language == eLanguageTypeUnknown)
+ {
+ if (m_flags.IsClear(flagsParsedLanguage))
+ {
+ m_flags.Set(flagsParsedLanguage);
+ SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ m_language = symbol_vendor->ParseCompileUnitLanguage(sc);
+ }
+ }
+ }
+ return m_language;
+}
+
+LineTable*
+CompileUnit::GetLineTable()
+{
+ if (m_line_table_ap.get() == NULL)
+ {
+ if (m_flags.IsClear(flagsParsedLineTable))
+ {
+ m_flags.Set(flagsParsedLineTable);
+ SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ symbol_vendor->ParseCompileUnitLineTable(sc);
+ }
+ }
+ }
+ return m_line_table_ap.get();
+}
+
+void
+CompileUnit::SetLineTable(LineTable* line_table)
+{
+ if (line_table == NULL)
+ m_flags.Clear(flagsParsedLineTable);
+ else
+ m_flags.Set(flagsParsedLineTable);
+ m_line_table_ap.reset(line_table);
+}
+
+VariableListSP
+CompileUnit::GetVariableList(bool can_create)
+{
+ if (m_variables.get() == NULL && can_create)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ assert(sc.module_sp);
+ sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
+ }
+
+ return m_variables;
+}
+
+uint32_t
+CompileUnit::FindLineEntry (uint32_t start_idx, uint32_t line, const FileSpec* file_spec_ptr, bool exact, LineEntry *line_entry_ptr)
+{
+ uint32_t file_idx = 0;
+
+ if (file_spec_ptr)
+ {
+ file_idx = GetSupportFiles().FindFileIndex (1, *file_spec_ptr, true);
+ if (file_idx == UINT32_MAX)
+ return UINT32_MAX;
+ }
+ else
+ {
+ // All the line table entries actually point to the version of the Compile
+ // Unit that is in the support files (the one at 0 was artifically added.)
+ // So prefer the one further on in the support files if it exists...
+ FileSpecList &support_files = GetSupportFiles();
+ const bool full = true;
+ file_idx = support_files.FindFileIndex (1, support_files.GetFileSpecAtIndex(0), full);
+ if (file_idx == UINT32_MAX)
+ file_idx = 0;
+ }
+ LineTable *line_table = GetLineTable();
+ if (line_table)
+ return line_table->FindLineEntryIndexByFileIndex (start_idx, file_idx, line, exact, line_entry_ptr);
+ return UINT32_MAX;
+}
+
+
+
+
+uint32_t
+CompileUnit::ResolveSymbolContext
+(
+ const FileSpec& file_spec,
+ uint32_t line,
+ bool check_inlines,
+ bool exact,
+ uint32_t resolve_scope,
+ SymbolContextList &sc_list
+)
+{
+ // First find all of the file indexes that match our "file_spec". If
+ // "file_spec" has an empty directory, then only compare the basenames
+ // when finding file indexes
+ std::vector<uint32_t> file_indexes;
+ const bool full_match = file_spec.GetDirectory();
+ bool file_spec_matches_cu_file_spec = FileSpec::Equal(file_spec, *this, full_match);
+
+ // 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);
+ while (file_idx != UINT32_MAX)
+ {
+ file_indexes.push_back (file_idx);
+ file_idx = GetSupportFiles().FindFileIndex (file_idx + 1, file_spec, true);
+ }
+
+ const size_t num_file_indexes = file_indexes.size();
+ if (num_file_indexes == 0)
+ return 0;
+
+ const uint32_t prev_size = sc_list.GetSize();
+
+ SymbolContext sc(GetModule());
+ sc.comp_unit = this;
+
+
+ if (line != 0)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != NULL)
+ {
+ uint32_t found_line;
+ uint32_t line_idx;
+
+ if (num_file_indexes == 1)
+ {
+ // We only have a single support file that matches, so use
+ // the line table function that searches for a line entries
+ // that match a single support file index
+ LineEntry line_entry;
+ line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes.front(), line, exact, &line_entry);
+
+ // If "exact == true", then "found_line" will be the same
+ // as "line". If "exact == false", the "found_line" will be the
+ // closest line entry with a line number greater than "line" and
+ // we will use this for our subsequent line exact matches below.
+ found_line = line_entry.line;
+
+ while (line_idx != UINT32_MAX)
+ {
+ // If they only asked for the line entry, then we're done, we can just copy that over.
+ // But if they wanted more than just the line number, fill it in.
+ if (resolve_scope == eSymbolContextLineEntry)
+ {
+ sc.line_entry = line_entry;
+ }
+ else
+ {
+ line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes.front(), found_line, true, &line_entry);
+ }
+ }
+ else
+ {
+ // We found multiple support files that match "file_spec" so use
+ // the line table function that searches for a line entries
+ // that match a multiple support file indexes.
+ LineEntry line_entry;
+ line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_indexes, line, exact, &line_entry);
+
+ // If "exact == true", then "found_line" will be the same
+ // as "line". If "exact == false", the "found_line" will be the
+ // closest line entry with a line number greater than "line" and
+ // we will use this for our subsequent line exact matches below.
+ found_line = line_entry.line;
+
+ while (line_idx != UINT32_MAX)
+ {
+ if (resolve_scope == eSymbolContextLineEntry)
+ {
+ sc.line_entry = line_entry;
+ }
+ else
+ {
+ line_entry.range.GetBaseAddress().CalculateSymbolContext(&sc, resolve_scope);
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_indexes, found_line, true, &line_entry);
+ }
+ }
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+void
+CompileUnit::SetVariableList(VariableListSP &variables)
+{
+ m_variables = variables;
+}
+
+FileSpecList&
+CompileUnit::GetSupportFiles ()
+{
+ if (m_support_files.GetSize() == 0)
+ {
+ if (m_flags.IsClear(flagsParsedSupportFiles))
+ {
+ m_flags.Set(flagsParsedSupportFiles);
+ SymbolVendor* symbol_vendor = GetModule()->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ symbol_vendor->ParseCompileUnitSupportFiles(sc, m_support_files);
+ }
+ }
+ }
+ return m_support_files;
+}
+
+void *
+CompileUnit::GetUserData () const
+{
+ return m_user_data;
+}
+
+
diff --git a/source/Symbol/DWARFCallFrameInfo.cpp b/source/Symbol/DWARFCallFrameInfo.cpp
new file mode 100644
index 000000000000..e8f99a980116
--- /dev/null
+++ b/source/Symbol/DWARFCallFrameInfo.cpp
@@ -0,0 +1,815 @@
+//===-- DWARFCallFrameInfo.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 <list>
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DWARFCallFrameInfo::DWARFCallFrameInfo(ObjectFile& objfile, SectionSP& section_sp, lldb::RegisterKind reg_kind, bool is_eh_frame) :
+ m_objfile (objfile),
+ m_section_sp (section_sp),
+ m_reg_kind (reg_kind), // The flavor of registers that the CFI data uses (enum RegisterKind)
+ m_flags (),
+ m_cie_map (),
+ m_cfi_data (),
+ m_cfi_data_initialized (false),
+ m_fde_index (),
+ m_fde_index_initialized (false),
+ m_is_eh_frame (is_eh_frame)
+{
+}
+
+DWARFCallFrameInfo::~DWARFCallFrameInfo()
+{
+}
+
+
+bool
+DWARFCallFrameInfo::GetUnwindPlan (Address addr, UnwindPlan& unwind_plan)
+{
+ FDEEntryMap::Entry fde_entry;
+
+ // Make sure that the Address we're searching for is the same object file
+ // as this DWARFCallFrameInfo, we only store File offsets in m_fde_index.
+ ModuleSP module_sp = addr.GetModule();
+ if (module_sp.get() == NULL || module_sp->GetObjectFile() == NULL || module_sp->GetObjectFile() != &m_objfile)
+ return false;
+
+ if (GetFDEEntryByFileAddress (addr.GetFileAddress(), fde_entry) == false)
+ return false;
+ return FDEToUnwindPlan (fde_entry.data, addr, unwind_plan);
+}
+
+bool
+DWARFCallFrameInfo::GetAddressRange (Address addr, AddressRange &range)
+{
+
+ // Make sure that the Address we're searching for is the same object file
+ // as this DWARFCallFrameInfo, we only store File offsets in m_fde_index.
+ ModuleSP module_sp = addr.GetModule();
+ if (module_sp.get() == NULL || module_sp->GetObjectFile() == NULL || module_sp->GetObjectFile() != &m_objfile)
+ return false;
+
+ if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ return false;
+ GetFDEIndex();
+ FDEEntryMap::Entry *fde_entry = m_fde_index.FindEntryThatContains (addr.GetFileAddress());
+ if (!fde_entry)
+ return false;
+
+ range = AddressRange(fde_entry->base, fde_entry->size, m_objfile.GetSectionList());
+ return true;
+}
+
+bool
+DWARFCallFrameInfo::GetFDEEntryByFileAddress (addr_t file_addr, FDEEntryMap::Entry &fde_entry)
+{
+ if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ return false;
+
+ GetFDEIndex();
+
+ if (m_fde_index.IsEmpty())
+ return false;
+
+ FDEEntryMap::Entry *fde = m_fde_index.FindEntryThatContains (file_addr);
+
+ if (fde == NULL)
+ return false;
+
+ fde_entry = *fde;
+ return true;
+}
+
+void
+DWARFCallFrameInfo::GetFunctionAddressAndSizeVector (FunctionAddressAndSizeVector &function_info)
+{
+ GetFDEIndex();
+ const size_t count = m_fde_index.GetSize();
+ function_info.Clear();
+ if (count > 0)
+ function_info.Reserve(count);
+ for (size_t i = 0; i < count; ++i)
+ {
+ const FDEEntryMap::Entry *func_offset_data_entry = m_fde_index.GetEntryAtIndex (i);
+ if (func_offset_data_entry)
+ {
+ FunctionAddressAndSizeVector::Entry function_offset_entry (func_offset_data_entry->base, func_offset_data_entry->size);
+ function_info.Append (function_offset_entry);
+ }
+ }
+}
+
+const DWARFCallFrameInfo::CIE*
+DWARFCallFrameInfo::GetCIE(dw_offset_t cie_offset)
+{
+ cie_map_t::iterator pos = m_cie_map.find(cie_offset);
+
+ if (pos != m_cie_map.end())
+ {
+ // Parse and cache the CIE
+ if (pos->second.get() == NULL)
+ pos->second = ParseCIE (cie_offset);
+
+ return pos->second.get();
+ }
+ return NULL;
+}
+
+DWARFCallFrameInfo::CIESP
+DWARFCallFrameInfo::ParseCIE (const dw_offset_t cie_offset)
+{
+ CIESP cie_sp(new CIE(cie_offset));
+ lldb::offset_t offset = cie_offset;
+ if (m_cfi_data_initialized == false)
+ GetCFIData();
+ const uint32_t length = m_cfi_data.GetU32(&offset);
+ const dw_offset_t cie_id = m_cfi_data.GetU32(&offset);
+ const dw_offset_t end_offset = cie_offset + length + 4;
+ if (length > 0 && ((!m_is_eh_frame && cie_id == UINT32_MAX) || (m_is_eh_frame && cie_id == 0ul)))
+ {
+ size_t i;
+ // cie.offset = cie_offset;
+ // cie.length = length;
+ // cie.cieID = cieID;
+ cie_sp->ptr_encoding = DW_EH_PE_absptr; // default
+ cie_sp->version = m_cfi_data.GetU8(&offset);
+
+ for (i=0; i<CFI_AUG_MAX_SIZE; ++i)
+ {
+ cie_sp->augmentation[i] = m_cfi_data.GetU8(&offset);
+ if (cie_sp->augmentation[i] == '\0')
+ {
+ // Zero out remaining bytes in augmentation string
+ for (size_t j = i+1; j<CFI_AUG_MAX_SIZE; ++j)
+ cie_sp->augmentation[j] = '\0';
+
+ break;
+ }
+ }
+
+ if (i == CFI_AUG_MAX_SIZE && cie_sp->augmentation[CFI_AUG_MAX_SIZE-1] != '\0')
+ {
+ Host::SystemLog (Host::eSystemLogError, "CIE parse error: CIE augmentation string was too large for the fixed sized buffer of %d bytes.\n", CFI_AUG_MAX_SIZE);
+ return cie_sp;
+ }
+ cie_sp->code_align = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ cie_sp->data_align = (int32_t)m_cfi_data.GetSLEB128(&offset);
+ cie_sp->return_addr_reg_num = m_cfi_data.GetU8(&offset);
+
+ if (cie_sp->augmentation[0])
+ {
+ // Get the length of the eh_frame augmentation data
+ // which starts with a ULEB128 length in bytes
+ const size_t aug_data_len = (size_t)m_cfi_data.GetULEB128(&offset);
+ const size_t aug_data_end = offset + aug_data_len;
+ const size_t aug_str_len = strlen(cie_sp->augmentation);
+ // A 'z' may be present as the first character of the string.
+ // If present, the Augmentation Data field shall be present.
+ // The contents of the Augmentation Data shall be intepreted
+ // according to other characters in the Augmentation String.
+ if (cie_sp->augmentation[0] == 'z')
+ {
+ // Extract the Augmentation Data
+ size_t aug_str_idx = 0;
+ for (aug_str_idx = 1; aug_str_idx < aug_str_len; aug_str_idx++)
+ {
+ char aug = cie_sp->augmentation[aug_str_idx];
+ switch (aug)
+ {
+ case 'L':
+ // Indicates the presence of one argument in the
+ // Augmentation Data of the CIE, and a corresponding
+ // argument in the Augmentation Data of the FDE. The
+ // argument in the Augmentation Data of the CIE is
+ // 1-byte and represents the pointer encoding used
+ // for the argument in the Augmentation Data of the
+ // 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);
+ break;
+
+ case 'P':
+ // Indicates the presence of two arguments in the
+ // Augmentation Data of the cie_sp-> 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.
+ {
+ 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);
+ }
+ break;
+
+ case 'R':
+ // A 'R' may be present at any position after the
+ // first character of the string. The Augmentation
+ // Data shall include a 1 byte argument that
+ // represents the pointer encoding for the address
+ // pointers used in the FDE.
+ // Example: 0x1B == DW_EH_PE_pcrel | DW_EH_PE_sdata4
+ cie_sp->ptr_encoding = m_cfi_data.GetU8(&offset);
+ break;
+ }
+ }
+ }
+ else if (strcmp(cie_sp->augmentation, "eh") == 0)
+ {
+ // If the Augmentation string has the value "eh", then
+ // the EH Data field shall be present
+ }
+
+ // Set the offset to be the end of the augmentation data just in case
+ // we didn't understand any of the data.
+ offset = (uint32_t)aug_data_end;
+ }
+
+ if (end_offset > offset)
+ {
+ cie_sp->inst_offset = offset;
+ cie_sp->inst_length = end_offset - offset;
+ }
+ while (offset < end_offset)
+ {
+ uint8_t inst = m_cfi_data.GetU8(&offset);
+ uint8_t primary_opcode = inst & 0xC0;
+ uint8_t extended_opcode = inst & 0x3F;
+
+ if (extended_opcode == DW_CFA_def_cfa)
+ {
+ // Takes two unsigned LEB128 operands representing a register
+ // number and a (non-factored) offset. The required action
+ // is to define the current CFA rule to use the provided
+ // register and offset.
+ uint32_t reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ cie_sp->initial_row.SetCFARegister (reg_num);
+ cie_sp->initial_row.SetCFAOffset (op_offset);
+ continue;
+ }
+ if (primary_opcode == DW_CFA_offset)
+ {
+ // 0x80 - high 2 bits are 0x2, lower 6 bits are register.
+ // Takes two arguments: an unsigned LEB128 constant representing a
+ // factored offset and a register number. The required action is to
+ // change the rule for the register indicated by the register number
+ // to be an offset(N) rule with a value of
+ // (N = factored offset * data_align).
+ uint32_t reg_num = extended_opcode;
+ int op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * cie_sp->data_align;
+ UnwindPlan::Row::RegisterLocation reg_location;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ cie_sp->initial_row.SetRegisterInfo (reg_num, reg_location);
+ continue;
+ }
+ if (extended_opcode == DW_CFA_nop)
+ {
+ continue;
+ }
+ break; // Stop if we hit an unrecognized opcode
+ }
+ }
+
+ return cie_sp;
+}
+
+void
+DWARFCallFrameInfo::GetCFIData()
+{
+ if (m_cfi_data_initialized == false)
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ m_objfile.GetModule()->LogMessage(log, "Reading EH frame info");
+ m_objfile.ReadSectionData (m_section_sp.get(), m_cfi_data);
+ m_cfi_data_initialized = true;
+ }
+}
+// Scan through the eh_frame or debug_frame section looking for FDEs and noting the start/end addresses
+// of the functions and a pointer back to the function's FDE for later expansion.
+// Internalize CIEs as we come across them.
+
+void
+DWARFCallFrameInfo::GetFDEIndex ()
+{
+ if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ return;
+
+ if (m_fde_index_initialized)
+ return;
+
+ Mutex::Locker locker(m_fde_index_mutex);
+
+ if (m_fde_index_initialized) // if two threads hit the locker
+ return;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s - %s", __PRETTY_FUNCTION__, m_objfile.GetFileSpec().GetFilename().AsCString(""));
+
+ lldb::offset_t offset = 0;
+ if (m_cfi_data_initialized == false)
+ GetCFIData();
+ while (m_cfi_data.ValidOffsetForDataOfSize (offset, 8))
+ {
+ const dw_offset_t current_entry = offset;
+ uint32_t len = m_cfi_data.GetU32 (&offset);
+ dw_offset_t next_entry = current_entry + len + 4;
+ dw_offset_t cie_id = m_cfi_data.GetU32 (&offset);
+
+ if (cie_id == 0 || cie_id == UINT32_MAX)
+ {
+ m_cie_map[current_entry] = ParseCIE (current_entry);
+ offset = next_entry;
+ continue;
+ }
+
+ const dw_offset_t cie_offset = current_entry + 4 - cie_id;
+ const CIE *cie = GetCIE (cie_offset);
+ if (cie)
+ {
+ const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
+ const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
+ const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
+
+ lldb::addr_t addr = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
+ lldb::addr_t length = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+ FDEEntryMap::Entry fde (addr, length, current_entry);
+ m_fde_index.Append(fde);
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "error: unable to find CIE at 0x%8.8x for cie_id = 0x%8.8x for entry at 0x%8.8x.\n",
+ cie_offset,
+ cie_id,
+ current_entry);
+ }
+ offset = next_entry;
+ }
+ m_fde_index.Sort();
+ m_fde_index_initialized = true;
+}
+
+bool
+DWARFCallFrameInfo::FDEToUnwindPlan (dw_offset_t dwarf_offset, Address startaddr, UnwindPlan& unwind_plan)
+{
+ lldb::offset_t offset = dwarf_offset;
+ lldb::offset_t current_entry = offset;
+
+ if (m_section_sp.get() == NULL || m_section_sp->IsEncrypted())
+ return false;
+
+ if (m_cfi_data_initialized == false)
+ GetCFIData();
+
+ uint32_t length = m_cfi_data.GetU32 (&offset);
+ dw_offset_t cie_offset = m_cfi_data.GetU32 (&offset);
+
+ assert (cie_offset != 0 && cie_offset != UINT32_MAX);
+
+ // Translate the CIE_id from the eh_frame format, which
+ // is relative to the FDE offset, into a __eh_frame section
+ // offset
+ if (m_is_eh_frame)
+ {
+ unwind_plan.SetSourceName ("eh_frame CFI");
+ cie_offset = current_entry + 4 - cie_offset;
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ }
+ else
+ {
+ unwind_plan.SetSourceName ("DWARF CFI");
+ // In theory the debug_frame info should be valid at all call sites
+ // ("asynchronous unwind info" as it is sometimes called) but in practice
+ // gcc et al all emit call frame info for the prologue and call sites, but
+ // not for the epilogue or all the other locations during the function reliably.
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ }
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolYes);
+
+ const CIE *cie = GetCIE (cie_offset);
+ assert (cie != NULL);
+
+ const dw_offset_t end_offset = current_entry + length + 4;
+
+ const lldb::addr_t pc_rel_addr = m_section_sp->GetFileAddress();
+ const lldb::addr_t text_addr = LLDB_INVALID_ADDRESS;
+ const lldb::addr_t data_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t range_base = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding, pc_rel_addr, text_addr, data_addr);
+ lldb::addr_t range_len = m_cfi_data.GetGNUEHPointer(&offset, cie->ptr_encoding & DW_EH_PE_MASK_ENCODING, pc_rel_addr, text_addr, data_addr);
+ AddressRange range (range_base, m_objfile.GetAddressByteSize(), m_objfile.GetSectionList());
+ range.SetByteSize (range_len);
+
+ if (cie->augmentation[0] == 'z')
+ {
+ uint32_t aug_data_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ offset += aug_data_len;
+ }
+
+ uint32_t reg_num = 0;
+ int32_t op_offset = 0;
+ uint32_t code_align = cie->code_align;
+ int32_t data_align = cie->data_align;
+
+ unwind_plan.SetPlanValidAddressRange (range);
+ UnwindPlan::Row *cie_initial_row = new UnwindPlan::Row;
+ *cie_initial_row = cie->initial_row;
+ UnwindPlan::RowSP row(cie_initial_row);
+
+ unwind_plan.SetRegisterKind (m_reg_kind);
+ unwind_plan.SetReturnAddressRegister (cie->return_addr_reg_num);
+
+ UnwindPlan::Row::RegisterLocation reg_location;
+ while (m_cfi_data.ValidOffset(offset) && offset < end_offset)
+ {
+ uint8_t inst = m_cfi_data.GetU8(&offset);
+ uint8_t primary_opcode = inst & 0xC0;
+ uint8_t extended_opcode = inst & 0x3F;
+
+ if (primary_opcode)
+ {
+ switch (primary_opcode)
+ {
+ case DW_CFA_advance_loc : // (Row Creation Instruction)
+ { // 0x40 - high 2 bits are 0x1, lower 6 bits are delta
+ // takes a single argument that represents a constant delta. The
+ // required action is to create a new table row with a location
+ // value that is computed by taking the current entry's location
+ // value and adding (delta * code_align). All other
+ // values in the new row are initially identical to the current row.
+ unwind_plan.AppendRow(row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ row->SlideOffset(extended_opcode * code_align);
+ }
+ break;
+
+ case DW_CFA_offset :
+ { // 0x80 - high 2 bits are 0x2, lower 6 bits are register
+ // takes two arguments: an unsigned LEB128 constant representing a
+ // factored offset and a register number. The required action is to
+ // change the rule for the register indicated by the register number
+ // to be an offset(N) rule with a value of
+ // (N = factored offset * data_align).
+ reg_num = extended_opcode;
+ op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_restore :
+ { // 0xC0 - high 2 bits are 0x3, lower 6 bits are register
+ // takes a single argument that represents a register number. The
+ // required action is to change the rule for the indicated register
+ // to the rule assigned it by the initial_instructions in the CIE.
+ reg_num = extended_opcode;
+ // We only keep enough register locations around to
+ // unwind what is in our thread, and these are organized
+ // by the register index in that state, so we need to convert our
+ // GCC register number from the EH frame info, to a register index
+
+ if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch (extended_opcode)
+ {
+ case DW_CFA_nop : // 0x0
+ break;
+
+ case DW_CFA_set_loc : // 0x1 (Row Creation Instruction)
+ {
+ // DW_CFA_set_loc takes a single argument that represents an address.
+ // The required action is to create a new table row using the
+ // specified address as the location. All other values in the new row
+ // are initially identical to the current row. The new location value
+ // should always be greater than the current one.
+ unwind_plan.AppendRow(row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ row->SetOffset(m_cfi_data.GetPointer(&offset) - startaddr.GetFileAddress());
+ }
+ break;
+
+ case DW_CFA_advance_loc1 : // 0x2 (Row Creation Instruction)
+ {
+ // takes a single uword argument that represents a constant delta.
+ // This instruction is identical to DW_CFA_advance_loc except for the
+ // encoding and size of the delta argument.
+ unwind_plan.AppendRow(row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ row->SlideOffset (m_cfi_data.GetU8(&offset) * code_align);
+ }
+ break;
+
+ case DW_CFA_advance_loc2 : // 0x3 (Row Creation Instruction)
+ {
+ // takes a single uword argument that represents a constant delta.
+ // This instruction is identical to DW_CFA_advance_loc except for the
+ // encoding and size of the delta argument.
+ unwind_plan.AppendRow(row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ row->SlideOffset (m_cfi_data.GetU16(&offset) * code_align);
+ }
+ break;
+
+ case DW_CFA_advance_loc4 : // 0x4 (Row Creation Instruction)
+ {
+ // takes a single uword argument that represents a constant delta.
+ // This instruction is identical to DW_CFA_advance_loc except for the
+ // encoding and size of the delta argument.
+ unwind_plan.AppendRow(row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ row->SlideOffset (m_cfi_data.GetU32(&offset) * code_align);
+ }
+ break;
+
+ case DW_CFA_offset_extended : // 0x5
+ {
+ // takes two unsigned LEB128 arguments representing a register number
+ // and a factored offset. This instruction is identical to DW_CFA_offset
+ // except for the encoding and size of the register argument.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ op_offset = (int32_t)m_cfi_data.GetULEB128(&offset) * data_align;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_restore_extended : // 0x6
+ {
+ // takes a single unsigned LEB128 argument that represents a register
+ // number. This instruction is identical to DW_CFA_restore except for
+ // the encoding and size of the register argument.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ if (unwind_plan.IsValidRowIndex(0) && unwind_plan.GetRowAtIndex(0)->GetRegisterInfo(reg_num, reg_location))
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_undefined : // 0x7
+ {
+ // takes a single unsigned LEB128 argument that represents a register
+ // number. The required action is to set the rule for the specified
+ // register to undefined.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ reg_location.SetUndefined();
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_same_value : // 0x8
+ {
+ // takes a single unsigned LEB128 argument that represents a register
+ // number. The required action is to set the rule for the specified
+ // register to same value.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ reg_location.SetSame();
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_register : // 0x9
+ {
+ // takes two unsigned LEB128 arguments representing register numbers.
+ // The required action is to set the rule for the first register to be
+ // the second register.
+
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t other_reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ reg_location.SetInRegister(other_reg_num);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_remember_state : // 0xA
+ {
+ // These instructions define a stack of information. Encountering the
+ // DW_CFA_remember_state instruction means to save the rules for every
+ // register on the current row on the stack. Encountering the
+ // DW_CFA_restore_state instruction means to pop the set of rules off
+ // the stack and place them in the current row. (This operation is
+ // useful for compilers that move epilogue code into the body of a
+ // function.)
+ unwind_plan.AppendRow (row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset (newrow);
+ }
+ break;
+
+ case DW_CFA_restore_state : // 0xB
+ // These instructions define a stack of information. Encountering the
+ // DW_CFA_remember_state instruction means to save the rules for every
+ // register on the current row on the stack. Encountering the
+ // DW_CFA_restore_state instruction means to pop the set of rules off
+ // the stack and place them in the current row. (This operation is
+ // useful for compilers that move epilogue code into the body of a
+ // function.)
+ {
+ row = unwind_plan.GetRowAtIndex(unwind_plan.GetRowCount() - 1);
+ }
+ break;
+
+ case DW_CFA_def_cfa : // 0xC (CFA Definition Instruction)
+ {
+ // Takes two unsigned LEB128 operands representing a register
+ // number and a (non-factored) offset. The required action
+ // is to define the current CFA rule to use the provided
+ // register and offset.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ row->SetCFARegister (reg_num);
+ row->SetCFAOffset (op_offset);
+ }
+ break;
+
+ case DW_CFA_def_cfa_register : // 0xD (CFA Definition Instruction)
+ {
+ // takes a single unsigned LEB128 argument representing a register
+ // number. The required action is to define the current CFA rule to
+ // use the provided register (but to keep the old offset).
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ row->SetCFARegister (reg_num);
+ }
+ break;
+
+ case DW_CFA_def_cfa_offset : // 0xE (CFA Definition Instruction)
+ {
+ // Takes a single unsigned LEB128 operand representing a
+ // (non-factored) offset. The required action is to define
+ // the current CFA rule to use the provided offset (but
+ // to keep the old register).
+ op_offset = (int32_t)m_cfi_data.GetULEB128(&offset);
+ row->SetCFAOffset (op_offset);
+ }
+ break;
+
+ case DW_CFA_def_cfa_expression : // 0xF (CFA Definition Instruction)
+ {
+ size_t block_len = (size_t)m_cfi_data.GetULEB128(&offset);
+ offset += (uint32_t)block_len;
+ }
+ break;
+
+ case DW_CFA_expression : // 0x10
+ {
+ // Takes two operands: an unsigned LEB128 value representing
+ // a register number, and a DW_FORM_block value representing a DWARF
+ // expression. The required action is to change the rule for the
+ // register indicated by the register number to be an expression(E)
+ // rule where E is the DWARF expression. That is, the DWARF
+ // expression computes the address. The value of the CFA is
+ // pushed on the DWARF evaluation stack prior to execution of
+ // the DWARF expression.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ const uint8_t *block_data = (uint8_t *)m_cfi_data.GetData(&offset, block_len);
+
+ reg_location.SetAtDWARFExpression(block_data, block_len);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_offset_extended_sf : // 0x11
+ {
+ // takes two operands: an unsigned LEB128 value representing a
+ // register number and a signed LEB128 factored offset. This
+ // instruction is identical to DW_CFA_offset_extended except
+ //that the second operand is signed and factored.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ reg_location.SetAtCFAPlusOffset(op_offset);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_def_cfa_sf : // 0x12 (CFA Definition Instruction)
+ {
+ // Takes two operands: an unsigned LEB128 value representing
+ // a register number and a signed LEB128 factored offset.
+ // This instruction is identical to DW_CFA_def_cfa except
+ // that the second operand is signed and factored.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ row->SetCFARegister (reg_num);
+ row->SetCFAOffset (op_offset);
+ }
+ break;
+
+ case DW_CFA_def_cfa_offset_sf : // 0x13 (CFA Definition Instruction)
+ {
+ // takes a signed LEB128 operand representing a factored
+ // offset. This instruction is identical to DW_CFA_def_cfa_offset
+ // except that the operand is signed and factored.
+ op_offset = (int32_t)m_cfi_data.GetSLEB128(&offset) * data_align;
+ row->SetCFAOffset (op_offset);
+ }
+ break;
+
+ case DW_CFA_val_expression : // 0x16
+ {
+ // takes two operands: an unsigned LEB128 value representing a register
+ // number, and a DW_FORM_block value representing a DWARF expression.
+ // The required action is to change the rule for the register indicated
+ // by the register number to be a val_expression(E) rule where E is the
+ // DWARF expression. That is, the DWARF expression computes the value of
+ // the given register. The value of the CFA is pushed on the DWARF
+ // evaluation stack prior to execution of the DWARF expression.
+ reg_num = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ uint32_t block_len = (uint32_t)m_cfi_data.GetULEB128(&offset);
+ const uint8_t* block_data = (uint8_t*)m_cfi_data.GetData(&offset, block_len);
+//#if defined(__i386__) || defined(__x86_64__)
+// // The EH frame info for EIP and RIP contains code that looks for traps to
+// // be a specific type and increments the PC.
+// // For i386:
+// // DW_CFA_val_expression where:
+// // eip = DW_OP_breg6(+28), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x34),
+// // DW_OP_deref, DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref,
+// // DW_OP_dup, DW_OP_lit3, DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne,
+// // DW_OP_and, DW_OP_plus
+// // This basically does a:
+// // eip = ucontenxt.mcontext32->gpr.eip;
+// // if (ucontenxt.mcontext32->exc.trapno != 3 && ucontenxt.mcontext32->exc.trapno != 4)
+// // eip++;
+// //
+// // For x86_64:
+// // DW_CFA_val_expression where:
+// // rip = DW_OP_breg3(+48), DW_OP_deref, DW_OP_dup, DW_OP_plus_uconst(0x90), DW_OP_deref,
+// // DW_OP_swap, DW_OP_plus_uconst(0), DW_OP_deref_size(4), DW_OP_dup, DW_OP_lit3,
+// // DW_OP_ne, DW_OP_swap, DW_OP_lit4, DW_OP_ne, DW_OP_and, DW_OP_plus
+// // This basically does a:
+// // rip = ucontenxt.mcontext64->gpr.rip;
+// // if (ucontenxt.mcontext64->exc.trapno != 3 && ucontenxt.mcontext64->exc.trapno != 4)
+// // rip++;
+// // The trap comparisons and increments are not needed as it hoses up the unwound PC which
+// // is expected to point at least past the instruction that causes the fault/trap. So we
+// // take it out by trimming the expression right at the first "DW_OP_swap" opcodes
+// if (block_data != NULL && thread->GetPCRegNum(Thread::GCC) == reg_num)
+// {
+// if (thread->Is64Bit())
+// {
+// if (block_len > 9 && block_data[8] == DW_OP_swap && block_data[9] == DW_OP_plus_uconst)
+// block_len = 8;
+// }
+// else
+// {
+// if (block_len > 8 && block_data[7] == DW_OP_swap && block_data[8] == DW_OP_plus_uconst)
+// block_len = 7;
+// }
+// }
+//#endif
+ reg_location.SetIsDWARFExpression(block_data, block_len);
+ row->SetRegisterInfo (reg_num, reg_location);
+ }
+ break;
+
+ case DW_CFA_val_offset : // 0x14
+ case DW_CFA_val_offset_sf : // 0x15
+ default:
+ break;
+ }
+ }
+ }
+ unwind_plan.AppendRow(row);
+
+ return true;
+}
diff --git a/source/Symbol/Declaration.cpp b/source/Symbol/Declaration.cpp
new file mode 100644
index 000000000000..3943f02c5474
--- /dev/null
+++ b/source/Symbol/Declaration.cpp
@@ -0,0 +1,117 @@
+//===-- Declaration.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/Symbol/Declaration.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+
+void
+Declaration::Dump(Stream *s, bool show_fullpaths) const
+{
+ if (m_file)
+ {
+ *s << ", decl = ";
+ if (show_fullpaths)
+ *s << m_file;
+ else
+ *s << m_file.GetFilename();
+ if (m_line > 0)
+ s->Printf(":%u", m_line);
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+#endif
+ }
+ else
+ {
+ if (m_line > 0)
+ {
+ s->Printf(", line = %u", m_line);
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+#endif
+ }
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ else if (m_column > 0)
+ s->Printf(", column = %u", m_column);
+#endif
+ }
+}
+
+bool
+Declaration::DumpStopContext (Stream *s, bool show_fullpaths) const
+{
+ if (m_file)
+ {
+ if (show_fullpaths || s->GetVerbose())
+ *s << m_file;
+ else
+ m_file.GetFilename().Dump(s);
+
+ if (m_line > 0)
+ s->Printf(":%u", m_line);
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+#endif
+ return true;
+ }
+ else if (m_line > 0)
+ {
+ s->Printf(" line %u", m_line);
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (m_column > 0)
+ s->Printf(":%u", m_column);
+#endif
+ return true;
+ }
+ return false;
+}
+
+size_t
+Declaration::MemorySize() const
+{
+ return sizeof(Declaration);
+}
+
+int
+Declaration::Compare(const Declaration& a, const Declaration& b)
+{
+ int result = FileSpec::Compare(a.m_file, b.m_file, true);
+ if (result)
+ return result;
+ if (a.m_line < b.m_line)
+ return -1;
+ else if (a.m_line > b.m_line)
+ return 1;
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (a.m_column < b.m_column)
+ return -1;
+ else if (a.m_column > b.m_column)
+ return 1;
+#endif
+ return 0;
+}
+
+bool
+lldb_private::operator == (const Declaration &lhs, const Declaration &rhs)
+{
+#ifdef LLDB_ENABLE_DECLARATION_COLUMNS
+ if (lhs.GetColumn () == rhs.GetColumn ())
+ if (lhs.GetLine () == rhs.GetLine ())
+ return lhs.GetFile() == rhs.GetFile();
+#else
+ if (lhs.GetLine () == rhs.GetLine ())
+ return lhs.GetFile() == rhs.GetFile();
+#endif
+ return false;
+}
+
diff --git a/source/Symbol/FuncUnwinders.cpp b/source/Symbol/FuncUnwinders.cpp
new file mode 100644
index 000000000000..3de06179ee07
--- /dev/null
+++ b/source/Symbol/FuncUnwinders.cpp
@@ -0,0 +1,247 @@
+//===-- FuncUnwinders.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/AddressRange.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/UnwindTable.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+FuncUnwinders::FuncUnwinders
+(
+ UnwindTable& unwind_table,
+ UnwindAssembly *assembly_profiler,
+ AddressRange range
+) :
+ m_unwind_table(unwind_table),
+ m_assembly_profiler(assembly_profiler),
+ m_range(range),
+ m_mutex (Mutex::eMutexTypeNormal),
+ m_unwind_plan_call_site_sp (),
+ m_unwind_plan_non_call_site_sp (),
+ 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_tried_unwind_fast (false),
+ m_tried_unwind_arch_default (false),
+ m_tried_unwind_arch_default_at_func_entry (false),
+ m_first_non_prologue_insn()
+{
+}
+
+FuncUnwinders::~FuncUnwinders ()
+{
+}
+
+UnwindPlanSP
+FuncUnwinders::GetUnwindPlanAtCallSite (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() == NULL)
+ {
+ 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);
+
+ DWARFCallFrameInfo *eh_frame = m_unwind_table.GetEHFrameInfo();
+ if (eh_frame)
+ {
+ 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();
+ }
+ }
+ }
+ return m_unwind_plan_call_site_sp;
+}
+
+UnwindPlanSP
+FuncUnwinders::GetUnwindPlanAtNonCallSite (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 (...)
+ Mutex::Locker locker (m_mutex);
+ if (m_tried_unwind_at_non_call_site == false && m_unwind_plan_non_call_site_sp.get() == NULL)
+ {
+ m_tried_unwind_at_non_call_site = true;
+ m_unwind_plan_non_call_site_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!m_assembly_profiler->GetNonCallSiteUnwindPlanFromAssembly (m_range, thread, *m_unwind_plan_non_call_site_sp))
+ m_unwind_plan_non_call_site_sp.reset();
+ }
+ return m_unwind_plan_non_call_site_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 (...)
+ Mutex::Locker locker (m_mutex);
+ if (m_tried_unwind_fast == false && m_unwind_plan_fast_sp.get() == NULL)
+ {
+ m_tried_unwind_fast = true;
+ m_unwind_plan_fast_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ if (!m_assembly_profiler->GetFastUnwindPlan (m_range, thread, *m_unwind_plan_fast_sp))
+ m_unwind_plan_fast_sp.reset();
+ }
+ return m_unwind_plan_fast_sp;
+}
+
+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 (...)
+ Mutex::Locker locker (m_mutex);
+ if (m_tried_unwind_arch_default == false && m_unwind_plan_arch_default_sp.get() == NULL)
+ {
+ 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)
+ {
+ 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);
+ }
+ }
+ }
+
+ return m_unwind_plan_arch_default_sp;
+}
+
+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 (...)
+ Mutex::Locker locker (m_mutex);
+ if (m_tried_unwind_arch_default_at_func_entry == false && m_unwind_plan_arch_default_at_func_entry_sp.get() == NULL)
+ {
+ 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)
+ {
+ 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);
+ }
+ }
+ }
+
+ return m_unwind_plan_arch_default_sp;
+}
+
+
+Address&
+FuncUnwinders::GetFirstNonPrologueInsn (Target& target)
+{
+ if (m_first_non_prologue_insn.IsValid())
+ return m_first_non_prologue_insn;
+ ExecutionContext exe_ctx (target.shared_from_this(), false);
+ m_assembly_profiler->FirstNonPrologueInsn (m_range, exe_ctx, m_first_non_prologue_insn);
+ return m_first_non_prologue_insn;
+}
+
+const Address&
+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;
+ }
+}
diff --git a/source/Symbol/Function.cpp b/source/Symbol/Function.cpp
new file mode 100644
index 000000000000..31334a6df8d7
--- /dev/null
+++ b/source/Symbol/Function.cpp
@@ -0,0 +1,572 @@
+//===-- Function.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/Symbol/Function.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "llvm/Support/Casting.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Basic function information is contained in the FunctionInfo class.
+// It is designed to contain the name, linkage name, and declaration
+// location.
+//----------------------------------------------------------------------
+FunctionInfo::FunctionInfo (const char *name, const Declaration *decl_ptr) :
+ m_name(name),
+ m_declaration(decl_ptr)
+{
+}
+
+
+FunctionInfo::FunctionInfo (const ConstString& name, const Declaration *decl_ptr) :
+ m_name(name),
+ m_declaration(decl_ptr)
+{
+}
+
+
+FunctionInfo::~FunctionInfo()
+{
+}
+
+void
+FunctionInfo::Dump(Stream *s, bool show_fullpaths) const
+{
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+ m_declaration.Dump(s, show_fullpaths);
+}
+
+
+int
+FunctionInfo::Compare(const FunctionInfo& a, const FunctionInfo& b)
+{
+ int result = ConstString::Compare(a.GetName(), b.GetName());
+ if (result)
+ return result;
+
+ return Declaration::Compare(a.m_declaration, b.m_declaration);
+}
+
+
+Declaration&
+FunctionInfo::GetDeclaration()
+{
+ return m_declaration;
+}
+
+const Declaration&
+FunctionInfo::GetDeclaration() const
+{
+ return m_declaration;
+}
+
+const ConstString&
+FunctionInfo::GetName() const
+{
+ return m_name;
+}
+
+size_t
+FunctionInfo::MemorySize() const
+{
+ return m_name.MemorySize() + m_declaration.MemorySize();
+}
+
+
+InlineFunctionInfo::InlineFunctionInfo
+(
+ const char *name,
+ const char *mangled,
+ const Declaration *decl_ptr,
+ const Declaration *call_decl_ptr
+) :
+ FunctionInfo(name, decl_ptr),
+ m_mangled(ConstString(mangled), true),
+ m_call_decl (call_decl_ptr)
+{
+}
+
+InlineFunctionInfo::InlineFunctionInfo
+(
+ const ConstString& name,
+ const Mangled &mangled,
+ const Declaration *decl_ptr,
+ const Declaration *call_decl_ptr
+) :
+ FunctionInfo(name, decl_ptr),
+ m_mangled(mangled),
+ m_call_decl (call_decl_ptr)
+{
+}
+
+InlineFunctionInfo::~InlineFunctionInfo()
+{
+}
+
+int
+InlineFunctionInfo::Compare(const InlineFunctionInfo& a, const InlineFunctionInfo& b)
+{
+
+ int result = FunctionInfo::Compare(a, b);
+ if (result)
+ return result;
+ // only compare the mangled names if both have them
+ return Mangled::Compare(a.m_mangled, a.m_mangled);
+}
+
+void
+InlineFunctionInfo::Dump(Stream *s, bool show_fullpaths) const
+{
+ FunctionInfo::Dump(s, show_fullpaths);
+ if (m_mangled)
+ m_mangled.Dump(s);
+}
+
+void
+InlineFunctionInfo::DumpStopContext (Stream *s) const
+{
+// s->Indent("[inlined] ");
+ s->Indent();
+ if (m_mangled)
+ s->PutCString (m_mangled.GetName().AsCString());
+ else
+ s->PutCString (m_name.AsCString());
+}
+
+
+const ConstString &
+InlineFunctionInfo::GetName () const
+{
+ if (m_mangled)
+ return m_mangled.GetName();
+ return m_name;
+}
+
+
+Declaration &
+InlineFunctionInfo::GetCallSite ()
+{
+ return m_call_decl;
+}
+
+const Declaration &
+InlineFunctionInfo::GetCallSite () const
+{
+ return m_call_decl;
+}
+
+
+Mangled&
+InlineFunctionInfo::GetMangled()
+{
+ return m_mangled;
+}
+
+const Mangled&
+InlineFunctionInfo::GetMangled() const
+{
+ return m_mangled;
+}
+
+size_t
+InlineFunctionInfo::MemorySize() const
+{
+ return FunctionInfo::MemorySize() + m_mangled.MemorySize();
+}
+
+//----------------------------------------------------------------------
+//
+//----------------------------------------------------------------------
+Function::Function
+(
+ CompileUnit *comp_unit,
+ lldb::user_id_t func_uid,
+ lldb::user_id_t type_uid,
+ const Mangled &mangled,
+ Type * type,
+ const AddressRange& range
+) :
+ UserID (func_uid),
+ m_comp_unit (comp_unit),
+ m_type_uid (type_uid),
+ m_type (type),
+ m_mangled (mangled),
+ m_block (func_uid),
+ m_range (range),
+ m_frame_base (),
+ m_flags (),
+ m_prologue_byte_size (0)
+{
+ m_block.SetParentScope(this);
+ assert(comp_unit != NULL);
+}
+
+Function::Function
+(
+ CompileUnit *comp_unit,
+ lldb::user_id_t func_uid,
+ lldb::user_id_t type_uid,
+ const char *mangled,
+ Type *type,
+ const AddressRange &range
+) :
+ UserID (func_uid),
+ m_comp_unit (comp_unit),
+ m_type_uid (type_uid),
+ m_type (type),
+ m_mangled (ConstString(mangled), true),
+ m_block (func_uid),
+ m_range (range),
+ m_frame_base (),
+ m_flags (),
+ m_prologue_byte_size (0)
+{
+ m_block.SetParentScope(this);
+ assert(comp_unit != NULL);
+}
+
+
+Function::~Function()
+{
+}
+
+void
+Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
+{
+ line_no = 0;
+ source_file.Clear();
+
+ if (m_comp_unit == NULL)
+ return;
+
+ if (m_type != NULL && m_type->GetDeclaration().GetLine() != 0)
+ {
+ source_file = m_type->GetDeclaration().GetFile();
+ line_no = m_type->GetDeclaration().GetLine();
+ }
+ else
+ {
+ LineTable *line_table = m_comp_unit->GetLineTable();
+ if (line_table == NULL)
+ return;
+
+ LineEntry line_entry;
+ if (line_table->FindLineEntryByAddress (GetAddressRange().GetBaseAddress(), line_entry, NULL))
+ {
+ line_no = line_entry.line;
+ source_file = line_entry.file;
+ }
+ }
+}
+
+void
+Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
+{
+ line_no = 0;
+ source_file.Clear();
+
+ // The -1 is kind of cheesy, but I want to get the last line entry for the given function, not the
+ // first entry of the next.
+ Address scratch_addr(GetAddressRange().GetBaseAddress());
+ scratch_addr.SetOffset (scratch_addr.GetOffset() + GetAddressRange().GetByteSize() - 1);
+
+ LineTable *line_table = m_comp_unit->GetLineTable();
+ if (line_table == NULL)
+ return;
+
+ LineEntry line_entry;
+ if (line_table->FindLineEntryByAddress (scratch_addr, line_entry, NULL))
+ {
+ line_no = line_entry.line;
+ source_file = line_entry.file;
+ }
+}
+
+Block &
+Function::GetBlock (bool can_create)
+{
+ if (!m_block.BlockInfoHasBeenParsed() && can_create)
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ if (sc.module_sp)
+ {
+ sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc);
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "error: unable to find module shared pointer for function '%s' in %s\n",
+ GetName().GetCString(),
+ m_comp_unit->GetPath().c_str());
+ }
+ m_block.SetBlockInfoHasBeenParsed (true, true);
+ }
+ return m_block;
+}
+
+CompileUnit*
+Function::GetCompileUnit()
+{
+ return m_comp_unit;
+}
+
+const CompileUnit*
+Function::GetCompileUnit() const
+{
+ return m_comp_unit;
+}
+
+
+void
+Function::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target)
+{
+ Type* func_type = GetType();
+ const char *name = func_type ? func_type->GetName().AsCString() : "<unknown>";
+
+ *s << "id = " << (const UserID&)*this << ", name = \"" << name << "\", range = ";
+
+ Address::DumpStyle fallback_style;
+ if (level == eDescriptionLevelVerbose)
+ fallback_style = Address::DumpStyleModuleWithFileAddress;
+ else
+ fallback_style = Address::DumpStyleFileAddress;
+ GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, fallback_style);
+}
+
+void
+Function::Dump(Stream *s, bool show_context) const
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ *s << "Function" << (const UserID&)*this;
+
+ m_mangled.Dump(s);
+
+ if (m_type)
+ {
+ s->Printf(", type = %p", m_type);
+ }
+ else if (m_type_uid != LLDB_INVALID_UID)
+ {
+ s->Printf(", type_uid = 0x%8.8" PRIx64, m_type_uid);
+ }
+
+ s->EOL();
+ // Dump the root object
+ if (m_block.BlockInfoHasBeenParsed ())
+ m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX, show_context);
+}
+
+
+void
+Function::CalculateSymbolContext(SymbolContext* sc)
+{
+ sc->function = this;
+ m_comp_unit->CalculateSymbolContext(sc);
+}
+
+ModuleSP
+Function::CalculateSymbolContextModule ()
+{
+ SectionSP section_sp (m_range.GetBaseAddress().GetSection());
+ if (section_sp)
+ return section_sp->GetModule();
+
+ return this->GetCompileUnit()->GetModule();
+}
+
+CompileUnit *
+Function::CalculateSymbolContextCompileUnit ()
+{
+ return this->GetCompileUnit();
+}
+
+Function *
+Function::CalculateSymbolContextFunction ()
+{
+ return this;
+}
+
+//Symbol *
+//Function::CalculateSymbolContextSymbol ()
+//{
+// return // TODO: find the symbol for the function???
+//}
+
+
+void
+Function::DumpSymbolContext(Stream *s)
+{
+ m_comp_unit->DumpSymbolContext(s);
+ s->Printf(", Function{0x%8.8" PRIx64 "}", GetID());
+}
+
+size_t
+Function::MemorySize () const
+{
+ size_t mem_size = sizeof(Function) + m_block.MemorySize();
+ return mem_size;
+}
+
+clang::DeclContext *
+Function::GetClangDeclContext()
+{
+ SymbolContext sc;
+
+ CalculateSymbolContext (&sc);
+
+ if (!sc.module_sp)
+ return NULL;
+
+ SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
+
+ if (!sym_vendor)
+ return NULL;
+
+ SymbolFile *sym_file = sym_vendor->GetSymbolFile();
+
+ if (!sym_file)
+ return NULL;
+
+ return sym_file->GetClangDeclContextForTypeUID (sc, m_uid);
+}
+
+Type*
+Function::GetType()
+{
+ if (m_type == NULL)
+ {
+ SymbolContext sc;
+
+ CalculateSymbolContext (&sc);
+
+ if (!sc.module_sp)
+ return NULL;
+
+ SymbolVendor *sym_vendor = sc.module_sp->GetSymbolVendor();
+
+ if (sym_vendor == NULL)
+ return NULL;
+
+ SymbolFile *sym_file = sym_vendor->GetSymbolFile();
+
+ if (sym_file == NULL)
+ return NULL;
+
+ m_type = sym_file->ResolveTypeUID(m_type_uid);
+ }
+ return m_type;
+}
+
+const Type*
+Function::GetType() const
+{
+ return m_type;
+}
+
+ClangASTType
+Function::GetClangType()
+{
+ Type *function_type = GetType();
+ if (function_type)
+ return function_type->GetClangFullType();
+ return ClangASTType();
+}
+
+uint32_t
+Function::GetPrologueByteSize ()
+{
+ if (m_prologue_byte_size == 0 && m_flags.IsClear(flagsCalculatedPrologueSize))
+ {
+ m_flags.Set(flagsCalculatedPrologueSize);
+ LineTable* line_table = m_comp_unit->GetLineTable ();
+ if (line_table)
+ {
+ LineEntry first_line_entry;
+ uint32_t first_line_entry_idx = UINT32_MAX;
+ if (line_table->FindLineEntryByAddress(GetAddressRange().GetBaseAddress(), first_line_entry, &first_line_entry_idx))
+ {
+ // Make sure the first line entry isn't already the end of the prologue
+ addr_t prologue_end_file_addr = LLDB_INVALID_ADDRESS;
+ if (first_line_entry.is_prologue_end)
+ {
+ prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress();
+ }
+ else
+ {
+ // Check the first few instructions and look for one that has
+ // is_prologue_end set to true.
+ const uint32_t last_line_entry_idx = first_line_entry_idx + 6;
+ for (uint32_t idx = first_line_entry_idx + 1; idx < last_line_entry_idx; ++idx)
+ {
+ LineEntry line_entry;
+ if (line_table->GetLineEntryAtIndex (idx, line_entry))
+ {
+ if (line_entry.is_prologue_end)
+ {
+ prologue_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress();
+ break;
+ }
+ }
+ }
+ }
+
+ // If we didn't find the end of the prologue in the line tables,
+ // then just use the end address of the first line table entry
+ if (prologue_end_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ // Check the first few instructions and look for one that has
+ // a line number that's different than the first entry.
+ const uint32_t last_line_entry_idx = first_line_entry_idx + 6;
+ for (uint32_t idx = first_line_entry_idx + 1; idx < last_line_entry_idx; ++idx)
+ {
+ LineEntry line_entry;
+ if (line_table->GetLineEntryAtIndex (idx, line_entry))
+ {
+ if (line_entry.line != first_line_entry.line)
+ {
+ prologue_end_file_addr = line_entry.range.GetBaseAddress().GetFileAddress();
+ break;
+ }
+ }
+ }
+
+ if (prologue_end_file_addr == LLDB_INVALID_ADDRESS)
+ {
+ prologue_end_file_addr = first_line_entry.range.GetBaseAddress().GetFileAddress() + first_line_entry.range.GetByteSize();
+ }
+ }
+ const addr_t func_start_file_addr = m_range.GetBaseAddress().GetFileAddress();
+ const addr_t func_end_file_addr = func_start_file_addr + m_range.GetByteSize();
+
+ // Verify that this prologue end file address in the function's
+ // address range just to be sure
+ if (func_start_file_addr < prologue_end_file_addr && prologue_end_file_addr < func_end_file_addr)
+ {
+ m_prologue_byte_size = prologue_end_file_addr - func_start_file_addr;
+ }
+ }
+ }
+ }
+ return m_prologue_byte_size;
+}
+
+
+
diff --git a/source/Symbol/LineEntry.cpp b/source/Symbol/LineEntry.cpp
new file mode 100644
index 000000000000..10dc552ea01a
--- /dev/null
+++ b/source/Symbol/LineEntry.cpp
@@ -0,0 +1,246 @@
+//===-- LineEntry.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/Symbol/LineEntry.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb_private;
+
+LineEntry::LineEntry() :
+ range(),
+ file(),
+ line(0),
+ column(0),
+ is_start_of_statement(0),
+ is_start_of_basic_block(0),
+ is_prologue_end(0),
+ is_epilogue_begin(0),
+ is_terminal_entry(0)
+{
+}
+
+LineEntry::LineEntry
+(
+ const lldb::SectionSP &section_sp,
+ lldb::addr_t section_offset,
+ lldb::addr_t byte_size,
+ const FileSpec &_file,
+ uint32_t _line,
+ uint16_t _column,
+ bool _is_start_of_statement,
+ bool _is_start_of_basic_block,
+ bool _is_prologue_end,
+ bool _is_epilogue_begin,
+ bool _is_terminal_entry
+) :
+ range(section_sp, section_offset, byte_size),
+ file(_file),
+ line(_line),
+ column(_column),
+ is_start_of_statement(_is_start_of_statement),
+ is_start_of_basic_block(_is_start_of_basic_block),
+ is_prologue_end(_is_prologue_end),
+ is_epilogue_begin(_is_epilogue_begin),
+ is_terminal_entry(_is_terminal_entry)
+{
+}
+
+void
+LineEntry::Clear()
+{
+ range.Clear();
+ file.Clear();
+ line = 0;
+ column = 0;
+ is_start_of_statement = 0;
+ is_start_of_basic_block = 0;
+ is_prologue_end = 0;
+ is_epilogue_begin = 0;
+ is_terminal_entry = 0;
+}
+
+
+bool
+LineEntry::IsValid() const
+{
+ return range.GetBaseAddress().IsValid() && line != 0;
+}
+
+bool
+LineEntry::DumpStopContext(Stream *s, bool show_fullpaths) const
+{
+ bool result = false;
+ if (file)
+ {
+ if (show_fullpaths)
+ file.Dump (s);
+ else
+ file.GetFilename().Dump (s);
+
+ if (line)
+ s->PutChar(':');
+ result = true;
+ }
+ if (line)
+ s->Printf ("%u", line);
+ else
+ result = false;
+
+ return result;
+}
+
+bool
+LineEntry::Dump
+(
+ Stream *s,
+ Target *target,
+ bool show_file,
+ Address::DumpStyle style,
+ Address::DumpStyle fallback_style,
+ bool show_range
+) const
+{
+ if (show_range)
+ {
+ // Show address range
+ if (!range.Dump(s, target, style, fallback_style))
+ return false;
+ }
+ else
+ {
+ // Show address only
+ if (!range.GetBaseAddress().Dump(s,
+ target,
+ style,
+ fallback_style))
+ return false;
+ }
+ if (show_file)
+ *s << ", file = " << file;
+ if (line)
+ s->Printf(", line = %u", line);
+ if (column)
+ s->Printf(", column = %u", column);
+ if (is_start_of_statement)
+ *s << ", is_start_of_statement = TRUE";
+
+ if (is_start_of_basic_block)
+ *s << ", is_start_of_basic_block = TRUE";
+
+ if (is_prologue_end)
+ *s << ", is_prologue_end = TRUE";
+
+ if (is_epilogue_begin)
+ *s << ", is_epilogue_begin = TRUE";
+
+ if (is_terminal_entry)
+ *s << ", is_terminal_entry = TRUE";
+ return true;
+}
+
+bool
+LineEntry::GetDescription (Stream *s, lldb::DescriptionLevel level, CompileUnit* cu, Target *target, bool show_address_only) const
+{
+
+ if (level == lldb::eDescriptionLevelBrief || level == lldb::eDescriptionLevelFull)
+ {
+ if (show_address_only)
+ {
+ range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ }
+ else
+ {
+ range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ }
+
+ *s << ": " << file;
+
+ if (line)
+ {
+ s->Printf(":%u", line);
+ if (column)
+ s->Printf(":%u", column);
+ }
+
+
+ if (level == lldb::eDescriptionLevelFull)
+ {
+ if (is_start_of_statement)
+ *s << ", is_start_of_statement = TRUE";
+
+ if (is_start_of_basic_block)
+ *s << ", is_start_of_basic_block = TRUE";
+
+ if (is_prologue_end)
+ *s << ", is_prologue_end = TRUE";
+
+ if (is_epilogue_begin)
+ *s << ", is_epilogue_begin = TRUE";
+
+ if (is_terminal_entry)
+ *s << ", is_terminal_entry = TRUE";
+ }
+ else
+ {
+ if (is_terminal_entry)
+ s->EOL();
+ }
+ }
+ else
+ {
+ return Dump (s, target, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true);
+ }
+ return true;
+}
+
+
+bool
+lldb_private::operator< (const LineEntry& a, const LineEntry& b)
+{
+ return LineEntry::Compare (a, b) < 0;
+}
+
+int
+LineEntry::Compare (const LineEntry& a, const LineEntry& b)
+{
+ int result = Address::CompareFileAddress (a.range.GetBaseAddress(), b.range.GetBaseAddress());
+ if (result != 0)
+ return result;
+
+ const lldb::addr_t a_byte_size = a.range.GetByteSize();
+ const lldb::addr_t b_byte_size = b.range.GetByteSize();
+
+ if (a_byte_size < b_byte_size)
+ return -1;
+ if (a_byte_size > b_byte_size)
+ return +1;
+
+ // Check for an end sequence entry mismatch after we have determined
+ // that the address values are equal. If one of the items is an end
+ // sequence, we don't care about the line, file, or column info.
+ if (a.is_terminal_entry > b.is_terminal_entry)
+ return -1;
+ if (a.is_terminal_entry < b.is_terminal_entry)
+ return +1;
+
+ if (a.line < b.line)
+ return -1;
+ if (a.line > b.line)
+ return +1;
+
+ if (a.column < b.column)
+ return -1;
+ if (a.column > b.column)
+ return +1;
+
+ return FileSpec::Compare (a.file, b.file, true);
+}
+
diff --git a/source/Symbol/LineTable.cpp b/source/Symbol/LineTable.cpp
new file mode 100644
index 000000000000..a4aa35ddb318
--- /dev/null
+++ b/source/Symbol/LineTable.cpp
@@ -0,0 +1,588 @@
+//===-- LineTable.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/Address.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include <algorithm>
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// LineTable constructor
+//----------------------------------------------------------------------
+LineTable::LineTable(CompileUnit* comp_unit) :
+ m_comp_unit(comp_unit),
+ m_entries()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+LineTable::~LineTable()
+{
+}
+
+void
+LineTable::InsertLineEntry
+(
+ lldb::addr_t file_addr,
+ uint32_t line,
+ uint16_t column,
+ uint16_t file_idx,
+ bool is_start_of_statement,
+ bool is_start_of_basic_block,
+ bool is_prologue_end,
+ bool is_epilogue_begin,
+ bool is_terminal_entry
+)
+{
+ Entry entry(file_addr, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
+
+ entry_collection::iterator begin_pos = m_entries.begin();
+ entry_collection::iterator end_pos = m_entries.end();
+ LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
+ entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp);
+
+// Stream s(stdout);
+// s << "\n\nBefore:\n";
+// Dump (&s, Address::DumpStyleFileAddress);
+ m_entries.insert(pos, entry);
+// s << "After:\n";
+// Dump (&s, Address::DumpStyleFileAddress);
+}
+
+LineSequence::LineSequence()
+{
+}
+
+void
+LineTable::LineSequenceImpl::Clear()
+{
+ m_entries.clear();
+}
+
+LineSequence* LineTable::CreateLineSequenceContainer ()
+{
+ return new LineTable::LineSequenceImpl();
+}
+
+void
+LineTable::AppendLineEntryToSequence
+(
+ LineSequence* sequence,
+ lldb::addr_t file_addr,
+ uint32_t line,
+ uint16_t column,
+ uint16_t file_idx,
+ bool is_start_of_statement,
+ bool is_start_of_basic_block,
+ bool is_prologue_end,
+ bool is_epilogue_begin,
+ bool is_terminal_entry
+)
+{
+ assert(sequence != NULL);
+ LineSequenceImpl* seq = reinterpret_cast<LineSequenceImpl*>(sequence);
+ Entry entry(file_addr, line, column, file_idx, is_start_of_statement, is_start_of_basic_block, is_prologue_end, is_epilogue_begin, is_terminal_entry);
+ seq->m_entries.push_back (entry);
+}
+
+void
+LineTable::InsertSequence (LineSequence* sequence)
+{
+ assert(sequence != NULL);
+ LineSequenceImpl* seq = reinterpret_cast<LineSequenceImpl*>(sequence);
+ if (seq->m_entries.empty())
+ return;
+ Entry& entry = seq->m_entries.front();
+
+ // If the first entry address in this sequence is greater than or equal to
+ // the address of the last item in our entry collection, just append.
+ if (m_entries.empty() || !Entry::EntryAddressLessThan(entry, m_entries.back()))
+ {
+ m_entries.insert(m_entries.end(),
+ seq->m_entries.begin(),
+ seq->m_entries.end());
+ return;
+ }
+
+ // Otherwise, find where this belongs in the collection
+ entry_collection::iterator begin_pos = m_entries.begin();
+ entry_collection::iterator end_pos = m_entries.end();
+ LineTable::Entry::LessThanBinaryPredicate less_than_bp(this);
+ entry_collection::iterator pos = upper_bound(begin_pos, end_pos, entry, less_than_bp);
+#ifdef LLDB_CONFIGURATION_DEBUG
+ // If we aren't inserting at the beginning, the previous entry should
+ // terminate a sequence.
+ if (pos != begin_pos)
+ {
+ entry_collection::iterator prev_pos = pos - 1;
+ assert(prev_pos->is_terminal_entry);
+ }
+#endif
+ m_entries.insert(pos, seq->m_entries.begin(), seq->m_entries.end());
+}
+
+//----------------------------------------------------------------------
+LineTable::Entry::LessThanBinaryPredicate::LessThanBinaryPredicate(LineTable *line_table) :
+ m_line_table (line_table)
+{
+}
+
+bool
+LineTable::Entry::LessThanBinaryPredicate::operator() (const LineTable::Entry& a, const LineTable::Entry& b) const
+{
+ #define LT_COMPARE(a,b) if (a != b) return a < b
+ LT_COMPARE (a.file_addr, b.file_addr);
+ // b and a reversed on purpose below.
+ LT_COMPARE (b.is_terminal_entry, a.is_terminal_entry);
+ LT_COMPARE (a.line, b.line);
+ LT_COMPARE (a.column, b.column);
+ LT_COMPARE (a.is_start_of_statement, b.is_start_of_statement);
+ LT_COMPARE (a.is_start_of_basic_block, b.is_start_of_basic_block);
+ // b and a reversed on purpose below.
+ LT_COMPARE (b.is_prologue_end, a.is_prologue_end);
+ LT_COMPARE (a.is_epilogue_begin, b.is_epilogue_begin);
+ LT_COMPARE (a.file_idx, b.file_idx);
+ return false;
+ #undef LT_COMPARE
+}
+
+
+
+uint32_t
+LineTable::GetSize() const
+{
+ return m_entries.size();
+}
+
+bool
+LineTable::GetLineEntryAtIndex(uint32_t idx, LineEntry& line_entry)
+{
+ if (idx < m_entries.size())
+ {
+ ConvertEntryAtIndexToLineEntry (idx, line_entry);
+ return true;
+ }
+ line_entry.Clear();
+ return false;
+}
+
+bool
+LineTable::FindLineEntryByAddress (const Address &so_addr, LineEntry& line_entry, uint32_t *index_ptr)
+{
+ if (index_ptr != NULL )
+ *index_ptr = UINT32_MAX;
+
+ bool success = false;
+
+ if (so_addr.GetModule().get() == m_comp_unit->GetModule().get())
+ {
+ Entry search_entry;
+ search_entry.file_addr = so_addr.GetFileAddress();
+ if (search_entry.file_addr != LLDB_INVALID_ADDRESS)
+ {
+ entry_collection::const_iterator begin_pos = m_entries.begin();
+ entry_collection::const_iterator end_pos = m_entries.end();
+ entry_collection::const_iterator pos = lower_bound(begin_pos, end_pos, search_entry, Entry::EntryAddressLessThan);
+ if (pos != end_pos)
+ {
+ if (pos != begin_pos)
+ {
+ if (pos->file_addr != search_entry.file_addr)
+ --pos;
+ else if (pos->file_addr == search_entry.file_addr)
+ {
+ // If this is a termination entry, it should't match since
+ // entries with the "is_terminal_entry" member set to true
+ // are termination entries that define the range for the
+ // previous entry.
+ if (pos->is_terminal_entry)
+ {
+ // The matching entry is a terminal entry, so we skip
+ // ahead to the next entry to see if there is another
+ // entry following this one whose section/offset matches.
+ ++pos;
+ if (pos != end_pos)
+ {
+ if (pos->file_addr != search_entry.file_addr)
+ pos = end_pos;
+ }
+ }
+
+ if (pos != end_pos)
+ {
+ // While in the same section/offset backup to find the first
+ // line entry that matches the address in case there are
+ // multiple
+ while (pos != begin_pos)
+ {
+ entry_collection::const_iterator prev_pos = pos - 1;
+ if (prev_pos->file_addr == search_entry.file_addr &&
+ prev_pos->is_terminal_entry == false)
+ --pos;
+ else
+ break;
+ }
+ }
+ }
+
+ }
+
+ // Make sure we have a valid match and that the match isn't a terminating
+ // entry for a previous line...
+ if (pos != end_pos && pos->is_terminal_entry == false)
+ {
+ uint32_t match_idx = std::distance (begin_pos, pos);
+ success = ConvertEntryAtIndexToLineEntry(match_idx, line_entry);
+ if (index_ptr != NULL && success)
+ *index_ptr = match_idx;
+ }
+ }
+ }
+ }
+ return success;
+}
+
+
+bool
+LineTable::ConvertEntryAtIndexToLineEntry (uint32_t idx, LineEntry &line_entry)
+{
+ if (idx < m_entries.size())
+ {
+ const Entry& entry = m_entries[idx];
+ ModuleSP module_sp (m_comp_unit->GetModule());
+ if (module_sp && module_sp->ResolveFileAddress(entry.file_addr, line_entry.range.GetBaseAddress()))
+ {
+ if (!entry.is_terminal_entry && idx + 1 < m_entries.size())
+ line_entry.range.SetByteSize(m_entries[idx+1].file_addr - entry.file_addr);
+ else
+ line_entry.range.SetByteSize(0);
+
+ line_entry.file = m_comp_unit->GetSupportFiles().GetFileSpecAtIndex (entry.file_idx);
+ line_entry.line = entry.line;
+ line_entry.column = entry.column;
+ line_entry.is_start_of_statement = entry.is_start_of_statement;
+ line_entry.is_start_of_basic_block = entry.is_start_of_basic_block;
+ line_entry.is_prologue_end = entry.is_prologue_end;
+ line_entry.is_epilogue_begin = entry.is_epilogue_begin;
+ line_entry.is_terminal_entry = entry.is_terminal_entry;
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+LineTable::FindLineEntryIndexByFileIndex
+(
+ uint32_t start_idx,
+ const std::vector<uint32_t> &file_indexes,
+ uint32_t line,
+ bool exact,
+ LineEntry* line_entry_ptr
+)
+{
+
+ const size_t count = m_entries.size();
+ std::vector<uint32_t>::const_iterator begin_pos = file_indexes.begin();
+ std::vector<uint32_t>::const_iterator end_pos = file_indexes.end();
+ size_t best_match = UINT32_MAX;
+
+ for (size_t idx = start_idx; idx < count; ++idx)
+ {
+ // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
+ if (m_entries[idx].is_terminal_entry)
+ continue;
+
+ if (find (begin_pos, end_pos, m_entries[idx].file_idx) == end_pos)
+ continue;
+
+ // Exact match always wins. Otherwise try to find the closest line > the desired
+ // line.
+ // FIXME: Maybe want to find the line closest before and the line closest after and
+ // if they're not in the same function, don't return a match.
+
+ if (m_entries[idx].line < line)
+ {
+ continue;
+ }
+ else if (m_entries[idx].line == line)
+ {
+ if (line_entry_ptr)
+ ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
+ return idx;
+ }
+ else if (!exact)
+ {
+ if (best_match == UINT32_MAX)
+ best_match = idx;
+ else if (m_entries[idx].line < m_entries[best_match].line)
+ best_match = idx;
+ }
+ }
+
+ if (best_match != UINT32_MAX)
+ {
+ if (line_entry_ptr)
+ ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
+ return best_match;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+LineTable::FindLineEntryIndexByFileIndex (uint32_t start_idx, uint32_t file_idx, uint32_t line, bool exact, LineEntry* line_entry_ptr)
+{
+ const size_t count = m_entries.size();
+ size_t best_match = UINT32_MAX;
+
+ for (size_t idx = start_idx; idx < count; ++idx)
+ {
+ // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
+ if (m_entries[idx].is_terminal_entry)
+ continue;
+
+ if (m_entries[idx].file_idx != file_idx)
+ continue;
+
+ // Exact match always wins. Otherwise try to find the closest line > the desired
+ // line.
+ // FIXME: Maybe want to find the line closest before and the line closest after and
+ // if they're not in the same function, don't return a match.
+
+ if (m_entries[idx].line < line)
+ {
+ continue;
+ }
+ else if (m_entries[idx].line == line)
+ {
+ if (line_entry_ptr)
+ ConvertEntryAtIndexToLineEntry (idx, *line_entry_ptr);
+ return idx;
+ }
+ else if (!exact)
+ {
+ if (best_match == UINT32_MAX)
+ best_match = idx;
+ else if (m_entries[idx].line < m_entries[best_match].line)
+ best_match = idx;
+ }
+ }
+
+ if (best_match != UINT32_MAX)
+ {
+ if (line_entry_ptr)
+ ConvertEntryAtIndexToLineEntry (best_match, *line_entry_ptr);
+ return best_match;
+ }
+ return UINT32_MAX;
+}
+
+size_t
+LineTable::FineLineEntriesForFileIndex (uint32_t file_idx,
+ bool append,
+ SymbolContextList &sc_list)
+{
+
+ if (!append)
+ sc_list.Clear();
+
+ size_t num_added = 0;
+ const size_t count = m_entries.size();
+ if (count > 0)
+ {
+ SymbolContext sc (m_comp_unit);
+
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ // Skip line table rows that terminate the previous row (is_terminal_entry is non-zero)
+ if (m_entries[idx].is_terminal_entry)
+ continue;
+
+ if (m_entries[idx].file_idx == file_idx)
+ {
+ if (ConvertEntryAtIndexToLineEntry (idx, sc.line_entry))
+ {
+ ++num_added;
+ sc_list.Append(sc);
+ }
+ }
+ }
+ }
+ return num_added;
+}
+
+
+void
+LineTable::Dump (Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style, bool show_line_ranges)
+{
+ const size_t count = m_entries.size();
+ LineEntry line_entry;
+ FileSpec prev_file;
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ ConvertEntryAtIndexToLineEntry (idx, line_entry);
+ line_entry.Dump (s, target, prev_file != line_entry.file, style, fallback_style, show_line_ranges);
+ s->EOL();
+ prev_file = line_entry.file;
+ }
+}
+
+
+void
+LineTable::GetDescription (Stream *s, Target *target, DescriptionLevel level)
+{
+ const size_t count = m_entries.size();
+ LineEntry line_entry;
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ ConvertEntryAtIndexToLineEntry (idx, line_entry);
+ line_entry.GetDescription (s, level, m_comp_unit, target, true);
+ s->EOL();
+ }
+}
+
+size_t
+LineTable::GetContiguousFileAddressRanges (FileAddressRanges &file_ranges, bool append)
+{
+ if (!append)
+ file_ranges.Clear();
+ const size_t initial_count = file_ranges.GetSize();
+
+ const size_t count = m_entries.size();
+ LineEntry line_entry;
+ FileAddressRanges::Entry range (LLDB_INVALID_ADDRESS, 0);
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ const Entry& entry = m_entries[idx];
+
+ if (entry.is_terminal_entry)
+ {
+ if (range.GetRangeBase() != LLDB_INVALID_ADDRESS)
+ {
+ range.SetRangeEnd(entry.file_addr);
+ file_ranges.Append(range);
+ range.Clear(LLDB_INVALID_ADDRESS);
+ }
+ }
+ else if (range.GetRangeBase() == LLDB_INVALID_ADDRESS)
+ {
+ range.SetRangeBase(entry.file_addr);
+ }
+ }
+ return file_ranges.GetSize() - initial_count;
+}
+
+LineTable *
+LineTable::LinkLineTable (const FileRangeMap &file_range_map)
+{
+ std::unique_ptr<LineTable> line_table_ap (new LineTable (m_comp_unit));
+ LineSequenceImpl sequence;
+ const size_t count = m_entries.size();
+ LineEntry line_entry;
+ const FileRangeMap::Entry *file_range_entry = NULL;
+ const FileRangeMap::Entry *prev_file_range_entry = NULL;
+ lldb::addr_t prev_file_addr = LLDB_INVALID_ADDRESS;
+ bool prev_entry_was_linked = false;
+ bool range_changed = false;
+ for (size_t idx = 0; idx < count; ++idx)
+ {
+ const Entry& entry = m_entries[idx];
+
+ const bool end_sequence = entry.is_terminal_entry;
+ const lldb::addr_t lookup_file_addr = entry.file_addr - (end_sequence ? 1 : 0);
+ if (file_range_entry == NULL || !file_range_entry->Contains(lookup_file_addr))
+ {
+ prev_file_range_entry = file_range_entry;
+ file_range_entry = file_range_map.FindEntryThatContains(lookup_file_addr);
+ range_changed = true;
+ }
+
+ lldb::addr_t prev_end_entry_linked_file_addr = LLDB_INVALID_ADDRESS;
+ lldb::addr_t entry_linked_file_addr = LLDB_INVALID_ADDRESS;
+
+ bool terminate_previous_entry = false;
+ if (file_range_entry)
+ {
+ entry_linked_file_addr = entry.file_addr - file_range_entry->GetRangeBase() + file_range_entry->data;
+ // Determine if we need to terminate the previous entry when the previous
+ // entry was not contguous with this one after being linked.
+ if (range_changed && prev_file_range_entry)
+ {
+ prev_end_entry_linked_file_addr = std::min<lldb::addr_t>(entry.file_addr, prev_file_range_entry->GetRangeEnd()) - prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
+ if (prev_end_entry_linked_file_addr != entry_linked_file_addr)
+ terminate_previous_entry = prev_entry_was_linked;
+ }
+ }
+ else if (prev_entry_was_linked)
+ {
+ // This entry doesn't have a remapping and it needs to be removed.
+ // Watch out in case we need to terminate a previous entry needs to
+ // be terminated now that one line entry in a sequence is not longer valid.
+ if (!entry.is_terminal_entry &&
+ !sequence.m_entries.empty() &&
+ !sequence.m_entries.back().is_terminal_entry)
+ {
+ terminate_previous_entry = true;
+ }
+ }
+
+ if (terminate_previous_entry && !sequence.m_entries.empty())
+ {
+ assert (prev_file_addr != LLDB_INVALID_ADDRESS);
+ sequence.m_entries.push_back(sequence.m_entries.back());
+ if (prev_end_entry_linked_file_addr == LLDB_INVALID_ADDRESS)
+ prev_end_entry_linked_file_addr = std::min<lldb::addr_t>(entry.file_addr,prev_file_range_entry->GetRangeEnd()) - prev_file_range_entry->GetRangeBase() + prev_file_range_entry->data;
+ sequence.m_entries.back().file_addr = prev_end_entry_linked_file_addr;
+ sequence.m_entries.back().is_terminal_entry = true;
+
+ // 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
+ if (file_range_entry)
+ {
+ // This entry has an address remapping and it needs to have its address relinked
+ sequence.m_entries.push_back(entry);
+ sequence.m_entries.back().file_addr = entry_linked_file_addr;
+ }
+
+ // If we have items in the sequence and the last entry is a terminal entry,
+ // insert this sequence into our new line table.
+ if (!sequence.m_entries.empty() && sequence.m_entries.back().is_terminal_entry)
+ {
+ line_table_ap->InsertSequence (&sequence);
+ sequence.Clear();
+ prev_entry_was_linked = false;
+ }
+ else
+ {
+ prev_entry_was_linked = file_range_entry != NULL;
+ }
+ prev_file_addr = entry.file_addr;
+ range_changed = false;
+ }
+ if (line_table_ap->m_entries.empty())
+ return NULL;
+ return line_table_ap.release();
+}
+
+
+
+
diff --git a/source/Symbol/ObjectFile.cpp b/source/Symbol/ObjectFile.cpp
new file mode 100644
index 000000000000..0c6159122cfb
--- /dev/null
+++ b/source/Symbol/ObjectFile.cpp
@@ -0,0 +1,621 @@
+//===-- ObjectFile.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/lldb-private-log.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/ObjectContainer.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Target/Process.h"
+#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ObjectFileSP
+ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
+ const FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ DataBufferSP &data_sp,
+ lldb::offset_t &data_offset)
+{
+ ObjectFileSP object_file_sp;
+
+ if (module_sp)
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "ObjectFile::FindPlugin (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ file, (uint64_t) file_offset, (uint64_t) file_size);
+ if (file)
+ {
+ FileSpec archive_file;
+ ObjectContainerCreateInstance create_object_container_callback;
+
+ const bool file_exists = file->Exists();
+ if (!data_sp)
+ {
+ // We have an object name which most likely means we have
+ // a .o file in a static archive (.a file). Try and see if
+ // we have a cached archive first without reading any data
+ // first
+ if (file_exists && module_sp->GetObjectName())
+ {
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
+
+ if (object_container_ap.get())
+ object_file_sp = object_container_ap->GetObjectFile(file);
+
+ if (object_file_sp.get())
+ return object_file_sp;
+ }
+ }
+ // Ok, we didn't find any containers that have a named object, now
+ // lets read the first 512 bytes from the file so the object file
+ // and object container plug-ins can use these bytes to see if they
+ // can parse this file.
+ if (file_size > 0)
+ {
+ data_sp = file->ReadFileContents(file_offset, std::min<size_t>(512, file_size));
+ data_offset = 0;
+ }
+ }
+
+ if (!data_sp || data_sp->GetByteSize() == 0)
+ {
+ // Check for archive file with format "/path/to/archive.a(object.o)"
+ char path_with_object[PATH_MAX*2];
+ module_sp->GetFileSpec().GetPath(path_with_object, sizeof(path_with_object));
+
+ ConstString archive_object;
+ const bool must_exist = true;
+ if (ObjectFile::SplitArchivePathWithObject (path_with_object, archive_file, archive_object, must_exist))
+ {
+ file_size = archive_file.GetByteSize();
+ if (file_size > 0)
+ {
+ file = &archive_file;
+ module_sp->SetFileSpecAndObjectName (archive_file, archive_object);
+ // Check if this is a object container by iterating through all object
+ // container plugin instances and then trying to get an object file
+ // from the container plugins since we had a name. Also, don't read
+ // ANY data in case there is data cached in the container plug-ins
+ // (like BSD archives caching the contained objects within an file).
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
+
+ if (object_container_ap.get())
+ object_file_sp = object_container_ap->GetObjectFile(file);
+
+ if (object_file_sp.get())
+ return object_file_sp;
+ }
+ // We failed to find any cached object files in the container
+ // plug-ins, so lets read the first 512 bytes and try again below...
+ data_sp = archive_file.ReadFileContents(file_offset, 512);
+ }
+ }
+ }
+
+ if (data_sp && data_sp->GetByteSize() > 0)
+ {
+ // Check if this is a normal object file by iterating through
+ // all object file plugin instances.
+ ObjectFileCreateInstance create_object_file_callback;
+ for (uint32_t idx = 0; (create_object_file_callback = PluginManager::GetObjectFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ object_file_sp.reset (create_object_file_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
+ if (object_file_sp.get())
+ return object_file_sp;
+ }
+
+ // Check if this is a object container by iterating through
+ // all object container plugin instances and then trying to get
+ // an object file from the container.
+ for (uint32_t idx = 0; (create_object_container_callback = PluginManager::GetObjectContainerCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<ObjectContainer> object_container_ap(create_object_container_callback(module_sp, data_sp, data_offset, file, file_offset, file_size));
+
+ if (object_container_ap.get())
+ object_file_sp = object_container_ap->GetObjectFile(file);
+
+ if (object_file_sp.get())
+ return object_file_sp;
+ }
+ }
+ }
+ }
+ // We didn't find it, so clear our shared pointer in case it
+ // contains anything and return an empty shared pointer
+ object_file_sp.reset();
+ return object_file_sp;
+}
+
+ObjectFileSP
+ObjectFile::FindPlugin (const lldb::ModuleSP &module_sp,
+ const ProcessSP &process_sp,
+ lldb::addr_t header_addr,
+ DataBufferSP &data_sp)
+{
+ ObjectFileSP object_file_sp;
+
+ if (module_sp)
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "ObjectFile::FindPlugin (module = %s, process = %p, header_addr = 0x%" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ process_sp.get(), header_addr);
+ uint32_t idx;
+
+ // Check if this is a normal object file by iterating through
+ // all object file plugin instances.
+ ObjectFileCreateMemoryInstance create_callback;
+ for (idx = 0; (create_callback = PluginManager::GetObjectFileCreateMemoryCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ object_file_sp.reset (create_callback(module_sp, data_sp, process_sp, header_addr));
+ if (object_file_sp.get())
+ return object_file_sp;
+ }
+
+ }
+ // We didn't find it, so clear our shared pointer in case it
+ // contains anything and return an empty shared pointer
+ object_file_sp.reset();
+ return object_file_sp;
+}
+
+size_t
+ObjectFile::GetModuleSpecifications (const FileSpec &file,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ ModuleSpecList &specs)
+{
+ DataBufferSP data_sp (file.ReadFileContents(file_offset, 512));
+ if (data_sp)
+ {
+ if (file_size == 0)
+ {
+ const lldb::offset_t actual_file_size = file.GetByteSize();
+ if (actual_file_size > file_offset)
+ file_size = actual_file_size - file_offset;
+ }
+ return ObjectFile::GetModuleSpecifications (file, // file spec
+ data_sp, // data bytes
+ 0, // data offset
+ file_offset,// file offset
+ file_size, // file length
+ specs);
+ }
+ return 0;
+}
+
+size_t
+ObjectFile::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb_private::ModuleSpecList &specs)
+{
+ const size_t initial_count = specs.GetSize();
+ ObjectFileGetModuleSpecifications callback;
+ uint32_t i;
+ // Try the ObjectFile plug-ins
+ for (i = 0; (callback = PluginManager::GetObjectFileGetModuleSpecificationsCallbackAtIndex(i)) != NULL; ++i)
+ {
+ if (callback (file, data_sp, data_offset, file_offset, file_size, specs) > 0)
+ return specs.GetSize() - initial_count;
+ }
+
+ // Try the ObjectContainer plug-ins
+ for (i = 0; (callback = PluginManager::GetObjectContainerGetModuleSpecificationsCallbackAtIndex(i)) != NULL; ++i)
+ {
+ if (callback (file, data_sp, data_offset, file_offset, file_size, specs) > 0)
+ return specs.GetSize() - initial_count;
+ }
+ return 0;
+}
+
+ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
+ const FileSpec *file_spec_ptr,
+ lldb::offset_t file_offset,
+ lldb::offset_t length,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset
+) :
+ ModuleChild (module_sp),
+ m_file (), // This file could be different from the original module's file
+ m_type (eTypeInvalid),
+ m_strata (eStrataInvalid),
+ m_file_offset (file_offset),
+ m_length (length),
+ m_data (),
+ m_unwind_table (*this),
+ m_process_wp(),
+ m_memory_addr (LLDB_INVALID_ADDRESS),
+ m_sections_ap(),
+ m_symtab_ap ()
+{
+ if (file_spec_ptr)
+ m_file = *file_spec_ptr;
+ if (data_sp)
+ m_data.SetData (data_sp, data_offset, length);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ {
+ if (m_file)
+ {
+ log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), file = %s, file_offset = 0x%8.8" PRIx64 ", size = %" PRIu64,
+ this,
+ module_sp.get(),
+ module_sp->GetSpecificationDescription().c_str(),
+ m_file.GetPath().c_str(),
+ m_file_offset,
+ m_length);
+ }
+ else
+ {
+ log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), file = <NULL>, file_offset = 0x%8.8" PRIx64 ", size = %" PRIu64,
+ this,
+ module_sp.get(),
+ module_sp->GetSpecificationDescription().c_str(),
+ m_file_offset,
+ m_length);
+ }
+ }
+}
+
+
+ObjectFile::ObjectFile (const lldb::ModuleSP &module_sp,
+ const ProcessSP &process_sp,
+ lldb::addr_t header_addr,
+ DataBufferSP& header_data_sp) :
+ ModuleChild (module_sp),
+ m_file (),
+ m_type (eTypeInvalid),
+ m_strata (eStrataInvalid),
+ m_file_offset (0),
+ m_length (0),
+ m_data (),
+ m_unwind_table (*this),
+ m_process_wp (process_sp),
+ m_memory_addr (header_addr),
+ m_sections_ap(),
+ m_symtab_ap ()
+{
+ if (header_data_sp)
+ m_data.SetData (header_data_sp, 0, header_data_sp->GetByteSize());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ {
+ log->Printf ("%p ObjectFile::ObjectFile() module = %p (%s), process = %p, header_addr = 0x%" PRIx64,
+ this,
+ module_sp.get(),
+ module_sp->GetSpecificationDescription().c_str(),
+ process_sp.get(),
+ m_memory_addr);
+ }
+}
+
+
+ObjectFile::~ObjectFile()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p ObjectFile::~ObjectFile ()\n", this);
+}
+
+bool
+ObjectFile::SetModulesArchitecture (const ArchSpec &new_arch)
+{
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ return module_sp->SetArchitecture (new_arch);
+ return false;
+}
+
+AddressClass
+ObjectFile::GetAddressClass (addr_t file_addr)
+{
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ {
+ Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr);
+ if (symbol)
+ {
+ if (symbol->ValueIsAddress())
+ {
+ const SectionSP section_sp (symbol->GetAddress().GetSection());
+ if (section_sp)
+ {
+ const SectionType section_type = section_sp->GetType();
+ switch (section_type)
+ {
+ case eSectionTypeInvalid: return eAddressClassUnknown;
+ case eSectionTypeCode: return eAddressClassCode;
+ case eSectionTypeContainer: return eAddressClassUnknown;
+ case eSectionTypeData:
+ case eSectionTypeDataCString:
+ case eSectionTypeDataCStringPointers:
+ case eSectionTypeDataSymbolAddress:
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ case eSectionTypeDataPointers:
+ case eSectionTypeZeroFill:
+ case eSectionTypeDataObjCMessageRefs:
+ case eSectionTypeDataObjCCFStrings:
+ return eAddressClassData;
+ case eSectionTypeDebug:
+ case eSectionTypeDWARFDebugAbbrev:
+ case eSectionTypeDWARFDebugAranges:
+ case eSectionTypeDWARFDebugFrame:
+ case eSectionTypeDWARFDebugInfo:
+ case eSectionTypeDWARFDebugLine:
+ case eSectionTypeDWARFDebugLoc:
+ case eSectionTypeDWARFDebugMacInfo:
+ case eSectionTypeDWARFDebugPubNames:
+ case eSectionTypeDWARFDebugPubTypes:
+ case eSectionTypeDWARFDebugRanges:
+ case eSectionTypeDWARFDebugStr:
+ case eSectionTypeDWARFAppleNames:
+ case eSectionTypeDWARFAppleTypes:
+ case eSectionTypeDWARFAppleNamespaces:
+ case eSectionTypeDWARFAppleObjC:
+ return eAddressClassDebug;
+ case eSectionTypeEHFrame: return eAddressClassRuntime;
+ case eSectionTypeELFSymbolTable:
+ case eSectionTypeELFDynamicSymbols:
+ case eSectionTypeELFRelocationEntries:
+ case eSectionTypeELFDynamicLinkInfo:
+ case eSectionTypeOther: return eAddressClassUnknown;
+ }
+ }
+ }
+
+ const SymbolType symbol_type = symbol->GetType();
+ switch (symbol_type)
+ {
+ case eSymbolTypeAny: return eAddressClassUnknown;
+ case eSymbolTypeAbsolute: return eAddressClassUnknown;
+ case eSymbolTypeCode: return eAddressClassCode;
+ case eSymbolTypeTrampoline: return eAddressClassCode;
+ case eSymbolTypeResolver: return eAddressClassCode;
+ case eSymbolTypeData: return eAddressClassData;
+ case eSymbolTypeRuntime: return eAddressClassRuntime;
+ case eSymbolTypeException: return eAddressClassRuntime;
+ case eSymbolTypeSourceFile: return eAddressClassDebug;
+ case eSymbolTypeHeaderFile: return eAddressClassDebug;
+ case eSymbolTypeObjectFile: return eAddressClassDebug;
+ case eSymbolTypeCommonBlock: return eAddressClassDebug;
+ case eSymbolTypeBlock: return eAddressClassDebug;
+ case eSymbolTypeLocal: return eAddressClassData;
+ case eSymbolTypeParam: return eAddressClassData;
+ case eSymbolTypeVariable: return eAddressClassData;
+ case eSymbolTypeVariableType: return eAddressClassDebug;
+ case eSymbolTypeLineEntry: return eAddressClassDebug;
+ case eSymbolTypeLineHeader: return eAddressClassDebug;
+ case eSymbolTypeScopeBegin: return eAddressClassDebug;
+ case eSymbolTypeScopeEnd: return eAddressClassDebug;
+ case eSymbolTypeAdditional: return eAddressClassUnknown;
+ case eSymbolTypeCompiler: return eAddressClassDebug;
+ case eSymbolTypeInstrumentation:return eAddressClassDebug;
+ case eSymbolTypeUndefined: return eAddressClassUnknown;
+ case eSymbolTypeObjCClass: return eAddressClassRuntime;
+ case eSymbolTypeObjCMetaClass: return eAddressClassRuntime;
+ case eSymbolTypeObjCIVar: return eAddressClassRuntime;
+ }
+ }
+ }
+ return eAddressClassUnknown;
+}
+
+DataBufferSP
+ObjectFile::ReadMemory (const ProcessSP &process_sp, lldb::addr_t addr, size_t byte_size)
+{
+ DataBufferSP data_sp;
+ if (process_sp)
+ {
+ std::unique_ptr<DataBufferHeap> data_ap (new DataBufferHeap (byte_size, 0));
+ Error error;
+ const size_t bytes_read = process_sp->ReadMemory (addr,
+ data_ap->GetBytes(),
+ data_ap->GetByteSize(),
+ error);
+ if (bytes_read == byte_size)
+ data_sp.reset (data_ap.release());
+ }
+ return data_sp;
+}
+
+size_t
+ObjectFile::GetData (off_t offset, size_t length, DataExtractor &data) const
+{
+ // The entire file has already been mmap'ed into m_data, so just copy from there
+ // as the back mmap buffer will be shared with shared pointers.
+ return data.SetData (m_data, offset, length);
+}
+
+size_t
+ObjectFile::CopyData (off_t offset, size_t length, void *dst) const
+{
+ // The entire file has already been mmap'ed into m_data, so just copy from there
+ return m_data.CopyByteOrderedData (offset, length, dst, length, lldb::endian::InlHostByteOrder());
+}
+
+
+size_t
+ObjectFile::ReadSectionData (const Section *section, off_t section_offset, void *dst, size_t dst_len) const
+{
+ // If some other objectfile owns this data, pass this to them.
+ if (section->GetObjectFile() != this)
+ return section->GetObjectFile()->ReadSectionData (section, section_offset, dst, dst_len);
+
+ if (IsInMemory())
+ {
+ ProcessSP process_sp (m_process_wp.lock());
+ if (process_sp)
+ {
+ Error error;
+ const addr_t base_load_addr = section->GetLoadBaseAddress (&process_sp->GetTarget());
+ if (base_load_addr != LLDB_INVALID_ADDRESS)
+ return process_sp->ReadMemory (base_load_addr + section_offset, dst, dst_len, error);
+ }
+ }
+ else
+ {
+ const uint64_t section_file_size = section->GetFileSize();
+ if (section_offset < section_file_size)
+ {
+ const uint64_t section_bytes_left = section_file_size - section_offset;
+ uint64_t section_dst_len = dst_len;
+ if (section_dst_len > section_bytes_left)
+ section_dst_len = section_bytes_left;
+ return CopyData (section->GetFileOffset() + section_offset, section_dst_len, dst);
+ }
+ else
+ {
+ if (section->GetType() == eSectionTypeZeroFill)
+ {
+ const uint64_t section_size = section->GetByteSize();
+ const uint64_t section_bytes_left = section_size - section_offset;
+ uint64_t section_dst_len = dst_len;
+ if (section_dst_len > section_bytes_left)
+ section_dst_len = section_bytes_left;
+ bzero(dst, section_dst_len);
+ return section_dst_len;
+ }
+ }
+ }
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// Get the section data the file on disk
+//----------------------------------------------------------------------
+size_t
+ObjectFile::ReadSectionData (const Section *section, DataExtractor& section_data) const
+{
+ // If some other objectfile owns this data, pass this to them.
+ if (section->GetObjectFile() != this)
+ return section->GetObjectFile()->ReadSectionData (section, section_data);
+
+ if (IsInMemory())
+ {
+ ProcessSP process_sp (m_process_wp.lock());
+ if (process_sp)
+ {
+ const addr_t base_load_addr = section->GetLoadBaseAddress (&process_sp->GetTarget());
+ if (base_load_addr != LLDB_INVALID_ADDRESS)
+ {
+ DataBufferSP data_sp (ReadMemory (process_sp, base_load_addr, section->GetByteSize()));
+ if (data_sp)
+ {
+ section_data.SetData (data_sp, 0, data_sp->GetByteSize());
+ section_data.SetByteOrder (process_sp->GetByteOrder());
+ section_data.SetAddressByteSize (process_sp->GetAddressByteSize());
+ return section_data.GetByteSize();
+ }
+ }
+ }
+ }
+ else
+ {
+ // The object file now contains a full mmap'ed copy of the object file data, so just use this
+ return MemoryMapSectionData (section, section_data);
+ }
+ section_data.Clear();
+ return 0;
+}
+
+size_t
+ObjectFile::MemoryMapSectionData (const Section *section, DataExtractor& section_data) const
+{
+ // If some other objectfile owns this data, pass this to them.
+ if (section->GetObjectFile() != this)
+ return section->GetObjectFile()->MemoryMapSectionData (section, section_data);
+
+ if (IsInMemory())
+ {
+ return ReadSectionData (section, section_data);
+ }
+ else
+ {
+ // 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;
+}
+
+
+bool
+ObjectFile::SplitArchivePathWithObject (const char *path_with_object, FileSpec &archive_file, ConstString &archive_object, bool must_exist)
+{
+ RegularExpression g_object_regex("(.*)\\(([^\\)]+)\\)$");
+ RegularExpression::Match regex_match(2);
+ if (g_object_regex.Execute (path_with_object, &regex_match))
+ {
+ std::string path;
+ std::string obj;
+ if (regex_match.GetMatchAtIndex (path_with_object, 1, path) &&
+ regex_match.GetMatchAtIndex (path_with_object, 2, obj))
+ {
+ archive_file.SetFile (path.c_str(), false);
+ archive_object.SetCString(obj.c_str());
+ if (must_exist && !archive_file.Exists())
+ return false;
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+ObjectFile::ClearSymtab ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ {
+ log->Printf ("%p ObjectFile::ClearSymtab () symtab = %p",
+ this,
+ m_symtab_ap.get());
+ }
+ m_symtab_ap.reset();
+ }
+}
+
+SectionList *
+ObjectFile::GetSectionList()
+{
+ if (m_sections_ap.get() == NULL)
+ {
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ CreateSections(*module_sp->GetUnifiedSectionList());
+ }
+ return m_sections_ap.get();
+}
diff --git a/source/Symbol/Symbol.cpp b/source/Symbol/Symbol.cpp
new file mode 100644
index 000000000000..7f3543c3b232
--- /dev/null
+++ b/source/Symbol/Symbol.cpp
@@ -0,0 +1,462 @@
+//===-- Symbol.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/Symbol/Symbol.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+Symbol::Symbol() :
+ SymbolContextScope (),
+ m_uid (UINT32_MAX),
+ m_type_data (0),
+ m_type_data_resolved (false),
+ m_is_synthetic (false),
+ m_is_debug (false),
+ m_is_external (false),
+ m_size_is_sibling (false),
+ m_size_is_synthesized (false),
+ m_size_is_valid (false),
+ m_demangled_is_synthesized (false),
+ m_type (eSymbolTypeInvalid),
+ m_mangled (),
+ m_addr_range (),
+ m_flags ()
+{
+}
+
+Symbol::Symbol
+(
+ uint32_t symID,
+ const char *name,
+ bool name_is_mangled,
+ SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const lldb::SectionSP &section_sp,
+ addr_t offset,
+ addr_t size,
+ bool size_is_valid,
+ uint32_t flags
+) :
+ SymbolContextScope (),
+ m_uid (symID),
+ m_type_data (0),
+ m_type_data_resolved (false),
+ m_is_synthetic (is_artificial),
+ m_is_debug (is_debug),
+ m_is_external (external),
+ m_size_is_sibling (false),
+ m_size_is_synthesized (false),
+ m_size_is_valid (size_is_valid || size > 0),
+ m_demangled_is_synthesized (false),
+ m_type (type),
+ m_mangled (ConstString(name), name_is_mangled),
+ m_addr_range (section_sp, offset, size),
+ m_flags (flags)
+{
+}
+
+Symbol::Symbol
+(
+ uint32_t symID,
+ const char *name,
+ bool name_is_mangled,
+ SymbolType type,
+ bool external,
+ bool is_debug,
+ bool is_trampoline,
+ bool is_artificial,
+ const AddressRange &range,
+ bool size_is_valid,
+ uint32_t flags
+) :
+ SymbolContextScope (),
+ m_uid (symID),
+ m_type_data (0),
+ m_type_data_resolved (false),
+ m_is_synthetic (is_artificial),
+ m_is_debug (is_debug),
+ m_is_external (external),
+ m_size_is_sibling (false),
+ m_size_is_synthesized (false),
+ m_size_is_valid (size_is_valid || range.GetByteSize() > 0),
+ m_demangled_is_synthesized (false),
+ m_type (type),
+ m_mangled (ConstString(name), name_is_mangled),
+ m_addr_range (range),
+ m_flags (flags)
+{
+}
+
+Symbol::Symbol(const Symbol& rhs):
+ SymbolContextScope (rhs),
+ m_uid (rhs.m_uid),
+ m_type_data (rhs.m_type_data),
+ m_type_data_resolved (rhs.m_type_data_resolved),
+ m_is_synthetic (rhs.m_is_synthetic),
+ m_is_debug (rhs.m_is_debug),
+ m_is_external (rhs.m_is_external),
+ m_size_is_sibling (rhs.m_size_is_sibling),
+ m_size_is_synthesized (false),
+ m_size_is_valid (rhs.m_size_is_valid),
+ m_demangled_is_synthesized (rhs.m_demangled_is_synthesized),
+ m_type (rhs.m_type),
+ m_mangled (rhs.m_mangled),
+ m_addr_range (rhs.m_addr_range),
+ m_flags (rhs.m_flags)
+{
+}
+
+const Symbol&
+Symbol::operator= (const Symbol& rhs)
+{
+ if (this != &rhs)
+ {
+ SymbolContextScope::operator= (rhs);
+ m_uid = rhs.m_uid;
+ m_type_data = rhs.m_type_data;
+ m_type_data_resolved = rhs.m_type_data_resolved;
+ m_is_synthetic = rhs.m_is_synthetic;
+ m_is_debug = rhs.m_is_debug;
+ m_is_external = rhs.m_is_external;
+ m_size_is_sibling = rhs.m_size_is_sibling;
+ m_size_is_synthesized = rhs.m_size_is_sibling;
+ m_size_is_valid = rhs.m_size_is_valid;
+ m_demangled_is_synthesized = rhs.m_demangled_is_synthesized;
+ m_type = rhs.m_type;
+ m_mangled = rhs.m_mangled;
+ m_addr_range = rhs.m_addr_range;
+ m_flags = rhs.m_flags;
+ }
+ return *this;
+}
+
+void
+Symbol::Clear()
+{
+ m_uid = UINT32_MAX;
+ m_mangled.Clear();
+ m_type_data = 0;
+ m_type_data_resolved = false;
+ m_is_synthetic = false;
+ m_is_debug = false;
+ m_is_external = false;
+ m_size_is_sibling = false;
+ m_size_is_synthesized = false;
+ m_size_is_valid = false;
+ m_demangled_is_synthesized = false;
+ m_type = eSymbolTypeInvalid;
+ m_flags = 0;
+ m_addr_range.Clear();
+}
+
+bool
+Symbol::ValueIsAddress() const
+{
+ return m_addr_range.GetBaseAddress().GetSection().get() != NULL;
+}
+
+uint32_t
+Symbol::GetSiblingIndex() const
+{
+ return m_size_is_sibling ? m_addr_range.GetByteSize() : 0;
+}
+
+bool
+Symbol::IsTrampoline () const
+{
+ return m_type == eSymbolTypeTrampoline;
+}
+
+bool
+Symbol::IsIndirect () const
+{
+ return m_type == eSymbolTypeResolver;
+}
+
+void
+Symbol::GetDescription (Stream *s, lldb::DescriptionLevel level, Target *target) const
+{
+ s->Printf("id = {0x%8.8x}", m_uid);
+
+ if (m_addr_range.GetBaseAddress().GetSection())
+ {
+ if (ValueIsAddress())
+ {
+ const lldb::addr_t byte_size = GetByteSize();
+ if (byte_size > 0)
+ {
+ s->PutCString (", range = ");
+ m_addr_range.Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ }
+ else
+ {
+ s->PutCString (", address = ");
+ m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ }
+ }
+ else
+ s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
+ }
+ else
+ {
+ if (m_size_is_sibling)
+ s->Printf (", sibling = %5" PRIu64, m_addr_range.GetBaseAddress().GetOffset());
+ else
+ s->Printf (", value = 0x%16.16" PRIx64, m_addr_range.GetBaseAddress().GetOffset());
+ }
+ if (m_mangled.GetDemangledName())
+ s->Printf(", name=\"%s\"", m_mangled.GetDemangledName().AsCString());
+ if (m_mangled.GetMangledName())
+ s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString());
+
+}
+
+void
+Symbol::Dump(Stream *s, Target *target, uint32_t index) const
+{
+// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+// s->Indent();
+// s->Printf("Symbol[%5u] %6u %c%c %-12s ",
+ s->Printf("[%5u] %6u %c%c%c %-12s ",
+ index,
+ GetID(),
+ m_is_debug ? 'D' : ' ',
+ m_is_synthetic ? 'S' : ' ',
+ m_is_external ? 'X' : ' ',
+ GetTypeAsString());
+
+ // Make sure the size of the symbol is up to date before dumping
+ GetByteSize();
+
+ if (ValueIsAddress())
+ {
+ if (!m_addr_range.GetBaseAddress().Dump(s, NULL, Address::DumpStyleFileAddress))
+ s->Printf("%*s", 18, "");
+
+ s->PutChar(' ');
+
+ if (!m_addr_range.GetBaseAddress().Dump(s, target, Address::DumpStyleLoadAddress))
+ s->Printf("%*s", 18, "");
+
+ const char *format = m_size_is_sibling ?
+ " Sibling -> [%5llu] 0x%8.8x %s\n":
+ " 0x%16.16" PRIx64 " 0x%8.8x %s\n";
+ s->Printf( format,
+ GetByteSize(),
+ m_flags,
+ m_mangled.GetName().AsCString(""));
+ }
+ else
+ {
+ const char *format = m_size_is_sibling ?
+ "0x%16.16" PRIx64 " Sibling -> [%5llu] 0x%8.8x %s\n":
+ "0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x %s\n";
+ s->Printf( format,
+ m_addr_range.GetBaseAddress().GetOffset(),
+ GetByteSize(),
+ m_flags,
+ m_mangled.GetName().AsCString(""));
+ }
+}
+
+uint32_t
+Symbol::GetPrologueByteSize ()
+{
+ if (m_type == eSymbolTypeCode || m_type == eSymbolTypeResolver)
+ {
+ if (!m_type_data_resolved)
+ {
+ m_type_data_resolved = true;
+
+ const Address &base_address = m_addr_range.GetBaseAddress();
+ Function *function = base_address.CalculateSymbolContextFunction();
+ if (function)
+ {
+ // Functions have line entries which can also potentially have end of prologue information.
+ // So if this symbol points to a function, use the prologue information from there.
+ m_type_data = function->GetPrologueByteSize();
+ }
+ else
+ {
+ ModuleSP module_sp (base_address.GetModule());
+ SymbolContext sc;
+ if (module_sp)
+ {
+ uint32_t resolved_flags = module_sp->ResolveSymbolContextForAddress (base_address,
+ eSymbolContextLineEntry,
+ sc);
+ if (resolved_flags & eSymbolContextLineEntry)
+ {
+ // Default to the end of the first line entry.
+ m_type_data = sc.line_entry.range.GetByteSize();
+
+ // Set address for next line.
+ Address addr (base_address);
+ addr.Slide (m_type_data);
+
+ // Check the first few instructions and look for one that has a line number that is
+ // different than the first entry. This is also done in Function::GetPrologueByteSize().
+ uint16_t total_offset = m_type_data;
+ for (int idx = 0; idx < 6; ++idx)
+ {
+ SymbolContext sc_temp;
+ resolved_flags = module_sp->ResolveSymbolContextForAddress (addr, eSymbolContextLineEntry, sc_temp);
+ // Make sure we got line number information...
+ if (!(resolved_flags & eSymbolContextLineEntry))
+ break;
+
+ // If this line number is different than our first one, use it and we're done.
+ if (sc_temp.line_entry.line != sc.line_entry.line)
+ {
+ m_type_data = total_offset;
+ break;
+ }
+
+ // Slide addr up to the next line address.
+ addr.Slide (sc_temp.line_entry.range.GetByteSize());
+ total_offset += sc_temp.line_entry.range.GetByteSize();
+ // If we've gone too far, bail out.
+ if (total_offset >= m_addr_range.GetByteSize())
+ break;
+ }
+
+ // Sanity check - this may be a function in the middle of code that has debug information, but
+ // not for this symbol. So the line entries surrounding us won't lie inside our function.
+ // In that case, the line entry will be bigger than we are, so we do that quick check and
+ // if that is true, we just return 0.
+ if (m_type_data >= m_addr_range.GetByteSize())
+ m_type_data = 0;
+ }
+ else
+ {
+ // TODO: expose something in Process to figure out the
+ // size of a function prologue.
+ m_type_data = 0;
+ }
+ }
+ }
+ }
+ return m_type_data;
+ }
+ return 0;
+}
+
+bool
+Symbol::Compare(const ConstString& name, SymbolType type) const
+{
+ if (type == eSymbolTypeAny || m_type == type)
+ return m_mangled.GetMangledName() == name || m_mangled.GetDemangledName() == name;
+ return false;
+}
+
+#define ENUM_TO_CSTRING(x) case eSymbolType##x: return #x;
+
+const char *
+Symbol::GetTypeAsString() const
+{
+ switch (m_type)
+ {
+ ENUM_TO_CSTRING(Invalid);
+ ENUM_TO_CSTRING(Absolute);
+ ENUM_TO_CSTRING(Code);
+ ENUM_TO_CSTRING(Data);
+ ENUM_TO_CSTRING(Trampoline);
+ ENUM_TO_CSTRING(Runtime);
+ ENUM_TO_CSTRING(Exception);
+ ENUM_TO_CSTRING(SourceFile);
+ ENUM_TO_CSTRING(HeaderFile);
+ ENUM_TO_CSTRING(ObjectFile);
+ ENUM_TO_CSTRING(CommonBlock);
+ ENUM_TO_CSTRING(Block);
+ ENUM_TO_CSTRING(Local);
+ ENUM_TO_CSTRING(Param);
+ ENUM_TO_CSTRING(Variable);
+ ENUM_TO_CSTRING(VariableType);
+ ENUM_TO_CSTRING(LineEntry);
+ ENUM_TO_CSTRING(LineHeader);
+ ENUM_TO_CSTRING(ScopeBegin);
+ ENUM_TO_CSTRING(ScopeEnd);
+ ENUM_TO_CSTRING(Additional);
+ ENUM_TO_CSTRING(Compiler);
+ ENUM_TO_CSTRING(Instrumentation);
+ ENUM_TO_CSTRING(Undefined);
+ ENUM_TO_CSTRING(ObjCClass);
+ ENUM_TO_CSTRING(ObjCMetaClass);
+ ENUM_TO_CSTRING(ObjCIVar);
+ default:
+ break;
+ }
+ return "<unknown SymbolType>";
+}
+
+void
+Symbol::CalculateSymbolContext (SymbolContext *sc)
+{
+ // Symbols can reconstruct the symbol and the module in the symbol context
+ sc->symbol = this;
+ if (ValueIsAddress())
+ sc->module_sp = GetAddress().GetModule();
+ else
+ sc->module_sp.reset();
+}
+
+ModuleSP
+Symbol::CalculateSymbolContextModule ()
+{
+ if (ValueIsAddress())
+ return GetAddress().GetModule();
+ return ModuleSP();
+}
+
+Symbol *
+Symbol::CalculateSymbolContextSymbol ()
+{
+ return this;
+}
+
+void
+Symbol::DumpSymbolContext (Stream *s)
+{
+ bool dumped_module = false;
+ if (ValueIsAddress())
+ {
+ ModuleSP module_sp (GetAddress().GetModule());
+ if (module_sp)
+ {
+ dumped_module = true;
+ module_sp->DumpSymbolContext(s);
+ }
+ }
+ if (dumped_module)
+ s->PutCString(", ");
+
+ s->Printf("Symbol{0x%8.8x}", GetID());
+}
+
+lldb::addr_t
+Symbol::GetByteSize () const
+{
+ return m_addr_range.GetByteSize();
+}
+
diff --git a/source/Symbol/SymbolContext.cpp b/source/Symbol/SymbolContext.cpp
new file mode 100644
index 000000000000..ac91161f7d6f
--- /dev/null
+++ b/source/Symbol/SymbolContext.cpp
@@ -0,0 +1,1205 @@
+//===-- SymbolContext.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/Symbol/SymbolContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SymbolContext::SymbolContext() :
+ target_sp (),
+ module_sp (),
+ comp_unit (NULL),
+ function (NULL),
+ block (NULL),
+ line_entry (),
+ symbol (NULL)
+{
+}
+
+SymbolContext::SymbolContext(const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
+ target_sp (),
+ module_sp (m),
+ comp_unit (cu),
+ function (f),
+ block (b),
+ line_entry (),
+ symbol (s)
+{
+ if (le)
+ line_entry = *le;
+}
+
+SymbolContext::SymbolContext(const TargetSP &t, const ModuleSP& m, CompileUnit *cu, Function *f, Block *b, LineEntry *le, Symbol *s) :
+ target_sp (t),
+ module_sp (m),
+ comp_unit (cu),
+ function (f),
+ block (b),
+ line_entry (),
+ symbol (s)
+{
+ if (le)
+ line_entry = *le;
+}
+
+SymbolContext::SymbolContext(const SymbolContext& rhs) :
+ target_sp (rhs.target_sp),
+ module_sp (rhs.module_sp),
+ comp_unit (rhs.comp_unit),
+ function (rhs.function),
+ block (rhs.block),
+ line_entry (rhs.line_entry),
+ symbol (rhs.symbol)
+{
+}
+
+
+SymbolContext::SymbolContext (SymbolContextScope *sc_scope) :
+ target_sp (),
+ module_sp (),
+ comp_unit (NULL),
+ function (NULL),
+ block (NULL),
+ line_entry (),
+ symbol (NULL)
+{
+ sc_scope->CalculateSymbolContext (this);
+}
+
+SymbolContext::~SymbolContext ()
+{
+}
+
+const SymbolContext&
+SymbolContext::operator= (const SymbolContext& rhs)
+{
+ if (this != &rhs)
+ {
+ target_sp = rhs.target_sp;
+ module_sp = rhs.module_sp;
+ comp_unit = rhs.comp_unit;
+ function = rhs.function;
+ block = rhs.block;
+ line_entry = rhs.line_entry;
+ symbol = rhs.symbol;
+ }
+ return *this;
+}
+
+void
+SymbolContext::Clear(bool clear_target)
+{
+ if (clear_target)
+ target_sp.reset();
+ module_sp.reset();
+ comp_unit = NULL;
+ function = NULL;
+ block = NULL;
+ line_entry.Clear();
+ symbol = NULL;
+}
+
+bool
+SymbolContext::DumpStopContext
+(
+ Stream *s,
+ ExecutionContextScope *exe_scope,
+ const Address &addr,
+ bool show_fullpaths,
+ bool show_module,
+ bool show_inlined_frames
+) const
+{
+ bool dumped_something = false;
+ if (show_module && module_sp)
+ {
+ if (show_fullpaths)
+ *s << module_sp->GetFileSpec();
+ else
+ *s << module_sp->GetFileSpec().GetFilename();
+ s->PutChar('`');
+ dumped_something = true;
+ }
+
+ if (function != NULL)
+ {
+ SymbolContext inline_parent_sc;
+ Address inline_parent_addr;
+ if (function->GetMangled().GetName())
+ {
+ dumped_something = true;
+ function->GetMangled().GetName().Dump(s);
+ }
+
+ if (addr.IsValid())
+ {
+ const addr_t function_offset = addr.GetOffset() - function->GetAddressRange().GetBaseAddress().GetOffset();
+ if (function_offset)
+ {
+ dumped_something = true;
+ s->Printf(" + %" PRIu64, function_offset);
+ }
+ }
+
+ if (GetParentOfInlinedScope (addr, inline_parent_sc, inline_parent_addr))
+ {
+ dumped_something = true;
+ Block *inlined_block = block->GetContainingInlinedBlock();
+ const InlineFunctionInfo* inlined_block_info = inlined_block->GetInlinedFunctionInfo();
+ s->Printf (" [inlined] %s", inlined_block_info->GetName().GetCString());
+
+ lldb_private::AddressRange block_range;
+ if (inlined_block->GetRangeContainingAddress(addr, block_range))
+ {
+ const addr_t inlined_function_offset = addr.GetOffset() - block_range.GetBaseAddress().GetOffset();
+ if (inlined_function_offset)
+ {
+ s->Printf(" + %" PRIu64, inlined_function_offset);
+ }
+ }
+ const Declaration &call_site = inlined_block_info->GetCallSite();
+ if (call_site.IsValid())
+ {
+ s->PutCString(" at ");
+ call_site.DumpStopContext (s, show_fullpaths);
+ }
+ if (show_inlined_frames)
+ {
+ s->EOL();
+ s->Indent();
+ return inline_parent_sc.DumpStopContext (s, exe_scope, inline_parent_addr, show_fullpaths, show_module, show_inlined_frames);
+ }
+ }
+ else
+ {
+ if (line_entry.IsValid())
+ {
+ dumped_something = true;
+ s->PutCString(" at ");
+ if (line_entry.DumpStopContext(s, show_fullpaths))
+ dumped_something = true;
+ }
+ }
+ }
+ else if (symbol != NULL)
+ {
+ if (symbol->GetMangled().GetName())
+ {
+ dumped_something = true;
+ if (symbol->GetType() == eSymbolTypeTrampoline)
+ s->PutCString("symbol stub for: ");
+ symbol->GetMangled().GetName().Dump(s);
+ }
+
+ if (addr.IsValid() && symbol->ValueIsAddress())
+ {
+ const addr_t symbol_offset = addr.GetOffset() - symbol->GetAddress().GetOffset();
+ if (symbol_offset)
+ {
+ dumped_something = true;
+ s->Printf(" + %" PRIu64, symbol_offset);
+ }
+ }
+ }
+ else if (addr.IsValid())
+ {
+ addr.Dump(s, exe_scope, Address::DumpStyleModuleWithFileAddress);
+ dumped_something = true;
+ }
+ return dumped_something;
+}
+
+void
+SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target) const
+{
+ if (module_sp)
+ {
+ s->Indent(" Module: file = \"");
+ module_sp->GetFileSpec().Dump(s);
+ *s << '"';
+ if (module_sp->GetArchitecture().IsValid())
+ s->Printf (", arch = \"%s\"", module_sp->GetArchitecture().GetArchitectureName());
+ s->EOL();
+ }
+
+ if (comp_unit != NULL)
+ {
+ s->Indent("CompileUnit: ");
+ comp_unit->GetDescription (s, level);
+ s->EOL();
+ }
+
+ if (function != NULL)
+ {
+ s->Indent(" Function: ");
+ function->GetDescription (s, level, target);
+ s->EOL();
+
+ Type *func_type = function->GetType();
+ if (func_type)
+ {
+ s->Indent(" FuncType: ");
+ func_type->GetDescription (s, level, false);
+ s->EOL();
+ }
+ }
+
+ if (block != NULL)
+ {
+ std::vector<Block *> blocks;
+ blocks.push_back (block);
+ Block *parent_block = block->GetParent();
+
+ while (parent_block)
+ {
+ blocks.push_back (parent_block);
+ parent_block = parent_block->GetParent();
+ }
+ std::vector<Block *>::reverse_iterator pos;
+ std::vector<Block *>::reverse_iterator begin = blocks.rbegin();
+ std::vector<Block *>::reverse_iterator end = blocks.rend();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos == begin)
+ s->Indent(" Blocks: ");
+ else
+ s->Indent(" ");
+ (*pos)->GetDescription(s, function, level, target);
+ s->EOL();
+ }
+ }
+
+ if (line_entry.IsValid())
+ {
+ s->Indent(" LineEntry: ");
+ line_entry.GetDescription (s, level, comp_unit, target, false);
+ s->EOL();
+ }
+
+ if (symbol != NULL)
+ {
+ s->Indent(" Symbol: ");
+ symbol->GetDescription(s, level, target);
+ s->EOL();
+ }
+}
+
+uint32_t
+SymbolContext::GetResolvedMask () const
+{
+ uint32_t resolved_mask = 0;
+ if (target_sp) resolved_mask |= eSymbolContextTarget;
+ if (module_sp) resolved_mask |= eSymbolContextModule;
+ if (comp_unit) resolved_mask |= eSymbolContextCompUnit;
+ if (function) resolved_mask |= eSymbolContextFunction;
+ if (block) resolved_mask |= eSymbolContextBlock;
+ if (line_entry.IsValid()) resolved_mask |= eSymbolContextLineEntry;
+ if (symbol) resolved_mask |= eSymbolContextSymbol;
+ return resolved_mask;
+}
+
+void
+SymbolContext::Dump(Stream *s, Target *target) const
+{
+ *s << (void *)this << ": ";
+ s->Indent();
+ s->PutCString("SymbolContext");
+ s->IndentMore();
+ s->EOL();
+ s->IndentMore();
+ s->Indent();
+ *s << "Module = " << (void *)module_sp.get() << ' ';
+ if (module_sp)
+ module_sp->GetFileSpec().Dump(s);
+ s->EOL();
+ s->Indent();
+ *s << "CompileUnit = " << (void *)comp_unit;
+ if (comp_unit != NULL)
+ *s << " {0x" << comp_unit->GetID() << "} " << *(static_cast<FileSpec*> (comp_unit));
+ s->EOL();
+ s->Indent();
+ *s << "Function = " << (void *)function;
+ if (function != NULL)
+ {
+ *s << " {0x" << function->GetID() << "} " << function->GetType()->GetName() << ", address-range = ";
+ function->GetAddressRange().Dump(s, target, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress);
+ s->EOL();
+ s->Indent();
+ Type* func_type = function->GetType();
+ if (func_type)
+ {
+ *s << " Type = ";
+ func_type->Dump (s, false);
+ }
+ }
+ s->EOL();
+ s->Indent();
+ *s << "Block = " << (void *)block;
+ if (block != NULL)
+ *s << " {0x" << block->GetID() << '}';
+ // Dump the block and pass it a negative depth to we print all the parent blocks
+ //if (block != NULL)
+ // block->Dump(s, function->GetFileAddress(), INT_MIN);
+ s->EOL();
+ s->Indent();
+ *s << "LineEntry = ";
+ line_entry.Dump (s, target, true, Address::DumpStyleLoadAddress, Address::DumpStyleModuleWithFileAddress, true);
+ s->EOL();
+ s->Indent();
+ *s << "Symbol = " << (void *)symbol;
+ if (symbol != NULL && symbol->GetMangled())
+ *s << ' ' << symbol->GetMangled().GetName().AsCString();
+ s->EOL();
+ s->IndentLess();
+ s->IndentLess();
+}
+
+bool
+lldb_private::operator== (const SymbolContext& lhs, const SymbolContext& rhs)
+{
+ return lhs.function == rhs.function
+ && lhs.symbol == rhs.symbol
+ && lhs.module_sp.get() == rhs.module_sp.get()
+ && lhs.comp_unit == rhs.comp_unit
+ && lhs.target_sp.get() == rhs.target_sp.get()
+ && LineEntry::Compare(lhs.line_entry, rhs.line_entry) == 0;
+}
+
+bool
+lldb_private::operator!= (const SymbolContext& lhs, const SymbolContext& rhs)
+{
+ return lhs.function != rhs.function
+ || lhs.symbol != rhs.symbol
+ || lhs.module_sp.get() != rhs.module_sp.get()
+ || lhs.comp_unit != rhs.comp_unit
+ || lhs.target_sp.get() != rhs.target_sp.get()
+ || LineEntry::Compare(lhs.line_entry, rhs.line_entry) != 0;
+}
+
+bool
+SymbolContext::GetAddressRange (uint32_t scope,
+ uint32_t range_idx,
+ bool use_inline_block_range,
+ AddressRange &range) const
+{
+ if ((scope & eSymbolContextLineEntry) && line_entry.IsValid())
+ {
+ range = line_entry.range;
+ return true;
+ }
+
+ if ((scope & eSymbolContextBlock) && (block != NULL))
+ {
+ if (use_inline_block_range)
+ {
+ Block *inline_block = block->GetContainingInlinedBlock();
+ if (inline_block)
+ return inline_block->GetRangeAtIndex (range_idx, range);
+ }
+ else
+ {
+ return block->GetRangeAtIndex (range_idx, range);
+ }
+ }
+
+ if ((scope & eSymbolContextFunction) && (function != NULL))
+ {
+ if (range_idx == 0)
+ {
+ range = function->GetAddressRange();
+ return true;
+ }
+ }
+
+ if ((scope & eSymbolContextSymbol) && (symbol != NULL))
+ {
+ if (range_idx == 0)
+ {
+ if (symbol->ValueIsAddress())
+ {
+ range.GetBaseAddress() = symbol->GetAddress();
+ range.SetByteSize (symbol->GetByteSize());
+ return true;
+ }
+ }
+ }
+ range.Clear();
+ return false;
+}
+
+bool
+SymbolContext::GetParentOfInlinedScope (const Address &curr_frame_pc,
+ SymbolContext &next_frame_sc,
+ Address &next_frame_pc) const
+{
+ next_frame_sc.Clear(false);
+ next_frame_pc.Clear();
+
+ if (block)
+ {
+ //const addr_t curr_frame_file_addr = curr_frame_pc.GetFileAddress();
+
+ // In order to get the parent of an inlined function we first need to
+ // see if we are in an inlined block as "this->block" could be an
+ // inlined block, or a parent of "block" could be. So lets check if
+ // this block or one of this blocks parents is an inlined function.
+ Block *curr_inlined_block = block->GetContainingInlinedBlock();
+ if (curr_inlined_block)
+ {
+ // "this->block" is contained in an inline function block, so to
+ // get the scope above the inlined block, we get the parent of the
+ // inlined block itself
+ Block *next_frame_block = curr_inlined_block->GetParent();
+ // Now calculate the symbol context of the containing block
+ next_frame_block->CalculateSymbolContext (&next_frame_sc);
+
+ // If we get here we weren't able to find the return line entry using the nesting of the blocks and
+ // the line table. So just use the call site info from our inlined block.
+
+ AddressRange range;
+ if (curr_inlined_block->GetRangeContainingAddress (curr_frame_pc, range))
+ {
+ // To see there this new frame block it, we need to look at the
+ // call site information from
+ const InlineFunctionInfo* curr_inlined_block_inlined_info = curr_inlined_block->GetInlinedFunctionInfo();
+ next_frame_pc = range.GetBaseAddress();
+ next_frame_sc.line_entry.range.GetBaseAddress() = next_frame_pc;
+ next_frame_sc.line_entry.file = curr_inlined_block_inlined_info->GetCallSite().GetFile();
+ next_frame_sc.line_entry.line = curr_inlined_block_inlined_info->GetCallSite().GetLine();
+ next_frame_sc.line_entry.column = curr_inlined_block_inlined_info->GetCallSite().GetColumn();
+ return true;
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));
+
+ if (log)
+ {
+ log->Printf ("warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64,
+ curr_inlined_block->GetID(), curr_frame_pc.GetFileAddress());
+ }
+#ifdef LLDB_CONFIGURATION_DEBUG
+ else
+ {
+ ObjectFile *objfile = NULL;
+ if (module_sp)
+ {
+ SymbolVendor *symbol_vendor = module_sp->GetSymbolVendor();
+ if (symbol_vendor)
+ {
+ SymbolFile *symbol_file = symbol_vendor->GetSymbolFile();
+ if (symbol_file)
+ objfile = symbol_file->GetObjectFile();
+ }
+ }
+ if (objfile)
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64 " in %s\n",
+ curr_inlined_block->GetID(),
+ curr_frame_pc.GetFileAddress(),
+ objfile->GetFileSpec().GetPath().c_str());
+ }
+ else
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: inlined block 0x%8.8" PRIx64 " doesn't have a range that contains file address 0x%" PRIx64 "\n",
+ curr_inlined_block->GetID(),
+ curr_frame_pc.GetFileAddress());
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ return false;
+}
+
+Block *
+SymbolContext::GetFunctionBlock ()
+{
+ if (function)
+ {
+ if (block)
+ {
+ // If this symbol context has a block, check to see if this block
+ // is itself, or is contained within a block with inlined function
+ // information. If so, then the inlined block is the block that
+ // defines the function.
+ Block *inlined_block = block->GetContainingInlinedBlock();
+ if (inlined_block)
+ return inlined_block;
+
+ // The block in this symbol context is not inside an inlined
+ // block, so the block that defines the function is the function's
+ // top level block, which is returned below.
+ }
+
+ // There is no block information in this symbol context, so we must
+ // assume that the block that is desired is the top level block of
+ // the function itself.
+ return &function->GetBlock(true);
+ }
+ return NULL;
+}
+
+bool
+SymbolContext::GetFunctionMethodInfo (lldb::LanguageType &language,
+ bool &is_instance_method,
+ ConstString &language_object_name)
+
+
+{
+ Block *function_block = GetFunctionBlock ();
+ if (function_block)
+ {
+ clang::DeclContext *decl_context = function_block->GetClangDeclContext();
+
+ if (decl_context)
+ {
+ return ClangASTContext::GetClassMethodInfoForDeclContext (decl_context,
+ language,
+ is_instance_method,
+ language_object_name);
+ }
+ }
+ language = eLanguageTypeUnknown;
+ is_instance_method = false;
+ language_object_name.Clear();
+ return false;
+}
+
+ConstString
+SymbolContext::GetFunctionName (Mangled::NamePreference preference) const
+{
+ if (function)
+ {
+ if (block)
+ {
+ Block *inlined_block = block->GetContainingInlinedBlock();
+
+ if (inlined_block)
+ {
+ const InlineFunctionInfo *inline_info = inlined_block->GetInlinedFunctionInfo();
+ if (inline_info)
+ return inline_info->GetName();
+ }
+ }
+ return function->GetMangled().GetName(preference);
+ }
+ else if (symbol && symbol->ValueIsAddress())
+ {
+ return symbol->GetMangled().GetName(preference);
+ }
+ else
+ {
+ // No function, return an empty string.
+ return ConstString();
+ }
+}
+
+LineEntry
+SymbolContext::GetFunctionStartLineEntry () const
+{
+ LineEntry line_entry;
+ Address start_addr;
+ if (block)
+ {
+ Block *inlined_block = block->GetContainingInlinedBlock();
+ if (inlined_block)
+ {
+ if (inlined_block->GetStartAddress (start_addr))
+ {
+ if (start_addr.CalculateSymbolContextLineEntry (line_entry))
+ return line_entry;
+ }
+ return LineEntry();
+ }
+ }
+
+ if (function)
+ {
+ if (function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry(line_entry))
+ return line_entry;
+ }
+ return LineEntry();
+}
+
+//----------------------------------------------------------------------
+//
+// SymbolContextSpecifier
+//
+//----------------------------------------------------------------------
+
+SymbolContextSpecifier::SymbolContextSpecifier (const TargetSP &target_sp) :
+ m_target_sp (target_sp),
+ m_module_spec (),
+ m_module_sp (),
+ m_file_spec_ap (),
+ m_start_line (0),
+ m_end_line (0),
+ m_function_spec (),
+ m_class_name (),
+ m_address_range_ap (),
+ m_type (eNothingSpecified)
+{
+}
+
+SymbolContextSpecifier::~SymbolContextSpecifier()
+{
+}
+
+bool
+SymbolContextSpecifier::AddLineSpecification (uint32_t line_no, SpecificationType type)
+{
+ bool return_value = true;
+ switch (type)
+ {
+ case eNothingSpecified:
+ Clear();
+ break;
+ case eLineStartSpecified:
+ m_start_line = line_no;
+ m_type |= eLineStartSpecified;
+ break;
+ case eLineEndSpecified:
+ m_end_line = line_no;
+ m_type |= eLineEndSpecified;
+ break;
+ default:
+ return_value = false;
+ break;
+ }
+ return return_value;
+}
+
+bool
+SymbolContextSpecifier::AddSpecification (const char *spec_string, SpecificationType type)
+{
+ bool return_value = true;
+ switch (type)
+ {
+ case eNothingSpecified:
+ Clear();
+ break;
+ case eModuleSpecified:
+ {
+ // See if we can find the Module, if so stick it in the SymbolContext.
+ FileSpec module_file_spec(spec_string, false);
+ ModuleSpec module_spec (module_file_spec);
+ lldb::ModuleSP module_sp (m_target_sp->GetImages().FindFirstModule (module_spec));
+ m_type |= eModuleSpecified;
+ if (module_sp)
+ m_module_sp = module_sp;
+ else
+ m_module_spec.assign (spec_string);
+ }
+ break;
+ case eFileSpecified:
+ // CompUnits can't necessarily be resolved here, since an inlined function might show up in
+ // a number of CompUnits. Instead we just convert to a FileSpec and store it away.
+ m_file_spec_ap.reset (new FileSpec (spec_string, false));
+ m_type |= eFileSpecified;
+ break;
+ case eLineStartSpecified:
+ m_start_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
+ if (return_value)
+ m_type |= eLineStartSpecified;
+ break;
+ case eLineEndSpecified:
+ m_end_line = Args::StringToSInt32(spec_string, 0, 0, &return_value);
+ if (return_value)
+ m_type |= eLineEndSpecified;
+ break;
+ case eFunctionSpecified:
+ m_function_spec.assign(spec_string);
+ m_type |= eFunctionSpecified;
+ break;
+ case eClassOrNamespaceSpecified:
+ Clear();
+ m_class_name.assign (spec_string);
+ m_type = eClassOrNamespaceSpecified;
+ break;
+ case eAddressRangeSpecified:
+ // Not specified yet...
+ break;
+ }
+
+ return return_value;
+}
+
+void
+SymbolContextSpecifier::Clear()
+{
+ m_module_spec.clear();
+ m_file_spec_ap.reset();
+ m_function_spec.clear();
+ m_class_name.clear();
+ m_start_line = 0;
+ m_end_line = 0;
+ m_address_range_ap.reset();
+
+ m_type = eNothingSpecified;
+}
+
+bool
+SymbolContextSpecifier::SymbolContextMatches(SymbolContext &sc)
+{
+ if (m_type == eNothingSpecified)
+ return true;
+
+ if (m_target_sp.get() != sc.target_sp.get())
+ return false;
+
+ if (m_type & eModuleSpecified)
+ {
+ if (sc.module_sp)
+ {
+ if (m_module_sp.get() != NULL)
+ {
+ if (m_module_sp.get() != sc.module_sp.get())
+ return false;
+ }
+ else
+ {
+ FileSpec module_file_spec (m_module_spec.c_str(), false);
+ if (!FileSpec::Equal (module_file_spec, sc.module_sp->GetFileSpec(), false))
+ return false;
+ }
+ }
+ }
+ if (m_type & eFileSpecified)
+ {
+ if (m_file_spec_ap.get())
+ {
+ // If we don't have a block or a comp_unit, then we aren't going to match a source file.
+ if (sc.block == NULL && sc.comp_unit == NULL)
+ return false;
+
+ // Check if the block is present, and if so is it inlined:
+ bool was_inlined = false;
+ if (sc.block != NULL)
+ {
+ const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
+ if (inline_info != NULL)
+ {
+ was_inlined = true;
+ if (!FileSpec::Equal (inline_info->GetDeclaration().GetFile(), *(m_file_spec_ap.get()), false))
+ return false;
+ }
+ }
+
+ // Next check the comp unit, but only if the SymbolContext was not inlined.
+ if (!was_inlined && sc.comp_unit != NULL)
+ {
+ if (!FileSpec::Equal (*(sc.comp_unit), *(m_file_spec_ap.get()), false))
+ return false;
+ }
+ }
+ }
+ if (m_type & eLineStartSpecified
+ || m_type & eLineEndSpecified)
+ {
+ if (sc.line_entry.line < m_start_line || sc.line_entry.line > m_end_line)
+ return false;
+ }
+
+ if (m_type & eFunctionSpecified)
+ {
+ // First check the current block, and if it is inlined, get the inlined function name:
+ bool was_inlined = false;
+ ConstString func_name(m_function_spec.c_str());
+
+ if (sc.block != NULL)
+ {
+ const InlineFunctionInfo *inline_info = sc.block->GetInlinedFunctionInfo();
+ if (inline_info != NULL)
+ {
+ was_inlined = true;
+ const Mangled &name = inline_info->GetMangled();
+ if (!name.NameMatches (func_name))
+ return false;
+ }
+ }
+ // If it wasn't inlined, check the name in the function or symbol:
+ if (!was_inlined)
+ {
+ if (sc.function != NULL)
+ {
+ if (!sc.function->GetMangled().NameMatches(func_name))
+ return false;
+ }
+ else if (sc.symbol != NULL)
+ {
+ if (!sc.symbol->GetMangled().NameMatches(func_name))
+ return false;
+ }
+ }
+
+
+ }
+
+ return true;
+}
+
+bool
+SymbolContextSpecifier::AddressMatches(lldb::addr_t addr)
+{
+ if (m_type & eAddressRangeSpecified)
+ {
+
+ }
+ else
+ {
+ Address match_address (addr, NULL);
+ SymbolContext sc;
+ m_target_sp->GetImages().ResolveSymbolContextForAddress(match_address, eSymbolContextEverything, sc);
+ return SymbolContextMatches(sc);
+ }
+ return true;
+}
+
+void
+SymbolContextSpecifier::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ char path_str[PATH_MAX + 1];
+
+ if (m_type == eNothingSpecified)
+ {
+ s->Printf ("Nothing specified.\n");
+ }
+
+ if (m_type == eModuleSpecified)
+ {
+ s->Indent();
+ if (m_module_sp)
+ {
+ m_module_sp->GetFileSpec().GetPath (path_str, PATH_MAX);
+ s->Printf ("Module: %s\n", path_str);
+ }
+ else
+ s->Printf ("Module: %s\n", m_module_spec.c_str());
+ }
+
+ if (m_type == eFileSpecified && m_file_spec_ap.get() != NULL)
+ {
+ m_file_spec_ap->GetPath (path_str, PATH_MAX);
+ s->Indent();
+ s->Printf ("File: %s", path_str);
+ if (m_type == eLineStartSpecified)
+ {
+ s->Printf (" from line %lu", m_start_line);
+ if (m_type == eLineEndSpecified)
+ s->Printf ("to line %lu", m_end_line);
+ else
+ s->Printf ("to end");
+ }
+ else if (m_type == eLineEndSpecified)
+ {
+ s->Printf (" from start to line %ld", m_end_line);
+ }
+ s->Printf (".\n");
+ }
+
+ if (m_type == eLineStartSpecified)
+ {
+ s->Indent();
+ s->Printf ("From line %lu", m_start_line);
+ if (m_type == eLineEndSpecified)
+ s->Printf ("to line %lu", m_end_line);
+ else
+ s->Printf ("to end");
+ s->Printf (".\n");
+ }
+ else if (m_type == eLineEndSpecified)
+ {
+ s->Printf ("From start to line %ld.\n", m_end_line);
+ }
+
+ if (m_type == eFunctionSpecified)
+ {
+ s->Indent();
+ s->Printf ("Function: %s.\n", m_function_spec.c_str());
+ }
+
+ if (m_type == eClassOrNamespaceSpecified)
+ {
+ s->Indent();
+ s->Printf ("Class name: %s.\n", m_class_name.c_str());
+ }
+
+ if (m_type == eAddressRangeSpecified && m_address_range_ap.get() != NULL)
+ {
+ s->Indent();
+ s->PutCString ("Address range: ");
+ m_address_range_ap->Dump (s, m_target_sp.get(), Address::DumpStyleLoadAddress, Address::DumpStyleFileAddress);
+ s->PutCString ("\n");
+ }
+}
+
+//----------------------------------------------------------------------
+//
+// SymbolContextList
+//
+//----------------------------------------------------------------------
+
+
+SymbolContextList::SymbolContextList() :
+ m_symbol_contexts()
+{
+}
+
+SymbolContextList::~SymbolContextList()
+{
+}
+
+void
+SymbolContextList::Append(const SymbolContext& sc)
+{
+ m_symbol_contexts.push_back(sc);
+}
+
+void
+SymbolContextList::Append (const SymbolContextList& sc_list)
+{
+ collection::const_iterator pos, end = sc_list.m_symbol_contexts.end();
+ for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos)
+ m_symbol_contexts.push_back (*pos);
+}
+
+
+uint32_t
+SymbolContextList::AppendIfUnique (const SymbolContextList& sc_list, bool merge_symbol_into_function)
+{
+ uint32_t unique_sc_add_count = 0;
+ collection::const_iterator pos, end = sc_list.m_symbol_contexts.end();
+ for (pos = sc_list.m_symbol_contexts.begin(); pos != end; ++pos)
+ {
+ if (AppendIfUnique (*pos, merge_symbol_into_function))
+ ++unique_sc_add_count;
+ }
+ return unique_sc_add_count;
+}
+
+bool
+SymbolContextList::AppendIfUnique (const SymbolContext& sc, bool merge_symbol_into_function)
+{
+ collection::iterator pos, end = m_symbol_contexts.end();
+ for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
+ {
+ if (*pos == sc)
+ return false;
+ }
+ if (merge_symbol_into_function
+ && sc.symbol != NULL
+ && sc.comp_unit == NULL
+ && sc.function == NULL
+ && sc.block == NULL
+ && sc.line_entry.IsValid() == false)
+ {
+ if (sc.symbol->ValueIsAddress())
+ {
+ for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
+ {
+ // Don't merge symbols into inlined function symbol contexts
+ if (pos->block && pos->block->GetContainingInlinedBlock())
+ continue;
+
+ if (pos->function)
+ {
+ if (pos->function->GetAddressRange().GetBaseAddress() == sc.symbol->GetAddress())
+ {
+ // Do we already have a function with this symbol?
+ if (pos->symbol == sc.symbol)
+ return false;
+ if (pos->symbol == NULL)
+ {
+ pos->symbol = sc.symbol;
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ m_symbol_contexts.push_back(sc);
+ return true;
+}
+
+bool
+SymbolContextList::MergeSymbolContextIntoFunctionContext (const SymbolContext& symbol_sc,
+ uint32_t start_idx,
+ uint32_t stop_idx)
+{
+ if (symbol_sc.symbol != NULL
+ && symbol_sc.comp_unit == NULL
+ && symbol_sc.function == NULL
+ && symbol_sc.block == NULL
+ && symbol_sc.line_entry.IsValid() == false)
+ {
+ if (symbol_sc.symbol->ValueIsAddress())
+ {
+ const size_t end = std::min<size_t>(m_symbol_contexts.size(), stop_idx);
+ for (size_t i=start_idx; i<end; ++i)
+ {
+ const SymbolContext &function_sc = m_symbol_contexts[i];
+ // Don't merge symbols into inlined function symbol contexts
+ if (function_sc.block && function_sc.block->GetContainingInlinedBlock())
+ continue;
+
+ if (function_sc.function)
+ {
+ if (function_sc.function->GetAddressRange().GetBaseAddress() == symbol_sc.symbol->GetAddress())
+ {
+ // Do we already have a function with this symbol?
+ if (function_sc.symbol == symbol_sc.symbol)
+ return true; // Already have a symbol context with this symbol, return true
+
+ if (function_sc.symbol == NULL)
+ {
+ // We successfully merged this symbol into an existing symbol context
+ m_symbol_contexts[i].symbol = symbol_sc.symbol;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void
+SymbolContextList::Clear()
+{
+ m_symbol_contexts.clear();
+}
+
+void
+SymbolContextList::Dump(Stream *s, Target *target) const
+{
+
+ *s << (void *)this << ": ";
+ s->Indent();
+ s->PutCString("SymbolContextList");
+ s->EOL();
+ s->IndentMore();
+
+ collection::const_iterator pos, end = m_symbol_contexts.end();
+ for (pos = m_symbol_contexts.begin(); pos != end; ++pos)
+ {
+ //pos->Dump(s, target);
+ pos->GetDescription(s, eDescriptionLevelVerbose, target);
+ }
+ s->IndentLess();
+}
+
+bool
+SymbolContextList::GetContextAtIndex(size_t idx, SymbolContext& sc) const
+{
+ if (idx < m_symbol_contexts.size())
+ {
+ sc = m_symbol_contexts[idx];
+ return true;
+ }
+ return false;
+}
+
+bool
+SymbolContextList::GetLastContext(SymbolContext& sc) const
+{
+ if (!m_symbol_contexts.empty())
+ {
+ sc = m_symbol_contexts.back();
+ return true;
+ }
+ return false;
+}
+
+bool
+SymbolContextList::RemoveContextAtIndex (size_t idx)
+{
+ if (idx < m_symbol_contexts.size())
+ {
+ m_symbol_contexts.erase(m_symbol_contexts.begin() + idx);
+ return true;
+ }
+ return false;
+}
+
+uint32_t
+SymbolContextList::GetSize() const
+{
+ return m_symbol_contexts.size();
+}
+
+uint32_t
+SymbolContextList::NumLineEntriesWithLine (uint32_t line) const
+{
+ uint32_t match_count = 0;
+ const size_t size = m_symbol_contexts.size();
+ for (size_t idx = 0; idx<size; ++idx)
+ {
+ if (m_symbol_contexts[idx].line_entry.line == line)
+ ++match_count;
+ }
+ return match_count;
+}
+
+void
+SymbolContextList::GetDescription(Stream *s,
+ lldb::DescriptionLevel level,
+ Target *target) const
+{
+ const size_t size = m_symbol_contexts.size();
+ for (size_t idx = 0; idx<size; ++idx)
+ m_symbol_contexts[idx].GetDescription (s, level, target);
+}
+
+bool
+lldb_private::operator== (const SymbolContextList& lhs, const SymbolContextList& rhs)
+{
+ const uint32_t size = lhs.GetSize();
+ if (size != rhs.GetSize())
+ return false;
+
+ SymbolContext lhs_sc;
+ SymbolContext rhs_sc;
+ for (uint32_t i=0; i<size; ++i)
+ {
+ lhs.GetContextAtIndex(i, lhs_sc);
+ rhs.GetContextAtIndex(i, rhs_sc);
+ if (lhs_sc != rhs_sc)
+ return false;
+ }
+ return true;
+}
+
+bool
+lldb_private::operator!= (const SymbolContextList& lhs, const SymbolContextList& rhs)
+{
+ return !(lhs == rhs);
+}
+
diff --git a/source/Symbol/SymbolFile.cpp b/source/Symbol/SymbolFile.cpp
new file mode 100644
index 000000000000..412c4600c9f7
--- /dev/null
+++ b/source/Symbol/SymbolFile.cpp
@@ -0,0 +1,89 @@
+//===-- SymbolFile.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/Symbol/SymbolFile.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb_private;
+
+SymbolFile*
+SymbolFile::FindPlugin (ObjectFile* obj_file)
+{
+ std::unique_ptr<SymbolFile> best_symfile_ap;
+ if (obj_file != NULL)
+ {
+
+ // We need to test the abilities of this section list. So create what it would
+ // be with this new obj_file.
+ lldb::ModuleSP module_sp(obj_file->GetModule());
+ if (module_sp)
+ {
+ // Default to the main module section list.
+ ObjectFile *module_obj_file = module_sp->GetObjectFile();
+ if (module_obj_file != obj_file)
+ {
+ // Make sure the main object file's sections are created
+ module_obj_file->GetSectionList();
+ obj_file->CreateSections (*module_sp->GetUnifiedSectionList());
+ }
+ }
+
+ // TODO: Load any plug-ins in the appropriate plug-in search paths and
+ // iterate over all of them to find the best one for the job.
+
+ uint32_t best_symfile_abilities = 0;
+
+ SymbolFileCreateInstance create_callback;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetSymbolFileCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<SymbolFile> curr_symfile_ap(create_callback(obj_file));
+
+ if (curr_symfile_ap.get())
+ {
+ const uint32_t sym_file_abilities = curr_symfile_ap->GetAbilities();
+ if (sym_file_abilities > best_symfile_abilities)
+ {
+ best_symfile_abilities = sym_file_abilities;
+ best_symfile_ap.reset (curr_symfile_ap.release());
+ // If any symbol file parser has all of the abilities, then
+ // we should just stop looking.
+ if ((kAllAbilities & sym_file_abilities) == kAllAbilities)
+ break;
+ }
+ }
+ }
+ if (best_symfile_ap.get())
+ {
+ // Let the winning symbol file parser initialize itself more
+ // completely now that it has been chosen
+ best_symfile_ap->InitializeObject();
+ }
+ }
+ return best_symfile_ap.release();
+}
+
+TypeList *
+SymbolFile::GetTypeList ()
+{
+ if (m_obj_file)
+ return m_obj_file->GetModule()->GetTypeList();
+ return NULL;
+}
+
+lldb_private::ClangASTContext &
+SymbolFile::GetClangASTContext ()
+{
+ return m_obj_file->GetModule()->GetClangASTContext();
+}
diff --git a/source/Symbol/SymbolVendor.cpp b/source/Symbol/SymbolVendor.cpp
new file mode 100644
index 000000000000..b51ac5a550fb
--- /dev/null
+++ b/source/Symbol/SymbolVendor.cpp
@@ -0,0 +1,486 @@
+//===-- SymbolVendor.mm -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Symbol/SymbolVendor.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// FindPlugin
+//
+// Platforms can register a callback to use when creating symbol
+// vendors to allow for complex debug information file setups, and to
+// also allow for finding separate debug information files.
+//----------------------------------------------------------------------
+SymbolVendor*
+SymbolVendor::FindPlugin (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
+{
+ std::unique_ptr<SymbolVendor> instance_ap;
+ SymbolVendorCreateInstance create_callback;
+
+ for (size_t idx = 0; (create_callback = PluginManager::GetSymbolVendorCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ instance_ap.reset(create_callback(module_sp, feedback_strm));
+
+ if (instance_ap.get())
+ {
+ return instance_ap.release();
+ }
+ }
+ // The default implementation just tries to create debug information using the
+ // file representation for the module.
+ instance_ap.reset(new SymbolVendor(module_sp));
+ if (instance_ap.get())
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ instance_ap->AddSymbolFileRepresentation(objfile->shared_from_this());
+ }
+ return instance_ap.release();
+}
+
+//----------------------------------------------------------------------
+// SymbolVendor constructor
+//----------------------------------------------------------------------
+SymbolVendor::SymbolVendor(const lldb::ModuleSP &module_sp) :
+ ModuleChild (module_sp),
+ m_type_list(),
+ m_compile_units(),
+ m_sym_file_ap()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendor::~SymbolVendor()
+{
+}
+
+//----------------------------------------------------------------------
+// Add a represention given an object file.
+//----------------------------------------------------------------------
+void
+SymbolVendor::AddSymbolFileRepresentation(const ObjectFileSP &objfile_sp)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (objfile_sp)
+ {
+ m_objfile_sp = objfile_sp;
+ m_sym_file_ap.reset(SymbolFile::FindPlugin(objfile_sp.get()));
+ }
+ }
+}
+
+bool
+SymbolVendor::SetCompileUnitAtIndex (size_t idx, const CompUnitSP &cu_sp)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ const size_t num_compile_units = GetNumCompileUnits();
+ if (idx < num_compile_units)
+ {
+ // Fire off an assertion if this compile unit already exists for now.
+ // The partial parsing should take care of only setting the compile
+ // unit once, so if this assertion fails, we need to make sure that
+ // we don't have a race condition, or have a second parse of the same
+ // compile unit.
+ assert(m_compile_units[idx].get() == NULL);
+ m_compile_units[idx] = cu_sp;
+ return true;
+ }
+ else
+ {
+ // This should NOT happen, and if it does, we want to crash and know
+ // about it
+ assert (idx < num_compile_units);
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolVendor::GetNumCompileUnits()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_compile_units.empty())
+ {
+ if (m_sym_file_ap.get())
+ {
+ // Resize our array of compile unit shared pointers -- which will
+ // each remain NULL until someone asks for the actual compile unit
+ // information. When this happens, the symbol file will be asked
+ // to parse this compile unit information.
+ m_compile_units.resize(m_sym_file_ap->GetNumCompileUnits());
+ }
+ }
+ }
+ return m_compile_units.size();
+}
+
+lldb::LanguageType
+SymbolVendor::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitLanguage(sc);
+ }
+ return eLanguageTypeUnknown;
+}
+
+
+size_t
+SymbolVendor::ParseCompileUnitFunctions (const SymbolContext &sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitFunctions(sc);
+ }
+ return 0;
+}
+
+bool
+SymbolVendor::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitLineTable(sc);
+ }
+ return false;
+}
+
+bool
+SymbolVendor::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseCompileUnitSupportFiles(sc, support_files);
+ }
+ return false;
+}
+
+size_t
+SymbolVendor::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseFunctionBlocks(sc);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::ParseTypes (const SymbolContext &sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseTypes(sc);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::ParseVariablesForContext (const SymbolContext& sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ParseVariablesForContext(sc);
+ }
+ return 0;
+}
+
+Type*
+SymbolVendor::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ResolveTypeUID(type_uid);
+ }
+ return NULL;
+}
+
+
+uint32_t
+SymbolVendor::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ResolveSymbolContext(so_addr, resolve_scope, sc);
+ }
+ return 0;
+}
+
+uint32_t
+SymbolVendor::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::FindGlobalVariables (const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, size_t max_matches, VariableList& variables)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindGlobalVariables(name, namespace_decl, append, max_matches, variables);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::FindGlobalVariables (const RegularExpression& regex, bool append, size_t max_matches, VariableList& variables)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindGlobalVariables(regex, append, max_matches, variables);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, append, sc_list);
+ }
+ return 0;
+}
+
+size_t
+SymbolVendor::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindFunctions(regex, include_inlines, append, sc_list);
+ }
+ return 0;
+}
+
+
+size_t
+SymbolVendor::FindTypes (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, size_t max_matches, TypeList& types)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->FindTypes(sc, name, namespace_decl, append, max_matches, types);
+ }
+ if (!append)
+ types.Clear();
+ return 0;
+}
+
+size_t
+SymbolVendor::GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ return m_sym_file_ap->GetTypes (sc_scope, type_mask, type_list);
+ }
+ return 0;
+}
+
+ClangNamespaceDecl
+SymbolVendor::FindNamespace(const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *parent_namespace_decl)
+{
+ ClangNamespaceDecl namespace_decl;
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+ if (m_sym_file_ap.get())
+ namespace_decl = m_sym_file_ap->FindNamespace (sc, name, parent_namespace_decl);
+ }
+ return namespace_decl;
+}
+
+void
+SymbolVendor::Dump(Stream *s)
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ bool show_context = false;
+
+ s->Printf("%p: ", this);
+ s->Indent();
+ s->PutCString("SymbolVendor");
+ if (m_sym_file_ap.get())
+ {
+ ObjectFile *objfile = m_sym_file_ap->GetObjectFile();
+ if (objfile)
+ {
+ const FileSpec &objfile_file_spec = objfile->GetFileSpec();
+ if (objfile_file_spec)
+ {
+ s->PutCString(" (");
+ objfile_file_spec.Dump(s);
+ s->PutChar(')');
+ }
+ }
+ }
+ s->EOL();
+ s->IndentMore();
+ m_type_list.Dump(s, show_context);
+
+ CompileUnitConstIter cu_pos, cu_end;
+ cu_end = m_compile_units.end();
+ for (cu_pos = m_compile_units.begin(); cu_pos != cu_end; ++cu_pos)
+ {
+ // We currently only dump the compile units that have been parsed
+ if (cu_pos->get())
+ (*cu_pos)->Dump(s, show_context);
+ }
+
+ s->IndentLess();
+ }
+}
+
+CompUnitSP
+SymbolVendor::GetCompileUnitAtIndex(size_t idx)
+{
+ CompUnitSP cu_sp;
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ const size_t num_compile_units = GetNumCompileUnits();
+ if (idx < num_compile_units)
+ {
+ cu_sp = m_compile_units[idx];
+ if (cu_sp.get() == NULL)
+ {
+ m_compile_units[idx] = m_sym_file_ap->ParseCompileUnitAtIndex(idx);
+ cu_sp = m_compile_units[idx];
+ }
+ }
+ }
+ return cu_sp;
+}
+
+Symtab *
+SymbolVendor::GetSymtab ()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ // Get symbol table from unified section list.
+ return objfile->GetSymtab ();
+ }
+ }
+ return NULL;
+}
+
+void
+SymbolVendor::ClearSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ // Clear symbol table from unified section list.
+ objfile->ClearSymtab ();
+ }
+ }
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SymbolVendor::GetPluginName()
+{
+ static ConstString g_name("vendor-default");
+ return g_name;
+}
+
+uint32_t
+SymbolVendor::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Symbol/Symtab.cpp b/source/Symbol/Symtab.cpp
new file mode 100644
index 000000000000..27af6988aa9d
--- /dev/null
+++ b/source/Symbol/Symtab.cpp
@@ -0,0 +1,1211 @@
+//===-- Symtab.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <map>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+Symtab::Symtab(ObjectFile *objfile) :
+ m_objfile (objfile),
+ m_symbols (),
+ m_file_addr_to_index (),
+ m_name_to_index (),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_file_addr_to_index_computed (false),
+ m_name_indexes_computed (false)
+{
+}
+
+Symtab::~Symtab()
+{
+}
+
+void
+Symtab::Reserve(size_t count)
+{
+ // Clients should grab the mutex from this symbol table and lock it manually
+ // when calling this function to avoid performance issues.
+ m_symbols.reserve (count);
+}
+
+Symbol *
+Symtab::Resize(size_t count)
+{
+ // Clients should grab the mutex from this symbol table and lock it manually
+ // when calling this function to avoid performance issues.
+ m_symbols.resize (count);
+ return &m_symbols[0];
+}
+
+uint32_t
+Symtab::AddSymbol(const Symbol& symbol)
+{
+ // Clients should grab the mutex from this symbol table and lock it manually
+ // when calling this function to avoid performance issues.
+ uint32_t symbol_idx = m_symbols.size();
+ m_name_to_index.Clear();
+ m_file_addr_to_index.Clear();
+ m_symbols.push_back(symbol);
+ m_file_addr_to_index_computed = false;
+ m_name_indexes_computed = false;
+ return symbol_idx;
+}
+
+size_t
+Symtab::GetNumSymbols() const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_symbols.size();
+}
+
+void
+Symtab::Dump (Stream *s, Target *target, SortOrder sort_order)
+{
+ Mutex::Locker locker (m_mutex);
+
+// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ const FileSpec &file_spec = m_objfile->GetFileSpec();
+ const char * object_name = NULL;
+ if (m_objfile->GetModule())
+ object_name = m_objfile->GetModule()->GetObjectName().GetCString();
+
+ if (file_spec)
+ s->Printf("Symtab, file = %s%s%s%s, num_symbols = %lu",
+ file_spec.GetPath().c_str(),
+ object_name ? "(" : "",
+ object_name ? object_name : "",
+ object_name ? ")" : "",
+ m_symbols.size());
+ else
+ s->Printf("Symtab, num_symbols = %lu", m_symbols.size());
+
+ if (!m_symbols.empty())
+ {
+ switch (sort_order)
+ {
+ case eSortOrderNone:
+ {
+ s->PutCString (":\n");
+ DumpSymbolHeader (s);
+ const_iterator begin = m_symbols.begin();
+ const_iterator end = m_symbols.end();
+ for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
+ {
+ s->Indent();
+ pos->Dump(s, target, std::distance(begin, pos));
+ }
+ }
+ break;
+
+ case eSortOrderByName:
+ {
+ // Although we maintain a lookup by exact name map, the table
+ // isn't sorted by name. So we must make the ordered symbol list
+ // up ourselves.
+ s->PutCString (" (sorted by name):\n");
+ DumpSymbolHeader (s);
+ typedef std::multimap<const char*, const Symbol *, CStringCompareFunctionObject> CStringToSymbol;
+ CStringToSymbol name_map;
+ for (const_iterator pos = m_symbols.begin(), end = m_symbols.end(); pos != end; ++pos)
+ {
+ const char *name = pos->GetMangled().GetName(Mangled::ePreferDemangled).AsCString();
+ if (name && name[0])
+ name_map.insert (std::make_pair(name, &(*pos)));
+ }
+
+ for (CStringToSymbol::const_iterator pos = name_map.begin(), end = name_map.end(); pos != end; ++pos)
+ {
+ s->Indent();
+ pos->second->Dump (s, target, pos->second - &m_symbols[0]);
+ }
+ }
+ break;
+
+ case eSortOrderByAddress:
+ s->PutCString (" (sorted by address):\n");
+ DumpSymbolHeader (s);
+ if (!m_file_addr_to_index_computed)
+ InitAddressIndexes();
+ const size_t num_entries = m_file_addr_to_index.GetSize();
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ s->Indent();
+ const uint32_t symbol_idx = m_file_addr_to_index.GetEntryRef(i).data;
+ m_symbols[symbol_idx].Dump(s, target, symbol_idx);
+ }
+ break;
+ }
+ }
+}
+
+void
+Symtab::Dump(Stream *s, Target *target, std::vector<uint32_t>& indexes) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ const size_t num_symbols = GetNumSymbols();
+ //s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ s->Indent();
+ s->Printf("Symtab %lu symbol indexes (%lu symbols total):\n", indexes.size(), m_symbols.size());
+ s->IndentMore();
+
+ if (!indexes.empty())
+ {
+ std::vector<uint32_t>::const_iterator pos;
+ std::vector<uint32_t>::const_iterator end = indexes.end();
+ DumpSymbolHeader (s);
+ for (pos = indexes.begin(); pos != end; ++pos)
+ {
+ size_t idx = *pos;
+ if (idx < num_symbols)
+ {
+ s->Indent();
+ m_symbols[idx].Dump(s, target, idx);
+ }
+ }
+ }
+ s->IndentLess ();
+}
+
+void
+Symtab::DumpSymbolHeader (Stream *s)
+{
+ s->Indent(" Debug symbol\n");
+ s->Indent(" |Synthetic symbol\n");
+ s->Indent(" ||Externally Visible\n");
+ s->Indent(" |||\n");
+ s->Indent("Index UserID DSX Type File Address/Value Load Address Size Flags Name\n");
+ s->Indent("------- ------ --- ------------ ------------------ ------------------ ------------------ ---------- ----------------------------------\n");
+}
+
+
+static int
+CompareSymbolID (const void *key, const void *p)
+{
+ const user_id_t match_uid = *(user_id_t*) key;
+ const user_id_t symbol_uid = ((Symbol *)p)->GetID();
+ if (match_uid < symbol_uid)
+ return -1;
+ if (match_uid > symbol_uid)
+ return 1;
+ return 0;
+}
+
+Symbol *
+Symtab::FindSymbolByID (lldb::user_id_t symbol_uid) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ Symbol *symbol = (Symbol*)::bsearch (&symbol_uid,
+ &m_symbols[0],
+ m_symbols.size(),
+ (uint8_t *)&m_symbols[1] - (uint8_t *)&m_symbols[0],
+ CompareSymbolID);
+ return symbol;
+}
+
+
+Symbol *
+Symtab::SymbolAtIndex(size_t idx)
+{
+ // Clients should grab the mutex from this symbol table and lock it manually
+ // when calling this function to avoid performance issues.
+ if (idx < m_symbols.size())
+ return &m_symbols[idx];
+ return NULL;
+}
+
+
+const Symbol *
+Symtab::SymbolAtIndex(size_t idx) const
+{
+ // Clients should grab the mutex from this symbol table and lock it manually
+ // when calling this function to avoid performance issues.
+ if (idx < m_symbols.size())
+ return &m_symbols[idx];
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// InitNameIndexes
+//----------------------------------------------------------------------
+void
+Symtab::InitNameIndexes()
+{
+ // Protected function, no need to lock mutex...
+ if (!m_name_indexes_computed)
+ {
+ m_name_indexes_computed = true;
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ // Create the name index vector to be able to quickly search by name
+ const size_t num_symbols = m_symbols.size();
+#if 1
+ m_name_to_index.Reserve (num_symbols);
+#else
+ // TODO: benchmark this to see if we save any memory. Otherwise we
+ // will always keep the memory reserved in the vector unless we pull
+ // some STL swap magic and then recopy...
+ uint32_t actual_count = 0;
+ for (const_iterator pos = m_symbols.begin(), end = m_symbols.end();
+ pos != end;
+ ++pos)
+ {
+ const Mangled &mangled = pos->GetMangled();
+ if (mangled.GetMangledName())
+ ++actual_count;
+
+ if (mangled.GetDemangledName())
+ ++actual_count;
+ }
+
+ m_name_to_index.Reserve (actual_count);
+#endif
+
+ NameToIndexMap::Entry entry;
+
+ // The "const char *" in "class_contexts" must come from a ConstString::GetCString()
+ std::set<const char *> class_contexts;
+ UniqueCStringMap<uint32_t> mangled_name_to_index;
+ std::vector<const char *> symbol_contexts(num_symbols, NULL);
+
+ for (entry.value = 0; entry.value<num_symbols; ++entry.value)
+ {
+ const Symbol *symbol = &m_symbols[entry.value];
+
+ // Don't let trampolines get into the lookup by name map
+ // If we ever need the trampoline symbols to be searchable by name
+ // we can remove this and then possibly add a new bool to any of the
+ // Symtab functions that lookup symbols by name to indicate if they
+ // want trampolines.
+ if (symbol->IsTrampoline())
+ continue;
+
+ const Mangled &mangled = symbol->GetMangled();
+ entry.cstring = mangled.GetMangledName().GetCString();
+ if (entry.cstring && entry.cstring[0])
+ {
+ m_name_to_index.Append (entry);
+
+ const SymbolType symbol_type = symbol->GetType();
+ if (symbol_type == eSymbolTypeCode || symbol_type == eSymbolTypeResolver)
+ {
+ if (entry.cstring[0] == '_' && entry.cstring[1] == 'Z' &&
+ (entry.cstring[2] != 'T' && // avoid virtual table, VTT structure, typeinfo structure, and typeinfo name
+ entry.cstring[2] != 'G' && // avoid guard variables
+ entry.cstring[2] != 'Z')) // named local entities (if we eventually handle eSymbolTypeData, we will want this back)
+ {
+ CPPLanguageRuntime::MethodName cxx_method (mangled.GetDemangledName());
+ entry.cstring = ConstString(cxx_method.GetBasename()).GetCString();
+ if (entry.cstring && entry.cstring[0])
+ {
+ // ConstString objects permanently store the string in the pool so calling
+ // GetCString() on the value gets us a const char * that will never go away
+ const char *const_context = ConstString(cxx_method.GetContext()).GetCString();
+
+ if (entry.cstring[0] == '~' || !cxx_method.GetQualifiers().empty())
+ {
+ // The first character of the demangled basename is '~' which
+ // means we have a class destructor. We can use this information
+ // to help us know what is a class and what isn't.
+ if (class_contexts.find(const_context) == class_contexts.end())
+ class_contexts.insert(const_context);
+ m_method_to_index.Append (entry);
+ }
+ else
+ {
+ if (const_context && const_context[0])
+ {
+ if (class_contexts.find(const_context) != class_contexts.end())
+ {
+ // The current decl context is in our "class_contexts" which means
+ // this is a method on a class
+ m_method_to_index.Append (entry);
+ }
+ else
+ {
+ // We don't know if this is a function basename or a method,
+ // so put it into a temporary collection so once we are done
+ // we can look in class_contexts to see if each entry is a class
+ // or just a function and will put any remaining items into
+ // m_method_to_index or m_basename_to_index as needed
+ mangled_name_to_index.Append (entry);
+ symbol_contexts[entry.value] = const_context;
+ }
+ }
+ else
+ {
+ // No context for this function so this has to be a basename
+ m_basename_to_index.Append(entry);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ entry.cstring = mangled.GetDemangledName().GetCString();
+ if (entry.cstring && entry.cstring[0])
+ m_name_to_index.Append (entry);
+
+ // If the demangled name turns out to be an ObjC name, and
+ // is a category name, add the version without categories to the index too.
+ ObjCLanguageRuntime::MethodName objc_method (entry.cstring, true);
+ if (objc_method.IsValid(true))
+ {
+ entry.cstring = objc_method.GetSelector().GetCString();
+ m_selector_to_index.Append (entry);
+
+ ConstString objc_method_no_category (objc_method.GetFullNameWithoutCategory(true));
+ if (objc_method_no_category)
+ {
+ entry.cstring = objc_method_no_category.GetCString();
+ m_name_to_index.Append (entry);
+ }
+ }
+
+ }
+
+ size_t count;
+ if (!mangled_name_to_index.IsEmpty())
+ {
+ count = mangled_name_to_index.GetSize();
+ for (size_t i=0; i<count; ++i)
+ {
+ if (mangled_name_to_index.GetValueAtIndex(i, entry.value))
+ {
+ entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
+ if (symbol_contexts[entry.value] && class_contexts.find(symbol_contexts[entry.value]) != class_contexts.end())
+ {
+ m_method_to_index.Append (entry);
+ }
+ else
+ {
+ // If we got here, we have something that had a context (was inside a namespace or class)
+ // yet we don't know if the entry
+ m_method_to_index.Append (entry);
+ m_basename_to_index.Append (entry);
+ }
+ }
+ }
+ }
+ m_name_to_index.Sort();
+ m_name_to_index.SizeToFit();
+ m_selector_to_index.Sort();
+ m_selector_to_index.SizeToFit();
+ m_basename_to_index.Sort();
+ m_basename_to_index.SizeToFit();
+ m_method_to_index.Sort();
+ m_method_to_index.SizeToFit();
+
+// static StreamFile a ("/tmp/a.txt");
+//
+// count = m_basename_to_index.GetSize();
+// if (count)
+// {
+// for (size_t i=0; i<count; ++i)
+// {
+// if (m_basename_to_index.GetValueAtIndex(i, entry.value))
+// a.Printf ("%s BASENAME\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
+// }
+// }
+// count = m_method_to_index.GetSize();
+// if (count)
+// {
+// for (size_t i=0; i<count; ++i)
+// {
+// if (m_method_to_index.GetValueAtIndex(i, entry.value))
+// a.Printf ("%s METHOD\n", m_symbols[entry.value].GetMangled().GetName().GetCString());
+// }
+// }
+ }
+}
+
+void
+Symtab::AppendSymbolNamesToMap (const IndexCollection &indexes,
+ bool add_demangled,
+ bool add_mangled,
+ NameToIndexMap &name_to_index_map) const
+{
+ if (add_demangled || add_mangled)
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ Mutex::Locker locker (m_mutex);
+
+ // Create the name index vector to be able to quickly search by name
+ NameToIndexMap::Entry entry;
+ const size_t num_indexes = indexes.size();
+ for (size_t i=0; i<num_indexes; ++i)
+ {
+ entry.value = indexes[i];
+ assert (i < m_symbols.size());
+ const Symbol *symbol = &m_symbols[entry.value];
+
+ const Mangled &mangled = symbol->GetMangled();
+ if (add_demangled)
+ {
+ entry.cstring = mangled.GetDemangledName().GetCString();
+ if (entry.cstring && entry.cstring[0])
+ name_to_index_map.Append (entry);
+ }
+
+ if (add_mangled)
+ {
+ entry.cstring = mangled.GetMangledName().GetCString();
+ if (entry.cstring && entry.cstring[0])
+ name_to_index_map.Append (entry);
+ }
+ }
+ }
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ uint32_t prev_size = indexes.size();
+
+ const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
+
+ for (uint32_t i = start_idx; i < count; ++i)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
+ indexes.push_back(i);
+ }
+
+ return indexes.size() - prev_size;
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithTypeAndFlagsValue (SymbolType symbol_type, uint32_t flags_value, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ uint32_t prev_size = indexes.size();
+
+ const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
+
+ for (uint32_t i = start_idx; i < count; ++i)
+ {
+ if ((symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type) && m_symbols[i].GetFlags() == flags_value)
+ indexes.push_back(i);
+ }
+
+ return indexes.size() - prev_size;
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithType (SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes, uint32_t start_idx, uint32_t end_index) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ uint32_t prev_size = indexes.size();
+
+ const uint32_t count = std::min<uint32_t> (m_symbols.size(), end_index);
+
+ for (uint32_t i = start_idx; i < count; ++i)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
+ {
+ if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility))
+ indexes.push_back(i);
+ }
+ }
+
+ return indexes.size() - prev_size;
+}
+
+
+uint32_t
+Symtab::GetIndexForSymbol (const Symbol *symbol) const
+{
+ const Symbol *first_symbol = &m_symbols[0];
+ if (symbol >= first_symbol && symbol < first_symbol + m_symbols.size())
+ return symbol - first_symbol;
+ return UINT32_MAX;
+}
+
+struct SymbolSortInfo
+{
+ const bool sort_by_load_addr;
+ const Symbol *symbols;
+};
+
+namespace {
+ struct SymbolIndexComparator {
+ const std::vector<Symbol>& symbols;
+ std::vector<lldb::addr_t> &addr_cache;
+
+ // Getting from the symbol to the Address to the File Address involves some work.
+ // Since there are potentially many symbols here, and we're using this for sorting so
+ // we're going to be computing the address many times, cache that in addr_cache.
+ // The array passed in has to be the same size as the symbols array passed into the
+ // member variable symbols, and should be initialized with LLDB_INVALID_ADDRESS.
+ // NOTE: You have to make addr_cache externally and pass it in because std::stable_sort
+ // makes copies of the comparator it is initially passed in, and you end up spending
+ // huge amounts of time copying this array...
+
+ SymbolIndexComparator(const std::vector<Symbol>& s, std::vector<lldb::addr_t> &a) : symbols(s), addr_cache(a) {
+ assert (symbols.size() == addr_cache.size());
+ }
+ bool operator()(uint32_t index_a, uint32_t index_b) {
+ addr_t value_a = addr_cache[index_a];
+ if (value_a == LLDB_INVALID_ADDRESS)
+ {
+ value_a = symbols[index_a].GetAddress().GetFileAddress();
+ addr_cache[index_a] = value_a;
+ }
+
+ addr_t value_b = addr_cache[index_b];
+ if (value_b == LLDB_INVALID_ADDRESS)
+ {
+ value_b = symbols[index_b].GetAddress().GetFileAddress();
+ addr_cache[index_b] = value_b;
+ }
+
+
+ if (value_a == value_b) {
+ // The if the values are equal, use the original symbol user ID
+ lldb::user_id_t uid_a = symbols[index_a].GetID();
+ lldb::user_id_t uid_b = symbols[index_b].GetID();
+ if (uid_a < uid_b)
+ return true;
+ if (uid_a > uid_b)
+ return false;
+ return false;
+ } else if (value_a < value_b)
+ return true;
+
+ return false;
+ }
+ };
+}
+
+void
+Symtab::SortSymbolIndexesByValue (std::vector<uint32_t>& indexes, bool remove_duplicates) const
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,__PRETTY_FUNCTION__);
+ // No need to sort if we have zero or one items...
+ if (indexes.size() <= 1)
+ return;
+
+ // Sort the indexes in place using std::stable_sort.
+ // NOTE: The use of std::stable_sort instead of std::sort here is strictly for performance,
+ // not correctness. The indexes vector tends to be "close" to sorted, which the
+ // stable sort handles better.
+
+ std::vector<lldb::addr_t> addr_cache(m_symbols.size(), LLDB_INVALID_ADDRESS);
+
+ SymbolIndexComparator comparator(m_symbols, addr_cache);
+ std::stable_sort(indexes.begin(), indexes.end(), comparator);
+
+ // Remove any duplicates if requested
+ if (remove_duplicates)
+ std::unique(indexes.begin(), indexes.end());
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ if (symbol_name)
+ {
+ const char *symbol_cstr = symbol_name.GetCString();
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ return m_name_to_index.GetValues (symbol_cstr, indexes);
+ }
+ return 0;
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithName (const ConstString& symbol_name, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ if (symbol_name)
+ {
+ const size_t old_size = indexes.size();
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ const char *symbol_cstr = symbol_name.GetCString();
+
+ std::vector<uint32_t> all_name_indexes;
+ const size_t name_match_count = m_name_to_index.GetValues (symbol_cstr, all_name_indexes);
+ for (size_t i=0; i<name_match_count; ++i)
+ {
+ if (CheckSymbolAtIndex(all_name_indexes[i], symbol_debug_type, symbol_visibility))
+ indexes.push_back (all_name_indexes[i]);
+ }
+ return indexes.size() - old_size;
+ }
+ return 0;
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (AppendSymbolIndexesWithName(symbol_name, indexes) > 0)
+ {
+ std::vector<uint32_t>::iterator pos = indexes.begin();
+ while (pos != indexes.end())
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
+ ++pos;
+ else
+ indexes.erase(pos);
+ }
+ }
+ return indexes.size();
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesWithNameAndType (const ConstString& symbol_name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (AppendSymbolIndexesWithName(symbol_name, symbol_debug_type, symbol_visibility, indexes) > 0)
+ {
+ std::vector<uint32_t>::iterator pos = indexes.begin();
+ while (pos != indexes.end())
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[*pos].GetType() == symbol_type)
+ ++pos;
+ else
+ indexes.erase(pos);
+ }
+ }
+ return indexes.size();
+}
+
+
+uint32_t
+Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ uint32_t prev_size = indexes.size();
+ uint32_t sym_end = m_symbols.size();
+
+ for (uint32_t i = 0; i < sym_end; i++)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
+ {
+ const char *name = m_symbols[i].GetMangled().GetName().AsCString();
+ if (name)
+ {
+ if (regexp.Execute (name))
+ indexes.push_back(i);
+ }
+ }
+ }
+ return indexes.size() - prev_size;
+
+}
+
+uint32_t
+Symtab::AppendSymbolIndexesMatchingRegExAndType (const RegularExpression &regexp, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ uint32_t prev_size = indexes.size();
+ uint32_t sym_end = m_symbols.size();
+
+ for (uint32_t i = 0; i < sym_end; i++)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[i].GetType() == symbol_type)
+ {
+ if (CheckSymbolAtIndex(i, symbol_debug_type, symbol_visibility) == false)
+ continue;
+
+ const char *name = m_symbols[i].GetMangled().GetName().AsCString();
+ if (name)
+ {
+ if (regexp.Execute (name))
+ indexes.push_back(i);
+ }
+ }
+ }
+ return indexes.size() - prev_size;
+
+}
+
+Symbol *
+Symtab::FindSymbolWithType (SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, uint32_t& start_idx)
+{
+ Mutex::Locker locker (m_mutex);
+
+ const size_t count = m_symbols.size();
+ for (size_t idx = start_idx; idx < count; ++idx)
+ {
+ if (symbol_type == eSymbolTypeAny || m_symbols[idx].GetType() == symbol_type)
+ {
+ if (CheckSymbolAtIndex(idx, symbol_debug_type, symbol_visibility))
+ {
+ start_idx = idx;
+ return &m_symbols[idx];
+ }
+ }
+ }
+ return NULL;
+}
+
+size_t
+Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, std::vector<uint32_t>& symbol_indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ // Initialize all of the lookup by name indexes before converting NAME
+ // to a uniqued string NAME_STR below.
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (name)
+ {
+ // The string table did have a string that matched, but we need
+ // to check the symbols and match the symbol_type if any was given.
+ AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_indexes);
+ }
+ return symbol_indexes.size();
+}
+
+size_t
+Symtab::FindAllSymbolsWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ // Initialize all of the lookup by name indexes before converting NAME
+ // to a uniqued string NAME_STR below.
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (name)
+ {
+ // The string table did have a string that matched, but we need
+ // to check the symbols and match the symbol_type if any was given.
+ AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
+ }
+ return symbol_indexes.size();
+}
+
+size_t
+Symtab::FindAllSymbolsMatchingRexExAndType (const RegularExpression &regex, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility, std::vector<uint32_t>& symbol_indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+ AppendSymbolIndexesMatchingRegExAndType(regex, symbol_type, symbol_debug_type, symbol_visibility, symbol_indexes);
+ return symbol_indexes.size();
+}
+
+Symbol *
+Symtab::FindFirstSymbolWithNameAndType (const ConstString &name, SymbolType symbol_type, Debug symbol_debug_type, Visibility symbol_visibility)
+{
+ Mutex::Locker locker (m_mutex);
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, "%s", __PRETTY_FUNCTION__);
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (name)
+ {
+ std::vector<uint32_t> matching_indexes;
+ // The string table did have a string that matched, but we need
+ // to check the symbols and match the symbol_type if any was given.
+ if (AppendSymbolIndexesWithNameAndType (name, symbol_type, symbol_debug_type, symbol_visibility, matching_indexes))
+ {
+ std::vector<uint32_t>::const_iterator pos, end = matching_indexes.end();
+ for (pos = matching_indexes.begin(); pos != end; ++pos)
+ {
+ Symbol *symbol = SymbolAtIndex(*pos);
+
+ if (symbol->Compare(name, symbol_type))
+ return symbol;
+ }
+ }
+ }
+ return NULL;
+}
+
+typedef struct
+{
+ const Symtab *symtab;
+ const addr_t file_addr;
+ Symbol *match_symbol;
+ const uint32_t *match_index_ptr;
+ addr_t match_offset;
+} SymbolSearchInfo;
+
+static int
+SymbolWithFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
+{
+ const Symbol *curr_symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
+ if (curr_symbol == NULL)
+ return -1;
+
+ const addr_t info_file_addr = info->file_addr;
+
+ // lldb::Symbol::GetAddressRangePtr() will only return a non NULL address
+ // range if the symbol has a section!
+ if (curr_symbol->ValueIsAddress())
+ {
+ const addr_t curr_file_addr = curr_symbol->GetAddress().GetFileAddress();
+ if (info_file_addr < curr_file_addr)
+ return -1;
+ if (info_file_addr > curr_file_addr)
+ return +1;
+ info->match_symbol = const_cast<Symbol *>(curr_symbol);
+ info->match_index_ptr = index_ptr;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int
+SymbolWithClosestFileAddress (SymbolSearchInfo *info, const uint32_t *index_ptr)
+{
+ const Symbol *symbol = info->symtab->SymbolAtIndex (index_ptr[0]);
+ if (symbol == NULL)
+ return -1;
+
+ const addr_t info_file_addr = info->file_addr;
+ if (symbol->ValueIsAddress())
+ {
+ const addr_t curr_file_addr = symbol->GetAddress().GetFileAddress();
+ if (info_file_addr < curr_file_addr)
+ return -1;
+
+ // Since we are finding the closest symbol that is greater than or equal
+ // to 'info->file_addr' we set the symbol here. This will get set
+ // multiple times, but after the search is done it will contain the best
+ // symbol match
+ info->match_symbol = const_cast<Symbol *>(symbol);
+ info->match_index_ptr = index_ptr;
+ info->match_offset = info_file_addr - curr_file_addr;
+
+ if (info_file_addr > curr_file_addr)
+ return +1;
+ return 0;
+ }
+ return -1;
+}
+
+static SymbolSearchInfo
+FindIndexPtrForSymbolContainingAddress(Symtab* symtab, addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
+{
+ SymbolSearchInfo info = { symtab, file_addr, NULL, NULL, 0 };
+ ::bsearch (&info,
+ indexes,
+ num_indexes,
+ sizeof(uint32_t),
+ (ComparisonFunction)SymbolWithClosestFileAddress);
+ return info;
+}
+
+
+void
+Symtab::InitAddressIndexes()
+{
+ // Protected function, no need to lock mutex...
+ if (!m_file_addr_to_index_computed && !m_symbols.empty())
+ {
+ m_file_addr_to_index_computed = true;
+
+ FileRangeToIndexMap::Entry entry;
+ const_iterator begin = m_symbols.begin();
+ const_iterator end = m_symbols.end();
+ for (const_iterator pos = m_symbols.begin(); pos != end; ++pos)
+ {
+ if (pos->ValueIsAddress())
+ {
+ entry.SetRangeBase(pos->GetAddress().GetFileAddress());
+ entry.SetByteSize(pos->GetByteSize());
+ entry.data = std::distance(begin, pos);
+ m_file_addr_to_index.Append(entry);
+ }
+ }
+ const size_t num_entries = m_file_addr_to_index.GetSize();
+ if (num_entries > 0)
+ {
+ m_file_addr_to_index.Sort();
+ m_file_addr_to_index.CalculateSizesOfZeroByteSizeRanges();
+
+ // Now our last symbols might not have had sizes because there
+ // was no subsequent symbol to calculate the size from. If this is
+ // the case, then calculate the size by capping it at the end of the
+ // section in which the symbol resides
+ for (int i = num_entries - 1; i >= 0; --i)
+ {
+ const FileRangeToIndexMap::Entry &entry = m_file_addr_to_index.GetEntryRef(i);
+ // As we iterate backwards, as soon as we find a symbol with a valid
+ // byte size, we are done
+ if (entry.GetByteSize() > 0)
+ break;
+
+ // Cap the size to the end of the section in which the symbol resides
+ SectionSP section_sp (m_objfile->GetSectionList()->FindSectionContainingFileAddress (entry.GetRangeBase()));
+ if (section_sp)
+ {
+ const lldb::addr_t end_section_file_addr = section_sp->GetFileAddress() + section_sp->GetByteSize();
+ const lldb::addr_t symbol_file_addr = entry.GetRangeBase();
+ if (end_section_file_addr > symbol_file_addr)
+ {
+ Symbol &symbol = m_symbols[entry.data];
+
+ symbol.SetByteSize(end_section_file_addr - symbol_file_addr);
+ symbol.SetSizeIsSynthesized(true);
+ }
+ }
+ }
+ // Sort again in case the range size changes the ordering
+ m_file_addr_to_index.Sort();
+ }
+ }
+}
+
+void
+Symtab::CalculateSymbolSizes ()
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (!m_symbols.empty())
+ {
+ if (!m_file_addr_to_index_computed)
+ InitAddressIndexes();
+
+ const size_t num_entries = m_file_addr_to_index.GetSize();
+
+ for (size_t i = 0; i < num_entries; ++i)
+ {
+ // The entries in the m_file_addr_to_index have calculated the sizes already
+ // so we will use this size if we need to.
+ const FileRangeToIndexMap::Entry &entry = m_file_addr_to_index.GetEntryRef(i);
+
+ Symbol &symbol = m_symbols[entry.data];
+
+ // If the symbol size is already valid, no need to do anything
+ if (symbol.GetByteSizeIsValid())
+ continue;
+
+ const addr_t range_size = entry.GetByteSize();
+ if (range_size > 0)
+ {
+ symbol.SetByteSize(range_size);
+ symbol.SetSizeIsSynthesized(true);
+ }
+ }
+ }
+}
+
+Symbol *
+Symtab::FindSymbolContainingFileAddress (addr_t file_addr, const uint32_t* indexes, uint32_t num_indexes)
+{
+ Mutex::Locker locker (m_mutex);
+
+
+ SymbolSearchInfo info = { this, file_addr, NULL, NULL, 0 };
+
+ ::bsearch (&info,
+ indexes,
+ num_indexes,
+ sizeof(uint32_t),
+ (ComparisonFunction)SymbolWithClosestFileAddress);
+
+ if (info.match_symbol)
+ {
+ if (info.match_offset == 0)
+ {
+ // We found an exact match!
+ return info.match_symbol;
+ }
+
+ const size_t symbol_byte_size = info.match_symbol->GetByteSize();
+
+ if (symbol_byte_size == 0)
+ {
+ // We weren't able to find the size of the symbol so lets just go
+ // with that match we found in our search...
+ return info.match_symbol;
+ }
+
+ // We were able to figure out a symbol size so lets make sure our
+ // offset puts "file_addr" in the symbol's address range.
+ if (info.match_offset < symbol_byte_size)
+ return info.match_symbol;
+ }
+ return NULL;
+}
+
+Symbol *
+Symtab::FindSymbolContainingFileAddress (addr_t file_addr)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (!m_file_addr_to_index_computed)
+ InitAddressIndexes();
+
+ const FileRangeToIndexMap::Entry *entry = m_file_addr_to_index.FindEntryThatContains(file_addr);
+ if (entry)
+ return SymbolAtIndex(entry->data);
+ return NULL;
+}
+
+void
+Symtab::SymbolIndicesToSymbolContextList (std::vector<uint32_t> &symbol_indexes, SymbolContextList &sc_list)
+{
+ // No need to protect this call using m_mutex all other method calls are
+ // already thread safe.
+
+ const bool merge_symbol_into_function = true;
+ size_t num_indices = symbol_indexes.size();
+ if (num_indices > 0)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_objfile->GetModule();
+ for (size_t i = 0; i < num_indices; i++)
+ {
+ sc.symbol = SymbolAtIndex (symbol_indexes[i]);
+ if (sc.symbol)
+ sc_list.AppendIfUnique(sc, merge_symbol_into_function);
+ }
+ }
+}
+
+
+size_t
+Symtab::FindFunctionSymbols (const ConstString &name,
+ uint32_t name_type_mask,
+ SymbolContextList& sc_list)
+{
+ size_t count = 0;
+ std::vector<uint32_t> symbol_indexes;
+
+ const char *name_cstr = name.GetCString();
+
+ // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
+ assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
+
+ if (name_type_mask & (eFunctionNameTypeBase | eFunctionNameTypeFull))
+ {
+ std::vector<uint32_t> temp_symbol_indexes;
+ FindAllSymbolsWithNameAndType (name, eSymbolTypeAny, temp_symbol_indexes);
+
+ unsigned temp_symbol_indexes_size = temp_symbol_indexes.size();
+ if (temp_symbol_indexes_size > 0)
+ {
+ Mutex::Locker locker (m_mutex);
+ for (unsigned i = 0; i < temp_symbol_indexes_size; i++)
+ {
+ SymbolContext sym_ctx;
+ sym_ctx.symbol = SymbolAtIndex (temp_symbol_indexes[i]);
+ if (sym_ctx.symbol)
+ {
+ switch (sym_ctx.symbol->GetType())
+ {
+ case eSymbolTypeCode:
+ case eSymbolTypeResolver:
+ symbol_indexes.push_back(temp_symbol_indexes[i]);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (name_type_mask & eFunctionNameTypeBase)
+ {
+ // From mangled names we can't tell what is a basename and what
+ // is a method name, so we just treat them the same
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (!m_basename_to_index.IsEmpty())
+ {
+ const UniqueCStringMap<uint32_t>::Entry *match;
+ for (match = m_basename_to_index.FindFirstValueForName(name_cstr);
+ match != NULL;
+ match = m_basename_to_index.FindNextValueForName(match))
+ {
+ symbol_indexes.push_back(match->value);
+ }
+ }
+ }
+
+ if (name_type_mask & eFunctionNameTypeMethod)
+ {
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (!m_method_to_index.IsEmpty())
+ {
+ const UniqueCStringMap<uint32_t>::Entry *match;
+ for (match = m_method_to_index.FindFirstValueForName(name_cstr);
+ match != NULL;
+ match = m_method_to_index.FindNextValueForName(match))
+ {
+ symbol_indexes.push_back(match->value);
+ }
+ }
+ }
+
+ if (name_type_mask & eFunctionNameTypeSelector)
+ {
+ if (!m_name_indexes_computed)
+ InitNameIndexes();
+
+ if (!m_selector_to_index.IsEmpty())
+ {
+ const UniqueCStringMap<uint32_t>::Entry *match;
+ for (match = m_selector_to_index.FindFirstValueForName(name_cstr);
+ match != NULL;
+ match = m_selector_to_index.FindNextValueForName(match))
+ {
+ symbol_indexes.push_back(match->value);
+ }
+ }
+ }
+
+ if (!symbol_indexes.empty())
+ {
+ std::sort(symbol_indexes.begin(), symbol_indexes.end());
+ symbol_indexes.erase(std::unique(symbol_indexes.begin(), symbol_indexes.end()), symbol_indexes.end());
+ count = symbol_indexes.size();
+ SymbolIndicesToSymbolContextList (symbol_indexes, sc_list);
+ }
+
+ return count;
+}
+
diff --git a/source/Symbol/Type.cpp b/source/Symbol/Type.cpp
new file mode 100644
index 000000000000..0af2359e1dad
--- /dev/null
+++ b/source/Symbol/Type.cpp
@@ -0,0 +1,990 @@
+//===-- Type.cpp ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Other libraries and framework includes
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class TypeAppendVisitor
+{
+public:
+ TypeAppendVisitor(TypeListImpl &type_list) :
+ m_type_list(type_list)
+ {
+ }
+
+ bool
+ operator() (const lldb::TypeSP& type)
+ {
+ m_type_list.Append(TypeImplSP(new TypeImpl(type)));
+ return true;
+ }
+
+private:
+ TypeListImpl &m_type_list;
+};
+
+void
+TypeListImpl::Append (const lldb_private::TypeList &type_list)
+{
+ TypeAppendVisitor cb(*this);
+ type_list.ForEach(cb);
+}
+
+
+Type *
+SymbolFileType::GetType ()
+{
+ if (!m_type_sp)
+ {
+ Type *resolved_type = m_symbol_file.ResolveTypeUID (GetID());
+ if (resolved_type)
+ m_type_sp = resolved_type->shared_from_this();
+ }
+ return m_type_sp.get();
+}
+
+
+Type::Type
+(
+ lldb::user_id_t uid,
+ SymbolFile* symbol_file,
+ const ConstString &name,
+ uint64_t byte_size,
+ SymbolContextScope *context,
+ user_id_t encoding_uid,
+ EncodingDataType encoding_uid_type,
+ const Declaration& decl,
+ const ClangASTType &clang_type,
+ ResolveState clang_type_resolve_state
+) :
+ std::enable_shared_from_this<Type> (),
+ UserID (uid),
+ m_name (name),
+ m_symbol_file (symbol_file),
+ m_context (context),
+ m_encoding_type (NULL),
+ m_encoding_uid (encoding_uid),
+ m_encoding_uid_type (encoding_uid_type),
+ m_byte_size (byte_size),
+ m_decl (decl),
+ m_clang_type (clang_type)
+{
+ m_flags.clang_type_resolve_state = (clang_type ? clang_type_resolve_state : eResolveStateUnresolved);
+ m_flags.is_complete_objc_class = false;
+}
+
+Type::Type () :
+ std::enable_shared_from_this<Type> (),
+ UserID (0),
+ m_name ("<INVALID TYPE>"),
+ m_symbol_file (NULL),
+ m_context (NULL),
+ m_encoding_type (NULL),
+ m_encoding_uid (LLDB_INVALID_UID),
+ m_encoding_uid_type (eEncodingInvalid),
+ m_byte_size (0),
+ m_decl (),
+ m_clang_type ()
+{
+ m_flags.clang_type_resolve_state = eResolveStateUnresolved;
+ m_flags.is_complete_objc_class = false;
+}
+
+
+Type::Type (const Type &rhs) :
+ std::enable_shared_from_this<Type> (rhs),
+ UserID (rhs),
+ m_name (rhs.m_name),
+ m_symbol_file (rhs.m_symbol_file),
+ m_context (rhs.m_context),
+ m_encoding_type (rhs.m_encoding_type),
+ m_encoding_uid (rhs.m_encoding_uid),
+ m_encoding_uid_type (rhs.m_encoding_uid_type),
+ m_byte_size (rhs.m_byte_size),
+ m_decl (rhs.m_decl),
+ m_clang_type (rhs.m_clang_type),
+ m_flags (rhs.m_flags)
+{
+}
+
+const Type&
+Type::operator= (const Type& rhs)
+{
+ if (this != &rhs)
+ {
+ }
+ return *this;
+}
+
+
+void
+Type::GetDescription (Stream *s, lldb::DescriptionLevel level, bool show_name)
+{
+ *s << "id = " << (const UserID&)*this;
+
+ // Call the name accessor to make sure we resolve the type name
+ if (show_name)
+ {
+ const ConstString &type_name = GetName();
+ if (type_name)
+ {
+ *s << ", name = \"" << type_name << '"';
+ ConstString qualified_type_name (GetQualifiedName());
+ if (qualified_type_name != type_name)
+ {
+ *s << ", qualified = \"" << qualified_type_name << '"';
+ }
+ }
+ }
+
+ // Call the get byte size accesor so we resolve our byte size
+ if (GetByteSize())
+ s->Printf(", byte-size = %" PRIu64, m_byte_size);
+ bool show_fullpaths = (level == lldb::eDescriptionLevelVerbose);
+ m_decl.Dump(s, show_fullpaths);
+
+ if (m_clang_type.IsValid())
+ {
+ *s << ", clang_type = \"";
+ GetClangForwardType().DumpTypeDescription(s);
+ *s << '"';
+ }
+ else if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ s->Printf(", type_uid = 0x%8.8" PRIx64, m_encoding_uid);
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingInvalid: break;
+ case eEncodingIsUID: s->PutCString(" (unresolved type)"); break;
+ case eEncodingIsConstUID: s->PutCString(" (unresolved const type)"); break;
+ case eEncodingIsRestrictUID: s->PutCString(" (unresolved restrict type)"); break;
+ case eEncodingIsVolatileUID: s->PutCString(" (unresolved volatile type)"); break;
+ case eEncodingIsTypedefUID: s->PutCString(" (unresolved typedef)"); break;
+ case eEncodingIsPointerUID: s->PutCString(" (unresolved pointer)"); break;
+ case eEncodingIsLValueReferenceUID: s->PutCString(" (unresolved L value reference)"); break;
+ case eEncodingIsRValueReferenceUID: s->PutCString(" (unresolved R value reference)"); break;
+ case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break;
+ }
+ }
+}
+
+
+void
+Type::Dump (Stream *s, bool show_context)
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ *s << "Type" << (const UserID&)*this << ' ';
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+
+ if (m_byte_size != 0)
+ s->Printf(", size = %" PRIu64, m_byte_size);
+
+ if (show_context && m_context != NULL)
+ {
+ s->PutCString(", context = ( ");
+ m_context->DumpSymbolContext(s);
+ s->PutCString(" )");
+ }
+
+ bool show_fullpaths = false;
+ m_decl.Dump (s,show_fullpaths);
+
+ if (m_clang_type.IsValid())
+ {
+ *s << ", clang_type = " << m_clang_type.GetOpaqueQualType() << ' ';
+ GetClangForwardType().DumpTypeDescription (s);
+ }
+ else if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ *s << ", type_data = " << (uint64_t)m_encoding_uid;
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingInvalid: break;
+ case eEncodingIsUID: s->PutCString(" (unresolved type)"); break;
+ case eEncodingIsConstUID: s->PutCString(" (unresolved const type)"); break;
+ case eEncodingIsRestrictUID: s->PutCString(" (unresolved restrict type)"); break;
+ case eEncodingIsVolatileUID: s->PutCString(" (unresolved volatile type)"); break;
+ case eEncodingIsTypedefUID: s->PutCString(" (unresolved typedef)"); break;
+ case eEncodingIsPointerUID: s->PutCString(" (unresolved pointer)"); break;
+ case eEncodingIsLValueReferenceUID: s->PutCString(" (unresolved L value reference)"); break;
+ case eEncodingIsRValueReferenceUID: s->PutCString(" (unresolved R value reference)"); break;
+ case eEncodingIsSyntheticUID: s->PutCString(" (synthetic type)"); break;
+ }
+ }
+
+//
+// if (m_access)
+// s->Printf(", access = %u", m_access);
+ s->EOL();
+}
+
+const ConstString &
+Type::GetName()
+{
+ if (!m_name)
+ m_name = GetClangForwardType().GetConstTypeName();
+ return m_name;
+}
+
+void
+Type::DumpTypeName(Stream *s)
+{
+ GetName().Dump(s, "<invalid-type-name>");
+}
+
+
+void
+Type::DumpValue
+(
+ ExecutionContext *exe_ctx,
+ Stream *s,
+ const DataExtractor &data,
+ uint32_t data_byte_offset,
+ bool show_types,
+ bool show_summary,
+ bool verbose,
+ lldb::Format format
+)
+{
+ if (ResolveClangType(eResolveStateForward))
+ {
+ if (show_types)
+ {
+ s->PutChar('(');
+ if (verbose)
+ s->Printf("Type{0x%8.8" PRIx64 "} ", GetID());
+ DumpTypeName (s);
+ s->PutCString(") ");
+ }
+
+ GetClangForwardType().DumpValue (exe_ctx,
+ s,
+ format == lldb::eFormatDefault ? GetFormat() : format,
+ data,
+ data_byte_offset,
+ GetByteSize(),
+ 0, // Bitfield bit size
+ 0, // Bitfield bit offset
+ show_types,
+ show_summary,
+ verbose,
+ 0);
+ }
+}
+
+Type *
+Type::GetEncodingType ()
+{
+ if (m_encoding_type == NULL && m_encoding_uid != LLDB_INVALID_UID)
+ m_encoding_type = m_symbol_file->ResolveTypeUID(m_encoding_uid);
+ return m_encoding_type;
+}
+
+
+
+uint64_t
+Type::GetByteSize()
+{
+ if (m_byte_size == 0)
+ {
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingInvalid:
+ case eEncodingIsSyntheticUID:
+ break;
+ case eEncodingIsUID:
+ case eEncodingIsConstUID:
+ case eEncodingIsRestrictUID:
+ case eEncodingIsVolatileUID:
+ case eEncodingIsTypedefUID:
+ {
+ Type *encoding_type = GetEncodingType ();
+ if (encoding_type)
+ m_byte_size = encoding_type->GetByteSize();
+ if (m_byte_size == 0)
+ m_byte_size = GetClangLayoutType().GetByteSize();
+ }
+ break;
+
+ // If we are a pointer or reference, then this is just a pointer size;
+ case eEncodingIsPointerUID:
+ case eEncodingIsLValueReferenceUID:
+ case eEncodingIsRValueReferenceUID:
+ m_byte_size = m_symbol_file->GetClangASTContext().GetPointerByteSize();
+ break;
+ }
+ }
+ return m_byte_size;
+}
+
+
+uint32_t
+Type::GetNumChildren (bool omit_empty_base_classes)
+{
+ return GetClangForwardType().GetNumChildren(omit_empty_base_classes);
+}
+
+bool
+Type::IsAggregateType ()
+{
+ return GetClangForwardType().IsAggregateType();
+}
+
+lldb::TypeSP
+Type::GetTypedefType()
+{
+ lldb::TypeSP type_sp;
+ if (IsTypedef())
+ {
+ Type *typedef_type = m_symbol_file->ResolveTypeUID(m_encoding_uid);
+ if (typedef_type)
+ type_sp = typedef_type->shared_from_this();
+ }
+ return type_sp;
+}
+
+
+
+lldb::Format
+Type::GetFormat ()
+{
+ return GetClangForwardType().GetFormat();
+}
+
+
+
+lldb::Encoding
+Type::GetEncoding (uint64_t &count)
+{
+ // Make sure we resolve our type if it already hasn't been.
+ return GetClangForwardType().GetEncoding(count);
+}
+
+bool
+Type::DumpValueInMemory
+(
+ ExecutionContext *exe_ctx,
+ Stream *s,
+ lldb::addr_t address,
+ AddressType address_type,
+ bool show_types,
+ bool show_summary,
+ bool verbose
+)
+{
+ if (address != LLDB_INVALID_ADDRESS)
+ {
+ DataExtractor data;
+ Target *target = NULL;
+ if (exe_ctx)
+ target = exe_ctx->GetTargetPtr();
+ if (target)
+ data.SetByteOrder (target->GetArchitecture().GetByteOrder());
+ if (ReadFromMemory (exe_ctx, address, address_type, data))
+ {
+ DumpValue(exe_ctx, s, data, 0, show_types, show_summary, verbose);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool
+Type::ReadFromMemory (ExecutionContext *exe_ctx, lldb::addr_t addr, AddressType address_type, DataExtractor &data)
+{
+ if (address_type == eAddressTypeFile)
+ {
+ // Can't convert a file address to anything valid without more
+ // context (which Module it came from)
+ return false;
+ }
+
+ const uint64_t byte_size = GetByteSize();
+ if (data.GetByteSize() < byte_size)
+ {
+ lldb::DataBufferSP data_sp(new DataBufferHeap (byte_size, '\0'));
+ data.SetData(data_sp);
+ }
+
+ uint8_t* dst = (uint8_t*)data.PeekData(0, byte_size);
+ if (dst != NULL)
+ {
+ if (address_type == eAddressTypeHost)
+ {
+ // The address is an address in this process, so just copy it
+ if (addr == 0)
+ return false;
+ memcpy (dst, (uint8_t*)NULL + addr, byte_size);
+ return true;
+ }
+ else
+ {
+ if (exe_ctx)
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ Error error;
+ return exe_ctx->GetProcessPtr()->ReadMemory(addr, dst, byte_size, error) == byte_size;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+Type::WriteToMemory (ExecutionContext *exe_ctx, lldb::addr_t addr, AddressType address_type, DataExtractor &data)
+{
+ return false;
+}
+
+
+TypeList*
+Type::GetTypeList()
+{
+ return GetSymbolFile()->GetTypeList();
+}
+
+const Declaration &
+Type::GetDeclaration () const
+{
+ return m_decl;
+}
+
+bool
+Type::ResolveClangType (ResolveState clang_type_resolve_state)
+{
+ Type *encoding_type = NULL;
+ if (!m_clang_type.IsValid())
+ {
+ encoding_type = GetEncodingType();
+ if (encoding_type)
+ {
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingIsUID:
+ {
+ ClangASTType encoding_clang_type = encoding_type->GetClangForwardType();
+ if (encoding_clang_type.IsValid())
+ {
+ m_clang_type = encoding_clang_type;
+ m_flags.clang_type_resolve_state = encoding_type->m_flags.clang_type_resolve_state;
+ }
+ }
+ break;
+
+ case eEncodingIsConstUID:
+ m_clang_type = encoding_type->GetClangForwardType().AddConstModifier();
+ break;
+
+ case eEncodingIsRestrictUID:
+ m_clang_type = encoding_type->GetClangForwardType().AddRestrictModifier();
+ break;
+
+ case eEncodingIsVolatileUID:
+ m_clang_type = encoding_type->GetClangForwardType().AddVolatileModifier();
+ break;
+
+ case eEncodingIsTypedefUID:
+ m_clang_type = encoding_type->GetClangForwardType().CreateTypedefType (GetName().AsCString(),
+ GetSymbolFile()->GetClangDeclContextContainingTypeUID(GetID()));
+ m_name.Clear();
+ break;
+
+ case eEncodingIsPointerUID:
+ m_clang_type = encoding_type->GetClangForwardType().GetPointerType();
+ break;
+
+ case eEncodingIsLValueReferenceUID:
+ m_clang_type = encoding_type->GetClangForwardType().GetLValueReferenceType();
+ break;
+
+ case eEncodingIsRValueReferenceUID:
+ m_clang_type = encoding_type->GetClangForwardType().GetRValueReferenceType();
+ break;
+
+ default:
+ assert(!"Unhandled encoding_data_type.");
+ break;
+ }
+ }
+ else
+ {
+ // We have no encoding type, return void?
+ ClangASTType void_clang_type (ClangASTContext::GetBasicType(GetClangASTContext().getASTContext(), eBasicTypeVoid));
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingIsUID:
+ m_clang_type = void_clang_type;
+ break;
+
+ case eEncodingIsConstUID:
+ m_clang_type = void_clang_type.AddConstModifier ();
+ break;
+
+ case eEncodingIsRestrictUID:
+ m_clang_type = void_clang_type.AddRestrictModifier ();
+ break;
+
+ case eEncodingIsVolatileUID:
+ m_clang_type = void_clang_type.AddVolatileModifier ();
+ break;
+
+ case eEncodingIsTypedefUID:
+ m_clang_type = void_clang_type.CreateTypedefType (GetName().AsCString(),
+ GetSymbolFile()->GetClangDeclContextContainingTypeUID(GetID()));
+ break;
+
+ case eEncodingIsPointerUID:
+ m_clang_type = void_clang_type.GetPointerType ();
+ break;
+
+ case eEncodingIsLValueReferenceUID:
+ m_clang_type = void_clang_type.GetLValueReferenceType ();
+ break;
+
+ case eEncodingIsRValueReferenceUID:
+ m_clang_type = void_clang_type.GetRValueReferenceType ();
+ break;
+
+ default:
+ assert(!"Unhandled encoding_data_type.");
+ break;
+ }
+ }
+ }
+
+ // Check if we have a forward reference to a class/struct/union/enum?
+ if (m_clang_type.IsValid() && m_flags.clang_type_resolve_state < clang_type_resolve_state)
+ {
+ m_flags.clang_type_resolve_state = eResolveStateFull;
+ if (!m_clang_type.IsDefined ())
+ {
+ // We have a forward declaration, we need to resolve it to a complete definition.
+ m_symbol_file->ResolveClangOpaqueTypeDefinition (m_clang_type);
+ }
+ }
+
+ // If we have an encoding type, then we need to make sure it is
+ // resolved appropriately.
+ if (m_encoding_uid != LLDB_INVALID_UID)
+ {
+ if (encoding_type == NULL)
+ encoding_type = GetEncodingType();
+ if (encoding_type)
+ {
+ ResolveState encoding_clang_type_resolve_state = clang_type_resolve_state;
+
+ if (clang_type_resolve_state == eResolveStateLayout)
+ {
+ switch (m_encoding_uid_type)
+ {
+ case eEncodingIsPointerUID:
+ case eEncodingIsLValueReferenceUID:
+ case eEncodingIsRValueReferenceUID:
+ encoding_clang_type_resolve_state = eResolveStateForward;
+ break;
+ default:
+ break;
+ }
+ }
+ encoding_type->ResolveClangType (encoding_clang_type_resolve_state);
+ }
+ }
+ return m_clang_type.IsValid();
+}
+uint32_t
+Type::GetEncodingMask ()
+{
+ uint32_t encoding_mask = 1u << m_encoding_uid_type;
+ Type *encoding_type = GetEncodingType();
+ assert (encoding_type != this);
+ if (encoding_type)
+ encoding_mask |= encoding_type->GetEncodingMask ();
+ return encoding_mask;
+}
+
+ClangASTType
+Type::GetClangFullType ()
+{
+ ResolveClangType(eResolveStateFull);
+ return m_clang_type;
+}
+
+ClangASTType
+Type::GetClangLayoutType ()
+{
+ ResolveClangType(eResolveStateLayout);
+ return m_clang_type;
+}
+
+ClangASTType
+Type::GetClangForwardType ()
+{
+ ResolveClangType (eResolveStateForward);
+ return m_clang_type;
+}
+
+ClangASTContext &
+Type::GetClangASTContext ()
+{
+ return m_symbol_file->GetClangASTContext();
+}
+
+int
+Type::Compare(const Type &a, const Type &b)
+{
+ // Just compare the UID values for now...
+ lldb::user_id_t a_uid = a.GetID();
+ lldb::user_id_t b_uid = b.GetID();
+ if (a_uid < b_uid)
+ return -1;
+ if (a_uid > b_uid)
+ return 1;
+ return 0;
+// if (a.getQualType() == b.getQualType())
+// return 0;
+}
+
+
+#if 0 // START REMOVE
+// Move this into ClangASTType
+void *
+Type::CreateClangPointerType (Type *type)
+{
+ assert(type);
+ return GetClangASTContext().CreatePointerType(type->GetClangForwardType());
+}
+
+void *
+Type::CreateClangTypedefType (Type *typedef_type, Type *base_type)
+{
+ assert(typedef_type && base_type);
+ return GetClangASTContext().CreateTypedefType (typedef_type->GetName().AsCString(),
+ base_type->GetClangForwardType(),
+ typedef_type->GetSymbolFile()->GetClangDeclContextContainingTypeUID(typedef_type->GetID()));
+}
+
+void *
+Type::CreateClangLValueReferenceType (Type *type)
+{
+ assert(type);
+ return GetClangASTContext().CreateLValueReferenceType(type->GetClangForwardType());
+}
+
+void *
+Type::CreateClangRValueReferenceType (Type *type)
+{
+ assert(type);
+ return GetClangASTContext().CreateRValueReferenceType (type->GetClangForwardType());
+}
+#endif // END REMOVE
+
+bool
+Type::IsRealObjCClass()
+{
+ // For now we are just skipping ObjC classes that get made by hand from the runtime, because
+ // those don't have any information. We could extend this to only return true for "full
+ // definitions" if we can figure that out.
+
+ if (m_clang_type.IsObjCObjectOrInterfaceType() && GetByteSize() != 0)
+ return true;
+ else
+ return false;
+}
+
+ConstString
+Type::GetQualifiedName ()
+{
+ return GetClangForwardType().GetConstTypeName();
+}
+
+
+bool
+Type::GetTypeScopeAndBasename (const char* &name_cstr,
+ std::string &scope,
+ std::string &basename,
+ TypeClass &type_class)
+{
+ // Protect against null c string.
+
+ type_class = eTypeClassAny;
+
+ if (name_cstr && name_cstr[0])
+ {
+ llvm::StringRef name_strref(name_cstr);
+ if (name_strref.startswith("struct "))
+ {
+ name_cstr += 7;
+ type_class = eTypeClassStruct;
+ }
+ else if (name_strref.startswith("class "))
+ {
+ name_cstr += 6;
+ type_class = eTypeClassClass;
+ }
+ else if (name_strref.startswith("union "))
+ {
+ name_cstr += 6;
+ type_class = eTypeClassUnion;
+ }
+ else if (name_strref.startswith("enum "))
+ {
+ name_cstr += 5;
+ type_class = eTypeClassEnumeration;
+ }
+ else if (name_strref.startswith("typedef "))
+ {
+ name_cstr += 8;
+ type_class = eTypeClassTypedef;
+ }
+ const char *basename_cstr = name_cstr;
+ const char* namespace_separator = ::strstr (basename_cstr, "::");
+ if (namespace_separator)
+ {
+ const char* template_arg_char = ::strchr (basename_cstr, '<');
+ while (namespace_separator != NULL)
+ {
+ if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
+ break;
+ basename_cstr = namespace_separator + 2;
+ namespace_separator = strstr(basename_cstr, "::");
+ }
+ if (basename_cstr > name_cstr)
+ {
+ scope.assign (name_cstr, basename_cstr - name_cstr);
+ basename.assign (basename_cstr);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+
+
+TypeAndOrName::TypeAndOrName () : m_type_sp(), m_type_name()
+{
+
+}
+
+TypeAndOrName::TypeAndOrName (TypeSP &in_type_sp) : m_type_sp(in_type_sp)
+{
+ if (in_type_sp)
+ m_type_name = in_type_sp->GetName();
+}
+
+TypeAndOrName::TypeAndOrName (const char *in_type_str) : m_type_name(in_type_str)
+{
+}
+
+TypeAndOrName::TypeAndOrName (const TypeAndOrName &rhs) : m_type_sp (rhs.m_type_sp), m_type_name (rhs.m_type_name)
+{
+
+}
+
+TypeAndOrName::TypeAndOrName (ConstString &in_type_const_string) : m_type_name (in_type_const_string)
+{
+}
+
+TypeAndOrName &
+TypeAndOrName::operator= (const TypeAndOrName &rhs)
+{
+ if (this != &rhs)
+ {
+ m_type_name = rhs.m_type_name;
+ m_type_sp = rhs.m_type_sp;
+ }
+ return *this;
+}
+
+bool
+TypeAndOrName::operator==(const TypeAndOrName &other) const
+{
+ if (m_type_sp != other.m_type_sp)
+ return false;
+ if (m_type_name != other.m_type_name)
+ return false;
+ return true;
+}
+
+bool
+TypeAndOrName::operator!=(const TypeAndOrName &other) const
+{
+ if (m_type_sp != other.m_type_sp)
+ return true;
+ if (m_type_name != other.m_type_name)
+ return true;
+ return false;
+}
+
+ConstString
+TypeAndOrName::GetName () const
+{
+ if (m_type_sp)
+ return m_type_sp->GetName();
+ else
+ return m_type_name;
+}
+
+void
+TypeAndOrName::SetName (const ConstString &type_name)
+{
+ m_type_name = type_name;
+}
+
+void
+TypeAndOrName::SetName (const char *type_name_cstr)
+{
+ m_type_name.SetCString (type_name_cstr);
+}
+
+void
+TypeAndOrName::SetTypeSP (lldb::TypeSP type_sp)
+{
+ m_type_sp = type_sp;
+ if (type_sp)
+ m_type_name = type_sp->GetName();
+}
+
+bool
+TypeAndOrName::IsEmpty()
+{
+ if (m_type_name || m_type_sp)
+ return false;
+ else
+ return true;
+}
+
+void
+TypeAndOrName::Clear ()
+{
+ m_type_name.Clear();
+ m_type_sp.reset();
+}
+
+bool
+TypeAndOrName::HasName ()
+{
+ return (bool)m_type_name;
+}
+
+bool
+TypeAndOrName::HasTypeSP ()
+{
+ return m_type_sp.get() != NULL;
+}
+
+TypeImpl::TypeImpl(const lldb_private::ClangASTType& clang_ast_type) :
+ m_clang_ast_type(clang_ast_type),
+ m_type_sp()
+{
+}
+
+TypeImpl::TypeImpl(const lldb::TypeSP& type) :
+ m_clang_ast_type(type->GetClangForwardType()),
+ m_type_sp(type)
+{
+}
+
+void
+TypeImpl::SetType (const lldb::TypeSP &type_sp)
+{
+ if (type_sp)
+ {
+ m_clang_ast_type = type_sp->GetClangForwardType();
+ m_type_sp = type_sp;
+ }
+ else
+ {
+ m_clang_ast_type.Clear();
+ m_type_sp.reset();
+ }
+}
+
+TypeImpl&
+TypeImpl::operator = (const TypeImpl& rhs)
+{
+ if (*this != rhs)
+ {
+ m_clang_ast_type = rhs.m_clang_ast_type;
+ m_type_sp = rhs.m_type_sp;
+ }
+ return *this;
+}
+
+clang::ASTContext*
+TypeImpl::GetASTContext()
+{
+ if (!IsValid())
+ return NULL;
+
+ return m_clang_ast_type.GetASTContext();
+}
+
+lldb::clang_type_t
+TypeImpl::GetOpaqueQualType()
+{
+ if (!IsValid())
+ return NULL;
+
+ return m_clang_ast_type.GetOpaqueQualType();
+}
+
+bool
+TypeImpl::GetDescription (lldb_private::Stream &strm,
+ lldb::DescriptionLevel description_level)
+{
+ if (m_clang_ast_type.IsValid())
+ {
+ m_clang_ast_type.DumpTypeDescription (&strm);
+ }
+ else
+ {
+ strm.PutCString ("No value");
+ }
+ return true;
+}
+
+ConstString
+TypeImpl::GetName ()
+{
+ if (m_clang_ast_type.IsValid())
+ return m_clang_ast_type.GetConstTypeName();
+ return ConstString();
+}
diff --git a/source/Symbol/TypeList.cpp b/source/Symbol/TypeList.cpp
new file mode 100644
index 000000000000..a033edd22e1f
--- /dev/null
+++ b/source/Symbol/TypeList.cpp
@@ -0,0 +1,356 @@
+//===-- TypeList.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 <vector>
+
+// Other libraries and framework includes
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/raw_ostream.h"
+
+// Project includes
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace clang;
+
+TypeList::TypeList() :
+ m_types ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TypeList::~TypeList()
+{
+}
+
+void
+TypeList::Insert (const TypeSP& type_sp)
+{
+ // Just push each type on the back for now. We will worry about uniquing later
+ if (type_sp)
+ m_types.insert(std::make_pair(type_sp->GetID(), type_sp));
+}
+
+
+bool
+TypeList::InsertUnique (const TypeSP& type_sp)
+{
+ if (type_sp)
+ {
+ user_id_t type_uid = type_sp->GetID();
+ iterator pos, end = m_types.end();
+
+ for (pos = m_types.find(type_uid); pos != end && pos->second->GetID() == type_uid; ++pos)
+ {
+ if (pos->second.get() == type_sp.get())
+ return false;
+ }
+ }
+ Insert (type_sp);
+ return true;
+}
+
+//----------------------------------------------------------------------
+// Find a base type by its unique ID.
+//----------------------------------------------------------------------
+//TypeSP
+//TypeList::FindType(lldb::user_id_t uid)
+//{
+// iterator pos = m_types.find(uid);
+// if (pos != m_types.end())
+// return pos->second;
+// return TypeSP();
+//}
+
+//----------------------------------------------------------------------
+// Find a type by name.
+//----------------------------------------------------------------------
+//TypeList
+//TypeList::FindTypes (const ConstString &name)
+//{
+// // Do we ever need to make a lookup by name map? Here we are doing
+// // a linear search which isn't going to be fast.
+// TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str());
+// iterator pos, end;
+// for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+// if (pos->second->GetName() == name)
+// types.Insert (pos->second);
+// return types;
+//}
+
+void
+TypeList::Clear()
+{
+ m_types.clear();
+}
+
+uint32_t
+TypeList::GetSize() const
+{
+ return m_types.size();
+}
+
+// GetTypeAtIndex isn't used a lot for large type lists, currently only for
+// type lists that are returned for "image dump -t TYPENAME" commands and other
+// simple symbol queries that grab the first result...
+
+TypeSP
+TypeList::GetTypeAtIndex(uint32_t idx)
+{
+ iterator pos, end;
+ uint32_t i = idx;
+ for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+ {
+ if (i == 0)
+ return pos->second;
+ --i;
+ }
+ return TypeSP();
+}
+
+void
+TypeList::ForEach (std::function <bool(const lldb::TypeSP &type_sp)> const &callback) const
+{
+ for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+ {
+ if (!callback(pos->second))
+ break;
+ }
+}
+
+void
+TypeList::ForEach (std::function <bool(lldb::TypeSP &type_sp)> const &callback)
+{
+ for (auto pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+ {
+ if (!callback(pos->second))
+ break;
+ }
+}
+
+
+bool
+TypeList::RemoveTypeWithUID (user_id_t uid)
+{
+ iterator pos = m_types.find(uid);
+
+ if (pos != m_types.end())
+ {
+ m_types.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+
+void
+TypeList::Dump(Stream *s, bool show_context)
+{
+ for (iterator pos = m_types.begin(), end = m_types.end(); pos != end; ++pos)
+ {
+ pos->second->Dump(s, show_context);
+ }
+}
+
+// depending on implementation details, type lookup might fail because of
+// embedded spurious namespace:: prefixes. this call strips them, paying
+// attention to the fact that a type might have namespace'd type names as
+// arguments to templates, and those must not be stripped off
+static bool
+GetTypeScopeAndBasename(const char* name_cstr, std::string &scope, std::string &basename, bool *exact_ptr)
+{
+ // Protect against null c string.
+
+ if (name_cstr && name_cstr[0])
+ {
+ const char *basename_cstr = name_cstr;
+ const char* namespace_separator = ::strstr (basename_cstr, "::");
+ if (namespace_separator)
+ {
+ const char* template_arg_char = ::strchr (basename_cstr, '<');
+ while (namespace_separator != NULL)
+ {
+ if (template_arg_char && namespace_separator > template_arg_char) // but namespace'd template arguments are still good to go
+ break;
+ basename_cstr = namespace_separator + 2;
+ namespace_separator = strstr(basename_cstr, "::");
+ }
+ if (basename_cstr > name_cstr)
+ {
+ scope.assign (name_cstr, basename_cstr - name_cstr);
+ if (scope.size() >= 2 && scope[0] == ':' && scope[1] == ':')
+ {
+ // The typename passed in started with "::" so make sure we only do exact matches
+ if (exact_ptr)
+ *exact_ptr = true;
+ // Strip the leading "::" as this won't ever show in qualified typenames we get
+ // from clang.
+ scope.erase(0,2);
+ }
+ basename.assign (basename_cstr);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+TypeList::RemoveMismatchedTypes (const char *qualified_typename,
+ bool exact_match)
+{
+ std::string type_scope;
+ std::string type_basename;
+ TypeClass type_class = eTypeClassAny;
+ if (!Type::GetTypeScopeAndBasename (qualified_typename, type_scope, type_basename, type_class))
+ {
+ type_basename = qualified_typename;
+ type_scope.clear();
+ }
+ return RemoveMismatchedTypes (type_scope, type_basename, type_class, exact_match);
+}
+
+void
+TypeList::RemoveMismatchedTypes (const std::string &type_scope,
+ const std::string &type_basename,
+ TypeClass type_class,
+ bool exact_match)
+{
+ // Our "collection" type currently is a std::map which doesn't
+ // have any good way to iterate and remove items from the map
+ // so we currently just make a new list and add all of the matching
+ // types to it, and then swap it into m_types at the end
+ collection matching_types;
+
+ iterator pos, end = m_types.end();
+
+ for (pos = m_types.begin(); pos != end; ++pos)
+ {
+ Type* the_type = pos->second.get();
+ bool keep_match = false;
+ TypeClass match_type_class = eTypeClassAny;
+
+ if (type_class != eTypeClassAny)
+ {
+ match_type_class = the_type->GetClangForwardType().GetTypeClass ();
+ if ((match_type_class & type_class) == 0)
+ continue;
+ }
+
+ ConstString match_type_name_const_str (the_type->GetQualifiedName());
+ if (match_type_name_const_str)
+ {
+ const char *match_type_name = match_type_name_const_str.GetCString();
+ std::string match_type_scope;
+ std::string match_type_basename;
+ if (Type::GetTypeScopeAndBasename (match_type_name,
+ match_type_scope,
+ match_type_basename,
+ match_type_class))
+ {
+ if (match_type_basename == type_basename)
+ {
+ const size_t type_scope_size = type_scope.size();
+ const size_t match_type_scope_size = match_type_scope.size();
+ if (exact_match || (type_scope_size == match_type_scope_size))
+ {
+ keep_match = match_type_scope == type_scope;
+ }
+ else
+ {
+ if (match_type_scope_size > type_scope_size)
+ {
+ const size_t type_scope_pos = match_type_scope.rfind(type_scope);
+ if (type_scope_pos == match_type_scope_size - type_scope_size)
+ {
+ if (type_scope_pos >= 2)
+ {
+ // Our match scope ends with the type scope we were lookikng for,
+ // but we need to make sure what comes before the matching
+ // type scope is a namepace boundary in case we are trying to match:
+ // type_basename = "d"
+ // type_scope = "b::c::"
+ // We want to match:
+ // match_type_scope "a::b::c::"
+ // But not:
+ // match_type_scope "a::bb::c::"
+ // So below we make sure what comes before "b::c::" in match_type_scope
+ // is "::", or the namespace boundary
+ if (match_type_scope[type_scope_pos - 1] == ':' &&
+ match_type_scope[type_scope_pos - 2] == ':')
+ {
+ keep_match = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // The type we are currently looking at doesn't exists
+ // in a namespace or class, so it only matches if there
+ // is no type scope...
+ keep_match = type_scope.empty() && type_basename.compare(match_type_name) == 0;
+ }
+ }
+
+ if (keep_match)
+ {
+ matching_types.insert (*pos);
+ }
+ }
+ m_types.swap(matching_types);
+}
+
+void
+TypeList::RemoveMismatchedTypes (TypeClass type_class)
+{
+ if (type_class == eTypeClassAny)
+ return;
+
+ // Our "collection" type currently is a std::map which doesn't
+ // have any good way to iterate and remove items from the map
+ // so we currently just make a new list and add all of the matching
+ // types to it, and then swap it into m_types at the end
+ collection matching_types;
+
+ iterator pos, end = m_types.end();
+
+ for (pos = m_types.begin(); pos != end; ++pos)
+ {
+ Type* the_type = pos->second.get();
+ TypeClass match_type_class = the_type->GetClangForwardType().GetTypeClass ();
+ if (match_type_class & type_class)
+ matching_types.insert (*pos);
+ }
+ m_types.swap(matching_types);
+}
diff --git a/source/Symbol/UnwindPlan.cpp b/source/Symbol/UnwindPlan.cpp
new file mode 100644
index 000000000000..c089a7bb8db8
--- /dev/null
+++ b/source/Symbol/UnwindPlan.cpp
@@ -0,0 +1,441 @@
+//===-- UnwindPlan.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/Symbol/UnwindPlan.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool
+UnwindPlan::Row::RegisterLocation::operator == (const UnwindPlan::Row::RegisterLocation& rhs) const
+{
+ if (m_type == rhs.m_type)
+ {
+ switch (m_type)
+ {
+ case unspecified:
+ case undefined:
+ case same:
+ return true;
+
+ case atCFAPlusOffset:
+ case isCFAPlusOffset:
+ return m_location.offset == rhs.m_location.offset;
+
+ case inOtherRegister:
+ return m_location.reg_num == rhs.m_location.reg_num;
+
+ case atDWARFExpression:
+ case isDWARFExpression:
+ if (m_location.expr.length == rhs.m_location.expr.length)
+ return !memcmp (m_location.expr.opcodes, rhs.m_location.expr.opcodes, m_location.expr.length);
+ break;
+ }
+ }
+ return false;
+}
+
+// This function doesn't copy the dwarf expression bytes; they must remain in allocated
+// memory for the lifespan of this UnwindPlan object.
+void
+UnwindPlan::Row::RegisterLocation::SetAtDWARFExpression (const uint8_t *opcodes, uint32_t len)
+{
+ m_type = atDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+// This function doesn't copy the dwarf expression bytes; they must remain in allocated
+// memory for the lifespan of this UnwindPlan object.
+void
+UnwindPlan::Row::RegisterLocation::SetIsDWARFExpression (const uint8_t *opcodes, uint32_t len)
+{
+ m_type = isDWARFExpression;
+ m_location.expr.opcodes = opcodes;
+ m_location.expr.length = len;
+}
+
+void
+UnwindPlan::Row::RegisterLocation::Dump (Stream &s, const UnwindPlan* unwind_plan, const UnwindPlan::Row* row, Thread* thread, bool verbose) const
+{
+ switch (m_type)
+ {
+ case unspecified:
+ if (verbose)
+ s.PutCString ("=<unspec>");
+ else
+ s.PutCString ("=!");
+ break;
+ case undefined:
+ if (verbose)
+ s.PutCString ("=<undef>");
+ else
+ s.PutCString ("=?");
+ break;
+ case same:
+ s.PutCString ("= <same>");
+ break;
+
+ case atCFAPlusOffset:
+ case isCFAPlusOffset:
+ {
+ s.PutChar('=');
+ if (m_type == atCFAPlusOffset)
+ s.PutChar('[');
+ if (verbose)
+ s.Printf ("CFA%+d", m_location.offset);
+
+ if (unwind_plan && row)
+ {
+ const uint32_t cfa_reg = row->GetCFARegister();
+ const RegisterInfo *cfa_reg_info = unwind_plan->GetRegisterInfo (thread, cfa_reg);
+ const int32_t offset = row->GetCFAOffset() + m_location.offset;
+ if (verbose)
+ {
+ if (cfa_reg_info)
+ s.Printf (" (%s%+d)", cfa_reg_info->name, offset);
+ else
+ s.Printf (" (reg(%u)%+d)", cfa_reg, offset);
+ }
+ else
+ {
+ if (cfa_reg_info)
+ s.Printf ("%s", cfa_reg_info->name);
+ else
+ s.Printf ("reg(%u)", cfa_reg);
+ if (offset != 0)
+ s.Printf ("%+d", offset);
+ }
+ }
+ if (m_type == atCFAPlusOffset)
+ s.PutChar(']');
+ }
+ break;
+
+ case inOtherRegister:
+ {
+ const RegisterInfo *other_reg_info = NULL;
+ if (unwind_plan)
+ other_reg_info = unwind_plan->GetRegisterInfo (thread, m_location.reg_num);
+ if (other_reg_info)
+ s.Printf ("=%s", other_reg_info->name);
+ else
+ s.Printf ("=reg(%u)", m_location.reg_num);
+ }
+ break;
+
+ case atDWARFExpression:
+ case isDWARFExpression:
+ {
+ s.PutChar('=');
+ if (m_type == atDWARFExpression)
+ s.PutCString("[dwarf-expr]");
+ else
+ s.PutCString("dwarf-expr");
+ }
+ break;
+
+ }
+}
+
+void
+UnwindPlan::Row::Clear ()
+{
+ m_offset = 0;
+ m_cfa_reg_num = LLDB_INVALID_REGNUM;
+ m_cfa_offset = 0;
+ m_register_locations.clear();
+}
+
+void
+UnwindPlan::Row::Dump (Stream& s, const UnwindPlan* unwind_plan, Thread* thread, addr_t base_addr) const
+{
+ const RegisterInfo *reg_info = unwind_plan->GetRegisterInfo (thread, GetCFARegister());
+
+ if (base_addr != LLDB_INVALID_ADDRESS)
+ s.Printf ("0x%16.16" PRIx64 ": CFA=", base_addr + GetOffset());
+ else
+ s.Printf ("0x%8.8" PRIx64 ": CFA=", GetOffset());
+
+ if (reg_info)
+ s.Printf ("%s", reg_info->name);
+ else
+ s.Printf ("reg(%u)", GetCFARegister());
+ s.Printf ("%+3d => ", GetCFAOffset ());
+ for (collection::const_iterator idx = m_register_locations.begin (); idx != m_register_locations.end (); ++idx)
+ {
+ reg_info = unwind_plan->GetRegisterInfo (thread, idx->first);
+ if (reg_info)
+ s.Printf ("%s", reg_info->name);
+ else
+ s.Printf ("reg(%u)", idx->first);
+ const bool verbose = false;
+ idx->second.Dump(s, unwind_plan, this, thread, verbose);
+ s.PutChar (' ');
+ }
+ s.EOL();
+}
+
+UnwindPlan::Row::Row() :
+ m_offset(0),
+ m_cfa_reg_num(LLDB_INVALID_REGNUM),
+ m_cfa_offset(0),
+ m_register_locations()
+{
+}
+
+bool
+UnwindPlan::Row::GetRegisterInfo (uint32_t reg_num, UnwindPlan::Row::RegisterLocation& register_location) const
+{
+ collection::const_iterator pos = m_register_locations.find(reg_num);
+ if (pos != m_register_locations.end())
+ {
+ register_location = pos->second;
+ return true;
+ }
+ return false;
+}
+
+void
+UnwindPlan::Row::SetRegisterInfo (uint32_t reg_num, const UnwindPlan::Row::RegisterLocation register_location)
+{
+ m_register_locations[reg_num] = register_location;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToAtCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
+{
+ if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetAtCFAPlusOffset(offset);
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToIsCFAPlusOffset (uint32_t reg_num, int32_t offset, bool can_replace)
+{
+ if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetIsCFAPlusOffset(offset);
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToUndefined (uint32_t reg_num, bool can_replace, bool can_replace_only_if_unspecified)
+{
+ collection::iterator pos = m_register_locations.find(reg_num);
+ collection::iterator end = m_register_locations.end();
+
+ if (pos != end)
+ {
+ if (!can_replace)
+ return false;
+ if (can_replace_only_if_unspecified && !pos->second.IsUnspecified())
+ return false;
+ }
+ RegisterLocation reg_loc;
+ reg_loc.SetUndefined();
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToUnspecified (uint32_t reg_num, bool can_replace)
+{
+ if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetUnspecified();
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToRegister (uint32_t reg_num,
+ uint32_t other_reg_num,
+ bool can_replace)
+{
+ if (!can_replace && m_register_locations.find(reg_num) != m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetInRegister(other_reg_num);
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+bool
+UnwindPlan::Row::SetRegisterLocationToSame (uint32_t reg_num, bool must_replace)
+{
+ if (must_replace && m_register_locations.find(reg_num) == m_register_locations.end())
+ return false;
+ RegisterLocation reg_loc;
+ reg_loc.SetSame();
+ m_register_locations[reg_num] = reg_loc;
+ return true;
+}
+
+void
+UnwindPlan::Row::SetCFARegister (uint32_t reg_num)
+{
+ m_cfa_reg_num = reg_num;
+}
+
+bool
+UnwindPlan::Row::operator == (const UnwindPlan::Row& rhs) const
+{
+ if (m_offset != rhs.m_offset || m_cfa_reg_num != rhs.m_cfa_reg_num || m_cfa_offset != rhs.m_cfa_offset)
+ return false;
+ return m_register_locations == rhs.m_register_locations;
+}
+
+void
+UnwindPlan::AppendRow (const UnwindPlan::RowSP &row_sp)
+{
+ if (m_row_list.empty() || m_row_list.back()->GetOffset() != row_sp->GetOffset())
+ m_row_list.push_back(row_sp);
+ else
+ m_row_list.back() = row_sp;
+}
+
+UnwindPlan::RowSP
+UnwindPlan::GetRowForFunctionOffset (int offset) const
+{
+ RowSP row;
+ if (!m_row_list.empty())
+ {
+ if (offset == -1)
+ row = m_row_list.back();
+ else
+ {
+ collection::const_iterator pos, end = m_row_list.end();
+ for (pos = m_row_list.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetOffset() <= offset)
+ row = *pos;
+ else
+ break;
+ }
+ }
+ }
+ return row;
+}
+
+bool
+UnwindPlan::IsValidRowIndex (uint32_t idx) const
+{
+ return idx < m_row_list.size();
+}
+
+const UnwindPlan::RowSP
+UnwindPlan::GetRowAtIndex (uint32_t idx) const
+{
+ // You must call IsValidRowIndex(idx) first before calling this!!!
+ assert (idx < m_row_list.size());
+ return m_row_list[idx];
+}
+
+const UnwindPlan::RowSP
+UnwindPlan::GetLastRow () const
+{
+ // You must call GetRowCount() first to make sure there is at least one row
+ assert (!m_row_list.empty());
+ return m_row_list.back();
+}
+
+int
+UnwindPlan::GetRowCount () const
+{
+ return m_row_list.size ();
+}
+
+void
+UnwindPlan::SetPlanValidAddressRange (const AddressRange& range)
+{
+ if (range.GetBaseAddress().IsValid() && range.GetByteSize() != 0)
+ m_plan_valid_address_range = range;
+}
+
+bool
+UnwindPlan::PlanValidAtAddress (Address addr)
+{
+ if (!m_plan_valid_address_range.GetBaseAddress().IsValid() || m_plan_valid_address_range.GetByteSize() == 0)
+ return true;
+
+ if (!addr.IsValid())
+ return true;
+
+ if (m_plan_valid_address_range.ContainsFileAddress (addr))
+ return true;
+
+ return false;
+}
+
+void
+UnwindPlan::Dump (Stream& s, Thread *thread, lldb::addr_t base_addr) const
+{
+ if (!m_source_name.IsEmpty())
+ {
+ s.Printf ("This UnwindPlan originally sourced from %s\n", m_source_name.GetCString());
+ }
+ if (m_plan_valid_address_range.GetBaseAddress().IsValid() && m_plan_valid_address_range.GetByteSize() > 0)
+ {
+ s.PutCString ("Address range of this UnwindPlan: ");
+ TargetSP target_sp(thread->CalculateTarget());
+ m_plan_valid_address_range.Dump (&s, target_sp.get(), Address::DumpStyleSectionNameOffset);
+ s.EOL();
+ }
+ collection::const_iterator pos, begin = m_row_list.begin(), end = m_row_list.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ s.Printf ("row[%u]: ", (uint32_t)std::distance (begin, pos));
+ (*pos)->Dump(s, this, thread, base_addr);
+ }
+}
+
+void
+UnwindPlan::SetSourceName (const char *source)
+{
+ m_source_name = ConstString (source);
+}
+
+ConstString
+UnwindPlan::GetSourceName () const
+{
+ return m_source_name;
+}
+
+const RegisterInfo *
+UnwindPlan::GetRegisterInfo (Thread* thread, uint32_t unwind_reg) const
+{
+ if (thread)
+ {
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ uint32_t reg;
+ if (m_register_kind == eRegisterKindLLDB)
+ reg = unwind_reg;
+ else
+ reg = reg_ctx->ConvertRegisterKindToRegisterNumber (m_register_kind, unwind_reg);
+ if (reg != LLDB_INVALID_REGNUM)
+ return reg_ctx->GetRegisterInfoAtIndex (reg);
+ }
+ }
+ return NULL;
+}
+
diff --git a/source/Symbol/UnwindTable.cpp b/source/Symbol/UnwindTable.cpp
new file mode 100644
index 000000000000..c77628bf7dd8
--- /dev/null
+++ b/source/Symbol/UnwindTable.cpp
@@ -0,0 +1,153 @@
+//===-- UnwindTable.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/Symbol/UnwindTable.h"
+
+#include <stdio.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+// There is one UnwindTable object per ObjectFile.
+// It contains a list of Unwind objects -- one per function, populated lazily -- for the ObjectFile.
+// Each Unwind object has multiple UnwindPlans for different scenarios.
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindTable::UnwindTable (ObjectFile& objfile) :
+ m_object_file (objfile),
+ m_unwinds (),
+ m_initialized (false),
+ m_assembly_profiler (NULL),
+ m_eh_frame (NULL)
+{
+}
+
+// We can't do some of this initialization when the ObjectFile is running its ctor; delay doing it
+// until needed for something.
+
+void
+UnwindTable::Initialize ()
+{
+ if (m_initialized)
+ return;
+
+ SectionList* sl = m_object_file.GetSectionList ();
+ if (sl)
+ {
+ SectionSP sect = sl->FindSectionByType (eSectionTypeEHFrame, true);
+ if (sect.get())
+ {
+ m_eh_frame = new DWARFCallFrameInfo(m_object_file, sect, eRegisterKindGCC, true);
+ }
+ }
+
+ ArchSpec arch;
+ if (m_object_file.GetArchitecture (arch))
+ {
+ m_assembly_profiler = UnwindAssembly::FindPlugin (arch);
+ m_initialized = true;
+ }
+}
+
+UnwindTable::~UnwindTable ()
+{
+ if (m_eh_frame)
+ delete m_eh_frame;
+}
+
+FuncUnwindersSP
+UnwindTable::GetFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
+{
+ FuncUnwindersSP no_unwind_found;
+
+ Initialize();
+
+ // There is an UnwindTable per object file, so we can safely use file handles
+ addr_t file_addr = addr.GetFileAddress();
+ iterator end = m_unwinds.end ();
+ iterator insert_pos = end;
+ if (!m_unwinds.empty())
+ {
+ insert_pos = m_unwinds.lower_bound (file_addr);
+ iterator pos = insert_pos;
+ if ((pos == m_unwinds.end ()) || (pos != m_unwinds.begin() && pos->second->GetFunctionStartAddress() != addr))
+ --pos;
+
+ if (pos->second->ContainsAddress (addr))
+ return pos->second;
+ }
+
+ AddressRange range;
+ if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
+ {
+ // Does the eh_frame unwind info has a function bounds for this addr?
+ if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
+ {
+ return no_unwind_found;
+ }
+ }
+
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
+ m_unwinds.insert (insert_pos, std::make_pair(range.GetBaseAddress().GetFileAddress(), func_unwinder_sp));
+// StreamFile s(stdout);
+// Dump (s);
+ return func_unwinder_sp;
+}
+
+// Ignore any existing FuncUnwinders for this function, create a new one and don't add it to the
+// UnwindTable. This is intended for use by target modules show-unwind where we want to create
+// new UnwindPlans, not re-use existing ones.
+
+FuncUnwindersSP
+UnwindTable::GetUncachedFuncUnwindersContainingAddress (const Address& addr, SymbolContext &sc)
+{
+ FuncUnwindersSP no_unwind_found;
+ Initialize();
+
+ AddressRange range;
+ if (!sc.GetAddressRange(eSymbolContextFunction | eSymbolContextSymbol, 0, false, range) || !range.GetBaseAddress().IsValid())
+ {
+ // Does the eh_frame unwind info has a function bounds for this addr?
+ if (m_eh_frame == NULL || !m_eh_frame->GetAddressRange (addr, range))
+ {
+ return no_unwind_found;
+ }
+ }
+
+ FuncUnwindersSP func_unwinder_sp(new FuncUnwinders(*this, m_assembly_profiler, range));
+ return func_unwinder_sp;
+}
+
+
+void
+UnwindTable::Dump (Stream &s)
+{
+ s.Printf("UnwindTable for '%s':\n", m_object_file.GetFileSpec().GetPath().c_str());
+ const_iterator begin = m_unwinds.begin();
+ const_iterator end = m_unwinds.end();
+ for (const_iterator pos = begin; pos != end; ++pos)
+ {
+ s.Printf ("[%u] 0x%16.16" PRIx64 "\n", (unsigned)std::distance (begin, pos), pos->first);
+ }
+ s.EOL();
+}
+
+DWARFCallFrameInfo *
+UnwindTable::GetEHFrameInfo ()
+{
+ Initialize();
+ return m_eh_frame;
+}
diff --git a/source/Symbol/Variable.cpp b/source/Symbol/Variable.cpp
new file mode 100644
index 000000000000..36439b561626
--- /dev/null
+++ b/source/Symbol/Variable.cpp
@@ -0,0 +1,894 @@
+//===-- Variable.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/Symbol/Variable.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Variable constructor
+//----------------------------------------------------------------------
+Variable::Variable
+(
+ lldb::user_id_t uid,
+ const char *name,
+ const char *mangled, // The mangled variable name for variables in namespaces
+ const lldb::SymbolFileTypeSP &symfile_type_sp,
+ ValueType scope,
+ SymbolContextScope *context,
+ Declaration* decl_ptr,
+ const DWARFExpression& location,
+ bool external,
+ bool artificial
+) :
+ UserID(uid),
+ m_name(name),
+ m_mangled (ConstString(mangled), true),
+ m_symfile_type_sp(symfile_type_sp),
+ m_scope(scope),
+ m_owner_scope(context),
+ m_declaration(decl_ptr),
+ m_location(location),
+ m_external(external),
+ m_artificial(artificial)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Variable::~Variable()
+{
+}
+
+
+const ConstString&
+Variable::GetName() const
+{
+ if (m_mangled)
+ return m_mangled.GetName();
+ return m_name;
+}
+
+bool
+Variable::NameMatches (const RegularExpression& regex) const
+{
+ if (regex.Execute (m_name.AsCString()))
+ return true;
+ return m_mangled.NameMatches (regex);
+}
+
+Type *
+Variable::GetType()
+{
+ if (m_symfile_type_sp)
+ return m_symfile_type_sp->GetType();
+ return NULL;
+}
+
+void
+Variable::Dump(Stream *s, bool show_context) const
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ *s << "Variable" << (const UserID&)*this;
+
+ if (m_name)
+ *s << ", name = \"" << m_name << "\"";
+
+ if (m_symfile_type_sp)
+ {
+ Type *type = m_symfile_type_sp->GetType();
+ if (type)
+ {
+ *s << ", type = {" << type->GetID() << "} " << (void*)type << " (";
+ type->DumpTypeName(s);
+ s->PutChar(')');
+ }
+ }
+
+ if (m_scope != eValueTypeInvalid)
+ {
+ s->PutCString(", scope = ");
+ switch (m_scope)
+ {
+ case eValueTypeVariableGlobal: s->PutCString(m_external ? "global" : "static"); break;
+ case eValueTypeVariableArgument: s->PutCString("parameter"); break;
+ case eValueTypeVariableLocal: s->PutCString("local"); break;
+ default: *s << "??? (" << m_scope << ')';
+ }
+ }
+
+ if (show_context && m_owner_scope != NULL)
+ {
+ s->PutCString(", context = ( ");
+ m_owner_scope->DumpSymbolContext(s);
+ s->PutCString(" )");
+ }
+
+ bool show_fullpaths = false;
+ m_declaration.Dump(s, show_fullpaths);
+
+ if (m_location.IsValid())
+ {
+ s->PutCString(", location = ");
+ lldb::addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
+ if (m_location.IsLocationList())
+ {
+ SymbolContext variable_sc;
+ m_owner_scope->CalculateSymbolContext(&variable_sc);
+ if (variable_sc.function)
+ loclist_base_addr = variable_sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ }
+ ABI *abi = NULL;
+ if (m_owner_scope)
+ {
+ ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
+ if (module_sp)
+ abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
+ }
+ m_location.GetDescription(s, lldb::eDescriptionLevelBrief, loclist_base_addr, abi);
+ }
+
+ if (m_external)
+ s->PutCString(", external");
+
+ if (m_artificial)
+ s->PutCString(", artificial");
+
+ s->EOL();
+}
+
+bool
+Variable::DumpDeclaration (Stream *s, bool show_fullpaths, bool show_module)
+{
+ bool dumped_declaration_info = false;
+ if (m_owner_scope)
+ {
+ SymbolContext sc;
+ m_owner_scope->CalculateSymbolContext(&sc);
+ sc.block = NULL;
+ sc.line_entry.Clear();
+ bool show_inlined_frames = false;
+
+ dumped_declaration_info = sc.DumpStopContext (s,
+ NULL,
+ Address(),
+ show_fullpaths,
+ show_module,
+ show_inlined_frames);
+
+ if (sc.function)
+ s->PutChar(':');
+ }
+ if (m_declaration.DumpStopContext (s, false))
+ dumped_declaration_info = true;
+ return dumped_declaration_info;
+}
+
+size_t
+Variable::MemorySize() const
+{
+ return sizeof(Variable);
+}
+
+
+void
+Variable::CalculateSymbolContext (SymbolContext *sc)
+{
+ if (m_owner_scope)
+ m_owner_scope->CalculateSymbolContext(sc);
+ else
+ sc->Clear(false);
+}
+
+bool
+Variable::LocationIsValidForFrame (StackFrame *frame)
+{
+ // Is the variable is described by a single location?
+ if (!m_location.IsLocationList())
+ {
+ // Yes it is, the location is valid.
+ return true;
+ }
+
+ if (frame)
+ {
+ Function *function = frame->GetSymbolContext(eSymbolContextFunction).function;
+ if (function)
+ {
+ TargetSP target_sp (frame->CalculateTarget());
+
+ addr_t loclist_base_load_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress (target_sp.get());
+ if (loclist_base_load_addr == LLDB_INVALID_ADDRESS)
+ return false;
+ // It is a location list. We just need to tell if the location
+ // list contains the current address when converted to a load
+ // address
+ return m_location.LocationListContainsAddress (loclist_base_load_addr,
+ frame->GetFrameCodeAddress().GetLoadAddress (target_sp.get()));
+ }
+ }
+ return false;
+}
+
+bool
+Variable::LocationIsValidForAddress (const Address &address)
+{
+ // Be sure to resolve the address to section offset prior to
+ // calling this function.
+ if (address.IsSectionOffset())
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ if (sc.module_sp == address.GetModule())
+ {
+ // Is the variable is described by a single location?
+ if (!m_location.IsLocationList())
+ {
+ // Yes it is, the location is valid.
+ return true;
+ }
+
+ if (sc.function)
+ {
+ addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
+ return false;
+ // It is a location list. We just need to tell if the location
+ // list contains the current address when converted to a load
+ // address
+ return m_location.LocationListContainsAddress (loclist_base_file_addr,
+ address.GetFileAddress());
+ }
+ }
+ }
+ return false;
+}
+
+bool
+Variable::IsInScope (StackFrame *frame)
+{
+ switch (m_scope)
+ {
+ case eValueTypeRegister:
+ case eValueTypeRegisterSet:
+ return frame != NULL;
+
+ case eValueTypeConstResult:
+ case eValueTypeVariableGlobal:
+ case eValueTypeVariableStatic:
+ return true;
+
+ case eValueTypeVariableArgument:
+ case eValueTypeVariableLocal:
+ if (frame)
+ {
+ // We don't have a location list, we just need to see if the block
+ // that this variable was defined in is currently
+ Block *deepest_frame_block = frame->GetSymbolContext(eSymbolContextBlock).block;
+ if (deepest_frame_block)
+ {
+ SymbolContext variable_sc;
+ CalculateSymbolContext (&variable_sc);
+ // Check for static or global variable defined at the compile unit
+ // level that wasn't defined in a block
+ if (variable_sc.block == NULL)
+ return true;
+
+ if (variable_sc.block == deepest_frame_block)
+ return true;
+ return variable_sc.block->Contains (deepest_frame_block);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+Error
+Variable::GetValuesForVariableExpressionPath (const char *variable_expr_path,
+ ExecutionContextScope *scope,
+ GetVariableCallback callback,
+ void *baton,
+ VariableList &variable_list,
+ ValueObjectList &valobj_list)
+{
+ Error error;
+ if (variable_expr_path && callback)
+ {
+ switch (variable_expr_path[0])
+ {
+ case '*':
+ {
+ error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
+ scope,
+ callback,
+ baton,
+ variable_list,
+ valobj_list);
+ if (error.Success())
+ {
+ for (uint32_t i=0; i<valobj_list.GetSize(); )
+ {
+ Error tmp_error;
+ ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->Dereference(tmp_error));
+ if (tmp_error.Fail())
+ {
+ variable_list.RemoveVariableAtIndex (i);
+ valobj_list.RemoveValueObjectAtIndex (i);
+ }
+ else
+ {
+ valobj_list.SetValueObjectAtIndex (i, valobj_sp);
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unknown error");
+ }
+ return error;
+ }
+ break;
+
+ case '&':
+ {
+ error = Variable::GetValuesForVariableExpressionPath (variable_expr_path + 1,
+ scope,
+ callback,
+ baton,
+ variable_list,
+ valobj_list);
+ if (error.Success())
+ {
+ for (uint32_t i=0; i<valobj_list.GetSize(); )
+ {
+ Error tmp_error;
+ ValueObjectSP valobj_sp (valobj_list.GetValueObjectAtIndex(i)->AddressOf(tmp_error));
+ if (tmp_error.Fail())
+ {
+ variable_list.RemoveVariableAtIndex (i);
+ valobj_list.RemoveValueObjectAtIndex (i);
+ }
+ else
+ {
+ valobj_list.SetValueObjectAtIndex (i, valobj_sp);
+ ++i;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("unknown error");
+ }
+ return error;
+ }
+ break;
+
+ default:
+ {
+ static RegularExpression g_regex ("^([A-Za-z_:][A-Za-z_0-9:]*)(.*)");
+ RegularExpression::Match regex_match(1);
+ if (g_regex.Execute(variable_expr_path, &regex_match))
+ {
+ std::string variable_name;
+ if (regex_match.GetMatchAtIndex(variable_expr_path, 1, variable_name))
+ {
+ variable_list.Clear();
+ if (callback (baton, variable_name.c_str(), variable_list))
+ {
+ uint32_t i=0;
+ while (i < variable_list.GetSize())
+ {
+ VariableSP var_sp (variable_list.GetVariableAtIndex (i));
+ ValueObjectSP valobj_sp;
+ if (var_sp)
+ {
+ ValueObjectSP variable_valobj_sp(ValueObjectVariable::Create (scope, var_sp));
+ if (variable_valobj_sp)
+ {
+ const char *variable_sub_expr_path = variable_expr_path + variable_name.size();
+ if (*variable_sub_expr_path)
+ {
+ const char* first_unparsed = NULL;
+ ValueObject::ExpressionPathScanEndReason reason_to_stop;
+ ValueObject::ExpressionPathEndResultType final_value_type;
+ ValueObject::GetValueForExpressionPathOptions options;
+ ValueObject::ExpressionPathAftermath final_task_on_target;
+
+ valobj_sp = variable_valobj_sp->GetValueForExpressionPath (variable_sub_expr_path,
+ &first_unparsed,
+ &reason_to_stop,
+ &final_value_type,
+ options,
+ &final_task_on_target);
+ if (!valobj_sp)
+ {
+ error.SetErrorStringWithFormat ("invalid expression path '%s' for variable '%s'",
+ variable_sub_expr_path,
+ var_sp->GetName().GetCString());
+ }
+ }
+ else
+ {
+ // Just the name of a variable with no extras
+ valobj_sp = variable_valobj_sp;
+ }
+ }
+ }
+
+ if (!var_sp || !valobj_sp)
+ {
+ variable_list.RemoveVariableAtIndex (i);
+ }
+ else
+ {
+ valobj_list.Append(valobj_sp);
+ ++i;
+ }
+ }
+
+ if (variable_list.GetSize() > 0)
+ {
+ error.Clear();
+ return error;
+ }
+ }
+ }
+ }
+ error.SetErrorStringWithFormat ("unable to extract a variable name from '%s'", variable_expr_path);
+ }
+ break;
+ }
+ }
+ error.SetErrorString ("unknown error");
+ return error;
+}
+
+bool
+Variable::DumpLocationForAddress (Stream *s, const Address &address)
+{
+ // Be sure to resolve the address to section offset prior to
+ // calling this function.
+ if (address.IsSectionOffset())
+ {
+ SymbolContext sc;
+ CalculateSymbolContext(&sc);
+ if (sc.module_sp == address.GetModule())
+ {
+ ABI *abi = NULL;
+ if (m_owner_scope)
+ {
+ ModuleSP module_sp (m_owner_scope->CalculateSymbolContextModule());
+ if (module_sp)
+ abi = ABI::FindPlugin (module_sp->GetArchitecture()).get();
+ }
+
+ const addr_t file_addr = address.GetFileAddress();
+ if (sc.function)
+ {
+ if (sc.function->GetAddressRange().ContainsFileAddress(address))
+ {
+ addr_t loclist_base_file_addr = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
+ return false;
+ return m_location.DumpLocationForAddress (s,
+ eDescriptionLevelBrief,
+ loclist_base_file_addr,
+ file_addr,
+ abi);
+ }
+ }
+ return m_location.DumpLocationForAddress (s,
+ eDescriptionLevelBrief,
+ LLDB_INVALID_ADDRESS,
+ file_addr,
+ abi);
+ }
+ }
+ return false;
+}
+
+
+static void
+PrivateAutoComplete (StackFrame *frame,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete);
+
+static void
+PrivateAutoCompleteMembers (StackFrame *frame,
+ const std::string &partial_member_name,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete);
+
+static void
+PrivateAutoCompleteMembers (StackFrame *frame,
+ const std::string &partial_member_name,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete)
+{
+
+ // We are in a type parsing child members
+ const uint32_t num_bases = clang_type.GetNumDirectBaseClasses();
+
+ if (num_bases > 0)
+ {
+ for (uint32_t i = 0; i < num_bases; ++i)
+ {
+ ClangASTType base_class_type (clang_type.GetDirectBaseClassAtIndex (i, NULL));
+
+ PrivateAutoCompleteMembers (frame,
+ partial_member_name,
+ partial_path,
+ prefix_path,
+ base_class_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+
+ const uint32_t num_vbases = clang_type.GetNumVirtualBaseClasses();
+
+ if (num_vbases > 0)
+ {
+ for (uint32_t i = 0; i < num_vbases; ++i)
+ {
+ ClangASTType vbase_class_type (clang_type.GetVirtualBaseClassAtIndex(i,NULL));
+
+ PrivateAutoCompleteMembers (frame,
+ partial_member_name,
+ partial_path,
+ prefix_path,
+ vbase_class_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+
+ // We are in a type parsing child members
+ const uint32_t num_fields = clang_type.GetNumFields();
+
+ if (num_fields > 0)
+ {
+ for (uint32_t i = 0; i < num_fields; ++i)
+ {
+ std::string member_name;
+
+ ClangASTType member_clang_type = clang_type.GetFieldAtIndex (i, member_name, NULL, NULL, NULL);
+
+ if (partial_member_name.empty() ||
+ member_name.find(partial_member_name) == 0)
+ {
+ if (member_name == partial_member_name)
+ {
+ PrivateAutoComplete (frame,
+ partial_path,
+ prefix_path + member_name, // Anything that has been resolved already will be in here
+ member_clang_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ matches.AppendString (prefix_path + member_name);
+ }
+ }
+ }
+ }
+}
+
+static void
+PrivateAutoComplete (StackFrame *frame,
+ const std::string &partial_path,
+ const std::string &prefix_path, // Anything that has been resolved already will be in here
+ const ClangASTType& clang_type,
+ StringList &matches,
+ bool &word_complete)
+{
+// printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str());
+ std::string remaining_partial_path;
+
+ const lldb::TypeClass type_class = clang_type.GetTypeClass();
+ if (partial_path.empty())
+ {
+ if (clang_type.IsValid())
+ {
+ switch (type_class)
+ {
+ default:
+ case eTypeClassArray:
+ case eTypeClassBlockPointer:
+ case eTypeClassBuiltin:
+ case eTypeClassComplexFloat:
+ case eTypeClassComplexInteger:
+ case eTypeClassEnumeration:
+ case eTypeClassFunction:
+ case eTypeClassMemberPointer:
+ case eTypeClassReference:
+ case eTypeClassTypedef:
+ case eTypeClassVector:
+ {
+ matches.AppendString (prefix_path);
+ word_complete = matches.GetSize() == 1;
+ }
+ break;
+
+ case eTypeClassClass:
+ case eTypeClassStruct:
+ case eTypeClassUnion:
+ if (prefix_path.back() != '.')
+ matches.AppendString (prefix_path + '.');
+ break;
+
+ case eTypeClassObjCObject:
+ case eTypeClassObjCInterface:
+ break;
+ case eTypeClassObjCObjectPointer:
+ case eTypeClassPointer:
+ {
+ bool omit_empty_base_classes = true;
+ if (clang_type.GetNumChildren (omit_empty_base_classes) > 0)
+ matches.AppendString (prefix_path + "->");
+ else
+ {
+ matches.AppendString (prefix_path);
+ word_complete = true;
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (frame)
+ {
+ const bool get_file_globals = true;
+
+ VariableList *variable_list = frame->GetVariableList(get_file_globals);
+
+ const size_t num_variables = variable_list->GetSize();
+ for (size_t i=0; i<num_variables; ++i)
+ {
+ Variable *variable = variable_list->GetVariableAtIndex(i).get();
+ matches.AppendString (variable->GetName().AsCString());
+ }
+ }
+ }
+ }
+ else
+ {
+ const char ch = partial_path[0];
+ switch (ch)
+ {
+ case '*':
+ if (prefix_path.empty())
+ {
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ std::string("*"),
+ clang_type,
+ matches,
+ word_complete);
+ }
+ break;
+
+ case '&':
+ if (prefix_path.empty())
+ {
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ std::string("&"),
+ clang_type,
+ matches,
+ word_complete);
+ }
+ break;
+
+ case '-':
+ if (partial_path[1] == '>' && !prefix_path.empty())
+ {
+ switch (type_class)
+ {
+ case lldb::eTypeClassPointer:
+ {
+ ClangASTType pointee_type(clang_type.GetPointeeType());
+ if (partial_path[2])
+ {
+ // If there is more after the "->", then search deeper
+ PrivateAutoComplete (frame,
+ partial_path.substr(2),
+ prefix_path + "->",
+ pointee_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ // Nothing after the "->", so list all members
+ PrivateAutoCompleteMembers (frame,
+ std::string(),
+ std::string(),
+ prefix_path + "->",
+ pointee_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ }
+ default:
+ break;
+ }
+ }
+ break;
+
+ case '.':
+ if (clang_type.IsValid())
+ {
+ switch (type_class)
+ {
+ case lldb::eTypeClassUnion:
+ case lldb::eTypeClassStruct:
+ case lldb::eTypeClassClass:
+ if (partial_path[1])
+ {
+ // If there is more after the ".", then search deeper
+ PrivateAutoComplete (frame,
+ partial_path.substr(1),
+ prefix_path + ".",
+ clang_type,
+ matches,
+ word_complete);
+
+ }
+ else
+ {
+ // Nothing after the ".", so list all members
+ PrivateAutoCompleteMembers (frame,
+ std::string(),
+ partial_path,
+ prefix_path + ".",
+ clang_type,
+ matches,
+ word_complete);
+ }
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ if (isalpha(ch) || ch == '_' || ch == '$')
+ {
+ const size_t partial_path_len = partial_path.size();
+ size_t pos = 1;
+ while (pos < partial_path_len)
+ {
+ const char curr_ch = partial_path[pos];
+ if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$')
+ {
+ ++pos;
+ continue;
+ }
+ break;
+ }
+
+ std::string token(partial_path, 0, pos);
+ remaining_partial_path = partial_path.substr(pos);
+
+ if (clang_type.IsValid())
+ {
+ PrivateAutoCompleteMembers (frame,
+ token,
+ remaining_partial_path,
+ prefix_path,
+ clang_type,
+ matches,
+ word_complete);
+ }
+ else if (frame)
+ {
+ // We haven't found our variable yet
+ const bool get_file_globals = true;
+
+ VariableList *variable_list = frame->GetVariableList(get_file_globals);
+
+ const size_t num_variables = variable_list->GetSize();
+ for (size_t i=0; i<num_variables; ++i)
+ {
+ Variable *variable = variable_list->GetVariableAtIndex(i).get();
+ const char *variable_name = variable->GetName().AsCString();
+ if (strstr(variable_name, token.c_str()) == variable_name)
+ {
+ if (strcmp (variable_name, token.c_str()) == 0)
+ {
+ Type *variable_type = variable->GetType();
+ if (variable_type)
+ {
+ ClangASTType variable_clang_type (variable_type->GetClangForwardType());
+ PrivateAutoComplete (frame,
+ remaining_partial_path,
+ prefix_path + token, // Anything that has been resolved already will be in here
+ variable_clang_type.GetCanonicalType(),
+ matches,
+ word_complete);
+ }
+ else
+ {
+ matches.AppendString (prefix_path + variable_name);
+ }
+ }
+ else if (remaining_partial_path.empty())
+ {
+ matches.AppendString (prefix_path + variable_name);
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+
+size_t
+Variable::AutoComplete (const ExecutionContext &exe_ctx,
+ const char *partial_path_cstr,
+ StringList &matches,
+ bool &word_complete)
+{
+ word_complete = false;
+ std::string partial_path;
+ std::string prefix_path;
+ ClangASTType clang_type;
+ if (partial_path_cstr && partial_path_cstr[0])
+ partial_path = partial_path_cstr;
+
+ PrivateAutoComplete (exe_ctx.GetFramePtr(),
+ partial_path,
+ prefix_path,
+ clang_type,
+ matches,
+ word_complete);
+
+ return matches.GetSize();
+}
+
diff --git a/source/Symbol/VariableList.cpp b/source/Symbol/VariableList.cpp
new file mode 100644
index 000000000000..3451166e52d4
--- /dev/null
+++ b/source/Symbol/VariableList.cpp
@@ -0,0 +1,201 @@
+//===-- VariableList.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/Symbol/VariableList.h"
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/CompileUnit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// VariableList constructor
+//----------------------------------------------------------------------
+VariableList::VariableList() :
+ m_variables()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+VariableList::~VariableList()
+{
+}
+
+void
+VariableList::AddVariable(const VariableSP &var_sp)
+{
+ m_variables.push_back(var_sp);
+}
+
+bool
+VariableList::AddVariableIfUnique (const lldb::VariableSP &var_sp)
+{
+ if (FindVariableIndex (var_sp) == UINT32_MAX)
+ {
+ m_variables.push_back(var_sp);
+ return true;
+ }
+ return false;
+}
+
+void
+VariableList::AddVariables(VariableList *variable_list)
+{
+ if (variable_list)
+ {
+ std::copy(variable_list->m_variables.begin(), // source begin
+ variable_list->m_variables.end(), // source end
+ back_inserter(m_variables)); // destination
+ }
+}
+
+void
+VariableList::Clear()
+{
+ m_variables.clear();
+}
+
+VariableSP
+VariableList::GetVariableAtIndex(size_t idx) const
+{
+ VariableSP var_sp;
+ if (idx < m_variables.size())
+ var_sp = m_variables[idx];
+ return var_sp;
+}
+
+VariableSP
+VariableList::RemoveVariableAtIndex(size_t idx)
+{
+ VariableSP var_sp;
+ if (idx < m_variables.size())
+ {
+ var_sp = m_variables[idx];
+ m_variables.erase (m_variables.begin() + idx);
+ }
+ return var_sp;
+}
+
+uint32_t
+VariableList::FindVariableIndex (const VariableSP &var_sp)
+{
+ iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == var_sp.get())
+ return std::distance (m_variables.begin(), pos);
+ }
+ return UINT32_MAX;
+}
+
+VariableSP
+VariableList::FindVariable(const ConstString& name)
+{
+ VariableSP var_sp;
+ iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->NameMatches(name))
+ {
+ var_sp = (*pos);
+ break;
+ }
+ }
+ return var_sp;
+}
+
+size_t
+VariableList::AppendVariablesIfUnique (const RegularExpression& regex, VariableList &var_list, size_t& total_matches)
+{
+ const size_t initial_size = var_list.GetSize();
+ iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->NameMatches (regex))
+ {
+ // Note the total matches found
+ total_matches++;
+ // Only add this variable if it isn't already in the "var_list"
+ var_list.AddVariableIfUnique (*pos);
+ }
+ }
+ // Return the number of new unique variables added to "var_list"
+ return var_list.GetSize() - initial_size;
+}
+
+size_t
+VariableList::AppendVariablesWithScope (lldb::ValueType type,
+ VariableList &var_list,
+ bool if_unique)
+{
+ const size_t initial_size = var_list.GetSize();
+ iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetScope() == type)
+ {
+ if (if_unique)
+ var_list.AddVariableIfUnique (*pos);
+ else
+ var_list.AddVariable(*pos);
+ }
+ }
+ // Return the number of new unique variables added to "var_list"
+ return var_list.GetSize() - initial_size;
+}
+
+uint32_t
+VariableList::FindIndexForVariable (Variable* variable)
+{
+ VariableSP var_sp;
+ iterator pos;
+ const iterator begin = m_variables.begin();
+ const iterator end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ if ((*pos).get() == variable)
+ return std::distance (begin, pos);
+ }
+ return UINT32_MAX;
+}
+
+size_t
+VariableList::MemorySize() const
+{
+ size_t mem_size = sizeof(VariableList);
+ const_iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ mem_size += (*pos)->MemorySize();
+ return mem_size;
+}
+
+size_t
+VariableList::GetSize() const
+{
+ return m_variables.size();
+}
+
+void
+VariableList::Dump(Stream *s, bool show_context) const
+{
+// s.Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+// s.Indent();
+// s << "VariableList\n";
+
+ const_iterator pos, end = m_variables.end();
+ for (pos = m_variables.begin(); pos != end; ++pos)
+ {
+ (*pos)->Dump(s, show_context);
+ }
+}
diff --git a/source/Symbol/VerifyDecl.cpp b/source/Symbol/VerifyDecl.cpp
new file mode 100644
index 000000000000..765568040ece
--- /dev/null
+++ b/source/Symbol/VerifyDecl.cpp
@@ -0,0 +1,16 @@
+//===-- VerifyDecl.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/Symbol/VerifyDecl.h"
+#include "clang/AST/DeclBase.h"
+
+void lldb_private::VerifyDecl (clang::Decl *decl)
+{
+ decl->getAccess();
+}
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp
new file mode 100644
index 000000000000..06215221d961
--- /dev/null
+++ b/source/Target/ABI.cpp
@@ -0,0 +1,175 @@
+//===-- ABI.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/ABI.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTType.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ABISP
+ABI::FindPlugin (const ArchSpec &arch)
+{
+ ABISP abi_sp;
+ ABICreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) != NULL;
+ ++idx)
+ {
+ abi_sp = create_callback(arch);
+
+ if (abi_sp)
+ return abi_sp;
+ }
+ abi_sp.reset();
+ return abi_sp;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+ABI::ABI()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ABI::~ABI()
+{
+}
+
+
+bool
+ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info)
+{
+ uint32_t count = 0;
+ const RegisterInfo *register_info_array = GetRegisterInfoArray (count);
+ if (register_info_array)
+ {
+ const char *unique_name_cstr = name.GetCString();
+ uint32_t i;
+ for (i=0; i<count; ++i)
+ {
+ if (register_info_array[i].name == unique_name_cstr)
+ {
+ info = register_info_array[i];
+ return true;
+ }
+ }
+ for (i=0; i<count; ++i)
+ {
+ if (register_info_array[i].alt_name == unique_name_cstr)
+ {
+ info = register_info_array[i];
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+ABI::GetRegisterInfoByKind (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &info)
+{
+ if (reg_kind < eRegisterKindGCC || reg_kind >= kNumRegisterKinds)
+ return false;
+
+ uint32_t count = 0;
+ const RegisterInfo *register_info_array = GetRegisterInfoArray (count);
+ if (register_info_array)
+ {
+ for (uint32_t i=0; i<count; ++i)
+ {
+ if (register_info_array[i].kinds[reg_kind] == reg_num)
+ {
+ info = register_info_array[i];
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ValueObjectSP
+ABI::GetReturnValueObject (Thread &thread,
+ ClangASTType &ast_type,
+ bool persistent) const
+{
+ if (!ast_type.IsValid())
+ return ValueObjectSP();
+
+ ValueObjectSP return_valobj_sp;
+
+ return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
+ if (!return_valobj_sp)
+ return return_valobj_sp;
+
+ // Now turn this into a persistent variable.
+ // FIXME: This code is duplicated from Target::EvaluateExpression, and it is used in similar form in a couple
+ // of other places. Figure out the correct Create function to do all this work.
+
+ if (persistent)
+ {
+ ClangPersistentVariables& persistent_variables = thread.CalculateTarget()->GetPersistentVariables();
+ ConstString persistent_variable_name (persistent_variables.GetNextPersistentVariableName());
+
+ lldb::ValueObjectSP const_valobj_sp;
+
+ // Check in case our value is already a constant value
+ if (return_valobj_sp->GetIsConstant())
+ {
+ const_valobj_sp = return_valobj_sp;
+ const_valobj_sp->SetName (persistent_variable_name);
+ }
+ else
+ const_valobj_sp = return_valobj_sp->CreateConstantValue (persistent_variable_name);
+
+ lldb::ValueObjectSP live_valobj_sp = return_valobj_sp;
+
+ return_valobj_sp = const_valobj_sp;
+
+ ClangExpressionVariableSP clang_expr_variable_sp(persistent_variables.CreatePersistentVariable(return_valobj_sp));
+
+ assert (clang_expr_variable_sp.get());
+
+ // Set flags and live data as appropriate
+
+ const Value &result_value = live_valobj_sp->GetValue();
+
+ switch (result_value.GetValueType())
+ {
+ case Value::eValueTypeHostAddress:
+ case Value::eValueTypeFileAddress:
+ // we don't do anything with these for now
+ break;
+ case Value::eValueTypeScalar:
+ case Value::eValueTypeVector:
+ clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsFreezeDried;
+ clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
+ clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
+ break;
+ case Value::eValueTypeLoadAddress:
+ clang_expr_variable_sp->m_live_sp = live_valobj_sp;
+ clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference;
+ break;
+ }
+
+ return_valobj_sp = clang_expr_variable_sp->GetValueObject();
+ }
+ return return_valobj_sp;
+}
+
+
diff --git a/source/Target/CPPLanguageRuntime.cpp b/source/Target/CPPLanguageRuntime.cpp
new file mode 100644
index 000000000000..f5b7f7fc41a6
--- /dev/null
+++ b/source/Target/CPPLanguageRuntime.cpp
@@ -0,0 +1,386 @@
+//===-- CPPLanguageRuntime.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/CPPLanguageRuntime.h"
+
+#include <string.h>
+
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Target/ExecutionContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+class CPPRuntimeEquivalents
+{
+public:
+ CPPRuntimeEquivalents ()
+ {
+
+ m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("basic_string<char>"));
+
+ // these two (with a prefixed std::) occur when c++stdlib string class occurs as a template argument in some STL container
+ m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, std::allocator<char> >").AsCString(), ConstString("std::basic_string<char>"));
+
+ m_impl.Sort();
+ }
+
+ void
+ Add (ConstString& type_name,
+ ConstString& type_equivalent)
+ {
+ m_impl.Insert(type_name.AsCString(), type_equivalent);
+ }
+
+ uint32_t
+ FindExactMatches (ConstString& type_name,
+ std::vector<ConstString>& equivalents)
+ {
+
+ uint32_t count = 0;
+
+ for (ImplData match = m_impl.FindFirstValueForName(type_name.AsCString());
+ match != NULL;
+ match = m_impl.FindNextValueForName(match))
+ {
+ equivalents.push_back(match->value);
+ count++;
+ }
+
+ return count;
+ }
+
+ // partial matches can occur when a name with equivalents is a template argument.
+ // e.g. we may have "class Foo" be a match for "struct Bar". if we have a typename
+ // such as "class Templatized<class Foo, Anything>" we want this to be replaced with
+ // "class Templatized<struct Bar, Anything>". Since partial matching is time consuming
+ // once we get a partial match, we add it to the exact matches list for faster retrieval
+ uint32_t
+ FindPartialMatches (ConstString& type_name,
+ std::vector<ConstString>& equivalents)
+ {
+
+ uint32_t count = 0;
+
+ const char* type_name_cstr = type_name.AsCString();
+
+ size_t items_count = m_impl.GetSize();
+
+ for (size_t item = 0; item < items_count; item++)
+ {
+ const char* key_cstr = m_impl.GetCStringAtIndex(item);
+ if ( strstr(type_name_cstr,key_cstr) )
+ {
+ count += AppendReplacements(type_name_cstr,
+ key_cstr,
+ equivalents);
+ }
+ }
+
+ return count;
+
+ }
+
+private:
+
+ std::string& replace (std::string& target,
+ std::string& pattern,
+ std::string& with)
+ {
+ size_t pos;
+ size_t pattern_len = pattern.size();
+
+ while ( (pos = target.find(pattern)) != std::string::npos )
+ target.replace(pos, pattern_len, with);
+
+ return target;
+ }
+
+ uint32_t
+ AppendReplacements (const char* original,
+ const char *matching_key,
+ std::vector<ConstString>& equivalents)
+ {
+
+ std::string matching_key_str(matching_key);
+ ConstString original_const(original);
+
+ uint32_t count = 0;
+
+ for (ImplData match = m_impl.FindFirstValueForName(matching_key);
+ match != NULL;
+ match = m_impl.FindNextValueForName(match))
+ {
+ std::string target(original);
+ std::string equiv_class(match->value.AsCString());
+
+ replace (target, matching_key_str, equiv_class);
+
+ ConstString target_const(target.c_str());
+
+// you will most probably want to leave this off since it might make this map grow indefinitely
+#ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW
+ Add(original_const, target_const);
+#endif
+ equivalents.push_back(target_const);
+
+ count++;
+ }
+
+ return count;
+ }
+
+ typedef UniqueCStringMap<ConstString> Impl;
+ typedef const Impl::Entry* ImplData;
+ Impl m_impl;
+};
+
+static CPPRuntimeEquivalents&
+GetEquivalentsMap ()
+{
+ static CPPRuntimeEquivalents g_equivalents_map;
+ return g_equivalents_map;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+CPPLanguageRuntime::~CPPLanguageRuntime()
+{
+}
+
+CPPLanguageRuntime::CPPLanguageRuntime (Process *process) :
+ LanguageRuntime (process)
+{
+
+}
+
+bool
+CPPLanguageRuntime::GetObjectDescription (Stream &str, ValueObject &object)
+{
+ // C++ has no generic way to do this.
+ return false;
+}
+
+bool
+CPPLanguageRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope)
+{
+ // C++ has no generic way to do this.
+ return false;
+}
+
+bool
+CPPLanguageRuntime::IsCPPMangledName (const char *name)
+{
+ // FIXME, we should really run through all the known C++ Language plugins and ask each one if
+ // this is a C++ mangled name, but we can put that off till there is actually more than one
+ // we care about.
+
+ if (name && name[0] == '_' && name[1] == 'Z')
+ return true;
+ else
+ return false;
+}
+
+bool
+CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end)
+{
+ 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
+ {
+ // FIXME: should check if there is
+ base_name_start = last_colon + 1;
+ return true;
+ }
+}
+
+uint32_t
+CPPLanguageRuntime::FindEquivalentNames(ConstString type_name, std::vector<ConstString>& equivalents)
+{
+ uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents);
+
+ bool might_have_partials=
+ ( count == 0 ) // if we have a full name match just use it
+ && (strchr(type_name.AsCString(), '<') != NULL // we should only have partial matches when templates are involved, check that we have
+ && strchr(type_name.AsCString(), '>') != NULL); // angle brackets in the type_name before trying to scan for partial matches
+
+ if ( might_have_partials )
+ count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents);
+
+ return count;
+}
+
+void
+CPPLanguageRuntime::MethodName::Clear()
+{
+ m_full.Clear();
+ m_basename = llvm::StringRef();
+ m_context = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_type = eTypeInvalid;
+ m_parsed = false;
+ m_parse_error = false;
+}
+
+bool
+ReverseFindMatchingChars (const llvm::StringRef &s,
+ const llvm::StringRef &left_right_chars,
+ size_t &left_pos,
+ size_t &right_pos,
+ size_t pos = llvm::StringRef::npos)
+{
+ assert (left_right_chars.size() == 2);
+ left_pos = llvm::StringRef::npos;
+ const char left_char = left_right_chars[0];
+ const char right_char = left_right_chars[1];
+ pos = s.find_last_of(left_right_chars, pos);
+ if (pos == llvm::StringRef::npos || s[pos] == left_char)
+ return false;
+ right_pos = pos;
+ uint32_t depth = 1;
+ while (pos > 0 && depth > 0)
+ {
+ pos = s.find_last_of(left_right_chars, pos);
+ if (pos == llvm::StringRef::npos)
+ return false;
+ if (s[pos] == left_char)
+ {
+ if (--depth == 0)
+ {
+ left_pos = pos;
+ return left_pos < right_pos;
+ }
+ }
+ else if (s[pos] == right_char)
+ {
+ ++depth;
+ }
+ }
+ return false;
+}
+
+void
+CPPLanguageRuntime::MethodName::Parse()
+{
+ if (!m_parsed && m_full)
+ {
+// ConstString mangled;
+// m_full.GetMangledCounterpart(mangled);
+// printf ("\n parsing = '%s'\n", m_full.GetCString());
+// if (mangled)
+// printf (" mangled = '%s'\n", mangled.GetCString());
+ m_parse_error = false;
+ m_parsed = true;
+ llvm::StringRef full (m_full.GetCString());
+
+ size_t arg_start, arg_end;
+ llvm::StringRef parens("()", 2);
+ if (ReverseFindMatchingChars (full, parens, arg_start, arg_end))
+ {
+ m_arguments = full.substr(arg_start, arg_end - arg_start + 1);
+ if (arg_end + 1 < full.size())
+ m_qualifiers = full.substr(arg_end + 1);
+ if (arg_start > 0)
+ {
+ size_t basename_end = arg_start;
+ size_t context_end = llvm::StringRef::npos;
+ if (basename_end > 0 && full[basename_end-1] == '>')
+ {
+ // TODO: handle template junk...
+ // Templated function
+ 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)
+ 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);
+ const size_t basename_begin = context_end + 1;
+ m_basename = full.substr(basename_begin, basename_end - basename_begin);
+ }
+ m_type = eTypeUnknownMethod;
+ }
+ else
+ {
+ m_parse_error = true;
+ return;
+ }
+
+// if (!m_context.empty())
+// printf (" context = '%s'\n", m_context.str().c_str());
+// if (m_basename)
+// printf (" basename = '%s'\n", m_basename.GetCString());
+// if (!m_arguments.empty())
+// printf (" arguments = '%s'\n", m_arguments.str().c_str());
+// if (!m_qualifiers.empty())
+// printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
+ }
+ else
+ {
+ m_parse_error = true;
+// printf ("error: didn't find matching parens for arguments\n");
+ }
+ }
+}
+
+llvm::StringRef
+CPPLanguageRuntime::MethodName::GetBasename ()
+{
+ if (!m_parsed)
+ Parse();
+ return m_basename;
+}
+
+llvm::StringRef
+CPPLanguageRuntime::MethodName::GetContext ()
+{
+ if (!m_parsed)
+ Parse();
+ return m_context;
+}
+
+llvm::StringRef
+CPPLanguageRuntime::MethodName::GetArguments ()
+{
+ if (!m_parsed)
+ Parse();
+ return m_arguments;
+}
+
+llvm::StringRef
+CPPLanguageRuntime::MethodName::GetQualifiers ()
+{
+ if (!m_parsed)
+ Parse();
+ return m_qualifiers;
+}
+
diff --git a/source/Target/ExecutionContext.cpp b/source/Target/ExecutionContext.cpp
new file mode 100644
index 000000000000..8b5731e80280
--- /dev/null
+++ b/source/Target/ExecutionContext.cpp
@@ -0,0 +1,824 @@
+//===-- ExecutionContext.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/ExecutionContext.h"
+
+#include "lldb/Core/State.h"
+#include "lldb/Target/ExecutionContextScope.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb_private;
+
+ExecutionContext::ExecutionContext() :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContext &rhs) :
+ m_target_sp(rhs.m_target_sp),
+ m_process_sp(rhs.m_process_sp),
+ m_thread_sp(rhs.m_thread_sp),
+ m_frame_sp(rhs.m_frame_sp)
+{
+}
+
+ExecutionContext::ExecutionContext (const lldb::TargetSP &target_sp, bool get_process) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (target_sp)
+ SetContext (target_sp, get_process);
+}
+
+ExecutionContext::ExecutionContext (const lldb::ProcessSP &process_sp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (process_sp)
+ SetContext (process_sp);
+}
+
+ExecutionContext::ExecutionContext (const lldb::ThreadSP &thread_sp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (thread_sp)
+ SetContext (thread_sp);
+}
+
+ExecutionContext::ExecutionContext (const lldb::StackFrameSP &frame_sp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (frame_sp)
+ SetContext (frame_sp);
+}
+
+ExecutionContext::ExecutionContext (const lldb::TargetWP &target_wp, bool get_process) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ lldb::TargetSP target_sp(target_wp.lock());
+ if (target_sp)
+ SetContext (target_sp, get_process);
+}
+
+ExecutionContext::ExecutionContext (const lldb::ProcessWP &process_wp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ lldb::ProcessSP process_sp(process_wp.lock());
+ if (process_sp)
+ SetContext (process_sp);
+}
+
+ExecutionContext::ExecutionContext (const lldb::ThreadWP &thread_wp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ lldb::ThreadSP thread_sp(thread_wp.lock());
+ if (thread_sp)
+ SetContext (thread_sp);
+}
+
+ExecutionContext::ExecutionContext (const lldb::StackFrameWP &frame_wp) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ lldb::StackFrameSP frame_sp(frame_wp.lock());
+ if (frame_sp)
+ SetContext (frame_sp);
+}
+
+ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) :
+ m_target_sp (t->shared_from_this()),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (t && fill_current_process_thread_frame)
+ {
+ m_process_sp = t->GetProcessSP();
+ if (m_process_sp)
+ {
+ m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread();
+ if (m_thread_sp)
+ m_frame_sp = m_thread_sp->GetSelectedFrame();
+ }
+ }
+}
+
+ExecutionContext::ExecutionContext(Process* process, Thread *thread, StackFrame *frame) :
+ m_target_sp (),
+ m_process_sp (process->shared_from_this()),
+ m_thread_sp (thread->shared_from_this()),
+ m_frame_sp (frame->shared_from_this())
+{
+ if (process)
+ m_target_sp = process->GetTarget().shared_from_this();
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref) :
+ m_target_sp (exe_ctx_ref.GetTargetSP()),
+ m_process_sp (exe_ctx_ref.GetProcessSP()),
+ m_thread_sp (exe_ctx_ref.GetThreadSP()),
+ m_frame_sp (exe_ctx_ref.GetFrameSP())
+{
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (exe_ctx_ref_ptr)
+ {
+ m_target_sp = exe_ctx_ref_ptr->GetTargetSP();
+ m_process_sp = exe_ctx_ref_ptr->GetProcessSP();
+ m_thread_sp = exe_ctx_ref_ptr->GetThreadSP();
+ m_frame_sp = exe_ctx_ref_ptr->GetFrameSP();
+ }
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr, Mutex::Locker &locker) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (exe_ctx_ref_ptr)
+ {
+ m_target_sp = exe_ctx_ref_ptr->GetTargetSP();
+ if (m_target_sp)
+ {
+ locker.Lock(m_target_sp->GetAPIMutex());
+ m_process_sp = exe_ctx_ref_ptr->GetProcessSP();
+ m_thread_sp = exe_ctx_ref_ptr->GetThreadSP();
+ m_frame_sp = exe_ctx_ref_ptr->GetFrameSP();
+ }
+ }
+}
+
+ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref, Mutex::Locker &locker) :
+ m_target_sp (exe_ctx_ref.GetTargetSP()),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (m_target_sp)
+ {
+ locker.Lock(m_target_sp->GetAPIMutex());
+ m_process_sp = exe_ctx_ref.GetProcessSP();
+ m_thread_sp = exe_ctx_ref.GetThreadSP();
+ m_frame_sp = exe_ctx_ref.GetFrameSP();
+ }
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr) :
+ m_target_sp (),
+ m_process_sp (),
+ m_thread_sp (),
+ m_frame_sp ()
+{
+ if (exe_scope_ptr)
+ exe_scope_ptr->CalculateExecutionContext (*this);
+}
+
+ExecutionContext::ExecutionContext (ExecutionContextScope &exe_scope_ref)
+{
+ exe_scope_ref.CalculateExecutionContext (*this);
+}
+
+void
+ExecutionContext::Clear()
+{
+ m_target_sp.reset();
+ m_process_sp.reset();
+ m_thread_sp.reset();
+ m_frame_sp.reset();
+}
+
+ExecutionContext::~ExecutionContext()
+{
+}
+
+uint32_t
+ExecutionContext::GetAddressByteSize() const
+{
+ if (m_target_sp && m_target_sp->GetArchitecture().IsValid())
+ m_target_sp->GetArchitecture().GetAddressByteSize();
+ if (m_process_sp)
+ m_process_sp->GetAddressByteSize();
+ return sizeof(void *);
+}
+
+
+
+RegisterContext *
+ExecutionContext::GetRegisterContext () const
+{
+ if (m_frame_sp)
+ return m_frame_sp->GetRegisterContext().get();
+ else if (m_thread_sp)
+ return m_thread_sp->GetRegisterContext().get();
+ return NULL;
+}
+
+Target *
+ExecutionContext::GetTargetPtr () const
+{
+ if (m_target_sp)
+ return m_target_sp.get();
+ if (m_process_sp)
+ return &m_process_sp->GetTarget();
+ return NULL;
+}
+
+Process *
+ExecutionContext::GetProcessPtr () const
+{
+ if (m_process_sp)
+ return m_process_sp.get();
+ if (m_target_sp)
+ return m_target_sp->GetProcessSP().get();
+ return NULL;
+}
+
+ExecutionContextScope *
+ExecutionContext::GetBestExecutionContextScope () const
+{
+ if (m_frame_sp)
+ return m_frame_sp.get();
+ if (m_thread_sp)
+ return m_thread_sp.get();
+ if (m_process_sp)
+ return m_process_sp.get();
+ return m_target_sp.get();
+}
+
+Target &
+ExecutionContext::GetTargetRef () const
+{
+#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ assert (m_target_sp.get());
+#endif
+ return *m_target_sp;
+}
+
+Process &
+ExecutionContext::GetProcessRef () const
+{
+#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ assert (m_process_sp.get());
+#endif
+ return *m_process_sp;
+}
+
+Thread &
+ExecutionContext::GetThreadRef () const
+{
+#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ assert (m_thread_sp.get());
+#endif
+ return *m_thread_sp;
+}
+
+StackFrame &
+ExecutionContext::GetFrameRef () const
+{
+#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE)
+ assert (m_frame_sp.get());
+#endif
+ return *m_frame_sp;
+}
+
+void
+ExecutionContext::SetTargetSP (const lldb::TargetSP &target_sp)
+{
+ m_target_sp = target_sp;
+}
+
+void
+ExecutionContext::SetProcessSP (const lldb::ProcessSP &process_sp)
+{
+ m_process_sp = process_sp;
+}
+
+void
+ExecutionContext::SetThreadSP (const lldb::ThreadSP &thread_sp)
+{
+ m_thread_sp = thread_sp;
+}
+
+void
+ExecutionContext::SetFrameSP (const lldb::StackFrameSP &frame_sp)
+{
+ m_frame_sp = frame_sp;
+}
+
+void
+ExecutionContext::SetTargetPtr (Target* target)
+{
+ if (target)
+ m_target_sp = target->shared_from_this();
+ else
+ m_target_sp.reset();
+}
+
+void
+ExecutionContext::SetProcessPtr (Process *process)
+{
+ if (process)
+ m_process_sp = process->shared_from_this();
+ else
+ m_process_sp.reset();
+}
+
+void
+ExecutionContext::SetThreadPtr (Thread *thread)
+{
+ if (thread)
+ m_thread_sp = thread->shared_from_this();
+ else
+ m_thread_sp.reset();
+}
+
+void
+ExecutionContext::SetFramePtr (StackFrame *frame)
+{
+ if (frame)
+ m_frame_sp = frame->shared_from_this();
+ else
+ m_frame_sp.reset();
+}
+
+void
+ExecutionContext::SetContext (const lldb::TargetSP &target_sp, bool get_process)
+{
+ m_target_sp = target_sp;
+ if (get_process && target_sp)
+ m_process_sp = target_sp->GetProcessSP();
+ else
+ m_process_sp.reset();
+ m_thread_sp.reset();
+ m_frame_sp.reset();
+}
+
+void
+ExecutionContext::SetContext (const lldb::ProcessSP &process_sp)
+{
+ m_process_sp = process_sp;
+ if (process_sp)
+ m_target_sp = process_sp->GetTarget().shared_from_this();
+ else
+ m_target_sp.reset();
+ m_thread_sp.reset();
+ m_frame_sp.reset();
+}
+
+void
+ExecutionContext::SetContext (const lldb::ThreadSP &thread_sp)
+{
+ m_frame_sp.reset();
+ m_thread_sp = thread_sp;
+ if (thread_sp)
+ {
+ m_process_sp = thread_sp->GetProcess();
+ if (m_process_sp)
+ m_target_sp = m_process_sp->GetTarget().shared_from_this();
+ else
+ m_target_sp.reset();
+ }
+ else
+ {
+ m_target_sp.reset();
+ m_process_sp.reset();
+ }
+}
+
+void
+ExecutionContext::SetContext (const lldb::StackFrameSP &frame_sp)
+{
+ m_frame_sp = frame_sp;
+ if (frame_sp)
+ {
+ m_thread_sp = frame_sp->CalculateThread();
+ if (m_thread_sp)
+ {
+ m_process_sp = m_thread_sp->GetProcess();
+ if (m_process_sp)
+ m_target_sp = m_process_sp->GetTarget().shared_from_this();
+ else
+ m_target_sp.reset();
+ }
+ else
+ {
+ m_target_sp.reset();
+ m_process_sp.reset();
+ }
+ }
+ else
+ {
+ m_target_sp.reset();
+ m_process_sp.reset();
+ m_thread_sp.reset();
+ }
+}
+
+ExecutionContext &
+ExecutionContext::operator =(const ExecutionContext &rhs)
+{
+ if (this != &rhs)
+ {
+ m_target_sp = rhs.m_target_sp;
+ m_process_sp = rhs.m_process_sp;
+ m_thread_sp = rhs.m_thread_sp;
+ m_frame_sp = rhs.m_frame_sp;
+ }
+ return *this;
+}
+
+bool
+ExecutionContext::operator ==(const ExecutionContext &rhs) const
+{
+ // Check that the frame shared pointers match, or both are valid and their stack
+ // IDs match since sometimes we get new objects that represent the same
+ // frame within a thread.
+ if ((m_frame_sp == rhs.m_frame_sp) || (m_frame_sp && rhs.m_frame_sp && m_frame_sp->GetStackID() == rhs.m_frame_sp->GetStackID()))
+ {
+ // Check that the thread shared pointers match, or both are valid and
+ // their thread IDs match since sometimes we get new objects that
+ // represent the same thread within a process.
+ if ((m_thread_sp == rhs.m_thread_sp) || (m_thread_sp && rhs.m_thread_sp && m_thread_sp->GetID() == rhs.m_thread_sp->GetID()))
+ {
+ // Processes and targets don't change much
+ return m_process_sp == rhs.m_process_sp && m_target_sp == rhs.m_target_sp;
+ }
+ }
+ return false;
+}
+
+bool
+ExecutionContext::operator !=(const ExecutionContext &rhs) const
+{
+ return !(*this == rhs);
+}
+
+bool
+ExecutionContext::HasTargetScope () const
+{
+ return ((bool) m_target_sp
+ && m_target_sp->IsValid());
+}
+
+bool
+ExecutionContext::HasProcessScope () const
+{
+ return (HasTargetScope()
+ && ((bool) m_process_sp && m_process_sp->IsValid()));
+}
+
+bool
+ExecutionContext::HasThreadScope () const
+{
+ return (HasProcessScope()
+ && ((bool) m_thread_sp && m_thread_sp->IsValid()));
+}
+
+bool
+ExecutionContext::HasFrameScope () const
+{
+ return HasThreadScope() && m_frame_sp;
+}
+
+ExecutionContextRef::ExecutionContextRef() :
+ m_target_wp (),
+ m_process_wp (),
+ m_thread_wp (),
+ m_tid(LLDB_INVALID_THREAD_ID),
+ m_stack_id ()
+{
+}
+
+ExecutionContextRef::ExecutionContextRef (const ExecutionContext *exe_ctx) :
+ m_target_wp (),
+ m_process_wp (),
+ m_thread_wp (),
+ m_tid(LLDB_INVALID_THREAD_ID),
+ m_stack_id ()
+{
+ if (exe_ctx)
+ *this = *exe_ctx;
+}
+
+ExecutionContextRef::ExecutionContextRef (const ExecutionContext &exe_ctx) :
+ m_target_wp (),
+ m_process_wp (),
+ m_thread_wp (),
+ m_tid(LLDB_INVALID_THREAD_ID),
+ m_stack_id ()
+{
+ *this = exe_ctx;
+}
+
+
+ExecutionContextRef::ExecutionContextRef (Target *target, bool adopt_selected) :
+ m_target_wp(),
+ m_process_wp(),
+ m_thread_wp(),
+ m_tid(LLDB_INVALID_THREAD_ID),
+ m_stack_id ()
+{
+ SetTargetPtr (target, adopt_selected);
+}
+
+
+
+
+ExecutionContextRef::ExecutionContextRef (const ExecutionContextRef &rhs) :
+ m_target_wp (rhs.m_target_wp),
+ m_process_wp(rhs.m_process_wp),
+ m_thread_wp (rhs.m_thread_wp),
+ m_tid (rhs.m_tid),
+ m_stack_id (rhs.m_stack_id)
+{
+}
+
+ExecutionContextRef &
+ExecutionContextRef::operator =(const ExecutionContextRef &rhs)
+{
+ if (this != &rhs)
+ {
+ m_target_wp = rhs.m_target_wp;
+ m_process_wp = rhs.m_process_wp;
+ m_thread_wp = rhs.m_thread_wp;
+ m_tid = rhs.m_tid;
+ m_stack_id = rhs.m_stack_id;
+ }
+ return *this;
+}
+
+ExecutionContextRef &
+ExecutionContextRef::operator =(const ExecutionContext &exe_ctx)
+{
+ m_target_wp = exe_ctx.GetTargetSP();
+ m_process_wp = exe_ctx.GetProcessSP();
+ lldb::ThreadSP thread_sp (exe_ctx.GetThreadSP());
+ m_thread_wp = thread_sp;
+ if (thread_sp)
+ m_tid = thread_sp->GetID();
+ else
+ m_tid = LLDB_INVALID_THREAD_ID;
+ lldb::StackFrameSP frame_sp (exe_ctx.GetFrameSP());
+ if (frame_sp)
+ m_stack_id = frame_sp->GetStackID();
+ else
+ m_stack_id.Clear();
+ return *this;
+}
+
+void
+ExecutionContextRef::Clear()
+{
+ m_target_wp.reset();
+ m_process_wp.reset();
+ ClearThread();
+ ClearFrame();
+}
+
+ExecutionContextRef::~ExecutionContextRef()
+{
+}
+
+void
+ExecutionContextRef::SetTargetSP (const lldb::TargetSP &target_sp)
+{
+ m_target_wp = target_sp;
+}
+
+void
+ExecutionContextRef::SetProcessSP (const lldb::ProcessSP &process_sp)
+{
+ if (process_sp)
+ {
+ m_process_wp = process_sp;
+ SetTargetSP (process_sp->GetTarget().shared_from_this());
+ }
+ else
+ {
+ m_process_wp.reset();
+ m_target_wp.reset();
+ }
+}
+
+void
+ExecutionContextRef::SetThreadSP (const lldb::ThreadSP &thread_sp)
+{
+ if (thread_sp)
+ {
+ m_thread_wp = thread_sp;
+ m_tid = thread_sp->GetID();
+ SetProcessSP (thread_sp->GetProcess());
+ }
+ else
+ {
+ ClearThread();
+ m_process_wp.reset();
+ m_target_wp.reset();
+ }
+}
+
+void
+ExecutionContextRef::SetFrameSP (const lldb::StackFrameSP &frame_sp)
+{
+ if (frame_sp)
+ {
+ m_stack_id = frame_sp->GetStackID();
+ SetThreadSP (frame_sp->GetThread());
+ }
+ else
+ {
+ ClearFrame();
+ ClearThread();
+ m_process_wp.reset();
+ m_target_wp.reset();
+ }
+
+}
+
+void
+ExecutionContextRef::SetTargetPtr (Target* target, bool adopt_selected)
+{
+ Clear();
+ if (target)
+ {
+ lldb::TargetSP target_sp (target->shared_from_this());
+ if (target_sp)
+ {
+ m_target_wp = target_sp;
+ if (adopt_selected)
+ {
+ lldb::ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ m_process_wp = process_sp;
+ if (process_sp)
+ {
+ // Only fill in the thread and frame if our process is stopped
+ if (StateIsStoppedState (process_sp->GetState(), true))
+ {
+ lldb::ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread());
+ if (!thread_sp)
+ thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0);
+
+ if (thread_sp)
+ {
+ SetThreadSP (thread_sp);
+ lldb::StackFrameSP frame_sp (thread_sp->GetSelectedFrame());
+ if (!frame_sp)
+ frame_sp = thread_sp->GetStackFrameAtIndex(0);
+ if (frame_sp)
+ SetFrameSP (frame_sp);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+ExecutionContextRef::SetProcessPtr (Process *process)
+{
+ if (process)
+ {
+ SetProcessSP(process->shared_from_this());
+ }
+ else
+ {
+ m_process_wp.reset();
+ m_target_wp.reset();
+ }
+}
+
+void
+ExecutionContextRef::SetThreadPtr (Thread *thread)
+{
+ if (thread)
+ {
+ SetThreadSP (thread->shared_from_this());
+ }
+ else
+ {
+ ClearThread();
+ m_process_wp.reset();
+ m_target_wp.reset();
+ }
+}
+
+void
+ExecutionContextRef::SetFramePtr (StackFrame *frame)
+{
+ if (frame)
+ SetFrameSP (frame->shared_from_this());
+ else
+ Clear();
+}
+
+lldb::TargetSP
+ExecutionContextRef::GetTargetSP () const
+{
+ lldb::TargetSP target_sp(m_target_wp.lock());
+ if (target_sp && !target_sp->IsValid())
+ target_sp.reset();
+ return target_sp;
+}
+
+lldb::ProcessSP
+ExecutionContextRef::GetProcessSP () const
+{
+ lldb::ProcessSP process_sp(m_process_wp.lock());
+ if (process_sp && !process_sp->IsValid())
+ process_sp.reset();
+ return process_sp;
+}
+
+lldb::ThreadSP
+ExecutionContextRef::GetThreadSP () const
+{
+ lldb::ThreadSP thread_sp (m_thread_wp.lock());
+
+ if (m_tid != LLDB_INVALID_THREAD_ID)
+ {
+ // We check if the thread has been destroyed in cases where clients
+ // might still have shared pointer to a thread, but the thread is
+ // not valid anymore (not part of the process)
+ if (!thread_sp || !thread_sp->IsValid())
+ {
+ lldb::ProcessSP process_sp(GetProcessSP());
+ if (process_sp && process_sp->IsValid())
+ {
+ thread_sp = process_sp->GetThreadList().FindThreadByID(m_tid);
+ m_thread_wp = thread_sp;
+ }
+ }
+ }
+
+ // Check that we aren't about to return an invalid thread sp. We might return a NULL thread_sp,
+ // but don't return an invalid one.
+
+ if (thread_sp && !thread_sp->IsValid())
+ thread_sp.reset();
+
+ return thread_sp;
+}
+
+lldb::StackFrameSP
+ExecutionContextRef::GetFrameSP () const
+{
+ if (m_stack_id.IsValid())
+ {
+ lldb::ThreadSP thread_sp (GetThreadSP());
+ if (thread_sp)
+ return thread_sp->GetFrameWithStackID (m_stack_id);
+ }
+ return lldb::StackFrameSP();
+}
+
+ExecutionContext
+ExecutionContextRef::Lock () const
+{
+ return ExecutionContext(this);
+}
+
+
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
new file mode 100644
index 000000000000..d2f586ac82fb
--- /dev/null
+++ b/source/Target/LanguageRuntime.cpp
@@ -0,0 +1,343 @@
+//===-- LanguageRuntime.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/LanguageRuntime.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+class ExceptionSearchFilter : public SearchFilter
+{
+public:
+ ExceptionSearchFilter (const lldb::TargetSP &target_sp,
+ lldb::LanguageType language) :
+ SearchFilter (target_sp),
+ m_language (language),
+ m_language_runtime (NULL),
+ m_filter_sp ()
+ {
+ UpdateModuleListIfNeeded ();
+ }
+
+ virtual bool
+ ModulePasses (const lldb::ModuleSP &module_sp)
+ {
+ UpdateModuleListIfNeeded ();
+ if (m_filter_sp)
+ return m_filter_sp->ModulePasses (module_sp);
+ return false;
+ }
+
+ virtual bool
+ ModulePasses (const FileSpec &spec)
+ {
+ UpdateModuleListIfNeeded ();
+ if (m_filter_sp)
+ return m_filter_sp->ModulePasses (spec);
+ return false;
+
+ }
+
+ virtual void
+ Search (Searcher &searcher)
+ {
+ UpdateModuleListIfNeeded ();
+ if (m_filter_sp)
+ m_filter_sp->Search (searcher);
+ }
+
+ virtual void
+ GetDescription (Stream *s)
+ {
+ UpdateModuleListIfNeeded ();
+ if (m_filter_sp)
+ m_filter_sp->GetDescription (s);
+ }
+
+protected:
+ LanguageType m_language;
+ LanguageRuntime *m_language_runtime;
+ SearchFilterSP m_filter_sp;
+
+ void
+ UpdateModuleListIfNeeded ()
+ {
+ ProcessSP process_sp (m_target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ bool refreash_filter = !m_filter_sp;
+ if (m_language_runtime == NULL)
+ {
+ m_language_runtime = process_sp->GetLanguageRuntime(m_language);
+ refreash_filter = true;
+ }
+ else
+ {
+ LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language);
+ if (m_language_runtime != language_runtime)
+ {
+ m_language_runtime = language_runtime;
+ refreash_filter = true;
+ }
+ }
+
+ if (refreash_filter && m_language_runtime)
+ {
+ m_filter_sp = m_language_runtime->CreateExceptionSearchFilter ();
+ }
+ }
+ else
+ {
+ m_filter_sp.reset();
+ m_language_runtime = NULL;
+ }
+ }
+};
+
+// The Target is the one that knows how to create breakpoints, so this function
+// is meant to be used either by the target or internally in Set/ClearExceptionBreakpoints.
+class ExceptionBreakpointResolver : public BreakpointResolver
+{
+public:
+ ExceptionBreakpointResolver (lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp) :
+ BreakpointResolver (NULL, BreakpointResolver::ExceptionResolver),
+ m_language (language),
+ m_language_runtime (NULL),
+ m_catch_bp (catch_bp),
+ m_throw_bp (throw_bp)
+ {
+ }
+
+ virtual
+ ~ExceptionBreakpointResolver()
+ {
+ }
+
+ virtual Searcher::CallbackReturn
+ SearchCallback (SearchFilter &filter,
+ SymbolContext &context,
+ Address *addr,
+ bool containing)
+ {
+
+ if (SetActualResolver())
+ return m_actual_resolver_sp->SearchCallback (filter, context, addr, containing);
+ else
+ return eCallbackReturnStop;
+ }
+
+ virtual Searcher::Depth
+ GetDepth ()
+ {
+ if (SetActualResolver())
+ return m_actual_resolver_sp->GetDepth();
+ else
+ return eDepthTarget;
+ }
+
+ virtual void
+ GetDescription (Stream *s)
+ {
+ s->Printf ("Exception breakpoint (catch: %s throw: %s)",
+ m_catch_bp ? "on" : "off",
+ m_throw_bp ? "on" : "off");
+
+ SetActualResolver();
+ if (m_actual_resolver_sp)
+ {
+ s->Printf (" using: ");
+ m_actual_resolver_sp->GetDescription (s);
+ }
+ else
+ s->Printf (" the correct runtime exception handler will be determined when you run");
+ }
+
+ virtual void
+ Dump (Stream *s) const
+ {
+ }
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast:
+ static inline bool classof(const BreakpointResolverName *) { return true; }
+ static inline bool classof(const BreakpointResolver *V) {
+ return V->getResolverID() == BreakpointResolver::ExceptionResolver;
+ }
+protected:
+ bool
+ SetActualResolver()
+ {
+ ProcessSP process_sp;
+ if (m_breakpoint)
+ {
+ process_sp = m_breakpoint->GetTarget().GetProcessSP();
+ if (process_sp)
+ {
+ bool refreash_resolver = !m_actual_resolver_sp;
+ if (m_language_runtime == NULL)
+ {
+ m_language_runtime = process_sp->GetLanguageRuntime(m_language);
+ refreash_resolver = true;
+ }
+ else
+ {
+ LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language);
+ if (m_language_runtime != language_runtime)
+ {
+ m_language_runtime = language_runtime;
+ refreash_resolver = true;
+ }
+ }
+
+ if (refreash_resolver && m_language_runtime)
+ {
+ m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver (m_breakpoint, m_catch_bp, m_throw_bp);
+ }
+ }
+ else
+ {
+ m_actual_resolver_sp.reset();
+ m_language_runtime = NULL;
+ }
+ }
+ else
+ {
+ m_actual_resolver_sp.reset();
+ m_language_runtime = NULL;
+ }
+ return (bool)m_actual_resolver_sp;
+ }
+ lldb::BreakpointResolverSP m_actual_resolver_sp;
+ lldb::LanguageType m_language;
+ LanguageRuntime *m_language_runtime;
+ bool m_catch_bp;
+ bool m_throw_bp;
+};
+
+
+LanguageRuntime*
+LanguageRuntime::FindPlugin (Process *process, lldb::LanguageType language)
+{
+ std::unique_ptr<LanguageRuntime> language_runtime_ap;
+ LanguageRuntimeCreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != NULL;
+ ++idx)
+ {
+ language_runtime_ap.reset (create_callback(process, language));
+
+ if (language_runtime_ap.get())
+ return language_runtime_ap.release();
+ }
+
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+LanguageRuntime::LanguageRuntime(Process *process) :
+ m_process (process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+LanguageRuntime::~LanguageRuntime()
+{
+}
+
+BreakpointSP
+LanguageRuntime::CreateExceptionBreakpoint (Target &target,
+ lldb::LanguageType language,
+ bool catch_bp,
+ bool throw_bp,
+ bool is_internal)
+{
+ BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
+ SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language));
+
+ BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal));
+ if (is_internal)
+ exc_breakpt_sp->SetBreakpointKind("exception");
+
+ return exc_breakpt_sp;
+}
+
+struct language_name_pair {
+ const char *name;
+ LanguageType type;
+};
+
+struct language_name_pair language_names[] =
+{
+ // To allow GetNameForLanguageType to be a simple array lookup, the first
+ // part of this array must follow enum LanguageType exactly.
+ { "unknown", eLanguageTypeUnknown },
+ { "c89", eLanguageTypeC89 },
+ { "c", eLanguageTypeC },
+ { "ada83", eLanguageTypeAda83 },
+ { "c++", eLanguageTypeC_plus_plus },
+ { "cobol74", eLanguageTypeCobol74 },
+ { "cobol85", eLanguageTypeCobol85 },
+ { "fortran77", eLanguageTypeFortran77 },
+ { "fortran90", eLanguageTypeFortran90 },
+ { "pascal83", eLanguageTypePascal83 },
+ { "modula2", eLanguageTypeModula2 },
+ { "java", eLanguageTypeJava },
+ { "c99", eLanguageTypeC99 },
+ { "ada95", eLanguageTypeAda95 },
+ { "fortran95", eLanguageTypeFortran95 },
+ { "pli", eLanguageTypePLI },
+ { "objective-c", eLanguageTypeObjC },
+ { "objective-c++", eLanguageTypeObjC_plus_plus },
+ { "upc", eLanguageTypeUPC },
+ { "d", eLanguageTypeD },
+ { "python", eLanguageTypePython },
+ // Now synonyms, in arbitrary order
+ { "objc", eLanguageTypeObjC },
+ { "objc++", eLanguageTypeObjC_plus_plus }
+};
+
+static uint32_t num_languages = sizeof(language_names) / sizeof (struct language_name_pair);
+
+LanguageType
+LanguageRuntime::GetLanguageTypeFromString (const char *string)
+{
+ for (uint32_t i = 0; i < num_languages; i++)
+ {
+ if (strcasecmp (language_names[i].name, string) == 0)
+ return (LanguageType) language_names[i].type;
+ }
+ return eLanguageTypeUnknown;
+}
+
+const char *
+LanguageRuntime::GetNameForLanguageType (LanguageType language)
+{
+ if (language < num_languages)
+ return language_names[language].name;
+ else
+ return language_names[eLanguageTypeUnknown].name;
+}
+
+lldb::SearchFilterSP
+LanguageRuntime::CreateExceptionSearchFilter ()
+{
+ return m_process->GetTarget().GetSearchFilterForModule(NULL);
+}
+
+
+
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
new file mode 100644
index 000000000000..3c8d483f3003
--- /dev/null
+++ b/source/Target/Memory.cpp
@@ -0,0 +1,461 @@
+//===-- Memory.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/Memory.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// MemoryCache constructor
+//----------------------------------------------------------------------
+MemoryCache::MemoryCache(Process &process) :
+ m_process (process),
+ m_cache_line_byte_size (512),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_cache (),
+ m_invalid_ranges ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+MemoryCache::~MemoryCache()
+{
+}
+
+void
+MemoryCache::Clear(bool clear_invalid_ranges)
+{
+ Mutex::Locker locker (m_mutex);
+ m_cache.clear();
+ if (clear_invalid_ranges)
+ m_invalid_ranges.Clear();
+}
+
+void
+MemoryCache::Flush (addr_t addr, size_t size)
+{
+ if (size == 0)
+ return;
+
+ Mutex::Locker locker (m_mutex);
+ if (m_cache.empty())
+ return;
+
+ const uint32_t cache_line_byte_size = m_cache_line_byte_size;
+ const addr_t end_addr = (addr + size - 1);
+ const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size);
+ const addr_t last_cache_line_addr = end_addr - (end_addr % cache_line_byte_size);
+ // Watch for overflow where size will cause us to go off the end of the
+ // 64 bit address space
+ uint32_t num_cache_lines;
+ if (last_cache_line_addr >= first_cache_line_addr)
+ num_cache_lines = ((last_cache_line_addr - first_cache_line_addr)/cache_line_byte_size) + 1;
+ else
+ num_cache_lines = (UINT64_MAX - first_cache_line_addr + 1)/cache_line_byte_size;
+
+ uint32_t cache_idx = 0;
+ for (addr_t curr_addr = first_cache_line_addr;
+ cache_idx < num_cache_lines;
+ curr_addr += cache_line_byte_size, ++cache_idx)
+ {
+ BlockMap::iterator pos = m_cache.find (curr_addr);
+ if (pos != m_cache.end())
+ m_cache.erase(pos);
+ }
+}
+
+void
+MemoryCache::AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
+{
+ if (byte_size > 0)
+ {
+ Mutex::Locker locker (m_mutex);
+ InvalidRanges::Entry range (base_addr, byte_size);
+ m_invalid_ranges.Append(range);
+ m_invalid_ranges.Sort();
+ }
+}
+
+bool
+MemoryCache::RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size)
+{
+ if (byte_size > 0)
+ {
+ Mutex::Locker locker (m_mutex);
+ const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr);
+ if (idx != UINT32_MAX)
+ {
+ const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex (idx);
+ if (entry->GetRangeBase() == base_addr && entry->GetByteSize() == byte_size)
+ return m_invalid_ranges.RemoveEntrtAtIndex (idx);
+ }
+ }
+ return false;
+}
+
+
+
+size_t
+MemoryCache::Read (addr_t addr,
+ void *dst,
+ size_t dst_len,
+ Error &error)
+{
+ size_t bytes_left = dst_len;
+ if (dst && bytes_left > 0)
+ {
+ const uint32_t cache_line_byte_size = m_cache_line_byte_size;
+ uint8_t *dst_buf = (uint8_t *)dst;
+ addr_t curr_addr = addr - (addr % cache_line_byte_size);
+ addr_t cache_offset = addr - curr_addr;
+ Mutex::Locker locker (m_mutex);
+
+ while (bytes_left > 0)
+ {
+ if (m_invalid_ranges.FindEntryThatContains(curr_addr))
+ {
+ error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, curr_addr);
+ return dst_len - bytes_left;
+ }
+
+ BlockMap::const_iterator pos = m_cache.find (curr_addr);
+ BlockMap::const_iterator end = m_cache.end ();
+
+ if (pos != end)
+ {
+ size_t curr_read_size = cache_line_byte_size - cache_offset;
+ if (curr_read_size > bytes_left)
+ curr_read_size = bytes_left;
+
+ memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes() + cache_offset, curr_read_size);
+
+ bytes_left -= curr_read_size;
+ curr_addr += curr_read_size + cache_offset;
+ cache_offset = 0;
+
+ if (bytes_left > 0)
+ {
+ // Get sequential cache page hits
+ for (++pos; (pos != end) && (bytes_left > 0); ++pos)
+ {
+ assert ((curr_addr % cache_line_byte_size) == 0);
+
+ if (pos->first != curr_addr)
+ break;
+
+ curr_read_size = pos->second->GetByteSize();
+ if (curr_read_size > bytes_left)
+ curr_read_size = bytes_left;
+
+ memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes(), curr_read_size);
+
+ bytes_left -= curr_read_size;
+ curr_addr += curr_read_size;
+
+ // We have a cache page that succeeded to read some bytes
+ // but not an entire page. If this happens, we must cap
+ // off how much data we are able to read...
+ if (pos->second->GetByteSize() != cache_line_byte_size)
+ return dst_len - bytes_left;
+ }
+ }
+ }
+
+ // We need to read from the process
+
+ if (bytes_left > 0)
+ {
+ assert ((curr_addr % cache_line_byte_size) == 0);
+ std::unique_ptr<DataBufferHeap> data_buffer_heap_ap(new DataBufferHeap (cache_line_byte_size, 0));
+ size_t process_bytes_read = m_process.ReadMemoryFromInferior (curr_addr,
+ data_buffer_heap_ap->GetBytes(),
+ data_buffer_heap_ap->GetByteSize(),
+ error);
+ if (process_bytes_read == 0)
+ return dst_len - bytes_left;
+
+ if (process_bytes_read != cache_line_byte_size)
+ data_buffer_heap_ap->SetByteSize (process_bytes_read);
+ m_cache[curr_addr] = DataBufferSP (data_buffer_heap_ap.release());
+ // We have read data and put it into the cache, continue through the
+ // loop again to get the data out of the cache...
+ }
+ }
+ }
+
+ return dst_len - bytes_left;
+}
+
+
+
+AllocatedBlock::AllocatedBlock (lldb::addr_t addr,
+ uint32_t byte_size,
+ uint32_t permissions,
+ uint32_t chunk_size) :
+ m_addr (addr),
+ m_byte_size (byte_size),
+ m_permissions (permissions),
+ m_chunk_size (chunk_size),
+ m_offset_to_chunk_size ()
+// m_allocated (byte_size / chunk_size)
+{
+ assert (byte_size > chunk_size);
+}
+
+AllocatedBlock::~AllocatedBlock ()
+{
+}
+
+lldb::addr_t
+AllocatedBlock::ReserveBlock (uint32_t size)
+{
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ if (size <= m_byte_size)
+ {
+ const uint32_t needed_chunks = CalculateChunksNeededForSize (size);
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
+
+ if (m_offset_to_chunk_size.empty())
+ {
+ m_offset_to_chunk_size[0] = needed_chunks;
+ if (log)
+ log->Printf ("[1] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, 0, needed_chunks, m_chunk_size);
+ addr = m_addr;
+ }
+ else
+ {
+ uint32_t last_offset = 0;
+ OffsetToChunkSize::const_iterator pos = m_offset_to_chunk_size.begin();
+ OffsetToChunkSize::const_iterator end = m_offset_to_chunk_size.end();
+ while (pos != end)
+ {
+ if (pos->first > last_offset)
+ {
+ const uint32_t bytes_available = pos->first - last_offset;
+ const uint32_t num_chunks = CalculateChunksNeededForSize (bytes_available);
+ if (num_chunks >= needed_chunks)
+ {
+ m_offset_to_chunk_size[last_offset] = needed_chunks;
+ if (log)
+ log->Printf ("[2] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ addr = m_addr + last_offset;
+ break;
+ }
+ }
+
+ last_offset = pos->first + pos->second * m_chunk_size;
+
+ if (++pos == end)
+ {
+ // Last entry...
+ const uint32_t chunks_left = CalculateChunksNeededForSize (m_byte_size - last_offset);
+ if (chunks_left >= needed_chunks)
+ {
+ m_offset_to_chunk_size[last_offset] = needed_chunks;
+ if (log)
+ log->Printf ("[3] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ addr = m_addr + last_offset;
+ break;
+ }
+ }
+ }
+ }
+// const uint32_t total_chunks = m_allocated.size ();
+// uint32_t unallocated_idx = 0;
+// uint32_t allocated_idx = m_allocated.find_first();
+// uint32_t first_chunk_idx = UINT32_MAX;
+// uint32_t num_chunks;
+// while (1)
+// {
+// if (allocated_idx == UINT32_MAX)
+// {
+// // No more bits are set starting from unallocated_idx, so we
+// // either have enough chunks for the request, or we don't.
+// // Eiter way we break out of the while loop...
+// num_chunks = total_chunks - unallocated_idx;
+// if (needed_chunks <= num_chunks)
+// first_chunk_idx = unallocated_idx;
+// break;
+// }
+// else if (allocated_idx > unallocated_idx)
+// {
+// // We have some allocated chunks, check if there are enough
+// // free chunks to satisfy the request?
+// num_chunks = allocated_idx - unallocated_idx;
+// if (needed_chunks <= num_chunks)
+// {
+// // Yep, we have enough!
+// first_chunk_idx = unallocated_idx;
+// break;
+// }
+// }
+//
+// while (unallocated_idx < total_chunks)
+// {
+// if (m_allocated[unallocated_idx])
+// ++unallocated_idx;
+// else
+// break;
+// }
+//
+// if (unallocated_idx >= total_chunks)
+// break;
+//
+// allocated_idx = m_allocated.find_next(unallocated_idx);
+// }
+//
+// if (first_chunk_idx != UINT32_MAX)
+// {
+// const uint32_t end_bit_idx = unallocated_idx + needed_chunks;
+// for (uint32_t idx = first_chunk_idx; idx < end_bit_idx; ++idx)
+// m_allocated.set(idx);
+// return m_addr + m_chunk_size * first_chunk_idx;
+// }
+ }
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
+ if (log)
+ log->Printf ("AllocatedBlock::ReserveBlock (size = %u (0x%x)) => 0x%16.16" PRIx64, size, size, (uint64_t)addr);
+ return addr;
+}
+
+bool
+AllocatedBlock::FreeBlock (addr_t addr)
+{
+ uint32_t offset = addr - m_addr;
+ OffsetToChunkSize::iterator pos = m_offset_to_chunk_size.find (offset);
+ bool success = false;
+ if (pos != m_offset_to_chunk_size.end())
+ {
+ m_offset_to_chunk_size.erase (pos);
+ success = true;
+ }
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
+ if (log)
+ log->Printf ("AllocatedBlock::FreeBlock (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success);
+ return success;
+}
+
+
+AllocatedMemoryCache::AllocatedMemoryCache (Process &process) :
+ m_process (process),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_memory_map()
+{
+}
+
+AllocatedMemoryCache::~AllocatedMemoryCache ()
+{
+}
+
+
+void
+AllocatedMemoryCache::Clear()
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_process.IsAlive())
+ {
+ PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
+ for (pos = m_memory_map.begin(); pos != end; ++pos)
+ m_process.DoDeallocateMemory(pos->second->GetBaseAddress());
+ }
+ m_memory_map.clear();
+}
+
+
+AllocatedMemoryCache::AllocatedBlockSP
+AllocatedMemoryCache::AllocatePage (uint32_t byte_size,
+ uint32_t permissions,
+ uint32_t chunk_size,
+ Error &error)
+{
+ AllocatedBlockSP block_sp;
+ const size_t page_size = 4096;
+ const size_t num_pages = (byte_size + page_size - 1) / page_size;
+ const size_t page_byte_size = num_pages * page_size;
+
+ addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error);
+
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ {
+ log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64,
+ page_byte_size,
+ GetPermissionsAsCString(permissions),
+ (uint64_t)addr);
+ }
+
+ if (addr != LLDB_INVALID_ADDRESS)
+ {
+ block_sp.reset (new AllocatedBlock (addr, page_byte_size, permissions, chunk_size));
+ m_memory_map.insert (std::make_pair (permissions, block_sp));
+ }
+ return block_sp;
+}
+
+lldb::addr_t
+AllocatedMemoryCache::AllocateMemory (size_t byte_size,
+ uint32_t permissions,
+ Error &error)
+{
+ Mutex::Locker locker (m_mutex);
+
+ addr_t addr = LLDB_INVALID_ADDRESS;
+ std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator> range = m_memory_map.equal_range (permissions);
+
+ for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; ++pos)
+ {
+ addr = (*pos).second->ReserveBlock (byte_size);
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ {
+ AllocatedBlockSP block_sp (AllocatePage (byte_size, permissions, 16, error));
+
+ if (block_sp)
+ addr = block_sp->ReserveBlock (byte_size);
+ }
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64, byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);
+ return addr;
+}
+
+bool
+AllocatedMemoryCache::DeallocateMemory (lldb::addr_t addr)
+{
+ Mutex::Locker locker (m_mutex);
+
+ PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
+ bool success = false;
+ for (pos = m_memory_map.begin(); pos != end; ++pos)
+ {
+ if (pos->second->Contains (addr))
+ {
+ success = pos->second->FreeBlock (addr);
+ break;
+ }
+ }
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success);
+ return success;
+}
+
+
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
new file mode 100644
index 000000000000..64ddfcc6c796
--- /dev/null
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -0,0 +1,605 @@
+//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/Type.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/MappedHash.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Target.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ObjCLanguageRuntime::~ObjCLanguageRuntime()
+{
+}
+
+ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) :
+ LanguageRuntime (process),
+ m_has_new_literals_and_indexing (eLazyBoolCalculate),
+ m_isa_to_descriptor(),
+ m_isa_to_descriptor_stop_id (UINT32_MAX)
+{
+
+}
+
+bool
+ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name)
+{
+ if (isa != 0)
+ {
+ m_isa_to_descriptor[isa] = descriptor_sp;
+ // class_name is assumed to be valid
+ m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
+ return true;
+ }
+ return false;
+}
+
+void
+ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr);
+ }
+ m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr));
+}
+
+lldb::addr_t
+ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector)
+{
+ MsgImplMap::iterator pos, end = m_impl_cache.end();
+ pos = m_impl_cache.find (ClassAndSel(class_addr, selector));
+ if (pos != end)
+ return (*pos).second;
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+lldb::TypeSP
+ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
+{
+ CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name);
+
+ if (complete_class_iter != m_complete_class_cache.end())
+ {
+ // Check the weak pointer to make sure the type hasn't been unloaded
+ TypeSP complete_type_sp (complete_class_iter->second.lock());
+
+ if (complete_type_sp)
+ return complete_type_sp;
+ else
+ m_complete_class_cache.erase(name);
+ }
+
+ if (m_negative_complete_class_cache.count(name) > 0)
+ return TypeSP();
+
+ const ModuleList &modules = m_process->GetTarget().GetImages();
+
+ SymbolContextList sc_list;
+ const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name,
+ eSymbolTypeObjCClass,
+ sc_list);
+
+ if (matching_symbols)
+ {
+ SymbolContext sc;
+
+ sc_list.GetContextAtIndex(0, sc);
+
+ ModuleSP module_sp(sc.module_sp);
+
+ if (!module_sp)
+ return TypeSP();
+
+ const SymbolContext null_sc;
+ const bool exact_match = true;
+ const uint32_t max_matches = UINT32_MAX;
+ TypeList types;
+
+ const uint32_t num_types = module_sp->FindTypes (null_sc,
+ name,
+ exact_match,
+ max_matches,
+ types);
+
+ if (num_types)
+ {
+ uint32_t i;
+ for (i = 0; i < num_types; ++i)
+ {
+ TypeSP type_sp (types.GetTypeAtIndex(i));
+
+ if (type_sp->GetClangForwardType().IsObjCObjectOrInterfaceType())
+ {
+ if (type_sp->IsCompleteObjCClass())
+ {
+ m_complete_class_cache[name] = type_sp;
+ return type_sp;
+ }
+ }
+ }
+ }
+ }
+ m_negative_complete_class_cache.insert(name);
+ return TypeSP();
+}
+
+size_t
+ObjCLanguageRuntime::GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name)
+{
+ return LLDB_INVALID_IVAR_OFFSET;
+}
+
+void
+ObjCLanguageRuntime::MethodName::Clear()
+{
+ m_full.Clear();
+ m_class.Clear();
+ m_category.Clear();
+ m_selector.Clear();
+ m_type = eTypeUnspecified;
+ m_category_is_valid = false;
+}
+
+//bool
+//ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
+//{
+// Clear();
+// if (name && name[0])
+// {
+// // If "strict" is true. then the method must be specified with a
+// // '+' or '-' at the beginning. If "strict" is false, then the '+'
+// // or '-' can be omitted
+// bool valid_prefix = false;
+//
+// if (name[0] == '+' || name[0] == '-')
+// {
+// valid_prefix = name[1] == '[';
+// }
+// else if (!strict)
+// {
+// // "strict" is false, the name just needs to start with '['
+// valid_prefix = name[0] == '[';
+// }
+//
+// if (valid_prefix)
+// {
+// static RegularExpression g_regex("^([-+]?)\\[([A-Za-z_][A-Za-z_0-9]*)(\\([A-Za-z_][A-Za-z_0-9]*\\))? ([A-Za-z_][A-Za-z_0-9:]*)\\]$");
+// llvm::StringRef matches[4];
+// // Since we are using a global regular expression, we must use the threadsafe version of execute
+// if (g_regex.ExecuteThreadSafe(name, matches, 4))
+// {
+// m_full.SetCString(name);
+// if (matches[0].empty())
+// m_type = eTypeUnspecified;
+// else if (matches[0][0] == '+')
+// m_type = eTypeClassMethod;
+// else
+// m_type = eTypeInstanceMethod;
+// m_class.SetString(matches[1]);
+// m_selector.SetString(matches[3]);
+// if (!matches[2].empty())
+// m_category.SetString(matches[2]);
+// }
+// }
+// }
+// return IsValid(strict);
+//}
+
+bool
+ObjCLanguageRuntime::MethodName::SetName (const char *name, bool strict)
+{
+ Clear();
+ if (name && name[0])
+ {
+ // If "strict" is true. then the method must be specified with a
+ // '+' or '-' at the beginning. If "strict" is false, then the '+'
+ // or '-' can be omitted
+ bool valid_prefix = false;
+
+ if (name[0] == '+' || name[0] == '-')
+ {
+ valid_prefix = name[1] == '[';
+ if (name[0] == '+')
+ m_type = eTypeClassMethod;
+ else
+ m_type = eTypeInstanceMethod;
+ }
+ else if (!strict)
+ {
+ // "strict" is false, the name just needs to start with '['
+ valid_prefix = name[0] == '[';
+ }
+
+ if (valid_prefix)
+ {
+ int name_len = strlen (name);
+ // Objective C methods must have at least:
+ // "-[" or "+[" prefix
+ // One character for a class name
+ // One character for the space between the class name
+ // One character for the method name
+ // "]" suffix
+ if (name_len >= (5 + (strict ? 1 : 0)) && name[name_len - 1] == ']')
+ {
+ m_full.SetCStringWithLength(name, name_len);
+ }
+ }
+ }
+ return IsValid(strict);
+}
+
+const ConstString &
+ObjCLanguageRuntime::MethodName::GetClassName ()
+{
+ if (!m_class)
+ {
+ if (IsValid(false))
+ {
+ const char *full = m_full.GetCString();
+ const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
+ const char *paren_pos = strchr (class_start, '(');
+ if (paren_pos)
+ {
+ m_class.SetCStringWithLength (class_start, paren_pos - class_start);
+ }
+ else
+ {
+ // No '(' was found in the full name, we can definitively say
+ // that our category was valid (and empty).
+ m_category_is_valid = true;
+ const char *space_pos = strchr (full, ' ');
+ if (space_pos)
+ {
+ m_class.SetCStringWithLength (class_start, space_pos - class_start);
+ if (!m_class_category)
+ {
+ // No category in name, so we can also fill in the m_class_category
+ m_class_category = m_class;
+ }
+ }
+ }
+ }
+ }
+ return m_class;
+}
+
+const ConstString &
+ObjCLanguageRuntime::MethodName::GetClassNameWithCategory ()
+{
+ if (!m_class_category)
+ {
+ if (IsValid(false))
+ {
+ const char *full = m_full.GetCString();
+ const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
+ const char *space_pos = strchr (full, ' ');
+ if (space_pos)
+ {
+ m_class_category.SetCStringWithLength (class_start, space_pos - class_start);
+ // If m_class hasn't been filled in and the class with category doesn't
+ // contain a '(', then we can also fill in the m_class
+ if (!m_class && strchr (m_class_category.GetCString(), '(') == NULL)
+ {
+ m_class = m_class_category;
+ // No '(' was found in the full name, we can definitively say
+ // that our category was valid (and empty).
+ m_category_is_valid = true;
+
+ }
+ }
+ }
+ }
+ return m_class_category;
+}
+
+const ConstString &
+ObjCLanguageRuntime::MethodName::GetSelector ()
+{
+ if (!m_selector)
+ {
+ if (IsValid(false))
+ {
+ const char *full = m_full.GetCString();
+ const char *space_pos = strchr (full, ' ');
+ if (space_pos)
+ {
+ ++space_pos; // skip the space
+ m_selector.SetCStringWithLength (space_pos, m_full.GetLength() - (space_pos - full) - 1);
+ }
+ }
+ }
+ return m_selector;
+}
+
+const ConstString &
+ObjCLanguageRuntime::MethodName::GetCategory ()
+{
+ if (!m_category_is_valid && !m_category)
+ {
+ if (IsValid(false))
+ {
+ m_category_is_valid = true;
+ const char *full = m_full.GetCString();
+ const char *class_start = (full[0] == '[' ? full + 1 : full + 2);
+ const char *open_paren_pos = strchr (class_start, '(');
+ if (open_paren_pos)
+ {
+ ++open_paren_pos; // Skip the open paren
+ const char *close_paren_pos = strchr (open_paren_pos, ')');
+ if (close_paren_pos)
+ m_category.SetCStringWithLength (open_paren_pos, close_paren_pos - open_paren_pos);
+ }
+ }
+ }
+ return m_category;
+}
+
+ConstString
+ObjCLanguageRuntime::MethodName::GetFullNameWithoutCategory (bool empty_if_no_category)
+{
+ if (IsValid(false))
+ {
+ if (HasCategory())
+ {
+ StreamString strm;
+ if (m_type == eTypeClassMethod)
+ strm.PutChar('+');
+ else if (m_type == eTypeInstanceMethod)
+ strm.PutChar('-');
+ strm.Printf("[%s %s]", GetClassName().GetCString(), GetSelector().GetCString());
+ return ConstString(strm.GetString().c_str());
+ }
+
+ if (!empty_if_no_category)
+ {
+ // Just return the full name since it doesn't have a category
+ return GetFullName();
+ }
+ }
+ return ConstString();
+}
+
+size_t
+ObjCLanguageRuntime::MethodName::GetFullNames (std::vector<ConstString> &names, bool append)
+{
+ if (!append)
+ names.clear();
+ if (IsValid(false))
+ {
+ StreamString strm;
+ const bool is_class_method = m_type == eTypeClassMethod;
+ const bool is_instance_method = m_type == eTypeInstanceMethod;
+ const ConstString &category = GetCategory();
+ if (is_class_method || is_instance_method)
+ {
+ names.push_back (m_full);
+ if (category)
+ {
+ strm.Printf("%c[%s %s]",
+ is_class_method ? '+' : '-',
+ GetClassName().GetCString(),
+ GetSelector().GetCString());
+ names.push_back(ConstString(strm.GetString().c_str()));
+ }
+ }
+ else
+ {
+ const ConstString &class_name = GetClassName();
+ const ConstString &selector = GetSelector();
+ strm.Printf("+[%s %s]", class_name.GetCString(), selector.GetCString());
+ names.push_back(ConstString(strm.GetString().c_str()));
+ strm.Clear();
+ strm.Printf("-[%s %s]", class_name.GetCString(), selector.GetCString());
+ names.push_back(ConstString(strm.GetString().c_str()));
+ strm.Clear();
+ if (category)
+ {
+ strm.Printf("+[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
+ names.push_back(ConstString(strm.GetString().c_str()));
+ strm.Clear();
+ strm.Printf("-[%s(%s) %s]", class_name.GetCString(), category.GetCString(), selector.GetCString());
+ names.push_back(ConstString(strm.GetString().c_str()));
+ }
+ }
+ }
+ return names.size();
+}
+
+
+bool
+ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value,
+ uint32_t ptr_size,
+ bool allow_NULLs,
+ bool allow_tagged,
+ bool check_version_specific) const
+{
+ if (!value)
+ return allow_NULLs;
+ if ( (value % 2) == 1 && allow_tagged)
+ return true;
+ if ((value % ptr_size) == 0)
+ return (check_version_specific ? CheckPointer(value,ptr_size) : true);
+ else
+ return false;
+}
+
+ObjCLanguageRuntime::ObjCISA
+ObjCLanguageRuntime::GetISA(const ConstString &name)
+{
+ ISAToDescriptorIterator pos = GetDescriptorIterator (name);
+ if (pos != m_isa_to_descriptor.end())
+ return pos->first;
+ return 0;
+}
+
+ObjCLanguageRuntime::ISAToDescriptorIterator
+ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name)
+{
+ ISAToDescriptorIterator end = m_isa_to_descriptor.end();
+
+ if (name)
+ {
+ UpdateISAToDescriptorMap();
+ if (m_hash_to_isa_map.empty())
+ {
+ // No name hashes were provided, we need to just linearly power through the
+ // names and find a match
+ for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos)
+ {
+ if (pos->second->GetClassName() == name)
+ return pos;
+ }
+ }
+ else
+ {
+ // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor
+ const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString());
+ std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash);
+ for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos)
+ {
+ ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second);
+ if (pos != m_isa_to_descriptor.end())
+ {
+ if (pos->second->GetClassName() == name)
+ return pos;
+ }
+ }
+ }
+ }
+ return end;
+}
+
+
+ObjCLanguageRuntime::ObjCISA
+ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa)
+{
+ ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa));
+ if (objc_class_sp)
+ {
+ ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass());
+ if (objc_super_class_sp)
+ return objc_super_class_sp->GetISA();
+ }
+ return 0;
+}
+
+ConstString
+ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
+{
+ ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa));
+ if (objc_class_sp)
+ return objc_class_sp->GetClassName();
+ return ConstString();
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name)
+{
+ ISAToDescriptorIterator pos = GetDescriptorIterator (class_name);
+ if (pos != m_isa_to_descriptor.end())
+ return pos->second;
+ return ClassDescriptorSP();
+
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj)
+{
+ ClassDescriptorSP objc_class_sp;
+ // if we get an invalid VO (which might still happen when playing around
+ // with pointers returned by the expression parser, don't consider this
+ // a valid ObjC object)
+ if (valobj.GetClangType().IsValid())
+ {
+ addr_t isa_pointer = valobj.GetPointerValue();
+ if (isa_pointer != LLDB_INVALID_ADDRESS)
+ {
+ ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process)
+ {
+ Error error;
+ ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
+ if (isa != LLDB_INVALID_ADDRESS)
+ objc_class_sp = GetClassDescriptorFromISA (isa);
+ }
+ }
+ }
+ return objc_class_sp;
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj)
+{
+ ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj));
+ if (objc_class_sp)
+ {
+ if (!objc_class_sp->IsKVO())
+ return objc_class_sp;
+
+ ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
+ if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
+ return non_kvo_objc_class_sp;
+ }
+ return ClassDescriptorSP();
+}
+
+
+ObjCLanguageRuntime::ClassDescriptorSP
+ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa)
+{
+ if (isa)
+ {
+ UpdateISAToDescriptorMap();
+ ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa);
+ if (pos != m_isa_to_descriptor.end())
+ return pos->second;
+ }
+ return ClassDescriptorSP();
+}
+
+ObjCLanguageRuntime::ClassDescriptorSP
+ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
+{
+ if (isa)
+ {
+ ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa);
+ if (objc_class_sp && objc_class_sp->IsValid())
+ {
+ if (!objc_class_sp->IsKVO())
+ return objc_class_sp;
+
+ ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
+ if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
+ return non_kvo_objc_class_sp;
+ }
+ }
+ return ClassDescriptorSP();
+}
+
+
+
diff --git a/source/Target/OperatingSystem.cpp b/source/Target/OperatingSystem.cpp
new file mode 100644
index 000000000000..8ba526838777
--- /dev/null
+++ b/source/Target/OperatingSystem.cpp
@@ -0,0 +1,67 @@
+//===-- OperatingSystem.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/OperatingSystem.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+OperatingSystem*
+OperatingSystem::FindPlugin (Process *process, const char *plugin_name)
+{
+ OperatingSystemCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ ConstString const_plugin_name(plugin_name);
+ create_callback = PluginManager::GetOperatingSystemCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ std::unique_ptr<OperatingSystem> instance_ap(create_callback(process, true));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetOperatingSystemCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ std::unique_ptr<OperatingSystem> instance_ap(create_callback(process, false));
+ if (instance_ap.get())
+ return instance_ap.release();
+ }
+ }
+ return NULL;
+}
+
+
+OperatingSystem::OperatingSystem (Process *process) :
+ m_process (process)
+{
+}
+
+OperatingSystem::~OperatingSystem()
+{
+}
+
+
+bool
+OperatingSystem::IsOperatingSystemPluginThread (const lldb::ThreadSP &thread_sp)
+{
+ if (thread_sp)
+ return thread_sp->IsOperatingSystemPluginThread();
+ return false;
+}
+
diff --git a/source/Target/PathMappingList.cpp b/source/Target/PathMappingList.cpp
new file mode 100644
index 000000000000..db23a0b27130
--- /dev/null
+++ b/source/Target/PathMappingList.cpp
@@ -0,0 +1,348 @@
+//===-- PathMappingList.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <limits.h>
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Target/PathMappingList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// PathMappingList constructor
+//----------------------------------------------------------------------
+PathMappingList::PathMappingList () :
+ m_pairs (),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_mod_id (0)
+{
+}
+
+PathMappingList::PathMappingList (ChangedCallback callback,
+ void *callback_baton) :
+ m_pairs (),
+ m_callback (callback),
+ m_callback_baton (callback_baton),
+ m_mod_id (0)
+{
+}
+
+
+PathMappingList::PathMappingList (const PathMappingList &rhs) :
+ m_pairs (rhs.m_pairs),
+ m_callback (NULL),
+ m_callback_baton (NULL),
+ m_mod_id (0)
+{
+
+}
+
+const PathMappingList &
+PathMappingList::operator =(const PathMappingList &rhs)
+{
+ if (this != &rhs)
+ {
+ m_pairs = rhs.m_pairs;
+ m_callback = NULL;
+ m_callback_baton = NULL;
+ m_mod_id = rhs.m_mod_id;
+ }
+ return *this;
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+PathMappingList::~PathMappingList ()
+{
+}
+
+void
+PathMappingList::Append (const ConstString &path,
+ const ConstString &replacement,
+ bool notify)
+{
+ ++m_mod_id;
+ m_pairs.push_back(pair(path, replacement));
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+void
+PathMappingList::Append (const PathMappingList &rhs, bool notify)
+{
+ ++m_mod_id;
+ if (!rhs.m_pairs.empty())
+ {
+ const_iterator pos, end = rhs.m_pairs.end();
+ for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
+ m_pairs.push_back(*pos);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ }
+}
+
+void
+PathMappingList::Insert (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t index,
+ bool notify)
+{
+ ++m_mod_id;
+ iterator insert_iter;
+ if (index >= m_pairs.size())
+ insert_iter = m_pairs.end();
+ else
+ insert_iter = m_pairs.begin() + index;
+ m_pairs.insert(insert_iter, pair(path, replacement));
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+bool
+PathMappingList::Replace (const ConstString &path,
+ const ConstString &replacement,
+ uint32_t index,
+ bool notify)
+{
+ iterator insert_iter;
+ if (index >= m_pairs.size())
+ return false;
+ ++m_mod_id;
+ m_pairs[index] = pair(path, replacement);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+}
+
+bool
+PathMappingList::Remove (off_t index, bool notify)
+{
+ if (index >= m_pairs.size())
+ return false;
+
+ ++m_mod_id;
+ iterator iter = m_pairs.begin() + index;
+ m_pairs.erase(iter);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+}
+
+// For clients which do not need the pair index dumped, pass a pair_index >= 0
+// to only dump the indicated pair.
+void
+PathMappingList::Dump (Stream *s, int pair_index)
+{
+ unsigned int numPairs = m_pairs.size();
+
+ if (pair_index < 0)
+ {
+ unsigned int index;
+ for (index = 0; index < numPairs; ++index)
+ s->Printf("[%d] \"%s\" -> \"%s\"\n",
+ index, m_pairs[index].first.GetCString(), m_pairs[index].second.GetCString());
+ }
+ else
+ {
+ if (pair_index < numPairs)
+ s->Printf("%s -> %s",
+ m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString());
+ }
+}
+
+void
+PathMappingList::Clear (bool notify)
+{
+ if (!m_pairs.empty())
+ ++m_mod_id;
+ m_pairs.clear();
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+}
+
+bool
+PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) const
+{
+ const char *path_cstr = path.GetCString();
+
+ if (!path_cstr)
+ return false;
+
+ const_iterator pos, end = m_pairs.end();
+ for (pos = m_pairs.begin(); pos != end; ++pos)
+ {
+ const size_t prefixLen = pos->first.GetLength();
+
+ if (::strncmp (pos->first.GetCString(), path_cstr, prefixLen) == 0)
+ {
+ std::string new_path_str (pos->second.GetCString());
+ new_path_str.append(path.GetCString() + prefixLen);
+ new_path.SetCString(new_path_str.c_str());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+PathMappingList::RemapPath (const char *path, std::string &new_path) const
+{
+ if (m_pairs.empty() || path == NULL || path[0] == '\0')
+ return false;
+
+ const_iterator pos, end = m_pairs.end();
+ for (pos = m_pairs.begin(); pos != end; ++pos)
+ {
+ const size_t prefix_len = pos->first.GetLength();
+
+ if (::strncmp (pos->first.GetCString(), path, prefix_len) == 0)
+ {
+ new_path = pos->second.GetCString();
+ new_path.append(path + prefix_len);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const
+{
+ if (!m_pairs.empty())
+ {
+ char orig_path[PATH_MAX];
+ char new_path[PATH_MAX];
+ const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path));
+ if (orig_path_len > 0)
+ {
+ const_iterator pos, end = m_pairs.end();
+ for (pos = m_pairs.begin(); pos != end; ++pos)
+ {
+ const size_t prefix_len = pos->first.GetLength();
+
+ if (orig_path_len >= prefix_len)
+ {
+ if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0)
+ {
+ const size_t new_path_len = snprintf(new_path, sizeof(new_path), "%s/%s", pos->second.GetCString(), orig_path + prefix_len);
+ if (new_path_len < sizeof(new_path))
+ {
+ new_spec.SetFile (new_path, true);
+ if (new_spec.Exists())
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ new_spec.Clear();
+ return false;
+}
+
+bool
+PathMappingList::Replace (const ConstString &path, const ConstString &new_path, bool notify)
+{
+ uint32_t idx = FindIndexForPath (path);
+ if (idx < m_pairs.size())
+ {
+ ++m_mod_id;
+ m_pairs[idx].second = new_path;
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+ }
+ return false;
+}
+
+bool
+PathMappingList::Remove (const ConstString &path, bool notify)
+{
+ iterator pos = FindIteratorForPath (path);
+ if (pos != m_pairs.end())
+ {
+ ++m_mod_id;
+ m_pairs.erase (pos);
+ if (notify && m_callback)
+ m_callback (*this, m_callback_baton);
+ return true;
+ }
+ return false;
+}
+
+PathMappingList::const_iterator
+PathMappingList::FindIteratorForPath (const ConstString &path) const
+{
+ const_iterator pos;
+ const_iterator begin = m_pairs.begin();
+ const_iterator end = m_pairs.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->first == path)
+ break;
+ }
+ return pos;
+}
+
+PathMappingList::iterator
+PathMappingList::FindIteratorForPath (const ConstString &path)
+{
+ iterator pos;
+ iterator begin = m_pairs.begin();
+ iterator end = m_pairs.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->first == path)
+ break;
+ }
+ return pos;
+}
+
+bool
+PathMappingList::GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const
+{
+ if (idx < m_pairs.size())
+ {
+ path = m_pairs[idx].first;
+ new_path = m_pairs[idx].second;
+ return true;
+ }
+ return false;
+}
+
+
+
+uint32_t
+PathMappingList::FindIndexForPath (const ConstString &path) const
+{
+ const_iterator pos;
+ const_iterator begin = m_pairs.begin();
+ const_iterator end = m_pairs.end();
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->first == path)
+ return std::distance (begin, pos);
+ }
+ return UINT32_MAX;
+}
+
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
new file mode 100644
index 000000000000..e6d3bc7a55d0
--- /dev/null
+++ b/source/Target/Platform.cpp
@@ -0,0 +1,779 @@
+//===-- Platform.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/Platform.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointIDList.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+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 ()
+{
+ static PlatformSP g_default_platform_sp;
+ return g_default_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 ()
+{
+ return "host";
+}
+
+//------------------------------------------------------------------
+/// Get the native host platform plug-in.
+///
+/// There should only be one of these for each host that LLDB runs
+/// upon that should be statically compiled in and registered using
+/// preprocessor macros or other similar build mechanisms.
+///
+/// This platform will be used as the default platform when launching
+/// or attaching to processes unless another platform is specified.
+//------------------------------------------------------------------
+PlatformSP
+Platform::GetDefaultPlatform ()
+{
+ return GetDefaultPlatformSP ();
+}
+
+void
+Platform::SetDefaultPlatform (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;
+}
+
+Error
+Platform::GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+FileSpecList
+Platform::LocateExecutableScriptingResources (Target *target, Module &module)
+{
+ 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;
+}
+
+Error
+Platform::GetSharedModule (const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ // Don't do any path remapping for the default implementation
+ // of the platform GetSharedModule function, just call through
+ // to our static ModuleList function. Platform subclasses that
+ // implement remote debugging, might have a developer kits
+ // installed that have cached versions of the files for the
+ // remote target, or might implement a download and cache
+ // locally implementation.
+ const bool always_create = false;
+ return ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr,
+ always_create);
+}
+
+PlatformSP
+Platform::Create (const char *platform_name, Error &error)
+{
+ PlatformCreateInstance create_callback = NULL;
+ lldb::PlatformSP platform_sp;
+ if (platform_name && platform_name[0])
+ {
+ ConstString const_platform_name (platform_name);
+ create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (const_platform_name);
+ if (create_callback)
+ platform_sp.reset(create_callback(true, NULL));
+ else
+ error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name);
+ }
+ else
+ error.SetErrorString ("invalid platform name");
+ return platform_sp;
+}
+
+
+PlatformSP
+Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error)
+{
+ lldb::PlatformSP platform_sp;
+ if (arch.IsValid())
+ {
+ uint32_t idx;
+ PlatformCreateInstance create_callback;
+ // First try exact arch matches across all platform plug-ins
+ bool exact = true;
+ 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))
+ 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))
+ return platform_sp;
+ }
+ }
+ }
+ else
+ error.SetErrorString ("invalid platform name");
+ if (platform_arch_ptr)
+ platform_arch_ptr->Clear();
+ platform_sp.reset();
+ 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
+//------------------------------------------------------------------
+Platform::Platform (bool is_host) :
+ m_is_host (is_host),
+ m_os_version_set_while_connected (false),
+ m_system_arch_set_while_connected (false),
+ m_sdk_sysroot (),
+ m_sdk_build (),
+ m_remote_url (),
+ m_name (),
+ m_major_os_version (UINT32_MAX),
+ m_minor_os_version (UINT32_MAX),
+ m_update_os_version (UINT32_MAX),
+ m_system_arch(),
+ m_uid_map_mutex (Mutex::eMutexTypeNormal),
+ m_gid_map_mutex (Mutex::eMutexTypeNormal),
+ m_uid_map(),
+ m_gid_map(),
+ m_max_uid_name_len (0),
+ m_max_gid_name_len (0)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Platform::Platform()", this);
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+Platform::~Platform()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Platform::~Platform()", this);
+}
+
+void
+Platform::GetStatus (Stream &strm)
+{
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ std::string s;
+ strm.Printf (" Platform: %s\n", GetPluginName().GetCString());
+
+ ArchSpec arch (GetSystemArchitecture());
+ if (arch.IsValid())
+ {
+ if (!arch.GetTriple().str().empty())
+ strm.Printf(" Triple: %s\n", arch.GetTriple().str().c_str());
+ }
+
+ if (GetOSVersion(major, minor, update))
+ {
+ strm.Printf("OS Version: %u", major);
+ if (minor != UINT32_MAX)
+ strm.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ strm.Printf(".%u", update);
+
+ if (GetOSBuildString (s))
+ strm.Printf(" (%s)", s.c_str());
+
+ strm.EOL();
+ }
+
+ if (GetOSKernelDescription (s))
+ strm.Printf(" Kernel: %s\n", s.c_str());
+
+ if (IsHost())
+ {
+ strm.Printf(" Hostname: %s\n", GetHostname());
+ }
+ else
+ {
+ const bool is_connected = IsConnected();
+ if (is_connected)
+ strm.Printf(" Hostname: %s\n", GetHostname());
+ strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no");
+ }
+}
+
+
+bool
+Platform::GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update)
+{
+ bool success = m_major_os_version != UINT32_MAX;
+ if (IsHost())
+ {
+ if (!success)
+ {
+ // We have a local host platform
+ success = Host::GetOSVersion (m_major_os_version,
+ m_minor_os_version,
+ m_update_os_version);
+ m_os_version_set_while_connected = success;
+ }
+ }
+ else
+ {
+ // We have a remote platform. We can only fetch the remote
+ // OS version if we are connected, and we don't want to do it
+ // more than once.
+
+ const bool is_connected = IsConnected();
+
+ bool fetch = false;
+ if (success)
+ {
+ // We have valid OS version info, check to make sure it wasn't
+ // manually set prior to connecting. If it was manually set prior
+ // to connecting, then lets fetch the actual OS version info
+ // if we are now connected.
+ if (is_connected && !m_os_version_set_while_connected)
+ fetch = true;
+ }
+ else
+ {
+ // We don't have valid OS version info, fetch it if we are connected
+ fetch = is_connected;
+ }
+
+ if (fetch)
+ {
+ success = GetRemoteOSVersion ();
+ m_os_version_set_while_connected = success;
+ }
+ }
+
+ if (success)
+ {
+ major = m_major_os_version;
+ minor = m_minor_os_version;
+ update = m_update_os_version;
+ }
+ return success;
+}
+
+bool
+Platform::GetOSBuildString (std::string &s)
+{
+ if (IsHost())
+ return Host::GetOSBuildString (s);
+ else
+ return GetRemoteOSBuildString (s);
+}
+
+bool
+Platform::GetOSKernelDescription (std::string &s)
+{
+ if (IsHost())
+ return Host::GetOSKernelDescription (s);
+ else
+ return GetRemoteOSKernelDescription (s);
+}
+
+ConstString
+Platform::GetName ()
+{
+ const char *name = GetHostname();
+ if (name == NULL || name[0] == '\0')
+ return GetPluginName();
+ return ConstString (name);
+}
+
+const char *
+Platform::GetHostname ()
+{
+ if (IsHost())
+ return "localhost";
+
+ if (m_name.empty())
+ return NULL;
+ return m_name.c_str();
+}
+
+const char *
+Platform::GetUserName (uint32_t uid)
+{
+ const char *user_name = GetCachedUserName(uid);
+ if (user_name)
+ return user_name;
+ if (IsHost())
+ {
+ std::string name;
+ if (Host::GetUserName(uid, name))
+ return SetCachedUserName (uid, name.c_str(), name.size());
+ }
+ return NULL;
+}
+
+const char *
+Platform::GetGroupName (uint32_t gid)
+{
+ const char *group_name = GetCachedGroupName(gid);
+ if (group_name)
+ return group_name;
+ if (IsHost())
+ {
+ std::string name;
+ if (Host::GetGroupName(gid, name))
+ return SetCachedGroupName (gid, name.c_str(), name.size());
+ }
+ return NULL;
+}
+
+bool
+Platform::SetOSVersion (uint32_t major,
+ uint32_t minor,
+ uint32_t update)
+{
+ if (IsHost())
+ {
+ // We don't need anyone setting the OS version for the host platform,
+ // we should be able to figure it out by calling Host::GetOSVersion(...).
+ return false;
+ }
+ else
+ {
+ // We have a remote platform, allow setting the target OS version if
+ // we aren't connected, since if we are connected, we should be able to
+ // request the remote OS version from the connected platform.
+ if (IsConnected())
+ return false;
+ else
+ {
+ // We aren't connected and we might want to set the OS version
+ // ahead of time before we connect so we can peruse files and
+ // use a local SDK or PDK cache of support files to disassemble
+ // or do other things.
+ m_major_os_version = major;
+ m_minor_os_version = minor;
+ m_update_os_version = update;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+Error
+Platform::ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &exe_arch,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ if (exe_file.Exists())
+ {
+ ModuleSpec module_spec (exe_file, exe_arch);
+ if (module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+ }
+ else
+ {
+ // 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)
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success() && exe_module_sp)
+ break;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ exe_file.GetPath().c_str());
+ }
+ return error;
+}
+
+Error
+Platform::ResolveSymbolFile (Target &target,
+ const ModuleSpec &sym_spec,
+ FileSpec &sym_file)
+{
+ Error error;
+ if (sym_spec.GetSymbolFileSpec().Exists())
+ sym_file = sym_spec.GetSymbolFileSpec();
+ else
+ error.SetErrorString("unable to resolve symbol file");
+ return error;
+
+}
+
+
+
+bool
+Platform::ResolveRemotePath (const FileSpec &platform_path,
+ FileSpec &resolved_platform_path)
+{
+ resolved_platform_path = platform_path;
+ return resolved_platform_path.ResolvePath();
+}
+
+
+const ArchSpec &
+Platform::GetSystemArchitecture()
+{
+ if (IsHost())
+ {
+ if (!m_system_arch.IsValid())
+ {
+ // We have a local host platform
+ m_system_arch = Host::GetArchitecture();
+ m_system_arch_set_while_connected = m_system_arch.IsValid();
+ }
+ }
+ else
+ {
+ // We have a remote platform. We can only fetch the remote
+ // system architecture if we are connected, and we don't want to do it
+ // more than once.
+
+ const bool is_connected = IsConnected();
+
+ bool fetch = false;
+ if (m_system_arch.IsValid())
+ {
+ // We have valid OS version info, check to make sure it wasn't
+ // manually set prior to connecting. If it was manually set prior
+ // to connecting, then lets fetch the actual OS version info
+ // if we are now connected.
+ if (is_connected && !m_system_arch_set_while_connected)
+ fetch = true;
+ }
+ else
+ {
+ // We don't have valid OS version info, fetch it if we are connected
+ fetch = is_connected;
+ }
+
+ if (fetch)
+ {
+ m_system_arch = GetRemoteSystemArchitecture ();
+ m_system_arch_set_while_connected = m_system_arch.IsValid();
+ }
+ }
+ return m_system_arch;
+}
+
+
+Error
+Platform::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsHost())
+ error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
+ else
+ error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString());
+ return error;
+}
+
+Error
+Platform::DisconnectRemote ()
+{
+ Error error;
+ if (IsHost())
+ error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString());
+ else
+ error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString());
+ return error;
+}
+
+bool
+Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ // Take care of the host case so that each subclass can just
+ // call this function to get the host functionality.
+ if (IsHost())
+ return Host::GetProcessInfo (pid, process_info);
+ return false;
+}
+
+uint32_t
+Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ // Take care of the host case so that each subclass can just
+ // call this function to get the host functionality.
+ uint32_t match_count = 0;
+ if (IsHost())
+ match_count = Host::FindProcesses (match_info, process_infos);
+ return match_count;
+}
+
+
+Error
+Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ // Take care of the host case so that each subclass can just
+ // call this function to get the host functionality.
+ if (IsHost())
+ {
+ if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY"))
+ launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
+
+ if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell))
+ {
+ const bool is_localhost = true;
+ const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
+ const bool first_arg_is_full_shell_command = false;
+ if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
+ is_localhost,
+ will_debug,
+ first_arg_is_full_shell_command))
+ return error;
+ }
+
+ error = Host::LaunchProcess (launch_info);
+ }
+ else
+ error.SetErrorString ("base lldb_private::Platform class can't launch remote processes");
+ return error;
+}
+
+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)
+{
+ ProcessSP process_sp;
+ // Make sure we stop at the entry point
+ launch_info.GetFlags ().Set (eLaunchFlagDebug);
+ // We always launch the process we are going to debug in a separate process
+ // group, since then we can handle ^C interrupts ourselves w/o having to worry
+ // about the target getting them as well.
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+
+ error = LaunchProcess (launch_info);
+ if (error.Success())
+ {
+ if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessAttachInfo attach_info (launch_info);
+ process_sp = Attach (attach_info, debugger, target, listener, error);
+ if (process_sp)
+ {
+ // Since we attached to the process, it will think it needs to detach
+ // if the process object just goes away without an explicit call to
+ // Process::Kill() or Process::Detach(), so let it know to kill the
+ // process if this happens.
+ process_sp->SetShouldDetach (false);
+
+ // If we didn't have any file actions, the pseudo terminal might
+ // have been used where the slave side was given as the file to
+ // open for stdin/out/err after we have already opened the master
+ // so we can read/write stdin/out/err.
+ int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
+ if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd)
+ {
+ process_sp->SetSTDIOFileDescriptor(pty_fd);
+ }
+ }
+ }
+ }
+ return process_sp;
+}
+
+
+lldb::PlatformSP
+Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr)
+{
+ lldb::PlatformSP platform_sp;
+ Error error;
+ if (arch.IsValid())
+ platform_sp = Platform::Create (arch, platform_arch_ptr, error);
+ return platform_sp;
+}
+
+
+//------------------------------------------------------------------
+/// Lets a platform answer if it is compatible with a given
+/// architecture and the target triple contained within.
+//------------------------------------------------------------------
+bool
+Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr)
+{
+ // If the architecture is invalid, we must answer true...
+ if (arch.IsValid())
+ {
+ ArchSpec platform_arch;
+ // Try for an exact architecture match first.
+ if (exact_arch_match)
+ {
+ for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
+ {
+ if (arch.IsExactMatch(platform_arch))
+ {
+ if (compatible_arch_ptr)
+ *compatible_arch_ptr = platform_arch;
+ return true;
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx)
+ {
+ if (arch.IsCompatibleMatch(platform_arch))
+ {
+ if (compatible_arch_ptr)
+ *compatible_arch_ptr = platform_arch;
+ return true;
+ }
+ }
+ }
+ }
+ if (compatible_arch_ptr)
+ compatible_arch_ptr->Clear();
+ return false;
+
+}
+
+
+lldb::BreakpointSP
+Platform::SetThreadCreationBreakpoint (lldb_private::Target &target)
+{
+ return lldb::BreakpointSP();
+}
+
+size_t
+Platform::GetEnvironment (StringList &environment)
+{
+ environment.Clear();
+ return false;
+}
+
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
new file mode 100644
index 000000000000..6edb9390d990
--- /dev/null
+++ b/source/Target/Process.cpp
@@ -0,0 +1,5595 @@
+//===-- Process.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/Process.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanBase.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// Comment out line below to disable memory caching, overriding the process setting
+// target.process.disable-memory-cache
+#define ENABLE_MEMORY_CACHING
+
+#ifdef ENABLE_MEMORY_CACHING
+#define DISABLE_MEM_CACHE_DEFAULT false
+#else
+#define DISABLE_MEM_CACHE_DEFAULT true
+#endif
+
+class ProcessOptionValueProperties : public OptionValueProperties
+{
+public:
+ ProcessOptionValueProperties (const ConstString &name) :
+ OptionValueProperties (name)
+ {
+ }
+
+ // This constructor is used when creating ProcessOptionValueProperties when it
+ // is part of a new lldb_private::Process instance. It will copy all current
+ // global property values as needed
+ ProcessOptionValueProperties (ProcessProperties *global_properties) :
+ OptionValueProperties(*global_properties->GetValueProperties())
+ {
+ }
+
+ virtual const Property *
+ GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+ {
+ // When gettings the value for a key from the process options, we will always
+ // try and grab the setting from the current process if there is one. Else we just
+ // use the one from this instance.
+ if (exe_ctx)
+ {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process)
+ {
+ ProcessOptionValueProperties *instance_properties = static_cast<ProcessOptionValueProperties *>(process->GetValueProperties().get());
+ if (this != instance_properties)
+ return instance_properties->ProtectedGetPropertyAtIndex (idx);
+ }
+ }
+ return ProtectedGetPropertyAtIndex (idx);
+ }
+};
+
+static PropertyDefinition
+g_properties[] =
+{
+ { "disable-memory-cache" , OptionValue::eTypeBoolean, false, DISABLE_MEM_CACHE_DEFAULT, NULL, NULL, "Disable reading and caching of memory in fixed-size units." },
+ { "extra-startup-command", OptionValue::eTypeArray , false, OptionValue::eTypeString, NULL, NULL, "A list containing extra commands understood by the particular process plugin used. "
+ "For instance, to turn on debugserver logging set this to \"QSetLogging:bitmask=LOG_DEFAULT;\"" },
+ { "ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, breakpoints will be ignored during expression evaluation." },
+ { "unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, errors in expression evaluation will unwind the stack back to the state before the call." },
+ { "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." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+};
+
+enum {
+ ePropertyDisableMemCache,
+ ePropertyExtraStartCommand,
+ ePropertyIgnoreBreakpointsInExpressions,
+ ePropertyUnwindOnErrorInExpressions,
+ ePropertyPythonOSPluginPath,
+ ePropertyStopOnSharedLibraryEvents,
+ ePropertyDetachKeepsStopped
+};
+
+ProcessProperties::ProcessProperties (bool is_global) :
+ Properties ()
+{
+ if (is_global)
+ {
+ m_collection_sp.reset (new ProcessOptionValueProperties(ConstString("process")));
+ m_collection_sp->Initialize(g_properties);
+ m_collection_sp->AppendProperty(ConstString("thread"),
+ ConstString("Settings specific to threads."),
+ true,
+ Thread::GetGlobalProperties()->GetValueProperties());
+ }
+ else
+ m_collection_sp.reset (new ProcessOptionValueProperties(Process::GetGlobalProperties().get()));
+}
+
+ProcessProperties::~ProcessProperties()
+{
+}
+
+bool
+ProcessProperties::GetDisableMemoryCache() const
+{
+ const uint32_t idx = ePropertyDisableMemCache;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+Args
+ProcessProperties::GetExtraStartupCommands () const
+{
+ Args args;
+ const uint32_t idx = ePropertyExtraStartCommand;
+ m_collection_sp->GetPropertyAtIndexAsArgs(NULL, idx, args);
+ return args;
+}
+
+void
+ProcessProperties::SetExtraStartupCommands (const Args &args)
+{
+ const uint32_t idx = ePropertyExtraStartCommand;
+ m_collection_sp->SetPropertyAtIndexFromArgs(NULL, idx, args);
+}
+
+FileSpec
+ProcessProperties::GetPythonOSPluginPath () const
+{
+ const uint32_t idx = ePropertyPythonOSPluginPath;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx);
+}
+
+void
+ProcessProperties::SetPythonOSPluginPath (const FileSpec &file)
+{
+ const uint32_t idx = ePropertyPythonOSPluginPath;
+ m_collection_sp->SetPropertyAtIndexAsFileSpec(NULL, idx, file);
+}
+
+
+bool
+ProcessProperties::GetIgnoreBreakpointsInExpressions () const
+{
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetIgnoreBreakpointsInExpressions (bool ignore)
+{
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, ignore);
+}
+
+bool
+ProcessProperties::GetUnwindOnErrorInExpressions () const
+{
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetUnwindOnErrorInExpressions (bool ignore)
+{
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, ignore);
+}
+
+bool
+ProcessProperties::GetStopOnSharedLibraryEvents () const
+{
+ const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetStopOnSharedLibraryEvents (bool stop)
+{
+ const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, stop);
+}
+
+bool
+ProcessProperties::GetDetachKeepsStopped () const
+{
+ const uint32_t idx = ePropertyDetachKeepsStopped;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+ProcessProperties::SetDetachKeepsStopped (bool stop)
+{
+ const uint32_t idx = ePropertyDetachKeepsStopped;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(NULL, idx, stop);
+}
+
+void
+ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
+{
+ const char *cstr;
+ if (m_pid != LLDB_INVALID_PROCESS_ID)
+ s.Printf (" pid = %" PRIu64 "\n", m_pid);
+
+ if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
+ s.Printf (" parent = %" PRIu64 "\n", m_parent_pid);
+
+ if (m_executable)
+ {
+ s.Printf (" name = %s\n", m_executable.GetFilename().GetCString());
+ s.PutCString (" file = ");
+ m_executable.Dump(&s);
+ s.EOL();
+ }
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ if (argc > 0)
+ {
+ for (uint32_t i=0; i<argc; i++)
+ {
+ const char *arg = m_arguments.GetArgumentAtIndex(i);
+ if (i < 10)
+ s.Printf (" arg[%u] = %s\n", i, arg);
+ else
+ s.Printf ("arg[%u] = %s\n", i, arg);
+ }
+ }
+
+ const uint32_t envc = m_environment.GetArgumentCount();
+ if (envc > 0)
+ {
+ for (uint32_t i=0; i<envc; i++)
+ {
+ const char *env = m_environment.GetArgumentAtIndex(i);
+ if (i < 10)
+ s.Printf (" env[%u] = %s\n", i, env);
+ else
+ s.Printf ("env[%u] = %s\n", i, env);
+ }
+ }
+
+ if (m_arch.IsValid())
+ s.Printf (" arch = %s\n", m_arch.GetTriple().str().c_str());
+
+ if (m_uid != UINT32_MAX)
+ {
+ cstr = platform->GetUserName (m_uid);
+ s.Printf (" uid = %-5u (%s)\n", m_uid, cstr ? cstr : "");
+ }
+ if (m_gid != UINT32_MAX)
+ {
+ cstr = platform->GetGroupName (m_gid);
+ s.Printf (" gid = %-5u (%s)\n", m_gid, cstr ? cstr : "");
+ }
+ if (m_euid != UINT32_MAX)
+ {
+ cstr = platform->GetUserName (m_euid);
+ s.Printf (" euid = %-5u (%s)\n", m_euid, cstr ? cstr : "");
+ }
+ if (m_egid != UINT32_MAX)
+ {
+ cstr = platform->GetGroupName (m_egid);
+ s.Printf (" egid = %-5u (%s)\n", m_egid, cstr ? cstr : "");
+ }
+}
+
+void
+ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose)
+{
+ const char *label;
+ if (show_args || verbose)
+ label = "ARGUMENTS";
+ else
+ label = "NAME";
+
+ if (verbose)
+ {
+ s.Printf ("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE %s\n", label);
+ s.PutCString ("====== ====== ========== ========== ========== ========== ======================== ============================\n");
+ }
+ else
+ {
+ s.Printf ("PID PARENT USER ARCH %s\n", label);
+ s.PutCString ("====== ====== ========== ======= ============================\n");
+ }
+}
+
+void
+ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const
+{
+ if (m_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ const char *cstr;
+ s.Printf ("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
+
+
+ if (verbose)
+ {
+ cstr = platform->GetUserName (m_uid);
+ if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf ("%-10s ", cstr);
+ else
+ s.Printf ("%-10u ", m_uid);
+
+ cstr = platform->GetGroupName (m_gid);
+ if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf ("%-10s ", cstr);
+ else
+ s.Printf ("%-10u ", m_gid);
+
+ cstr = platform->GetUserName (m_euid);
+ if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf ("%-10s ", cstr);
+ else
+ s.Printf ("%-10u ", m_euid);
+
+ cstr = platform->GetGroupName (m_egid);
+ if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf ("%-10s ", cstr);
+ else
+ s.Printf ("%-10u ", m_egid);
+ s.Printf ("%-24s ", m_arch.IsValid() ? m_arch.GetTriple().str().c_str() : "");
+ }
+ else
+ {
+ s.Printf ("%-10s %-7d %s ",
+ platform->GetUserName (m_euid),
+ (int)m_arch.GetTriple().getArchName().size(),
+ m_arch.GetTriple().getArchName().data());
+ }
+
+ if (verbose || show_args)
+ {
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ if (argc > 0)
+ {
+ for (uint32_t i=0; i<argc; i++)
+ {
+ if (i > 0)
+ s.PutChar (' ');
+ s.PutCString (m_arguments.GetArgumentAtIndex(i));
+ }
+ }
+ }
+ else
+ {
+ s.PutCString (GetName());
+ }
+
+ s.EOL();
+ }
+}
+
+
+void
+ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable)
+{
+ m_arguments.SetArguments (argv);
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable)
+ {
+ const char *first_arg = m_arguments.GetArgumentAtIndex (0);
+ if (first_arg)
+ {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
+ }
+ }
+}
+void
+ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable)
+{
+ // Copy all arguments
+ m_arguments = args;
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable)
+ {
+ const char *first_arg = m_arguments.GetArgumentAtIndex (0);
+ if (first_arg)
+ {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
+ }
+ }
+}
+
+void
+ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
+{
+ // If notthing was specified, then check the process for any default
+ // settings that were set with "settings set"
+ if (m_file_actions.empty())
+ {
+ if (m_flags.Test(eLaunchFlagDisableSTDIO))
+ {
+ AppendSuppressFileAction (STDIN_FILENO , true, false);
+ AppendSuppressFileAction (STDOUT_FILENO, false, true);
+ AppendSuppressFileAction (STDERR_FILENO, false, true);
+ }
+ else
+ {
+ // Check for any values that might have gotten set with any of:
+ // (lldb) settings set target.input-path
+ // (lldb) settings set target.output-path
+ // (lldb) settings set target.error-path
+ FileSpec in_path;
+ FileSpec out_path;
+ FileSpec err_path;
+ if (target)
+ {
+ in_path = target->GetStandardInputPath();
+ out_path = target->GetStandardOutputPath();
+ err_path = target->GetStandardErrorPath();
+ }
+
+ if (in_path || out_path || err_path)
+ {
+ char path[PATH_MAX];
+ if (in_path && in_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDIN_FILENO, path, true, false);
+
+ if (out_path && out_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+
+ if (err_path && err_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDERR_FILENO, path, false, true);
+ }
+ else if (default_to_use_pty)
+ {
+ if (m_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0))
+ {
+ const char *slave_path = m_pty.GetSlaveName (NULL, 0);
+ AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
+ AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
+ AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
+ }
+ }
+ }
+ }
+}
+
+
+bool
+ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
+ bool localhost,
+ bool will_debug,
+ bool first_arg_is_full_shell_command)
+{
+ error.Clear();
+
+ if (GetFlags().Test (eLaunchFlagLaunchInShell))
+ {
+ const char *shell_executable = GetShell();
+ if (shell_executable)
+ {
+ char shell_resolved_path[PATH_MAX];
+
+ if (localhost)
+ {
+ FileSpec shell_filespec (shell_executable, true);
+
+ if (!shell_filespec.Exists())
+ {
+ // Resolve the path in case we just got "bash", "sh" or "tcsh"
+ if (!shell_filespec.ResolveExecutableLocation ())
+ {
+ error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
+ return false;
+ }
+ }
+ shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
+ shell_executable = shell_resolved_path;
+ }
+
+ const char **argv = GetArguments().GetConstArgumentVector ();
+ if (argv == NULL || argv[0] == NULL)
+ return false;
+ Args shell_arguments;
+ std::string safe_arg;
+ shell_arguments.AppendArgument (shell_executable);
+ shell_arguments.AppendArgument ("-c");
+ StreamString shell_command;
+ if (will_debug)
+ {
+ // Add a modified PATH environment variable in case argv[0]
+ // is a relative path
+ const char *argv0 = argv[0];
+ if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
+ {
+ // We have a relative path to our executable which may not work if
+ // we just try to run "a.out" (without it being converted to "./a.out")
+ const char *working_dir = GetWorkingDirectory();
+ // Be sure to put quotes around PATH's value in case any paths have spaces...
+ std::string new_path("PATH=\"");
+ const size_t empty_path_len = new_path.size();
+
+ if (working_dir && working_dir[0])
+ {
+ new_path += working_dir;
+ }
+ else
+ {
+ char current_working_dir[PATH_MAX];
+ const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
+ if (cwd && cwd[0])
+ new_path += cwd;
+ }
+ const char *curr_path = getenv("PATH");
+ if (curr_path)
+ {
+ if (new_path.size() > empty_path_len)
+ new_path += ':';
+ new_path += curr_path;
+ }
+ new_path += "\" ";
+ shell_command.PutCString(new_path.c_str());
+ }
+
+ shell_command.PutCString ("exec");
+
+ // Only Apple supports /usr/bin/arch being able to specify the architecture
+ if (GetArchitecture().IsValid())
+ {
+ shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
+ // Set the resume count to 2:
+ // 1 - stop in shell
+ // 2 - stop in /usr/bin/arch
+ // 3 - then we will stop in our program
+ SetResumeCount(2);
+ }
+ else
+ {
+ // Set the resume count to 1:
+ // 1 - stop in shell
+ // 2 - then we will stop in our program
+ SetResumeCount(1);
+ }
+ }
+
+ if (first_arg_is_full_shell_command)
+ {
+ // There should only be one argument that is the shell command itself to be used as is
+ if (argv[0] && !argv[1])
+ shell_command.Printf("%s", argv[0]);
+ else
+ return false;
+ }
+ else
+ {
+ for (size_t i=0; argv[i] != NULL; ++i)
+ {
+ const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
+ shell_command.Printf(" %s", arg);
+ }
+ }
+ shell_arguments.AppendArgument (shell_command.GetString().c_str());
+ m_executable.SetFile(shell_executable, false);
+ m_arguments = shell_arguments;
+ return true;
+ }
+ else
+ {
+ error.SetErrorString ("invalid shell path");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("not launching in shell");
+ }
+ return false;
+}
+
+
+bool
+ProcessLaunchInfo::FileAction::Open (int fd, const char *path, bool read, bool write)
+{
+ if ((read || write) && fd >= 0 && path && path[0])
+ {
+ m_action = eFileActionOpen;
+ m_fd = fd;
+ if (read && write)
+ m_arg = O_NOCTTY | O_CREAT | O_RDWR;
+ else if (read)
+ m_arg = O_NOCTTY | O_RDONLY;
+ else
+ m_arg = O_NOCTTY | O_CREAT | O_WRONLY;
+ m_path.assign (path);
+ return true;
+ }
+ else
+ {
+ Clear();
+ }
+ return false;
+}
+
+bool
+ProcessLaunchInfo::FileAction::Close (int fd)
+{
+ Clear();
+ if (fd >= 0)
+ {
+ m_action = eFileActionClose;
+ m_fd = fd;
+ }
+ return m_fd >= 0;
+}
+
+
+bool
+ProcessLaunchInfo::FileAction::Duplicate (int fd, int dup_fd)
+{
+ Clear();
+ if (fd >= 0 && dup_fd >= 0)
+ {
+ m_action = eFileActionDuplicate;
+ m_fd = fd;
+ m_arg = dup_fd;
+ }
+ return m_fd >= 0;
+}
+
+
+
+bool
+ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (posix_spawn_file_actions_t *file_actions,
+ const FileAction *info,
+ Log *log,
+ Error& error)
+{
+ if (info == NULL)
+ return false;
+
+ switch (info->m_action)
+ {
+ case eFileActionNone:
+ error.Clear();
+ break;
+
+ case eFileActionClose:
+ if (info->m_fd == -1)
+ error.SetErrorString ("invalid fd for posix_spawn_file_actions_addclose(...)");
+ else
+ {
+ error.SetError (::posix_spawn_file_actions_addclose (file_actions, info->m_fd),
+ eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
+ file_actions, info->m_fd);
+ }
+ break;
+
+ case eFileActionDuplicate:
+ if (info->m_fd == -1)
+ error.SetErrorString ("invalid fd for posix_spawn_file_actions_adddup2(...)");
+ else if (info->m_arg == -1)
+ error.SetErrorString ("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
+ else
+ {
+ error.SetError (::posix_spawn_file_actions_adddup2 (file_actions, info->m_fd, info->m_arg),
+ eErrorTypePOSIX);
+ if (log && (error.Fail() || log))
+ error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
+ file_actions, info->m_fd, info->m_arg);
+ }
+ break;
+
+ case eFileActionOpen:
+ if (info->m_fd == -1)
+ error.SetErrorString ("invalid fd in posix_spawn_file_actions_addopen(...)");
+ else
+ {
+ int oflag = info->m_arg;
+
+ mode_t mode = 0;
+
+ if (oflag & O_CREAT)
+ mode = 0640;
+
+ error.SetError (::posix_spawn_file_actions_addopen (file_actions,
+ info->m_fd,
+ info->m_path.c_str(),
+ oflag,
+ mode),
+ eErrorTypePOSIX);
+ if (error.Fail() || log)
+ error.PutToLog(log,
+ "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
+ file_actions, info->m_fd, info->m_path.c_str(), oflag, mode);
+ }
+ break;
+ }
+ return error.Success();
+}
+
+Error
+ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
+{
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option)
+ {
+ case 's': // Stop at program entry point
+ launch_info.GetFlags().Set (eLaunchFlagStopAtEntry);
+ break;
+
+ case 'i': // STDIN for read only
+ {
+ ProcessLaunchInfo::FileAction action;
+ if (action.Open (STDIN_FILENO, option_arg, true, false))
+ launch_info.AppendFileAction (action);
+ }
+ break;
+
+ case 'o': // Open STDOUT for write only
+ {
+ ProcessLaunchInfo::FileAction action;
+ if (action.Open (STDOUT_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
+ }
+ break;
+
+ case 'e': // STDERR for write only
+ {
+ ProcessLaunchInfo::FileAction action;
+ if (action.Open (STDERR_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
+ }
+ break;
+
+
+ case 'p': // Process plug-in name
+ launch_info.SetProcessPluginName (option_arg);
+ break;
+
+ case 'n': // Disable STDIO
+ {
+ ProcessLaunchInfo::FileAction action;
+ if (action.Open (STDIN_FILENO, "/dev/null", true, false))
+ launch_info.AppendFileAction (action);
+ if (action.Open (STDOUT_FILENO, "/dev/null", false, true))
+ launch_info.AppendFileAction (action);
+ if (action.Open (STDERR_FILENO, "/dev/null", false, true))
+ launch_info.AppendFileAction (action);
+ }
+ break;
+
+ case 'w':
+ launch_info.SetWorkingDirectory (option_arg);
+ break;
+
+ case 't': // Open process in new terminal window
+ launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
+ break;
+
+ case 'a':
+ if (!launch_info.GetArchitecture().SetTriple (option_arg, m_interpreter.GetPlatform(true).get()))
+ launch_info.GetArchitecture().SetTriple (option_arg);
+ break;
+
+ case 'A':
+ launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ break;
+
+ case 'c':
+ if (option_arg && option_arg[0])
+ launch_info.SetShell (option_arg);
+ else
+ launch_info.SetShell ("/bin/bash");
+ break;
+
+ case 'v':
+ launch_info.GetEnvironmentEntries().AppendArgument(option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option);
+ break;
+
+ }
+ return error;
+}
+
+OptionDefinition
+ProcessLaunchCommandOptions::g_option_table[] =
+{
+{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', no_argument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
+{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', no_argument, NULL, 0, eArgTypeNone, "Disable address space layout randomization when launching a process."},
+{ LLDB_OPT_SET_ALL, false, "plugin", 'p', required_argument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', required_argument, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
+{ LLDB_OPT_SET_ALL, false, "arch", 'a', required_argument, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
+{ LLDB_OPT_SET_ALL, false, "environment", 'v', required_argument, NULL, 0, eArgTypeNone, "Specify an environment variable name/value stirng (--environement NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
+{ LLDB_OPT_SET_ALL, false, "shell", 'c', optional_argument, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
+
+{ LLDB_OPT_SET_1 , false, "stdin", 'i', required_argument, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stdout", 'o', required_argument, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stderr", 'e', required_argument, NULL, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>."},
+
+{ LLDB_OPT_SET_2 , false, "tty", 't', no_argument, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
+
+{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', no_argument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
+
+{ 0 , false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+
+bool
+ProcessInstanceInfoMatch::NameMatches (const char *process_name) const
+{
+ if (m_name_match_type == eNameMatchIgnore || process_name == NULL)
+ return true;
+ const char *match_name = m_match_info.GetName();
+ if (!match_name)
+ return true;
+
+ return lldb_private::NameMatches (process_name, m_name_match_type, match_name);
+}
+
+bool
+ProcessInstanceInfoMatch::Matches (const ProcessInstanceInfo &proc_info) const
+{
+ if (!NameMatches (proc_info.GetName()))
+ return false;
+
+ if (m_match_info.ProcessIDIsValid() &&
+ m_match_info.GetProcessID() != proc_info.GetProcessID())
+ return false;
+
+ if (m_match_info.ParentProcessIDIsValid() &&
+ m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
+ return false;
+
+ if (m_match_info.UserIDIsValid () &&
+ m_match_info.GetUserID() != proc_info.GetUserID())
+ return false;
+
+ if (m_match_info.GroupIDIsValid () &&
+ m_match_info.GetGroupID() != proc_info.GetGroupID())
+ return false;
+
+ if (m_match_info.EffectiveUserIDIsValid () &&
+ m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
+ return false;
+
+ if (m_match_info.EffectiveGroupIDIsValid () &&
+ m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
+ return false;
+
+ if (m_match_info.GetArchitecture().IsValid() &&
+ !m_match_info.GetArchitecture().IsCompatibleMatch(proc_info.GetArchitecture()))
+ return false;
+ return true;
+}
+
+bool
+ProcessInstanceInfoMatch::MatchAllProcesses () const
+{
+ if (m_name_match_type != eNameMatchIgnore)
+ return false;
+
+ if (m_match_info.ProcessIDIsValid())
+ return false;
+
+ if (m_match_info.ParentProcessIDIsValid())
+ return false;
+
+ if (m_match_info.UserIDIsValid ())
+ return false;
+
+ if (m_match_info.GroupIDIsValid ())
+ return false;
+
+ if (m_match_info.EffectiveUserIDIsValid ())
+ return false;
+
+ if (m_match_info.EffectiveGroupIDIsValid ())
+ return false;
+
+ if (m_match_info.GetArchitecture().IsValid())
+ return false;
+
+ if (m_match_all_users)
+ return false;
+
+ return true;
+
+}
+
+void
+ProcessInstanceInfoMatch::Clear()
+{
+ m_match_info.Clear();
+ m_name_match_type = eNameMatchIgnore;
+ m_match_all_users = false;
+}
+
+ProcessSP
+Process::FindPlugin (Target &target, const char *plugin_name, Listener &listener, const FileSpec *crash_file_path)
+{
+ static uint32_t g_process_unique_id = 0;
+
+ ProcessSP process_sp;
+ ProcessCreateInstance create_callback = NULL;
+ if (plugin_name)
+ {
+ ConstString const_plugin_name(plugin_name);
+ create_callback = PluginManager::GetProcessCreateCallbackForPluginName (const_plugin_name);
+ if (create_callback)
+ {
+ process_sp = create_callback(target, listener, crash_file_path);
+ if (process_sp)
+ {
+ if (process_sp->CanDebug(target, true))
+ {
+ process_sp->m_process_unique_id = ++g_process_unique_id;
+ }
+ else
+ process_sp.reset();
+ }
+ }
+ }
+ else
+ {
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ process_sp = create_callback(target, listener, crash_file_path);
+ if (process_sp)
+ {
+ if (process_sp->CanDebug(target, false))
+ {
+ process_sp->m_process_unique_id = ++g_process_unique_id;
+ break;
+ }
+ else
+ process_sp.reset();
+ }
+ }
+ }
+ return process_sp;
+}
+
+ConstString &
+Process::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.process");
+ return class_name;
+}
+
+//----------------------------------------------------------------------
+// Process constructor
+//----------------------------------------------------------------------
+Process::Process(Target &target, Listener &listener) :
+ ProcessProperties (false),
+ UserID (LLDB_INVALID_PROCESS_ID),
+ Broadcaster (&(target.GetDebugger()), "lldb.process"),
+ m_target (target),
+ m_public_state (eStateUnloaded),
+ m_private_state (eStateUnloaded),
+ m_private_state_broadcaster (NULL, "lldb.process.internal_state_broadcaster"),
+ 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_thread_mutex (Mutex::eMutexTypeRecursive),
+ m_thread_list_real (this),
+ m_thread_list (this),
+ m_notifications (),
+ m_image_tokens (),
+ m_listener (listener),
+ m_breakpoint_site_list (),
+ m_dynamic_checkers_ap (),
+ m_unix_signals (),
+ m_abi_sp (),
+ m_process_input_reader (),
+ m_stdio_communication ("process.stdio"),
+ m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
+ m_stdout_data (),
+ m_stderr_data (),
+ m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
+ m_profile_data (),
+ m_memory_cache (*this),
+ m_allocated_memory_cache (*this),
+ m_should_detach (false),
+ m_next_event_action_ap(),
+ m_public_run_lock (),
+ m_private_run_lock (),
+ m_currently_handling_event(false),
+ m_finalize_called(false),
+ m_clear_thread_plans_on_stop (false),
+ m_last_broadcast_state (eStateInvalid),
+ m_destroy_in_process (false),
+ m_can_jit(eCanJITDontKnow)
+{
+ CheckInWithManager ();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Process::Process()", this);
+
+ SetEventName (eBroadcastBitStateChanged, "state-changed");
+ SetEventName (eBroadcastBitInterrupt, "interrupt");
+ SetEventName (eBroadcastBitSTDOUT, "stdout-available");
+ SetEventName (eBroadcastBitSTDERR, "stderr-available");
+ SetEventName (eBroadcastBitProfileData, "profile-data-available");
+
+ m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlStop , "control-stop" );
+ m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlPause , "control-pause" );
+ m_private_state_control_broadcaster.SetEventName (eBroadcastInternalStateControlResume, "control-resume");
+
+ listener.StartListeningForEvents (this,
+ eBroadcastBitStateChanged |
+ eBroadcastBitInterrupt |
+ eBroadcastBitSTDOUT |
+ eBroadcastBitSTDERR |
+ eBroadcastBitProfileData);
+
+ m_private_state_listener.StartListeningForEvents(&m_private_state_broadcaster,
+ eBroadcastBitStateChanged |
+ eBroadcastBitInterrupt);
+
+ m_private_state_listener.StartListeningForEvents(&m_private_state_control_broadcaster,
+ eBroadcastInternalStateControlStop |
+ eBroadcastInternalStateControlPause |
+ eBroadcastInternalStateControlResume);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Process::~Process()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Process::~Process()", this);
+ StopPrivateStateThread();
+}
+
+const ProcessPropertiesSP &
+Process::GetGlobalProperties()
+{
+ static ProcessPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new ProcessProperties (true));
+ return g_settings_sp;
+}
+
+void
+Process::Finalize()
+{
+ switch (GetPrivateState())
+ {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStopped:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ if (GetShouldDetach())
+ {
+ // FIXME: This will have to be a process setting:
+ bool keep_stopped = false;
+ Detach(keep_stopped);
+ }
+ else
+ Destroy();
+ break;
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateDetached:
+ case eStateExited:
+ break;
+ }
+
+ // Clear our broadcaster before we proceed with destroying
+ Broadcaster::Clear();
+
+ // Do any cleanup needed prior to being destructed... Subclasses
+ // that override this method should call this superclass method as well.
+
+ // We need to destroy the loader before the derived Process class gets destroyed
+ // since it is very likely that undoing the loader will require access to the real process.
+ m_dynamic_checkers_ap.reset();
+ m_abi_sp.reset();
+ m_os_ap.reset();
+ m_dyld_ap.reset();
+ m_thread_list_real.Destroy();
+ m_thread_list.Destroy();
+ std::vector<Notifications> empty_notifications;
+ m_notifications.swap(empty_notifications);
+ m_image_tokens.clear();
+ m_memory_cache.Clear();
+ m_allocated_memory_cache.Clear();
+ m_language_runtimes.clear();
+ m_next_event_action_ap.reset();
+//#ifdef LLDB_CONFIGURATION_DEBUG
+// StreamFile s(stdout, false);
+// EventSP event_sp;
+// while (m_private_state_listener.GetNextEvent(event_sp))
+// {
+// event_sp->Dump (&s);
+// s.EOL();
+// }
+//#endif
+ // We have to be very careful here as the m_private_state_listener might
+ // contain events that have ProcessSP values in them which can keep this
+ // process around forever. These events need to be cleared out.
+ m_private_state_listener.Clear();
+ m_public_run_lock.TrySetRunning(); // This will do nothing if already locked
+ m_public_run_lock.SetStopped();
+ m_private_run_lock.TrySetRunning(); // This will do nothing if already locked
+ m_private_run_lock.SetStopped();
+ m_finalize_called = true;
+}
+
+void
+Process::RegisterNotificationCallbacks (const Notifications& callbacks)
+{
+ m_notifications.push_back(callbacks);
+ if (callbacks.initialize != NULL)
+ callbacks.initialize (callbacks.baton, this);
+}
+
+bool
+Process::UnregisterNotificationCallbacks(const Notifications& callbacks)
+{
+ std::vector<Notifications>::iterator pos, end = m_notifications.end();
+ for (pos = m_notifications.begin(); pos != end; ++pos)
+ {
+ if (pos->baton == callbacks.baton &&
+ pos->initialize == callbacks.initialize &&
+ pos->process_state_changed == callbacks.process_state_changed)
+ {
+ m_notifications.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+Process::SynchronouslyNotifyStateChanged (StateType state)
+{
+ std::vector<Notifications>::iterator notification_pos, notification_end = m_notifications.end();
+ for (notification_pos = m_notifications.begin(); notification_pos != notification_end; ++notification_pos)
+ {
+ if (notification_pos->process_state_changed)
+ notification_pos->process_state_changed (notification_pos->baton, this, state);
+ }
+}
+
+// FIXME: We need to do some work on events before the general Listener sees them.
+// For instance if we are continuing from a breakpoint, we need to ensure that we do
+// the little "insert real insn, step & stop" trick. But we can't do that when the
+// event is delivered by the broadcaster - since that is done on the thread that is
+// waiting for new events, so if we needed more than one event for our handling, we would
+// stall. So instead we do it when we fetch the event off of the queue.
+//
+
+StateType
+Process::GetNextEvent (EventSP &event_sp)
+{
+ StateType state = eStateInvalid;
+
+ if (m_listener.GetNextEventForBroadcaster (this, event_sp) && event_sp)
+ state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+
+ return state;
+}
+
+
+StateType
+Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr)
+{
+ // 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
+ // on the event.
+ if (event_sp_ptr)
+ event_sp_ptr->reset();
+ StateType state = GetState();
+ // If we are exited or detached, we won't ever get back to any
+ // other valid state...
+ if (state == eStateDetached || state == eStateExited)
+ return state;
+
+ while (state != eStateInvalid)
+ {
+ EventSP event_sp;
+ state = WaitForStateChangedEvents (timeout, event_sp);
+ if (event_sp_ptr && event_sp)
+ *event_sp_ptr = event_sp;
+
+ switch (state)
+ {
+ case eStateCrashed:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ return state;
+ case eStateStopped:
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ continue;
+ else
+ return state;
+ default:
+ continue;
+ }
+ }
+ return state;
+}
+
+
+StateType
+Process::WaitForState
+(
+ const TimeValue *timeout,
+ const StateType *match_states, const uint32_t num_match_states
+)
+{
+ EventSP event_sp;
+ uint32_t i;
+ StateType state = GetState();
+ while (state != eStateInvalid)
+ {
+ // If we are exited or detached, we won't ever get back to any
+ // other valid state...
+ if (state == eStateDetached || state == eStateExited)
+ return state;
+
+ state = WaitForStateChangedEvents (timeout, event_sp);
+
+ for (i=0; i<num_match_states; ++i)
+ {
+ if (match_states[i] == state)
+ return state;
+ }
+ }
+ return state;
+}
+
+bool
+Process::HijackProcessEvents (Listener *listener)
+{
+ if (listener != NULL)
+ {
+ return HijackBroadcaster(listener, eBroadcastBitStateChanged | eBroadcastBitInterrupt);
+ }
+ else
+ return false;
+}
+
+void
+Process::RestoreProcessEvents ()
+{
+ RestoreBroadcaster();
+}
+
+bool
+Process::HijackPrivateProcessEvents (Listener *listener)
+{
+ if (listener != NULL)
+ {
+ return m_private_state_broadcaster.HijackBroadcaster(listener, eBroadcastBitStateChanged | eBroadcastBitInterrupt);
+ }
+ else
+ return false;
+}
+
+void
+Process::RestorePrivateProcessEvents ()
+{
+ m_private_state_broadcaster.RestoreBroadcaster();
+}
+
+StateType
+Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ StateType state = eStateInvalid;
+ if (m_listener.WaitForEventForBroadcasterWithType (timeout,
+ this,
+ eBroadcastBitStateChanged | eBroadcastBitInterrupt,
+ event_sp))
+ {
+ if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ else if (log)
+ log->Printf ("Process::%s got no event or was interrupted.", __FUNCTION__);
+ }
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
+ __FUNCTION__,
+ timeout,
+ StateAsCString(state));
+ return state;
+}
+
+Event *
+Process::PeekAtStateChangedEvents ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s...", __FUNCTION__);
+
+ Event *event_ptr;
+ event_ptr = m_listener.PeekAtNextEventForBroadcasterWithType (this,
+ eBroadcastBitStateChanged);
+ if (log)
+ {
+ if (event_ptr)
+ {
+ log->Printf ("Process::%s (event_ptr) => %s",
+ __FUNCTION__,
+ StateAsCString(ProcessEventData::GetStateFromEvent (event_ptr)));
+ }
+ else
+ {
+ log->Printf ("Process::%s no events found",
+ __FUNCTION__);
+ }
+ }
+ return event_ptr;
+}
+
+StateType
+Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &event_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ StateType state = eStateInvalid;
+ if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout,
+ &m_private_state_broadcaster,
+ eBroadcastBitStateChanged | eBroadcastBitInterrupt,
+ event_sp))
+ if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ // This is a bit of a hack, but when we wait here we could very well return
+ // to the command-line, and that could disable the log, which would render the
+ // log we got above invalid.
+ if (log)
+ {
+ if (state == eStateInvalid)
+ log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout);
+ else
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
+ }
+ return state;
+}
+
+bool
+Process::WaitForEventsPrivate (const TimeValue *timeout, EventSP &event_sp, bool control_only)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+
+ if (control_only)
+ return m_private_state_listener.WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp);
+ else
+ return m_private_state_listener.WaitForEvent(timeout, event_sp);
+}
+
+bool
+Process::IsRunning () const
+{
+ return StateIsRunningState (m_public_state.GetValue());
+}
+
+int
+Process::GetExitStatus ()
+{
+ if (m_public_state.GetValue() == eStateExited)
+ return m_exit_status;
+ return -1;
+}
+
+
+const char *
+Process::GetExitDescription ()
+{
+ if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
+ return m_exit_string.c_str();
+ return NULL;
+}
+
+bool
+Process::SetExitStatus (int status, const char *cstr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)",
+ status, status,
+ cstr ? "\"" : "",
+ cstr ? cstr : "NULL",
+ cstr ? "\"" : "");
+
+ // We were already in the exited state
+ if (m_private_state.GetValue() == eStateExited)
+ {
+ if (log)
+ log->Printf("Process::SetExitStatus () ignoring exit status because state was already set to eStateExited");
+ return false;
+ }
+
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ DidExit ();
+
+ SetPrivateState (eStateExited);
+ return true;
+}
+
+// This static callback can be used to watch for local child processes on
+// the current host. The the child process exits, the process will be
+// found in the global target list (we want to be completely sure that the
+// lldb_private::Process doesn't go away before we can deliver the signal.
+bool
+Process::SetProcessExitStatus (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::SetProcessExitStatus (baton=%p, pid=%" PRIu64 ", exited=%i, signal=%i, exit_status=%i)\n",
+ callback_baton,
+ pid,
+ exited,
+ signo,
+ exit_status);
+
+ if (exited)
+ {
+ TargetSP target_sp(Debugger::FindTargetWithProcessID (pid));
+ if (target_sp)
+ {
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ if (process_sp)
+ {
+ const char *signal_cstr = NULL;
+ if (signo)
+ signal_cstr = process_sp->GetUnixSignals().GetSignalAsCString (signo);
+
+ process_sp->SetExitStatus (exit_status, signal_cstr);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+void
+Process::UpdateThreadListIfNeeded ()
+{
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
+ {
+ const StateType state = GetPrivateState();
+ if (StateIsStoppedState (state, true))
+ {
+ Mutex::Locker locker (m_thread_list.GetMutex ());
+ // m_thread_list does have its own mutex, but we need to
+ // hold onto the mutex between the call to UpdateThreadList(...)
+ // and the os->UpdateThreadList(...) so it doesn't change on us
+ ThreadList &old_thread_list = m_thread_list;
+ ThreadList real_thread_list(this);
+ ThreadList new_thread_list(this);
+ // Always update the thread list with the protocol specific
+ // thread list, but only update if "true" is returned
+ if (UpdateThreadList (m_thread_list_real, real_thread_list))
+ {
+ // Don't call into the OperatingSystem to update the thread list if we are shutting down, since
+ // that may call back into the SBAPI's, requiring the API lock which is already held by whoever is
+ // shutting us down, causing a deadlock.
+ if (!m_destroy_in_process)
+ {
+ OperatingSystem *os = GetOperatingSystem ();
+ if (os)
+ {
+ // Clear any old backing threads where memory threads might have been
+ // backed by actual threads from the lldb_private::Process subclass
+ size_t num_old_threads = old_thread_list.GetSize(false);
+ for (size_t i=0; i<num_old_threads; ++i)
+ old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread();
+
+ // Now let the OperatingSystem plug-in update the thread list
+ os->UpdateThreadList (old_thread_list, // Old list full of threads created by OS plug-in
+ real_thread_list, // The actual thread list full of threads created by each lldb_private::Process subclass
+ new_thread_list); // The new thread list that we will show to the user that gets filled in
+ }
+ else
+ {
+ // No OS plug-in, the new thread list is the same as the real thread list
+ new_thread_list = real_thread_list;
+ }
+ }
+
+ m_thread_list_real.Update(real_thread_list);
+ m_thread_list.Update (new_thread_list);
+ m_thread_list.SetStopID (stop_id);
+ }
+ }
+ }
+}
+
+ThreadSP
+Process::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context)
+{
+ OperatingSystem *os = GetOperatingSystem ();
+ if (os)
+ return os->CreateThread(tid, context);
+ return ThreadSP();
+}
+
+uint32_t
+Process::GetNextThreadIndexID (uint64_t thread_id)
+{
+ return AssignIndexIDToThread(thread_id);
+}
+
+bool
+Process::HasAssignedIndexIDToThread(uint64_t thread_id)
+{
+ std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_index_id_map.find(thread_id);
+ if (iterator == m_thread_id_to_index_id_map.end())
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+uint32_t
+Process::AssignIndexIDToThread(uint64_t thread_id)
+{
+ uint32_t result = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_index_id_map.find(thread_id);
+ if (iterator == m_thread_id_to_index_id_map.end())
+ {
+ result = ++m_thread_index_id;
+ m_thread_id_to_index_id_map[thread_id] = result;
+ }
+ else
+ {
+ result = iterator->second;
+ }
+
+ return result;
+}
+
+StateType
+Process::GetState()
+{
+ // If any other threads access this we will need a mutex for it
+ return m_public_state.GetValue ();
+}
+
+void
+Process::SetPublicState (StateType new_state, bool restarted)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::SetPublicState (state = %s, restarted = %i)", StateAsCString(new_state), restarted);
+ const StateType old_state = m_public_state.GetValue();
+ m_public_state.SetValue (new_state);
+
+ // 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 (new_state == eStateDetached)
+ {
+ if (log)
+ log->Printf("Process::SetPublicState (%s) -- unlocking run lock for detach", StateAsCString(new_state));
+ m_public_run_lock.SetStopped();
+ }
+ else
+ {
+ const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+ const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+ if ((old_state_is_stopped != new_state_is_stopped))
+ {
+ if (new_state_is_stopped && !restarted)
+ {
+ if (log)
+ log->Printf("Process::SetPublicState (%s) -- unlocking run lock", StateAsCString(new_state));
+ m_public_run_lock.SetStopped();
+ }
+ }
+ }
+ }
+}
+
+Error
+Process::Resume ()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Resume -- 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;
+ }
+ return PrivateResume();
+}
+
+StateType
+Process::GetPrivateState ()
+{
+ return m_private_state.GetValue();
+}
+
+void
+Process::SetPrivateState (StateType new_state)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ bool state_changed = false;
+
+ if (log)
+ log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state));
+
+ Mutex::Locker thread_locker(m_thread_list.GetMutex());
+ Mutex::Locker locker(m_private_state.GetMutex());
+
+ const StateType old_state = m_private_state.GetValueNoLock ();
+ state_changed = old_state != new_state;
+
+ const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+ const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+ if (old_state_is_stopped != new_state_is_stopped)
+ {
+ if (new_state_is_stopped)
+ m_private_run_lock.SetStopped();
+ else
+ m_private_run_lock.SetRunning();
+ }
+
+ if (state_changed)
+ {
+ m_private_state.SetValueNoLock (new_state);
+ if (StateIsStoppedState(new_state, false))
+ {
+ // Note, this currently assumes that all threads in the list
+ // stop when the process stops. In the future we will want to
+ // support a debugging model where some threads continue to run
+ // while others are stopped. When that happens we will either need
+ // a way for the thread list to identify which threads are stopping
+ // or create a special thread list containing only threads which
+ // actually stopped.
+ //
+ // The process plugin is responsible for managing the actual
+ // behavior of the threads and should have stopped any threads
+ // that are going to stop before we get here.
+ m_thread_list.DidStop();
+
+ m_mod_id.BumpStopID();
+ m_memory_cache.Clear();
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_mod_id.GetStopID());
+ }
+ // Use our target to get a shared pointer to ourselves...
+ if (m_finalize_called && PrivateStateThreadIsValid() == false)
+ BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ else
+ m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ }
+ else
+ {
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) state didn't change. Ignoring...", StateAsCString(new_state));
+ }
+}
+
+void
+Process::SetRunningUserExpression (bool on)
+{
+ m_mod_id.SetRunningUserExpression (on);
+}
+
+addr_t
+Process::GetImageInfoAddress()
+{
+ return LLDB_INVALID_ADDRESS;
+}
+
+//----------------------------------------------------------------------
+// LoadImage
+//
+// This function provides a default implementation that works for most
+// unix variants. Any Process subclasses that need to do shared library
+// loading differently should override LoadImage and UnloadImage and
+// do what is needed.
+//----------------------------------------------------------------------
+uint32_t
+Process::LoadImage (const FileSpec &image_spec, Error &error)
+{
+ char path[PATH_MAX];
+ image_spec.GetPath(path, sizeof(path));
+
+ DynamicLoader *loader = GetDynamicLoader();
+ if (loader)
+ {
+ error = loader->CanLoadImage();
+ if (error.Fail())
+ return LLDB_INVALID_IMAGE_TOKEN;
+ }
+
+ if (error.Success())
+ {
+ ThreadSP thread_sp(GetThreadList ().GetSelectedThread());
+
+ if (thread_sp)
+ {
+ StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex (0));
+
+ if (frame_sp)
+ {
+ ExecutionContext exe_ctx;
+ frame_sp->CalculateExecutionContext (exe_ctx);
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ StreamString expr;
+ expr.Printf("dlopen (\"%s\", 2)", path);
+ const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n";
+ lldb::ValueObjectSP result_valobj_sp;
+ ClangUserExpression::Evaluate (exe_ctx,
+ eExecutionPolicyAlways,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny,
+ unwind_on_error,
+ ignore_breakpoints,
+ expr.GetData(),
+ prefix,
+ result_valobj_sp,
+ true,
+ ClangUserExpression::kDefaultTimeout);
+ error = result_valobj_sp->GetError();
+ if (error.Success())
+ {
+ Scalar scalar;
+ if (result_valobj_sp->ResolveValue (scalar))
+ {
+ addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
+ if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
+ {
+ uint32_t image_token = m_image_tokens.size();
+ m_image_tokens.push_back (image_ptr);
+ return image_token;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!error.AsCString())
+ error.SetErrorStringWithFormat("unable to load '%s'", path);
+ return LLDB_INVALID_IMAGE_TOKEN;
+}
+
+//----------------------------------------------------------------------
+// UnloadImage
+//
+// This function provides a default implementation that works for most
+// unix variants. Any Process subclasses that need to do shared library
+// loading differently should override LoadImage and UnloadImage and
+// do what is needed.
+//----------------------------------------------------------------------
+Error
+Process::UnloadImage (uint32_t image_token)
+{
+ Error error;
+ if (image_token < m_image_tokens.size())
+ {
+ const addr_t image_addr = m_image_tokens[image_token];
+ if (image_addr == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString("image already unloaded");
+ }
+ else
+ {
+ DynamicLoader *loader = GetDynamicLoader();
+ if (loader)
+ error = loader->CanLoadImage();
+
+ if (error.Success())
+ {
+ ThreadSP thread_sp(GetThreadList ().GetSelectedThread());
+
+ if (thread_sp)
+ {
+ StackFrameSP frame_sp (thread_sp->GetStackFrameAtIndex (0));
+
+ if (frame_sp)
+ {
+ ExecutionContext exe_ctx;
+ frame_sp->CalculateExecutionContext (exe_ctx);
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ StreamString expr;
+ expr.Printf("dlclose ((void *)0x%" PRIx64 ")", image_addr);
+ const char *prefix = "extern \"C\" int dlclose(void* handle);\n";
+ lldb::ValueObjectSP result_valobj_sp;
+ ClangUserExpression::Evaluate (exe_ctx,
+ eExecutionPolicyAlways,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny,
+ unwind_on_error,
+ ignore_breakpoints,
+ expr.GetData(),
+ prefix,
+ result_valobj_sp,
+ true,
+ ClangUserExpression::kDefaultTimeout);
+ if (result_valobj_sp->GetError().Success())
+ {
+ Scalar scalar;
+ if (result_valobj_sp->ResolveValue (scalar))
+ {
+ if (scalar.UInt(1))
+ {
+ error.SetErrorStringWithFormat("expression failed: \"%s\"", expr.GetData());
+ }
+ else
+ {
+ m_image_tokens[image_token] = LLDB_INVALID_ADDRESS;
+ }
+ }
+ }
+ else
+ {
+ error = result_valobj_sp->GetError();
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("invalid image token");
+ }
+ return error;
+}
+
+const lldb::ABISP &
+Process::GetABI()
+{
+ if (!m_abi_sp)
+ m_abi_sp = ABI::FindPlugin(m_target.GetArchitecture());
+ return m_abi_sp;
+}
+
+LanguageRuntime *
+Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null)
+{
+ LanguageRuntimeCollection::iterator pos;
+ pos = m_language_runtimes.find (language);
+ if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second))
+ {
+ lldb::LanguageRuntimeSP runtime_sp(LanguageRuntime::FindPlugin(this, language));
+
+ m_language_runtimes[language] = runtime_sp;
+ return runtime_sp.get();
+ }
+ else
+ return (*pos).second.get();
+}
+
+CPPLanguageRuntime *
+Process::GetCPPLanguageRuntime (bool retry_if_null)
+{
+ LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null);
+ if (runtime != NULL && runtime->GetLanguageType() == eLanguageTypeC_plus_plus)
+ return static_cast<CPPLanguageRuntime *> (runtime);
+ return NULL;
+}
+
+ObjCLanguageRuntime *
+Process::GetObjCLanguageRuntime (bool retry_if_null)
+{
+ LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeObjC, retry_if_null);
+ if (runtime != NULL && runtime->GetLanguageType() == eLanguageTypeObjC)
+ return static_cast<ObjCLanguageRuntime *> (runtime);
+ return NULL;
+}
+
+bool
+Process::IsPossibleDynamicValue (ValueObject& in_value)
+{
+ if (in_value.IsDynamic())
+ return false;
+ LanguageType known_type = in_value.GetObjectRuntimeLanguage();
+
+ if (known_type != eLanguageTypeUnknown && known_type != eLanguageTypeC)
+ {
+ LanguageRuntime *runtime = GetLanguageRuntime (known_type);
+ return runtime ? runtime->CouldHaveDynamicValue(in_value) : false;
+ }
+
+ LanguageRuntime *cpp_runtime = GetLanguageRuntime (eLanguageTypeC_plus_plus);
+ if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value))
+ return true;
+
+ LanguageRuntime *objc_runtime = GetLanguageRuntime (eLanguageTypeObjC);
+ return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false;
+}
+
+BreakpointSiteList &
+Process::GetBreakpointSiteList()
+{
+ return m_breakpoint_site_list;
+}
+
+const BreakpointSiteList &
+Process::GetBreakpointSiteList() const
+{
+ return m_breakpoint_site_list;
+}
+
+
+void
+Process::DisableAllBreakpointSites ()
+{
+ m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void {
+// bp_site->SetEnabled(true);
+ DisableBreakpointSite(bp_site);
+ });
+}
+
+Error
+Process::ClearBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error (DisableBreakpointSiteByID (break_id));
+
+ if (error.Success())
+ m_breakpoint_site_list.Remove(break_id);
+
+ return error;
+}
+
+Error
+Process::DisableBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
+ if (bp_site_sp)
+ {
+ if (bp_site_sp->IsEnabled())
+ error = DisableBreakpointSite (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id);
+ }
+
+ return error;
+}
+
+Error
+Process::EnableBreakpointSiteByID (lldb::user_id_t break_id)
+{
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
+ if (bp_site_sp)
+ {
+ if (!bp_site_sp->IsEnabled())
+ error = EnableBreakpointSite (bp_site_sp.get());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id);
+ }
+ return error;
+}
+
+lldb::break_id_t
+Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware)
+{
+ const addr_t load_addr = owner->GetAddress().GetOpcodeLoadAddress (&m_target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ BreakpointSiteSP bp_site_sp;
+
+ // Look up this breakpoint site. If it exists, then add this new owner, otherwise
+ // create a new breakpoint site and add it.
+
+ bp_site_sp = m_breakpoint_site_list.FindByAddress (load_addr);
+
+ if (bp_site_sp)
+ {
+ bp_site_sp->AddOwner (owner);
+ owner->SetBreakpointSite (bp_site_sp);
+ return bp_site_sp->GetID();
+ }
+ else
+ {
+ bp_site_sp.reset (new BreakpointSite (&m_breakpoint_site_list, owner, load_addr, use_hardware));
+ if (bp_site_sp)
+ {
+ if (EnableBreakpointSite (bp_site_sp.get()).Success())
+ {
+ owner->SetBreakpointSite (bp_site_sp);
+ return m_breakpoint_site_list.Add (bp_site_sp);
+ }
+ }
+ }
+ }
+ // We failed to enable the breakpoint
+ return LLDB_INVALID_BREAK_ID;
+
+}
+
+void
+Process::RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, lldb::user_id_t owner_loc_id, BreakpointSiteSP &bp_site_sp)
+{
+ uint32_t num_owners = bp_site_sp->RemoveOwner (owner_id, owner_loc_id);
+ if (num_owners == 0)
+ {
+ // Don't try to disable the site if we don't have a live process anymore.
+ if (IsAlive())
+ DisableBreakpointSite (bp_site_sp.get());
+ m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress());
+ }
+}
+
+
+size_t
+Process::RemoveBreakpointOpcodesFromBuffer (addr_t bp_addr, size_t size, uint8_t *buf) const
+{
+ size_t bytes_removed = 0;
+ BreakpointSiteList bp_sites_in_range;
+
+ if (m_breakpoint_site_list.FindInRange (bp_addr, bp_addr + size, bp_sites_in_range))
+ {
+ bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed](BreakpointSite *bp_site) -> void {
+ if (bp_site->GetType() == BreakpointSite::eSoftware)
+ {
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr, &intersect_size, &opcode_offset))
+ {
+ assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
+ assert(bp_addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= bp_addr + size);
+ assert(opcode_offset + intersect_size <= bp_site->GetByteSize());
+ size_t buf_offset = intersect_addr - bp_addr;
+ ::memcpy(buf + buf_offset, bp_site->GetSavedOpcodeBytes() + opcode_offset, intersect_size);
+ }
+ }
+ });
+ }
+ return bytes_removed;
+}
+
+
+
+size_t
+Process::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
+{
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp)
+ return platform_sp->GetSoftwareBreakpointTrapOpcode (m_target, bp_site);
+ return 0;
+}
+
+Error
+Process::EnableSoftwareBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ const addr_t bp_addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64, bp_site->GetID(), (uint64_t)bp_addr);
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already enabled", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (bp_addr == LLDB_INVALID_ADDRESS)
+ {
+ error.SetErrorString("BreakpointSite contains an invalid load address.");
+ return error;
+ }
+ // Ask the lldb::Process subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site
+ const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ if (bp_opcode_size == 0)
+ {
+ error.SetErrorStringWithFormat ("Process::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, bp_addr);
+ }
+ else
+ {
+ const uint8_t * const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes();
+
+ if (bp_opcode_bytes == NULL)
+ {
+ error.SetErrorString ("BreakpointSite doesn't contain a valid breakpoint trap opcode.");
+ return error;
+ }
+
+ // Save the original opcode by reading it
+ if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size, error) == bp_opcode_size)
+ {
+ // Write a software breakpoint in place of the original opcode
+ if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
+ {
+ uint8_t verify_bp_opcode_bytes[64];
+ if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
+ {
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eSoftware);
+ if (log)
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS",
+ bp_site->GetID(),
+ (uint64_t)bp_addr);
+ }
+ else
+ error.SetErrorString("failed to verify the breakpoint trap in memory.");
+ }
+ else
+ error.SetErrorString("Unable to read memory to verify breakpoint trap.");
+ }
+ else
+ error.SetErrorString("Unable to write breakpoint trap to memory.");
+ }
+ else
+ error.SetErrorString("Unable to read memory at breakpoint address.");
+ }
+ if (log && error.Fail())
+ log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s",
+ bp_site->GetID(),
+ (uint64_t)bp_addr,
+ error.AsCString());
+ return error;
+}
+
+Error
+Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ addr_t bp_addr = bp_site->GetLoadAddress();
+ lldb::user_id_t breakID = bp_site->GetID();
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (breakID = %" PRIu64 ") addr = 0x%" PRIx64, breakID, (uint64_t)bp_addr);
+
+ if (bp_site->IsHardware())
+ {
+ error.SetErrorString("Breakpoint site is a hardware breakpoint.");
+ }
+ else if (bp_site->IsEnabled())
+ {
+ const size_t break_op_size = bp_site->GetByteSize();
+ const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();
+ if (break_op_size > 0)
+ {
+ // Clear a software breakoint instruction
+ uint8_t curr_break_op[8];
+ assert (break_op_size <= sizeof(curr_break_op));
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size)
+ {
+ bool verify = false;
+ // Make sure we have the a breakpoint opcode exists at this address
+ if (::memcmp (curr_break_op, break_op, break_op_size) == 0)
+ {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ if (DoWriteMemory (bp_addr, bp_site->GetSavedOpcodeBytes(), break_op_size, error) == break_op_size)
+ {
+ verify = true;
+ }
+ else
+ error.SetErrorString("Memory write failed when restoring original opcode.");
+ }
+ else
+ {
+ error.SetErrorString("Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has already been restored
+ verify = true;
+ }
+
+ if (verify)
+ {
+ uint8_t verify_opcode[8];
+ assert (break_op_size < sizeof(verify_opcode));
+ // Verify that our original opcode made it back to the inferior
+ if (DoReadMemory (bp_addr, verify_opcode, break_op_size, error) == break_op_size)
+ {
+ // compare the memory we just read with the original opcode
+ if (::memcmp (bp_site->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
+ {
+ // SUCCESS
+ bp_site->SetEnabled(false);
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+ else
+ {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ }
+ else
+ error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
+ }
+ }
+ else
+ error.SetErrorString("Unable to read memory that should contain the breakpoint trap.");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already disabled", bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (log)
+ log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s",
+ bp_site->GetID(),
+ (uint64_t)bp_addr,
+ error.AsCString());
+ return error;
+
+}
+
+// Uncomment to verify memory caching works after making changes to caching code
+//#define VERIFY_MEMORY_READS
+
+size_t
+Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (!GetDisableMemoryCache())
+ {
+#if defined (VERIFY_MEMORY_READS)
+ // Memory caching is enabled, with debug verification
+
+ if (buf && size)
+ {
+ // Uncomment the line below to make sure memory caching is working.
+ // I ran this through the test suite and got no assertions, so I am
+ // pretty confident this is working well. If any changes are made to
+ // memory caching, uncomment the line below and test your changes!
+
+ // Verify all memory reads by using the cache first, then redundantly
+ // reading the same memory from the inferior and comparing to make sure
+ // everything is exactly the same.
+ std::string verify_buf (size, '\0');
+ assert (verify_buf.size() == size);
+ const size_t cache_bytes_read = m_memory_cache.Read (this, addr, buf, size, error);
+ Error verify_error;
+ const size_t verify_bytes_read = ReadMemoryFromInferior (addr, const_cast<char *>(verify_buf.data()), verify_buf.size(), verify_error);
+ assert (cache_bytes_read == verify_bytes_read);
+ assert (memcmp(buf, verify_buf.data(), verify_buf.size()) == 0);
+ assert (verify_error.Success() == error.Success());
+ return cache_bytes_read;
+ }
+ return 0;
+#else // !defined(VERIFY_MEMORY_READS)
+ // Memory caching is enabled, without debug verification
+
+ return m_memory_cache.Read (addr, buf, size, error);
+#endif // defined (VERIFY_MEMORY_READS)
+ }
+ else
+ {
+ // Memory caching is disabled
+
+ return ReadMemoryFromInferior (addr, buf, size, error);
+ }
+}
+
+size_t
+Process::ReadCStringFromMemory (addr_t addr, std::string &out_str, Error &error)
+{
+ char buf[256];
+ out_str.clear();
+ addr_t curr_addr = addr;
+ while (1)
+ {
+ size_t length = ReadCStringFromMemory (curr_addr, buf, sizeof(buf), error);
+ if (length == 0)
+ break;
+ out_str.append(buf, length);
+ // If we got "length - 1" bytes, we didn't get the whole C string, we
+ // need to read some more characters
+ if (length == sizeof(buf) - 1)
+ curr_addr += length;
+ else
+ break;
+ }
+ return out_str.size();
+}
+
+
+size_t
+Process::ReadStringFromMemory (addr_t addr, char *dst, size_t max_bytes, Error &error,
+ size_t type_width)
+{
+ size_t total_bytes_read = 0;
+ if (dst && max_bytes && type_width && max_bytes >= type_width)
+ {
+ // Ensure a null terminator independent of the number of bytes that is read.
+ memset (dst, 0, max_bytes);
+ size_t bytes_left = max_bytes - type_width;
+
+ const char terminator[4] = {'\0', '\0', '\0', '\0'};
+ assert(sizeof(terminator) >= type_width &&
+ "Attempting to validate a string with more than 4 bytes per character!");
+
+ addr_t curr_addr = addr;
+ const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
+ char *curr_dst = dst;
+
+ error.Clear();
+ while (bytes_left > 0 && error.Success())
+ {
+ addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error);
+
+ if (bytes_read == 0)
+ break;
+
+ // Search for a null terminator of correct size and alignment in bytes_read
+ size_t aligned_start = total_bytes_read - total_bytes_read % type_width;
+ for (size_t i = aligned_start; i + type_width <= total_bytes_read + bytes_read; i += type_width)
+ if (::strncmp(&dst[i], terminator, type_width) == 0)
+ {
+ error.Clear();
+ return i;
+ }
+
+ total_bytes_read += bytes_read;
+ curr_dst += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ }
+ }
+ else
+ {
+ if (max_bytes)
+ error.SetErrorString("invalid arguments");
+ }
+ return total_bytes_read;
+}
+
+// Deprecated in favor of ReadStringFromMemory which has wchar support and correct code to find
+// null terminators.
+size_t
+Process::ReadCStringFromMemory (addr_t addr, char *dst, size_t dst_max_len, Error &result_error)
+{
+ size_t total_cstr_len = 0;
+ if (dst && dst_max_len)
+ {
+ result_error.Clear();
+ // NULL out everything just to be safe
+ memset (dst, 0, dst_max_len);
+ Error error;
+ addr_t curr_addr = addr;
+ const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
+ size_t bytes_left = dst_max_len - 1;
+ char *curr_dst = dst;
+
+ while (bytes_left > 0)
+ {
+ addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error);
+
+ if (bytes_read == 0)
+ {
+ result_error = error;
+ dst[total_cstr_len] = '\0';
+ break;
+ }
+ const size_t len = strlen(curr_dst);
+
+ total_cstr_len += len;
+
+ if (len < bytes_to_read)
+ break;
+
+ curr_dst += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ }
+ }
+ else
+ {
+ if (dst == NULL)
+ result_error.SetErrorString("invalid arguments");
+ else
+ result_error.Clear();
+ }
+ return total_cstr_len;
+}
+
+size_t
+Process::ReadMemoryFromInferior (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (buf == NULL || size == 0)
+ return 0;
+
+ size_t bytes_read = 0;
+ uint8_t *bytes = (uint8_t *)buf;
+
+ while (bytes_read < size)
+ {
+ const size_t curr_size = size - bytes_read;
+ const size_t curr_bytes_read = DoReadMemory (addr + bytes_read,
+ bytes + bytes_read,
+ curr_size,
+ error);
+ bytes_read += curr_bytes_read;
+ if (curr_bytes_read == curr_size || curr_bytes_read == 0)
+ break;
+ }
+
+ // Replace any software breakpoint opcodes that fall into this range back
+ // into "buf" before we return
+ if (bytes_read > 0)
+ RemoveBreakpointOpcodesFromBuffer (addr, bytes_read, (uint8_t *)buf);
+ return bytes_read;
+}
+
+uint64_t
+Process::ReadUnsignedIntegerFromMemory (lldb::addr_t vm_addr, size_t integer_byte_size, uint64_t fail_value, Error &error)
+{
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar, error))
+ return scalar.ULongLong(fail_value);
+ return fail_value;
+}
+
+addr_t
+Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error)
+{
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar, error))
+ return scalar.ULongLong(LLDB_INVALID_ADDRESS);
+ return LLDB_INVALID_ADDRESS;
+}
+
+
+bool
+Process::WritePointerToMemory (lldb::addr_t vm_addr,
+ lldb::addr_t ptr_value,
+ Error &error)
+{
+ Scalar scalar;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ if (addr_byte_size <= 4)
+ scalar = (uint32_t)ptr_value;
+ else
+ scalar = ptr_value;
+ return WriteScalarToMemory(vm_addr, scalar, addr_byte_size, error) == addr_byte_size;
+}
+
+size_t
+Process::WriteMemoryPrivate (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ size_t bytes_written = 0;
+ const uint8_t *bytes = (const uint8_t *)buf;
+
+ while (bytes_written < size)
+ {
+ const size_t curr_size = size - bytes_written;
+ const size_t curr_bytes_written = DoWriteMemory (addr + bytes_written,
+ bytes + bytes_written,
+ curr_size,
+ error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written == curr_size || curr_bytes_written == 0)
+ break;
+ }
+ return bytes_written;
+}
+
+size_t
+Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+#if defined (ENABLE_MEMORY_CACHING)
+ m_memory_cache.Flush (addr, size);
+#endif
+
+ if (buf == NULL || size == 0)
+ return 0;
+
+ m_mod_id.BumpMemoryID();
+
+ // We need to write any data that would go where any current software traps
+ // (enabled software breakpoints) any software traps (breakpoints) that we
+ // may have placed in our tasks memory.
+
+ BreakpointSiteList bp_sites_in_range;
+
+ if (m_breakpoint_site_list.FindInRange (addr, addr + size, bp_sites_in_range))
+ {
+ // No breakpoint sites overlap
+ if (bp_sites_in_range.IsEmpty())
+ return WriteMemoryPrivate (addr, buf, size, error);
+ else
+ {
+ const uint8_t *ubuf = (const uint8_t *)buf;
+ uint64_t bytes_written = 0;
+
+ bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, &error](BreakpointSite *bp) -> void {
+
+ if (error.Success())
+ {
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ const bool intersects = bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset);
+ assert(intersects);
+ assert(addr <= intersect_addr && intersect_addr < addr + size);
+ assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
+ assert(opcode_offset + intersect_size <= bp->GetByteSize());
+
+ // Check for bytes before this breakpoint
+ const addr_t curr_addr = addr + bytes_written;
+ if (intersect_addr > curr_addr)
+ {
+ // There are some bytes before this breakpoint that we need to
+ // just write to memory
+ size_t curr_size = intersect_addr - curr_addr;
+ size_t curr_bytes_written = WriteMemoryPrivate (curr_addr,
+ ubuf + bytes_written,
+ curr_size,
+ error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written != curr_size)
+ {
+ // We weren't able to write all of the requested bytes, we
+ // are done looping and will return the number of bytes that
+ // we have written so far.
+ if (error.Success())
+ error.SetErrorToGenericError();
+ }
+ }
+ // Now write any bytes that would cover up any software breakpoints
+ // directly into the breakpoint opcode buffer
+ ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
+ bytes_written += intersect_size;
+ }
+ });
+
+ if (bytes_written < size)
+ bytes_written += WriteMemoryPrivate (addr + bytes_written,
+ ubuf + bytes_written,
+ size - bytes_written,
+ error);
+ }
+ }
+ else
+ {
+ return WriteMemoryPrivate (addr, buf, size, error);
+ }
+
+ // Write any remaining bytes after the last breakpoint if we have any left
+ return 0; //bytes_written;
+}
+
+size_t
+Process::WriteScalarToMemory (addr_t addr, const Scalar &scalar, size_t byte_size, Error &error)
+{
+ if (byte_size == UINT32_MAX)
+ byte_size = scalar.GetByteSize();
+ if (byte_size > 0)
+ {
+ uint8_t buf[32];
+ const size_t mem_size = scalar.GetAsMemoryData (buf, byte_size, GetByteOrder(), error);
+ if (mem_size > 0)
+ return WriteMemory(addr, buf, mem_size, error);
+ else
+ error.SetErrorString ("failed to get scalar as memory data");
+ }
+ else
+ {
+ error.SetErrorString ("invalid scalar value");
+ }
+ return 0;
+}
+
+size_t
+Process::ReadScalarIntegerFromMemory (addr_t addr,
+ uint32_t byte_size,
+ bool is_signed,
+ Scalar &scalar,
+ Error &error)
+{
+ uint64_t uval = 0;
+ if (byte_size == 0)
+ {
+ error.SetErrorString ("byte size is zero");
+ }
+ else if (byte_size & (byte_size - 1))
+ {
+ error.SetErrorStringWithFormat ("byte size %u is not a power of 2", byte_size);
+ }
+ else if (byte_size <= sizeof(uval))
+ {
+ const size_t bytes_read = ReadMemory (addr, &uval, byte_size, error);
+ if (bytes_read == byte_size)
+ {
+ DataExtractor data (&uval, sizeof(uval), GetByteOrder(), GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ if (byte_size <= 4)
+ scalar = data.GetMaxU32 (&offset, byte_size);
+ else
+ scalar = data.GetMaxU64 (&offset, byte_size);
+ if (is_signed)
+ scalar.SignExtend(byte_size * 8);
+ return bytes_read;
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("byte size of %u is too large for integer scalar type", byte_size);
+ }
+ return 0;
+}
+
+#define USE_ALLOCATE_MEMORY_CACHE 1
+addr_t
+Process::AllocateMemory(size_t size, uint32_t permissions, Error &error)
+{
+ if (GetPrivateState() != eStateStopped)
+ return LLDB_INVALID_ADDRESS;
+
+#if defined (USE_ALLOCATE_MEMORY_CACHE)
+ return m_allocated_memory_cache.AllocateMemory(size, permissions, error);
+#else
+ addr_t allocated_addr = DoAllocateMemory (size, permissions, error);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::AllocateMemory(size=%4zu, permissions=%s) => 0x%16.16" PRIx64 " (m_stop_id = %u m_memory_id = %u)",
+ size,
+ GetPermissionsAsCString (permissions),
+ (uint64_t)allocated_addr,
+ m_mod_id.GetStopID(),
+ m_mod_id.GetMemoryID());
+ return allocated_addr;
+#endif
+}
+
+bool
+Process::CanJIT ()
+{
+ if (m_can_jit == eCanJITDontKnow)
+ {
+ Error err;
+
+ uint64_t allocated_memory = AllocateMemory(8,
+ ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable,
+ err);
+
+ if (err.Success())
+ m_can_jit = eCanJITYes;
+ else
+ m_can_jit = eCanJITNo;
+
+ DeallocateMemory (allocated_memory);
+ }
+
+ return m_can_jit == eCanJITYes;
+}
+
+void
+Process::SetCanJIT (bool can_jit)
+{
+ m_can_jit = (can_jit ? eCanJITYes : eCanJITNo);
+}
+
+Error
+Process::DeallocateMemory (addr_t ptr)
+{
+ Error error;
+#if defined (USE_ALLOCATE_MEMORY_CACHE)
+ if (!m_allocated_memory_cache.DeallocateMemory(ptr))
+ {
+ error.SetErrorStringWithFormat ("deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr);
+ }
+#else
+ error = DoDeallocateMemory (ptr);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::DeallocateMemory(addr=0x%16.16" PRIx64 ") => err = %s (m_stop_id = %u, m_memory_id = %u)",
+ ptr,
+ error.AsCString("SUCCESS"),
+ m_mod_id.GetStopID(),
+ m_mod_id.GetMemoryID());
+#endif
+ return error;
+}
+
+
+ModuleSP
+Process::ReadModuleFromMemory (const FileSpec& file_spec,
+ lldb::addr_t header_addr)
+{
+ ModuleSP module_sp (new Module (file_spec, ArchSpec()));
+ if (module_sp)
+ {
+ Error error;
+ ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error);
+ if (objfile)
+ return module_sp;
+ }
+ return ModuleSP();
+}
+
+Error
+Process::EnableWatchpoint (Watchpoint *watchpoint, bool notify)
+{
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
+}
+
+Error
+Process::DisableWatchpoint (Watchpoint *watchpoint, bool notify)
+{
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
+}
+
+StateType
+Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp)
+{
+ StateType state;
+ // Now wait for the process to launch and return control to us, and then
+ // call DidLaunch:
+ while (1)
+ {
+ event_sp.reset();
+ state = WaitForStateChangedEventsPrivate (timeout, event_sp);
+
+ if (StateIsStoppedState(state, false))
+ break;
+
+ // If state is invalid, then we timed out
+ if (state == eStateInvalid)
+ break;
+
+ if (event_sp)
+ HandlePrivateEvent (event_sp);
+ }
+ return state;
+}
+
+Error
+Process::Launch (const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ m_abi_sp.reset();
+ m_dyld_ap.reset();
+ m_os_ap.reset();
+ m_process_input_reader.reset();
+
+ Module *exe_module = m_target.GetExecutableModulePointer();
+ if (exe_module)
+ {
+ char local_exec_file_path[PATH_MAX];
+ char platform_exec_file_path[PATH_MAX];
+ exe_module->GetFileSpec().GetPath(local_exec_file_path, sizeof(local_exec_file_path));
+ exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, sizeof(platform_exec_file_path));
+ if (exe_module->GetFileSpec().Exists())
+ {
+ if (PrivateStateThreadIsValid ())
+ PausePrivateStateThread ();
+
+ error = WillLaunch (exe_module);
+ if (error.Success())
+ {
+ const bool restarted = false;
+ SetPublicState (eStateLaunching, restarted);
+ m_should_detach = false;
+
+ if (m_public_run_lock.TrySetRunning())
+ {
+ // Now launch using these arguments.
+ error = DoLaunch (exe_module, launch_info);
+ }
+ else
+ {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Fail())
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ SetID (LLDB_INVALID_PROCESS_ID);
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "launch failed";
+ SetExitStatus (-1, error_string);
+ }
+ }
+ else
+ {
+ EventSP event_sp;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(10);
+ StateType state = WaitForProcessStopPrivate(&timeout_time, event_sp);
+
+ if (state == eStateInvalid || event_sp.get() == NULL)
+ {
+ // We were able to launch the process, but we failed to
+ // catch the initial stop.
+ SetExitStatus (0, "failed to catch stop after launch");
+ Destroy();
+ }
+ else if (state == eStateStopped || state == eStateCrashed)
+ {
+
+ DidLaunch ();
+
+ DynamicLoader *dyld = GetDynamicLoader ();
+ if (dyld)
+ dyld->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);
+
+ if (PrivateStateThreadIsValid ())
+ ResumePrivateStateThread ();
+ else
+ StartPrivateStateThread ();
+ }
+ else if (state == eStateExited)
+ {
+ // We exited while trying to launch somehow. Don't call DidLaunch as that's
+ // not likely to work, and return an invalid pid.
+ HandlePrivateEvent (event_sp);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("file doesn't exist: '%s'", local_exec_file_path);
+ }
+ }
+ return error;
+}
+
+
+Error
+Process::LoadCore ()
+{
+ Error error = DoLoadCore();
+ if (error.Success())
+ {
+ if (PrivateStateThreadIsValid ())
+ ResumePrivateStateThread ();
+ else
+ StartPrivateStateThread ();
+
+ DynamicLoader *dyld = GetDynamicLoader ();
+ if (dyld)
+ dyld->DidAttach();
+
+ m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
+ // We successfully loaded a core file, now pretend we stopped so we can
+ // show all of the threads in the core file and explore the crashed
+ // state.
+ SetPrivateState (eStateStopped);
+
+ }
+ return error;
+}
+
+DynamicLoader *
+Process::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL));
+ return m_dyld_ap.get();
+}
+
+
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
+{
+ StateType state = ProcessEventData::GetStateFromEvent (event_sp.get());
+ switch (state)
+ {
+ case eStateRunning:
+ case eStateConnected:
+ return eEventActionRetry;
+
+ case eStateStopped:
+ case eStateCrashed:
+ {
+ // During attach, prior to sending the eStateStopped event,
+ // lldb_private::Process subclasses must set the new process ID.
+ assert (m_process->GetID() != LLDB_INVALID_PROCESS_ID);
+ // We don't want these events to be reported, so go set the ShouldReportStop here:
+ m_process->GetThreadList().SetShouldReportStop (eVoteNo);
+
+ if (m_exec_count > 0)
+ {
+ --m_exec_count;
+ RequestResume();
+ return eEventActionRetry;
+ }
+ else
+ {
+ m_process->CompleteAttach ();
+ return eEventActionSuccess;
+ }
+ }
+ break;
+
+ default:
+ case eStateExited:
+ case eStateInvalid:
+ break;
+ }
+
+ m_exit_string.assign ("No valid Process");
+ return eEventActionExit;
+}
+
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::HandleBeingInterrupted()
+{
+ return eEventActionSuccess;
+}
+
+const char *
+Process::AttachCompletionHandler::GetExitString ()
+{
+ return m_exit_string.c_str();
+}
+
+Error
+Process::Attach (ProcessAttachInfo &attach_info)
+{
+ m_abi_sp.reset();
+ m_process_input_reader.reset();
+ m_dyld_ap.reset();
+ m_os_ap.reset();
+
+ lldb::pid_t attach_pid = attach_info.GetProcessID();
+ Error error;
+ if (attach_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ char process_name[PATH_MAX];
+
+ if (attach_info.GetExecutableFile().GetPath (process_name, sizeof(process_name)))
+ {
+ const bool wait_for_launch = attach_info.GetWaitForLaunch();
+
+ if (wait_for_launch)
+ {
+ error = WillAttachToProcessWithName(process_name, wait_for_launch);
+ if (error.Success())
+ {
+ if (m_public_run_lock.TrySetRunning())
+ {
+ m_should_detach = true;
+ const bool restarted = false;
+ SetPublicState (eStateAttaching, restarted);
+ // Now attach using these arguments.
+ error = DoAttachToProcessWithName (process_name, wait_for_launch, attach_info);
+ }
+ else
+ {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Fail())
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ SetID (LLDB_INVALID_PROCESS_ID);
+ if (error.AsCString() == NULL)
+ error.SetErrorString("attach failed");
+
+ SetExitStatus(-1, error.AsCString());
+ }
+ }
+ else
+ {
+ SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount()));
+ StartPrivateStateThread();
+ }
+ return error;
+ }
+ }
+ else
+ {
+ ProcessInstanceInfoList process_infos;
+ PlatformSP platform_sp (m_target.GetPlatform ());
+
+ if (platform_sp)
+ {
+ ProcessInstanceInfoMatch match_info;
+ match_info.GetProcessInfo() = attach_info;
+ match_info.SetNameMatchType (eNameMatchEquals);
+ platform_sp->FindProcesses (match_info, process_infos);
+ const uint32_t num_matches = process_infos.GetSize();
+ if (num_matches == 1)
+ {
+ attach_pid = process_infos.GetProcessIDAtIndex(0);
+ // Fall through and attach using the above process ID
+ }
+ else
+ {
+ match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name));
+ if (num_matches > 1)
+ error.SetErrorStringWithFormat ("more than one process named %s", process_name);
+ else
+ error.SetErrorStringWithFormat ("could not find a process named %s", process_name);
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid platform, can't find processes by name");
+ return error;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("invalid process name");
+ }
+ }
+
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ error = WillAttachToProcessWithID(attach_pid);
+ if (error.Success())
+ {
+
+ if (m_public_run_lock.TrySetRunning())
+ {
+ // Now attach using these arguments.
+ m_should_detach = true;
+ const bool restarted = false;
+ SetPublicState (eStateAttaching, restarted);
+ error = DoAttachToProcessWithID (attach_pid, attach_info);
+ }
+ else
+ {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Success())
+ {
+
+ SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount()));
+ StartPrivateStateThread();
+ }
+ 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);
+ }
+ }
+ }
+ }
+ return error;
+}
+
+void
+Process::CompleteAttach ()
+{
+ // Let the process subclass figure out at much as it can about the process
+ // before we go looking for a dynamic loader plug-in.
+ DidAttach();
+
+ // We just attached. If we have a platform, ask it for the process architecture, and if it isn't
+ // the same as the one we've already set, switch architectures.
+ PlatformSP platform_sp (m_target.GetPlatform ());
+ assert (platform_sp.get());
+ if (platform_sp)
+ {
+ const ArchSpec &target_arch = m_target.GetArchitecture();
+ if (target_arch.IsValid() && !platform_sp->IsCompatibleArchitecture (target_arch, false, NULL))
+ {
+ ArchSpec platform_arch;
+ platform_sp = platform_sp->GetPlatformForArchitecture (target_arch, &platform_arch);
+ if (platform_sp)
+ {
+ m_target.SetPlatform (platform_sp);
+ m_target.SetArchitecture(platform_arch);
+ }
+ }
+ else
+ {
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (GetID(), process_info);
+ const ArchSpec &process_arch = process_info.GetArchitecture();
+ if (process_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(process_arch))
+ m_target.SetArchitecture (process_arch);
+ }
+ }
+
+ // We have completed the attach, now it is time to find the dynamic loader
+ // plug-in
+ DynamicLoader *dyld = GetDynamicLoader ();
+ if (dyld)
+ dyld->DidAttach();
+
+ m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
+ // Figure out which one is the executable, and set that in our target:
+ const ModuleList &target_modules = m_target.GetImages();
+ Mutex::Locker modules_locker(target_modules.GetMutex());
+ size_t num_modules = target_modules.GetSize();
+ ModuleSP new_executable_module_sp;
+
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ ModuleSP module_sp (target_modules.GetModuleAtIndexUnlocked (i));
+ if (module_sp && module_sp->IsExecutable())
+ {
+ if (m_target.GetExecutableModulePointer() != module_sp.get())
+ new_executable_module_sp = module_sp;
+ break;
+ }
+ }
+ if (new_executable_module_sp)
+ m_target.SetExecutableModule (new_executable_module_sp, false);
+}
+
+Error
+Process::ConnectRemote (Stream *strm, const char *remote_url)
+{
+ m_abi_sp.reset();
+ m_process_input_reader.reset();
+
+ // Find the process and its architecture. Make sure it matches the architecture
+ // of the current Target, and if not adjust it.
+
+ Error error (DoConnectRemote (strm, remote_url));
+ if (error.Success())
+ {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ EventSP event_sp;
+ StateType state = WaitForProcessStopPrivate(NULL, event_sp);
+
+ if (state == eStateStopped || state == eStateCrashed)
+ {
+ // If we attached and actually have a process on the other end, then
+ // this ended up being the equivalent of an attach.
+ CompleteAttach ();
+
+ // This delays passing the stopped event to listeners till
+ // CompleteAttach gets a chance to complete...
+ HandlePrivateEvent (event_sp);
+
+ }
+ }
+
+ if (PrivateStateThreadIsValid ())
+ ResumePrivateStateThread ();
+ else
+ StartPrivateStateThread ();
+ }
+ return error;
+}
+
+
+Error
+Process::PrivateResume ()
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s private state: %s",
+ m_mod_id.GetStopID(),
+ StateAsCString(m_public_state.GetValue()),
+ StateAsCString(m_private_state.GetValue()));
+
+ Error error (WillResume());
+ // Tell the process it is about to resume before the thread list
+ if (error.Success())
+ {
+ // Now let the thread list know we are about to resume so it
+ // can let all of our threads know that they are about to be
+ // resumed. Threads will each be called with
+ // Thread::WillResume(StateType) where StateType contains the state
+ // that they are supposed to have when the process is resumed
+ // (suspended/running/stepping). Threads should also check
+ // their resume signal in lldb::Thread::GetResumeSignal()
+ // to see if they are supposed to start back up with a signal.
+ if (m_thread_list.WillResume())
+ {
+ // Last thing, do the PreResumeActions.
+ if (!RunPreResumeActions())
+ {
+ error.SetErrorStringWithFormat ("Process::PrivateResume PreResumeActions failed, not resuming.");
+ }
+ else
+ {
+ m_mod_id.BumpResumeID();
+ error = DoResume();
+ if (error.Success())
+ {
+ DidResume();
+ m_thread_list.DidResume();
+ if (log)
+ log->Printf ("Process thinks the process has resumed.");
+ }
+ }
+ }
+ else
+ {
+ // Somebody wanted to run without running. So generate a continue & a stopped event,
+ // and let the world handle them.
+ if (log)
+ log->Printf ("Process::PrivateResume() asked to simulate a start & stop.");
+
+ SetPrivateState(eStateRunning);
+ SetPrivateState(eStateStopped);
+ }
+ }
+ else if (log)
+ log->Printf ("Process::PrivateResume() got an error \"%s\".", error.AsCString("<unknown error>"));
+ return error;
+}
+
+Error
+Process::Halt (bool clear_thread_plans)
+{
+ // Don't clear the m_clear_thread_plans_on_stop, only set it to true if
+ // in case it was already set and some thread plan logic calls halt on its
+ // own.
+ m_clear_thread_plans_on_stop |= clear_thread_plans;
+
+ // First make sure we aren't in the middle of handling an event, or we might restart. This is pretty weak, since
+ // we could just straightaway get another event. It just narrows the window...
+ m_currently_handling_event.WaitForValueEqualTo(false);
+
+
+ // Pause our private state thread so we can ensure no one else eats
+ // the stop event out from under us.
+ Listener halt_listener ("lldb.process.halt_listener");
+ HijackPrivateProcessEvents(&halt_listener);
+
+ EventSP event_sp;
+ Error error (WillHalt());
+
+ if (error.Success())
+ {
+
+ bool caused_stop = false;
+
+ // Ask the process subclass to actually halt our process
+ error = DoHalt(caused_stop);
+ if (error.Success())
+ {
+ if (m_public_state.GetValue() == eStateAttaching)
+ {
+ SetExitStatus(SIGKILL, "Cancelled async attach.");
+ Destroy ();
+ }
+ else
+ {
+ // If "caused_stop" is true, then DoHalt stopped the process. If
+ // "caused_stop" is false, the process was already stopped.
+ // If the DoHalt caused the process to stop, then we want to catch
+ // this event and set the interrupted bool to true before we pass
+ // this along so clients know that the process was interrupted by
+ // a halt command.
+ if (caused_stop)
+ {
+ // Wait for 1 second for the process to stop.
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(1);
+ bool got_event = halt_listener.WaitForEvent (&timeout_time, event_sp);
+ StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (!got_event || state == eStateInvalid)
+ {
+ // We timeout out and didn't get a stop event...
+ error.SetErrorStringWithFormat ("Halt timed out. State = %s", StateAsCString(GetState()));
+ }
+ else
+ {
+ if (StateIsStoppedState (state, false))
+ {
+ // We caused the process to interrupt itself, so mark this
+ // as such in the stop event so clients can tell an interrupted
+ // process from a natural stop
+ ProcessEventData::SetInterruptedInEvent (event_sp.get(), true);
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state));
+ error.SetErrorString ("Did not get stopped event after halt.");
+ }
+ }
+ }
+ DidHalt();
+ }
+ }
+ }
+ // Resume our private state thread before we post the event (if any)
+ RestorePrivateProcessEvents();
+
+ // Post any event we might have consumed. If all goes well, we will have
+ // stopped the process, intercepted the event and set the interrupted
+ // bool in the event. Post it to the private event queue and that will end up
+ // correctly setting the state.
+ if (event_sp)
+ m_private_state_broadcaster.BroadcastEvent(event_sp);
+
+ return error;
+}
+
+Error
+Process::HaltForDestroyOrDetach(lldb::EventSP &exit_event_sp)
+{
+ Error error;
+ if (m_public_state.GetValue() == eStateRunning)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Destroy() About to halt.");
+ error = Halt();
+ if (error.Success())
+ {
+ // Consume the halt event.
+ TimeValue timeout (TimeValue::Now());
+ timeout.OffsetWithSeconds(1);
+ StateType state = WaitForProcessToStop (&timeout, &exit_event_sp);
+
+ // If the process exited while we were waiting for it to stop, put the exited event into
+ // the shared pointer passed in and return. Our caller doesn't need to do anything else, since
+ // they don't have a process anymore...
+
+ if (state == eStateExited || m_private_state.GetValue() == eStateExited)
+ {
+ if (log)
+ log->Printf("Process::HaltForDestroyOrDetach() Process exited while waiting to Halt.");
+ return error;
+ }
+ else
+ exit_event_sp.reset(); // It is ok to consume any non-exit stop events
+
+ if (state != eStateStopped)
+ {
+ if (log)
+ log->Printf("Process::HaltForDestroyOrDetach() Halt failed to stop, state is: %s", StateAsCString(state));
+ // If we really couldn't stop the process then we should just error out here, but if the
+ // lower levels just bobbled sending the event and we really are stopped, then continue on.
+ StateType private_state = m_private_state.GetValue();
+ if (private_state != eStateStopped)
+ {
+ return error;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Process::HaltForDestroyOrDetach() Halt got error: %s", error.AsCString());
+ }
+ }
+ return error;
+}
+
+Error
+Process::Detach (bool keep_stopped)
+{
+ EventSP exit_event_sp;
+ Error error;
+ m_destroy_in_process = true;
+
+ error = WillDetach();
+
+ if (error.Success())
+ {
+ if (DetachRequiresHalt())
+ {
+ error = HaltForDestroyOrDetach (exit_event_sp);
+ if (!error.Success())
+ {
+ m_destroy_in_process = false;
+ return error;
+ }
+ else if (exit_event_sp)
+ {
+ // We shouldn't need to do anything else here. There's no process left to detach from...
+ StopPrivateStateThread();
+ m_destroy_in_process = false;
+ return error;
+ }
+ }
+
+ error = DoDetach(keep_stopped);
+ if (error.Success())
+ {
+ DidDetach();
+ StopPrivateStateThread();
+ }
+ else
+ {
+ return error;
+ }
+ }
+ m_destroy_in_process = false;
+
+ // If we exited when we were waiting for a process to stop, then
+ // forward the event here so we don't lose the event
+ if (exit_event_sp)
+ {
+ // Directly broadcast our exited event because we shut down our
+ // private state thread above
+ BroadcastEvent(exit_event_sp);
+ }
+
+ // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
+ // the last events through the event system, in which case we might strand the write lock. Unlock
+ // it here so when we do to tear down the process we don't get an error destroying the lock.
+
+ m_public_run_lock.SetStopped();
+ return error;
+}
+
+Error
+Process::Destroy ()
+{
+
+ // Tell ourselves we are in the process of destroying the process, so that we don't do any unnecessary work
+ // that might hinder the destruction. Remember to set this back to false when we are done. That way if the attempt
+ // failed and the process stays around for some reason it won't be in a confused state.
+
+ m_destroy_in_process = true;
+
+ Error error (WillDestroy());
+ if (error.Success())
+ {
+ EventSP exit_event_sp;
+ if (DestroyRequiresHalt())
+ {
+ error = HaltForDestroyOrDetach(exit_event_sp);
+ }
+
+ if (m_public_state.GetValue() != eStateRunning)
+ {
+ // Ditch all thread plans, and remove all our breakpoints: in case we have to restart the target to
+ // kill it, we don't want it hitting a breakpoint...
+ // Only do this if we've stopped, however, since if we didn't manage to halt it above, then
+ // we're not going to have much luck doing this now.
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+ }
+
+ error = DoDestroy();
+ if (error.Success())
+ {
+ DidDestroy();
+ StopPrivateStateThread();
+ }
+ m_stdio_communication.StopReadThread();
+ m_stdio_communication.Disconnect();
+ if (m_process_input_reader && m_process_input_reader->IsActive())
+ m_target.GetDebugger().PopInputReader (m_process_input_reader);
+ if (m_process_input_reader)
+ m_process_input_reader.reset();
+
+ // If we exited when we were waiting for a process to stop, then
+ // forward the event here so we don't lose the event
+ if (exit_event_sp)
+ {
+ // Directly broadcast our exited event because we shut down our
+ // private state thread above
+ BroadcastEvent(exit_event_sp);
+ }
+
+ // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
+ // the last events through the event system, in which case we might strand the write lock. Unlock
+ // it here so when we do to tear down the process we don't get an error destroying the lock.
+ m_public_run_lock.SetStopped();
+ }
+
+ m_destroy_in_process = false;
+
+ return error;
+}
+
+Error
+Process::Signal (int signal)
+{
+ Error error (WillSignal());
+ if (error.Success())
+ {
+ error = DoSignal(signal);
+ if (error.Success())
+ DidSignal();
+ }
+ return error;
+}
+
+lldb::ByteOrder
+Process::GetByteOrder () const
+{
+ return m_target.GetArchitecture().GetByteOrder();
+}
+
+uint32_t
+Process::GetAddressByteSize () const
+{
+ return m_target.GetArchitecture().GetAddressByteSize();
+}
+
+
+bool
+Process::ShouldBroadcastEvent (Event *event_ptr)
+{
+ const StateType state = Process::ProcessEventData::GetStateFromEvent (event_ptr);
+ bool return_value = true;
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | LIBLLDB_LOG_PROCESS));
+
+ switch (state)
+ {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ // These events indicate changes in the state of the debugging session, always report them.
+ return_value = true;
+ break;
+ case eStateInvalid:
+ // We stopped for no apparent reason, don't report it.
+ return_value = false;
+ break;
+ case eStateRunning:
+ case eStateStepping:
+ // If we've started the target running, we handle the cases where we
+ // are already running and where there is a transition from stopped to
+ // running differently.
+ // running -> running: Automatically suppress extra running events
+ // stopped -> running: Report except when there is one or more no votes
+ // and no yes votes.
+ SynchronouslyNotifyStateChanged (state);
+ switch (m_last_broadcast_state)
+ {
+ case eStateRunning:
+ case eStateStepping:
+ // We always suppress multiple runnings with no PUBLIC stop in between.
+ return_value = false;
+ break;
+ default:
+ // TODO: make this work correctly. For now always report
+ // run if we aren't running so we don't miss any runnning
+ // events. If I run the lldb/test/thread/a.out file and
+ // break at main.cpp:58, run and hit the breakpoints on
+ // multiple threads, then somehow during the stepping over
+ // of all breakpoints no run gets reported.
+
+ // This is a transition from stop to run.
+ switch (m_thread_list.ShouldReportRun (event_ptr))
+ {
+ case eVoteYes:
+ case eVoteNoOpinion:
+ return_value = true;
+ break;
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+ break;
+ }
+ break;
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ {
+ // We've stopped. First see if we're going to restart the target.
+ // If we are going to stop, then we always broadcast the event.
+ // If we aren't going to stop, let the thread plans decide if we're going to report this event.
+ // If no thread has an opinion, we don't report it.
+
+ RefreshStateAfterStop ();
+ if (ProcessEventData::GetInterruptedFromEvent (event_ptr))
+ {
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s",
+ event_ptr,
+ StateAsCString(state));
+ return_value = true;
+ }
+ else
+ {
+ bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);
+ bool should_resume = false;
+
+ // It makes no sense to ask "ShouldStop" if we've already been restarted...
+ // Asking the thread list is also not likely to go well, since we are running again.
+ // So in that case just report the event.
+
+ if (!was_restarted)
+ should_resume = m_thread_list.ShouldStop (event_ptr) == false;
+
+ if (was_restarted || should_resume || m_resume_requested)
+ {
+ Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.",
+ should_resume,
+ StateAsCString(state),
+ was_restarted,
+ stop_vote);
+
+ switch (stop_vote)
+ {
+ case eVoteYes:
+ return_value = true;
+ break;
+ case eVoteNoOpinion:
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+
+ if (!was_restarted)
+ {
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state));
+ ProcessEventData::SetRestartedInEvent(event_ptr, true);
+ PrivateResume ();
+ }
+
+ }
+ else
+ {
+ return_value = true;
+ SynchronouslyNotifyStateChanged (state);
+ }
+ }
+ }
+ break;
+ }
+
+ // We do some coalescing of events (for instance two consecutive running events get coalesced.)
+ // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state
+ // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done,
+ // because the PublicState reflects the last event pulled off the queue, and there may be several
+ // events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event
+ // yet. m_last_broadcast_state gets updated here.
+
+ if (return_value)
+ m_last_broadcast_state = state;
+
+ if (log)
+ log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s",
+ event_ptr,
+ StateAsCString(state),
+ StateAsCString(m_last_broadcast_state),
+ return_value ? "YES" : "NO");
+ return return_value;
+}
+
+
+bool
+Process::StartPrivateStateThread (bool force)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
+
+ bool already_running = PrivateStateThreadIsValid ();
+ if (log)
+ log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread");
+
+ if (!force && already_running)
+ return true;
+
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ char thread_name[1024];
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+ else
+ snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
+
+ // Create the private state thread, and start it running.
+ m_private_state_thread = Host::ThreadCreate (thread_name, Process::PrivateStateThread, this, NULL);
+ bool success = IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
+ if (success)
+ {
+ ResumePrivateStateThread();
+ return true;
+ }
+ else
+ return false;
+}
+
+void
+Process::PausePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlPause);
+}
+
+void
+Process::ResumePrivateStateThread ()
+{
+ ControlPrivateStateThread (eBroadcastInternalStateControlResume);
+}
+
+void
+Process::StopPrivateStateThread ()
+{
+ if (PrivateStateThreadIsValid ())
+ ControlPrivateStateThread (eBroadcastInternalStateControlStop);
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Went to stop the private state thread, but it was already invalid.");
+ }
+}
+
+void
+Process::ControlPrivateStateThread (uint32_t signal)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ assert (signal == eBroadcastInternalStateControlStop ||
+ signal == eBroadcastInternalStateControlPause ||
+ signal == eBroadcastInternalStateControlResume);
+
+ if (log)
+ log->Printf ("Process::%s (signal = %d)", __FUNCTION__, 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))
+ {
+ TimeValue timeout_time;
+ bool timed_out;
+
+ m_private_state_control_broadcaster.BroadcastEvent (signal, NULL);
+
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds(2);
+ if (log)
+ log->Printf ("Sending control event of type: %d.", signal);
+ m_private_state_control_wait.WaitForValueEqualTo (true, &timeout_time, &timed_out);
+ m_private_state_control_wait.SetValue (false, eBroadcastNever);
+
+ if (signal == eBroadcastInternalStateControlStop)
+ {
+ if (timed_out)
+ {
+ Error error;
+ Host::ThreadCancel (private_state_thread, &error);
+ if (log)
+ log->Printf ("Timed out responding to the control event, cancel got error: \"%s\".", error.AsCString());
+ }
+ else
+ {
+ if (log)
+ log->Printf ("The control event killed the private state thread without having to cancel.");
+ }
+
+ thread_result_t result = NULL;
+ Host::ThreadJoin (private_state_thread, &result, NULL);
+ m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Private state thread already dead, no need to signal it to stop.");
+ }
+}
+
+void
+Process::SendAsyncInterrupt ()
+{
+ if (PrivateStateThreadIsValid())
+ m_private_state_broadcaster.BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+ else
+ BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+}
+
+void
+Process::HandlePrivateEvent (EventSP &event_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ m_resume_requested = false;
+
+ m_currently_handling_event.SetValue(true, eBroadcastNever);
+
+ const StateType new_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ // First check to see if anybody wants a shot at this event:
+ if (m_next_event_action_ap.get() != NULL)
+ {
+ NextEventAction::EventActionResult action_result = m_next_event_action_ap->PerformAction(event_sp);
+ if (log)
+ log->Printf ("Ran next event action, result was %d.", action_result);
+
+ switch (action_result)
+ {
+ case NextEventAction::eEventActionSuccess:
+ SetNextEventAction(NULL);
+ break;
+
+ case NextEventAction::eEventActionRetry:
+ break;
+
+ case NextEventAction::eEventActionExit:
+ // Handle Exiting Here. If we already got an exited event,
+ // we should just propagate it. Otherwise, swallow this event,
+ // and set our state to exit so the next event will kill us.
+ if (new_state != eStateExited)
+ {
+ // FIXME: should cons up an exited event, and discard this one.
+ SetExitStatus(0, m_next_event_action_ap->GetExitString());
+ m_currently_handling_event.SetValue(false, eBroadcastAlways);
+ SetNextEventAction(NULL);
+ return;
+ }
+ SetNextEventAction(NULL);
+ break;
+ }
+ }
+
+ // See if we should broadcast this state to external clients?
+ const bool should_broadcast = ShouldBroadcastEvent (event_sp.get());
+
+ if (should_broadcast)
+ {
+ if (log)
+ {
+ log->Printf ("Process::%s (pid = %" PRIu64 ") broadcasting new state %s (old state %s) to %s",
+ __FUNCTION__,
+ GetID(),
+ StateAsCString(new_state),
+ StateAsCString (GetState ()),
+ IsHijackedForEvent(eBroadcastBitStateChanged) ? "hijacked" : "public");
+ }
+ Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
+ if (StateIsRunningState (new_state))
+ PushProcessInputReader ();
+ else if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ PopProcessInputReader ();
+
+ BroadcastEvent (event_sp);
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("Process::%s (pid = %" PRIu64 ") suppressing state %s (old state %s): should_broadcast == false",
+ __FUNCTION__,
+ GetID(),
+ StateAsCString(new_state),
+ StateAsCString (GetState ()));
+ }
+ }
+ m_currently_handling_event.SetValue(false, eBroadcastAlways);
+}
+
+void *
+Process::PrivateStateThread (void *arg)
+{
+ Process *proc = static_cast<Process*> (arg);
+ void *result = proc->RunPrivateStateThread ();
+ return result;
+}
+
+void *
+Process::RunPrivateStateThread ()
+{
+ bool control_only = true;
+ m_private_state_control_wait.SetValue (false, eBroadcastNever);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, this, GetID());
+
+ bool exit_now = false;
+ while (!exit_now)
+ {
+ EventSP event_sp;
+ WaitForEventsPrivate (NULL, event_sp, control_only);
+ if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster))
+ {
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d", __FUNCTION__, this, GetID(), event_sp->GetType());
+
+ switch (event_sp->GetType())
+ {
+ case eBroadcastInternalStateControlStop:
+ exit_now = true;
+ break; // doing any internal state managment below
+
+ case eBroadcastInternalStateControlPause:
+ control_only = true;
+ break;
+
+ case eBroadcastInternalStateControlResume:
+ control_only = false;
+ break;
+ }
+
+ m_private_state_control_wait.SetValue (true, eBroadcastAlways);
+ continue;
+ }
+ else if (event_sp->GetType() == eBroadcastBitInterrupt)
+ {
+ if (m_public_state.GetValue() == eStateAttaching)
+ {
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.", __FUNCTION__, this, GetID());
+ BroadcastEvent (eBroadcastBitInterrupt, NULL);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", __FUNCTION__, this, GetID());
+ Halt();
+ }
+ continue;
+ }
+
+ const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (internal_state != eStateInvalid)
+ {
+ if (m_clear_thread_plans_on_stop &&
+ StateIsStoppedState(internal_state, true))
+ {
+ m_clear_thread_plans_on_stop = false;
+ m_thread_list.DiscardThreadPlans();
+ }
+ HandlePrivateEvent (event_sp);
+ }
+
+ if (internal_state == eStateInvalid ||
+ internal_state == eStateExited ||
+ internal_state == eStateDetached )
+ {
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", __FUNCTION__, this, GetID(), StateAsCString(internal_state));
+
+ break;
+ }
+ }
+
+ // Verify log is still enabled before attempting to write to it...
+ if (log)
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, this, GetID());
+
+ m_public_run_lock.SetStopped();
+ m_private_state_control_wait.SetValue (true, eBroadcastAlways);
+ m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// Process Event Data
+//------------------------------------------------------------------
+
+Process::ProcessEventData::ProcessEventData () :
+ EventData (),
+ m_process_sp (),
+ m_state (eStateInvalid),
+ m_restarted (false),
+ m_update_state (0),
+ m_interrupted (false)
+{
+}
+
+Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
+ EventData (),
+ m_process_sp (process_sp),
+ m_state (state),
+ m_restarted (false),
+ m_update_state (0),
+ m_interrupted (false)
+{
+}
+
+Process::ProcessEventData::~ProcessEventData()
+{
+}
+
+const ConstString &
+Process::ProcessEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Process::ProcessEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Process::ProcessEventData::GetFlavor () const
+{
+ return ProcessEventData::GetFlavorString ();
+}
+
+void
+Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
+{
+ // This function gets called twice for each event, once when the event gets pulled
+ // off of the private process event queue, and then any number of times, first when it gets pulled off of
+ // the public event queue, then other times when we're pretending that this is where we stopped at the
+ // end of expression evaluation. m_update_state is used to distinguish these
+ // three cases; it is 0 when we're just pulling it off for private handling,
+ // and > 1 for expression evaluation, and we don't want to do the breakpoint command handling then.
+ if (m_update_state != 1)
+ return;
+
+ m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
+
+ // If we're stopped and haven't restarted, then do the breakpoint commands here:
+ if (m_state == eStateStopped && ! m_restarted)
+ {
+ ThreadList &curr_thread_list = m_process_sp->GetThreadList();
+ uint32_t num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+
+ // The actions might change one of the thread's stop_info's opinions about whether we should
+ // stop the process, so we need to query that as we go.
+
+ // One other complication here, is that we try to catch any case where the target has run (except for expressions)
+ // and immediately exit, but if we get that wrong (which is possible) then the thread list might have changed, and
+ // that would cause our iteration here to crash. We could make a copy of the thread list, but we'd really like
+ // to also know if it has changed at all, so we make up a vector of the thread ID's and check what we get back
+ // against this list & bag out if anything differs.
+ std::vector<uint32_t> thread_index_array(num_threads);
+ for (idx = 0; idx < num_threads; ++idx)
+ thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetIndexID();
+
+ // Use this to track whether we should continue from here. We will only continue the target running if
+ // no thread says we should stop. Of course if some thread's PerformAction actually sets the target running,
+ // then it doesn't matter what the other threads say...
+
+ bool still_should_stop = false;
+
+ // Sometimes - for instance if we have a bug in the stub we are talking to, we stop but no thread has a
+ // valid stop reason. In that case we should just stop, because we have no way of telling what the right
+ // thing to do is, and it's better to let the user decide than continue behind their backs.
+
+ bool does_anybody_have_an_opinion = false;
+
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ curr_thread_list = m_process_sp->GetThreadList();
+ if (curr_thread_list.GetSize() != num_threads)
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Number of threads changed from %u to %u while processing event.", num_threads, curr_thread_list.GetSize());
+ break;
+ }
+
+ lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
+
+ if (thread_sp->GetIndexID() != thread_index_array[idx])
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("The thread at position %u changed from %u to %u while processing event.",
+ idx,
+ thread_index_array[idx],
+ thread_sp->GetIndexID());
+ break;
+ }
+
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo ();
+ if (stop_info_sp && stop_info_sp->IsValid())
+ {
+ does_anybody_have_an_opinion = true;
+ bool this_thread_wants_to_stop;
+ if (stop_info_sp->GetOverrideShouldStop())
+ {
+ this_thread_wants_to_stop = stop_info_sp->GetOverriddenShouldStopValue();
+ }
+ else
+ {
+ stop_info_sp->PerformAction(event_ptr);
+ // The stop action might restart the target. If it does, then we want to mark that in the
+ // event so that whoever is receiving it will know to wait for the running event and reflect
+ // that state appropriately.
+ // We also need to stop processing actions, since they aren't expecting the target to be running.
+
+ // FIXME: we might have run.
+ if (stop_info_sp->HasTargetRunSinceMe())
+ {
+ SetRestarted (true);
+ break;
+ }
+
+ this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
+ }
+
+ if (still_should_stop == false)
+ still_should_stop = this_thread_wants_to_stop;
+ }
+ }
+
+
+ if (!GetRestarted())
+ {
+ if (!still_should_stop && does_anybody_have_an_opinion)
+ {
+ // We've been asked to continue, so do that here.
+ SetRestarted(true);
+ // Use the public resume method here, since this is just
+ // extending a public resume.
+ m_process_sp->PrivateResume();
+ }
+ else
+ {
+ // If we didn't restart, run the Stop Hooks here:
+ // They might also restart the target, so watch for that.
+ m_process_sp->GetTarget().RunStopHooks();
+ if (m_process_sp->GetPrivateState() == eStateRunning)
+ SetRestarted(true);
+ }
+ }
+ }
+}
+
+void
+Process::ProcessEventData::Dump (Stream *s) const
+{
+ if (m_process_sp)
+ s->Printf(" process = %p (pid = %" PRIu64 "), ", m_process_sp.get(), m_process_sp->GetID());
+
+ s->Printf("state = %s", StateAsCString(GetState()));
+}
+
+const Process::ProcessEventData *
+Process::ProcessEventData::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == ProcessEventData::GetFlavorString())
+ return static_cast <const ProcessEventData *> (event_ptr->GetData());
+ }
+ return NULL;
+}
+
+ProcessSP
+Process::ProcessEventData::GetProcessFromEvent (const Event *event_ptr)
+{
+ ProcessSP process_sp;
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data)
+ process_sp = data->GetProcessSP();
+ return process_sp;
+}
+
+StateType
+Process::ProcessEventData::GetStateFromEvent (const Event *event_ptr)
+{
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data == NULL)
+ return eStateInvalid;
+ else
+ return data->GetState();
+}
+
+bool
+Process::ProcessEventData::GetRestartedFromEvent (const Event *event_ptr)
+{
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data == NULL)
+ return false;
+ else
+ return data->GetRestarted();
+}
+
+void
+Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ data->SetRestarted(new_value);
+}
+
+size_t
+Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ return data->GetNumRestartedReasons();
+ else
+ return 0;
+}
+
+const char *
+Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ return data->GetRestartedReasonAtIndex(idx);
+ else
+ return NULL;
+}
+
+void
+Process::ProcessEventData::AddRestartedReason (Event *event_ptr, const char *reason)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ data->AddRestartedReason(reason);
+}
+
+bool
+Process::ProcessEventData::GetInterruptedFromEvent (const Event *event_ptr)
+{
+ const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
+ if (data == NULL)
+ return false;
+ else
+ return data->GetInterrupted ();
+}
+
+void
+Process::ProcessEventData::SetInterruptedInEvent (Event *event_ptr, bool new_value)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data != NULL)
+ data->SetInterrupted(new_value);
+}
+
+bool
+Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr)
+{
+ ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
+ if (data)
+ {
+ data->SetUpdateStateOnRemoval();
+ return true;
+ }
+ return false;
+}
+
+lldb::TargetSP
+Process::CalculateTarget ()
+{
+ return m_target.shared_from_this();
+}
+
+void
+Process::CalculateExecutionContext (ExecutionContext &exe_ctx)
+{
+ exe_ctx.SetTargetPtr (&m_target);
+ exe_ctx.SetProcessPtr (this);
+ exe_ctx.SetThreadPtr(NULL);
+ exe_ctx.SetFramePtr (NULL);
+}
+
+//uint32_t
+//Process::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
+//{
+// return 0;
+//}
+//
+//ArchSpec
+//Process::GetArchSpecForExistingProcess (lldb::pid_t pid)
+//{
+// return Host::GetArchSpecForExistingProcess (pid);
+//}
+//
+//ArchSpec
+//Process::GetArchSpecForExistingProcess (const char *process_name)
+//{
+// return Host::GetArchSpecForExistingProcess (process_name);
+//}
+//
+void
+Process::AppendSTDOUT (const char * s, size_t len)
+{
+ Mutex::Locker locker (m_stdio_communication_mutex);
+ m_stdout_data.append (s, len);
+ BroadcastEventIfUnique (eBroadcastBitSTDOUT, new ProcessEventData (shared_from_this(), GetState()));
+}
+
+void
+Process::AppendSTDERR (const char * s, size_t len)
+{
+ Mutex::Locker locker (m_stdio_communication_mutex);
+ m_stderr_data.append (s, len);
+ BroadcastEventIfUnique (eBroadcastBitSTDERR, new ProcessEventData (shared_from_this(), GetState()));
+}
+
+void
+Process::BroadcastAsyncProfileData(const std::string &one_profile_data)
+{
+ Mutex::Locker locker (m_profile_data_comm_mutex);
+ m_profile_data.push_back(one_profile_data);
+ BroadcastEventIfUnique (eBroadcastBitProfileData, new ProcessEventData (shared_from_this(), GetState()));
+}
+
+size_t
+Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)
+{
+ Mutex::Locker locker(m_profile_data_comm_mutex);
+ if (m_profile_data.empty())
+ return 0;
+
+ std::string &one_profile_data = m_profile_data.front();
+ size_t bytes_available = one_profile_data.size();
+ if (bytes_available > 0)
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, one_profile_data.c_str(), buf_size);
+ one_profile_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, one_profile_data.c_str(), bytes_available);
+ m_profile_data.erase(m_profile_data.begin());
+ }
+ }
+ return bytes_available;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+
+size_t
+Process::GetSTDOUT (char *buf, size_t buf_size, Error &error)
+{
+ Mutex::Locker locker(m_stdio_communication_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0)
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stdout_data.c_str(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stdout_data.c_str(), bytes_available);
+ m_stdout_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+
+size_t
+Process::GetSTDERR (char *buf, size_t buf_size, Error &error)
+{
+ Mutex::Locker locker(m_stdio_communication_mutex);
+ size_t bytes_available = m_stderr_data.size();
+ if (bytes_available > 0)
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ if (bytes_available > buf_size)
+ {
+ memcpy(buf, m_stderr_data.c_str(), buf_size);
+ m_stderr_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ }
+ else
+ {
+ memcpy(buf, m_stderr_data.c_str(), bytes_available);
+ m_stderr_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+void
+Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ Process *process = (Process *) baton;
+ process->AppendSTDOUT (static_cast<const char *>(src), src_len);
+}
+
+size_t
+Process::ProcessInputReaderCallback (void *baton,
+ InputReader &reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len)
+{
+ Process *process = (Process *) baton;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderReactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ break;
+
+ case eInputReaderGotToken:
+ {
+ Error error;
+ process->PutSTDIN (bytes, bytes_len, error);
+ }
+ break;
+
+ case eInputReaderInterrupt:
+ process->SendAsyncInterrupt();
+ break;
+
+ case eInputReaderEndOfFile:
+ process->AppendSTDOUT ("^D", 2);
+ break;
+
+ case eInputReaderDone:
+ break;
+
+ }
+
+ return bytes_len;
+}
+
+void
+Process::ResetProcessInputReader ()
+{
+ m_process_input_reader.reset();
+}
+
+void
+Process::SetSTDIOFileDescriptor (int file_descriptor)
+{
+ // First set up the Read Thread for reading/handling process I/O
+
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap (new ConnectionFileDescriptor (file_descriptor, true));
+
+ if (conn_ap.get())
+ {
+ m_stdio_communication.SetConnection (conn_ap.release());
+ if (m_stdio_communication.IsConnected())
+ {
+ m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
+
+ // Now read thread is set up, set up input reader.
+
+ if (!m_process_input_reader.get())
+ {
+ m_process_input_reader.reset (new InputReader(m_target.GetDebugger()));
+ Error err (m_process_input_reader->Initialize (Process::ProcessInputReaderCallback,
+ this,
+ eInputReaderGranularityByte,
+ NULL,
+ NULL,
+ false));
+
+ if (err.Fail())
+ m_process_input_reader.reset();
+ }
+ }
+ }
+}
+
+void
+Process::PushProcessInputReader ()
+{
+ if (m_process_input_reader && !m_process_input_reader->IsActive())
+ m_target.GetDebugger().PushInputReader (m_process_input_reader);
+}
+
+void
+Process::PopProcessInputReader ()
+{
+ if (m_process_input_reader && m_process_input_reader->IsActive())
+ m_target.GetDebugger().PopInputReader (m_process_input_reader);
+}
+
+// The process needs to know about installed plug-ins
+void
+Process::SettingsInitialize ()
+{
+// static std::vector<OptionEnumValueElement> g_plugins;
+//
+// int i=0;
+// const char *name;
+// OptionEnumValueElement option_enum;
+// while ((name = PluginManager::GetProcessPluginNameAtIndex (i)) != NULL)
+// {
+// if (name)
+// {
+// option_enum.value = i;
+// option_enum.string_value = name;
+// option_enum.usage = PluginManager::GetProcessPluginDescriptionAtIndex (i);
+// g_plugins.push_back (option_enum);
+// }
+// ++i;
+// }
+// option_enum.value = 0;
+// option_enum.string_value = NULL;
+// option_enum.usage = NULL;
+// g_plugins.push_back (option_enum);
+//
+// for (i=0; (name = SettingsController::instance_settings_table[i].var_name); ++i)
+// {
+// if (::strcmp (name, "plugin") == 0)
+// {
+// SettingsController::instance_settings_table[i].enum_values = &g_plugins[0];
+// break;
+// }
+// }
+//
+ Thread::SettingsInitialize ();
+}
+
+void
+Process::SettingsTerminate ()
+{
+ Thread::SettingsTerminate ();
+}
+
+ExecutionResults
+Process::RunThreadPlan (ExecutionContext &exe_ctx,
+ lldb::ThreadPlanSP &thread_plan_sp,
+ bool stop_others,
+ bool run_others,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ uint32_t timeout_usec,
+ Stream &errors)
+{
+ ExecutionResults return_value = eExecutionSetupError;
+
+ if (thread_plan_sp.get() == NULL)
+ {
+ errors.Printf("RunThreadPlan called with empty thread plan.");
+ return eExecutionSetupError;
+ }
+
+ if (!thread_plan_sp->ValidatePlan(NULL))
+ {
+ errors.Printf ("RunThreadPlan called with an invalid thread plan.");
+ return eExecutionSetupError;
+ }
+
+ if (exe_ctx.GetProcessPtr() != this)
+ {
+ errors.Printf("RunThreadPlan called on wrong process.");
+ return eExecutionSetupError;
+ }
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread == NULL)
+ {
+ errors.Printf("RunThreadPlan called with invalid thread.");
+ return eExecutionSetupError;
+ }
+
+ // We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes.
+ // For that to be true the plan can't be private - since private plans suppress themselves in the
+ // GetCompletedPlan call.
+
+ bool orig_plan_private = thread_plan_sp->GetPrivate();
+ thread_plan_sp->SetPrivate(false);
+
+ if (m_private_state.GetValue() != eStateStopped)
+ {
+ errors.Printf ("RunThreadPlan called while the private state was not stopped.");
+ return eExecutionSetupError;
+ }
+
+ // Save the thread & frame from the exe_ctx for restoration after we run
+ const uint32_t thread_idx_id = thread->GetIndexID();
+ StackFrameSP selected_frame_sp = thread->GetSelectedFrame();
+ if (!selected_frame_sp)
+ {
+ thread->SetSelectedFrame(0);
+ selected_frame_sp = thread->GetSelectedFrame();
+ if (!selected_frame_sp)
+ {
+ errors.Printf("RunThreadPlan called without a selected frame on thread %d", thread_idx_id);
+ return eExecutionSetupError;
+ }
+ }
+
+ StackID ctx_frame_id = selected_frame_sp->GetStackID();
+
+ // N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either,
+ // so we should arrange to reset them as well.
+
+ lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread();
+
+ uint32_t selected_tid;
+ StackID selected_stack_id;
+ if (selected_thread_sp)
+ {
+ selected_tid = selected_thread_sp->GetIndexID();
+ selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID();
+ }
+ else
+ {
+ selected_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ lldb::thread_t backup_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ lldb::StateType old_state;
+ lldb::ThreadPlanSP stopper_base_plan_sp;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
+ if (Host::GetCurrentThread() == m_private_state_thread)
+ {
+ // 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.
+ // The simplest thing to do is to spin up a temporary thread to handle private state thread events while
+ // we are fielding public events here.
+ if (log)
+ log->Printf ("Running thread plan on private state thread, spinning up another state thread to handle the events.");
+
+
+ backup_private_state_thread = m_private_state_thread;
+
+ // One other bit of business: we want to run just this thread plan and anything it pushes, and then stop,
+ // returning control here.
+ // But in the normal course of things, the plan above us on the stack would be given a shot at the stop
+ // event before deciding to stop, and we don't want that. So we insert a "stopper" base plan on the stack
+ // before the plan we want to run. Since base plans always stop and return control to the user, that will
+ // do just what we want.
+ stopper_base_plan_sp.reset(new ThreadPlanBase (*thread));
+ thread->QueueThreadPlan (stopper_base_plan_sp, false);
+ // Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly.
+ old_state = m_public_state.GetValue();
+ m_public_state.SetValueNoLock(eStateStopped);
+
+ // Now spin up the private state thread:
+ StartPrivateStateThread(true);
+ }
+
+ thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense?
+
+ Listener listener("lldb.process.listener.run-thread-plan");
+
+ lldb::EventSP event_to_broadcast_sp;
+
+ {
+ // This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get
+ // restored on exit to the function.
+ //
+ // If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event
+ // is put into event_to_broadcast_sp for rebroadcasting.
+
+ ProcessEventHijacker run_thread_plan_hijacker (*this, &listener);
+
+ if (log)
+ {
+ StreamString s;
+ thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64 " to run thread plan \"%s\".",
+ thread->GetIndexID(),
+ thread->GetID(),
+ s.GetData());
+ }
+
+ bool got_event;
+ lldb::EventSP event_sp;
+ lldb::StateType stop_state = lldb::eStateInvalid;
+
+ TimeValue* timeout_ptr = NULL;
+ TimeValue real_timeout;
+
+ bool before_first_timeout = true; // This is set to false the first time that we have to halt the target.
+ bool do_resume = true;
+ bool handle_running_event = true;
+ const uint64_t default_one_thread_timeout_usec = 250000;
+
+ // This is just for accounting:
+ uint32_t num_resumes = 0;
+
+ TimeValue one_thread_timeout = TimeValue::Now();
+ TimeValue final_timeout = one_thread_timeout;
+
+ if (run_others)
+ {
+ // If we are running all threads then we take half the time to run all threads, bounded by
+ // .25 sec.
+ if (timeout_usec == 0)
+ one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec);
+ else
+ {
+ uint64_t computed_timeout = timeout_usec / 2;
+ if (computed_timeout > default_one_thread_timeout_usec)
+ computed_timeout = default_one_thread_timeout_usec;
+ one_thread_timeout.OffsetWithMicroSeconds(computed_timeout);
+ }
+ final_timeout.OffsetWithMicroSeconds (timeout_usec);
+ }
+ else
+ {
+ if (timeout_usec != 0)
+ final_timeout.OffsetWithMicroSeconds(timeout_usec);
+ }
+
+ // This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
+ // So don't call return anywhere within it.
+
+ while (1)
+ {
+ // We usually want to resume the process if we get to the top of the loop.
+ // The only exception is if we get two running events with no intervening
+ // stop, which can happen, we will just wait for then next stop event.
+ if (log)
+ log->Printf ("Top of while loop: do_resume: %i handle_running_event: %i before_first_timeout: %i.",
+ do_resume,
+ handle_running_event,
+ before_first_timeout);
+
+ if (do_resume || handle_running_event)
+ {
+ // Do the initial resume and wait for the running event before going further.
+
+ if (do_resume)
+ {
+ num_resumes++;
+ Error resume_error = PrivateResume ();
+ if (!resume_error.Success())
+ {
+ errors.Printf("Error resuming inferior the %d time: \"%s\".\n",
+ num_resumes,
+ resume_error.AsCString());
+ return_value = eExecutionSetupError;
+ break;
+ }
+ }
+
+ TimeValue resume_timeout = TimeValue::Now();
+ resume_timeout.OffsetWithMicroSeconds(500000);
+
+ got_event = listener.WaitForEvent(&resume_timeout, event_sp);
+ if (!got_event)
+ {
+ if (log)
+ log->Printf ("Process::RunThreadPlan(): didn't get any event after resume %d, exiting.",
+ num_resumes);
+
+ errors.Printf("Didn't get any event after resume %d, exiting.", num_resumes);
+ return_value = eExecutionSetupError;
+ break;
+ }
+
+ stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (stop_state != eStateRunning)
+ {
+ bool restarted = false;
+
+ if (stop_state == eStateStopped)
+ {
+ restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get());
+ if (log)
+ log->Printf("Process::RunThreadPlan(): didn't get running event after "
+ "resume %d, got %s instead (restarted: %i, do_resume: %i, handle_running_event: %i).",
+ num_resumes,
+ StateAsCString(stop_state),
+ restarted,
+ do_resume,
+ handle_running_event);
+ }
+
+ if (restarted)
+ {
+ // This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted
+ // event here. But if I do, the best thing is to Halt and then get out of here.
+ Halt();
+ }
+
+ errors.Printf("Didn't get running event after initial resume, got %s instead.",
+ StateAsCString(stop_state));
+ return_value = eExecutionSetupError;
+ break;
+ }
+
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): resuming succeeded.");
+ // We need to call the function synchronously, so spin waiting for it to return.
+ // If we get interrupted while executing, we're going to lose our context, and
+ // won't be able to gather the result at this point.
+ // We set the timeout AFTER the resume, since the resume takes some time and we
+ // don't want to charge that to the timeout.
+ }
+ else
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): waiting for next event.");
+ }
+
+ if (before_first_timeout)
+ {
+ if (run_others)
+ timeout_ptr = &one_thread_timeout;
+ else
+ {
+ if (timeout_usec == 0)
+ timeout_ptr = NULL;
+ else
+ timeout_ptr = &final_timeout;
+ }
+ }
+ else
+ {
+ if (timeout_usec == 0)
+ timeout_ptr = NULL;
+ else
+ timeout_ptr = &final_timeout;
+ }
+
+ do_resume = true;
+ handle_running_event = true;
+
+ // Now wait for the process to stop again:
+ event_sp.reset();
+
+ if (log)
+ {
+ if (timeout_ptr)
+ {
+ log->Printf ("Process::RunThreadPlan(): about to wait - now is %" PRIu64 " - endpoint is %" PRIu64,
+ TimeValue::Now().GetAsMicroSecondsSinceJan1_1970(),
+ timeout_ptr->GetAsMicroSecondsSinceJan1_1970());
+ }
+ else
+ {
+ log->Printf ("Process::RunThreadPlan(): about to wait forever.");
+ }
+ }
+
+ got_event = listener.WaitForEvent (timeout_ptr, event_sp);
+
+ if (got_event)
+ {
+ if (event_sp.get())
+ {
+ bool keep_going = false;
+ if (event_sp->GetType() == eBroadcastBitInterrupt)
+ {
+ Halt();
+ return_value = eExecutionInterrupted;
+ errors.Printf ("Execution halted by user interrupt.");
+ if (log)
+ log->Printf ("Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting.");
+ break;
+ }
+ else
+ {
+ stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (log)
+ log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state));
+
+ switch (stop_state)
+ {
+ case lldb::eStateStopped:
+ {
+ // We stopped, figure out what we are going to do now.
+ ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id);
+ if (!thread_sp)
+ {
+ // Ooh, our thread has vanished. Unlikely that this was successful execution...
+ if (log)
+ log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id);
+ return_value = eExecutionInterrupted;
+ }
+ else
+ {
+ // If we were restarted, we just need to go back up to fetch another event.
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ {
+ if (log)
+ {
+ log->Printf ("Process::RunThreadPlan(): Got a stop and restart, so we'll continue waiting.");
+ }
+ keep_going = true;
+ do_resume = false;
+ handle_running_event = true;
+
+ }
+ else
+ {
+
+ StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ StopReason stop_reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ stop_reason = stop_info_sp->GetStopReason();
+
+
+ // FIXME: We only check if the stop reason is plan complete, should we make sure that
+ // it is OUR plan that is complete?
+ if (stop_reason == eStopReasonPlanComplete)
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): execution completed successfully.");
+ // Now mark this plan as private so it doesn't get reported as the stop reason
+ // after this point.
+ if (thread_plan_sp)
+ thread_plan_sp->SetPrivate (orig_plan_private);
+ return_value = eExecutionCompleted;
+ }
+ else
+ {
+ // Something restarted the target, so just wait for it to stop for real.
+ if (stop_reason == eStopReasonBreakpoint)
+ {
+ if (log)
+ log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
+ return_value = eExecutionHitBreakpoint;
+ if (!ignore_breakpoints)
+ {
+ event_to_broadcast_sp = event_sp;
+ }
+ }
+ else
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
+ if (!unwind_on_error)
+ event_to_broadcast_sp = event_sp;
+ return_value = eExecutionInterrupted;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case lldb::eStateRunning:
+ // This shouldn't really happen, but sometimes we do get two running events without an
+ // intervening stop, and in that case we should just go back to waiting for the stop.
+ do_resume = false;
+ keep_going = true;
+ handle_running_event = false;
+ break;
+
+ default:
+ if (log)
+ log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state));
+
+ if (stop_state == eStateExited)
+ event_to_broadcast_sp = event_sp;
+
+ errors.Printf ("Execution stopped with unexpected state.\n");
+ return_value = eExecutionInterrupted;
+ break;
+ }
+ }
+
+ if (keep_going)
+ continue;
+ else
+ break;
+ }
+ else
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd...");
+ return_value = eExecutionInterrupted;
+ break;
+ }
+ }
+ else
+ {
+ // If we didn't get an event that means we've timed out...
+ // We will interrupt the process here. Depending on what we were asked to do we will
+ // either exit, or try with all threads running for the same timeout.
+
+ if (log) {
+ if (run_others)
+ {
+ uint64_t remaining_time = final_timeout - TimeValue::Now();
+ if (before_first_timeout)
+ log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
+ "running till for %" PRId64 " usec with all threads enabled.",
+ remaining_time);
+ else
+ log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "
+ "and timeout: %d timed out, abandoning execution.",
+ timeout_usec);
+ }
+ else
+ log->Printf ("Process::RunThreadPlan(): Running function with timeout: %d timed out, "
+ "abandoning execution.",
+ timeout_usec);
+ }
+
+ // It is possible that between the time we issued the Halt, and we get around to calling Halt the target
+ // could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event.
+ // BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In
+ // that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's
+ // stopped event. That's what this while loop does.
+
+ bool back_to_top = true;
+ uint32_t try_halt_again = 0;
+ bool do_halt = true;
+ const uint32_t num_retries = 5;
+ while (try_halt_again < num_retries)
+ {
+ Error halt_error;
+ if (do_halt)
+ {
+ if (log)
+ log->Printf ("Process::RunThreadPlan(): Running Halt.");
+ halt_error = Halt();
+ }
+ if (halt_error.Success())
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
+
+ real_timeout = TimeValue::Now();
+ real_timeout.OffsetWithMicroSeconds(500000);
+
+ got_event = listener.WaitForEvent(&real_timeout, event_sp);
+
+ if (got_event)
+ {
+ stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (log)
+ {
+ log->Printf ("Process::RunThreadPlan(): Stopped with event: %s", StateAsCString(stop_state));
+ if (stop_state == lldb::eStateStopped
+ && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
+ log->PutCString (" Event was the Halt interruption event.");
+ }
+
+ if (stop_state == lldb::eStateStopped)
+ {
+ // Between the time we initiated the Halt and the time we delivered it, the process could have
+ // already finished its job. Check that here:
+
+ if (thread->IsThreadPlanDone (thread_plan_sp.get()))
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
+ "Exiting wait loop.");
+ return_value = eExecutionCompleted;
+ back_to_top = false;
+ break;
+ }
+
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): Went to halt but got a restarted event, there must be an un-restarted stopped event so try again... "
+ "Exiting wait loop.");
+ try_halt_again++;
+ do_halt = false;
+ continue;
+ }
+
+ if (!run_others)
+ {
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
+ return_value = eExecutionInterrupted;
+ back_to_top = false;
+ break;
+ }
+
+ if (before_first_timeout)
+ {
+ // Set all the other threads to run, and return to the top of the loop, which will continue;
+ before_first_timeout = false;
+ thread_plan_sp->SetStopOthers (false);
+ if (log)
+ log->PutCString ("Process::RunThreadPlan(): about to resume.");
+
+ back_to_top = true;
+ break;
+ }
+ else
+ {
+ // Running all threads failed, so return Interrupted.
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
+ return_value = eExecutionInterrupted;
+ back_to_top = false;
+ break;
+ }
+ }
+ }
+ else
+ { if (log)
+ log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
+ "I'm getting out of here passing Interrupted.");
+ return_value = eExecutionInterrupted;
+ back_to_top = false;
+ break;
+ }
+ }
+ else
+ {
+ try_halt_again++;
+ continue;
+ }
+ }
+
+ if (!back_to_top || try_halt_again > num_retries)
+ break;
+ else
+ continue;
+ }
+ } // END WAIT LOOP
+
+ // If we had to start up a temporary private state thread to run this thread plan, shut it down now.
+ if (IS_VALID_LLDB_HOST_THREAD(backup_private_state_thread))
+ {
+ StopPrivateStateThread();
+ Error error;
+ m_private_state_thread = backup_private_state_thread;
+ if (stopper_base_plan_sp)
+ {
+ thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
+ }
+ m_public_state.SetValueNoLock(old_state);
+
+ }
+
+ // Restore the thread state if we are going to discard the plan execution. There are three cases where this
+ // could happen:
+ // 1) The execution successfully completed
+ // 2) We hit a breakpoint, and ignore_breakpoints was true
+ // 3) We got some other error, and discard_on_error was true
+ bool should_unwind = (return_value == eExecutionInterrupted && unwind_on_error)
+ || (return_value == eExecutionHitBreakpoint && ignore_breakpoints);
+
+ if (return_value == eExecutionCompleted
+ || should_unwind)
+ {
+ thread_plan_sp->RestoreThreadState();
+ }
+
+ // Now do some processing on the results of the run:
+ if (return_value == eExecutionInterrupted || return_value == eExecutionHitBreakpoint)
+ {
+ if (log)
+ {
+ StreamString s;
+ if (event_sp)
+ event_sp->Dump (&s);
+ else
+ {
+ log->PutCString ("Process::RunThreadPlan(): Stop event that interrupted us is NULL.");
+ }
+
+ StreamString ts;
+
+ const char *event_explanation = NULL;
+
+ do
+ {
+ if (!event_sp)
+ {
+ event_explanation = "<no event>";
+ break;
+ }
+ else if (event_sp->GetType() == eBroadcastBitInterrupt)
+ {
+ event_explanation = "<user interrupt>";
+ break;
+ }
+ else
+ {
+ const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get());
+
+ if (!event_data)
+ {
+ event_explanation = "<no event data>";
+ break;
+ }
+
+ Process *process = event_data->GetProcessSP().get();
+
+ if (!process)
+ {
+ event_explanation = "<no process>";
+ break;
+ }
+
+ ThreadList &thread_list = process->GetThreadList();
+
+ uint32_t num_threads = thread_list.GetSize();
+ uint32_t thread_index;
+
+ ts.Printf("<%u threads> ", num_threads);
+
+ for (thread_index = 0;
+ thread_index < num_threads;
+ ++thread_index)
+ {
+ Thread *thread = thread_list.GetThreadAtIndex(thread_index).get();
+
+ if (!thread)
+ {
+ ts.Printf("<?> ");
+ continue;
+ }
+
+ ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID());
+ RegisterContext *register_context = thread->GetRegisterContext().get();
+
+ if (register_context)
+ ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC());
+ else
+ ts.Printf("[ip unknown] ");
+
+ lldb::StopInfoSP stop_info_sp = thread->GetStopInfo();
+ if (stop_info_sp)
+ {
+ const char *stop_desc = stop_info_sp->GetDescription();
+ if (stop_desc)
+ ts.PutCString (stop_desc);
+ }
+ ts.Printf(">");
+ }
+
+ event_explanation = ts.GetData();
+ }
+ } while (0);
+
+ if (event_explanation)
+ log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation);
+ else
+ log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData());
+ }
+
+ if (should_unwind && thread_plan_sp)
+ {
+ if (log)
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get());
+ thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+ thread_plan_sp->SetPrivate (orig_plan_private);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get());
+ }
+ }
+ else if (return_value == eExecutionSetupError)
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): execution set up error.");
+
+ if (unwind_on_error && thread_plan_sp)
+ {
+ thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+ thread_plan_sp->SetPrivate (orig_plan_private);
+ }
+ }
+ else
+ {
+ if (thread->IsThreadPlanDone (thread_plan_sp.get()))
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): thread plan is done");
+ return_value = eExecutionCompleted;
+ }
+ else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get()))
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): thread plan was discarded");
+ return_value = eExecutionDiscarded;
+ }
+ else
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course");
+ if (unwind_on_error && thread_plan_sp)
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set.");
+ thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+ thread_plan_sp->SetPrivate (orig_plan_private);
+ }
+ }
+ }
+
+ // Thread we ran the function in may have gone away because we ran the target
+ // Check that it's still there, and if it is put it back in the context. Also restore the
+ // frame in the context if it is still present.
+ thread = GetThreadList().FindThreadByIndexID(thread_idx_id, true).get();
+ if (thread)
+ {
+ exe_ctx.SetFrameSP (thread->GetFrameWithStackID (ctx_frame_id));
+ }
+
+ // Also restore the current process'es selected frame & thread, since this function calling may
+ // be done behind the user's back.
+
+ if (selected_tid != LLDB_INVALID_THREAD_ID)
+ {
+ if (GetThreadList().SetSelectedThreadByIndexID (selected_tid) && selected_stack_id.IsValid())
+ {
+ // We were able to restore the selected thread, now restore the frame:
+ Mutex::Locker lock(GetThreadList().GetMutex());
+ StackFrameSP old_frame_sp = GetThreadList().GetSelectedThread()->GetFrameWithStackID(selected_stack_id);
+ if (old_frame_sp)
+ GetThreadList().GetSelectedThread()->SetSelectedFrame(old_frame_sp.get());
+ }
+ }
+ }
+
+ // If the process exited during the run of the thread plan, notify everyone.
+
+ if (event_to_broadcast_sp)
+ {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): rebroadcasting event.");
+ BroadcastEvent(event_to_broadcast_sp);
+ }
+
+ return return_value;
+}
+
+const char *
+Process::ExecutionResultAsCString (ExecutionResults result)
+{
+ const char *result_name;
+
+ switch (result)
+ {
+ case eExecutionCompleted:
+ result_name = "eExecutionCompleted";
+ break;
+ case eExecutionDiscarded:
+ result_name = "eExecutionDiscarded";
+ break;
+ case eExecutionInterrupted:
+ result_name = "eExecutionInterrupted";
+ break;
+ case eExecutionHitBreakpoint:
+ result_name = "eExecutionHitBreakpoint";
+ break;
+ case eExecutionSetupError:
+ result_name = "eExecutionSetupError";
+ break;
+ case eExecutionTimedOut:
+ result_name = "eExecutionTimedOut";
+ break;
+ }
+ return result_name;
+}
+
+void
+Process::GetStatus (Stream &strm)
+{
+ const StateType state = GetState();
+ if (StateIsStoppedState(state, false))
+ {
+ if (state == eStateExited)
+ {
+ int exit_status = GetExitStatus();
+ const char *exit_description = GetExitDescription();
+ strm.Printf ("Process %" PRIu64 " exited with status = %i (0x%8.8x) %s\n",
+ GetID(),
+ exit_status,
+ exit_status,
+ exit_description ? exit_description : "");
+ }
+ else
+ {
+ if (state == eStateConnected)
+ strm.Printf ("Connected to remote target.\n");
+ else
+ strm.Printf ("Process %" PRIu64 " %s\n", GetID(), StateAsCString (state));
+ }
+ }
+ else
+ {
+ strm.Printf ("Process %" PRIu64 " is running.\n", GetID());
+ }
+}
+
+size_t
+Process::GetThreadStatus (Stream &strm,
+ bool only_threads_with_stop_reason,
+ uint32_t start_frame,
+ uint32_t num_frames,
+ uint32_t num_frames_with_source)
+{
+ size_t num_thread_infos_dumped = 0;
+
+ Mutex::Locker locker (GetThreadList().GetMutex());
+ const size_t num_threads = GetThreadList().GetSize();
+ for (uint32_t i = 0; i < num_threads; i++)
+ {
+ Thread *thread = GetThreadList().GetThreadAtIndex(i).get();
+ if (thread)
+ {
+ if (only_threads_with_stop_reason)
+ {
+ StopInfoSP stop_info_sp = thread->GetStopInfo();
+ if (stop_info_sp.get() == NULL || !stop_info_sp->IsValid())
+ continue;
+ }
+ thread->GetStatus (strm,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ ++num_thread_infos_dumped;
+ }
+ }
+ return num_thread_infos_dumped;
+}
+
+void
+Process::AddInvalidMemoryRegion (const LoadRange &region)
+{
+ m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize());
+}
+
+bool
+Process::RemoveInvalidMemoryRange (const LoadRange &region)
+{
+ return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(), region.GetByteSize());
+}
+
+void
+Process::AddPreResumeAction (PreResumeActionCallback callback, void *baton)
+{
+ m_pre_resume_actions.push_back(PreResumeCallbackAndBaton (callback, baton));
+}
+
+bool
+Process::RunPreResumeActions ()
+{
+ bool result = true;
+ while (!m_pre_resume_actions.empty())
+ {
+ 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;
+ }
+ return result;
+}
+
+void
+Process::ClearPreResumeActions ()
+{
+ m_pre_resume_actions.clear();
+}
+
+void
+Process::Flush ()
+{
+ m_thread_list.Flush();
+}
+
+void
+Process::DidExec ()
+{
+ Target &target = GetTarget();
+ target.CleanupProcess ();
+ ModuleList unloaded_modules (target.GetImages());
+ target.ModulesDidUnload (unloaded_modules);
+ target.GetSectionLoadList().Clear();
+ m_dynamic_checkers_ap.reset();
+ m_abi_sp.reset();
+ m_os_ap.reset();
+ m_dyld_ap.reset();
+ m_image_tokens.clear();
+ m_allocated_memory_cache.Clear();
+ m_language_runtimes.clear();
+ m_thread_list.DiscardThreadPlans();
+ m_memory_cache.Clear(true);
+ DoDidExec();
+ CompleteAttach ();
+}
diff --git a/source/Target/RegisterContext.cpp b/source/Target/RegisterContext.cpp
new file mode 100644
index 000000000000..0d89db724ab4
--- /dev/null
+++ b/source/Target/RegisterContext.cpp
@@ -0,0 +1,600 @@
+//===-- RegisterContext.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/Target/RegisterContext.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContext::RegisterContext (Thread &thread, uint32_t concrete_frame_idx) :
+ m_thread (thread),
+ m_concrete_frame_idx (concrete_frame_idx),
+ m_stop_id (thread.GetProcess()->GetStopID())
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContext::~RegisterContext()
+{
+}
+
+void
+RegisterContext::InvalidateIfNeeded (bool force)
+{
+ ProcessSP process_sp (m_thread.GetProcess());
+ bool invalidate = force;
+ uint32_t process_stop_id = UINT32_MAX;
+
+ if (process_sp)
+ process_stop_id = process_sp->GetStopID();
+ else
+ invalidate = true;
+
+ if (!invalidate)
+ invalidate = process_stop_id != GetStopID();
+
+ if (invalidate)
+ {
+ InvalidateAllRegisters ();
+ SetStopID (process_stop_id);
+ }
+}
+
+
+const RegisterInfo *
+RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
+{
+ if (reg_name && reg_name[0])
+ {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+
+ if ((reg_info->name != NULL && ::strcasecmp (reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != NULL && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
+ {
+ return reg_info;
+ }
+ }
+ }
+ return NULL;
+}
+
+const char *
+RegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return NULL;
+}
+
+uint64_t
+RegisterContext::GetPC(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetPC(uint64_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ bool success = WriteRegisterFromUnsigned (reg, pc);
+ if (success)
+ {
+ StackFrameSP frame_sp(m_thread.GetFrameWithConcreteFrameIndex (m_concrete_frame_idx));
+ if (frame_sp)
+ frame_sp->ChangePC(pc);
+ else
+ m_thread.ClearStackFrames ();
+ }
+ return success;
+}
+
+uint64_t
+RegisterContext::GetSP(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetSP(uint64_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+uint64_t
+RegisterContext::GetFP(uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+bool
+RegisterContext::SetFP(uint64_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+uint64_t
+RegisterContext::GetReturnAddress (uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+uint64_t
+RegisterContext::GetFlags (uint64_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+uint64_t
+RegisterContext::ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+ return fail_value;
+}
+
+uint64_t
+RegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value)
+{
+ if (reg_info)
+ {
+ RegisterValue value;
+ if (ReadRegister (reg_info, value))
+ return value.GetAsUInt64();
+ }
+ return fail_value;
+}
+
+bool
+RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+ return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+bool
+RegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+ if (reg_info)
+ {
+ RegisterValue value;
+ if (value.SetUInt(uval, reg_info->byte_size))
+ return WriteRegister (reg_info, value);
+ }
+ return false;
+}
+
+bool
+RegisterContext::CopyFromRegisterContext (lldb::RegisterContextSP context)
+{
+ uint32_t num_register_sets = context->GetRegisterSetCount();
+ // We don't know that two threads have the same register context, so require the threads to be the same.
+ if (context->GetThreadID() != GetThreadID())
+ return false;
+
+ if (num_register_sets != GetRegisterSetCount())
+ return false;
+
+ RegisterContextSP frame_zero_context = m_thread.GetRegisterContext();
+
+ for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx)
+ {
+ const RegisterSet * const reg_set = GetRegisterSet(set_idx);
+
+ const uint32_t num_registers = reg_set->num_registers;
+ for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
+ {
+ const uint32_t reg = reg_set->registers[reg_idx];
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (!reg_info || reg_info->value_regs)
+ continue;
+ RegisterValue reg_value;
+
+ // If we can reconstruct the register from the frame we are copying from, then do so, otherwise
+ // use the value from frame 0.
+ if (context->ReadRegister(reg_info, reg_value))
+ {
+ WriteRegister(reg_info, reg_value);
+ }
+ else if (frame_zero_context->ReadRegister(reg_info, reg_value))
+ {
+ WriteRegister(reg_info, reg_value);
+ }
+ }
+ }
+ return true;
+}
+
+lldb::tid_t
+RegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+RegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+RegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+RegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+RegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+RegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Error
+RegisterContext::ReadRegisterValueFromMemory (const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ uint32_t src_len,
+ RegisterValue &reg_value)
+{
+ Error error;
+ if (reg_info == NULL)
+ {
+ error.SetErrorString ("invalid register info argument.");
+ return error;
+ }
+
+
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > RegisterValue::kMaxRegisterByteSize)
+ {
+ error.SetErrorString ("register too small to receive memory data");
+ return error;
+ }
+
+ const uint32_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len);
+ return error;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ const uint32_t bytes_read = process_sp->ReadMemory (src_addr, src, src_len, error);
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len)
+ {
+ if (error.Success())
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read, src_len);
+ }
+ return error;
+ }
+
+ // We now have a memory buffer that contains the part or all of the register
+ // value. Set the register value using this memory data.
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+ reg_value.SetFromMemoryData (reg_info,
+ src,
+ src_len,
+ process_sp->GetByteOrder(),
+ error);
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+Error
+RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info,
+ lldb::addr_t dst_addr,
+ uint32_t dst_len,
+ const RegisterValue &reg_value)
+{
+
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (process_sp)
+ {
+
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are assuming
+ // they are the same.
+
+ const uint32_t bytes_copied = reg_value.GetAsMemoryData (reg_info,
+ dst,
+ dst_len,
+ process_sp->GetByteOrder(),
+ error);
+
+ if (error.Success())
+ {
+ if (bytes_copied == 0)
+ {
+ error.SetErrorString("byte copy failed.");
+ }
+ else
+ {
+ const uint32_t bytes_written = process_sp->WriteMemory (dst_addr, dst, bytes_copied, error);
+ if (bytes_written != bytes_copied)
+ {
+ if (error.Success())
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %u of %u bytes", bytes_written, bytes_copied);
+ }
+ }
+ }
+ }
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+
+}
+
+TargetSP
+RegisterContext::CalculateTarget ()
+{
+ return m_thread.CalculateTarget();
+}
+
+
+ProcessSP
+RegisterContext::CalculateProcess ()
+{
+ return m_thread.CalculateProcess ();
+}
+
+ThreadSP
+RegisterContext::CalculateThread ()
+{
+ return m_thread.shared_from_this();
+}
+
+StackFrameSP
+RegisterContext::CalculateStackFrame ()
+{
+ // Register contexts might belong to many frames if we have inlined
+ // functions inside a frame since all inlined functions share the
+ // same registers, so we can't definitively say which frame we come from...
+ return StackFrameSP();
+}
+
+void
+RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx)
+{
+ m_thread.CalculateExecutionContext (exe_ctx);
+}
+
+
+bool
+RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum)
+{
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = 0; reg < num_registers; ++reg)
+ {
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
+
+ if (reg_info->kinds[source_rk] == source_regnum)
+ {
+ target_regnum = reg_info->kinds[target_rk];
+ if (target_regnum == LLDB_INVALID_REGNUM)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//bool
+//RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+//{
+// DataExtractor data;
+// if (!ReadRegisterBytes (reg, data))
+// return false;
+//
+// const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+// uint32_t offset = 0;
+// switch (reg_info->encoding)
+// {
+// case eEncodingInvalid:
+// case eEncodingVector:
+// break;
+//
+// case eEncodingUint:
+// switch (reg_info->byte_size)
+// {
+// case 1:
+// {
+// value = data.GetU8 (&offset);
+// return true;
+// }
+// case 2:
+// {
+// value = data.GetU16 (&offset);
+// return true;
+// }
+// case 4:
+// {
+// value = data.GetU32 (&offset);
+// return true;
+// }
+// case 8:
+// {
+// value = data.GetU64 (&offset);
+// return true;
+// }
+// }
+// break;
+// case eEncodingSint:
+// switch (reg_info->byte_size)
+// {
+// case 1:
+// {
+// int8_t v;
+// if (data.ExtractBytes (0, sizeof (int8_t), lldb::endian::InlHostByteOrder(), &v) != sizeof (int8_t))
+// return false;
+// value = v;
+// return true;
+// }
+// case 2:
+// {
+// int16_t v;
+// if (data.ExtractBytes (0, sizeof (int16_t), lldb::endian::InlHostByteOrder(), &v) != sizeof (int16_t))
+// return false;
+// value = v;
+// return true;
+// }
+// case 4:
+// {
+// int32_t v;
+// if (data.ExtractBytes (0, sizeof (int32_t), lldb::endian::InlHostByteOrder(), &v) != sizeof (int32_t))
+// return false;
+// value = v;
+// return true;
+// }
+// case 8:
+// {
+// int64_t v;
+// if (data.ExtractBytes (0, sizeof (int64_t), lldb::endian::InlHostByteOrder(), &v) != sizeof (int64_t))
+// return false;
+// value = v;
+// return true;
+// }
+// }
+// break;
+// case eEncodingIEEE754:
+// switch (reg_info->byte_size)
+// {
+// case sizeof (float):
+// {
+// float v;
+// if (data.ExtractBytes (0, sizeof (float), lldb::endian::InlHostByteOrder(), &v) != sizeof (float))
+// return false;
+// value = v;
+// return true;
+// }
+// case sizeof (double):
+// {
+// double v;
+// if (data.ExtractBytes (0, sizeof (double), lldb::endian::InlHostByteOrder(), &v) != sizeof (double))
+// return false;
+// value = v;
+// return true;
+// }
+// case sizeof (long double):
+// {
+// double v;
+// if (data.ExtractBytes (0, sizeof (long double), lldb::endian::InlHostByteOrder(), &v) != sizeof (long double))
+// return false;
+// value = v;
+// return true;
+// }
+// }
+// break;
+// }
+// return false;
+//}
+//
+//bool
+//RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+//{
+// DataExtractor data;
+// if (!value.IsValid())
+// return false;
+// if (!value.GetData (data))
+// return false;
+//
+// return WriteRegisterBytes (reg, data);
+//}
diff --git a/source/Target/SectionLoadList.cpp b/source/Target/SectionLoadList.cpp
new file mode 100644
index 000000000000..96713c6ea797
--- /dev/null
+++ b/source/Target/SectionLoadList.cpp
@@ -0,0 +1,276 @@
+//===-- SectionLoadList.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/SectionLoadList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+SectionLoadList::IsEmpty() const
+{
+ Mutex::Locker locker(m_mutex);
+ return m_addr_to_sect.empty();
+}
+
+void
+SectionLoadList::Clear ()
+{
+ Mutex::Locker locker(m_mutex);
+ m_addr_to_sect.clear();
+ m_sect_to_addr.clear();
+}
+
+addr_t
+SectionLoadList::GetSectionLoadAddress (const lldb::SectionSP &section) const
+{
+ // TODO: add support for the same section having multiple load addresses
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ if (section)
+ {
+ Mutex::Locker locker(m_mutex);
+ sect_to_addr_collection::const_iterator pos = m_sect_to_addr.find (section.get());
+
+ if (pos != m_sect_to_addr.end())
+ section_load_addr = pos->second;
+ }
+ return section_load_addr;
+}
+
+bool
+SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t load_addr, bool warn_multiple)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
+
+ ModuleSP module_sp (section->GetModule());
+
+ if (module_sp)
+ {
+ if (log)
+ {
+ const FileSpec &module_file_spec (module_sp->GetFileSpec());
+ log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ") module = %p",
+ __FUNCTION__,
+ section.get(),
+ module_file_spec.GetPath().c_str(),
+ section->GetName().AsCString(),
+ load_addr,
+ module_sp.get());
+ }
+
+ if (section->GetByteSize() == 0)
+ return false; // No change
+
+ // Fill in the section -> load_addr map
+ Mutex::Locker locker(m_mutex);
+ sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section.get());
+ if (sta_pos != m_sect_to_addr.end())
+ {
+ if (load_addr == sta_pos->second)
+ return false; // No change...
+ else
+ sta_pos->second = load_addr;
+ }
+ else
+ m_sect_to_addr[section.get()] = load_addr;
+
+ // Fill in the load_addr -> section map
+ addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
+ if (ats_pos != m_addr_to_sect.end())
+ {
+ // Some sections are ok to overlap, and for others we should warn. When
+ // we have multiple load addresses that correspond to a section, we will
+ // allways attribute the section to the be last section that claims it
+ // exists at that address. Sometimes it is ok for more that one section
+ // to be loaded at a specific load address, and other times it isn't.
+ // The "warn_multiple" parameter tells us if we should warn in this case
+ // or not. The DynamicLoader plug-in subclasses should know which
+ // sections should warn and which shouldn't (darwin shared cache modules
+ // all shared the same "__LINKEDIT" sections, so the dynamic loader can
+ // pass false for "warn_multiple").
+ if (warn_multiple && section != ats_pos->second)
+ {
+ ModuleSP module_sp (section->GetModule());
+ if (module_sp)
+ {
+ ModuleSP curr_module_sp (ats_pos->second->GetModule());
+ if (curr_module_sp)
+ {
+ module_sp->ReportWarning ("address 0x%16.16" PRIx64 " maps to more than one section: %s.%s and %s.%s",
+ load_addr,
+ module_sp->GetFileSpec().GetFilename().GetCString(),
+ section->GetName().GetCString(),
+ curr_module_sp->GetFileSpec().GetFilename().GetCString(),
+ ats_pos->second->GetName().GetCString());
+ }
+ }
+ }
+ ats_pos->second = section;
+ }
+ else
+ m_addr_to_sect[load_addr] = section;
+ return true; // Changed
+
+ }
+ else
+ {
+ if (log)
+ {
+ log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted",
+ __FUNCTION__,
+ section.get(),
+ section->GetName().AsCString(),
+ load_addr);
+ }
+ }
+ return false;
+}
+
+size_t
+SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp)
+{
+ size_t unload_count = 0;
+
+ if (section_sp)
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
+
+ if (log)
+ {
+ const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
+ log->Printf ("SectionLoadList::%s (section = %p (%s.%s))",
+ __FUNCTION__,
+ section_sp.get(),
+ module_file_spec.GetPath().c_str(),
+ section_sp->GetName().AsCString());
+ }
+
+ Mutex::Locker locker(m_mutex);
+
+ sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());
+ if (sta_pos != m_sect_to_addr.end())
+ {
+ ++unload_count;
+ addr_t load_addr = sta_pos->second;
+ m_sect_to_addr.erase (sta_pos);
+
+ addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
+ if (ats_pos != m_addr_to_sect.end())
+ m_addr_to_sect.erase (ats_pos);
+ }
+ }
+ return unload_count;
+}
+
+bool
+SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp, addr_t load_addr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
+
+ if (log)
+ {
+ const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
+ log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")",
+ __FUNCTION__,
+ section_sp.get(),
+ module_file_spec.GetPath().c_str(),
+ section_sp->GetName().AsCString(),
+ load_addr);
+ }
+ bool erased = false;
+ Mutex::Locker locker(m_mutex);
+ sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());
+ if (sta_pos != m_sect_to_addr.end())
+ {
+ erased = true;
+ m_sect_to_addr.erase (sta_pos);
+ }
+
+ addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
+ if (ats_pos != m_addr_to_sect.end())
+ {
+ erased = true;
+ m_addr_to_sect.erase (ats_pos);
+ }
+
+ return erased;
+}
+
+
+bool
+SectionLoadList::ResolveLoadAddress (addr_t load_addr, Address &so_addr) const
+{
+ // First find the top level section that this load address exists in
+ Mutex::Locker locker(m_mutex);
+ if (!m_addr_to_sect.empty())
+ {
+ addr_to_sect_collection::const_iterator pos = m_addr_to_sect.lower_bound (load_addr);
+ if (pos != m_addr_to_sect.end())
+ {
+ if (load_addr != pos->first && pos != m_addr_to_sect.begin())
+ --pos;
+ const addr_t pos_load_addr = pos->first;
+ if (load_addr >= pos_load_addr)
+ {
+ addr_t offset = load_addr - pos_load_addr;
+ if (offset < pos->second->GetByteSize())
+ {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return pos->second->ResolveContainedAddress (offset, so_addr);
+ }
+ }
+ }
+ else
+ {
+ // There are no entries that have an address that is >= load_addr,
+ // so we need to check the last entry on our collection.
+ addr_to_sect_collection::const_reverse_iterator rpos = m_addr_to_sect.rbegin();
+ if (load_addr >= rpos->first)
+ {
+ addr_t offset = load_addr - rpos->first;
+ if (offset < rpos->second->GetByteSize())
+ {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return rpos->second->ResolveContainedAddress (offset, so_addr);
+ }
+ }
+ }
+ }
+ so_addr.Clear();
+ return false;
+}
+
+void
+SectionLoadList::Dump (Stream &s, Target *target)
+{
+ Mutex::Locker locker(m_mutex);
+ addr_to_sect_collection::const_iterator pos, end;
+ for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; ++pos)
+ {
+ s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first, pos->second.get());
+ pos->second->Dump (&s, target, 0);
+ }
+}
+
+
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
new file mode 100644
index 000000000000..3c4c43d9f44c
--- /dev/null
+++ b/source/Target/StackFrame.cpp
@@ -0,0 +1,1449 @@
+//===-- StackFrame.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/StackFrame.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContextScope.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// The first bits in the flags are reserved for the SymbolContext::Scope bits
+// so we know if we have tried to look up information in our internal symbol
+// context (m_sc) already.
+#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1))
+#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1)
+#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1)
+#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1)
+#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1)
+
+StackFrame::StackFrame (const ThreadSP &thread_sp,
+ user_id_t frame_idx,
+ user_id_t unwind_frame_index,
+ addr_t cfa,
+ addr_t pc,
+ const SymbolContext *sc_ptr) :
+ m_thread_wp (thread_sp),
+ m_frame_index (frame_idx),
+ m_concrete_frame_index (unwind_frame_index),
+ m_reg_context_sp (),
+ m_id (pc, cfa, NULL),
+ m_frame_code_addr (pc),
+ m_sc (),
+ m_flags (),
+ m_frame_base (),
+ m_frame_base_error (),
+ m_variable_list_sp (),
+ m_variable_list_value_objects (),
+ m_disassembly ()
+{
+ if (sc_ptr != NULL)
+ {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask ());
+ }
+}
+
+StackFrame::StackFrame (const ThreadSP &thread_sp,
+ user_id_t frame_idx,
+ user_id_t unwind_frame_index,
+ const RegisterContextSP &reg_context_sp,
+ addr_t cfa,
+ addr_t pc,
+ const SymbolContext *sc_ptr) :
+ m_thread_wp (thread_sp),
+ m_frame_index (frame_idx),
+ m_concrete_frame_index (unwind_frame_index),
+ m_reg_context_sp (reg_context_sp),
+ m_id (pc, cfa, NULL),
+ m_frame_code_addr (pc),
+ m_sc (),
+ m_flags (),
+ m_frame_base (),
+ m_frame_base_error (),
+ m_variable_list_sp (),
+ m_variable_list_value_objects (),
+ m_disassembly ()
+{
+ if (sc_ptr != NULL)
+ {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask ());
+ }
+
+ if (reg_context_sp && !m_sc.target_sp)
+ {
+ m_sc.target_sp = reg_context_sp->CalculateTarget();
+ if (m_sc.target_sp)
+ m_flags.Set (eSymbolContextTarget);
+ }
+}
+
+StackFrame::StackFrame (const ThreadSP &thread_sp,
+ user_id_t frame_idx,
+ user_id_t unwind_frame_index,
+ const RegisterContextSP &reg_context_sp,
+ addr_t cfa,
+ const Address& pc_addr,
+ const SymbolContext *sc_ptr) :
+ m_thread_wp (thread_sp),
+ m_frame_index (frame_idx),
+ m_concrete_frame_index (unwind_frame_index),
+ m_reg_context_sp (reg_context_sp),
+ m_id (pc_addr.GetLoadAddress (thread_sp->CalculateTarget().get()), cfa, NULL),
+ m_frame_code_addr (pc_addr),
+ m_sc (),
+ m_flags (),
+ m_frame_base (),
+ m_frame_base_error (),
+ m_variable_list_sp (),
+ m_variable_list_value_objects (),
+ m_disassembly ()
+{
+ if (sc_ptr != NULL)
+ {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask ());
+ }
+
+ if (m_sc.target_sp.get() == NULL && reg_context_sp)
+ {
+ m_sc.target_sp = reg_context_sp->CalculateTarget();
+ if (m_sc.target_sp)
+ m_flags.Set (eSymbolContextTarget);
+ }
+
+ ModuleSP pc_module_sp (pc_addr.GetModule());
+ if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp)
+ {
+ if (pc_module_sp)
+ {
+ m_sc.module_sp = pc_module_sp;
+ m_flags.Set (eSymbolContextModule);
+ }
+ else
+ {
+ m_sc.module_sp.reset();
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrame::~StackFrame()
+{
+}
+
+StackID&
+StackFrame::GetStackID()
+{
+ // Make sure we have resolved the StackID object's symbol context scope if
+ // we already haven't looked it up.
+
+ if (m_flags.IsClear (RESOLVED_FRAME_ID_SYMBOL_SCOPE))
+ {
+ if (m_id.GetSymbolContextScope ())
+ {
+ // We already have a symbol context scope, we just don't have our
+ // flag bit set.
+ m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
+ }
+ else
+ {
+ // Calculate the frame block and use this for the stack ID symbol
+ // context scope if we have one.
+ SymbolContextScope *scope = GetFrameBlock ();
+ if (scope == NULL)
+ {
+ // We don't have a block, so use the symbol
+ if (m_flags.IsClear (eSymbolContextSymbol))
+ GetSymbolContext (eSymbolContextSymbol);
+
+ // It is ok if m_sc.symbol is NULL here
+ scope = m_sc.symbol;
+ }
+ // Set the symbol context scope (the accessor will set the
+ // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags).
+ SetSymbolContextScope (scope);
+ }
+ }
+ return m_id;
+}
+
+uint32_t
+StackFrame::GetFrameIndex () const
+{
+ ThreadSP thread_sp = GetThread();
+ if (thread_sp)
+ return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex(m_frame_index);
+ else
+ return m_frame_index;
+}
+
+void
+StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
+{
+ m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
+ m_id.SetSymbolContextScope (symbol_scope);
+}
+
+const Address&
+StackFrame::GetFrameCodeAddress()
+{
+ if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset())
+ {
+ m_flags.Set (RESOLVED_FRAME_CODE_ADDR);
+
+ // Resolve the PC into a temporary address because if ResolveLoadAddress
+ // fails to resolve the address, it will clear the address object...
+ ThreadSP thread_sp (GetThread());
+ if (thread_sp)
+ {
+ TargetSP target_sp (thread_sp->CalculateTarget());
+ if (target_sp)
+ {
+ if (m_frame_code_addr.SetOpcodeLoadAddress (m_frame_code_addr.GetOffset(), target_sp.get()))
+ {
+ ModuleSP module_sp (m_frame_code_addr.GetModule());
+ if (module_sp)
+ {
+ m_sc.module_sp = module_sp;
+ m_flags.Set(eSymbolContextModule);
+ }
+ }
+ }
+ }
+ }
+ return m_frame_code_addr;
+}
+
+void
+StackFrame::ChangePC (addr_t pc)
+{
+ m_frame_code_addr.SetRawAddress(pc);
+ m_sc.Clear(false);
+ m_flags.Reset(0);
+ ThreadSP thread_sp (GetThread());
+ if (thread_sp)
+ thread_sp->ClearStackFrames ();
+}
+
+const char *
+StackFrame::Disassemble ()
+{
+ if (m_disassembly.GetSize() == 0)
+ {
+ ExecutionContext exe_ctx (shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const char *plugin_name = NULL;
+ const char *flavor = NULL;
+ Disassembler::Disassemble (target->GetDebugger(),
+ target->GetArchitecture(),
+ plugin_name,
+ flavor,
+ exe_ctx,
+ 0,
+ 0,
+ 0,
+ m_disassembly);
+ }
+ if (m_disassembly.GetSize() == 0)
+ return NULL;
+ }
+ return m_disassembly.GetData();
+}
+
+Block *
+StackFrame::GetFrameBlock ()
+{
+ if (m_sc.block == NULL && m_flags.IsClear (eSymbolContextBlock))
+ GetSymbolContext (eSymbolContextBlock);
+
+ if (m_sc.block)
+ {
+ Block *inline_block = m_sc.block->GetContainingInlinedBlock();
+ if (inline_block)
+ {
+ // Use the block with the inlined function info
+ // as the frame block we want this frame to have only the variables
+ // for the inlined function and its non-inlined block child blocks.
+ return inline_block;
+ }
+ else
+ {
+ // This block is not contained withing any inlined function blocks
+ // with so we want to use the top most function block.
+ return &m_sc.function->GetBlock (false);
+ }
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Get the symbol context if we already haven't done so by resolving the
+// PC address as much as possible. This way when we pass around a
+// StackFrame object, everyone will have as much information as
+// possible and no one will ever have to look things up manually.
+//----------------------------------------------------------------------
+const SymbolContext&
+StackFrame::GetSymbolContext (uint32_t resolve_scope)
+{
+ // Copy our internal symbol context into "sc".
+ if ((m_flags.Get() & resolve_scope) != resolve_scope)
+ {
+ uint32_t resolved = 0;
+
+ // If the target was requested add that:
+ if (!m_sc.target_sp)
+ {
+ m_sc.target_sp = CalculateTarget();
+ if (m_sc.target_sp)
+ resolved |= eSymbolContextTarget;
+ }
+
+
+ // Resolve our PC to section offset if we haven't alreday done so
+ // and if we don't have a module. The resolved address section will
+ // contain the module to which it belongs
+ if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR))
+ GetFrameCodeAddress();
+
+ // If this is not frame zero, then we need to subtract 1 from the PC
+ // value when doing address lookups since the PC will be on the
+ // instruction following the function call instruction...
+
+ Address lookup_addr(GetFrameCodeAddress());
+ if (m_frame_index > 0 && lookup_addr.IsValid())
+ {
+ addr_t offset = lookup_addr.GetOffset();
+ if (offset > 0)
+ lookup_addr.SetOffset(offset - 1);
+ }
+
+
+ if (m_sc.module_sp)
+ {
+ // We have something in our stack frame symbol context, lets check
+ // if we haven't already tried to lookup one of those things. If we
+ // haven't then we will do the query.
+
+ uint32_t actual_resolve_scope = 0;
+
+ if (resolve_scope & eSymbolContextCompUnit)
+ {
+ if (m_flags.IsClear (eSymbolContextCompUnit))
+ {
+ if (m_sc.comp_unit)
+ resolved |= eSymbolContextCompUnit;
+ else
+ actual_resolve_scope |= eSymbolContextCompUnit;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextFunction)
+ {
+ if (m_flags.IsClear (eSymbolContextFunction))
+ {
+ if (m_sc.function)
+ resolved |= eSymbolContextFunction;
+ else
+ actual_resolve_scope |= eSymbolContextFunction;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ if (m_flags.IsClear (eSymbolContextBlock))
+ {
+ if (m_sc.block)
+ resolved |= eSymbolContextBlock;
+ else
+ actual_resolve_scope |= eSymbolContextBlock;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ if (m_flags.IsClear (eSymbolContextSymbol))
+ {
+ if (m_sc.symbol)
+ resolved |= eSymbolContextSymbol;
+ else
+ actual_resolve_scope |= eSymbolContextSymbol;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextLineEntry)
+ {
+ if (m_flags.IsClear (eSymbolContextLineEntry))
+ {
+ if (m_sc.line_entry.IsValid())
+ resolved |= eSymbolContextLineEntry;
+ else
+ actual_resolve_scope |= eSymbolContextLineEntry;
+ }
+ }
+
+ if (actual_resolve_scope)
+ {
+ // We might be resolving less information than what is already
+ // in our current symbol context so resolve into a temporary
+ // symbol context "sc" so we don't clear out data we have
+ // already found in "m_sc"
+ SymbolContext sc;
+ // Set flags that indicate what we have tried to resolve
+ resolved |= m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, actual_resolve_scope, sc);
+ // Only replace what we didn't already have as we may have
+ // information for an inlined function scope that won't match
+ // what a standard lookup by address would match
+ if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == NULL)
+ m_sc.comp_unit = sc.comp_unit;
+ if ((resolved & eSymbolContextFunction) && m_sc.function == NULL)
+ m_sc.function = sc.function;
+ if ((resolved & eSymbolContextBlock) && m_sc.block == NULL)
+ m_sc.block = sc.block;
+ if ((resolved & eSymbolContextSymbol) && m_sc.symbol == NULL)
+ m_sc.symbol = sc.symbol;
+ if ((resolved & eSymbolContextLineEntry) && !m_sc.line_entry.IsValid())
+ {
+ m_sc.line_entry = sc.line_entry;
+ if (m_sc.target_sp)
+ {
+ // Be sure to apply and file remappings to our file and line
+ // entries when handing out a line entry
+ FileSpec new_file_spec;
+ if (m_sc.target_sp->GetSourcePathMap().FindFile (m_sc.line_entry.file, new_file_spec))
+ m_sc.line_entry.file = new_file_spec;
+ }
+ }
+ }
+ }
+ else
+ {
+ // If we don't have a module, then we can't have the compile unit,
+ // function, block, line entry or symbol, so we can safely call
+ // ResolveSymbolContextForAddress with our symbol context member m_sc.
+ if (m_sc.target_sp)
+ {
+ resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc);
+ }
+ }
+
+ // Update our internal flags so we remember what we have tried to locate so
+ // we don't have to keep trying when more calls to this function are made.
+ // We might have dug up more information that was requested (for example
+ // if we were asked to only get the block, we will have gotten the
+ // compile unit, and function) so set any additional bits that we resolved
+ m_flags.Set (resolve_scope | resolved);
+ }
+
+ // Return the symbol context with everything that was possible to resolve
+ // resolved.
+ return m_sc;
+}
+
+
+VariableList *
+StackFrame::GetVariableList (bool get_file_globals)
+{
+ if (m_flags.IsClear(RESOLVED_VARIABLES))
+ {
+ m_flags.Set(RESOLVED_VARIABLES);
+
+ Block *frame_block = GetFrameBlock();
+
+ if (frame_block)
+ {
+ const bool get_child_variables = true;
+ const bool can_create = true;
+ const bool stop_if_child_block_is_inlined_function = true;
+ m_variable_list_sp.reset(new VariableList());
+ frame_block->AppendBlockVariables(can_create, get_child_variables, stop_if_child_block_is_inlined_function, m_variable_list_sp.get());
+ }
+ }
+
+ if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) &&
+ get_file_globals)
+ {
+ m_flags.Set(RESOLVED_GLOBAL_VARIABLES);
+
+ if (m_flags.IsClear (eSymbolContextCompUnit))
+ GetSymbolContext (eSymbolContextCompUnit);
+
+ if (m_sc.comp_unit)
+ {
+ VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true));
+ if (m_variable_list_sp)
+ m_variable_list_sp->AddVariables (global_variable_list_sp.get());
+ else
+ m_variable_list_sp = global_variable_list_sp;
+ }
+ }
+
+ return m_variable_list_sp.get();
+}
+
+VariableListSP
+StackFrame::GetInScopeVariableList (bool get_file_globals)
+{
+ VariableListSP var_list_sp(new VariableList);
+ GetSymbolContext (eSymbolContextCompUnit | eSymbolContextBlock);
+
+ if (m_sc.block)
+ {
+ const bool can_create = true;
+ const bool get_parent_variables = true;
+ const bool stop_if_block_is_inlined_function = true;
+ m_sc.block->AppendVariables (can_create,
+ get_parent_variables,
+ stop_if_block_is_inlined_function,
+ var_list_sp.get());
+ }
+
+ if (m_sc.comp_unit)
+ {
+ VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true));
+ if (global_variable_list_sp)
+ var_list_sp->AddVariables (global_variable_list_sp.get());
+ }
+
+ return var_list_sp;
+}
+
+
+ValueObjectSP
+StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
+ DynamicValueType use_dynamic,
+ uint32_t options,
+ VariableSP &var_sp,
+ Error &error)
+{
+
+ if (var_expr_cstr && var_expr_cstr[0])
+ {
+ const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0;
+ const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
+ const bool no_synth_child = (options & eExpressionPathOptionsNoSyntheticChildren) != 0;
+ //const bool no_synth_array = (options & eExpressionPathOptionsNoSyntheticArrayRange) != 0;
+ error.Clear();
+ bool deref = false;
+ bool address_of = false;
+ ValueObjectSP valobj_sp;
+ const bool get_file_globals = true;
+ // When looking up a variable for an expression, we need only consider the
+ // variables that are in scope.
+ VariableListSP var_list_sp (GetInScopeVariableList (get_file_globals));
+ VariableList *variable_list = var_list_sp.get();
+
+ if (variable_list)
+ {
+ // If first character is a '*', then show pointer contents
+ const char *var_expr = var_expr_cstr;
+ if (var_expr[0] == '*')
+ {
+ deref = true;
+ var_expr++; // Skip the '*'
+ }
+ else if (var_expr[0] == '&')
+ {
+ address_of = true;
+ var_expr++; // Skip the '&'
+ }
+
+ std::string var_path (var_expr);
+ size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}");
+ StreamString var_expr_path_strm;
+
+ ConstString name_const_string;
+ if (separator_idx == std::string::npos)
+ name_const_string.SetCString (var_path.c_str());
+ else
+ name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx);
+
+ var_sp = variable_list->FindVariable(name_const_string);
+
+ bool synthetically_added_instance_object = false;
+
+ if (var_sp)
+ {
+ var_path.erase (0, name_const_string.GetLength ());
+ }
+ else if (options & eExpressionPathOptionsAllowDirectIVarAccess)
+ {
+ // Check for direct ivars access which helps us with implicit
+ // access to ivars with the "this->" or "self->"
+ GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock);
+ lldb::LanguageType method_language = eLanguageTypeUnknown;
+ bool is_instance_method = false;
+ ConstString method_object_name;
+ if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name))
+ {
+ if (is_instance_method && method_object_name)
+ {
+ var_sp = variable_list->FindVariable(method_object_name);
+ if (var_sp)
+ {
+ separator_idx = 0;
+ var_path.insert(0, "->");
+ synthetically_added_instance_object = true;
+ }
+ }
+ }
+ }
+
+ if (var_sp)
+ {
+ valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic);
+ if (!valobj_sp)
+ return valobj_sp;
+
+ // We are dumping at least one child
+ while (separator_idx != std::string::npos)
+ {
+ // Calculate the next separator index ahead of time
+ ValueObjectSP child_valobj_sp;
+ const char separator_type = var_path[0];
+ switch (separator_type)
+ {
+
+ case '-':
+ if (var_path.size() >= 2 && var_path[1] != '>')
+ return ValueObjectSP();
+
+ if (no_fragile_ivar)
+ {
+ // 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))
+ {
+ // This was an objective C object pointer and
+ // it was requested we skip any fragile ivars
+ // so return nothing here
+ return ValueObjectSP();
+ }
+ }
+ var_path.erase (0, 1); // Remove the '-'
+ // Fall through
+ case '.':
+ {
+ const bool expr_is_ptr = var_path[0] == '>';
+
+ var_path.erase (0, 1); // Remove the '.' or '>'
+ separator_idx = var_path.find_first_of(".-[");
+ ConstString child_name;
+ if (separator_idx == std::string::npos)
+ child_name.SetCString (var_path.c_str());
+ else
+ child_name.SetCStringWithLength(var_path.c_str(), separator_idx);
+
+ if (check_ptr_vs_member)
+ {
+ // We either have a pointer type and need to verify
+ // valobj_sp is a pointer, or we have a member of a
+ // class/union/struct being accessed with the . syntax
+ // and need to verify we don't have a pointer.
+ const bool actual_is_ptr = valobj_sp->IsPointerType ();
+
+ if (actual_is_ptr != expr_is_ptr)
+ {
+ // Incorrect use of "." with a pointer, or "->" with
+ // a class/union/struct instance or reference.
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ if (actual_is_ptr)
+ error.SetErrorStringWithFormat ("\"%s\" is a pointer and . was used to attempt to access \"%s\". Did you mean \"%s->%s\"?",
+ var_expr_path_strm.GetString().c_str(),
+ child_name.GetCString(),
+ var_expr_path_strm.GetString().c_str(),
+ var_path.c_str());
+ else
+ error.SetErrorStringWithFormat ("\"%s\" is not a pointer and -> was used to attempt to access \"%s\". Did you mean \"%s.%s\"?",
+ var_expr_path_strm.GetString().c_str(),
+ child_name.GetCString(),
+ var_expr_path_strm.GetString().c_str(),
+ var_path.c_str());
+ return ValueObjectSP();
+ }
+ }
+ child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
+ if (!child_valobj_sp)
+ {
+ if (no_synth_child == false)
+ {
+ child_valobj_sp = valobj_sp->GetSyntheticValue();
+ if (child_valobj_sp)
+ child_valobj_sp = child_valobj_sp->GetChildMemberWithName (child_name, true);
+ }
+
+ if (no_synth_child || !child_valobj_sp)
+ {
+ // No child member with name "child_name"
+ if (synthetically_added_instance_object)
+ {
+ // We added a "this->" or "self->" to the beginning of the expression
+ // and this is the first pointer ivar access, so just return the normal
+ // error
+ error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame",
+ name_const_string.GetCString());
+ }
+ else
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ if (child_name)
+ {
+ error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"",
+ child_name.GetCString(),
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"",
+ var_expr_path_strm.GetString().c_str(),
+ var_expr_cstr);
+ }
+ }
+ return ValueObjectSP();
+ }
+ }
+ synthetically_added_instance_object = false;
+ // Remove the child name from the path
+ var_path.erase(0, child_name.GetLength());
+ if (use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
+ }
+ break;
+
+ case '[':
+ // Array member access, or treating pointer as an array
+ if (var_path.size() > 2) // Need at least two brackets and a number
+ {
+ char *end = NULL;
+ long child_index = ::strtol (&var_path[1], &end, 0);
+ if (end && *end == ']'
+ && *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go
+ {
+ if (valobj_sp->GetClangType().IsPointerToScalarType() && deref)
+ {
+ // what we have is *ptr[low]. the most similar C++ syntax is to deref ptr
+ // and extract bit low out of it. reading array item low
+ // would be done by saying ptr[low], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->Dereference(error));
+ if (error.Fail())
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+ else if (valobj_sp->GetClangType().IsArrayOfScalarType() && deref)
+ {
+ // what we have is *arr[low]. the most similar C++ syntax is to get arr[0]
+ // (an operation that is equivalent to deref-ing arr)
+ // and extract bit low out of it. reading array item low
+ // would be done by saying arr[low], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
+ if (error.Fail())
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+
+ bool is_incomplete_array = false;
+ if (valobj_sp->IsPointerType ())
+ {
+ bool is_objc_pointer = true;
+
+ if (valobj_sp->GetClangType().GetMinimumLanguage() != eLanguageTypeObjC)
+ is_objc_pointer = false;
+ else if (!valobj_sp->GetClangType().IsPointerType())
+ is_objc_pointer = false;
+
+ if (no_synth_child && is_objc_pointer)
+ {
+ error.SetErrorStringWithFormat("\"(%s) %s\" is an Objective-C pointer, and cannot be subscripted",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+
+ return ValueObjectSP();
+ }
+ else if (is_objc_pointer)
+ {
+ // dereferencing ObjC variables is not valid.. so let's try and recur to synthetic children
+ ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
+ if (synthetic.get() == NULL /* no synthetic */
+ || synthetic == valobj_sp) /* synthetic is the same as the original object */
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ else
+ {
+ child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ }
+ else
+ {
+ child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true);
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("failed to use pointer as array for index %ld for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ }
+ else if (valobj_sp->GetClangType().IsArrayType (NULL, NULL, &is_incomplete_array))
+ {
+ // Pass false to dynamic_value here so we can tell the difference between
+ // no dynamic value and no member of this type...
+ child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
+ if (!child_valobj_sp && (is_incomplete_array || no_synth_child == false))
+ child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true);
+
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ else if (valobj_sp->GetClangType().IsScalarType())
+ {
+ // this is a bitfield asking to display just one bit
+ child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true);
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"",
+ child_index, child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
+ if (no_synth_child /* synthetic is forbidden */ ||
+ synthetic.get() == NULL /* no synthetic */
+ || synthetic == valobj_sp) /* synthetic is the same as the original object */
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ else
+ {
+ child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!child_valobj_sp)
+ {
+ // Invalid array index...
+ return ValueObjectSP();
+ }
+
+ // Erase the array member specification '[%i]' where
+ // %i is the array index
+ var_path.erase(0, (end - var_path.c_str()) + 1);
+ separator_idx = var_path.find_first_of(".-[");
+ if (use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
+ // Break out early from the switch since we were
+ // able to find the child member
+ break;
+ }
+ else if (end && *end == '-')
+ {
+ // this is most probably a BitField, let's take a look
+ char *real_end = NULL;
+ long final_index = ::strtol (end+1, &real_end, 0);
+ bool expand_bitfield = true;
+ if (real_end && *real_end == ']')
+ {
+ // if the format given is [high-low], swap range
+ if (child_index > final_index)
+ {
+ long temp = child_index;
+ child_index = final_index;
+ final_index = temp;
+ }
+
+ if (valobj_sp->GetClangType().IsPointerToScalarType() && deref)
+ {
+ // what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr
+ // and extract bits low thru high out of it. reading array items low thru high
+ // would be done by saying ptr[low-high], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->Dereference(error));
+ if (error.Fail())
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+ else if (valobj_sp->GetClangType().IsArrayOfScalarType() && deref)
+ {
+ // what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0]
+ // (an operation that is equivalent to deref-ing arr)
+ // and extract bits low thru high out of it. reading array items low thru high
+ // would be done by saying arr[low-high], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
+ if (error.Fail())
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+ /*else if (valobj_sp->IsArrayType() || valobj_sp->IsPointerType())
+ {
+ child_valobj_sp = valobj_sp->GetSyntheticArrayRangeChild(child_index, final_index, true);
+ expand_bitfield = false;
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("array range %i-%i is not valid for \"(%s) %s\"",
+ child_index, final_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }*/
+
+ if (expand_bitfield)
+ {
+ child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true);
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"",
+ child_index, final_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!child_valobj_sp)
+ {
+ // Invalid bitfield range...
+ return ValueObjectSP();
+ }
+
+ // Erase the bitfield member specification '[%i-%i]' where
+ // %i is the index
+ var_path.erase(0, (real_end - var_path.c_str()) + 1);
+ separator_idx = var_path.find_first_of(".-[");
+ if (use_dynamic != eNoDynamicValues)
+ {
+ ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
+ // Break out early from the switch since we were
+ // able to find the child member
+ break;
+
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"",
+ var_expr_path_strm.GetString().c_str(),
+ var_path.c_str());
+ }
+ return ValueObjectSP();
+
+ default:
+ // Failure...
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm, false);
+ error.SetErrorStringWithFormat ("unexpected char '%c' encountered after \"%s\" in \"%s\"",
+ separator_type,
+ var_expr_path_strm.GetString().c_str(),
+ var_path.c_str());
+
+ return ValueObjectSP();
+ }
+ }
+
+ if (child_valobj_sp)
+ valobj_sp = child_valobj_sp;
+
+ if (var_path.empty())
+ break;
+
+ }
+ if (valobj_sp)
+ {
+ if (deref)
+ {
+ ValueObjectSP deref_valobj_sp (valobj_sp->Dereference(error));
+ valobj_sp = deref_valobj_sp;
+ }
+ else if (address_of)
+ {
+ ValueObjectSP address_of_valobj_sp (valobj_sp->AddressOf(error));
+ valobj_sp = address_of_valobj_sp;
+ }
+ }
+ return valobj_sp;
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("no variable named '%s' found in this frame",
+ name_const_string.GetCString());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr);
+ }
+ return ValueObjectSP();
+}
+
+bool
+StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
+{
+ if (m_flags.IsClear(GOT_FRAME_BASE))
+ {
+ if (m_sc.function)
+ {
+ m_frame_base.Clear();
+ m_frame_base_error.Clear();
+
+ m_flags.Set(GOT_FRAME_BASE);
+ ExecutionContext exe_ctx (shared_from_this());
+ Value expr_value;
+ addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
+ if (m_sc.function->GetFrameBaseExpression().IsLocationList())
+ loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (exe_ctx.GetTargetPtr());
+
+ if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, NULL, NULL, NULL, loclist_base_addr, NULL, expr_value, &m_frame_base_error) == false)
+ {
+ // We should really have an error if evaluate returns, but in case
+ // we don't, lets set the error to something at least.
+ if (m_frame_base_error.Success())
+ m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed.");
+ }
+ else
+ {
+ m_frame_base = expr_value.ResolveValue(&exe_ctx);
+ }
+ }
+ else
+ {
+ m_frame_base_error.SetErrorString ("No function in symbol context.");
+ }
+ }
+
+ if (m_frame_base_error.Success())
+ frame_base = m_frame_base;
+
+ if (error_ptr)
+ *error_ptr = m_frame_base_error;
+ return m_frame_base_error.Success();
+}
+
+RegisterContextSP
+StackFrame::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ {
+ ThreadSP thread_sp (GetThread());
+ if (thread_sp)
+ m_reg_context_sp = thread_sp->CreateRegisterContextForFrame (this);
+ }
+ return m_reg_context_sp;
+}
+
+bool
+StackFrame::HasDebugInformation ()
+{
+ GetSymbolContext (eSymbolContextLineEntry);
+ return m_sc.line_entry.IsValid();
+}
+
+
+ValueObjectSP
+StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
+{
+ ValueObjectSP valobj_sp;
+ VariableList *var_list = GetVariableList (true);
+ if (var_list)
+ {
+ // Make sure the variable is a frame variable
+ const uint32_t var_idx = var_list->FindIndexForVariable (variable_sp.get());
+ const uint32_t num_variables = var_list->GetSize();
+ if (var_idx < num_variables)
+ {
+ valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex (var_idx);
+ if (valobj_sp.get() == NULL)
+ {
+ if (m_variable_list_value_objects.GetSize() < num_variables)
+ m_variable_list_value_objects.Resize(num_variables);
+ valobj_sp = ValueObjectVariable::Create (this, variable_sp);
+ m_variable_list_value_objects.SetValueObjectAtIndex (var_idx, valobj_sp);
+ }
+ }
+ }
+ if (use_dynamic != eNoDynamicValues && valobj_sp)
+ {
+ ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (use_dynamic);
+ if (dynamic_sp)
+ return dynamic_sp;
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP
+StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
+{
+ // Check to make sure we aren't already tracking this variable?
+ ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic));
+ if (!valobj_sp)
+ {
+ // We aren't already tracking this global
+ VariableList *var_list = GetVariableList (true);
+ // If this frame has no variables, create a new list
+ if (var_list == NULL)
+ m_variable_list_sp.reset (new VariableList());
+
+ // Add the global/static variable to this frame
+ m_variable_list_sp->AddVariable (variable_sp);
+
+ // Now make a value object for it so we can track its changes
+ valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic);
+ }
+ return valobj_sp;
+}
+
+bool
+StackFrame::IsInlined ()
+{
+ if (m_sc.block == NULL)
+ GetSymbolContext (eSymbolContextBlock);
+ if (m_sc.block)
+ return m_sc.block->GetContainingInlinedBlock() != NULL;
+ return false;
+}
+
+TargetSP
+StackFrame::CalculateTarget ()
+{
+ TargetSP target_sp;
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->CalculateProcess());
+ if (process_sp)
+ target_sp = process_sp->CalculateTarget();
+ }
+ return target_sp;
+}
+
+ProcessSP
+StackFrame::CalculateProcess ()
+{
+ ProcessSP process_sp;
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp)
+ process_sp = thread_sp->CalculateProcess();
+ return process_sp;
+}
+
+ThreadSP
+StackFrame::CalculateThread ()
+{
+ return GetThread();
+}
+
+StackFrameSP
+StackFrame::CalculateStackFrame ()
+{
+ return shared_from_this();
+}
+
+
+void
+StackFrame::CalculateExecutionContext (ExecutionContext &exe_ctx)
+{
+ exe_ctx.SetContext (shared_from_this());
+}
+
+void
+StackFrame::DumpUsingSettingsFormat (Stream *strm)
+{
+ if (strm == NULL)
+ return;
+
+ GetSymbolContext(eSymbolContextEverything);
+ ExecutionContext exe_ctx (shared_from_this());
+ StreamString s;
+ const char *frame_format = NULL;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ frame_format = target->GetDebugger().GetFrameFormat();
+ if (frame_format && Debugger::FormatPrompt (frame_format, &m_sc, &exe_ctx, NULL, s))
+ {
+ strm->Write(s.GetData(), s.GetSize());
+ }
+ else
+ {
+ Dump (strm, true, false);
+ strm->EOL();
+ }
+}
+
+void
+StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths)
+{
+ if (strm == NULL)
+ return;
+
+ if (show_frame_index)
+ strm->Printf("frame #%u: ", m_frame_index);
+ ExecutionContext exe_ctx (shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ strm->Printf("0x%0*" PRIx64 " ",
+ target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16,
+ GetFrameCodeAddress().GetLoadAddress(target));
+ GetSymbolContext(eSymbolContextEverything);
+ const bool show_module = true;
+ const bool show_inline = true;
+ m_sc.DumpStopContext (strm,
+ exe_ctx.GetBestExecutionContextScope(),
+ GetFrameCodeAddress(),
+ show_fullpaths,
+ show_module,
+ show_inline);
+}
+
+void
+StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
+{
+ 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);
+ if (!m_disassembly.GetString().empty())
+ m_disassembly.GetString().swap (m_disassembly.GetString());
+}
+
+
+void
+StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame)
+{
+ 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());
+ m_frame_index = curr_frame.m_frame_index;
+ m_concrete_frame_index = curr_frame.m_concrete_frame_index;
+ m_reg_context_sp = curr_frame.m_reg_context_sp;
+ m_frame_code_addr = curr_frame.m_frame_code_addr;
+ assert (m_sc.target_sp.get() == NULL || curr_frame.m_sc.target_sp.get() == NULL || m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get());
+ assert (m_sc.module_sp.get() == NULL || curr_frame.m_sc.module_sp.get() == NULL || m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get());
+ assert (m_sc.comp_unit == NULL || curr_frame.m_sc.comp_unit == NULL || m_sc.comp_unit == curr_frame.m_sc.comp_unit);
+ assert (m_sc.function == NULL || curr_frame.m_sc.function == NULL || m_sc.function == curr_frame.m_sc.function);
+ m_sc = curr_frame.m_sc;
+ m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything);
+ m_flags.Set (m_sc.GetResolvedMask());
+ m_frame_base.Clear();
+ m_frame_base_error.Clear();
+}
+
+
+bool
+StackFrame::HasCachedData () const
+{
+ if (m_variable_list_sp.get())
+ return true;
+ if (m_variable_list_value_objects.GetSize() > 0)
+ return true;
+ if (!m_disassembly.GetString().empty())
+ return true;
+ return false;
+}
+
+bool
+StackFrame::GetStatus (Stream& strm,
+ bool show_frame_info,
+ bool show_source)
+{
+
+ if (show_frame_info)
+ {
+ strm.Indent();
+ DumpUsingSettingsFormat (&strm);
+ }
+
+ if (show_source)
+ {
+ ExecutionContext exe_ctx (shared_from_this());
+ bool have_source = false;
+ Debugger::StopDisassemblyType disasm_display = Debugger::eStopDisassemblyTypeNever;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ Debugger &debugger = target->GetDebugger();
+ const uint32_t source_lines_before = debugger.GetStopSourceLineCount(true);
+ const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false);
+ disasm_display = debugger.GetStopDisassemblyDisplay ();
+
+ if (source_lines_before > 0 || source_lines_after > 0)
+ {
+ GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
+
+ if (m_sc.comp_unit && m_sc.line_entry.IsValid())
+ {
+ have_source = true;
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file,
+ m_sc.line_entry.line,
+ source_lines_before,
+ source_lines_after,
+ "->",
+ &strm);
+ }
+ }
+ switch (disasm_display)
+ {
+ case Debugger::eStopDisassemblyTypeNever:
+ break;
+
+ case Debugger::eStopDisassemblyTypeNoSource:
+ if (have_source)
+ break;
+ // Fall through to next case
+ case Debugger::eStopDisassemblyTypeAlways:
+ if (target)
+ {
+ const uint32_t disasm_lines = debugger.GetDisassemblyLineCount();
+ if (disasm_lines > 0)
+ {
+ const ArchSpec &target_arch = target->GetArchitecture();
+ AddressRange pc_range;
+ pc_range.GetBaseAddress() = GetFrameCodeAddress();
+ pc_range.SetByteSize(disasm_lines * target_arch.GetMaximumOpcodeByteSize());
+ const char *plugin_name = NULL;
+ const char *flavor = NULL;
+ Disassembler::Disassemble (target->GetDebugger(),
+ target_arch,
+ plugin_name,
+ flavor,
+ exe_ctx,
+ pc_range,
+ disasm_lines,
+ 0,
+ Disassembler::eOptionMarkPCAddress,
+ strm);
+ }
+ }
+ break;
+ }
+ }
+ }
+ return true;
+}
+
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
new file mode 100644
index 000000000000..69309dfae7b6
--- /dev/null
+++ b/source/Target/StackFrameList.cpp
@@ -0,0 +1,899 @@
+//===-- StackFrameList.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/StackFrameList.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Unwind.h"
+
+//#define DEBUG_STACK_FRAMES 1
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// StackFrameList constructor
+//----------------------------------------------------------------------
+StackFrameList::StackFrameList
+(
+ Thread &thread,
+ const lldb::StackFrameListSP &prev_frames_sp,
+ bool show_inline_frames
+) :
+ m_thread (thread),
+ m_prev_frames_sp (prev_frames_sp),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_frames (),
+ m_selected_frame_idx (0),
+ m_concrete_frames_fetched (0),
+ m_current_inlined_depth (UINT32_MAX),
+ m_current_inlined_pc (LLDB_INVALID_ADDRESS),
+ m_show_inlined_frames (show_inline_frames)
+{
+ if (prev_frames_sp)
+ {
+ m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
+ m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StackFrameList::~StackFrameList()
+{
+ // Call clear since this takes a lock and clears the stack frame list
+ // in case another thread is currently using this stack frame list
+ Clear();
+}
+
+void
+StackFrameList::CalculateCurrentInlinedDepth()
+{
+ uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
+ if (cur_inlined_depth == UINT32_MAX)
+ {
+ ResetCurrentInlinedDepth();
+ }
+}
+
+uint32_t
+StackFrameList::GetCurrentInlinedDepth ()
+{
+ if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS)
+ {
+ lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ if (cur_pc != m_current_inlined_pc)
+ {
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ m_current_inlined_depth = UINT32_MAX;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("GetCurrentInlinedDepth: invalidating current inlined depth.\n");
+ }
+ return m_current_inlined_depth;
+ }
+ else
+ {
+ return UINT32_MAX;
+ }
+}
+
+void
+StackFrameList::ResetCurrentInlinedDepth ()
+{
+ if (m_show_inlined_frames)
+ {
+ GetFramesUpTo(0);
+ if (!m_frames[0]->IsInlined())
+ {
+ m_current_inlined_depth = UINT32_MAX;
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");
+ }
+ else
+ {
+ // We only need to do something special about inlined blocks when we
+ // are at the beginning of an inlined function:
+ // FIXME: We probably also have to do something special if the PC is at the END
+ // of an inlined function, which coincides with the end of either its containing
+ // function or another inlined function.
+
+ lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
+ Block *block_ptr = m_frames[0]->GetFrameBlock();
+ if (block_ptr)
+ {
+ Address pc_as_address;
+ pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget()));
+ AddressRange containing_range;
+ if (block_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
+ {
+ if (pc_as_address == containing_range.GetBaseAddress())
+ {
+ // If we got here because of a breakpoint hit, then set the inlined depth depending on where
+ // the breakpoint was set.
+ // If we got here because of a crash, then set the inlined depth to the deepest most block.
+ // Otherwise, we stopped here naturally as the result of a step, so set ourselves in the
+ // containing frame of the whole set of nested inlines, so the user can then "virtually"
+ // step into the frames one by one, or next over the whole mess.
+ // Note: We don't have to handle being somewhere in the middle of the stack here, since
+ // ResetCurrentInlinedDepth doesn't get called if there is a valid inlined depth set.
+ StopInfoSP stop_info_sp = m_thread.GetStopInfo();
+ if (stop_info_sp)
+ {
+ switch (stop_info_sp->GetStopReason())
+ {
+ case eStopReasonWatchpoint:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonSignal:
+ // In all these cases we want to stop in the deepest most frame.
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = 0;
+ break;
+ case eStopReasonBreakpoint:
+ {
+ // FIXME: Figure out what this break point is doing, and set the inline depth
+ // appropriately. Be careful to take into account breakpoints that implement
+ // step over prologue, since that should do the default calculation.
+ // For now, if the breakpoints corresponding to this hit are all internal,
+ // I set the stop location to the top of the inlined stack, since that will make
+ // things like stepping over prologues work right. But if there are any non-internal
+ // breakpoints I do to the bottom of the stack, since that was the old behavior.
+ uint32_t bp_site_id = stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp(m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id));
+ bool all_internal = true;
+ if (bp_site_sp)
+ {
+ uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (uint32_t i = 0; i < num_owners; i++)
+ {
+ Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+ if (!bp_ref.IsInternal())
+ {
+ all_internal = false;
+ }
+ }
+ }
+ if (!all_internal)
+ {
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = 0;
+ break;
+ }
+ }
+ default:
+ {
+ // Otherwise, we should set ourselves at the container of the inlining, so that the
+ // user can descend into them.
+ // So first we check whether we have more than one inlined block sharing this PC:
+ int num_inlined_functions = 0;
+
+ for (Block *container_ptr = block_ptr->GetInlinedParent();
+ container_ptr != NULL;
+ container_ptr = container_ptr->GetInlinedParent())
+ {
+ if (!container_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
+ break;
+ if (pc_as_address != containing_range.GetBaseAddress())
+ break;
+
+ num_inlined_functions++;
+ }
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = num_inlined_functions + 1;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("ResetCurrentInlinedDepth: setting inlined depth: %d 0x%" PRIx64 ".\n", m_current_inlined_depth, curr_pc);
+
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+StackFrameList::DecrementCurrentInlinedDepth ()
+{
+ if (m_show_inlined_frames)
+ {
+ uint32_t current_inlined_depth = GetCurrentInlinedDepth();
+ if (current_inlined_depth != UINT32_MAX)
+ {
+ if (current_inlined_depth > 0)
+ {
+ m_current_inlined_depth--;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+StackFrameList::SetCurrentInlinedDepth (uint32_t new_depth)
+{
+ m_current_inlined_depth = new_depth;
+ if (new_depth == UINT32_MAX)
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ else
+ m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();
+}
+
+void
+StackFrameList::GetFramesUpTo(uint32_t end_idx)
+{
+ // this makes sure we do not fetch frames for an invalid thread
+ if (m_thread.IsValid() == false)
+ return;
+
+ // We've already gotten more frames than asked for, or we've already finished unwinding, return.
+ if (m_frames.size() > end_idx || GetAllFramesFetched())
+ return;
+
+ Unwind *unwinder = m_thread.GetUnwinder ();
+
+ if (m_show_inlined_frames)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ StreamFile s(stdout, false);
+#endif
+ // If we are hiding some frames from the outside world, we need to add those onto the total count of
+ // frames to fetch. However, we don't need ot do that if end_idx is 0 since in that case we always
+ // get the first concrete frame and all the inlined frames below it... And of course, if end_idx is
+ // UINT32_MAX that means get all, so just do that...
+
+ uint32_t inlined_depth = 0;
+ if (end_idx > 0 && end_idx != UINT32_MAX)
+ {
+ inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ {
+ if (end_idx > 0)
+ end_idx += inlined_depth;
+ }
+ }
+
+ StackFrameSP unwind_frame_sp;
+ do
+ {
+ uint32_t idx = m_concrete_frames_fetched++;
+ lldb::addr_t pc;
+ lldb::addr_t cfa;
+ if (idx == 0)
+ {
+ // We might have already created frame zero, only create it
+ // if we need to
+ if (m_frames.empty())
+ {
+ RegisterContextSP reg_ctx_sp (m_thread.GetRegisterContext());
+
+ if (reg_ctx_sp)
+ {
+
+ const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
+ // There shouldn't be any way not to get the frame info for frame 0.
+ // But if the unwinder can't make one, lets make one by hand with the
+ // SP as the CFA and see if that gets any further.
+ if (!success)
+ {
+ cfa = reg_ctx_sp->GetSP();
+ pc = reg_ctx_sp->GetPC();
+ }
+
+ unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(),
+ m_frames.size(),
+ idx,
+ reg_ctx_sp,
+ cfa,
+ pc,
+ NULL));
+ m_frames.push_back (unwind_frame_sp);
+ }
+ }
+ else
+ {
+ unwind_frame_sp = m_frames.front();
+ cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
+ }
+ }
+ else
+ {
+ const bool success = unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
+ if (!success)
+ {
+ // We've gotten to the end of the stack.
+ SetAllFramesFetched();
+ break;
+ }
+ unwind_frame_sp.reset (new StackFrame (m_thread.shared_from_this(), m_frames.size(), idx, cfa, pc, NULL));
+ m_frames.push_back (unwind_frame_sp);
+ }
+
+ SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
+ Block *unwind_block = unwind_sc.block;
+ if (unwind_block)
+ {
+ Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress());
+ // Be sure to adjust the frame address to match the address
+ // that was used to lookup the symbol context above. If we are
+ // in the first concrete frame, then we lookup using the current
+ // address, else we decrement the address by one to get the correct
+ // location.
+ if (idx > 0)
+ curr_frame_address.Slide(-1);
+
+ SymbolContext next_frame_sc;
+ Address next_frame_address;
+
+ while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address))
+ {
+ StackFrameSP frame_sp(new StackFrame (m_thread.shared_from_this(),
+ m_frames.size(),
+ idx,
+ unwind_frame_sp->GetRegisterContextSP (),
+ cfa,
+ next_frame_address,
+ &next_frame_sc));
+
+ m_frames.push_back (frame_sp);
+ unwind_sc = next_frame_sc;
+ curr_frame_address = next_frame_address;
+ }
+ }
+ } while (m_frames.size() - 1 < end_idx);
+
+ // Don't try to merge till you've calculated all the frames in this stack.
+ if (GetAllFramesFetched() && m_prev_frames_sp)
+ {
+ StackFrameList *prev_frames = m_prev_frames_sp.get();
+ StackFrameList *curr_frames = this;
+
+ //curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth;
+ //curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc;
+ //printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc);
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("\nprev_frames:\n");
+ prev_frames->Dump (&s);
+ s.PutCString("\ncurr_frames:\n");
+ curr_frames->Dump (&s);
+ s.EOL();
+#endif
+ size_t curr_frame_num, prev_frame_num;
+
+ for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
+ curr_frame_num > 0 && prev_frame_num > 0;
+ --curr_frame_num, --prev_frame_num)
+ {
+ const size_t curr_frame_idx = curr_frame_num-1;
+ const size_t prev_frame_idx = prev_frame_num-1;
+ StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
+ StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
+ if (curr_frame_sp)
+ curr_frame_sp->Dump (&s, true, false);
+ else
+ s.PutCString("NULL");
+ s.Printf("\nPrev frame #%u ", prev_frame_idx);
+ if (prev_frame_sp)
+ prev_frame_sp->Dump (&s, true, false);
+ else
+ s.PutCString("NULL");
+#endif
+
+ StackFrame *curr_frame = curr_frame_sp.get();
+ StackFrame *prev_frame = prev_frame_sp.get();
+
+ if (curr_frame == NULL || prev_frame == NULL)
+ break;
+
+ // Check the stack ID to make sure they are equal
+ if (curr_frame->GetStackID() != prev_frame->GetStackID())
+ break;
+
+ prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
+ // Now copy the fixed up previous frame into the current frames
+ // so the pointer doesn't change
+ m_frames[curr_frame_idx] = prev_frame_sp;
+ //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.Printf("\n Copying previous frame to current frame");
+#endif
+ }
+ // We are done with the old stack frame list, we can release it now
+ m_prev_frames_sp.reset();
+ }
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("\n\nNew frames:\n");
+ Dump (&s);
+ s.EOL();
+#endif
+ }
+ else
+ {
+ if (end_idx < m_concrete_frames_fetched)
+ return;
+
+ uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
+ if (num_frames <= end_idx + 1)
+ {
+ //Done unwinding.
+ m_concrete_frames_fetched = UINT32_MAX;
+ }
+ m_frames.resize(num_frames);
+ }
+}
+
+uint32_t
+StackFrameList::GetNumFrames (bool can_create)
+{
+ Mutex::Locker locker (m_mutex);
+
+ if (can_create)
+ GetFramesUpTo (UINT32_MAX);
+
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth == UINT32_MAX)
+ return m_frames.size();
+ else
+ return m_frames.size() - inlined_depth;
+}
+
+void
+StackFrameList::Dump (Stream *s)
+{
+ if (s == NULL)
+ return;
+ Mutex::Locker locker (m_mutex);
+
+ const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ StackFrame *frame = (*pos).get();
+ s->Printf("%p: ", frame);
+ if (frame)
+ {
+ frame->GetStackID().Dump (s);
+ frame->DumpUsingSettingsFormat (s);
+ }
+ else
+ s->Printf("frame #%u", (uint32_t)std::distance (begin, pos));
+ s->EOL();
+ }
+ s->EOL();
+}
+
+StackFrameSP
+StackFrameList::GetFrameAtIndex (uint32_t idx)
+{
+ StackFrameSP frame_sp;
+ Mutex::Locker locker (m_mutex);
+ uint32_t original_idx = idx;
+
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ idx += inlined_depth;
+
+ if (idx < m_frames.size())
+ frame_sp = m_frames[idx];
+
+ if (frame_sp)
+ return frame_sp;
+
+ // GetFramesUpTo will fill m_frames with as many frames as you asked for,
+ // if there are that many. If there weren't then you asked for too many
+ // frames.
+ GetFramesUpTo (idx);
+ if (idx < m_frames.size())
+ {
+ if (m_show_inlined_frames)
+ {
+ // When inline frames are enabled we actually create all the frames in GetFramesUpTo.
+ frame_sp = m_frames[idx];
+ }
+ else
+ {
+ Unwind *unwinder = m_thread.GetUnwinder ();
+ if (unwinder)
+ {
+ addr_t pc, cfa;
+ if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
+ {
+ frame_sp.reset (new StackFrame (m_thread.shared_from_this(), idx, idx, cfa, pc, NULL));
+
+ Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
+ if (function)
+ {
+ // When we aren't showing inline functions we always use
+ // the top most function block as the scope.
+ frame_sp->SetSymbolContextScope (&function->GetBlock(false));
+ }
+ else
+ {
+ // Set the symbol scope from the symbol regardless if it is NULL or valid.
+ frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
+ }
+ SetFrameAtIndex(idx, frame_sp);
+ }
+ }
+ }
+ }
+ else if (original_idx == 0)
+ {
+ // There should ALWAYS be a frame at index 0. If something went wrong with the CurrentInlinedDepth such that
+ // there weren't as many frames as we thought taking that into account, then reset the current inlined depth
+ // and return the real zeroth frame.
+ if (m_frames.size() > 0)
+ {
+ ResetCurrentInlinedDepth();
+ frame_sp = m_frames[original_idx];
+ }
+ else
+ {
+ // Why do we have a thread with zero frames, that should not ever happen...
+ if (m_thread.IsValid())
+ assert ("A valid thread has no frames.");
+
+ }
+ }
+
+ return frame_sp;
+}
+
+StackFrameSP
+StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
+{
+ // First try assuming the unwind index is the same as the frame index. The
+ // unwind index is always greater than or equal to the frame index, so it
+ // is a good place to start. If we have inlined frames we might have 5
+ // concrete frames (frame unwind indexes go from 0-4), but we might have 15
+ // frames after we make all the inlined frames. Most of the time the unwind
+ // frame index (or the concrete frame index) is the same as the frame index.
+ uint32_t frame_idx = unwind_idx;
+ StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
+ while (frame_sp)
+ {
+ if (frame_sp->GetFrameIndex() == unwind_idx)
+ break;
+ frame_sp = GetFrameAtIndex (++frame_idx);
+ }
+ return frame_sp;
+}
+
+static bool
+CompareStackID (const StackFrameSP &stack_sp, const StackID &stack_id)
+{
+ return stack_sp->GetStackID() < stack_id;
+}
+
+StackFrameSP
+StackFrameList::GetFrameWithStackID (const StackID &stack_id)
+{
+ StackFrameSP frame_sp;
+
+ if (stack_id.IsValid())
+ {
+ Mutex::Locker locker (m_mutex);
+ uint32_t frame_idx = 0;
+ // Do a binary search in case the stack frame is already in our cache
+ collection::const_iterator begin = m_frames.begin();
+ collection::const_iterator end = m_frames.end();
+ 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 (m_frames.back()->GetStackID() < stack_id)
+ frame_idx = m_frames.size();
+ }
+ do
+ {
+ frame_sp = GetFrameAtIndex (frame_idx);
+ if (frame_sp && frame_sp->GetStackID() == stack_id)
+ break;
+ frame_idx++;
+ }
+ while (frame_sp);
+ }
+ return frame_sp;
+}
+
+bool
+StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
+{
+ if (idx >= m_frames.size())
+ m_frames.resize(idx + 1);
+ // Make sure allocation succeeded by checking bounds again
+ if (idx < m_frames.size())
+ {
+ m_frames[idx] = frame_sp;
+ return true;
+ }
+ return false; // resize failed, out of memory?
+}
+
+uint32_t
+StackFrameList::GetSelectedFrameIndex () const
+{
+ Mutex::Locker locker (m_mutex);
+ return m_selected_frame_idx;
+}
+
+
+uint32_t
+StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
+{
+ Mutex::Locker locker (m_mutex);
+ const_iterator pos;
+ const_iterator begin = m_frames.begin();
+ const_iterator end = m_frames.end();
+ m_selected_frame_idx = 0;
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == frame)
+ {
+ m_selected_frame_idx = std::distance (begin, pos);
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ m_selected_frame_idx -= inlined_depth;
+ break;
+ }
+ }
+ SetDefaultFileAndLineToSelectedFrame();
+ return m_selected_frame_idx;
+}
+
+// Mark a stack frame as the current frame using the frame index
+bool
+StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
+{
+ Mutex::Locker locker (m_mutex);
+ StackFrameSP frame_sp (GetFrameAtIndex (idx));
+ if (frame_sp)
+ {
+ SetSelectedFrame(frame_sp.get());
+ return true;
+ }
+ else
+ return false;
+}
+
+void
+StackFrameList::SetDefaultFileAndLineToSelectedFrame()
+{
+ if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID())
+ {
+ StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex()));
+ if (frame_sp)
+ {
+ SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
+ if (sc.line_entry.file)
+ m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file,
+ sc.line_entry.line);
+ }
+ }
+}
+
+// The thread has been run, reset the number stack frames to zero so we can
+// determine how many frames we have lazily.
+void
+StackFrameList::Clear ()
+{
+ Mutex::Locker locker (m_mutex);
+ m_frames.clear();
+ m_concrete_frames_fetched = 0;
+}
+
+void
+StackFrameList::InvalidateFrames (uint32_t start_idx)
+{
+ Mutex::Locker locker (m_mutex);
+ if (m_show_inlined_frames)
+ {
+ Clear();
+ }
+ else
+ {
+ const size_t num_frames = m_frames.size();
+ while (start_idx < num_frames)
+ {
+ m_frames[start_idx].reset();
+ ++start_idx;
+ }
+ }
+}
+
+void
+StackFrameList::Merge (std::unique_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp)
+{
+ Mutex::Locker curr_locker (curr_ap.get() ? &curr_ap->m_mutex : NULL);
+ Mutex::Locker prev_locker (prev_sp.get() ? &prev_sp->m_mutex : NULL);
+
+#if defined (DEBUG_STACK_FRAMES)
+ StreamFile s(stdout, false);
+ s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
+ if (prev_sp.get())
+ prev_sp->Dump (&s);
+ else
+ s.PutCString ("NULL");
+ s.PutCString("\nCurr:\n");
+ if (curr_ap.get())
+ curr_ap->Dump (&s);
+ else
+ s.PutCString ("NULL");
+ s.EOL();
+#endif
+
+ if (curr_ap.get() == NULL || curr_ap->GetNumFrames (false) == 0)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("No current frames, leave previous frames alone...\n");
+#endif
+ curr_ap.release();
+ return;
+ }
+
+ if (prev_sp.get() == NULL || prev_sp->GetNumFrames (false) == 0)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("No previous frames, so use current frames...\n");
+#endif
+ // We either don't have any previous frames, or since we have more than
+ // one current frames it means we have all the frames and can safely
+ // replace our previous frames.
+ prev_sp.reset (curr_ap.release());
+ return;
+ }
+
+ const uint32_t num_curr_frames = curr_ap->GetNumFrames (false);
+
+ if (num_curr_frames > 1)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("We have more than one current frame, so use current frames...\n");
+#endif
+ // We have more than one current frames it means we have all the frames
+ // and can safely replace our previous frames.
+ prev_sp.reset (curr_ap.release());
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("\nMerged:\n");
+ prev_sp->Dump (&s);
+#endif
+ return;
+ }
+
+ StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0));
+ StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0));
+ StackID curr_stack_id (curr_frame_zero_sp->GetStackID());
+ StackID prev_stack_id (prev_frame_zero_sp->GetStackID());
+
+#if defined (DEBUG_STACK_FRAMES)
+ const uint32_t num_prev_frames = prev_sp->GetNumFrames (false);
+ s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
+#endif
+
+ // We have only a single current frame
+ // Our previous stack frames only had a single frame as well...
+ if (curr_stack_id == prev_stack_id)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n");
+#endif
+
+ curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp);
+// prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp);
+// prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
+ }
+ else if (curr_stack_id < prev_stack_id)
+ {
+#if defined (DEBUG_STACK_FRAMES)
+ s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n");
+#endif
+ prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp);
+ }
+
+ curr_ap.release();
+
+#if defined (DEBUG_STACK_FRAMES)
+ s.PutCString("\nMerged:\n");
+ prev_sp->Dump (&s);
+#endif
+
+
+}
+
+lldb::StackFrameSP
+StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
+{
+ const_iterator pos;
+ const_iterator begin = m_frames.begin();
+ const_iterator end = m_frames.end();
+ lldb::StackFrameSP ret_sp;
+
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == stack_frame_ptr)
+ {
+ ret_sp = (*pos);
+ break;
+ }
+ }
+ return ret_sp;
+}
+
+size_t
+StackFrameList::GetStatus (Stream& strm,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source)
+{
+ size_t num_frames_displayed = 0;
+
+ if (num_frames == 0)
+ return 0;
+
+ StackFrameSP frame_sp;
+ uint32_t frame_idx = 0;
+ uint32_t last_frame;
+
+ // Don't let the last frame wrap around...
+ if (num_frames == UINT32_MAX)
+ last_frame = UINT32_MAX;
+ else
+ last_frame = first_frame + num_frames;
+
+ for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx)
+ {
+ frame_sp = GetFrameAtIndex(frame_idx);
+ if (frame_sp.get() == NULL)
+ break;
+
+ if (!frame_sp->GetStatus (strm,
+ show_frame_info,
+ num_frames_with_source > (first_frame - frame_idx)))
+ break;
+ ++num_frames_displayed;
+ }
+
+ strm.IndentLess();
+ return num_frames_displayed;
+}
+
diff --git a/source/Target/StackID.cpp b/source/Target/StackID.cpp
new file mode 100644
index 000000000000..9e8c315d0704
--- /dev/null
+++ b/source/Target/StackID.cpp
@@ -0,0 +1,110 @@
+//===-- StackID.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/StackID.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+using namespace lldb_private;
+
+
+void
+StackID::Dump (Stream *s)
+{
+ s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p", (uint64_t)m_pc, (uint64_t)m_cfa, m_symbol_scope);
+ if (m_symbol_scope)
+ {
+ SymbolContext sc;
+
+ m_symbol_scope->CalculateSymbolContext (&sc);
+ if (sc.block)
+ s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID());
+ else if (sc.symbol)
+ s->Printf(" (Symbol{0x%8.8x})", sc.symbol->GetID());
+ }
+ s->PutCString(") ");
+}
+
+bool
+lldb_private::operator== (const StackID& lhs, const StackID& rhs)
+{
+ if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
+ return false;
+
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+
+ // Only compare the PC values if both symbol context scopes are NULL
+ if (lhs_scope == NULL && rhs_scope == NULL)
+ return lhs.GetPC() == rhs.GetPC();
+
+ return lhs_scope == rhs_scope;
+}
+
+bool
+lldb_private::operator!= (const StackID& lhs, const StackID& rhs)
+{
+ if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
+ return true;
+
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+
+ if (lhs_scope == NULL && rhs_scope == NULL)
+ return lhs.GetPC() != rhs.GetPC();
+
+ return lhs_scope != rhs_scope;
+}
+
+bool
+lldb_private::operator< (const StackID& lhs, const StackID& rhs)
+{
+ const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress();
+ const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress();
+
+ // FIXME: We are assuming that the stacks grow downward in memory. That's not necessary, but true on
+ // all the machines we care about at present. If this changes, we'll have to deal with that. The ABI is the
+ // agent who knows this ordering, but the StackID has no access to the ABI. The most straightforward way
+ // to handle this is to add a "m_grows_downward" bool to the StackID, and set it in the constructor.
+ // But I'm not going to waste a bool per StackID on this till we need it.
+
+ if (lhs_cfa != rhs_cfa)
+ return lhs_cfa < rhs_cfa;
+
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+
+ if (lhs_scope != NULL && rhs_scope != NULL)
+ {
+ // Same exact scope, lhs is not less than (younger than rhs)
+ if (lhs_scope == rhs_scope)
+ return false;
+
+ SymbolContext lhs_sc;
+ SymbolContext rhs_sc;
+ lhs_scope->CalculateSymbolContext (&lhs_sc);
+ rhs_scope->CalculateSymbolContext (&rhs_sc);
+
+ // Items with the same function can only be compared
+ if (lhs_sc.function == rhs_sc.function &&
+ lhs_sc.function != NULL && lhs_sc.block != NULL &&
+ rhs_sc.function != NULL && rhs_sc.block != NULL)
+ {
+ return rhs_sc.block->Contains (lhs_sc.block);
+ }
+ }
+ return false;
+}
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
new file mode 100644
index 000000000000..81b9d866f711
--- /dev/null
+++ b/source/Target/StopInfo.cpp
@@ -0,0 +1,1143 @@
+//===-- StopInfo.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/StopInfo.h"
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+StopInfo::StopInfo (Thread &thread, uint64_t value) :
+ m_thread_wp (thread.shared_from_this()),
+ m_stop_id (thread.GetProcess()->GetStopID()),
+ m_resume_id (thread.GetProcess()->GetResumeID()),
+ m_value (value),
+ m_override_should_notify (eLazyBoolCalculate),
+ m_override_should_stop (eLazyBoolCalculate)
+{
+}
+
+bool
+StopInfo::IsValid () const
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetStopID() == m_stop_id;
+ return false;
+}
+
+void
+StopInfo::MakeStopInfoValid ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ m_stop_id = thread_sp->GetProcess()->GetStopID();
+ m_resume_id = thread_sp->GetProcess()->GetResumeID();
+ }
+}
+
+bool
+StopInfo::HasTargetRunSinceMe ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+
+ if (thread_sp)
+ {
+ lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState();
+ if (ret_type == eStateRunning)
+ {
+ return true;
+ }
+ else if (ret_type == eStateStopped)
+ {
+ // This is a little tricky. We want to count "run and stopped again before you could
+ // ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we don't want to
+ // include any running of the target done for expressions. So we track both resumes,
+ // and resumes caused by expressions, and check if there are any resumes NOT caused
+ // by expressions.
+
+ uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID();
+ uint32_t last_user_expression_id = thread_sp->GetProcess()->GetLastUserExpressionResumeID ();
+ if (curr_resume_id == m_resume_id)
+ {
+ return false;
+ }
+ else if (curr_resume_id > last_user_expression_id)
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// StopInfoBreakpoint
+//----------------------------------------------------------------------
+
+namespace lldb_private
+{
+class StopInfoBreakpoint : public StopInfo
+{
+public:
+
+ StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
+ StopInfo (thread, break_id),
+ m_description(),
+ m_should_stop (false),
+ m_should_stop_is_valid (false),
+ m_should_perform_action (true),
+ m_address (LLDB_INVALID_ADDRESS),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_was_one_shot (false)
+ {
+ StoreBPInfo();
+ }
+
+ StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
+ StopInfo (thread, break_id),
+ m_description(),
+ m_should_stop (should_stop),
+ m_should_stop_is_valid (true),
+ m_should_perform_action (true),
+ m_address (LLDB_INVALID_ADDRESS),
+ m_break_id(LLDB_INVALID_BREAK_ID),
+ m_was_one_shot (false)
+ {
+ StoreBPInfo();
+ }
+
+ void
+ StoreBPInfo ()
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+ if (bp_site_sp)
+ {
+ if (bp_site_sp->GetNumberOfOwners() == 1)
+ {
+ BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
+ if (bp_loc_sp)
+ {
+ m_break_id = bp_loc_sp->GetBreakpoint().GetID();
+ m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot();
+ }
+ }
+ m_address = bp_site_sp->GetLoadAddress();
+ }
+ }
+ }
+
+ virtual ~StopInfoBreakpoint ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonBreakpoint;
+ }
+
+ virtual bool
+ ShouldStopSynchronous (Event *event_ptr)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ if (!m_should_stop_is_valid)
+ {
+ // Only check once if we should stop at a breakpoint
+ BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+ if (bp_site_sp)
+ {
+ ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+ StoppointCallbackContext context (event_ptr, exe_ctx, true);
+ m_should_stop = bp_site_sp->ShouldStop (&context);
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+
+ m_should_stop = true;
+ }
+ m_should_stop_is_valid = true;
+ }
+ return m_should_stop;
+ }
+ return false;
+ }
+
+ virtual bool
+ DoShouldNotify (Event *event_ptr)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+ if (bp_site_sp)
+ {
+ bool all_internal = true;
+
+ for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
+ {
+ if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+ {
+ all_internal = false;
+ break;
+ }
+ }
+ return all_internal == false;
+ }
+ }
+ return true;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+ if (bp_site_sp)
+ {
+ StreamString strm;
+ // If we have just hit an internal breakpoint, and it has a kind description, print that instead of the
+ // full breakpoint printing:
+ if (bp_site_sp->IsInternal())
+ {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t idx = 0; idx < num_owners; idx++)
+ {
+ const char *kind = bp_site_sp->GetOwnerAtIndex(idx)->GetBreakpoint().GetBreakpointKind();
+ if (kind != NULL)
+ {
+ m_description.assign (kind);
+ return kind;
+ }
+ }
+ }
+
+ strm.Printf("breakpoint ");
+ bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
+ m_description.swap (strm.GetString());
+ }
+ else
+ {
+ StreamString strm;
+ if (m_break_id != LLDB_INVALID_BREAK_ID)
+ {
+ BreakpointSP break_sp = thread_sp->GetProcess()->GetTarget().GetBreakpointByID(m_break_id);
+ if (break_sp)
+ {
+ if (break_sp->IsInternal())
+ {
+ const char *kind = break_sp->GetBreakpointKind();
+ if (kind)
+ strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id);
+ else
+ strm.Printf ("internal breakpoint(%d).", m_break_id);
+ }
+ else
+ {
+ strm.Printf ("breakpoint %d.", m_break_id);
+ }
+ }
+ else
+ {
+ if (m_was_one_shot)
+ strm.Printf ("one-shot breakpoint %d", m_break_id);
+ else
+ strm.Printf ("breakpoint %d which has been deleted.", m_break_id);
+ }
+ }
+ else if (m_address == LLDB_INVALID_ADDRESS)
+ strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);
+ else
+ strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address);
+
+ m_description.swap (strm.GetString());
+ }
+ }
+ }
+ return m_description.c_str();
+ }
+
+protected:
+ bool
+ ShouldStop (Event *event_ptr)
+ {
+ // This just reports the work done by PerformAction or the synchronous stop. It should
+ // only ever get called after they have had a chance to run.
+ assert (m_should_stop_is_valid);
+ return m_should_stop;
+ }
+
+ virtual void
+ PerformAction (Event *event_ptr)
+ {
+ if (!m_should_perform_action)
+ return;
+ m_should_perform_action = false;
+
+ ThreadSP thread_sp (m_thread_wp.lock());
+
+ if (thread_sp)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ if (!thread_sp->IsValid())
+ {
+ // This shouldn't ever happen, but just in case, don't do more harm.
+ if (log)
+ {
+ log->Printf ("PerformAction got called with an invalid thread.");
+ }
+ m_should_stop = true;
+ m_should_stop_is_valid = true;
+ return;
+ }
+
+ BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
+
+ if (bp_site_sp)
+ {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+
+ if (num_owners == 0)
+ {
+ m_should_stop = true;
+ }
+ else
+ {
+ // We go through each location, and test first its condition. If the condition says to stop,
+ // then we run the callback for that location. If that callback says to stop as well, then
+ // we set m_should_stop to true; we are going to stop.
+ // But we still want to give all the breakpoints whose conditions say we are going to stop a
+ // chance to run their callbacks.
+ // Of course if any callback restarts the target by putting "continue" in the callback, then
+ // we're going to restart, without running the rest of the callbacks. And in this case we will
+ // end up not stopping even if another location said we should stop. But that's better than not
+ // running all the callbacks.
+
+ m_should_stop = false;
+
+ ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process->GetModIDRef().IsLastResumeForUserExpression())
+ {
+ // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or
+ // expressions. That could lead to infinite recursion if the command or condition re-calls the function
+ // with this breakpoint.
+ // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
+ // PerformAction calls that can arise when the action runs a function that hits another breakpoint,
+ // and only stop running commands when we see the same breakpoint hit a second time.
+
+ m_should_stop_is_valid = true;
+ if (log)
+ log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
+ " not running commands to avoid recursion.");
+ bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions();
+ if (ignoring_breakpoints)
+ {
+ m_should_stop = false;
+ // Internal breakpoints will always stop.
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
+ if (bp_loc_sp->GetBreakpoint().IsInternal())
+ {
+ m_should_stop = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ m_should_stop = true;
+ }
+ if (log)
+ log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.",
+ m_should_stop ? "true" : "false");
+ process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while "
+ "running function, skipping commands and conditions to prevent recursion.");
+ return;
+ }
+
+ StoppointCallbackContext context (event_ptr, exe_ctx, false);
+
+ // Let's copy the breakpoint locations out of the site and store them in a local list. That way if
+ // one of the breakpoint actions changes the site, then we won't be operating on a bad list.
+
+ BreakpointLocationCollection site_locations;
+ for (size_t j = 0; j < num_owners; j++)
+ site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
+
+ for (size_t j = 0; j < num_owners; j++)
+ {
+ lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
+
+ // If another action disabled this breakpoint or its location, then don't run the actions.
+ if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())
+ continue;
+
+ // The breakpoint site may have many locations associated with it, not all of them valid for
+ // this thread. Skip the ones that aren't:
+ if (!bp_loc_sp->ValidForThisThread(thread_sp.get()))
+ continue;
+
+ // First run the condition for the breakpoint. If that says we should stop, then we'll run
+ // the callback for the breakpoint. If the callback says we shouldn't stop that will win.
+
+ if (bp_loc_sp->GetConditionText() != NULL)
+ {
+ Error condition_error;
+ bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
+
+ if (!condition_error.Success())
+ {
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream ();
+ error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
+ bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+ error_sp->Printf (": \"%s\"",
+ bp_loc_sp->GetConditionText());
+ error_sp->EOL();
+ const char *err_str = condition_error.AsCString("<Unknown Error>");
+ if (log)
+ log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+
+ error_sp->PutCString (err_str);
+ error_sp->EOL();
+ error_sp->Flush();
+ // If the condition fails to be parsed or run, we should stop.
+ condition_says_stop = true;
+ }
+ else
+ {
+ if (!condition_says_stop)
+ continue;
+ }
+ }
+
+ bool callback_says_stop;
+
+ // FIXME: For now the callbacks have to run in async mode - the first time we restart we need
+ // to get out of there. So set it here.
+ // When we figure out how to nest breakpoint hits then this will change.
+
+ Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
+ bool old_async = debugger.GetAsyncExecution();
+ debugger.SetAsyncExecution (true);
+
+ callback_says_stop = bp_loc_sp->InvokeCallback (&context);
+
+ debugger.SetAsyncExecution (old_async);
+
+ if (callback_says_stop)
+ m_should_stop = true;
+
+ // If we are going to stop for this breakpoint, then remove the breakpoint.
+ if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())
+ {
+ thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());
+ }
+
+ // Also make sure that the callback hasn't continued the target.
+ // If it did, when we'll set m_should_start to false and get out of here.
+ if (HasTargetRunSinceMe ())
+ {
+ m_should_stop = false;
+ break;
+ }
+ }
+ }
+ // We've figured out what this stop wants to do, so mark it as valid so we don't compute it again.
+ m_should_stop_is_valid = true;
+
+ }
+ else
+ {
+ m_should_stop = true;
+ m_should_stop_is_valid = true;
+ Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log_process)
+ log_process->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+ }
+ if (log)
+ log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
+ }
+ }
+
+private:
+ std::string m_description;
+ bool m_should_stop;
+ bool m_should_stop_is_valid;
+ bool m_should_perform_action; // Since we are trying to preserve the "state" of the system even if we run functions
+ // etc. behind the users backs, we need to make sure we only REALLY perform the action once.
+ lldb::addr_t m_address; // We use this to capture the breakpoint site address when we create the StopInfo,
+ // in case somebody deletes it between the time the StopInfo is made and the
+ // description is asked for.
+ lldb::break_id_t m_break_id;
+ bool m_was_one_shot;
+};
+
+
+//----------------------------------------------------------------------
+// StopInfoWatchpoint
+//----------------------------------------------------------------------
+
+class StopInfoWatchpoint : public StopInfo
+{
+public:
+ // Make sure watchpoint is properly disabled and subsequently enabled while performing watchpoint actions.
+ class WatchpointSentry {
+ public:
+ WatchpointSentry(Process *p, Watchpoint *w):
+ process(p),
+ watchpoint(w)
+ {
+ if (process && watchpoint)
+ {
+ const bool notify = false;
+ watchpoint->TurnOnEphemeralMode();
+ process->DisableWatchpoint(watchpoint, notify);
+ }
+ }
+ ~WatchpointSentry()
+ {
+ if (process && watchpoint)
+ {
+ if (!watchpoint->IsDisabledDuringEphemeralMode())
+ {
+ const bool notify = false;
+ process->EnableWatchpoint(watchpoint, notify);
+ }
+ watchpoint->TurnOffEphemeralMode();
+ }
+ }
+ private:
+ Process *process;
+ Watchpoint *watchpoint;
+ };
+
+ StopInfoWatchpoint (Thread &thread, break_id_t watch_id) :
+ StopInfo(thread, watch_id),
+ m_description(),
+ m_should_stop(false),
+ m_should_stop_is_valid(false)
+ {
+ }
+
+ virtual ~StopInfoWatchpoint ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonWatchpoint;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ {
+ StreamString strm;
+ strm.Printf("watchpoint %" PRIi64, m_value);
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+ }
+
+protected:
+ virtual bool
+ ShouldStopSynchronous (Event *event_ptr)
+ {
+ // ShouldStop() method is idempotent and should not affect hit count.
+ // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent()
+ // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()->
+ // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()->
+ // StopInfoWatchpoint::ShouldStop() and
+ // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()->
+ // StopInfoWatchpoint::PerformAction().
+ if (m_should_stop_is_valid)
+ return m_should_stop;
+
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
+ if (wp_sp)
+ {
+ // Check if we should stop at a watchpoint.
+ ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+ StoppointCallbackContext context (event_ptr, exe_ctx, true);
+ m_should_stop = wp_sp->ShouldStop (&context);
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("Process::%s could not find watchpoint location id: %" PRId64 "...",
+ __FUNCTION__, GetValue());
+
+ m_should_stop = true;
+ }
+ }
+ m_should_stop_is_valid = true;
+ return m_should_stop;
+ }
+
+ bool
+ ShouldStop (Event *event_ptr)
+ {
+ // This just reports the work done by PerformAction or the synchronous stop. It should
+ // only ever get called after they have had a chance to run.
+ assert (m_should_stop_is_valid);
+ return m_should_stop;
+ }
+
+ virtual void
+ PerformAction (Event *event_ptr)
+ {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS);
+ // We're going to calculate if we should stop or not in some way during the course of
+ // this code. Also by default we're going to stop, so set that here.
+ m_should_stop = true;
+
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+
+ WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
+ if (wp_sp)
+ {
+ ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
+ Process* process = exe_ctx.GetProcessPtr();
+
+ // This sentry object makes sure the current watchpoint is disabled while performing watchpoint actions,
+ // and it is then enabled after we are finished.
+ WatchpointSentry sentry(process, wp_sp.get());
+
+ {
+ // check if this process is running on an architecture where watchpoints trigger
+ // before the associated instruction runs. if so, disable the WP, single-step and then
+ // re-enable the watchpoint
+ if (process)
+ {
+ uint32_t num;
+ bool wp_triggers_after;
+ if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success())
+ {
+ if (!wp_triggers_after)
+ {
+ StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo();
+ 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
+ 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->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
+ thread_sp->SetStopInfo(stored_stop_info_sp);
+ }
+ }
+ }
+ }
+
+ if (m_should_stop && wp_sp->GetConditionText() != NULL)
+ {
+ // We need to make sure the user sees any parse errors in their condition, so we'll hook the
+ // constructor errors up to the debugger's Async I/O.
+ ExecutionResults result_code;
+ ValueObjectSP result_value_sp;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ Error error;
+ result_code = ClangUserExpression::EvaluateWithError (exe_ctx,
+ eExecutionPolicyOnlyWhenNeeded,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny,
+ unwind_on_error,
+ ignore_breakpoints,
+ wp_sp->GetConditionText(),
+ NULL,
+ result_value_sp,
+ error,
+ true,
+ ClangUserExpression::kDefaultTimeout);
+ if (result_code == eExecutionCompleted)
+ {
+ if (result_value_sp)
+ {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue (scalar_value))
+ {
+ if (scalar_value.ULongLong(1) == 0)
+ {
+ // We have been vetoed. This takes precedence over querying
+ // the watchpoint whether it should stop (aka ignore count and
+ // friends). See also StopInfoWatchpoint::ShouldStop() as well
+ // as Process::ProcessEventData::DoOnRemoval().
+ m_should_stop = false;
+ }
+ else
+ m_should_stop = true;
+ if (log)
+ log->Printf("Condition successfully evaluated, result is %s.\n",
+ m_should_stop ? "true" : "false");
+ }
+ else
+ {
+ m_should_stop = true;
+ if (log)
+ log->Printf("Failed to get an integer result from the expression.");
+ }
+ }
+ }
+ else
+ {
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream ();
+ error_sp->Printf ("Stopped due to an error evaluating condition of watchpoint ");
+ wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
+ error_sp->Printf (": \"%s\"",
+ wp_sp->GetConditionText());
+ error_sp->EOL();
+ const char *err_str = error.AsCString("<Unknown Error>");
+ if (log)
+ log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+
+ error_sp->PutCString (err_str);
+ error_sp->EOL();
+ error_sp->Flush();
+ // If the condition fails to be parsed or run, we should stop.
+ m_should_stop = true;
+ }
+ }
+
+ // If the condition says to stop, we run the callback to further decide whether to stop.
+ if (m_should_stop)
+ {
+ StoppointCallbackContext context (event_ptr, exe_ctx, false);
+ bool stop_requested = wp_sp->InvokeCallback (&context);
+ // Also make sure that the callback hasn't continued the target.
+ // If it did, when we'll set m_should_stop to false and get out of here.
+ if (HasTargetRunSinceMe ())
+ m_should_stop = false;
+
+ if (m_should_stop && !stop_requested)
+ {
+ // We have been vetoed by the callback mechanism.
+ m_should_stop = false;
+ }
+ }
+ // Finally, if we are going to stop, print out the new & old values:
+ if (m_should_stop)
+ {
+ wp_sp->CaptureWatchedValue(exe_ctx);
+
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP output_sp = debugger.GetAsyncOutputStream ();
+ wp_sp->DumpSnapshots(output_sp.get());
+ output_sp->EOL();
+ output_sp->Flush();
+ }
+
+ }
+ else
+ {
+ Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
+ if (log_process)
+ log_process->Printf ("Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value);
+ }
+ if (log)
+ log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
+
+ m_should_stop_is_valid = true;
+ }
+ }
+
+private:
+ std::string m_description;
+ bool m_should_stop;
+ bool m_should_stop_is_valid;
+};
+
+
+
+//----------------------------------------------------------------------
+// StopInfoUnixSignal
+//----------------------------------------------------------------------
+
+class StopInfoUnixSignal : public StopInfo
+{
+public:
+
+ StopInfoUnixSignal (Thread &thread, int signo) :
+ StopInfo (thread, signo)
+ {
+ }
+
+ virtual ~StopInfoUnixSignal ()
+ {
+ }
+
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonSignal;
+ }
+
+ virtual bool
+ ShouldStopSynchronous (Event *event_ptr)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+ return false;
+ }
+
+ virtual bool
+ ShouldStop (Event *event_ptr)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetUnixSignals().GetShouldStop (m_value);
+ return false;
+ }
+
+
+ // If should stop returns false, check if we should notify of this event
+ virtual bool
+ DoShouldNotify (Event *event_ptr)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ bool should_notify = thread_sp->GetProcess()->GetUnixSignals().GetShouldNotify (m_value);
+ if (should_notify)
+ {
+ StreamString strm;
+ strm.Printf ("thread %d received signal: %s",
+ thread_sp->GetIndexID(),
+ thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value));
+ Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData());
+ }
+ return should_notify;
+ }
+ return true;
+ }
+
+
+ virtual void
+ WillResume (lldb::StateType resume_state)
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ if (thread_sp->GetProcess()->GetUnixSignals().GetShouldSuppress(m_value) == false)
+ thread_sp->SetResumeSignal(m_value);
+ }
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ {
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ StreamString strm;
+ const char *signal_name = thread_sp->GetProcess()->GetUnixSignals().GetSignalAsCString (m_value);
+ if (signal_name)
+ strm.Printf("signal %s", signal_name);
+ else
+ strm.Printf("signal %" PRIi64, m_value);
+ m_description.swap (strm.GetString());
+ }
+ }
+ return m_description.c_str();
+ }
+};
+
+//----------------------------------------------------------------------
+// StopInfoTrace
+//----------------------------------------------------------------------
+
+class StopInfoTrace : public StopInfo
+{
+public:
+
+ StopInfoTrace (Thread &thread) :
+ StopInfo (thread, LLDB_INVALID_UID)
+ {
+ }
+
+ virtual ~StopInfoTrace ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonTrace;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ return "trace";
+ else
+ return m_description.c_str();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// StopInfoException
+//----------------------------------------------------------------------
+
+class StopInfoException : public StopInfo
+{
+public:
+
+ StopInfoException (Thread &thread, const char *description) :
+ StopInfo (thread, LLDB_INVALID_UID)
+ {
+ if (description)
+ SetDescription (description);
+ }
+
+ virtual
+ ~StopInfoException ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ return "exception";
+ else
+ return m_description.c_str();
+ }
+};
+
+
+//----------------------------------------------------------------------
+// StopInfoThreadPlan
+//----------------------------------------------------------------------
+
+class StopInfoThreadPlan : public StopInfo
+{
+public:
+
+ StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp) :
+ StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
+ m_plan_sp (plan_sp),
+ m_return_valobj_sp (return_valobj_sp)
+ {
+ }
+
+ virtual ~StopInfoThreadPlan ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonPlanComplete;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ if (m_description.empty())
+ {
+ StreamString strm;
+ m_plan_sp->GetDescription (&strm, eDescriptionLevelBrief);
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+ }
+
+ ValueObjectSP
+ GetReturnValueObject()
+ {
+ return m_return_valobj_sp;
+ }
+
+protected:
+ virtual bool
+ ShouldStop (Event *event_ptr)
+ {
+ if (m_plan_sp)
+ return m_plan_sp->ShouldStop(event_ptr);
+ else
+ return StopInfo::ShouldStop(event_ptr);
+ }
+
+private:
+ ThreadPlanSP m_plan_sp;
+ ValueObjectSP m_return_valobj_sp;
+};
+
+class StopInfoExec : public StopInfo
+{
+public:
+
+ StopInfoExec (Thread &thread) :
+ StopInfo (thread, LLDB_INVALID_UID),
+ m_performed_action (false)
+ {
+ }
+
+ virtual
+ ~StopInfoExec ()
+ {
+ }
+
+ virtual StopReason
+ GetStopReason () const
+ {
+ return eStopReasonExec;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ return "exec";
+ }
+protected:
+
+ virtual void
+ PerformAction (Event *event_ptr)
+ {
+ // Only perform the action once
+ if (m_performed_action)
+ return;
+ m_performed_action = true;
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ thread_sp->GetProcess()->DidExec();
+ }
+
+ bool m_performed_action;
+};
+
+} // namespace lldb_private
+
+StopInfoSP
+StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id)
+{
+ return StopInfoSP (new StopInfoBreakpoint (thread, break_id));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id, bool should_stop)
+{
+ return StopInfoSP (new StopInfoBreakpoint (thread, break_id, should_stop));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id)
+{
+ return StopInfoSP (new StopInfoWatchpoint (thread, watch_id));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo)
+{
+ return StopInfoSP (new StopInfoUnixSignal (thread, signo));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonToTrace (Thread &thread)
+{
+ return StopInfoSP (new StopInfoTrace (thread));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp)
+{
+ return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithException (Thread &thread, const char *description)
+{
+ return StopInfoSP (new StopInfoException (thread, description));
+}
+
+StopInfoSP
+StopInfo::CreateStopReasonWithExec (Thread &thread)
+{
+ return StopInfoSP (new StopInfoExec (thread));
+}
+
+ValueObjectSP
+StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)
+{
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete)
+ {
+ StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
+ return plan_stop_info->GetReturnValueObject();
+ }
+ else
+ return ValueObjectSP();
+}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
new file mode 100644
index 000000000000..5766b737c7d8
--- /dev/null
+++ b/source/Target/Target.cpp
@@ -0,0 +1,2866 @@
+//===-- Target.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/Target.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Breakpoint/BreakpointResolverAddress.h"
+#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
+#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
+#include "lldb/Breakpoint/BreakpointResolverName.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/OptionGroupWatchpoint.h"
+#include "lldb/Interpreter/OptionValues.h"
+#include "lldb/Interpreter/Property.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConstString &
+Target::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.target");
+ return class_name;
+}
+
+//----------------------------------------------------------------------
+// Target constructor
+//----------------------------------------------------------------------
+Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp) :
+ TargetProperties (this),
+ Broadcaster (&debugger, Target::GetStaticBroadcasterClass().AsCString()),
+ ExecutionContextScope (),
+ m_debugger (debugger),
+ m_platform_sp (platform_sp),
+ m_mutex (Mutex::eMutexTypeRecursive),
+ m_arch (target_arch),
+ m_images (this),
+ m_section_load_list (),
+ m_breakpoint_list (false),
+ m_internal_breakpoint_list (true),
+ m_watchpoint_list (),
+ m_process_sp (),
+ m_valid (true),
+ m_search_filter_sp (),
+ m_image_search_paths (ImageSearchPathsChanged, this),
+ m_scratch_ast_context_ap (),
+ m_scratch_ast_source_ap (),
+ m_ast_importer_ap (),
+ m_persistent_variables (),
+ m_source_manager_ap(),
+ m_stop_hooks (),
+ m_stop_hook_next_id (0),
+ m_suppress_stop_hooks (false),
+ m_suppress_synthetic_value(false)
+{
+ SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
+ SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
+ SetEventName (eBroadcastBitModulesUnloaded, "modules-unloaded");
+ SetEventName (eBroadcastBitWatchpointChanged, "watchpoint-changed");
+ SetEventName (eBroadcastBitSymbolsLoaded, "symbols-loaded");
+
+ CheckInWithManager();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Target::Target()", this);
+ if (m_arch.IsValid())
+ {
+ LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::Target created with architecture %s (%s)", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str());
+ }
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+Target::~Target()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Target::~Target()", this);
+ DeleteCurrentProcess ();
+}
+
+void
+Target::Dump (Stream *s, lldb::DescriptionLevel description_level)
+{
+// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
+ if (description_level != lldb::eDescriptionLevelBrief)
+ {
+ s->Indent();
+ s->PutCString("Target\n");
+ s->IndentMore();
+ m_images.Dump(s);
+ m_breakpoint_list.Dump(s);
+ m_internal_breakpoint_list.Dump(s);
+ s->IndentLess();
+ }
+ else
+ {
+ Module *exe_module = GetExecutableModulePointer();
+ if (exe_module)
+ s->PutCString (exe_module->GetFileSpec().GetFilename().GetCString());
+ else
+ s->PutCString ("No executable module.");
+ }
+}
+
+void
+Target::CleanupProcess ()
+{
+ // Do any cleanup of the target we need to do between process instances.
+ // NB It is better to do this before destroying the process in case the
+ // clean up needs some help from the process.
+ m_breakpoint_list.ClearAllBreakpointSites();
+ m_internal_breakpoint_list.ClearAllBreakpointSites();
+ // Disable watchpoints just on the debugger side.
+ Mutex::Locker locker;
+ this->GetWatchpointList().GetListMutex(locker);
+ DisableAllWatchpoints(false);
+ ClearAllWatchpointHitCounts();
+}
+
+void
+Target::DeleteCurrentProcess ()
+{
+ if (m_process_sp.get())
+ {
+ m_section_load_list.Clear();
+ if (m_process_sp->IsAlive())
+ m_process_sp->Destroy();
+
+ m_process_sp->Finalize();
+
+ CleanupProcess ();
+
+ m_process_sp.reset();
+ }
+}
+
+const lldb::ProcessSP &
+Target::CreateProcess (Listener &listener, const char *plugin_name, const FileSpec *crash_file)
+{
+ DeleteCurrentProcess ();
+ m_process_sp = Process::FindPlugin(*this, plugin_name, listener, crash_file);
+ return m_process_sp;
+}
+
+const lldb::ProcessSP &
+Target::GetProcessSP () const
+{
+ return m_process_sp;
+}
+
+void
+Target::Destroy()
+{
+ Mutex::Locker locker (m_mutex);
+ m_valid = false;
+ DeleteCurrentProcess ();
+ m_platform_sp.reset();
+ m_arch.Clear();
+ m_images.Clear();
+ m_section_load_list.Clear();
+ const bool notify = false;
+ m_breakpoint_list.RemoveAll(notify);
+ m_internal_breakpoint_list.RemoveAll(notify);
+ m_last_created_breakpoint.reset();
+ m_last_created_watchpoint.reset();
+ m_search_filter_sp.reset();
+ m_image_search_paths.Clear(notify);
+ m_scratch_ast_context_ap.reset();
+ m_scratch_ast_source_ap.reset();
+ m_ast_importer_ap.reset();
+ m_persistent_variables.Clear();
+ m_stop_hooks.clear();
+ m_stop_hook_next_id = 0;
+ m_suppress_stop_hooks = false;
+ m_suppress_synthetic_value = false;
+}
+
+
+BreakpointList &
+Target::GetBreakpointList(bool internal)
+{
+ if (internal)
+ return m_internal_breakpoint_list;
+ else
+ return m_breakpoint_list;
+}
+
+const BreakpointList &
+Target::GetBreakpointList(bool internal) const
+{
+ if (internal)
+ return m_internal_breakpoint_list;
+ else
+ return m_breakpoint_list;
+}
+
+BreakpointSP
+Target::GetBreakpointByID (break_id_t break_id)
+{
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *source_file_spec_list,
+ RegularExpression &source_regex,
+ bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex (NULL, source_regex));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+BreakpointSP
+Target::CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpec &file,
+ uint32_t line_no,
+ LazyBool check_inlines,
+ LazyBool skip_prologue,
+ bool internal)
+{
+ if (check_inlines == eLazyBoolCalculate)
+ {
+ const InlineStrategy inline_strategy = GetInlineStrategy();
+ switch (inline_strategy)
+ {
+ case eInlineBreakpointsNever:
+ check_inlines = eLazyBoolNo;
+ break;
+
+ case eInlineBreakpointsHeaders:
+ if (file.IsSourceImplementationFile())
+ check_inlines = eLazyBoolNo;
+ else
+ check_inlines = eLazyBoolYes;
+ break;
+
+ case eInlineBreakpointsAlways:
+ check_inlines = eLazyBoolYes;
+ break;
+ }
+ }
+ SearchFilterSP filter_sp;
+ if (check_inlines == eLazyBoolNo)
+ {
+ // Not checking for inlines, we are looking only for matching compile units
+ FileSpecList compile_unit_list;
+ compile_unit_list.Append (file);
+ filter_sp = GetSearchFilterForModuleAndCUList (containingModules, &compile_unit_list);
+ }
+ else
+ {
+ filter_sp = GetSearchFilterForModuleList (containingModules);
+ }
+ if (skip_prologue == eLazyBoolCalculate)
+ skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo;
+
+ BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (NULL,
+ file,
+ line_no,
+ check_inlines,
+ skip_prologue));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+
+BreakpointSP
+Target::CreateBreakpoint (lldb::addr_t addr, bool internal)
+{
+ Address so_addr;
+ // Attempt to resolve our load address if possible, though it is ok if
+ // it doesn't resolve to section/offset.
+
+ // Try and resolve as a load address if possible
+ m_section_load_list.ResolveLoadAddress(addr, so_addr);
+ if (!so_addr.IsValid())
+ {
+ // The address didn't resolve, so just set this as an absolute address
+ so_addr.SetOffset (addr);
+ }
+ BreakpointSP bp_sp (CreateBreakpoint(so_addr, internal));
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (Address &addr, bool internal)
+{
+ SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+BreakpointSP
+Target::CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const char *func_name,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue,
+ bool internal)
+{
+ BreakpointSP bp_sp;
+ if (func_name)
+ {
+ SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+
+ if (skip_prologue == eLazyBoolCalculate)
+ skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo;
+
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL,
+ func_name,
+ func_name_type_mask,
+ Breakpoint::Exact,
+ skip_prologue));
+ bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal);
+ }
+ return bp_sp;
+}
+
+lldb::BreakpointSP
+Target::CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const std::vector<std::string> &func_names,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue,
+ bool internal)
+{
+ BreakpointSP bp_sp;
+ size_t num_names = func_names.size();
+ if (num_names > 0)
+ {
+ SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+
+ if (skip_prologue == eLazyBoolCalculate)
+ skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo;
+
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL,
+ func_names,
+ func_name_type_mask,
+ skip_prologue));
+ bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal);
+ }
+ return bp_sp;
+}
+
+BreakpointSP
+Target::CreateBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ const char *func_names[],
+ size_t num_names,
+ uint32_t func_name_type_mask,
+ LazyBool skip_prologue,
+ bool internal)
+{
+ BreakpointSP bp_sp;
+ if (num_names > 0)
+ {
+ SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+
+ if (skip_prologue == eLazyBoolCalculate)
+ skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo;
+
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (NULL,
+ func_names,
+ num_names,
+ func_name_type_mask,
+ skip_prologue));
+ bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal);
+ }
+ return bp_sp;
+}
+
+SearchFilterSP
+Target::GetSearchFilterForModule (const FileSpec *containingModule)
+{
+ SearchFilterSP filter_sp;
+ if (containingModule != NULL)
+ {
+ // TODO: We should look into sharing module based search filters
+ // across many breakpoints like we do for the simple target based one
+ filter_sp.reset (new SearchFilterByModule (shared_from_this(), *containingModule));
+ }
+ else
+ {
+ if (m_search_filter_sp.get() == NULL)
+ m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ filter_sp = m_search_filter_sp;
+ }
+ return filter_sp;
+}
+
+SearchFilterSP
+Target::GetSearchFilterForModuleList (const FileSpecList *containingModules)
+{
+ SearchFilterSP filter_sp;
+ if (containingModules && containingModules->GetSize() != 0)
+ {
+ // TODO: We should look into sharing module based search filters
+ // across many breakpoints like we do for the simple target based one
+ filter_sp.reset (new SearchFilterByModuleList (shared_from_this(), *containingModules));
+ }
+ else
+ {
+ if (m_search_filter_sp.get() == NULL)
+ m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ filter_sp = m_search_filter_sp;
+ }
+ return filter_sp;
+}
+
+SearchFilterSP
+Target::GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles)
+{
+ if (containingSourceFiles == NULL || containingSourceFiles->GetSize() == 0)
+ return GetSearchFilterForModuleList(containingModules);
+
+ SearchFilterSP filter_sp;
+ if (containingModules == NULL)
+ {
+ // We could make a special "CU List only SearchFilter". Better yet was if these could be composable,
+ // but that will take a little reworking.
+
+ filter_sp.reset (new SearchFilterByModuleListAndCU (shared_from_this(), FileSpecList(), *containingSourceFiles));
+ }
+ else
+ {
+ filter_sp.reset (new SearchFilterByModuleListAndCU (shared_from_this(), *containingModules, *containingSourceFiles));
+ }
+ return filter_sp;
+}
+
+BreakpointSP
+Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
+ const FileSpecList *containingSourceFiles,
+ RegularExpression &func_regex,
+ LazyBool skip_prologue,
+ bool internal)
+{
+ SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+ BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL,
+ func_regex,
+ skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue));
+
+ return CreateBreakpoint (filter_sp, resolver_sp, internal);
+}
+
+lldb::BreakpointSP
+Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal)
+{
+ return LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal);
+}
+
+BreakpointSP
+Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal)
+{
+ BreakpointSP bp_sp;
+ if (filter_sp && resolver_sp)
+ {
+ bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp));
+ resolver_sp->SetBreakpoint (bp_sp.get());
+
+ 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());
+ }
+
+ bp_sp->ResolveBreakpoint();
+ }
+
+ if (!internal && bp_sp)
+ {
+ m_last_created_breakpoint = bp_sp;
+ }
+
+ return bp_sp;
+}
+
+bool
+Target::ProcessIsValid()
+{
+ return (m_process_sp && m_process_sp->IsAlive());
+}
+
+static bool
+CheckIfWatchpointsExhausted(Target *target, Error &error)
+{
+ uint32_t num_supported_hardware_watchpoints;
+ Error rc = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints);
+ if (rc.Success())
+ {
+ uint32_t num_current_watchpoints = target->GetWatchpointList().GetSize();
+ if (num_current_watchpoints >= num_supported_hardware_watchpoints)
+ error.SetErrorStringWithFormat("number of supported hardware watchpoints (%u) has been reached",
+ num_supported_hardware_watchpoints);
+ }
+ return false;
+}
+
+// See also Watchpoint::SetWatchpointType(uint32_t type) and
+// the OptionGroupWatchpoint::WatchType enum type.
+WatchpointSP
+Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const ClangASTType *type, uint32_t kind, Error &error)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("Target::%s (addr = 0x%8.8" PRIx64 " size = %" PRIu64 " type = %u)\n",
+ __FUNCTION__, addr, (uint64_t)size, kind);
+
+ WatchpointSP wp_sp;
+ if (!ProcessIsValid())
+ {
+ error.SetErrorString("process is not alive");
+ return wp_sp;
+ }
+
+ if (addr == LLDB_INVALID_ADDRESS || size == 0)
+ {
+ if (size == 0)
+ error.SetErrorString("cannot set a watchpoint with watch_size of 0");
+ else
+ error.SetErrorStringWithFormat("invalid watch address: %" PRIu64, addr);
+ return wp_sp;
+ }
+
+ if (!LLDB_WATCH_TYPE_IS_VALID(kind))
+ {
+ error.SetErrorStringWithFormat ("invalid watchpoint type: %d", kind);
+ }
+
+ // Currently we only support one watchpoint per address, with total number
+ // of watchpoints limited by the hardware which the inferior is running on.
+
+ // Grab the list mutex while doing operations.
+ const bool notify = false; // Don't notify about all the state changes we do on creating the watchpoint.
+ Mutex::Locker locker;
+ this->GetWatchpointList().GetListMutex(locker);
+ WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr);
+ if (matched_sp)
+ {
+ size_t old_size = matched_sp->GetByteSize();
+ uint32_t old_type =
+ (matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) |
+ (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0);
+ // Return the existing watchpoint if both size and type match.
+ if (size == old_size && kind == old_type)
+ {
+ wp_sp = matched_sp;
+ wp_sp->SetEnabled(false, notify);
+ }
+ else
+ {
+ // Nil the matched watchpoint; we will be creating a new one.
+ m_process_sp->DisableWatchpoint(matched_sp.get(), notify);
+ m_watchpoint_list.Remove(matched_sp->GetID(), true);
+ }
+ }
+
+ if (!wp_sp)
+ {
+ wp_sp.reset(new Watchpoint(*this, addr, size, type));
+ wp_sp->SetWatchpointType(kind, notify);
+ m_watchpoint_list.Add (wp_sp, true);
+ }
+
+ error = m_process_sp->EnableWatchpoint(wp_sp.get(), notify);
+ if (log)
+ log->Printf("Target::%s (creation of watchpoint %s with id = %u)\n",
+ __FUNCTION__,
+ error.Success() ? "succeeded" : "failed",
+ wp_sp->GetID());
+
+ if (error.Fail())
+ {
+ // Enabling the watchpoint on the device side failed.
+ // Remove the said watchpoint from the list maintained by the target instance.
+ m_watchpoint_list.Remove (wp_sp->GetID(), true);
+ // See if we could provide more helpful error message.
+ if (!CheckIfWatchpointsExhausted(this, error))
+ {
+ if (!OptionGroupWatchpoint::IsWatchSizeSupported(size))
+ error.SetErrorStringWithFormat("watch size of %lu is not supported", size);
+ }
+ wp_sp.reset();
+ }
+ else
+ m_last_created_watchpoint = wp_sp;
+ return wp_sp;
+}
+
+void
+Target::RemoveAllBreakpoints (bool internal_also)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.RemoveAll (true);
+ if (internal_also)
+ m_internal_breakpoint_list.RemoveAll (false);
+
+ m_last_created_breakpoint.reset();
+}
+
+void
+Target::DisableAllBreakpoints (bool internal_also)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.SetEnabledAll (false);
+ if (internal_also)
+ m_internal_breakpoint_list.SetEnabledAll (false);
+}
+
+void
+Target::EnableAllBreakpoints (bool internal_also)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no");
+
+ m_breakpoint_list.SetEnabledAll (true);
+ if (internal_also)
+ m_internal_breakpoint_list.SetEnabledAll (true);
+}
+
+bool
+Target::RemoveBreakpointByID (break_id_t break_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ if (DisableBreakpointByID (break_id))
+ {
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ m_internal_breakpoint_list.Remove(break_id, false);
+ else
+ {
+ if (m_last_created_breakpoint)
+ {
+ if (m_last_created_breakpoint->GetID() == break_id)
+ m_last_created_breakpoint.reset();
+ }
+ m_breakpoint_list.Remove(break_id, true);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+Target::DisableBreakpointByID (break_id_t break_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+ if (bp_sp)
+ {
+ bp_sp->SetEnabled (false);
+ return true;
+ }
+ return false;
+}
+
+bool
+Target::EnableBreakpointByID (break_id_t break_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("Target::%s (break_id = %i, internal = %s)\n",
+ __FUNCTION__,
+ break_id,
+ LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no");
+
+ BreakpointSP bp_sp;
+
+ if (LLDB_BREAK_ID_IS_INTERNAL (break_id))
+ bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id);
+ else
+ bp_sp = m_breakpoint_list.FindBreakpointByID (break_id);
+
+ if (bp_sp)
+ {
+ bp_sp->SetEnabled (true);
+ return true;
+ }
+ return false;
+}
+
+// The flag 'end_to_end', default to true, signifies that the operation is
+// performed end to end, for both the debugger and the debuggee.
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list for end
+// to end operations.
+bool
+Target::RemoveAllWatchpoints (bool end_to_end)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ if (!end_to_end) {
+ m_watchpoint_list.RemoveAll(true);
+ return true;
+ }
+
+ // Otherwise, it's an end to end operation.
+
+ if (!ProcessIsValid())
+ return false;
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ if (rc.Fail())
+ return false;
+ }
+ m_watchpoint_list.RemoveAll (true);
+ m_last_created_watchpoint.reset();
+ return true; // Success!
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list for end to
+// end operations.
+bool
+Target::DisableAllWatchpoints (bool end_to_end)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ if (!end_to_end) {
+ m_watchpoint_list.SetEnabledAll(false);
+ return true;
+ }
+
+ // Otherwise, it's an end to end operation.
+
+ if (!ProcessIsValid())
+ return false;
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ if (rc.Fail())
+ return false;
+ }
+ return true; // Success!
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list for end to
+// end operations.
+bool
+Target::EnableAllWatchpoints (bool end_to_end)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ if (!end_to_end) {
+ m_watchpoint_list.SetEnabledAll(true);
+ return true;
+ }
+
+ // Otherwise, it's an end to end operation.
+
+ if (!ProcessIsValid())
+ return false;
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ Error rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+ if (rc.Fail())
+ return false;
+ }
+ return true; // Success!
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::ClearAllWatchpointHitCounts ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ wp_sp->ResetHitCount();
+ }
+ return true; // Success!
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list
+// during these operations.
+bool
+Target::IgnoreAllWatchpoints (uint32_t ignore_count)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s\n", __FUNCTION__);
+
+ if (!ProcessIsValid())
+ return false;
+
+ size_t num_watchpoints = m_watchpoint_list.GetSize();
+ for (size_t i = 0; i < num_watchpoints; ++i)
+ {
+ WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i);
+ if (!wp_sp)
+ return false;
+
+ wp_sp->SetIgnoreCount(ignore_count);
+ }
+ return true; // Success!
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::DisableWatchpointByID (lldb::watch_id_t watch_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id);
+
+ if (!ProcessIsValid())
+ return false;
+
+ WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id);
+ if (wp_sp)
+ {
+ Error rc = m_process_sp->DisableWatchpoint(wp_sp.get());
+ if (rc.Success())
+ return true;
+
+ // Else, fallthrough.
+ }
+ return false;
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::EnableWatchpointByID (lldb::watch_id_t watch_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id);
+
+ if (!ProcessIsValid())
+ return false;
+
+ WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id);
+ if (wp_sp)
+ {
+ Error rc = m_process_sp->EnableWatchpoint(wp_sp.get());
+ if (rc.Success())
+ return true;
+
+ // Else, fallthrough.
+ }
+ return false;
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::RemoveWatchpointByID (lldb::watch_id_t watch_id)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id);
+
+ WatchpointSP watch_to_remove_sp = m_watchpoint_list.FindByID(watch_id);
+ if (watch_to_remove_sp == m_last_created_watchpoint)
+ m_last_created_watchpoint.reset();
+
+ if (DisableWatchpointByID (watch_id))
+ {
+ m_watchpoint_list.Remove(watch_id, true);
+ return true;
+ }
+ return false;
+}
+
+// Assumption: Caller holds the list mutex lock for m_watchpoint_list.
+bool
+Target::IgnoreWatchpointByID (lldb::watch_id_t watch_id, uint32_t ignore_count)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id);
+
+ if (!ProcessIsValid())
+ return false;
+
+ WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id);
+ if (wp_sp)
+ {
+ wp_sp->SetIgnoreCount(ignore_count);
+ return true;
+ }
+ return false;
+}
+
+ModuleSP
+Target::GetExecutableModule ()
+{
+ return m_images.GetModuleAtIndex(0);
+}
+
+Module*
+Target::GetExecutableModulePointer ()
+{
+ return m_images.GetModulePointerAtIndex(0);
+}
+
+static void
+LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target)
+{
+ Error error;
+ StreamString feedback_stream;
+ if (module_sp && !module_sp->LoadScriptingResourceInTarget(target, error, &feedback_stream))
+ {
+ if (error.AsCString())
+ target->GetDebugger().GetErrorStream().Printf("unable to load scripting data for module %s - error reported was %s\n",
+ module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(),
+ error.AsCString());
+ if (feedback_stream.GetSize())
+ target->GetDebugger().GetOutputStream().Printf("%s\n",
+ feedback_stream.GetData());
+ }
+}
+
+void
+Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
+ m_images.Clear();
+ m_scratch_ast_context_ap.reset();
+ m_scratch_ast_source_ap.reset();
+ m_ast_importer_ap.reset();
+
+ if (executable_sp.get())
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "Target::SetExecutableModule (executable = '%s')",
+ executable_sp->GetFileSpec().GetPath().c_str());
+
+ m_images.Append(executable_sp); // The first image is our exectuable file
+
+ // If we haven't set an architecture yet, reset our architecture based on what we found in the executable module.
+ if (!m_arch.IsValid())
+ {
+ m_arch = executable_sp->GetArchitecture();
+ if (log)
+ log->Printf ("Target::SetExecutableModule setting architecture to %s (%s) based on executable file", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str());
+ }
+
+ FileSpecList dependent_files;
+ ObjectFile *executable_objfile = executable_sp->GetObjectFile();
+
+ if (executable_objfile && get_dependent_files)
+ {
+ executable_objfile->GetDependentModules(dependent_files);
+ for (uint32_t i=0; i<dependent_files.GetSize(); i++)
+ {
+ FileSpec dependent_file_spec (dependent_files.GetFileSpecPointerAtIndex(i));
+ FileSpec platform_dependent_file_spec;
+ if (m_platform_sp)
+ m_platform_sp->GetFile (dependent_file_spec, NULL, platform_dependent_file_spec);
+ else
+ platform_dependent_file_spec = dependent_file_spec;
+
+ ModuleSpec module_spec (platform_dependent_file_spec, m_arch);
+ ModuleSP image_module_sp(GetSharedModule (module_spec));
+ if (image_module_sp.get())
+ {
+ ObjectFile *objfile = image_module_sp->GetObjectFile();
+ if (objfile)
+ objfile->GetDependentModules(dependent_files);
+ }
+ }
+ }
+ }
+}
+
+
+bool
+Target::SetArchitecture (const ArchSpec &arch_spec)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
+ if (m_arch.IsCompatibleMatch(arch_spec) || !m_arch.IsValid())
+ {
+ // If we haven't got a valid arch spec, or the architectures are
+ // compatible, so just update the architecture. Architectures can be
+ // equal, yet the triple OS and vendor might change, so we need to do
+ // the assignment here just in case.
+ m_arch = arch_spec;
+ if (log)
+ log->Printf ("Target::SetArchitecture setting architecture to %s (%s)", arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str());
+ return true;
+ }
+ else
+ {
+ // If we have an executable file, try to reset the executable to the desired architecture
+ if (log)
+ log->Printf ("Target::SetArchitecture changing architecture to %s (%s)", arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str());
+ m_arch = arch_spec;
+ ModuleSP executable_sp = GetExecutableModule ();
+ m_images.Clear();
+ m_scratch_ast_context_ap.reset();
+ m_scratch_ast_source_ap.reset();
+ m_ast_importer_ap.reset();
+ // Need to do something about unsetting breakpoints.
+
+ if (executable_sp)
+ {
+ if (log)
+ log->Printf("Target::SetArchitecture Trying to select executable file architecture %s (%s)", arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str());
+ ModuleSpec module_spec (executable_sp->GetFileSpec(), arch_spec);
+ Error error = ModuleList::GetSharedModule (module_spec,
+ executable_sp,
+ &GetExecutableSearchPaths(),
+ NULL,
+ NULL);
+
+ if (!error.Fail() && executable_sp)
+ {
+ SetExecutableModule (executable_sp, true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+Target::WillClearList (const ModuleList& module_list)
+{
+}
+
+void
+Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList my_module_list;
+ my_module_list.Append(module_sp);
+ LoadScriptingResourceForModule(module_sp, this);
+ ModulesDidLoad (my_module_list);
+}
+
+void
+Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp)
+{
+ // A module is being added to this target for the first time
+ ModuleList my_module_list;
+ my_module_list.Append(module_sp);
+ ModulesDidUnload (my_module_list);
+}
+
+void
+Target::ModuleUpdated (const ModuleList& module_list, const ModuleSP &old_module_sp, const ModuleSP &new_module_sp)
+{
+ // A module is replacing an already added module
+ m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
+}
+
+void
+Target::ModulesDidLoad (ModuleList &module_list)
+{
+ if (module_list.GetSize())
+ {
+ m_breakpoint_list.UpdateBreakpoints (module_list, true);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
+ }
+}
+
+void
+Target::SymbolsDidLoad (ModuleList &module_list)
+{
+ if (module_list.GetSize())
+ {
+ if (m_process_sp)
+ {
+ LanguageRuntime* runtime = m_process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
+ if (runtime)
+ {
+ ObjCLanguageRuntime *objc_runtime = (ObjCLanguageRuntime*)runtime;
+ objc_runtime->SymbolsDidLoad(module_list);
+ }
+ }
+
+ m_breakpoint_list.UpdateBreakpoints (module_list, true);
+ BroadcastEvent(eBroadcastBitSymbolsLoaded, NULL);
+ }
+}
+
+void
+Target::ModulesDidUnload (ModuleList &module_list)
+{
+ if (module_list.GetSize())
+ {
+ m_breakpoint_list.UpdateBreakpoints (module_list, false);
+ // TODO: make event data that packages up the module_list
+ BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
+ }
+}
+
+bool
+Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_file_spec)
+{
+ if (GetBreakpointsConsultPlatformAvoidList())
+ {
+ ModuleList matchingModules;
+ ModuleSpec module_spec (module_file_spec);
+ size_t num_modules = GetImages().FindModules(module_spec, matchingModules);
+
+ // If there is more than one module for this file spec, only return true if ALL the modules are on the
+ // black list.
+ if (num_modules > 0)
+ {
+ for (size_t i = 0; i < num_modules; i++)
+ {
+ if (!ModuleIsExcludedForNonModuleSpecificSearches (matchingModules.GetModuleAtIndex(i)))
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Target::ModuleIsExcludedForNonModuleSpecificSearches (const lldb::ModuleSP &module_sp)
+{
+ if (GetBreakpointsConsultPlatformAvoidList())
+ {
+ if (m_platform_sp)
+ return m_platform_sp->ModuleIsExcludedForNonModuleSpecificSearches (*this, module_sp);
+ }
+ return false;
+}
+
+size_t
+Target::ReadMemoryFromFileCache (const Address& addr, void *dst, size_t dst_len, Error &error)
+{
+ SectionSP section_sp (addr.GetSection());
+ if (section_sp)
+ {
+ // If the contents of this section are encrypted, the on-disk file is unusuable. Read only from live memory.
+ if (section_sp->IsEncrypted())
+ {
+ error.SetErrorString("section is encrypted");
+ return 0;
+ }
+ ModuleSP module_sp (section_sp->GetModule());
+ if (module_sp)
+ {
+ ObjectFile *objfile = section_sp->GetModule()->GetObjectFile();
+ if (objfile)
+ {
+ size_t bytes_read = objfile->ReadSectionData (section_sp.get(),
+ addr.GetOffset(),
+ dst,
+ dst_len);
+ if (bytes_read > 0)
+ return bytes_read;
+ else
+ error.SetErrorStringWithFormat("error reading data from section %s", section_sp->GetName().GetCString());
+ }
+ else
+ error.SetErrorString("address isn't from a object file");
+ }
+ else
+ error.SetErrorString("address isn't in a module");
+ }
+ else
+ error.SetErrorString("address doesn't contain a section that points to a section in a object file");
+
+ return 0;
+}
+
+size_t
+Target::ReadMemory (const Address& addr,
+ bool prefer_file_cache,
+ void *dst,
+ size_t dst_len,
+ Error &error,
+ lldb::addr_t *load_addr_ptr)
+{
+ error.Clear();
+
+ // if we end up reading this from process memory, we will fill this
+ // with the actual load address
+ if (load_addr_ptr)
+ *load_addr_ptr = LLDB_INVALID_ADDRESS;
+
+ size_t bytes_read = 0;
+
+ addr_t load_addr = LLDB_INVALID_ADDRESS;
+ addr_t file_addr = LLDB_INVALID_ADDRESS;
+ Address resolved_addr;
+ if (!addr.IsSectionOffset())
+ {
+ if (m_section_load_list.IsEmpty())
+ {
+ // No sections are loaded, so we must assume we are not running
+ // yet and anything we are given is a file address.
+ file_addr = addr.GetOffset(); // "addr" doesn't have a section, so its offset is the file address
+ m_images.ResolveFileAddress (file_addr, resolved_addr);
+ }
+ else
+ {
+ // We have at least one section loaded. This can be becuase
+ // we have manually loaded some sections with "target modules load ..."
+ // or because we have have a live process that has sections loaded
+ // through the dynamic loader
+ load_addr = addr.GetOffset(); // "addr" doesn't have a section, so its offset is the load address
+ m_section_load_list.ResolveLoadAddress (load_addr, resolved_addr);
+ }
+ }
+ if (!resolved_addr.IsValid())
+ resolved_addr = addr;
+
+
+ if (prefer_file_cache)
+ {
+ bytes_read = ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error);
+ if (bytes_read > 0)
+ return bytes_read;
+ }
+
+ if (ProcessIsValid())
+ {
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ load_addr = resolved_addr.GetLoadAddress (this);
+
+ if (load_addr == LLDB_INVALID_ADDRESS)
+ {
+ 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(),
+ resolved_addr.GetFileAddress(),
+ addr_module_sp->GetFileSpec().GetFilename().AsCString());
+ else
+ error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", resolved_addr.GetFileAddress());
+ }
+ else
+ {
+ bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error);
+ if (bytes_read != dst_len)
+ {
+ if (error.Success())
+ {
+ if (bytes_read == 0)
+ error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", load_addr);
+ else
+ error.SetErrorStringWithFormat("only %" PRIu64 " of %" PRIu64 " bytes were read from memory at 0x%" PRIx64, (uint64_t)bytes_read, (uint64_t)dst_len, load_addr);
+ }
+ }
+ if (bytes_read)
+ {
+ if (load_addr_ptr)
+ *load_addr_ptr = load_addr;
+ return bytes_read;
+ }
+ // If the address is not section offset we have an address that
+ // doesn't resolve to any address in any currently loaded shared
+ // libaries and we failed to read memory so there isn't anything
+ // more we can do. If it is section offset, we might be able to
+ // read cached memory from the object file.
+ if (!resolved_addr.IsSectionOffset())
+ return 0;
+ }
+ }
+
+ if (!prefer_file_cache && resolved_addr.IsSectionOffset())
+ {
+ // If we didn't already try and read from the object file cache, then
+ // try it after failing to read from the process.
+ return ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error);
+ }
+ return 0;
+}
+
+size_t
+Target::ReadCStringFromMemory (const Address& addr, std::string &out_str, Error &error)
+{
+ char buf[256];
+ out_str.clear();
+ addr_t curr_addr = addr.GetLoadAddress(this);
+ Address address(addr);
+ while (1)
+ {
+ size_t length = ReadCStringFromMemory (address, buf, sizeof(buf), error);
+ if (length == 0)
+ break;
+ out_str.append(buf, length);
+ // If we got "length - 1" bytes, we didn't get the whole C string, we
+ // need to read some more characters
+ if (length == sizeof(buf) - 1)
+ curr_addr += length;
+ else
+ break;
+ address = Address(curr_addr);
+ }
+ return out_str.size();
+}
+
+
+size_t
+Target::ReadCStringFromMemory (const Address& addr, char *dst, size_t dst_max_len, Error &result_error)
+{
+ size_t total_cstr_len = 0;
+ if (dst && dst_max_len)
+ {
+ result_error.Clear();
+ // NULL out everything just to be safe
+ memset (dst, 0, dst_max_len);
+ Error error;
+ addr_t curr_addr = addr.GetLoadAddress(this);
+ Address address(addr);
+ const size_t cache_line_size = 512;
+ size_t bytes_left = dst_max_len - 1;
+ char *curr_dst = dst;
+
+ while (bytes_left > 0)
+ {
+ addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ size_t bytes_read = ReadMemory (address, false, curr_dst, bytes_to_read, error);
+
+ if (bytes_read == 0)
+ {
+ result_error = error;
+ dst[total_cstr_len] = '\0';
+ break;
+ }
+ const size_t len = strlen(curr_dst);
+
+ total_cstr_len += len;
+
+ if (len < bytes_to_read)
+ break;
+
+ curr_dst += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ address = Address(curr_addr);
+ }
+ }
+ else
+ {
+ if (dst == NULL)
+ result_error.SetErrorString("invalid arguments");
+ else
+ result_error.Clear();
+ }
+ return total_cstr_len;
+}
+
+size_t
+Target::ReadScalarIntegerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ uint32_t byte_size,
+ bool is_signed,
+ Scalar &scalar,
+ Error &error)
+{
+ uint64_t uval;
+
+ if (byte_size <= sizeof(uval))
+ {
+ size_t bytes_read = ReadMemory (addr, prefer_file_cache, &uval, byte_size, error);
+ if (bytes_read == byte_size)
+ {
+ DataExtractor data (&uval, sizeof(uval), m_arch.GetByteOrder(), m_arch.GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ if (byte_size <= 4)
+ scalar = data.GetMaxU32 (&offset, byte_size);
+ else
+ scalar = data.GetMaxU64 (&offset, byte_size);
+
+ if (is_signed)
+ scalar.SignExtend(byte_size * 8);
+ return bytes_read;
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("byte size of %u is too large for integer scalar type", byte_size);
+ }
+ return 0;
+}
+
+uint64_t
+Target::ReadUnsignedIntegerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ size_t integer_byte_size,
+ uint64_t fail_value,
+ Error &error)
+{
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory (addr,
+ prefer_file_cache,
+ integer_byte_size,
+ false,
+ scalar,
+ error))
+ return scalar.ULongLong(fail_value);
+ return fail_value;
+}
+
+bool
+Target::ReadPointerFromMemory (const Address& addr,
+ bool prefer_file_cache,
+ Error &error,
+ Address &pointer_addr)
+{
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory (addr,
+ prefer_file_cache,
+ m_arch.GetAddressByteSize(),
+ false,
+ scalar,
+ error))
+ {
+ addr_t pointer_vm_addr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
+ if (pointer_vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (m_section_load_list.IsEmpty())
+ {
+ // No sections are loaded, so we must assume we are not running
+ // yet and anything we are given is a file address.
+ m_images.ResolveFileAddress (pointer_vm_addr, pointer_addr);
+ }
+ else
+ {
+ // We have at least one section loaded. This can be becuase
+ // we have manually loaded some sections with "target modules load ..."
+ // or because we have have a live process that has sections loaded
+ // through the dynamic loader
+ m_section_load_list.ResolveLoadAddress (pointer_vm_addr, pointer_addr);
+ }
+ // We weren't able to resolve the pointer value, so just return
+ // an address with no section
+ if (!pointer_addr.IsValid())
+ pointer_addr.SetOffset (pointer_vm_addr);
+ return true;
+
+ }
+ }
+ return false;
+}
+
+ModuleSP
+Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr)
+{
+ ModuleSP module_sp;
+
+ Error error;
+
+ // First see if we already have this module in our module list. If we do, then we're done, we don't need
+ // to consult the shared modules list. But only do this if we are passed a UUID.
+
+ if (module_spec.GetUUID().IsValid())
+ module_sp = m_images.FindFirstModule(module_spec);
+
+ if (!module_sp)
+ {
+ ModuleSP old_module_sp; // This will get filled in if we have a new version of the library
+ bool did_create_module = false;
+
+ // If there are image search path entries, try to use them first to acquire a suitable image.
+ if (m_image_search_paths.GetSize())
+ {
+ ModuleSpec transformed_spec (module_spec);
+ if (m_image_search_paths.RemapPath (module_spec.GetFileSpec().GetDirectory(), transformed_spec.GetFileSpec().GetDirectory()))
+ {
+ transformed_spec.GetFileSpec().GetFilename() = module_spec.GetFileSpec().GetFilename();
+ error = ModuleList::GetSharedModule (transformed_spec,
+ module_sp,
+ &GetExecutableSearchPaths(),
+ &old_module_sp,
+ &did_create_module);
+ }
+ }
+
+ if (!module_sp)
+ {
+ // If we have a UUID, we can check our global shared module list in case
+ // we already have it. If we don't have a valid UUID, then we can't since
+ // the path in "module_spec" will be a platform path, and we will need to
+ // let the platform find that file. For example, we could be asking for
+ // "/usr/lib/dyld" and if we do not have a UUID, we don't want to pick
+ // the local copy of "/usr/lib/dyld" since our platform could be a remote
+ // platform that has its own "/usr/lib/dyld" in an SDK or in a local file
+ // cache.
+ if (module_spec.GetUUID().IsValid())
+ {
+ // We have a UUID, it is OK to check the global module list...
+ error = ModuleList::GetSharedModule (module_spec,
+ module_sp,
+ &GetExecutableSearchPaths(),
+ &old_module_sp,
+ &did_create_module);
+ }
+
+ if (!module_sp)
+ {
+ // The platform is responsible for finding and caching an appropriate
+ // module in the shared module cache.
+ if (m_platform_sp)
+ {
+ FileSpec platform_file_spec;
+ error = m_platform_sp->GetSharedModule (module_spec,
+ module_sp,
+ &GetExecutableSearchPaths(),
+ &old_module_sp,
+ &did_create_module);
+ }
+ else
+ {
+ error.SetErrorString("no platform is currently set");
+ }
+ }
+ }
+
+ // We found a module that wasn't in our target list. Let's make sure that there wasn't an equivalent
+ // module in the list already, and if there was, let's remove it.
+ if (module_sp)
+ {
+ ObjectFile *objfile = module_sp->GetObjectFile();
+ if (objfile)
+ {
+ switch (objfile->GetType())
+ {
+ case ObjectFile::eTypeCoreFile: /// A core file that has a checkpoint of a program's execution state
+ case ObjectFile::eTypeExecutable: /// A normal executable
+ case ObjectFile::eTypeDynamicLinker: /// The platform's dynamic linker executable
+ case ObjectFile::eTypeObjectFile: /// An intermediate object file
+ case ObjectFile::eTypeSharedLibrary: /// A shared library that can be used during execution
+ break;
+ case ObjectFile::eTypeDebugInfo: /// An object file that contains only debug information
+ if (error_ptr)
+ error_ptr->SetErrorString("debug info files aren't valid target modules, please specify an executable");
+ return ModuleSP();
+ case ObjectFile::eTypeStubLibrary: /// A library that can be linked against but not used for execution
+ if (error_ptr)
+ error_ptr->SetErrorString("stub libraries aren't valid target modules, please specify an executable");
+ return ModuleSP();
+ default:
+ if (error_ptr)
+ error_ptr->SetErrorString("unsupported file type, please specify an executable");
+ return ModuleSP();
+ }
+ // GetSharedModule is not guaranteed to find the old shared module, for instance
+ // in the common case where you pass in the UUID, it is only going to find the one
+ // module matching the UUID. In fact, it has no good way to know what the "old module"
+ // relevant to this target is, since there might be many copies of a module with this file spec
+ // in various running debug sessions, but only one of them will belong to this target.
+ // So let's remove the UUID from the module list, and look in the target's module list.
+ // Only do this if there is SOMETHING else in the module spec...
+ if (!old_module_sp)
+ {
+ if (module_spec.GetUUID().IsValid() && !module_spec.GetFileSpec().GetFilename().IsEmpty() && !module_spec.GetFileSpec().GetDirectory().IsEmpty())
+ {
+ ModuleSpec module_spec_copy(module_spec.GetFileSpec());
+ module_spec_copy.GetUUID().Clear();
+
+ ModuleList found_modules;
+ size_t num_found = m_images.FindModules (module_spec_copy, found_modules);
+ if (num_found == 1)
+ {
+ old_module_sp = found_modules.GetModuleAtIndex(0);
+ }
+ }
+ }
+
+ if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32)
+ {
+ m_images.ReplaceModule(old_module_sp, module_sp);
+ Module *old_module_ptr = old_module_sp.get();
+ old_module_sp.reset();
+ ModuleList::RemoveSharedModuleIfOrphaned (old_module_ptr);
+ }
+ else
+ m_images.Append(module_sp);
+ }
+ }
+ }
+ if (error_ptr)
+ *error_ptr = error;
+ return module_sp;
+}
+
+
+TargetSP
+Target::CalculateTarget ()
+{
+ return shared_from_this();
+}
+
+ProcessSP
+Target::CalculateProcess ()
+{
+ return ProcessSP();
+}
+
+ThreadSP
+Target::CalculateThread ()
+{
+ return ThreadSP();
+}
+
+StackFrameSP
+Target::CalculateStackFrame ()
+{
+ return StackFrameSP();
+}
+
+void
+Target::CalculateExecutionContext (ExecutionContext &exe_ctx)
+{
+ exe_ctx.Clear();
+ exe_ctx.SetTargetPtr(this);
+}
+
+PathMappingList &
+Target::GetImageSearchPathList ()
+{
+ return m_image_search_paths;
+}
+
+void
+Target::ImageSearchPathsChanged
+(
+ const PathMappingList &path_list,
+ void *baton
+)
+{
+ Target *target = (Target *)baton;
+ ModuleSP exe_module_sp (target->GetExecutableModule());
+ if (exe_module_sp)
+ {
+ target->m_images.Clear();
+ target->SetExecutableModule (exe_module_sp, true);
+ }
+}
+
+ClangASTContext *
+Target::GetScratchClangASTContext(bool create_on_demand)
+{
+ // Now see if we know the target triple, and if so, create our scratch AST context:
+ if (m_scratch_ast_context_ap.get() == NULL && m_arch.IsValid() && create_on_demand)
+ {
+ m_scratch_ast_context_ap.reset (new ClangASTContext(m_arch.GetTriple().str().c_str()));
+ m_scratch_ast_source_ap.reset (new ClangASTSource(shared_from_this()));
+ m_scratch_ast_source_ap->InstallASTContext(m_scratch_ast_context_ap->getASTContext());
+ llvm::OwningPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());
+ m_scratch_ast_context_ap->SetExternalSource(proxy_ast_source);
+ }
+ return m_scratch_ast_context_ap.get();
+}
+
+ClangASTImporter *
+Target::GetClangASTImporter()
+{
+ ClangASTImporter *ast_importer = m_ast_importer_ap.get();
+
+ if (!ast_importer)
+ {
+ ast_importer = new ClangASTImporter();
+ m_ast_importer_ap.reset(ast_importer);
+ }
+
+ return ast_importer;
+}
+
+void
+Target::SettingsInitialize ()
+{
+ Process::SettingsInitialize ();
+}
+
+void
+Target::SettingsTerminate ()
+{
+ Process::SettingsTerminate ();
+}
+
+FileSpecList
+Target::GetDefaultExecutableSearchPaths ()
+{
+ TargetPropertiesSP properties_sp(Target::GetGlobalProperties());
+ if (properties_sp)
+ return properties_sp->GetExecutableSearchPaths();
+ return FileSpecList();
+}
+
+FileSpecList
+Target::GetDefaultDebugFileSearchPaths ()
+{
+ TargetPropertiesSP properties_sp(Target::GetGlobalProperties());
+ if (properties_sp)
+ return properties_sp->GetDebugFileSearchPaths();
+ return FileSpecList();
+}
+
+ArchSpec
+Target::GetDefaultArchitecture ()
+{
+ TargetPropertiesSP properties_sp(Target::GetGlobalProperties());
+ if (properties_sp)
+ return properties_sp->GetDefaultArchitecture();
+ return ArchSpec();
+}
+
+void
+Target::SetDefaultArchitecture (const ArchSpec &arch)
+{
+ TargetPropertiesSP properties_sp(Target::GetGlobalProperties());
+ if (properties_sp)
+ {
+ LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::SetDefaultArchitecture setting target's default architecture to %s (%s)", arch.GetArchitectureName(), arch.GetTriple().getTriple().c_str());
+ return properties_sp->SetDefaultArchitecture(arch);
+ }
+}
+
+Target *
+Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr)
+{
+ // The target can either exist in the "process" of ExecutionContext, or in
+ // the "target_sp" member of SymbolContext. This accessor helper function
+ // will get the target from one of these locations.
+
+ Target *target = NULL;
+ if (sc_ptr != NULL)
+ target = sc_ptr->target_sp.get();
+ if (target == NULL && exe_ctx_ptr)
+ target = exe_ctx_ptr->GetTargetPtr();
+ return target;
+}
+
+ExecutionResults
+Target::EvaluateExpression
+(
+ const char *expr_cstr,
+ StackFrame *frame,
+ lldb::ValueObjectSP &result_valobj_sp,
+ const EvaluateExpressionOptions& options
+)
+{
+ result_valobj_sp.reset();
+
+ ExecutionResults execution_results = eExecutionSetupError;
+
+ if (expr_cstr == NULL || expr_cstr[0] == '\0')
+ return execution_results;
+
+ // We shouldn't run stop hooks in expressions.
+ // Be sure to reset this if you return anywhere within this function.
+ bool old_suppress_value = m_suppress_stop_hooks;
+ m_suppress_stop_hooks = true;
+
+ ExecutionContext exe_ctx;
+
+ if (frame)
+ {
+ frame->CalculateExecutionContext(exe_ctx);
+ }
+ else if (m_process_sp)
+ {
+ m_process_sp->CalculateExecutionContext(exe_ctx);
+ }
+ else
+ {
+ CalculateExecutionContext(exe_ctx);
+ }
+
+ // Make sure we aren't just trying to see the value of a persistent
+ // variable (something like "$0")
+ lldb::ClangExpressionVariableSP persistent_var_sp;
+ // Only check for persistent variables the expression starts with a '$'
+ if (expr_cstr[0] == '$')
+ persistent_var_sp = m_persistent_variables.GetVariable (expr_cstr);
+
+ if (persistent_var_sp)
+ {
+ result_valobj_sp = persistent_var_sp->GetValueObject ();
+ execution_results = eExecutionCompleted;
+ }
+ else
+ {
+ const char *prefix = GetExpressionPrefixContentsAsCString();
+
+ execution_results = ClangUserExpression::Evaluate (exe_ctx,
+ options.GetExecutionPolicy(),
+ lldb::eLanguageTypeUnknown,
+ options.DoesCoerceToId() ? ClangUserExpression::eResultTypeId : ClangUserExpression::eResultTypeAny,
+ options.DoesUnwindOnError(),
+ options.DoesIgnoreBreakpoints(),
+ expr_cstr,
+ prefix,
+ result_valobj_sp,
+ options.GetRunOthers(),
+ options.GetTimeoutUsec());
+ }
+
+ m_suppress_stop_hooks = old_suppress_value;
+
+ return execution_results;
+}
+
+lldb::addr_t
+Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const
+{
+ addr_t code_addr = load_addr;
+ switch (m_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ switch (addr_class)
+ {
+ case eAddressClassData:
+ case eAddressClassDebug:
+ return LLDB_INVALID_ADDRESS;
+
+ case eAddressClassUnknown:
+ case eAddressClassInvalid:
+ case eAddressClassCode:
+ case eAddressClassCodeAlternateISA:
+ case eAddressClassRuntime:
+ // Check if bit zero it no set?
+ if ((code_addr & 1ull) == 0)
+ {
+ // Bit zero isn't set, check if the address is a multiple of 2?
+ if (code_addr & 2ull)
+ {
+ // The address is a multiple of 2 so it must be thumb, set bit zero
+ code_addr |= 1ull;
+ }
+ else if (addr_class == eAddressClassCodeAlternateISA)
+ {
+ // We checked the address and the address claims to be the alternate ISA
+ // which means thumb, so set bit zero.
+ code_addr |= 1ull;
+ }
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return code_addr;
+}
+
+lldb::addr_t
+Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const
+{
+ addr_t opcode_addr = load_addr;
+ switch (m_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ switch (addr_class)
+ {
+ case eAddressClassData:
+ case eAddressClassDebug:
+ return LLDB_INVALID_ADDRESS;
+
+ case eAddressClassInvalid:
+ case eAddressClassUnknown:
+ case eAddressClassCode:
+ case eAddressClassCodeAlternateISA:
+ case eAddressClassRuntime:
+ opcode_addr &= ~(1ull);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return opcode_addr;
+}
+
+SourceManager &
+Target::GetSourceManager ()
+{
+ if (m_source_manager_ap.get() == NULL)
+ m_source_manager_ap.reset (new SourceManager(shared_from_this()));
+ return *m_source_manager_ap;
+}
+
+
+lldb::user_id_t
+Target::AddStopHook (Target::StopHookSP &new_hook_sp)
+{
+ lldb::user_id_t new_uid = ++m_stop_hook_next_id;
+ new_hook_sp.reset (new StopHook(shared_from_this(), new_uid));
+ m_stop_hooks[new_uid] = new_hook_sp;
+ return new_uid;
+}
+
+bool
+Target::RemoveStopHookByID (lldb::user_id_t user_id)
+{
+ size_t num_removed;
+ num_removed = m_stop_hooks.erase (user_id);
+ if (num_removed == 0)
+ return false;
+ else
+ return true;
+}
+
+void
+Target::RemoveAllStopHooks ()
+{
+ m_stop_hooks.clear();
+}
+
+Target::StopHookSP
+Target::GetStopHookByID (lldb::user_id_t user_id)
+{
+ StopHookSP found_hook;
+
+ StopHookCollection::iterator specified_hook_iter;
+ specified_hook_iter = m_stop_hooks.find (user_id);
+ if (specified_hook_iter != m_stop_hooks.end())
+ found_hook = (*specified_hook_iter).second;
+ return found_hook;
+}
+
+bool
+Target::SetStopHookActiveStateByID (lldb::user_id_t user_id, bool active_state)
+{
+ StopHookCollection::iterator specified_hook_iter;
+ specified_hook_iter = m_stop_hooks.find (user_id);
+ if (specified_hook_iter == m_stop_hooks.end())
+ return false;
+
+ (*specified_hook_iter).second->SetIsActive (active_state);
+ return true;
+}
+
+void
+Target::SetAllStopHooksActiveState (bool active_state)
+{
+ StopHookCollection::iterator pos, end = m_stop_hooks.end();
+ for (pos = m_stop_hooks.begin(); pos != end; pos++)
+ {
+ (*pos).second->SetIsActive (active_state);
+ }
+}
+
+void
+Target::RunStopHooks ()
+{
+ if (m_suppress_stop_hooks)
+ return;
+
+ if (!m_process_sp)
+ return;
+
+ // <rdar://problem/12027563> make sure we check that we are not stopped because of us running a user expression
+ // since in that case we do not want to run the stop-hooks
+ if (m_process_sp->GetModIDRef().IsLastResumeForUserExpression())
+ return;
+
+ if (m_stop_hooks.empty())
+ return;
+
+ StopHookCollection::iterator pos, end = m_stop_hooks.end();
+
+ // If there aren't any active stop hooks, don't bother either:
+ bool any_active_hooks = false;
+ for (pos = m_stop_hooks.begin(); pos != end; pos++)
+ {
+ if ((*pos).second->IsActive())
+ {
+ any_active_hooks = true;
+ break;
+ }
+ }
+ if (!any_active_hooks)
+ return;
+
+ CommandReturnObject result;
+
+ std::vector<ExecutionContext> exc_ctx_with_reasons;
+ std::vector<SymbolContext> sym_ctx_with_reasons;
+
+ ThreadList &cur_threadlist = m_process_sp->GetThreadList();
+ size_t num_threads = cur_threadlist.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex (i);
+ if (cur_thread_sp->ThreadStoppedForAReason())
+ {
+ lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0);
+ exc_ctx_with_reasons.push_back(ExecutionContext(m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get()));
+ sym_ctx_with_reasons.push_back(cur_frame_sp->GetSymbolContext(eSymbolContextEverything));
+ }
+ }
+
+ // If no threads stopped for a reason, don't run the stop-hooks.
+ size_t num_exe_ctx = exc_ctx_with_reasons.size();
+ if (num_exe_ctx == 0)
+ return;
+
+ result.SetImmediateOutputStream (m_debugger.GetAsyncOutputStream());
+ result.SetImmediateErrorStream (m_debugger.GetAsyncErrorStream());
+
+ bool keep_going = true;
+ bool hooks_ran = false;
+ bool print_hook_header;
+ bool print_thread_header;
+
+ if (num_exe_ctx == 1)
+ print_thread_header = false;
+ else
+ print_thread_header = true;
+
+ if (m_stop_hooks.size() == 1)
+ print_hook_header = false;
+ else
+ print_hook_header = true;
+
+ for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++)
+ {
+ // result.Clear();
+ StopHookSP cur_hook_sp = (*pos).second;
+ if (!cur_hook_sp->IsActive())
+ continue;
+
+ bool any_thread_matched = false;
+ for (size_t i = 0; keep_going && i < num_exe_ctx; i++)
+ {
+ if ((cur_hook_sp->GetSpecifier () == NULL
+ || cur_hook_sp->GetSpecifier()->SymbolContextMatches(sym_ctx_with_reasons[i]))
+ && (cur_hook_sp->GetThreadSpecifier() == NULL
+ || cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx_with_reasons[i].GetThreadRef())))
+ {
+ if (!hooks_ran)
+ {
+ hooks_ran = true;
+ }
+ if (print_hook_header && !any_thread_matched)
+ {
+ const char *cmd = (cur_hook_sp->GetCommands().GetSize() == 1 ?
+ cur_hook_sp->GetCommands().GetStringAtIndex(0) :
+ NULL);
+ if (cmd)
+ result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), cmd);
+ else
+ result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", cur_hook_sp->GetID());
+ any_thread_matched = true;
+ }
+
+ 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,
+ result);
+
+ // If the command started the target going again, we should bag out of
+ // running the stop hooks.
+ if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) ||
+ (result.GetStatus() == eReturnStatusSuccessContinuingResult))
+ {
+ result.AppendMessageWithFormat ("Aborting stop hooks, hook %" PRIu64 " set the program running.", cur_hook_sp->GetID());
+ keep_going = false;
+ }
+ }
+ }
+ }
+
+ result.GetImmediateOutputStream()->Flush();
+ result.GetImmediateErrorStream()->Flush();
+}
+
+
+//--------------------------------------------------------------
+// class Target::StopHook
+//--------------------------------------------------------------
+
+
+Target::StopHook::StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid) :
+ UserID (uid),
+ m_target_sp (target_sp),
+ m_commands (),
+ m_specifier_sp (),
+ m_thread_spec_ap(),
+ m_active (true)
+{
+}
+
+Target::StopHook::StopHook (const StopHook &rhs) :
+ UserID (rhs.GetID()),
+ m_target_sp (rhs.m_target_sp),
+ m_commands (rhs.m_commands),
+ m_specifier_sp (rhs.m_specifier_sp),
+ m_thread_spec_ap (),
+ m_active (rhs.m_active)
+{
+ if (rhs.m_thread_spec_ap.get() != NULL)
+ m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
+}
+
+
+Target::StopHook::~StopHook ()
+{
+}
+
+void
+Target::StopHook::SetThreadSpecifier (ThreadSpec *specifier)
+{
+ m_thread_spec_ap.reset (specifier);
+}
+
+
+void
+Target::StopHook::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ int indent_level = s->GetIndentLevel();
+
+ s->SetIndentLevel(indent_level + 2);
+
+ s->Printf ("Hook: %" PRIu64 "\n", GetID());
+ if (m_active)
+ s->Indent ("State: enabled\n");
+ else
+ s->Indent ("State: disabled\n");
+
+ if (m_specifier_sp)
+ {
+ s->Indent();
+ s->PutCString ("Specifier:\n");
+ s->SetIndentLevel (indent_level + 4);
+ m_specifier_sp->GetDescription (s, level);
+ s->SetIndentLevel (indent_level + 2);
+ }
+
+ if (m_thread_spec_ap.get() != NULL)
+ {
+ StreamString tmp;
+ s->Indent("Thread:\n");
+ m_thread_spec_ap->GetDescription (&tmp, level);
+ s->SetIndentLevel (indent_level + 4);
+ s->Indent (tmp.GetData());
+ s->PutCString ("\n");
+ s->SetIndentLevel (indent_level + 2);
+ }
+
+ s->Indent ("Commands: \n");
+ s->SetIndentLevel (indent_level + 4);
+ uint32_t num_commands = m_commands.GetSize();
+ for (uint32_t i = 0; i < num_commands; i++)
+ {
+ s->Indent(m_commands.GetStringAtIndex(i));
+ s->PutCString ("\n");
+ }
+ s->SetIndentLevel (indent_level);
+}
+
+//--------------------------------------------------------------
+// class TargetProperties
+//--------------------------------------------------------------
+
+OptionEnumValueElement
+lldb_private::g_dynamic_value_types[] =
+{
+ { eNoDynamicValues, "no-dynamic-values", "Don't calculate the dynamic type of values"},
+ { eDynamicCanRunTarget, "run-target", "Calculate the dynamic type of values even if you have to run the target."},
+ { eDynamicDontRunTarget, "no-run-target", "Calculate the dynamic type of values, but don't run the target."},
+ { 0, NULL, NULL }
+};
+
+static OptionEnumValueElement
+g_inline_breakpoint_enums[] =
+{
+ { eInlineBreakpointsNever, "never", "Never look for inline breakpoint locations (fastest). This setting should only be used if you know that no inlining occurs in your programs."},
+ { eInlineBreakpointsHeaders, "headers", "Only check for inline breakpoint locations when setting breakpoints in header files, but not when setting breakpoint in implementation source files (default)."},
+ { eInlineBreakpointsAlways, "always", "Always look for inline breakpoint locations when setting file and line breakpoints (slower but most accurate)."},
+ { 0, NULL, NULL }
+};
+
+typedef enum x86DisassemblyFlavor
+{
+ eX86DisFlavorDefault,
+ eX86DisFlavorIntel,
+ eX86DisFlavorATT
+} x86DisassemblyFlavor;
+
+static OptionEnumValueElement
+g_x86_dis_flavor_value_types[] =
+{
+ { eX86DisFlavorDefault, "default", "Disassembler default (currently att)."},
+ { eX86DisFlavorIntel, "intel", "Intel disassembler flavor."},
+ { eX86DisFlavorATT, "att", "AT&T disassembler flavor."},
+ { 0, NULL, NULL }
+};
+
+static OptionEnumValueElement
+g_hex_immediate_style_values[] =
+{
+ { Disassembler::eHexStyleC, "c", "C-style (0xffff)."},
+ { Disassembler::eHexStyleAsm, "asm", "Asm-style (0ffffh)."},
+ { 0, NULL, NULL }
+};
+
+static OptionEnumValueElement
+g_load_script_from_sym_file_values[] =
+{
+ { eLoadScriptFromSymFileTrue, "true", "Load debug scripts inside symbol files"},
+ { eLoadScriptFromSymFileFalse, "false", "Do not load debug scripts inside symbol files."},
+ { eLoadScriptFromSymFileWarn, "warn", "Warn about debug scripts inside symbol files but do not load them."},
+ { 0, NULL, NULL }
+};
+
+
+static OptionEnumValueElement
+g_memory_module_load_level_values[] =
+{
+ { eMemoryModuleLoadLevelMinimal, "minimal" , "Load minimal information when loading modules from memory. Currently this setting loads sections only."},
+ { eMemoryModuleLoadLevelPartial, "partial" , "Load partial information when loading modules from memory. Currently this setting loads sections and function bounds."},
+ { eMemoryModuleLoadLevelComplete, "complete", "Load complete information when loading modules from memory. Currently this setting loads sections and all symbols."},
+ { 0, NULL, NULL }
+};
+
+static PropertyDefinition
+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." },
+ { "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 "
+ "where it exists on the current system. It consists of an array of duples, the first element of each duple is "
+ "some part (starting at the root) of the path to the file when it was built, "
+ "and the second is where the remainder of the original build hierarchy is rooted on the local system. "
+ "Each element of the array is checked in order and the first one that results in a match wins." },
+ { "exec-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "Executable search paths to use when locating executable files whose paths don't match the local file system." },
+ { "debug-file-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , NULL, NULL, "List of directories to be searched when locating debug symbol files." },
+ { "max-children-count" , OptionValue::eTypeSInt64 , false, 256 , NULL, NULL, "Maximum number of children to expand in any level of depth." },
+ { "max-string-summary-length" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of characters to show when using %s in summary strings." },
+ { "max-memory-read-size" , OptionValue::eTypeSInt64 , false, 1024 , NULL, NULL, "Maximum number of bytes that 'memory read' will fetch before --force must be specified." },
+ { "breakpoints-use-platform-avoid-list", OptionValue::eTypeBoolean , false, true , NULL, NULL, "Consult the platform module avoid list when setting non-module specific breakpoints." },
+ { "arg0" , OptionValue::eTypeString , false, 0 , NULL, NULL, "The first argument passed to the program in the argument array which can be different from the executable itself." },
+ { "run-args" , OptionValue::eTypeArgs , false, 0 , NULL, NULL, "A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0." },
+ { "env-vars" , OptionValue::eTypeDictionary, false, OptionValue::eTypeString , NULL, NULL, "A list of all the environment variables to be passed to the executable's environment, and their values." },
+ { "inherit-env" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Inherit the environment from the process that is running LLDB." },
+ { "input-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for reading its standard input." },
+ { "output-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard output." },
+ { "error-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard error." },
+ { "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. "
+ "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 "
+ "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." },
+ { "use-hex-immediates" , OptionValue::eTypeBoolean , false, true, NULL, NULL, "Show immediates in disassembly as hexadecimal." },
+ { "hex-immediate-style" , OptionValue::eTypeEnum , false, Disassembler::eHexStyleC, NULL, g_hex_immediate_style_values, "Which style to use for printing hexadecimal disassembly values." },
+ { "use-fast-stepping" , OptionValue::eTypeBoolean , false, true, NULL, NULL, "Use a fast stepping algorithm based on running from branch to branch rather than instruction single-stepping." },
+ { "load-script-from-symbol-file" , OptionValue::eTypeEnum , false, eLoadScriptFromSymFileWarn, NULL, g_load_script_from_sym_file_values, "Allow LLDB to load scripting resources embedded in symbol files when available." },
+ { "memory-module-load-level" , OptionValue::eTypeEnum , false, eMemoryModuleLoadLevelComplete, NULL, g_memory_module_load_level_values,
+ "Loading modules from memory can be slow as reading the symbol tables and other data can take a long time depending on your connection to the debug target. "
+ "This setting helps users control how much information gets loaded when loading modules from memory."
+ "'complete' is the default value for this setting which will load all sections and symbols by reading them from memory (slowest, most accurate). "
+ "'partial' will load sections and attempt to find function bounds without downloading the symbol table (faster, still accurate, missing symbol names). "
+ "'minimal' is the fastest setting and will load section data with no symbols, but should rarely be used as stack frames in these memory regions will be inaccurate and not provide any context (fastest). " },
+ { NULL , OptionValue::eTypeInvalid , false, 0 , NULL, NULL, NULL }
+};
+enum
+{
+ ePropertyDefaultArch,
+ ePropertyExprPrefix,
+ ePropertyPreferDynamic,
+ ePropertyEnableSynthetic,
+ ePropertySkipPrologue,
+ ePropertySourceMap,
+ ePropertyExecutableSearchPaths,
+ ePropertyDebugFileSearchPaths,
+ ePropertyMaxChildrenCount,
+ ePropertyMaxSummaryLength,
+ ePropertyMaxMemReadSize,
+ ePropertyBreakpointUseAvoidList,
+ ePropertyArg0,
+ ePropertyRunArgs,
+ ePropertyEnvVars,
+ ePropertyInheritEnv,
+ ePropertyInputPath,
+ ePropertyOutputPath,
+ ePropertyErrorPath,
+ ePropertyDisableASLR,
+ ePropertyDisableSTDIO,
+ ePropertyInlineStrategy,
+ ePropertyDisassemblyFlavor,
+ ePropertyUseHexImmediates,
+ ePropertyHexImmediateStyle,
+ ePropertyUseFastStepping,
+ ePropertyLoadScriptFromSymbolFile,
+ ePropertyMemoryModuleLoadLevel
+};
+
+
+class TargetOptionValueProperties : public OptionValueProperties
+{
+public:
+ TargetOptionValueProperties (const ConstString &name) :
+ OptionValueProperties (name),
+ m_target (NULL),
+ m_got_host_env (false)
+ {
+ }
+
+ // This constructor is used when creating TargetOptionValueProperties when it
+ // is part of a new lldb_private::Target instance. It will copy all current
+ // global property values as needed
+ TargetOptionValueProperties (Target *target, const TargetPropertiesSP &target_properties_sp) :
+ OptionValueProperties(*target_properties_sp->GetValueProperties()),
+ m_target (target),
+ m_got_host_env (false)
+ {
+ }
+
+ virtual const Property *
+ GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+ {
+ // When gettings the value for a key from the target options, we will always
+ // try and grab the setting from the current target if there is one. Else we just
+ // use the one from this instance.
+ if (idx == ePropertyEnvVars)
+ GetHostEnvironmentIfNeeded ();
+
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ TargetOptionValueProperties *target_properties = static_cast<TargetOptionValueProperties *>(target->GetValueProperties().get());
+ if (this != target_properties)
+ return target_properties->ProtectedGetPropertyAtIndex (idx);
+ }
+ }
+ return ProtectedGetPropertyAtIndex (idx);
+ }
+
+ lldb::TargetSP
+ GetTargetSP ()
+ {
+ return m_target->shared_from_this();
+ }
+
+protected:
+
+ void
+ GetHostEnvironmentIfNeeded () const
+ {
+ if (!m_got_host_env)
+ {
+ if (m_target)
+ {
+ m_got_host_env = true;
+ const uint32_t idx = ePropertyInheritEnv;
+ if (GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0))
+ {
+ PlatformSP platform_sp (m_target->GetPlatform());
+ if (platform_sp)
+ {
+ StringList env;
+ if (platform_sp->GetEnvironment(env))
+ {
+ OptionValueDictionary *env_dict = GetPropertyAtIndexAsOptionValueDictionary (NULL, ePropertyEnvVars);
+ if (env_dict)
+ {
+ const bool can_replace = false;
+ const size_t envc = env.GetSize();
+ for (size_t idx=0; idx<envc; idx++)
+ {
+ const char *env_entry = env.GetStringAtIndex (idx);
+ if (env_entry)
+ {
+ const char *equal_pos = ::strchr(env_entry, '=');
+ ConstString key;
+ // It is ok to have environment variables with no values
+ const char *value = NULL;
+ if (equal_pos)
+ {
+ key.SetCStringWithLength(env_entry, equal_pos - env_entry);
+ if (equal_pos[1])
+ value = equal_pos + 1;
+ }
+ else
+ {
+ key.SetCString(env_entry);
+ }
+ // Don't allow existing keys to be replaced with ones we get from the platform environment
+ env_dict->SetValueForKey(key, OptionValueSP(new OptionValueString(value)), can_replace);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Target *m_target;
+ mutable bool m_got_host_env;
+};
+
+TargetProperties::TargetProperties (Target *target) :
+ Properties ()
+{
+ if (target)
+ {
+ m_collection_sp.reset (new TargetOptionValueProperties(target, Target::GetGlobalProperties()));
+ }
+ else
+ {
+ m_collection_sp.reset (new TargetOptionValueProperties(ConstString("target")));
+ m_collection_sp->Initialize(g_properties);
+ m_collection_sp->AppendProperty(ConstString("process"),
+ ConstString("Settings specify to processes."),
+ true,
+ Process::GetGlobalProperties()->GetValueProperties());
+ }
+}
+
+TargetProperties::~TargetProperties ()
+{
+}
+ArchSpec
+TargetProperties::GetDefaultArchitecture () const
+{
+ OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch (NULL, ePropertyDefaultArch);
+ if (value)
+ return value->GetCurrentValue();
+ return ArchSpec();
+}
+
+void
+TargetProperties::SetDefaultArchitecture (const ArchSpec& arch)
+{
+ OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch (NULL, ePropertyDefaultArch);
+ if (value)
+ return value->SetCurrentValue(arch, true);
+}
+
+lldb::DynamicValueType
+TargetProperties::GetPreferDynamicValue() const
+{
+ const uint32_t idx = ePropertyPreferDynamic;
+ return (lldb::DynamicValueType)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+bool
+TargetProperties::GetDisableASLR () const
+{
+ const uint32_t idx = ePropertyDisableASLR;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+TargetProperties::SetDisableASLR (bool b)
+{
+ const uint32_t idx = ePropertyDisableASLR;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
+TargetProperties::GetDisableSTDIO () const
+{
+ const uint32_t idx = ePropertyDisableSTDIO;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+TargetProperties::SetDisableSTDIO (bool b)
+{
+ const uint32_t idx = ePropertyDisableSTDIO;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+const char *
+TargetProperties::GetDisassemblyFlavor () const
+{
+ const uint32_t idx = ePropertyDisassemblyFlavor;
+ const char *return_value;
+
+ x86DisassemblyFlavor flavor_value = (x86DisassemblyFlavor) m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+ return_value = g_x86_dis_flavor_value_types[flavor_value].string_value;
+ return return_value;
+}
+
+InlineStrategy
+TargetProperties::GetInlineStrategy () const
+{
+ const uint32_t idx = ePropertyInlineStrategy;
+ return (InlineStrategy)m_collection_sp->GetPropertyAtIndexAsEnumeration (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+const char *
+TargetProperties::GetArg0 () const
+{
+ const uint32_t idx = ePropertyArg0;
+ return m_collection_sp->GetPropertyAtIndexAsString (NULL, idx, NULL);
+}
+
+void
+TargetProperties::SetArg0 (const char *arg)
+{
+ const uint32_t idx = ePropertyArg0;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, arg);
+}
+
+bool
+TargetProperties::GetRunArguments (Args &args) const
+{
+ const uint32_t idx = ePropertyRunArgs;
+ return m_collection_sp->GetPropertyAtIndexAsArgs (NULL, idx, args);
+}
+
+void
+TargetProperties::SetRunArguments (const Args &args)
+{
+ const uint32_t idx = ePropertyRunArgs;
+ m_collection_sp->SetPropertyAtIndexFromArgs (NULL, idx, args);
+}
+
+size_t
+TargetProperties::GetEnvironmentAsArgs (Args &env) const
+{
+ const uint32_t idx = ePropertyEnvVars;
+ return m_collection_sp->GetPropertyAtIndexAsArgs (NULL, idx, env);
+}
+
+bool
+TargetProperties::GetSkipPrologue() const
+{
+ const uint32_t idx = ePropertySkipPrologue;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+PathMappingList &
+TargetProperties::GetSourcePathMap () const
+{
+ const uint32_t idx = ePropertySourceMap;
+ OptionValuePathMappings *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings (NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+}
+
+FileSpecList &
+TargetProperties::GetExecutableSearchPaths ()
+{
+ const uint32_t idx = ePropertyExecutableSearchPaths;
+ OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+}
+
+FileSpecList &
+TargetProperties::GetDebugFileSearchPaths ()
+{
+ const uint32_t idx = ePropertyDebugFileSearchPaths;
+ OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList (NULL, false, idx);
+ assert(option_value);
+ return option_value->GetCurrentValue();
+}
+
+bool
+TargetProperties::GetEnableSyntheticValue () const
+{
+ const uint32_t idx = ePropertyEnableSynthetic;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+uint32_t
+TargetProperties::GetMaximumNumberOfChildrenToDisplay() const
+{
+ const uint32_t idx = ePropertyMaxChildrenCount;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+uint32_t
+TargetProperties::GetMaximumSizeOfStringSummary() const
+{
+ const uint32_t idx = ePropertyMaxSummaryLength;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+uint32_t
+TargetProperties::GetMaximumMemReadSize () const
+{
+ const uint32_t idx = ePropertyMaxMemReadSize;
+ return m_collection_sp->GetPropertyAtIndexAsSInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
+FileSpec
+TargetProperties::GetStandardInputPath () const
+{
+ const uint32_t idx = ePropertyInputPath;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx);
+}
+
+void
+TargetProperties::SetStandardInputPath (const char *p)
+{
+ const uint32_t idx = ePropertyInputPath;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p);
+}
+
+FileSpec
+TargetProperties::GetStandardOutputPath () const
+{
+ const uint32_t idx = ePropertyOutputPath;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx);
+}
+
+void
+TargetProperties::SetStandardOutputPath (const char *p)
+{
+ const uint32_t idx = ePropertyOutputPath;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p);
+}
+
+FileSpec
+TargetProperties::GetStandardErrorPath () const
+{
+ const uint32_t idx = ePropertyErrorPath;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx);
+}
+
+const char *
+TargetProperties::GetExpressionPrefixContentsAsCString ()
+{
+ const uint32_t idx = ePropertyExprPrefix;
+ OptionValueFileSpec *file = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec (NULL, false, idx);
+ if (file)
+ {
+ const bool null_terminate = true;
+ DataBufferSP data_sp(file->GetFileContents(null_terminate));
+ if (data_sp)
+ return (const char *) data_sp->GetBytes();
+ }
+ return NULL;
+}
+
+void
+TargetProperties::SetStandardErrorPath (const char *p)
+{
+ const uint32_t idx = ePropertyErrorPath;
+ m_collection_sp->SetPropertyAtIndexAsString (NULL, idx, p);
+}
+
+bool
+TargetProperties::GetBreakpointsConsultPlatformAvoidList ()
+{
+ const uint32_t idx = ePropertyBreakpointUseAvoidList;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+TargetProperties::GetUseHexImmediates () const
+{
+ const uint32_t idx = ePropertyUseHexImmediates;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+TargetProperties::GetUseFastStepping () const
+{
+ const uint32_t idx = ePropertyUseFastStepping;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+LoadScriptFromSymFile
+TargetProperties::GetLoadScriptFromSymbolFile () const
+{
+ const uint32_t idx = ePropertyLoadScriptFromSymbolFile;
+ return (LoadScriptFromSymFile)m_collection_sp->GetPropertyAtIndexAsEnumeration(NULL, idx, g_properties[idx].default_uint_value);
+}
+
+Disassembler::HexImmediateStyle
+TargetProperties::GetHexImmediateStyle () const
+{
+ const uint32_t idx = ePropertyHexImmediateStyle;
+ return (Disassembler::HexImmediateStyle)m_collection_sp->GetPropertyAtIndexAsEnumeration(NULL, idx, g_properties[idx].default_uint_value);
+}
+
+MemoryModuleLoadLevel
+TargetProperties::GetMemoryModuleLoadLevel() const
+{
+ const uint32_t idx = ePropertyMemoryModuleLoadLevel;
+ return (MemoryModuleLoadLevel)m_collection_sp->GetPropertyAtIndexAsEnumeration(NULL, idx, g_properties[idx].default_uint_value);
+}
+
+
+const TargetPropertiesSP &
+Target::GetGlobalProperties()
+{
+ static TargetPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ {
+ g_settings_sp.reset (new TargetProperties (NULL));
+ }
+ return g_settings_sp;
+}
+
+const ConstString &
+Target::TargetEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Target::TargetEventData");
+ return g_flavor;
+}
+
+const ConstString &
+Target::TargetEventData::GetFlavor () const
+{
+ return TargetEventData::GetFlavorString ();
+}
+
+Target::TargetEventData::TargetEventData (const lldb::TargetSP &new_target_sp) :
+ EventData(),
+ m_target_sp (new_target_sp)
+{
+}
+
+Target::TargetEventData::~TargetEventData()
+{
+
+}
+
+void
+Target::TargetEventData::Dump (Stream *s) const
+{
+
+}
+
+const TargetSP
+Target::TargetEventData::GetTargetFromEvent (const lldb::EventSP &event_sp)
+{
+ TargetSP target_sp;
+
+ const TargetEventData *data = GetEventDataFromEvent (event_sp.get());
+ if (data)
+ target_sp = data->m_target_sp;
+
+ return target_sp;
+}
+
+const Target::TargetEventData *
+Target::TargetEventData::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == TargetEventData::GetFlavorString())
+ return static_cast <const TargetEventData *> (event_ptr->GetData());
+ }
+ return NULL;
+}
+
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
new file mode 100644
index 000000000000..8d907f432697
--- /dev/null
+++ b/source/Target/TargetList.cpp
@@ -0,0 +1,576 @@
+//===-- TargetList.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"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Event.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/TargetList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ConstString &
+TargetList::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.targetList");
+ return class_name;
+}
+
+//----------------------------------------------------------------------
+// TargetList constructor
+//----------------------------------------------------------------------
+TargetList::TargetList(Debugger &debugger) :
+ Broadcaster(&debugger, TargetList::GetStaticBroadcasterClass().AsCString()),
+ m_target_list(),
+ m_target_list_mutex (Mutex::eMutexTypeRecursive),
+ m_selected_target_idx (0)
+{
+ CheckInWithManager();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+TargetList::~TargetList()
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ m_target_list.clear();
+}
+
+Error
+TargetList::CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const char *triple_cstr,
+ bool get_dependent_files,
+ const OptionGroupPlatform *platform_options,
+ TargetSP &target_sp)
+{
+ Error error;
+ PlatformSP platform_sp;
+
+ // This is purposely left empty unless it is specified by triple_cstr.
+ // If not initialized via triple_cstr, then the currently selected platform
+ // will set the architecture correctly.
+ const ArchSpec arch(triple_cstr);
+ if (triple_cstr && triple_cstr[0])
+ {
+ if (!arch.IsValid())
+ {
+ error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr);
+ return error;
+ }
+ }
+
+ ArchSpec platform_arch(arch);
+
+
+ if (user_exe_path && user_exe_path[0])
+ {
+ ModuleSpecList module_specs;
+ ModuleSpec module_spec;
+ module_spec.GetFileSpec().SetFile(user_exe_path, true);
+ lldb::offset_t file_offset = 0;
+ lldb::offset_t file_size = 0;
+ const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs);
+ if (num_specs > 0)
+ {
+ ModuleSpec matching_module_spec;
+
+ if (num_specs == 1)
+ {
+ if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec))
+ {
+ if (platform_arch.IsValid())
+ {
+ if (!platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture()))
+ {
+ error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'",
+ platform_arch.GetTriple().str().c_str(),
+ matching_module_spec.GetArchitecture().GetTriple().str().c_str(),
+ module_spec.GetFileSpec().GetPath().c_str());
+ return error;
+ }
+ }
+ else
+ {
+ // Only one arch and none was specified
+ platform_arch = matching_module_spec.GetArchitecture();
+ }
+ }
+ }
+ else
+ {
+ if (arch.IsValid())
+ {
+ module_spec.GetArchitecture() = arch;
+ if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec))
+ {
+ platform_arch = matching_module_spec.GetArchitecture();
+ }
+ }
+ // Don't just select the first architecture, we want to let the platform select
+ // the best architecture first when there are multiple archs.
+// else
+// {
+// // No arch specified, select the first arch
+// if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec))
+// {
+// platform_arch = matching_module_spec.GetArchitecture();
+// }
+// }
+ }
+ }
+ }
+
+ CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
+ if (platform_options)
+ {
+ if (platform_options->PlatformWasSpecified ())
+ {
+ const bool select_platform = true;
+ platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
+ arch,
+ select_platform,
+ error,
+ platform_arch);
+ if (!platform_sp)
+ return error;
+ }
+ }
+
+ if (!platform_sp)
+ {
+ // Get the current platform and make sure it is compatible with the
+ // current architecture if we have a valid architecture.
+ platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
+
+ if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ {
+ platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ }
+ }
+
+ if (!platform_arch.IsValid())
+ platform_arch = arch;
+
+ error = TargetList::CreateTarget (debugger,
+ user_exe_path,
+ platform_arch,
+ get_dependent_files,
+ platform_sp,
+ target_sp);
+ return error;
+}
+
+Error
+TargetList::CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& specified_arch,
+ bool get_dependent_files,
+ PlatformSP &platform_sp,
+ TargetSP &target_sp)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "TargetList::CreateTarget (file = '%s', arch = '%s')",
+ user_exe_path,
+ specified_arch.GetArchitectureName());
+ Error error;
+
+ ArchSpec arch(specified_arch);
+
+ if (platform_sp)
+ {
+ if (arch.IsValid())
+ {
+ if (!platform_sp->IsCompatibleArchitecture(arch, false, NULL))
+ platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
+ }
+ }
+ else if (arch.IsValid())
+ {
+ platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
+ }
+
+ if (!platform_sp)
+ platform_sp = debugger.GetPlatformList().GetSelectedPlatform();
+
+ if (!arch.IsValid())
+ arch = specified_arch;
+
+ FileSpec file (user_exe_path, false);
+ if (!file.Exists() && user_exe_path && user_exe_path[0] == '~')
+ {
+ // we want to expand the tilde but we don't want to resolve any symbolic links
+ // so we can't use the FileSpec constructor's resolve flag
+ char unglobbed_path[PATH_MAX];
+ unglobbed_path[0] = '\0';
+
+ size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path));
+
+ if (return_count == 0 || return_count >= sizeof(unglobbed_path))
+ ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path);
+
+ file = FileSpec(unglobbed_path, false);
+ }
+
+ bool user_exe_path_is_bundle = false;
+ char resolved_bundle_exe_path[PATH_MAX];
+ resolved_bundle_exe_path[0] = '\0';
+ if (file)
+ {
+ if (file.GetFileType() == FileSpec::eFileTypeDirectory)
+ user_exe_path_is_bundle = true;
+
+ if (file.IsRelativeToCurrentWorkingDirectory())
+ {
+ // Ignore paths that start with "./" and "../"
+ if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
+ (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/')))
+ {
+ char cwd[PATH_MAX];
+ if (getcwd (cwd, sizeof(cwd)))
+ {
+ std::string cwd_user_exe_path (cwd);
+ cwd_user_exe_path += '/';
+ cwd_user_exe_path += user_exe_path;
+ FileSpec cwd_file (cwd_user_exe_path.c_str(), false);
+ if (cwd_file.Exists())
+ file = cwd_file;
+ }
+ }
+ }
+
+ ModuleSP exe_module_sp;
+ if (platform_sp)
+ {
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ error = platform_sp->ResolveExecutable (file,
+ arch,
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ }
+
+ if (error.Success() && exe_module_sp)
+ {
+ if (exe_module_sp->GetObjectFile() == NULL)
+ {
+ if (arch.IsValid())
+ {
+ error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s",
+ file.GetPath().c_str(),
+ arch.GetArchitectureName());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("unsupported file type \"%s\"",
+ file.GetPath().c_str());
+ }
+ return error;
+ }
+ target_sp.reset(new Target(debugger, arch, platform_sp));
+ 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));
+ }
+ }
+ else
+ {
+ // 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));
+ }
+
+ if (target_sp)
+ {
+ // Set argv0 with what the user typed, unless the user specified a
+ // directory. If the user specified a directory, then it is probably a
+ // bundle that was resolved and we need to use the resolved bundle path
+ if (user_exe_path)
+ {
+ // Use exactly what the user typed as the first argument when we exec or posix_spawn
+ if (user_exe_path_is_bundle && resolved_bundle_exe_path[0])
+ {
+ target_sp->SetArg0 (resolved_bundle_exe_path);
+ }
+ else
+ {
+ // Use resolved path
+ target_sp->SetArg0 (file.GetPath().c_str());
+ }
+ }
+ if (file.GetDirectory())
+ {
+ FileSpec file_dir;
+ 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);
+
+
+ }
+
+ return error;
+}
+
+bool
+TargetList::DeleteTarget (TargetSP &target_sp)
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::iterator pos, end = m_target_list.end();
+
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (pos->get() == target_sp.get())
+ {
+ m_target_list.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+
+TargetSP
+TargetList::FindTargetWithExecutableAndArchitecture
+(
+ const FileSpec &exe_file_spec,
+ const ArchSpec *exe_arch_ptr
+) const
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ TargetSP target_sp;
+ bool full_match = exe_file_spec.GetDirectory();
+
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ Module *exe_module = (*pos)->GetExecutableModulePointer();
+
+ if (exe_module)
+ {
+ if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match))
+ {
+ if (exe_arch_ptr)
+ {
+ if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture()))
+ continue;
+ }
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+TargetList::FindTargetWithProcessID (lldb::pid_t pid) const
+{
+ Mutex::Locker locker(m_target_list_mutex);
+ TargetSP target_sp;
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ Process* process = (*pos)->GetProcessSP().get();
+ if (process && process->GetID() == pid)
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ return target_sp;
+}
+
+
+TargetSP
+TargetList::FindTargetWithProcess (Process *process) const
+{
+ TargetSP target_sp;
+ if (process)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (process == (*pos)->GetProcessSP().get())
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+TargetSP
+TargetList::GetTargetSP (Target *target) const
+{
+ TargetSP target_sp;
+ if (target)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::const_iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ if (target == (*pos).get())
+ {
+ target_sp = *pos;
+ break;
+ }
+ }
+ }
+ return target_sp;
+}
+
+uint32_t
+TargetList::SendAsyncInterrupt (lldb::pid_t pid)
+{
+ uint32_t num_async_interrupts_sent = 0;
+
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ TargetSP target_sp(FindTargetWithProcessID (pid));
+ if (target_sp.get())
+ {
+ Process* process = target_sp->GetProcessSP().get();
+ if (process)
+ {
+ process->SendAsyncInterrupt();
+ ++num_async_interrupts_sent;
+ }
+ }
+ }
+ else
+ {
+ // We don't have a valid pid to broadcast to, so broadcast to the target
+ // list's async broadcaster...
+ BroadcastEvent (Process::eBroadcastBitInterrupt, NULL);
+ }
+
+ return num_async_interrupts_sent;
+}
+
+uint32_t
+TargetList::SignalIfRunning (lldb::pid_t pid, int signo)
+{
+ uint32_t num_signals_sent = 0;
+ Process *process = NULL;
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // Signal all processes with signal
+ Mutex::Locker locker(m_target_list_mutex);
+ collection::iterator pos, end = m_target_list.end();
+ for (pos = m_target_list.begin(); pos != end; ++pos)
+ {
+ process = (*pos)->GetProcessSP().get();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ ++num_signals_sent;
+ process->Signal (signo);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Signal a specific process with signal
+ TargetSP target_sp(FindTargetWithProcessID (pid));
+ if (target_sp.get())
+ {
+ process = target_sp->GetProcessSP().get();
+ if (process)
+ {
+ if (process->IsAlive())
+ {
+ ++num_signals_sent;
+ process->Signal (signo);
+ }
+ }
+ }
+ }
+ return num_signals_sent;
+}
+
+int
+TargetList::GetNumTargets () const
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ return m_target_list.size();
+}
+
+lldb::TargetSP
+TargetList::GetTargetAtIndex (uint32_t idx) const
+{
+ TargetSP target_sp;
+ Mutex::Locker locker (m_target_list_mutex);
+ if (idx < m_target_list.size())
+ target_sp = m_target_list[idx];
+ return target_sp;
+}
+
+uint32_t
+TargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ size_t num_targets = m_target_list.size();
+ for (size_t idx = 0; idx < num_targets; idx++)
+ {
+ if (target_sp == m_target_list[idx])
+ return idx;
+ }
+ return UINT32_MAX;
+}
+
+uint32_t
+TargetList::SetSelectedTarget (Target* target)
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ collection::const_iterator pos,
+ begin = m_target_list.begin(),
+ end = m_target_list.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos->get() == target)
+ {
+ m_selected_target_idx = std::distance (begin, pos);
+ return m_selected_target_idx;
+ }
+ }
+ m_selected_target_idx = 0;
+ return m_selected_target_idx;
+}
+
+lldb::TargetSP
+TargetList::GetSelectedTarget ()
+{
+ Mutex::Locker locker (m_target_list_mutex);
+ if (m_selected_target_idx >= m_target_list.size())
+ m_selected_target_idx = 0;
+ return GetTargetAtIndex (m_selected_target_idx);
+}
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
new file mode 100644
index 000000000000..b65434bf9482
--- /dev/null
+++ b/source/Target/Thread.cpp
@@ -0,0 +1,1988 @@
+//===-- Thread.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/lldb-private-log.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+#include "lldb/Target/ThreadPlanStepOverRange.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Target/ThreadPlanStepUntil.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/UnwindLLDB.h"
+#include "UnwindMacOSXFrameBackchain.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+const ThreadPropertiesSP &
+Thread::GetGlobalProperties()
+{
+ static ThreadPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new ThreadProperties (true));
+ return g_settings_sp;
+}
+
+static PropertyDefinition
+g_properties[] =
+{
+ { "step-avoid-regexp", OptionValue::eTypeRegex , true , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." },
+ { "trace-thread", OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." },
+ { NULL , OptionValue::eTypeInvalid, false, 0 , NULL, NULL, NULL }
+};
+
+enum {
+ ePropertyStepAvoidRegex,
+ ePropertyEnableThreadTrace
+};
+
+
+class ThreadOptionValueProperties : public OptionValueProperties
+{
+public:
+ ThreadOptionValueProperties (const ConstString &name) :
+ OptionValueProperties (name)
+ {
+ }
+
+ // This constructor is used when creating ThreadOptionValueProperties when it
+ // is part of a new lldb_private::Thread instance. It will copy all current
+ // global property values as needed
+ ThreadOptionValueProperties (ThreadProperties *global_properties) :
+ OptionValueProperties(*global_properties->GetValueProperties())
+ {
+ }
+
+ virtual const Property *
+ GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
+ {
+ // When gettings the value for a key from the thread options, we will always
+ // try and grab the setting from the current thread if there is one. Else we just
+ // use the one from this instance.
+ if (exe_ctx)
+ {
+ Thread *thread = exe_ctx->GetThreadPtr();
+ if (thread)
+ {
+ ThreadOptionValueProperties *instance_properties = static_cast<ThreadOptionValueProperties *>(thread->GetValueProperties().get());
+ if (this != instance_properties)
+ return instance_properties->ProtectedGetPropertyAtIndex (idx);
+ }
+ }
+ return ProtectedGetPropertyAtIndex (idx);
+ }
+};
+
+
+
+ThreadProperties::ThreadProperties (bool is_global) :
+ Properties ()
+{
+ if (is_global)
+ {
+ m_collection_sp.reset (new ThreadOptionValueProperties(ConstString("thread")));
+ m_collection_sp->Initialize(g_properties);
+ }
+ else
+ m_collection_sp.reset (new ThreadOptionValueProperties(Thread::GetGlobalProperties().get()));
+}
+
+ThreadProperties::~ThreadProperties()
+{
+}
+
+const RegularExpression *
+ThreadProperties::GetSymbolsToAvoidRegexp()
+{
+ const uint32_t idx = ePropertyStepAvoidRegex;
+ return m_collection_sp->GetPropertyAtIndexAsOptionValueRegex (NULL, idx);
+}
+
+bool
+ThreadProperties::GetTraceEnabledState() const
+{
+ const uint32_t idx = ePropertyEnableThreadTrace;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+//------------------------------------------------------------------
+// Thread Event Data
+//------------------------------------------------------------------
+
+
+const ConstString &
+Thread::ThreadEventData::GetFlavorString ()
+{
+ static ConstString g_flavor ("Thread::ThreadEventData");
+ return g_flavor;
+}
+
+Thread::ThreadEventData::ThreadEventData (const lldb::ThreadSP thread_sp) :
+ m_thread_sp (thread_sp),
+ m_stack_id ()
+{
+}
+
+Thread::ThreadEventData::ThreadEventData (const lldb::ThreadSP thread_sp, const StackID &stack_id) :
+ m_thread_sp (thread_sp),
+ m_stack_id (stack_id)
+{
+}
+
+Thread::ThreadEventData::ThreadEventData () :
+ m_thread_sp (),
+ m_stack_id ()
+{
+}
+
+Thread::ThreadEventData::~ThreadEventData ()
+{
+}
+
+void
+Thread::ThreadEventData::Dump (Stream *s) const
+{
+
+}
+
+const Thread::ThreadEventData *
+Thread::ThreadEventData::GetEventDataFromEvent (const Event *event_ptr)
+{
+ if (event_ptr)
+ {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data && event_data->GetFlavor() == ThreadEventData::GetFlavorString())
+ return static_cast <const ThreadEventData *> (event_ptr->GetData());
+ }
+ return NULL;
+}
+
+ThreadSP
+Thread::ThreadEventData::GetThreadFromEvent (const Event *event_ptr)
+{
+ ThreadSP thread_sp;
+ const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr);
+ if (event_data)
+ thread_sp = event_data->GetThread();
+ return thread_sp;
+}
+
+StackID
+Thread::ThreadEventData::GetStackIDFromEvent (const Event *event_ptr)
+{
+ StackID stack_id;
+ const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr);
+ if (event_data)
+ stack_id = event_data->GetStackID();
+ return stack_id;
+}
+
+StackFrameSP
+Thread::ThreadEventData::GetStackFrameFromEvent (const Event *event_ptr)
+{
+ const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr);
+ StackFrameSP frame_sp;
+ if (event_data)
+ {
+ ThreadSP thread_sp = event_data->GetThread();
+ if (thread_sp)
+ {
+ frame_sp = thread_sp->GetStackFrameList()->GetFrameWithStackID (event_data->GetStackID());
+ }
+ }
+ return frame_sp;
+}
+
+//------------------------------------------------------------------
+// Thread class
+//------------------------------------------------------------------
+
+ConstString &
+Thread::GetStaticBroadcasterClass ()
+{
+ static ConstString class_name ("lldb.thread");
+ return class_name;
+}
+
+Thread::Thread (Process &process, lldb::tid_t tid) :
+ ThreadProperties (false),
+ UserID (tid),
+ Broadcaster(&process.GetTarget().GetDebugger(), Thread::GetStaticBroadcasterClass().AsCString()),
+ m_process_wp (process.shared_from_this()),
+ m_stop_info_sp (),
+ m_stop_info_stop_id (0),
+ m_index_id (process.GetNextThreadIndexID(tid)),
+ m_reg_context_sp (),
+ m_state (eStateUnloaded),
+ m_state_mutex (Mutex::eMutexTypeRecursive),
+ m_plan_stack (),
+ m_completed_plan_stack(),
+ m_frame_mutex (Mutex::eMutexTypeRecursive),
+ m_curr_frames_sp (),
+ m_prev_frames_sp (),
+ m_resume_signal (LLDB_INVALID_SIGNAL_NUMBER),
+ m_resume_state (eStateRunning),
+ m_temporary_resume_state (eStateRunning),
+ m_unwinder_ap (),
+ m_destroy_called (false),
+ m_override_should_notify (eLazyBoolCalculate)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", this, GetID());
+
+ CheckInWithManager();
+ QueueFundamentalPlan(true);
+}
+
+
+Thread::~Thread()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", this, GetID());
+ /// If you hit this assert, it means your derived class forgot to call DoDestroy in its destructor.
+ assert (m_destroy_called);
+}
+
+void
+Thread::DestroyThread ()
+{
+ // Tell any plans on the plan stack that the thread is being destroyed since
+ // any active plans that have a thread go away in the middle of might need
+ // to do cleanup.
+ for (auto plan : m_plan_stack)
+ plan->ThreadDestroyed();
+
+ m_destroy_called = true;
+ m_plan_stack.clear();
+ m_discarded_plan_stack.clear();
+ m_completed_plan_stack.clear();
+
+ // Push a ThreadPlanNull on the plan stack. That way we can continue assuming that the
+ // plan stack is never empty, but if somebody errantly asks questions of a destroyed thread
+ // without checking first whether it is destroyed, they won't crash.
+ ThreadPlanSP null_plan_sp(new ThreadPlanNull (*this));
+ m_plan_stack.push_back (null_plan_sp);
+
+ m_stop_info_sp.reset();
+ m_reg_context_sp.reset();
+ m_unwinder_ap.reset();
+ Mutex::Locker locker(m_frame_mutex);
+ m_curr_frames_sp.reset();
+ m_prev_frames_sp.reset();
+}
+
+void
+Thread::BroadcastSelectedFrameChange(StackID &new_frame_id)
+{
+ if (EventTypeHasListeners(eBroadcastBitSelectedFrameChanged))
+ BroadcastEvent(eBroadcastBitSelectedFrameChanged, new ThreadEventData (this->shared_from_this(), new_frame_id));
+}
+
+uint32_t
+Thread::SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast)
+{
+ uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame);
+ if (broadcast)
+ BroadcastSelectedFrameChange(frame->GetStackID());
+ return ret_value;
+}
+
+bool
+Thread::SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast)
+{
+ StackFrameSP frame_sp(GetStackFrameList()->GetFrameAtIndex (frame_idx));
+ if (frame_sp)
+ {
+ GetStackFrameList()->SetSelectedFrame(frame_sp.get());
+ if (broadcast)
+ BroadcastSelectedFrameChange(frame_sp->GetStackID());
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream)
+{
+ const bool broadcast = true;
+ bool success = SetSelectedFrameByIndex (frame_idx, broadcast);
+ if (success)
+ {
+ StackFrameSP frame_sp = GetSelectedFrame();
+ if (frame_sp)
+ {
+ bool already_shown = false;
+ SymbolContext frame_sc(frame_sp->GetSymbolContext(eSymbolContextLineEntry));
+ if (GetProcess()->GetTarget().GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0)
+ {
+ already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
+ }
+
+ bool show_frame_info = true;
+ bool show_source = !already_shown;
+ return frame_sp->GetStatus (output_stream, show_frame_info, show_source);
+ }
+ return false;
+ }
+ else
+ return false;
+}
+
+
+lldb::StopInfoSP
+Thread::GetStopInfo ()
+{
+ if (m_destroy_called)
+ return m_stop_info_sp;
+
+ ThreadPlanSP plan_sp (GetCompletedPlan());
+ ProcessSP process_sp (GetProcess());
+ const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
+ if (plan_sp && plan_sp->PlanSucceeded())
+ {
+ return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject());
+ }
+ else
+ {
+ if ((m_stop_info_stop_id == stop_id) || // Stop info is valid, just return what we have (even if empty)
+ (m_stop_info_sp && m_stop_info_sp->IsValid())) // Stop info is valid, just return what we have
+ {
+ return m_stop_info_sp;
+ }
+ else
+ {
+ GetPrivateStopInfo ();
+ return m_stop_info_sp;
+ }
+ }
+}
+
+lldb::StopInfoSP
+Thread::GetPrivateStopInfo ()
+{
+ if (m_destroy_called)
+ return m_stop_info_sp;
+
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ const uint32_t process_stop_id = process_sp->GetStopID();
+ if (m_stop_info_stop_id != process_stop_id)
+ {
+ if (m_stop_info_sp)
+ {
+ if (m_stop_info_sp->IsValid()
+ || IsStillAtLastBreakpointHit()
+ || GetCurrentPlan()->IsVirtualStep())
+ SetStopInfo (m_stop_info_sp);
+ else
+ m_stop_info_sp.reset();
+ }
+
+ if (!m_stop_info_sp)
+ {
+ if (CalculateStopInfo() == false)
+ SetStopInfo (StopInfoSP());
+ }
+ }
+ }
+ return m_stop_info_sp;
+}
+
+
+lldb::StopReason
+Thread::GetStopReason()
+{
+ lldb::StopInfoSP stop_info_sp (GetStopInfo ());
+ if (stop_info_sp)
+ return stop_info_sp->GetStopReason();
+ return eStopReasonNone;
+}
+
+
+
+void
+Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)
+{
+ m_stop_info_sp = stop_info_sp;
+ if (m_stop_info_sp)
+ {
+ m_stop_info_sp->MakeStopInfoValid();
+ // If we are overriding the ShouldReportStop, do that here:
+ if (m_override_should_notify != eLazyBoolCalculate)
+ m_stop_info_sp->OverrideShouldNotify (m_override_should_notify == eLazyBoolYes);
+ }
+
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ m_stop_info_stop_id = process_sp->GetStopID();
+ else
+ m_stop_info_stop_id = UINT32_MAX;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)\n", this, GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", m_stop_info_stop_id);
+}
+
+void
+Thread::SetShouldReportStop (Vote vote)
+{
+ if (vote == eVoteNoOpinion)
+ return;
+ else
+ {
+ m_override_should_notify = (vote == eVoteYes ? eLazyBoolYes : eLazyBoolNo);
+ if (m_stop_info_sp)
+ m_stop_info_sp->OverrideShouldNotify (m_override_should_notify == eLazyBoolYes);
+ }
+}
+
+void
+Thread::SetStopInfoToNothing()
+{
+ // Note, we can't just NULL out the private reason, or the native thread implementation will try to
+ // go calculate it again. For now, just set it to a Unix Signal with an invalid signal number.
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal (*this, LLDB_INVALID_SIGNAL_NUMBER));
+}
+
+bool
+Thread::ThreadStoppedForAReason (void)
+{
+ return (bool) GetPrivateStopInfo ();
+}
+
+bool
+Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state)
+{
+ if (!SaveFrameZeroState(saved_state.register_backup))
+ return false;
+
+ saved_state.stop_info_sp = GetStopInfo();
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ saved_state.orig_stop_id = process_sp->GetStopID();
+ saved_state.current_inlined_depth = GetCurrentInlinedDepth();
+
+ return true;
+}
+
+bool
+Thread::RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state)
+{
+ RestoreSaveFrameZero(saved_state.register_backup);
+ return true;
+}
+
+bool
+Thread::RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state)
+{
+ if (saved_state.stop_info_sp)
+ saved_state.stop_info_sp->MakeStopInfoValid();
+ SetStopInfo(saved_state.stop_info_sp);
+ GetStackFrameList()->SetCurrentInlinedDepth (saved_state.current_inlined_depth);
+ return true;
+}
+
+StateType
+Thread::GetState() const
+{
+ // If any other threads access this we will need a mutex for it
+ Mutex::Locker locker(m_state_mutex);
+ return m_state;
+}
+
+void
+Thread::SetState(StateType state)
+{
+ Mutex::Locker locker(m_state_mutex);
+ m_state = state;
+}
+
+void
+Thread::WillStop()
+{
+ ThreadPlan *current_plan = GetCurrentPlan();
+
+ // FIXME: I may decide to disallow threads with no plans. In which
+ // case this should go to an assert.
+
+ if (!current_plan)
+ return;
+
+ current_plan->WillStop();
+}
+
+void
+Thread::SetupForResume ()
+{
+ if (GetResumeState() != eStateSuspended)
+ {
+
+ // If we're at a breakpoint push the step-over breakpoint plan. Do this before
+ // telling the current plan it will resume, since we might change what the current
+ // plan is.
+
+// StopReason stop_reason = lldb::eStopReasonInvalid;
+// StopInfoSP stop_info_sp = GetStopInfo();
+// if (stop_info_sp.get())
+// stop_reason = stop_info_sp->GetStopReason();
+// if (stop_reason == lldb::eStopReasonBreakpoint)
+ lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(reg_ctx_sp->GetPC());
+ if (bp_site_sp)
+ {
+ // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
+ // special to step over a breakpoint.
+
+ ThreadPlan *cur_plan = GetCurrentPlan();
+
+ if (cur_plan->GetKind() != ThreadPlan::eKindStepOverBreakpoint)
+ {
+ ThreadPlanStepOverBreakpoint *step_bp_plan = new ThreadPlanStepOverBreakpoint (*this);
+ if (step_bp_plan)
+ {
+ ThreadPlanSP step_bp_plan_sp;
+ step_bp_plan->SetPrivate (true);
+
+ if (GetCurrentPlan()->RunState() != eStateStepping)
+ {
+ step_bp_plan->SetAutoContinue(true);
+ }
+ step_bp_plan_sp.reset (step_bp_plan);
+ QueueThreadPlan (step_bp_plan_sp, false);
+ }
+ }
+ }
+ }
+ }
+}
+
+bool
+Thread::ShouldResume (StateType resume_state)
+{
+ // At this point clear the completed plan stack.
+ m_completed_plan_stack.clear();
+ m_discarded_plan_stack.clear();
+ m_override_should_notify = eLazyBoolCalculate;
+
+ m_temporary_resume_state = resume_state;
+
+ lldb::ThreadSP backing_thread_sp (GetBackingThread ());
+ if (backing_thread_sp)
+ backing_thread_sp->m_temporary_resume_state = resume_state;
+
+ // Make sure m_stop_info_sp is valid
+ GetPrivateStopInfo();
+
+ // This is a little dubious, but we are trying to limit how often we actually fetch stop info from
+ // the target, 'cause that slows down single stepping. So assume that if we got to the point where
+ // we're about to resume, and we haven't yet had to fetch the stop reason, then it doesn't need to know
+ // about the fact that we are resuming...
+ const uint32_t process_stop_id = GetProcess()->GetStopID();
+ if (m_stop_info_stop_id == process_stop_id &&
+ (m_stop_info_sp && m_stop_info_sp->IsValid()))
+ {
+ StopInfo *stop_info = GetPrivateStopInfo().get();
+ if (stop_info)
+ stop_info->WillResume (resume_state);
+ }
+
+ // Tell all the plans that we are about to resume in case they need to clear any state.
+ // We distinguish between the plan on the top of the stack and the lower
+ // plans in case a plan needs to do any special business before it runs.
+
+ bool need_to_resume = false;
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ if (plan_ptr)
+ {
+ need_to_resume = plan_ptr->WillResume(resume_state, true);
+
+ while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
+ {
+ plan_ptr->WillResume (resume_state, false);
+ }
+
+ // If the WillResume for the plan says we are faking a resume, then it will have set an appropriate stop info.
+ // In that case, don't reset it here.
+
+ if (need_to_resume && resume_state != eStateSuspended)
+ {
+ m_stop_info_sp.reset();
+ }
+ }
+
+ if (need_to_resume)
+ {
+ ClearStackFrames();
+ // Let Thread subclasses do any special work they need to prior to resuming
+ WillResume (resume_state);
+ }
+
+ return need_to_resume;
+}
+
+void
+Thread::DidResume ()
+{
+ SetResumeSignal (LLDB_INVALID_SIGNAL_NUMBER);
+}
+
+void
+Thread::DidStop ()
+{
+ SetState (eStateStopped);
+}
+
+bool
+Thread::ShouldStop (Event* event_ptr)
+{
+ ThreadPlan *current_plan = GetCurrentPlan();
+
+ bool should_stop = true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (GetResumeState () == eStateSuspended)
+ {
+ if (log)
+ log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)",
+ __FUNCTION__,
+ GetID (),
+ GetProtocolID());
+ return false;
+ }
+
+ if (GetTemporaryResumeState () == eStateSuspended)
+ {
+ if (log)
+ log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)",
+ __FUNCTION__,
+ GetID (),
+ GetProtocolID());
+ return false;
+ }
+
+ // Based on the current thread plan and process stop info, check if this
+ // thread caused the process to stop. NOTE: this must take place before
+ // the plan is moved from the current plan stack to the completed plan
+ // stack.
+ if (ThreadStoppedForAReason() == false)
+ {
+ if (log)
+ log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64 ", should_stop = 0 (ignore since no stop reason)",
+ __FUNCTION__,
+ GetID (),
+ GetProtocolID(),
+ GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);
+ return false;
+ }
+
+ if (log)
+ {
+ log->Printf ("Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64,
+ __FUNCTION__,
+ this,
+ GetID (),
+ GetProtocolID (),
+ GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);
+ log->Printf ("^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^");
+ StreamString s;
+ s.IndentMore();
+ DumpThreadPlans(&s);
+ log->Printf ("Plan stack initial state:\n%s", s.GetData());
+ }
+
+ // The top most plan always gets to do the trace log...
+ current_plan->DoTraceLog ();
+
+ // First query the stop info's ShouldStopSynchronous. This handles "synchronous" stop reasons, for example the breakpoint
+ // command on internal breakpoints. If a synchronous stop reason says we should not stop, then we don't have to
+ // do any more work on this stop.
+ StopInfoSP private_stop_info (GetPrivateStopInfo());
+ if (private_stop_info && private_stop_info->ShouldStopSynchronous(event_ptr) == false)
+ {
+ if (log)
+ log->Printf ("StopInfo::ShouldStop async callback says we should not stop, returning ShouldStop of false.");
+ return false;
+ }
+
+ // If we've already been restarted, don't query the plans since the state they would examine is not current.
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_ptr))
+ return false;
+
+ // Before the plans see the state of the world, calculate the current inlined depth.
+ GetStackFrameList()->CalculateCurrentInlinedDepth();
+
+ // If the base plan doesn't understand why we stopped, then we have to find a plan that does.
+ // If that plan is still working, then we don't need to do any more work. If the plan that explains
+ // the stop is done, then we should pop all the plans below it, and pop it, and then let the plans above it decide
+ // whether they still need to do more work.
+
+ bool done_processing_current_plan = false;
+
+ if (!current_plan->PlanExplainsStop(event_ptr))
+ {
+ if (current_plan->TracerExplainsStop())
+ {
+ done_processing_current_plan = true;
+ should_stop = false;
+ }
+ else
+ {
+ // If the current plan doesn't explain the stop, then find one that
+ // does and let it handle the situation.
+ ThreadPlan *plan_ptr = current_plan;
+ while ((plan_ptr = GetPreviousPlan(plan_ptr)) != NULL)
+ {
+ if (plan_ptr->PlanExplainsStop(event_ptr))
+ {
+ should_stop = plan_ptr->ShouldStop (event_ptr);
+
+ // plan_ptr explains the stop, next check whether plan_ptr is done, if so, then we should take it
+ // and all the plans below it off the stack.
+
+ if (plan_ptr->MischiefManaged())
+ {
+ // We're going to pop the plans up to and including the plan that explains the stop.
+ ThreadPlan *prev_plan_ptr = GetPreviousPlan (plan_ptr);
+
+ do
+ {
+ if (should_stop)
+ current_plan->WillStop();
+ PopPlan();
+ }
+ while ((current_plan = GetCurrentPlan()) != prev_plan_ptr);
+ // Now, if the responsible plan was not "Okay to discard" then we're done,
+ // otherwise we forward this to the next plan in the stack below.
+ if (plan_ptr->IsMasterPlan() && !plan_ptr->OkayToDiscard())
+ done_processing_current_plan = true;
+ else
+ done_processing_current_plan = false;
+ }
+ else
+ done_processing_current_plan = true;
+
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (!done_processing_current_plan)
+ {
+ bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr);
+
+ if (log)
+ log->Printf("Plan %s explains stop, auto-continue %i.", current_plan->GetName(), over_ride_stop);
+
+ // We're starting from the base plan, so just let it decide;
+ if (PlanIsBasePlan(current_plan))
+ {
+ should_stop = current_plan->ShouldStop (event_ptr);
+ if (log)
+ log->Printf("Base plan says should stop: %i.", should_stop);
+ }
+ else
+ {
+ // Otherwise, don't let the base plan override what the other plans say to do, since
+ // presumably if there were other plans they would know what to do...
+ while (1)
+ {
+ if (PlanIsBasePlan(current_plan))
+ break;
+
+ should_stop = current_plan->ShouldStop(event_ptr);
+ if (log)
+ log->Printf("Plan %s should stop: %d.", current_plan->GetName(), should_stop);
+ if (current_plan->MischiefManaged())
+ {
+ if (should_stop)
+ current_plan->WillStop();
+
+ // If a Master Plan wants to stop, and wants to stick on the stack, we let it.
+ // Otherwise, see if the plan's parent wants to stop.
+
+ if (should_stop && current_plan->IsMasterPlan() && !current_plan->OkayToDiscard())
+ {
+ PopPlan();
+ break;
+ }
+ else
+ {
+
+ PopPlan();
+
+ current_plan = GetCurrentPlan();
+ if (current_plan == NULL)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ 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.
+
+ if (should_stop)
+ {
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ while (!PlanIsBasePlan(plan_ptr))
+ {
+ bool stale = plan_ptr->IsPlanStale ();
+ ThreadPlan *examined_plan = plan_ptr;
+ plan_ptr = GetPreviousPlan (examined_plan);
+
+ if (stale)
+ {
+ if (log)
+ log->Printf("Plan %s being discarded in cleanup, it says it is already done.", examined_plan->GetName());
+ DiscardThreadPlansUpToPlan(examined_plan);
+ }
+ }
+ }
+
+ }
+
+ if (log)
+ {
+ StreamString s;
+ s.IndentMore();
+ DumpThreadPlans(&s);
+ log->Printf ("Plan stack final state:\n%s", s.GetData());
+ log->Printf ("vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv", should_stop);
+ }
+ return should_stop;
+}
+
+Vote
+Thread::ShouldReportStop (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+ StateType temp_thread_state = GetTemporaryResumeState();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (thread_state == eStateSuspended || thread_state == eStateInvalid)
+ {
+ if (log)
+ log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (state was suspended or invalid)", GetID(), eVoteNoOpinion);
+ return eVoteNoOpinion;
+ }
+
+ if (temp_thread_state == eStateSuspended || temp_thread_state == eStateInvalid)
+ {
+ if (log)
+ log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (temporary state was suspended or invalid)", GetID(), eVoteNoOpinion);
+ return eVoteNoOpinion;
+ }
+
+ if (!ThreadStoppedForAReason())
+ {
+ if (log)
+ log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (thread didn't stop for a reason.)", GetID(), eVoteNoOpinion);
+ return eVoteNoOpinion;
+ }
+
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (log)
+ log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote for complete stack's back plan", GetID());
+ return m_completed_plan_stack.back()->ShouldReportStop (event_ptr);
+ }
+ else
+ {
+ Vote thread_vote = eVoteNoOpinion;
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ while (1)
+ {
+ if (plan_ptr->PlanExplainsStop(event_ptr))
+ {
+ thread_vote = plan_ptr->ShouldReportStop(event_ptr);
+ break;
+ }
+ if (PlanIsBasePlan(plan_ptr))
+ break;
+ else
+ plan_ptr = GetPreviousPlan(plan_ptr);
+ }
+ if (log)
+ log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i for current plan", GetID(), thread_vote);
+
+ return thread_vote;
+ }
+}
+
+Vote
+Thread::ShouldReportRun (Event* event_ptr)
+{
+ StateType thread_state = GetResumeState ();
+
+ if (thread_state == eStateSuspended
+ || thread_state == eStateInvalid)
+ {
+ return eVoteNoOpinion;
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (m_completed_plan_stack.size() > 0)
+ {
+ // Don't use GetCompletedPlan here, since that suppresses private plans.
+ if (log)
+ log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.",
+ GetIndexID(),
+ this,
+ GetID(),
+ StateAsCString(GetTemporaryResumeState()),
+ m_completed_plan_stack.back()->GetName());
+
+ return m_completed_plan_stack.back()->ShouldReportRun (event_ptr);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.",
+ GetIndexID(),
+ this,
+ GetID(),
+ StateAsCString(GetTemporaryResumeState()),
+ GetCurrentPlan()->GetName());
+
+ return GetCurrentPlan()->ShouldReportRun (event_ptr);
+ }
+}
+
+bool
+Thread::MatchesSpec (const ThreadSpec *spec)
+{
+ if (spec == NULL)
+ return true;
+
+ return spec->ThreadPassesBasicTests(*this);
+}
+
+void
+Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
+{
+ if (thread_plan_sp)
+ {
+ // If the thread plan doesn't already have a tracer, give it its parent's tracer:
+ if (!thread_plan_sp->GetThreadPlanTracer())
+ thread_plan_sp->SetThreadPlanTracer(m_plan_stack.back()->GetThreadPlanTracer());
+ m_plan_stack.push_back (thread_plan_sp);
+
+ thread_plan_sp->DidPush();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ StreamString s;
+ thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
+ log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
+ this,
+ s.GetData(),
+ thread_plan_sp->GetThread().GetID());
+ }
+ }
+}
+
+void
+Thread::PopPlan ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (m_plan_stack.size() <= 1)
+ return;
+ else
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ if (log)
+ {
+ log->Printf("Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", plan->GetName(), plan->GetThread().GetID());
+ }
+ m_completed_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+void
+Thread::DiscardPlan ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (m_plan_stack.size() > 1)
+ {
+ ThreadPlanSP &plan = m_plan_stack.back();
+ if (log)
+ log->Printf("Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", plan->GetName(), plan->GetThread().GetID());
+
+ m_discarded_plan_stack.push_back (plan);
+ plan->WillPop();
+ m_plan_stack.pop_back();
+ }
+}
+
+ThreadPlan *
+Thread::GetCurrentPlan ()
+{
+ // There will always be at least the base plan. If somebody is mucking with a
+ // thread with an empty plan stack, we should assert right away.
+ if (m_plan_stack.empty())
+ return NULL;
+ return m_plan_stack.back().get();
+}
+
+ThreadPlanSP
+Thread::GetCompletedPlan ()
+{
+ ThreadPlanSP empty_plan_sp;
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ ThreadPlanSP completed_plan_sp;
+ completed_plan_sp = m_completed_plan_stack[i];
+ if (!completed_plan_sp->GetPrivate ())
+ return completed_plan_sp;
+ }
+ }
+ return empty_plan_sp;
+}
+
+ValueObjectSP
+Thread::GetReturnValueObject ()
+{
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ ValueObjectSP return_valobj_sp;
+ return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject();
+ if (return_valobj_sp)
+ return return_valobj_sp;
+ }
+ }
+ return ValueObjectSP();
+}
+
+bool
+Thread::IsThreadPlanDone (ThreadPlan *plan)
+{
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ if (m_completed_plan_stack[i].get() == plan)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+Thread::WasThreadPlanDiscarded (ThreadPlan *plan)
+{
+ if (!m_discarded_plan_stack.empty())
+ {
+ for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--)
+ {
+ if (m_discarded_plan_stack[i].get() == plan)
+ return true;
+ }
+ }
+ return false;
+}
+
+ThreadPlan *
+Thread::GetPreviousPlan (ThreadPlan *current_plan)
+{
+ if (current_plan == NULL)
+ return NULL;
+
+ int stack_size = m_completed_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_completed_plan_stack[i].get())
+ return m_completed_plan_stack[i-1].get();
+ }
+
+ if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan)
+ {
+ if (m_plan_stack.size() > 0)
+ return m_plan_stack.back().get();
+ else
+ return NULL;
+ }
+
+ stack_size = m_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (current_plan == m_plan_stack[i].get())
+ return m_plan_stack[i-1].get();
+ }
+ return NULL;
+}
+
+void
+Thread::QueueThreadPlan (ThreadPlanSP &thread_plan_sp, bool abort_other_plans)
+{
+ if (abort_other_plans)
+ DiscardThreadPlans(true);
+
+ PushPlan (thread_plan_sp);
+}
+
+
+void
+Thread::EnableTracer (bool value, bool single_stepping)
+{
+ int stack_size = m_plan_stack.size();
+ for (int i = 0; i < stack_size; i++)
+ {
+ if (m_plan_stack[i]->GetThreadPlanTracer())
+ {
+ m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value);
+ m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping);
+ }
+ }
+}
+
+void
+Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp)
+{
+ int stack_size = m_plan_stack.size();
+ for (int i = 0; i < stack_size; i++)
+ m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
+}
+
+void
+Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp)
+{
+ DiscardThreadPlansUpToPlan (up_to_plan_sp.get());
+}
+
+void
+Thread::DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", GetID(), up_to_plan_ptr);
+ }
+
+ int stack_size = m_plan_stack.size();
+
+ // If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the
+ // stack, and if so discard up to and including it.
+
+ if (up_to_plan_ptr == NULL)
+ {
+ for (int i = stack_size - 1; i > 0; i--)
+ DiscardPlan();
+ }
+ else
+ {
+ bool found_it = false;
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (m_plan_stack[i].get() == up_to_plan_ptr)
+ found_it = true;
+ }
+ if (found_it)
+ {
+ bool last_one = false;
+ for (int i = stack_size - 1; i > 0 && !last_one ; i--)
+ {
+ if (GetCurrentPlan() == up_to_plan_ptr)
+ last_one = true;
+ DiscardPlan();
+ }
+ }
+ }
+ return;
+}
+
+void
+Thread::DiscardThreadPlans(bool force)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf("Discarding thread plans for thread (tid = 0x%4.4" PRIx64 ", force %d)", GetID(), force);
+ }
+
+ if (force)
+ {
+ int stack_size = m_plan_stack.size();
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ DiscardPlan();
+ }
+ return;
+ }
+
+ while (1)
+ {
+
+ int master_plan_idx;
+ bool discard = true;
+
+ // Find the first master plan, see if it wants discarding, and if yes discard up to it.
+ for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; master_plan_idx--)
+ {
+ if (m_plan_stack[master_plan_idx]->IsMasterPlan())
+ {
+ discard = m_plan_stack[master_plan_idx]->OkayToDiscard();
+ break;
+ }
+ }
+
+ if (discard)
+ {
+ // First pop all the dependent plans:
+ for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--)
+ {
+
+ // FIXME: Do we need a finalize here, or is the rule that "PrepareForStop"
+ // for the plan leaves it in a state that it is safe to pop the plan
+ // with no more notice?
+ DiscardPlan();
+ }
+
+ // Now discard the master plan itself.
+ // The bottom-most plan never gets discarded. "OkayToDiscard" for it means
+ // discard it's dependent plans, but not it...
+ if (master_plan_idx > 0)
+ {
+ DiscardPlan();
+ }
+ }
+ else
+ {
+ // If the master plan doesn't want to get discarded, then we're done.
+ break;
+ }
+
+ }
+}
+
+bool
+Thread::PlanIsBasePlan (ThreadPlan *plan_ptr)
+{
+ if (plan_ptr->IsBasePlan())
+ return true;
+ else if (m_plan_stack.size() == 0)
+ return false;
+ else
+ return m_plan_stack[0].get() == plan_ptr;
+}
+
+Error
+Thread::UnwindInnermostExpression()
+{
+ Error error;
+ int stack_size = m_plan_stack.size();
+
+ // If the input plan is NULL, discard all plans. Otherwise make sure this plan is in the
+ // stack, and if so discard up to and including it.
+
+ for (int i = stack_size - 1; i > 0; i--)
+ {
+ if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction)
+ {
+ DiscardThreadPlansUpToPlan(m_plan_stack[i].get());
+ return error;
+ }
+ }
+ error.SetErrorString("No expressions currently active on this thread");
+ return error;
+}
+
+
+ThreadPlanSP
+Thread::QueueFundamentalPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanBase(*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepSingleInstruction
+(
+ bool step_over,
+ bool abort_other_plans,
+ bool stop_other_threads
+)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepInstruction (*this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepOverRange
+(
+ bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_other_threads
+)
+{
+ ThreadPlanSP thread_plan_sp;
+ thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads));
+
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepInRange
+(
+ bool abort_other_plans,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_in_target,
+ lldb::RunMode stop_other_threads,
+ bool avoid_code_without_debug_info
+)
+{
+ ThreadPlanSP thread_plan_sp;
+ ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
+ if (avoid_code_without_debug_info)
+ plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ else
+ plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ 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;
+}
+
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepOverBreakpointPlan (bool abort_other_plans)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepOut
+(
+ bool abort_other_plans,
+ SymbolContext *addr_context,
+ bool first_insn,
+ bool stop_other_threads,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx
+)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,
+ addr_context,
+ first_insn,
+ stop_other_threads,
+ stop_vote,
+ run_vote,
+ frame_idx));
+
+ if (thread_plan_sp->ValidatePlan(NULL))
+ {
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+ }
+ else
+ {
+ return ThreadPlanSP();
+ }
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id, bool abort_other_plans, bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp(new ThreadPlanStepThrough (*this, return_stack_id, stop_other_threads));
+ if (!thread_plan_sp || !thread_plan_sp->ValidatePlan (NULL))
+ return ThreadPlanSP();
+
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForCallFunction (bool abort_other_plans,
+ Address& function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanCallFunction (*this,
+ function,
+ ClangASTType(),
+ arg,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans,
+ Address &target_addr,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanRunToAddress (*this, target_addr, stop_other_threads));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+}
+
+ThreadPlanSP
+Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_other_threads,
+ uint32_t frame_idx)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads, frame_idx));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ return thread_plan_sp;
+
+}
+
+uint32_t
+Thread::GetIndexID () const
+{
+ return m_index_id;
+}
+
+void
+Thread::DumpThreadPlans (lldb_private::Stream *s) const
+{
+ 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->EOL();
+ s->IndentLess();
+ }
+
+ stack_size = m_completed_plan_stack.size();
+ if (stack_size > 0)
+ {
+ s->Indent();
+ s->Printf ("Completed 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_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->EOL();
+ s->IndentLess();
+ }
+ }
+
+ 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();
+ }
+ }
+
+}
+
+TargetSP
+Thread::CalculateTarget ()
+{
+ TargetSP target_sp;
+ ProcessSP process_sp(GetProcess());
+ if (process_sp)
+ target_sp = process_sp->CalculateTarget();
+ return target_sp;
+
+}
+
+ProcessSP
+Thread::CalculateProcess ()
+{
+ return GetProcess();
+}
+
+ThreadSP
+Thread::CalculateThread ()
+{
+ return shared_from_this();
+}
+
+StackFrameSP
+Thread::CalculateStackFrame ()
+{
+ return StackFrameSP();
+}
+
+void
+Thread::CalculateExecutionContext (ExecutionContext &exe_ctx)
+{
+ exe_ctx.SetContext (shared_from_this());
+}
+
+
+StackFrameListSP
+Thread::GetStackFrameList ()
+{
+ StackFrameListSP frame_list_sp;
+ Mutex::Locker locker(m_frame_mutex);
+ if (m_curr_frames_sp)
+ {
+ frame_list_sp = m_curr_frames_sp;
+ }
+ else
+ {
+ frame_list_sp.reset(new StackFrameList (*this, m_prev_frames_sp, true));
+ m_curr_frames_sp = frame_list_sp;
+ }
+ return frame_list_sp;
+}
+
+void
+Thread::ClearStackFrames ()
+{
+ Mutex::Locker locker(m_frame_mutex);
+
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+
+ // Only store away the old "reference" StackFrameList if we got all its frames:
+ // FIXME: At some point we can try to splice in the frames we have fetched into
+ // the new frame as we make it, but let's not try that now.
+ if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched())
+ m_prev_frames_sp.swap (m_curr_frames_sp);
+ m_curr_frames_sp.reset();
+}
+
+lldb::StackFrameSP
+Thread::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
+{
+ return GetStackFrameList()->GetFrameWithConcreteFrameIndex (unwind_idx);
+}
+
+
+Error
+Thread::ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp, bool broadcast)
+{
+ StackFrameSP frame_sp = GetStackFrameAtIndex (frame_idx);
+ Error return_error;
+
+ if (!frame_sp)
+ {
+ return_error.SetErrorStringWithFormat("Could not find frame with index %d in thread 0x%" PRIx64 ".", frame_idx, GetID());
+ }
+
+ return ReturnFromFrame(frame_sp, return_value_sp, broadcast);
+}
+
+Error
+Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp, bool broadcast)
+{
+ Error return_error;
+
+ if (!frame_sp)
+ {
+ return_error.SetErrorString("Can't return to a null frame.");
+ return return_error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+ uint32_t older_frame_idx = frame_sp->GetFrameIndex() + 1;
+ StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(older_frame_idx);
+ if (!older_frame_sp)
+ {
+ return_error.SetErrorString("No older frame to return to.");
+ return return_error;
+ }
+
+ if (return_value_sp)
+ {
+ lldb::ABISP abi = thread->GetProcess()->GetABI();
+ if (!abi)
+ {
+ return_error.SetErrorString("Could not find ABI to set return value.");
+ return return_error;
+ }
+ SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextFunction);
+
+ // 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)
+ {
+ Type *function_type = sc.function->GetType();
+ if (function_type)
+ {
+ ClangASTType return_type = sc.function->GetClangType().GetFunctionReturnType();
+ if (return_type)
+ {
+ StreamString s;
+ return_type.DumpTypeDescription(&s);
+ ValueObjectSP cast_value_sp = return_value_sp->Cast(return_type);
+ if (cast_value_sp)
+ {
+ cast_value_sp->SetFormat(eFormatHex);
+ return_value_sp = cast_value_sp;
+ }
+ }
+ }
+ }
+
+ return_error = abi->SetReturnValueObject(older_frame_sp, return_value_sp);
+ if (!return_error.Success())
+ return return_error;
+ }
+
+ // Now write the return registers for the chosen frame:
+ // Note, we can't use ReadAllRegisterValues->WriteAllRegisterValues, since the read & write
+ // cook their data
+
+ StackFrameSP youngest_frame_sp = thread->GetStackFrameAtIndex(0);
+ if (youngest_frame_sp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp (youngest_frame_sp->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ bool copy_success = reg_ctx_sp->CopyFromRegisterContext(older_frame_sp->GetRegisterContext());
+ if (copy_success)
+ {
+ thread->DiscardThreadPlans(true);
+ thread->ClearStackFrames();
+ if (broadcast && EventTypeHasListeners(eBroadcastBitStackChanged))
+ BroadcastEvent(eBroadcastBitStackChanged, new ThreadEventData (this->shared_from_this()));
+ }
+ else
+ {
+ return_error.SetErrorString("Could not reset register values.");
+ }
+ }
+ else
+ {
+ return_error.SetErrorString("Frame has no register context.");
+ }
+ }
+ else
+ {
+ return_error.SetErrorString("Returned past top frame.");
+ }
+ return return_error;
+}
+
+void
+Thread::DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx)
+{
+ ExecutionContext exe_ctx (shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return;
+
+ StackFrameSP frame_sp;
+ SymbolContext frame_sc;
+ if (frame_idx != LLDB_INVALID_INDEX32)
+ {
+ frame_sp = GetStackFrameAtIndex (frame_idx);
+ if (frame_sp)
+ {
+ exe_ctx.SetFrameSP(frame_sp);
+ frame_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
+ }
+ }
+
+ const char *thread_format = exe_ctx.GetTargetRef().GetDebugger().GetThreadFormat();
+ assert (thread_format);
+ Debugger::FormatPrompt (thread_format,
+ frame_sp ? &frame_sc : NULL,
+ &exe_ctx,
+ NULL,
+ strm);
+}
+
+void
+Thread::SettingsInitialize ()
+{
+}
+
+void
+Thread::SettingsTerminate ()
+{
+}
+
+lldb::StackFrameSP
+Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
+{
+ return GetStackFrameList()->GetStackFrameSPForStackFramePtr (stack_frame_ptr);
+}
+
+const char *
+Thread::StopReasonAsCString (lldb::StopReason reason)
+{
+ switch (reason)
+ {
+ case eStopReasonInvalid: return "invalid";
+ case eStopReasonNone: return "none";
+ case eStopReasonTrace: return "trace";
+ case eStopReasonBreakpoint: return "breakpoint";
+ case eStopReasonWatchpoint: return "watchpoint";
+ case eStopReasonSignal: return "signal";
+ case eStopReasonException: return "exception";
+ case eStopReasonExec: return "exec";
+ case eStopReasonPlanComplete: return "plan complete";
+ case eStopReasonThreadExiting: return "thread exiting";
+ }
+
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "StopReason = %i", reason);
+ return unknown_state_string;
+}
+
+const char *
+Thread::RunModeAsCString (lldb::RunMode mode)
+{
+ switch (mode)
+ {
+ case eOnlyThisThread: return "only this thread";
+ case eAllThreads: return "all threads";
+ case eOnlyDuringStepping: return "only during stepping";
+ }
+
+ static char unknown_state_string[64];
+ snprintf(unknown_state_string, sizeof (unknown_state_string), "RunMode = %i", mode);
+ return unknown_state_string;
+}
+
+size_t
+Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint32_t num_frames_with_source)
+{
+ ExecutionContext exe_ctx (shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+ size_t num_frames_shown = 0;
+ strm.Indent();
+ bool is_selected = false;
+ if (process)
+ {
+ if (process->GetThreadList().GetSelectedThread().get() == this)
+ is_selected = true;
+ }
+ strm.Printf("%c ", is_selected ? '*' : ' ');
+ if (target && target->GetDebugger().GetUseExternalEditor())
+ {
+ StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame);
+ if (frame_sp)
+ {
+ SymbolContext frame_sc(frame_sp->GetSymbolContext (eSymbolContextLineEntry));
+ if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file)
+ {
+ Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line);
+ }
+ }
+ }
+
+ DumpUsingSettingsFormat (strm, start_frame);
+
+ if (num_frames > 0)
+ {
+ strm.IndentMore();
+
+ const bool show_frame_info = true;
+ strm.IndentMore ();
+ num_frames_shown = GetStackFrameList ()->GetStatus (strm,
+ start_frame,
+ num_frames,
+ show_frame_info,
+ num_frames_with_source);
+ strm.IndentLess();
+ strm.IndentLess();
+ }
+ return num_frames_shown;
+}
+
+size_t
+Thread::GetStackFrameStatus (Stream& strm,
+ uint32_t first_frame,
+ uint32_t num_frames,
+ bool show_frame_info,
+ uint32_t num_frames_with_source)
+{
+ return GetStackFrameList()->GetStatus (strm,
+ first_frame,
+ num_frames,
+ show_frame_info,
+ num_frames_with_source);
+}
+
+bool
+Thread::SaveFrameZeroState (RegisterCheckpoint &checkpoint)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ checkpoint.SetStackID(frame_sp->GetStackID());
+ lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
+ if (reg_ctx_sp)
+ return reg_ctx_sp->ReadAllRegisterValues (checkpoint.GetData());
+ }
+ return false;
+}
+
+bool
+Thread::RestoreSaveFrameZero (const RegisterCheckpoint &checkpoint)
+{
+ return ResetFrameZeroRegisters (checkpoint.GetData());
+}
+
+bool
+Thread::ResetFrameZeroRegisters (lldb::DataBufferSP register_data_sp)
+{
+ lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
+ if (frame_sp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ bool ret = reg_ctx_sp->WriteAllRegisterValues (register_data_sp);
+
+ // Clear out all stack frames as our world just changed.
+ ClearStackFrames();
+ reg_ctx_sp->InvalidateIfNeeded(true);
+ if (m_unwinder_ap.get())
+ m_unwinder_ap->Clear();
+ return ret;
+ }
+ }
+ return false;
+}
+
+Unwind *
+Thread::GetUnwinder ()
+{
+ if (m_unwinder_ap.get() == NULL)
+ {
+ const ArchSpec target_arch (CalculateTarget()->GetArchitecture ());
+ const llvm::Triple::ArchType machine = target_arch.GetMachine();
+ switch (machine)
+ {
+ case llvm::Triple::x86_64:
+ case llvm::Triple::x86:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ m_unwinder_ap.reset (new UnwindLLDB (*this));
+ break;
+
+ default:
+ if (target_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
+ break;
+ }
+ }
+ return m_unwinder_ap.get();
+}
+
+
+void
+Thread::Flush ()
+{
+ ClearStackFrames ();
+ m_reg_context_sp.reset();
+}
+
+bool
+Thread::IsStillAtLastBreakpointHit ()
+{
+ // If we are currently stopped at a breakpoint, always return that stopinfo and don't reset it.
+ // This allows threads to maintain their breakpoint stopinfo, such as when thread-stepping in
+ // multithreaded programs.
+ if (m_stop_info_sp) {
+ StopReason stop_reason = m_stop_info_sp->GetStopReason();
+ if (stop_reason == lldb::eStopReasonBreakpoint) {
+ uint64_t value = m_stop_info_sp->GetValue();
+ lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
+ if (reg_ctx_sp)
+ {
+ lldb::addr_t pc = reg_ctx_sp->GetPC();
+ BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && value == bp_site_sp->GetID())
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
new file mode 100644
index 000000000000..1f8b351100a6
--- /dev/null
+++ b/source/Target/ThreadList.cpp
@@ -0,0 +1,785 @@
+//===-- ThreadList.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/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadList::ThreadList (Process *process) :
+ m_process (process),
+ m_stop_id (0),
+ m_threads(),
+ m_selected_tid (LLDB_INVALID_THREAD_ID)
+{
+}
+
+ThreadList::ThreadList (const ThreadList &rhs) :
+ 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
+ *this = rhs;
+}
+
+const ThreadList&
+ThreadList::operator = (const ThreadList& rhs)
+{
+ if (this != &rhs)
+ {
+ // Lock both mutexes to make sure neither side changes anyone on us
+ // while the assignement occurs
+ Mutex::Locker locker(GetMutex());
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads = rhs.m_threads;
+ m_selected_tid = rhs.m_selected_tid;
+ }
+ return *this;
+}
+
+
+ThreadList::~ThreadList()
+{
+ // Clear the thread list. Clear will take the mutex lock
+ // which will ensure that if anyone is using the list
+ // they won't get it removed while using it.
+ Clear();
+}
+
+
+uint32_t
+ThreadList::GetStopID () const
+{
+ return m_stop_id;
+}
+
+void
+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);
+}
+
+uint32_t
+ThreadList::GetSize (bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+ return m_threads.size();
+}
+
+ThreadSP
+ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ if (idx < m_threads.size())
+ thread_sp = m_threads[idx];
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::FindThreadByProtocolID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetProtocolID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+
+ThreadSP
+ThreadList::RemoveThreadByID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ m_threads.erase(m_threads.begin()+idx);
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetProtocolID() == tid)
+ {
+ thread_sp = m_threads[idx];
+ m_threads.erase(m_threads.begin()+idx);
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+ThreadSP
+ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_ptr)
+ {
+ Mutex::Locker locker(GetMutex());
+
+ uint32_t idx = 0;
+ const uint32_t num_threads = m_threads.size();
+ for (idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx].get() == thread_ptr)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ }
+ return thread_sp;
+}
+
+
+
+ThreadSP
+ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update)
+{
+ Mutex::Locker locker(GetMutex());
+
+ if (can_update)
+ m_process->UpdateThreadListIfNeeded();
+
+ ThreadSP thread_sp;
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetIndexID() == index_id)
+ {
+ thread_sp = m_threads[idx];
+ break;
+ }
+ }
+ return thread_sp;
+}
+
+bool
+ThreadList::ShouldStop (Event *event_ptr)
+{
+ // Running events should never stop, obviously...
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ // The ShouldStop method of the threads can do a whole lot of work,
+ // running breakpoint commands & conditions, etc. So we don't want
+ // to keep the ThreadList locked the whole time we are doing this.
+ // FIXME: It is possible that running code could cause new threads
+ // to be created. If that happens we will miss asking them whether
+ // then should stop. This is not a big deal, since we haven't had
+ // a chance to hang any interesting operations on those threads yet.
+
+ collection threads_copy;
+ {
+ // Scope for locker
+ Mutex::Locker locker(GetMutex());
+
+ m_process->UpdateThreadListIfNeeded();
+ threads_copy = m_threads;
+ }
+
+ collection::iterator pos, end = threads_copy.end();
+
+ if (log)
+ {
+ log->PutCString("");
+ log->Printf ("ThreadList::%s: %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
+ }
+
+ bool did_anybody_stop_for_a_reason = false;
+ bool should_stop = false;
+
+ // Now we run through all the threads and get their stop info's. We want to make sure to do this first before
+ // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a
+ // thread specific breakpoint another thread had stopped at) which could lead us to compute the StopInfo incorrectly.
+ // We don't need to use it here, we just want to make sure it gets computed.
+
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->GetStopInfo();
+ }
+
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+
+ did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason();
+
+ const bool thread_should_stop = thread_sp->ShouldStop(event_ptr);
+ if (thread_should_stop)
+ should_stop |= true;
+ }
+
+ // We should never get a stop for which no thread had a stop reason, but sometimes we do see this -
+ // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out
+ // the right thing to do and stopping gives the user control over what to do in this instance.
+
+ if (!should_stop && !did_anybody_stop_for_a_reason)
+ {
+ should_stop = true;
+ if (log)
+ log->Printf ("ThreadList::%s we stopped but no threads had a stop reason, overriding should_stop and stopping.", __FUNCTION__);
+ }
+
+ if (log)
+ log->Printf ("ThreadList::%s overall should_stop = %i", __FUNCTION__, should_stop);
+
+ if (should_stop)
+ {
+ for (pos = threads_copy.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->WillStop ();
+ }
+ }
+
+ return should_stop;
+}
+
+Vote
+ThreadList::ShouldReportStop (Event *event_ptr)
+{
+ Mutex::Locker locker(GetMutex());
+
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (log)
+ log->Printf ("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size());
+
+ // Run through the threads and ask whether we should report this event.
+ // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion.
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ const Vote vote = thread_sp->ShouldReportStop (event_ptr);
+ switch (vote)
+ {
+ case eVoteNoOpinion:
+ continue;
+
+ case eVoteYes:
+ result = eVoteYes;
+ break;
+
+ case eVoteNo:
+ if (result == eVoteNoOpinion)
+ {
+ result = eVoteNo;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ThreadList::%s thread 0x%4.4" PRIx64 ": voted %s, but lost out because result was %s",
+ __FUNCTION__,
+ thread_sp->GetID (),
+ GetVoteAsCString (vote),
+ GetVoteAsCString (result));
+ }
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("ThreadList::%s returning %s", __FUNCTION__, GetVoteAsCString (result));
+ return result;
+}
+
+void
+ThreadList::SetShouldReportStop (Vote vote)
+{
+ Mutex::Locker locker(GetMutex());
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ thread_sp->SetShouldReportStop (vote);
+ }
+}
+
+Vote
+ThreadList::ShouldReportRun (Event *event_ptr)
+{
+
+ Mutex::Locker locker(GetMutex());
+
+ Vote result = eVoteNoOpinion;
+ m_process->UpdateThreadListIfNeeded();
+ collection::iterator pos, end = m_threads.end();
+
+ // Run through the threads and ask whether we should report this event.
+ // The rule is NO vote wins over everything, a YES vote wins over no opinion.
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState () != eStateSuspended)
+ {
+ switch ((*pos)->ShouldReportRun (event_ptr))
+ {
+ case eVoteNoOpinion:
+ continue;
+ case eVoteYes:
+ if (result == eVoteNoOpinion)
+ result = eVoteYes;
+ break;
+ case eVoteNo:
+ if (log)
+ log->Printf ("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 ") says don't report.",
+ (*pos)->GetIndexID(),
+ (*pos)->GetID());
+ result = eVoteNo;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+void
+ThreadList::Clear()
+{
+ Mutex::Locker locker(GetMutex());
+ m_stop_id = 0;
+ m_threads.clear();
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+}
+
+void
+ThreadList::Destroy()
+{
+ Mutex::Locker locker(GetMutex());
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ m_threads[idx]->DestroyThread();
+ }
+}
+
+void
+ThreadList::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(GetMutex());
+
+ m_process->UpdateThreadListIfNeeded();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning off notification of new threads while single stepping a thread.");
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->RefreshStateAfterStop ();
+}
+
+void
+ThreadList::DiscardThreadPlans ()
+{
+ // You don't need to update the thread list here, because only threads
+ // that you currently know about have any thread plans.
+ Mutex::Locker locker(GetMutex());
+
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->DiscardThreadPlans (true);
+
+}
+
+bool
+ThreadList::WillResume ()
+{
+ // Run through the threads and perform their momentary actions.
+ // But we only do this for threads that are running, user suspended
+ // threads stay where they are.
+
+ Mutex::Locker locker(GetMutex());
+ m_process->UpdateThreadListIfNeeded();
+
+ collection::iterator pos, end = m_threads.end();
+
+ // See if any thread wants to run stopping others. If it does, then we won't
+ // setup the other threads for resume, since they aren't going to get a chance
+ // to run. This is necessary because the SetupForResume might add "StopOthers"
+ // plans which would then get to be part of the who-gets-to-run negotiation, but
+ // they're coming in after the fact, and the threads that are already set up should
+ // take priority.
+
+ bool wants_solo_run = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState() != eStateSuspended &&
+ (*pos)->GetCurrentPlan()->StopOthers())
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+ wants_solo_run = true;
+ break;
+ }
+ }
+
+ if (wants_solo_run)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning on notification of new threads while single stepping a thread.");
+ m_process->StartNoticingNewThreads();
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Turning off notification of new threads while single stepping a thread.");
+ m_process->StopNoticingNewThreads();
+ }
+
+ // Give all the threads that are likely to run a last chance to set up their state before we
+ // negotiate who is actually going to get a chance to run...
+ // Don't set to resume suspended threads, and if any thread wanted to stop others, only
+ // call setup on the threads that request StopOthers...
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ if ((*pos)->GetResumeState() != eStateSuspended
+ && (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers()))
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+ (*pos)->SetupForResume ();
+ }
+ }
+
+ // Now go through the threads and see if any thread wants to run just itself.
+ // if so then pick one and run it.
+
+ ThreadList run_me_only_list (m_process);
+
+ run_me_only_list.SetStopID(m_process->GetStopID());
+
+ bool run_only_current_thread = false;
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState() != eStateSuspended &&
+ thread_sp->GetCurrentPlan()->StopOthers())
+ {
+ if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread())
+ continue;
+
+ // You can't say "stop others" and also want yourself to be suspended.
+ assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended);
+
+ if (thread_sp == GetSelectedThread())
+ {
+ run_only_current_thread = true;
+ run_me_only_list.Clear();
+ run_me_only_list.AddThread (thread_sp);
+ break;
+ }
+
+ run_me_only_list.AddThread (thread_sp);
+ }
+
+ }
+
+ bool need_to_resume = true;
+
+ if (run_me_only_list.GetSize (false) == 0)
+ {
+ // Everybody runs as they wish:
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ StateType run_state;
+ if (thread_sp->GetResumeState() != eStateSuspended)
+ run_state = thread_sp->GetCurrentPlan()->RunState();
+ else
+ run_state = eStateSuspended;
+ if (!thread_sp->ShouldResume(run_state))
+ need_to_resume = false;
+ }
+ }
+ else
+ {
+ ThreadSP thread_to_run;
+
+ if (run_only_current_thread)
+ {
+ thread_to_run = GetSelectedThread();
+ }
+ else if (run_me_only_list.GetSize (false) == 1)
+ {
+ thread_to_run = run_me_only_list.GetThreadAtIndex (0);
+ }
+ else
+ {
+ int random_thread = (int)
+ ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0));
+ thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread);
+ }
+
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ ThreadSP thread_sp(*pos);
+ if (thread_sp == thread_to_run)
+ {
+ if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState()))
+ need_to_resume = false;
+ }
+ else
+ thread_sp->ShouldResume (eStateSuspended);
+ }
+ }
+
+ return need_to_resume;
+}
+
+void
+ThreadList::DidResume ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ // Don't clear out threads that aren't going to get a chance to run, rather
+ // leave their state for the next time around.
+ ThreadSP thread_sp(*pos);
+ if (thread_sp->GetResumeState() != eStateSuspended)
+ thread_sp->DidResume ();
+ }
+}
+
+void
+ThreadList::DidStop ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ {
+ // Notify threads that the process just stopped.
+ // Note, this currently assumes that all threads in the list
+ // stop when the process stops. In the future we will want to support
+ // a debugging model where some threads continue to run while others
+ // are stopped. We either need to handle that somehow here or
+ // create a special thread list containing only threads which will
+ // stop in the code that calls this method (currently
+ // Process::SetPrivateState).
+ ThreadSP thread_sp(*pos);
+ if (StateIsRunningState(thread_sp->GetState()))
+ thread_sp->DidStop ();
+ }
+}
+
+ThreadSP
+ThreadList::GetSelectedThread ()
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP thread_sp = FindThreadByID(m_selected_tid);
+ if (!thread_sp.get())
+ {
+ if (m_threads.size() == 0)
+ return thread_sp;
+ m_selected_tid = m_threads[0]->GetID();
+ thread_sp = m_threads[0];
+ }
+ return thread_sp;
+}
+
+bool
+ThreadList::SetSelectedThreadByID (lldb::tid_t tid, bool notify)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP selected_thread_sp(FindThreadByID(tid));
+ if (selected_thread_sp)
+ {
+ m_selected_tid = tid;
+ selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
+ }
+ else
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+
+ if (notify)
+ NotifySelectedThreadChanged(m_selected_tid);
+
+ return m_selected_tid != LLDB_INVALID_THREAD_ID;
+}
+
+bool
+ThreadList::SetSelectedThreadByIndexID (uint32_t index_id, bool notify)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP selected_thread_sp (FindThreadByIndexID(index_id));
+ if (selected_thread_sp.get())
+ {
+ m_selected_tid = selected_thread_sp->GetID();
+ selected_thread_sp->SetDefaultFileAndLineToSelectedFrame();
+ }
+ else
+ m_selected_tid = LLDB_INVALID_THREAD_ID;
+
+ if (notify)
+ NotifySelectedThreadChanged(m_selected_tid);
+
+ return m_selected_tid != LLDB_INVALID_THREAD_ID;
+}
+
+void
+ThreadList::NotifySelectedThreadChanged (lldb::tid_t tid)
+{
+ ThreadSP selected_thread_sp (FindThreadByID(tid));
+ if (selected_thread_sp->EventTypeHasListeners(Thread::eBroadcastBitThreadSelected))
+ selected_thread_sp->BroadcastEvent(Thread::eBroadcastBitThreadSelected,
+ new Thread::ThreadEventData(selected_thread_sp));
+}
+
+void
+ThreadList::Update (ThreadList &rhs)
+{
+ if (this != &rhs)
+ {
+ // Lock both mutexes to make sure neither side changes anyone on us
+ // while the assignement occurs
+ Mutex::Locker locker(GetMutex());
+ m_process = rhs.m_process;
+ m_stop_id = rhs.m_stop_id;
+ m_threads.swap(rhs.m_threads);
+ m_selected_tid = rhs.m_selected_tid;
+
+
+ // Now we look for threads that we are done with and
+ // make sure to clear them up as much as possible so
+ // anyone with a shared pointer will still have a reference,
+ // but the thread won't be of much use. Using std::weak_ptr
+ // for all backward references (such as a thread to a process)
+ // will eventually solve this issue for us, but for now, we
+ // need to work around the issue
+ collection::iterator rhs_pos, rhs_end = rhs.m_threads.end();
+ for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos)
+ {
+ const lldb::tid_t tid = (*rhs_pos)->GetID();
+ bool thread_is_alive = false;
+ const uint32_t num_threads = m_threads.size();
+ for (uint32_t idx = 0; idx < num_threads; ++idx)
+ {
+ if (m_threads[idx]->GetID() == tid)
+ {
+ thread_is_alive = true;
+ break;
+ }
+ }
+ if (!thread_is_alive)
+ (*rhs_pos)->DestroyThread();
+ }
+ }
+}
+
+void
+ThreadList::Flush ()
+{
+ Mutex::Locker locker(GetMutex());
+ collection::iterator pos, end = m_threads.end();
+ for (pos = m_threads.begin(); pos != end; ++pos)
+ (*pos)->Flush ();
+}
+
+Mutex &
+ThreadList::GetMutex ()
+{
+ return m_process->m_thread_mutex;
+}
+
diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp
new file mode 100644
index 000000000000..65d51bd01734
--- /dev/null
+++ b/source/Target/ThreadPlan.cpp
@@ -0,0 +1,353 @@
+//===-- 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/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlan constructor
+//----------------------------------------------------------------------
+ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) :
+ m_thread (thread),
+ m_stop_vote (stop_vote),
+ m_run_vote (run_vote),
+ m_kind (kind),
+ m_name (name),
+ m_plan_complete_mutex (Mutex::eMutexTypeRecursive),
+ m_cached_plan_explains_stop (eLazyBoolCalculate),
+ m_plan_complete (false),
+ m_plan_private (false),
+ m_okay_to_discard (true),
+ m_is_master_plan (false),
+ m_plan_succeeded(true)
+{
+ SetID (GetNextID());
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlan::~ThreadPlan()
+{
+}
+
+bool
+ThreadPlan::PlanExplainsStop (Event *event_ptr)
+{
+ if (m_cached_plan_explains_stop == eLazyBoolCalculate)
+ {
+ bool actual_value = DoPlanExplainsStop(event_ptr);
+ m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo;
+ return actual_value;
+ }
+ else
+ {
+ return m_cached_plan_explains_stop == eLazyBoolYes;
+ }
+}
+
+bool
+ThreadPlan::IsPlanComplete ()
+{
+ Mutex::Locker locker(m_plan_complete_mutex);
+ return m_plan_complete;
+}
+
+void
+ThreadPlan::SetPlanComplete (bool success)
+{
+ Mutex::Locker locker(m_plan_complete_mutex);
+ m_plan_complete = true;
+ m_plan_succeeded = success;
+}
+
+bool
+ThreadPlan::MischiefManaged ()
+{
+ Mutex::Locker locker(m_plan_complete_mutex);
+ // Mark the plan is complete, but don't override the success flag.
+ m_plan_complete = true;
+ return true;
+}
+
+Vote
+ThreadPlan::ShouldReportStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (m_stop_vote == eVoteNoOpinion)
+ {
+ ThreadPlan *prev_plan = GetPreviousPlan ();
+ if (prev_plan)
+ {
+ Vote prev_vote = prev_plan->ShouldReportStop (event_ptr);
+ if (log)
+ log->Printf ("ThreadPlan::ShouldReportStop() returning previous thread plan vote: %s",
+ GetVoteAsCString (prev_vote));
+ return prev_vote;
+ }
+ }
+ if (log)
+ log->Printf ("ThreadPlan::ShouldReportStop() returning vote: %s", GetVoteAsCString (m_stop_vote));
+ return m_stop_vote;
+}
+
+Vote
+ThreadPlan::ShouldReportRun (Event *event_ptr)
+{
+ if (m_run_vote == eVoteNoOpinion)
+ {
+ ThreadPlan *prev_plan = GetPreviousPlan ();
+ if (prev_plan)
+ return prev_plan->ShouldReportRun (event_ptr);
+ }
+ return m_run_vote;
+}
+
+bool
+ThreadPlan::StopOthers ()
+{
+ ThreadPlan *prev_plan;
+ prev_plan = GetPreviousPlan ();
+ if (prev_plan == NULL)
+ return false;
+ else
+ return prev_plan->StopOthers();
+}
+
+void
+ThreadPlan::SetStopOthers (bool new_value)
+{
+ // SetStopOthers doesn't work up the hierarchy. You have to set the
+ // explicit ThreadPlan you want to affect.
+}
+
+bool
+ThreadPlan::WillResume (StateType resume_state, bool current_plan)
+{
+ m_cached_plan_explains_stop = eLazyBoolCalculate;
+
+ if (current_plan)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (log)
+ {
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ addr_t pc = reg_ctx->GetPC();
+ addr_t sp = reg_ctx->GetSP();
+ addr_t fp = reg_ctx->GetFP();
+ log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", "
+ "plan = '%s', state = %s, stop others = %d",
+ __FUNCTION__,
+ m_thread.GetIndexID(),
+ &m_thread,
+ m_thread.GetID(),
+ (uint64_t)pc,
+ (uint64_t)sp,
+ (uint64_t)fp,
+ m_name.c_str(),
+ StateAsCString(resume_state),
+ StopOthers());
+ }
+ }
+ return DoWillResume (resume_state, current_plan);
+}
+
+lldb::user_id_t
+ThreadPlan::GetNextID()
+{
+ static uint32_t g_nextPlanID = 0;
+ return ++g_nextPlanID;
+}
+
+void
+ThreadPlan::DidPush()
+{
+}
+
+void
+ThreadPlan::WillPop()
+{
+}
+
+bool
+ThreadPlan::OkayToDiscard()
+{
+ if (!IsMasterPlan())
+ return true;
+ else
+ return m_okay_to_discard;
+}
+
+lldb::StateType
+ThreadPlan::RunState ()
+{
+ if (m_tracer_sp && m_tracer_sp->TracingEnabled() && m_tracer_sp->SingleStepEnabled())
+ return eStateStepping;
+ else
+ return GetPlanRunState();
+}
+
+//----------------------------------------------------------------------
+// ThreadPlanNull
+//----------------------------------------------------------------------
+
+ThreadPlanNull::ThreadPlanNull (Thread &thread) :
+ ThreadPlan (ThreadPlan::eKindNull,
+ "Null Thread Plan",
+ thread,
+ eVoteNoOpinion,
+ eVoteNoOpinion)
+{
+}
+
+ThreadPlanNull::~ThreadPlanNull ()
+{
+}
+
+void
+ThreadPlanNull::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ s->PutCString("Null thread plan - thread has been destroyed.");
+}
+
+bool
+ThreadPlanNull::ValidatePlan (Stream *error)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::ShouldStop (Event *event_ptr)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::WillStop ()
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+bool
+ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr)
+{
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return true;
+}
+
+// The null plan is never done.
+bool
+ThreadPlanNull::MischiefManaged ()
+{
+ // The null plan is never done.
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return false;
+}
+
+lldb::StateType
+ThreadPlanNull::GetPlanRunState ()
+{
+ // Not sure what to return here. This is a dead thread.
+#ifdef LLDB_CONFIGURATION_DEBUG
+ fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#else
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")",
+ __PRETTY_FUNCTION__,
+ m_thread.GetID(),
+ m_thread.GetProtocolID());
+#endif
+ return eStateRunning;
+}
diff --git a/source/Target/ThreadPlanBase.cpp b/source/Target/ThreadPlanBase.cpp
new file mode 100644
index 000000000000..240f23a0b8f4
--- /dev/null
+++ b/source/Target/ThreadPlanBase.cpp
@@ -0,0 +1,237 @@
+//===-- ThreadPlanBase.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/ThreadPlanBase.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+//
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanBase: This one always stops, and never has anything particular
+// to do.
+// FIXME: The "signal handling" policies should probably go here.
+//----------------------------------------------------------------------
+
+ThreadPlanBase::ThreadPlanBase (Thread &thread) :
+ ThreadPlan(ThreadPlan::eKindBase, "base plan", thread, eVoteYes, eVoteNoOpinion)
+{
+ // Set the tracer to a default tracer.
+ // FIXME: need to add a thread settings variable to pix various tracers...
+#define THREAD_PLAN_USE_ASSEMBLY_TRACER 1
+
+#ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER
+ ThreadPlanTracerSP new_tracer_sp (new ThreadPlanAssemblyTracer (m_thread));
+#else
+ ThreadPlanTracerSP new_tracer_sp (new ThreadPlanTracer (m_thread));
+#endif
+ new_tracer_sp->EnableTracing (m_thread.GetTraceEnabledState());
+ SetThreadPlanTracer(new_tracer_sp);
+ SetIsMasterPlan (true);
+}
+
+ThreadPlanBase::~ThreadPlanBase ()
+{
+
+}
+
+void
+ThreadPlanBase::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ s->Printf ("Base thread plan.");
+}
+
+bool
+ThreadPlanBase::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::DoPlanExplainsStop (Event *event_ptr)
+{
+ // The base plan should defer to its tracer, since by default it
+ // always handles the stop.
+ if (TracerExplainsStop())
+ return false;
+ else
+ return true;
+}
+
+Vote
+ThreadPlanBase::ShouldReportStop(Event *event_ptr)
+{
+ StopInfoSP stop_info_sp = m_thread.GetStopInfo ();
+ if (stop_info_sp)
+ {
+ bool should_notify = stop_info_sp->ShouldNotify(event_ptr);
+ if (should_notify)
+ return eVoteYes;
+ else
+ return eVoteNoOpinion;
+ }
+ else
+ return eVoteNoOpinion;
+}
+
+bool
+ThreadPlanBase::ShouldStop (Event *event_ptr)
+{
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason ();
+ switch (reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ // This
+ m_run_vote = eVoteNoOpinion;
+ m_stop_vote = eVoteNo;
+ return false;
+
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ if (stop_info_sp->ShouldStopSynchronous(event_ptr))
+ {
+ // If we are going to stop for a breakpoint, then unship the other plans
+ // at this point. Don't force the discard, however, so Master plans can stay
+ // in place if they want to.
+ if (log)
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (breakpoint hit.)", m_thread.GetID());
+ m_thread.DiscardThreadPlans(false);
+ return true;
+ }
+ // If we aren't going to stop at this breakpoint, and it is internal,
+ // don't report this stop or the subsequent running event.
+ // Otherwise we will post the stopped & running, but the stopped event will get marked
+ // with "restarted" so the UI will know to wait and expect the consequent "running".
+ if (stop_info_sp->ShouldNotify (event_ptr))
+ {
+ m_stop_vote = eVoteYes;
+ m_run_vote = eVoteYes;
+ }
+ else
+ {
+ m_stop_vote = eVoteNo;
+ m_run_vote = eVoteNo;
+ }
+ return false;
+
+ // TODO: the break below was missing, was this intentional??? If so
+ // please mention it
+ break;
+
+ case eStopReasonException:
+ // If we crashed, discard thread plans and stop. Don't force the discard, however,
+ // since on rerun the target may clean up this exception and continue normally from there.
+ if (log)
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception.)", m_thread.GetID());
+ m_thread.DiscardThreadPlans(false);
+ return true;
+
+ case eStopReasonExec:
+ // If we crashed, discard thread plans and stop. Don't force the discard, however,
+ // since on rerun the target may clean up this exception and continue normally from there.
+ if (log)
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exec.)", m_thread.GetID());
+ m_thread.DiscardThreadPlans(false);
+ return true;
+
+ case eStopReasonThreadExiting:
+ case eStopReasonSignal:
+ if (stop_info_sp->ShouldStop(event_ptr))
+ {
+ if (log)
+ log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal.)", m_thread.GetID());
+ m_thread.DiscardThreadPlans(false);
+ return true;
+ }
+ else
+ {
+ // We're not going to stop, but while we are here, let's figure out
+ // whether to report this.
+ if (stop_info_sp->ShouldNotify(event_ptr))
+ m_stop_vote = eVoteYes;
+ else
+ m_stop_vote = eVoteNo;
+ }
+ return false;
+
+ default:
+ return true;
+ }
+
+ }
+ else
+ {
+ m_run_vote = eVoteNoOpinion;
+ m_stop_vote = eVoteNo;
+ }
+
+ // If there's no explicit reason to stop, then we will continue.
+ return false;
+}
+
+bool
+ThreadPlanBase::StopOthers ()
+{
+ return false;
+}
+
+StateType
+ThreadPlanBase::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanBase::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanBase::DoWillResume (lldb::StateType resume_state, bool current_plan)
+{
+ // Reset these to the default values so we don't set them wrong, then not get asked
+ // for a while, then return the wrong answer.
+ m_run_vote = eVoteNoOpinion;
+ m_stop_vote = eVoteNo;
+ return true;
+}
+
+
+// The base plan is never done.
+bool
+ThreadPlanBase::MischiefManaged ()
+{
+ // The base plan is never done.
+ return false;
+}
+
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
new file mode 100644
index 000000000000..c9baaafffd6a
--- /dev/null
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -0,0 +1,614 @@
+//===-- ThreadPlanCallFunction.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/ThreadPlanCallFunction.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/Support/MachO.h"
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanCallFunction: Plan to call a single function
+//----------------------------------------------------------------------
+bool
+ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
+ ABI *& abi,
+ lldb::addr_t &start_load_addr,
+ lldb::addr_t &function_load_addr)
+{
+ SetIsMasterPlan (true);
+ SetOkayToDiscard (false);
+ SetPrivate (true);
+
+ ProcessSP process_sp (thread.GetProcess());
+ if (!process_sp)
+ return false;
+
+ abi = process_sp->GetABI().get();
+
+ if (!abi)
+ return false;
+
+ TargetSP target_sp (thread.CalculateTarget());
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
+
+ SetBreakpoints();
+
+ m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
+ // If we can't read memory at the point of the process where we are planning to put our function, we're
+ // not going to get any further...
+ Error error;
+ process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error);
+ if (!error.Success())
+ {
+ m_constructor_errors.Printf ("Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", m_function_sp);
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ return false;
+ }
+
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+
+ if (exe_module == NULL)
+ {
+ m_constructor_errors.Printf ("Can't execute code without an executable module.");
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ return false;
+ }
+ else
+ {
+ ObjectFile *objectFile = exe_module->GetObjectFile();
+ if (!objectFile)
+ {
+ m_constructor_errors.Printf ("Could not find object file for module \"%s\".",
+ exe_module->GetFileSpec().GetFilename().AsCString());
+
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ return false;
+ }
+
+ m_start_addr = objectFile->GetEntryPointAddress();
+ if (!m_start_addr.IsValid())
+ {
+ m_constructor_errors.Printf ("Could not find entry point address for executable module \"%s\".",
+ exe_module->GetFileSpec().GetFilename().AsCString());
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ return false;
+ }
+ }
+
+ start_load_addr = m_start_addr.GetLoadAddress (target_sp.get());
+
+ // Checkpoint the thread state so we can restore it later.
+ if (log && log->GetVerbose())
+ ReportRegisterState ("About to checkpoint thread before function call. Original register state was:");
+
+ if (!thread.CheckpointThreadState (m_stored_thread_state))
+ {
+ m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ return false;
+ }
+ function_load_addr = m_function_addr.GetLoadAddress (target_sp.get());
+
+ return true;
+}
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ const Address &function,
+ const ClangASTType &return_type,
+ addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ addr_t *this_arg,
+ addr_t *cmd_arg) :
+ ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid (false),
+ m_stop_other_threads (stop_other_threads),
+ m_function_addr (function),
+ m_function_sp (0),
+ m_return_type (return_type),
+ m_takedown_done (false),
+ m_stop_address (LLDB_INVALID_ADDRESS),
+ m_unwind_on_error (unwind_on_error),
+ m_ignore_breakpoints (ignore_breakpoints)
+{
+ lldb::addr_t start_load_addr;
+ ABI *abi;
+ lldb::addr_t function_load_addr;
+ if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
+ return;
+
+ if (this_arg && cmd_arg)
+ {
+ if (!abi->PrepareTrivialCall (thread,
+ m_function_sp,
+ function_load_addr,
+ start_load_addr,
+ this_arg,
+ cmd_arg,
+ &arg))
+ return;
+ }
+ else if (this_arg)
+ {
+ if (!abi->PrepareTrivialCall (thread,
+ m_function_sp,
+ function_load_addr,
+ start_load_addr,
+ this_arg,
+ &arg))
+ return;
+ }
+ else
+ {
+ if (!abi->PrepareTrivialCall (thread,
+ m_function_sp,
+ function_load_addr,
+ start_load_addr,
+ &arg))
+ return;
+ }
+
+ ReportRegisterState ("Function call was set up. Register state was:");
+
+ m_valid = true;
+}
+
+
+ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
+ const Address &function,
+ const ClangASTType &return_type,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) :
+ ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_valid (false),
+ m_stop_other_threads (stop_other_threads),
+ m_function_addr (function),
+ m_function_sp (0),
+ m_return_type (return_type),
+ m_takedown_done (false),
+ m_stop_address (LLDB_INVALID_ADDRESS),
+ m_unwind_on_error (unwind_on_error),
+ m_ignore_breakpoints (ignore_breakpoints)
+{
+ lldb::addr_t start_load_addr;
+ ABI *abi;
+ lldb::addr_t function_load_addr;
+ if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr))
+ return;
+
+ if (!abi->PrepareTrivialCall (thread,
+ m_function_sp,
+ function_load_addr,
+ start_load_addr,
+ arg1_ptr,
+ arg2_ptr,
+ arg3_ptr,
+ arg4_ptr,
+ arg5_ptr,
+ arg6_ptr))
+ {
+ return;
+ }
+
+ ReportRegisterState ("Function call was set up. Register state was:");
+
+ m_valid = true;
+}
+
+ThreadPlanCallFunction::~ThreadPlanCallFunction ()
+{
+ DoTakedown(PlanSucceeded());
+}
+
+void
+ThreadPlanCallFunction::ReportRegisterState (const char *message)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_VERBOSE));
+ if (log)
+ {
+ StreamString strm;
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+
+ log->PutCString(message);
+
+ RegisterValue reg_value;
+
+ for (uint32_t reg_idx = 0, num_registers = reg_ctx->GetRegisterCount();
+ reg_idx < num_registers;
+ ++reg_idx)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx);
+ if (reg_ctx->ReadRegister(reg_info, reg_value))
+ {
+ reg_value.Dump(&strm, reg_info, true, false, eFormatDefault);
+ strm.EOL();
+ }
+ }
+ log->PutCString(strm.GetData());
+ }
+}
+
+void
+ThreadPlanCallFunction::DoTakedown (bool success)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (!m_valid)
+ {
+ //Don't call DoTakedown if we were never valid to begin with.
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.", this);
+ return;
+ }
+
+ if (!m_takedown_done)
+ {
+ if (success)
+ {
+ ProcessSP process_sp (m_thread.GetProcess());
+ const ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+ if (abi && m_return_type.IsValid())
+ {
+ const bool persistent = false;
+ m_return_valobj_sp = abi->GetReturnValueObject (m_thread, m_return_type, persistent);
+ }
+ }
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ m_takedown_done = true;
+ m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
+ m_real_stop_info_sp = GetPrivateStopInfo ();
+ m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state);
+ SetPlanComplete(success);
+ ClearBreakpoints();
+ if (log && log->GetVerbose())
+ ReportRegisterState ("Restoring thread state after function call. Restored register state:");
+
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ }
+}
+
+void
+ThreadPlanCallFunction::WillPop ()
+{
+ DoTakedown(PlanSucceeded());
+}
+
+void
+ThreadPlanCallFunction::GetDescription (Stream *s, DescriptionLevel level)
+{
+ if (level == eDescriptionLevelBrief)
+ {
+ s->Printf("Function call thread plan");
+ }
+ else
+ {
+ TargetSP target_sp (m_thread.CalculateTarget());
+ s->Printf("Thread plan to call 0x%" PRIx64, m_function_addr.GetLoadAddress(target_sp.get()));
+ }
+}
+
+bool
+ThreadPlanCallFunction::ValidatePlan (Stream *error)
+{
+ if (!m_valid)
+ {
+ if (error)
+ {
+ if (m_constructor_errors.GetSize() > 0)
+ error->PutCString (m_constructor_errors.GetData());
+ else
+ error->PutCString ("Unknown error");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+
+Vote
+ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr)
+{
+ if (m_takedown_done || IsPlanComplete())
+ return eVoteYes;
+ else
+ return ThreadPlan::ShouldReportStop(event_ptr);
+}
+
+bool
+ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP|LIBLLDB_LOG_PROCESS));
+ m_real_stop_info_sp = GetPrivateStopInfo ();
+
+ // If our subplan knows why we stopped, even if it's done (which would forward the question to us)
+ // we answer yes.
+ if (m_subplan_sp.get() != NULL && m_subplan_sp->PlanExplainsStop(event_ptr))
+ {
+ SetPlanComplete();
+ return true;
+ }
+
+ // Check if the breakpoint is one of ours.
+
+ StopReason stop_reason;
+ if (!m_real_stop_info_sp)
+ stop_reason = eStopReasonNone;
+ else
+ stop_reason = m_real_stop_info_sp->GetStopReason();
+ if (log)
+ log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - %s.", Thread::StopReasonAsCString(stop_reason));
+
+ if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop())
+ return true;
+
+ // We control breakpoints separately from other "stop reasons." So first,
+ // check the case where we stopped for an internal breakpoint, in that case, continue on.
+ // If it is not an internal breakpoint, consult m_ignore_breakpoints.
+
+
+ if (stop_reason == eStopReasonBreakpoint)
+ {
+ ProcessSP process_sp (m_thread.CalculateProcess());
+ uint64_t break_site_id = m_real_stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id);
+ if (bp_site_sp)
+ {
+ uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+ bool is_internal = true;
+ for (uint32_t i = 0; i < num_owners; i++)
+ {
+ Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+ if (log)
+ log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: hit breakpoint %d while calling function", bp.GetID());
+
+ if (!bp.IsInternal())
+ {
+ is_internal = false;
+ break;
+ }
+ }
+ if (is_internal)
+ {
+ if (log)
+ log->Printf ("ThreadPlanCallFunction::PlanExplainsStop hit an internal breakpoint, not stopping.");
+ return false;
+ }
+ }
+
+ if (m_ignore_breakpoints)
+ {
+ if (log)
+ log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true");
+ m_real_stop_info_sp->OverrideShouldStop(false);
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are not ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true");
+ m_real_stop_info_sp->OverrideShouldStop(true);
+ return false;
+ }
+ }
+ else if (!m_unwind_on_error)
+ {
+ // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack.
+ return false;
+ }
+ else
+ {
+ // If the subplan is running, any crashes are attributable to us.
+ // If we want to discard the plan, then we say we explain the stop
+ // but if we are going to be discarded, let whoever is above us
+ // explain the stop.
+ // But don't discard the plan if the stop would restart itself (for instance if it is a
+ // signal that is set not to stop. Check that here first. We just say we explain the stop
+ // but aren't done and everything will continue on from there.
+
+ if (m_real_stop_info_sp->ShouldStopSynchronous(event_ptr))
+ {
+ SetPlanComplete(false);
+ if (m_subplan_sp)
+ {
+ if (m_unwind_on_error)
+ return true;
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return true;
+ }
+}
+
+bool
+ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
+{
+ // We do some computation in DoPlanExplainsStop that may or may not set the plan as complete.
+ // We need to do that here to make sure our state is correct.
+ DoPlanExplainsStop(event_ptr);
+
+ if (IsPlanComplete())
+ {
+ ReportRegisterState ("Function completed. Register state was:");
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+ThreadPlanCallFunction::StopOthers ()
+{
+ return m_stop_other_threads;
+}
+
+void
+ThreadPlanCallFunction::SetStopOthers (bool new_value)
+{
+ if (m_subplan_sp)
+ {
+ ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
+ address_plan->SetStopOthers(new_value);
+ }
+ m_stop_other_threads = new_value;
+}
+
+StateType
+ThreadPlanCallFunction::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+void
+ThreadPlanCallFunction::DidPush ()
+{
+//#define SINGLE_STEP_EXPRESSIONS
+
+ // Now set the thread state to "no reason" so we don't run with whatever signal was outstanding...
+ // Wait till the plan is pushed so we aren't changing the stop info till we're about to run.
+
+ GetThread().SetStopInfoToNothing();
+
+#ifndef SINGLE_STEP_EXPRESSIONS
+ m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads));
+
+ m_thread.QueueThreadPlan(m_subplan_sp, false);
+ m_subplan_sp->SetPrivate (true);
+#endif
+}
+
+bool
+ThreadPlanCallFunction::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanCallFunction::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (IsPlanComplete())
+ {
+ if (log)
+ log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", this);
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void
+ThreadPlanCallFunction::SetBreakpoints ()
+{
+ ProcessSP process_sp (m_thread.CalculateProcess());
+ if (process_sp)
+ {
+ m_cxx_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus);
+ m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC);
+
+ if (m_cxx_language_runtime)
+ m_cxx_language_runtime->SetExceptionBreakpoints();
+ if (m_objc_language_runtime)
+ m_objc_language_runtime->SetExceptionBreakpoints();
+ }
+}
+
+void
+ThreadPlanCallFunction::ClearBreakpoints ()
+{
+ if (m_cxx_language_runtime)
+ m_cxx_language_runtime->ClearExceptionBreakpoints();
+ if (m_objc_language_runtime)
+ m_objc_language_runtime->ClearExceptionBreakpoints();
+}
+
+bool
+ThreadPlanCallFunction::BreakpointsExplainStop()
+{
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+
+ if ((m_cxx_language_runtime &&
+ m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))
+ ||(m_objc_language_runtime &&
+ m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)))
+ {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete.");
+
+ SetPlanComplete(false);
+
+ // If the user has set the ObjC language breakpoint, it would normally get priority over our internal
+ // catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here.
+ stop_info_sp->OverrideShouldStop (true);
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ThreadPlanCallFunction::RestoreThreadState()
+{
+ return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state);
+}
+
diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp
new file mode 100644
index 000000000000..70de1cbe86e1
--- /dev/null
+++ b/source/Target/ThreadPlanCallUserExpression.cpp
@@ -0,0 +1,82 @@
+//===-- ThreadPlanCallUserExpression.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/ThreadPlanCallUserExpression.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/Support/MachO.h"
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanCallUserExpression: Plan to call a single function
+//----------------------------------------------------------------------
+
+ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread,
+ Address &function,
+ lldb::addr_t arg,
+ bool stop_other_threads,
+ bool unwind_on_error,
+ bool ignore_breakpoints,
+ lldb::addr_t *this_arg,
+ lldb::addr_t *cmd_arg,
+ ClangUserExpression::ClangUserExpressionSP &user_expression_sp) :
+ ThreadPlanCallFunction (thread, function, ClangASTType(), arg, stop_other_threads, unwind_on_error, ignore_breakpoints, this_arg, cmd_arg),
+ m_user_expression_sp (user_expression_sp)
+{
+ // User expressions are generally "User generated" so we should set them up to stop when done.
+ SetIsMasterPlan (true);
+ SetOkayToDiscard(false);
+}
+
+ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression ()
+{
+}
+
+void
+ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ ThreadPlanCallFunction::GetDescription (s, level);
+}
+
+StopInfoSP
+ThreadPlanCallUserExpression::GetRealStopInfo()
+{
+ StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo();
+
+ if (stop_info_sp)
+ {
+ lldb::addr_t addr = GetStopAddress();
+ DynamicCheckerFunctions *checkers = m_thread.GetProcess()->GetDynamicCheckers();
+ StreamString s;
+
+ if (checkers && checkers->DoCheckersExplainStop(addr, s))
+ stop_info_sp->SetDescription(s.GetData());
+ }
+
+ return stop_info_sp;
+}
diff --git a/source/Target/ThreadPlanRunToAddress.cpp b/source/Target/ThreadPlanRunToAddress.cpp
new file mode 100644
index 000000000000..86825d2eb26b
--- /dev/null
+++ b/source/Target/ThreadPlanRunToAddress.cpp
@@ -0,0 +1,268 @@
+//===-- ThreadPlanRunToAddress.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/ThreadPlanRunToAddress.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanRunToAddress: Continue plan
+//----------------------------------------------------------------------
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ Address &address,
+ bool stop_others
+) :
+ ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_addresses (),
+ m_break_ids ()
+{
+ m_addresses.push_back (address.GetOpcodeLoadAddress (m_thread.CalculateTarget().get()));
+ SetInitialBreakpoints();
+}
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ lldb::addr_t address,
+ bool stop_others
+) :
+ ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_addresses (),
+ m_break_ids ()
+{
+ m_addresses.push_back(m_thread.CalculateTarget()->GetOpcodeLoadAddress(address));
+ SetInitialBreakpoints();
+}
+
+ThreadPlanRunToAddress::ThreadPlanRunToAddress
+(
+ Thread &thread,
+ const std::vector<lldb::addr_t> &addresses,
+ bool stop_others
+) :
+ ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_stop_others (stop_others),
+ m_addresses (addresses),
+ m_break_ids ()
+{
+ // Convert all addressses into opcode addresses to make sure we set
+ // breakpoints at the correct address.
+ Target &target = thread.GetProcess()->GetTarget();
+ std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end();
+ for (pos = m_addresses.begin(); pos != end; ++pos)
+ *pos = target.GetOpcodeLoadAddress (*pos);
+
+ SetInitialBreakpoints();
+}
+
+void
+ThreadPlanRunToAddress::SetInitialBreakpoints ()
+{
+ size_t num_addresses = m_addresses.size();
+ m_break_ids.resize(num_addresses);
+
+ for (size_t i = 0; i < num_addresses; i++)
+ {
+ Breakpoint *breakpoint;
+ breakpoint = m_thread.CalculateTarget()->CreateBreakpoint (m_addresses[i], true).get();
+ if (breakpoint != NULL)
+ {
+ m_break_ids[i] = breakpoint->GetID();
+ breakpoint->SetThreadID(m_thread.GetID());
+ breakpoint->SetBreakpointKind("run-to-address");
+ }
+ }
+}
+
+ThreadPlanRunToAddress::~ThreadPlanRunToAddress ()
+{
+ size_t num_break_ids = m_break_ids.size();
+ for (size_t i = 0; i < num_break_ids; i++)
+ {
+ m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]);
+ }
+}
+
+void
+ThreadPlanRunToAddress::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ size_t num_addresses = m_addresses.size();
+
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ if (num_addresses == 0)
+ {
+ s->Printf ("run to address with no addresses given.");
+ return;
+ }
+ else if (num_addresses == 1)
+ s->Printf ("run to address: ");
+ else
+ s->Printf ("run to addresses: ");
+
+ for (size_t i = 0; i < num_addresses; i++)
+ {
+ s->Address (m_addresses[i], sizeof (addr_t));
+ s->Printf(" ");
+ }
+ }
+ else
+ {
+ if (num_addresses == 0)
+ {
+ s->Printf ("run to address with no addresses given.");
+ return;
+ }
+ else if (num_addresses == 1)
+ s->Printf ("Run to address: ");
+ else
+ {
+ s->Printf ("Run to addresses: ");
+ }
+
+ for (size_t i = 0; i < num_addresses; i++)
+ {
+ if (num_addresses > 1)
+ {
+ s->Printf("\n");
+ s->Indent();
+ }
+
+ s->Address(m_addresses[i], sizeof (addr_t));
+ s->Printf (" using breakpoint: %d - ", m_break_ids[i]);
+ Breakpoint *breakpoint = m_thread.CalculateTarget()->GetBreakpointByID (m_break_ids[i]).get();
+ if (breakpoint)
+ breakpoint->Dump (s);
+ else
+ s->Printf ("but the breakpoint has been deleted.");
+ }
+ }
+}
+
+bool
+ThreadPlanRunToAddress::ValidatePlan (Stream *error)
+{
+ // If we couldn't set the breakpoint for some reason, then this won't
+ // work.
+ bool all_bps_good = true;
+ size_t num_break_ids = m_break_ids.size();
+
+ for (size_t i = 0; i < num_break_ids; i++)
+ {
+ if (m_break_ids[i] == LLDB_INVALID_BREAK_ID)
+ {
+ all_bps_good = false;
+ if (error)
+ {
+ error->Printf ("Could not set breakpoint for address: ");
+ error->Address (m_addresses[i], sizeof (addr_t));
+ error->Printf ("\n");
+ }
+ }
+ }
+ return all_bps_good;
+}
+
+bool
+ThreadPlanRunToAddress::DoPlanExplainsStop (Event *event_ptr)
+{
+ return AtOurAddress();
+}
+
+bool
+ThreadPlanRunToAddress::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanRunToAddress::StopOthers ()
+{
+ return m_stop_others;
+}
+
+void
+ThreadPlanRunToAddress::SetStopOthers (bool new_value)
+{
+ m_stop_others = new_value;
+}
+
+StateType
+ThreadPlanRunToAddress::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanRunToAddress::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanRunToAddress::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (AtOurAddress())
+ {
+ // Remove the breakpoint
+ size_t num_break_ids = m_break_ids.size();
+
+ for (size_t i = 0; i < num_break_ids; i++)
+ {
+ if (m_break_ids[i] != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]);
+ m_break_ids[i] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+ if (log)
+ log->Printf("Completed run to address plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+ThreadPlanRunToAddress::AtOurAddress ()
+{
+ lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC();
+ bool found_it = false;
+ size_t num_addresses = m_addresses.size();
+ for (size_t i = 0; i < num_addresses; i++)
+ {
+ if (m_addresses[i] == current_address)
+ {
+ found_it = true;
+ break;
+ }
+ }
+ return found_it;
+}
diff --git a/source/Target/ThreadPlanShouldStopHere.cpp b/source/Target/ThreadPlanShouldStopHere.cpp
new file mode 100644
index 000000000000..87662345a06d
--- /dev/null
+++ b/source/Target/ThreadPlanShouldStopHere.cpp
@@ -0,0 +1,74 @@
+//===-- ThreadPlanShouldStopHere.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/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanShouldStopHere.h"
+#include "lldb/Core/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+//----------------------------------------------------------------------
+// ThreadPlanShouldStopHere constructor
+//----------------------------------------------------------------------
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) :
+ m_callback (callback),
+ m_baton (baton),
+ m_owner (owner),
+ m_flags (ThreadPlanShouldStopHere::eNone)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
+{
+}
+
+void
+ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton)
+{
+ m_callback = callback;
+ m_baton = baton;
+}
+
+ThreadPlanSP
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
+{
+ if (m_callback)
+ {
+ ThreadPlanSP return_plan_sp(m_callback (m_owner, m_flags, m_baton));
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0);
+
+ if (return_plan_sp)
+ {
+ StreamString s;
+ return_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
+ log->Printf ("ShouldStopHere callback found a step out plan from 0x%" PRIx64 ": %s.", current_addr, s.GetData());
+ }
+ else
+ {
+ log->Printf ("ShouldStopHere callback didn't find a step out plan from: 0x%" PRIx64 ".", current_addr);
+ }
+ }
+ return return_plan_sp;
+ }
+ else
+ return ThreadPlanSP();
+}
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
new file mode 100644
index 000000000000..c1f14bd216de
--- /dev/null
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -0,0 +1,485 @@
+//===-- ThreadPlanStepInRange.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/ThreadPlanStepInRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+#include "lldb/Core/RegularExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepInRange::ThreadPlanStepInRange
+(
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others
+) :
+ ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ m_step_past_prologue (true),
+ m_virtual_step (false)
+{
+ SetFlagsToDefault ();
+}
+
+ThreadPlanStepInRange::ThreadPlanStepInRange
+(
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ const char *step_into_target,
+ lldb::RunMode stop_others
+) :
+ ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others),
+ ThreadPlanShouldStopHere (this, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ m_step_past_prologue (true),
+ m_virtual_step (false),
+ m_step_into_target (step_into_target)
+{
+ SetFlagsToDefault ();
+}
+
+ThreadPlanStepInRange::~ThreadPlanStepInRange ()
+{
+}
+
+void
+ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("step in");
+ else
+ {
+ s->Printf ("Stepping through range (stepping into functions): ");
+ 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('.');
+ }
+}
+
+bool
+ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (log)
+ {
+ StreamString s;
+ s.Address (m_thread.GetRegisterContext()->GetPC(),
+ m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ log->Printf("ThreadPlanStepInRange reached %s.", s.GetData());
+ }
+
+ if (IsPlanComplete())
+ return true;
+
+ m_no_more_plans = false;
+ if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete())
+ {
+ if (!m_sub_plan_sp->PlanSucceeded())
+ {
+ SetPlanComplete();
+ m_no_more_plans = true;
+ return true;
+ }
+ else
+ m_sub_plan_sp.reset();
+ }
+
+ if (m_virtual_step)
+ {
+ // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
+ // we're done.
+ m_sub_plan_sp = InvokeShouldStopHereCallback();
+ }
+ else
+ {
+ // Stepping through should be done running other threads in general, since we're setting a breakpoint and
+ // continuing. So only stop others if we are explicitly told to do so.
+
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = false;
+ else
+ stop_others = true;
+
+ FrameComparison frame_order = CompareCurrentFrameToStartFrame();
+
+ if (frame_order == eFrameCompareOlder)
+ {
+ // If we're in an older frame then we should stop.
+ //
+ // A caveat to this is if we think the frame is older but we're actually in a trampoline.
+ // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
+ // in a trampoline we think the frame is older because the trampoline confused the backtracer.
+ m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+ if (!m_sub_plan_sp)
+ return true;
+ else if (log)
+ {
+ log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
+ }
+
+ }
+ else if (frame_order == eFrameCompareEqual && InSymbol())
+ {
+ // If we are not in a place we should step through, we're done.
+ // One tricky bit here is that some stubs don't push a frame, so we have to check
+ // both the case of a frame that is younger, or the same as this frame.
+ // However, if the frame is the same, and we are still in the symbol we started
+ // in, the we don't need to do this. This first check isn't strictly necessary,
+ // but it is more efficient.
+
+ // If we're still in the range, keep going, either by running to the next branch breakpoint, or by
+ // stepping.
+ if (InRange())
+ {
+ SetNextBranchBreakpoint();
+ return false;
+ }
+
+ SetPlanComplete();
+ m_no_more_plans = true;
+ return true;
+ }
+
+ // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
+ ClearNextBranchBreakpoint();
+
+ // We may have set the plan up above in the FrameIsOlder section:
+
+ if (!m_sub_plan_sp)
+ m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+
+ if (log)
+ {
+ if (m_sub_plan_sp)
+ log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName());
+ else
+ log->Printf ("No step through plan found.");
+ }
+
+ // If not, give the "should_stop" callback a chance to push a plan to get us out of here.
+ // But only do that if we actually have stepped in.
+ if (!m_sub_plan_sp && frame_order == eFrameCompareYounger)
+ m_sub_plan_sp = InvokeShouldStopHereCallback();
+
+ // If we've stepped in and we are going to stop here, check to see if we were asked to
+ // run past the prologue, and if so do that.
+
+ if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue)
+ {
+ lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0);
+ if (curr_frame)
+ {
+ size_t bytes_to_skip = 0;
+ lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC();
+ Address func_start_address;
+
+ SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol);
+
+ if (sc.function)
+ {
+ func_start_address = sc.function->GetAddressRange().GetBaseAddress();
+ if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
+ bytes_to_skip = sc.function->GetPrologueByteSize();
+ }
+ else if (sc.symbol)
+ {
+ func_start_address = sc.symbol->GetAddress();
+ if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get()))
+ bytes_to_skip = sc.symbol->GetPrologueByteSize();
+ }
+
+ if (bytes_to_skip != 0)
+ {
+ func_start_address.Slide (bytes_to_skip);
+ log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
+ if (log)
+ log->Printf ("Pushing past prologue ");
+
+ m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true);
+ }
+ }
+ }
+ }
+
+ if (!m_sub_plan_sp)
+ {
+ m_no_more_plans = true;
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ m_no_more_plans = false;
+ return false;
+ }
+}
+
+void
+ThreadPlanStepInRange::SetFlagsToDefault ()
+{
+ GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
+}
+
+void
+ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
+{
+ if (m_avoid_regexp_ap.get() == NULL)
+ m_avoid_regexp_ap.reset (new RegularExpression(name));
+
+ m_avoid_regexp_ap->Compile (name);
+}
+
+void
+ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value)
+{
+ // TODO: Should we test this for sanity?
+ ThreadPlanStepInRange::s_default_flag_values = new_value;
+}
+
+bool
+ThreadPlanStepInRange::FrameMatchesAvoidRegexp ()
+{
+ StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get();
+
+ const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get();
+ if (avoid_regexp_to_use == NULL)
+ avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp();
+
+ if (avoid_regexp_to_use != NULL)
+ {
+ SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
+ if (sc.symbol != NULL)
+ {
+ const char *frame_function_name = sc.GetFunctionName().GetCString();
+ if (frame_function_name)
+ {
+ size_t num_matches = 0;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ num_matches = 1;
+
+ RegularExpression::Match regex_match(num_matches);
+
+ bool return_value = avoid_regexp_to_use->Execute(frame_function_name, &regex_match);
+ if (return_value)
+ {
+ if (log)
+ {
+ std::string match;
+ regex_match.GetMatchAtIndex(frame_function_name,0, match);
+ log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".",
+ frame_function_name,
+ avoid_regexp_to_use->GetText(),
+ match.c_str());
+ }
+
+ }
+ return return_value;
+ }
+ }
+ }
+ return false;
+}
+
+ThreadPlanSP
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+{
+ bool should_step_out = false;
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (flags.Test(eAvoidNoDebug))
+ {
+ if (!frame->HasDebugInformation())
+ {
+ if (log)
+ log->Printf ("Stepping out of frame with no debug info");
+
+ should_step_out = true;
+ }
+ }
+
+ if (current_plan->GetKind() == eKindStepInRange)
+ {
+ ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
+ if (step_in_range_plan->m_step_into_target)
+ {
+ SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol);
+ if (sc.symbol != NULL)
+ {
+ // First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare.
+ if (step_in_range_plan->m_step_into_target == sc.GetFunctionName())
+ {
+ should_step_out = false;
+ }
+ else
+ {
+ const char *target_name = step_in_range_plan->m_step_into_target.AsCString();
+ const char *function_name = sc.GetFunctionName().AsCString();
+
+ if (function_name == NULL)
+ should_step_out = true;
+ else if (strstr (function_name, target_name) == NULL)
+ should_step_out = true;
+ }
+ if (log && should_step_out)
+ log->Printf("Stepping out of frame %s which did not match step into target %s.",
+ sc.GetFunctionName().AsCString(),
+ step_in_range_plan->m_step_into_target.AsCString());
+ }
+ }
+
+ if (!should_step_out)
+ {
+ ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan);
+ // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidRegexp.
+ should_step_out = step_in_range_plan->FrameMatchesAvoidRegexp ();
+ }
+ }
+
+
+ if (should_step_out)
+ {
+ // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
+ // We really should have all plans take the tri-state for "stop others" so we can do the right
+ // thing. For now let's be safe and always run others when we are likely to run arbitrary code.
+ const bool stop_others = false;
+ return current_plan->GetThread().QueueThreadPlanForStepOut (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0); // Frame index
+ }
+
+ return ThreadPlanSP();
+}
+
+bool
+ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr)
+{
+ // We always explain a stop. Either we've just done a single step, in which
+ // case we'll do our ordinary processing, or we stopped for some
+ // reason that isn't handled by our sub-plans, in which case we want to just stop right
+ // away.
+ // In general, we don't want to mark the plan as complete for unexplained stops.
+ // For instance, if you step in to some code with no debug info, so you step out
+ // and in the course of that hit a breakpoint, then you want to stop & show the user
+ // the breakpoint, but not unship the step in plan, since you still may want to complete that
+ // plan when you continue. This is particularly true when doing "step in to target function."
+ // stepping.
+ //
+ // The only variation is that if we are doing "step by running to next branch" in which case
+ // if we hit our branch breakpoint we don't set the plan to complete.
+
+ bool return_value;
+
+ if (m_virtual_step)
+ {
+ return_value = true;
+ }
+ else
+ {
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ if (NextRangeBreakpointExplainsStop(stop_info_sp))
+ {
+ return_value = true;
+ break;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
+ }
+ return_value = false;
+ break;
+ default:
+ return_value = true;
+ break;
+ }
+ }
+ else
+ return_value = true;
+ }
+
+ return return_value;
+}
+
+bool
+ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan)
+{
+ if (resume_state == eStateStepping && current_plan)
+ {
+ // See if we are about to step over a virtual inlined call.
+ bool step_without_resume = m_thread.DecrementCurrentInlinedDepth();
+ if (step_without_resume)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d",
+ m_thread.GetCurrentInlinedDepth());
+ SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread));
+
+ // FIXME: Maybe it would be better to create a InlineStep stop reason, but then
+ // the whole rest of the world would have to handle that stop reason.
+ m_virtual_step = true;
+ }
+ return !step_without_resume;
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepInRange::IsVirtualStep()
+{
+ return m_virtual_step;
+}
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
new file mode 100644
index 000000000000..f644ee88f701
--- /dev/null
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -0,0 +1,227 @@
+//===-- ThreadPlanStepInstruction.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/ThreadPlanStepInstruction.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepInstruction: Step over the current instruction
+//----------------------------------------------------------------------
+
+ThreadPlanStepInstruction::ThreadPlanStepInstruction
+(
+ Thread &thread,
+ bool step_over,
+ bool stop_other_threads,
+ Vote stop_vote,
+ Vote run_vote
+) :
+ ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote),
+ m_instruction_addr (0),
+ m_stop_other_threads (stop_other_threads),
+ m_step_over (step_over)
+{
+ m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
+ StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0));
+ m_stack_id = m_start_frame_sp->GetStackID();
+
+ m_start_has_symbol = m_start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
+
+ StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
+ if (parent_frame_sp)
+ m_parent_frame_id = parent_frame_sp->GetStackID();
+}
+
+ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
+{
+}
+
+void
+ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ if (m_step_over)
+ s->Printf ("instruction step over");
+ else
+ s->Printf ("instruction step into");
+ }
+ else
+ {
+ s->Printf ("Stepping one instruction past ");
+ s->Address(m_instruction_addr, sizeof (addr_t));
+ if (!m_start_has_symbol)
+ s->Printf(" which has no symbol");
+
+ if (m_step_over)
+ s->Printf(" stepping over calls");
+ else
+ s->Printf(" stepping into calls");
+ }
+}
+
+bool
+ThreadPlanStepInstruction::ValidatePlan (Stream *error)
+{
+ // Since we read the instruction we're stepping over from the thread,
+ // this plan will always work.
+ return true;
+}
+
+bool
+ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
+{
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+ if (reason == eStopReasonTrace || reason == eStopReasonNone)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool
+ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
+{
+ if (m_step_over)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ // We've stepped in, step back out again:
+ StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get();
+ if (return_frame)
+ {
+ if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
+ {
+ if (log)
+ {
+ StreamString s;
+ s.PutCString ("Stepped in to: ");
+ addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC();
+ s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ s.PutCString (" stepping out to: ");
+ addr_t return_addr = return_frame->GetRegisterContext()->GetPC();
+ s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ log->Printf("%s.", s.GetData());
+ }
+
+ // StepInstruction should probably have the tri-state RunMode, but for now it is safer to
+ // run others.
+ const bool stop_others = false;
+ m_thread.QueueThreadPlanForStepOut(false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
+ return false;
+ }
+ else
+ {
+ if (log)
+ {
+ log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols. "
+ "We are probably just confused about where we are, stopping.");
+ }
+ SetPlanComplete();
+ return true;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("Could not find previous frame, stopping.");
+ SetPlanComplete();
+ return true;
+ }
+
+ }
+
+ }
+ else
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ {
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepInstruction::StopOthers ()
+{
+ return m_stop_other_threads;
+}
+
+StateType
+ThreadPlanStepInstruction::GetPlanRunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepInstruction::WillStop ()
+{
+ return true;
+}
+
+bool
+ThreadPlanStepInstruction::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Completed single instruction step plan.");
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
new file mode 100644
index 000000000000..ba529587437d
--- /dev/null
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -0,0 +1,489 @@
+//===-- ThreadPlanStepOut.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/ThreadPlanStepOut.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanStepOverRange.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOut: Step out of the current frame
+//----------------------------------------------------------------------
+ThreadPlanStepOut::ThreadPlanStepOut
+(
+ Thread &thread,
+ SymbolContext *context,
+ bool first_insn,
+ bool stop_others,
+ Vote stop_vote,
+ Vote run_vote,
+ uint32_t frame_idx
+) :
+ ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
+ m_step_from_context (context),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_bp_id (LLDB_INVALID_BREAK_ID),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_first_insn (first_insn),
+ m_stop_others (stop_others),
+ m_step_through_inline_plan_sp(),
+ m_step_out_plan_sp (),
+ m_immediate_step_from_function(NULL)
+
+{
+ m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0);
+
+ StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
+ StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx));
+
+ if (!return_frame_sp || !immediate_return_from_sp)
+ return; // we can't do anything here. ValidatePlan() will return false.
+
+ m_step_out_to_id = return_frame_sp->GetStackID();
+ m_immediate_step_from_id = immediate_return_from_sp->GetStackID();
+
+ StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ // If the frame directly below the one we are returning to is inlined, we have to be
+ // a little more careful. It is non-trivial to determine the real "return code address" for
+ // an inlined frame, so we have to work our way to that frame and then step out.
+ if (immediate_return_from_sp && immediate_return_from_sp->IsInlined())
+ {
+ if (frame_idx > 0)
+ {
+ // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second
+ // plan that walks us out of this frame.
+ m_step_out_plan_sp.reset (new ThreadPlanStepOut(m_thread,
+ NULL,
+ false,
+ stop_others,
+ eVoteNoOpinion,
+ eVoteNoOpinion,
+ frame_idx - 1));
+ }
+ else
+ {
+ // If we're already at the inlined frame we're stepping through, then just do that now.
+ QueueInlinedStepPlan(false);
+ }
+
+ }
+ else if (return_frame_sp)
+ {
+ // Find the return address and set a breakpoint there:
+ // FIXME - can we do this more securely if we know first_insn?
+
+ m_return_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(&m_thread.GetProcess()->GetTarget());
+
+ if (m_return_addr == LLDB_INVALID_ADDRESS)
+ return;
+
+ Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(m_thread.GetID());
+ m_return_bp_id = return_bp->GetID();
+ return_bp->SetBreakpointKind ("step-out");
+ }
+
+ if (immediate_return_from_sp)
+ {
+ const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction);
+ if (sc.function)
+ {
+ m_immediate_step_from_function = sc.function;
+ }
+ }
+ }
+
+}
+
+void
+ThreadPlanStepOut::DidPush()
+{
+ if (m_step_out_plan_sp)
+ m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
+ else if (m_step_through_inline_plan_sp)
+ m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false);
+}
+
+ThreadPlanStepOut::~ThreadPlanStepOut ()
+{
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id);
+}
+
+void
+ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("step out");
+ else
+ {
+ if (m_step_out_plan_sp)
+ s->Printf ("Stepping out to inlined frame so we can walk through it.");
+ else if (m_step_through_inline_plan_sp)
+ s->Printf ("Stepping out by stepping through inlined function.");
+ 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);
+ }
+}
+
+bool
+ThreadPlanStepOut::ValidatePlan (Stream *error)
+{
+ if (m_step_out_plan_sp)
+ return m_step_out_plan_sp->ValidatePlan (error);
+ else if (m_step_through_inline_plan_sp)
+ return m_step_through_inline_plan_sp->ValidatePlan (error);
+ else if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ {
+ if (error)
+ error->PutCString("Could not create return address breakpoint.");
+ return false;
+ }
+ else
+ return true;
+}
+
+bool
+ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
+{
+ // If one of our child plans just finished, then we do explain the stop.
+ if (m_step_out_plan_sp)
+ {
+ if (m_step_out_plan_sp->MischiefManaged())
+ {
+ // If this one is done, then we are all done.
+ CalculateReturnValue();
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
+ return true;
+ else
+ return false;
+ }
+
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ {
+ // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
+ BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()));
+ if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id))
+ {
+ bool done;
+
+ StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ if (m_step_out_to_id == frame_zero_id)
+ done = true;
+ else if (m_step_out_to_id < frame_zero_id)
+ {
+ // Either we stepped past the breakpoint, or the stack ID calculation
+ // was incorrect and we should probably stop.
+ done = true;
+ }
+ else
+ {
+ if (m_immediate_step_from_id < frame_zero_id)
+ done = true;
+ else
+ done = false;
+ }
+
+ if (done)
+ {
+ CalculateReturnValue();
+ SetPlanComplete();
+ }
+
+ // If there was only one owner, then we're done. But if we also hit some
+ // user breakpoint on our way out, we should mark ourselves as done, but
+ // also not claim to explain the stop, since it is more important to report
+ // the user breakpoint than the step out completion.
+
+ if (site_sp->GetNumberOfOwners() == 1)
+ return true;
+
+ }
+ return false;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ return false;
+
+ default:
+ return true;
+ }
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::ShouldStop (Event *event_ptr)
+{
+ if (IsPlanComplete())
+ return true;
+
+ bool done;
+
+ StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ if (frame_zero_id < m_step_out_to_id)
+ done = false;
+ else
+ done = true;
+
+ if (done)
+ {
+ CalculateReturnValue();
+ SetPlanComplete();
+ return true;
+ }
+ else
+ {
+ if (m_step_out_plan_sp)
+ {
+ if (m_step_out_plan_sp->MischiefManaged())
+ {
+ // Now step through the inlined stack we are in:
+ if (QueueInlinedStepPlan(true))
+ {
+ return false;
+ }
+ else
+ {
+ CalculateReturnValue();
+ SetPlanComplete ();
+ return true;
+ }
+ }
+ else
+ return m_step_out_plan_sp->ShouldStop(event_ptr);
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
+ {
+ // We don't calculate the return value here because we don't know how to.
+ // But in case we had a return value sitting around from our process in
+ // getting here, let's clear it out.
+ m_return_valobj_sp.reset();
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
+ }
+ else
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepOut::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepOut::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan)
+{
+ if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
+ return true;
+
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+
+ if (current_plan)
+ {
+ Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (true);
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOut::WillStop ()
+{
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (false);
+ }
+
+ return true;
+}
+
+bool
+ThreadPlanStepOut::MischiefManaged ()
+{
+ if (IsPlanComplete())
+ {
+ // Did I reach my breakpoint? If so I'm done.
+ //
+ // I also check the stack depth, since if we've blown past the breakpoint for some
+ // reason and we're now stopping for some other reason altogether, then we're done
+ // with this step out operation.
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Completed step out plan.");
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool
+ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
+{
+ // Now figure out the range of this inlined block, and set up a "step through range"
+ // plan for that. If we've been provided with a context, then use the block in that
+ // context.
+ StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0));
+ if (!immediate_return_from_sp)
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ StreamString s;
+ immediate_return_from_sp->Dump(&s, true, false);
+ log->Printf("Queuing inlined frame to step past: %s.", s.GetData());
+ }
+
+ Block *from_block = immediate_return_from_sp->GetFrameBlock();
+ if (from_block)
+ {
+ Block *inlined_block = from_block->GetContainingInlinedBlock();
+ if (inlined_block)
+ {
+ size_t num_ranges = inlined_block->GetNumRanges();
+ AddressRange inline_range;
+ if (inlined_block->GetRangeAtIndex(0, inline_range))
+ {
+ SymbolContext inlined_sc;
+ inlined_block->CalculateSymbolContext(&inlined_sc);
+ inlined_sc.target_sp = GetTarget().shared_from_this();
+ RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads;
+ ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
+ inline_range,
+ inlined_sc,
+ run_mode);
+ step_through_inline_plan_ptr->SetOkayToDiscard(true);
+ StreamString errors;
+ if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
+ {
+ //FIXME: Log this failure.
+ delete step_through_inline_plan_ptr;
+ return false;
+ }
+
+ for (size_t i = 1; i < num_ranges; i++)
+ {
+ 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;
+ }
+ }
+ }
+
+ return false;
+}
+
+void
+ThreadPlanStepOut::CalculateReturnValue ()
+{
+ if (m_return_valobj_sp)
+ return;
+
+ if (m_immediate_step_from_function != NULL)
+ {
+ ClangASTType return_clang_type = m_immediate_step_from_function->GetClangType().GetFunctionReturnType();
+ if (return_clang_type)
+ {
+ lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI();
+ if (abi_sp)
+ m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, return_clang_type);
+ }
+ }
+}
+
+bool
+ThreadPlanStepOut::IsPlanStale()
+{
+ // If we are still lower on the stack than the frame we are returning to, then
+ // there's something for us to do. Otherwise, we're stale.
+
+ StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ if (frame_zero_id < m_step_out_to_id)
+ return false;
+ else
+ return true;
+}
+
diff --git a/source/Target/ThreadPlanStepOverBreakpoint.cpp b/source/Target/ThreadPlanStepOverBreakpoint.cpp
new file mode 100644
index 000000000000..dc011e545402
--- /dev/null
+++ b/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -0,0 +1,165 @@
+//===-- ThreadPlanStepOverBreakpoint.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/ThreadPlanStepOverBreakpoint.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOverBreakpoint: Single steps over a breakpoint bp_site_sp at the pc.
+//----------------------------------------------------------------------
+
+ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint (Thread &thread) :
+ ThreadPlan (ThreadPlan::eKindStepOverBreakpoint, "Step over breakpoint trap",
+ thread,
+ eVoteNo,
+ eVoteNoOpinion), // We need to report the run since this happens
+ // first in the thread plan stack when stepping
+ // over a breakpoint
+ m_breakpoint_addr (LLDB_INVALID_ADDRESS),
+ m_auto_continue(false),
+ m_reenabled_breakpoint_site (false)
+
+{
+ m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC();
+ m_breakpoint_site_id = m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress (m_breakpoint_addr);
+}
+
+ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint ()
+{
+}
+
+void
+ThreadPlanStepOverBreakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ s->Printf("Single stepping past breakpoint site %" PRIu64 " at 0x%" PRIx64, m_breakpoint_site_id, (uint64_t)m_breakpoint_addr);
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr)
+{
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+ if (reason == eStopReasonTrace || reason == eStopReasonNone)
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr)
+{
+ return false;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::StopOthers ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepOverBreakpoint::GetPlanRunState ()
+{
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::DoWillResume (StateType resume_state, bool current_plan)
+{
+ if (current_plan)
+ {
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ m_thread.GetProcess()->DisableBreakpointSite (bp_site_sp.get());
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::WillStop ()
+{
+ ReenableBreakpointSite ();
+ return true;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::MischiefManaged ()
+{
+ lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC();
+
+ if (pc_addr == m_breakpoint_addr)
+ {
+ // If we are still at the PC of our breakpoint, then for some reason we didn't
+ // get a chance to run.
+ return false;
+ }
+ else
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Completed step over breakpoint plan.");
+ // Otherwise, re-enable the breakpoint we were stepping over, and we're done.
+ ReenableBreakpointSite ();
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
+void
+ThreadPlanStepOverBreakpoint::ReenableBreakpointSite ()
+{
+ if (!m_reenabled_breakpoint_site)
+ {
+ m_reenabled_breakpoint_site = true;
+ BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress (m_breakpoint_addr));
+ if (bp_site_sp)
+ {
+ m_thread.GetProcess()->EnableBreakpointSite (bp_site_sp.get());
+ }
+ }
+}
+void
+ThreadPlanStepOverBreakpoint::ThreadDestroyed ()
+{
+ ReenableBreakpointSite ();
+}
+
+void
+ThreadPlanStepOverBreakpoint::SetAutoContinue (bool do_it)
+{
+ m_auto_continue = do_it;
+}
+
+bool
+ThreadPlanStepOverBreakpoint::ShouldAutoContinue (Event *event_ptr)
+{
+ return m_auto_continue;
+}
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
new file mode 100644
index 000000000000..7b8539ce422b
--- /dev/null
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -0,0 +1,388 @@
+//===-- ThreadPlanStepOverRange.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/ThreadPlanStepOverRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+
+//----------------------------------------------------------------------
+// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepOverRange::ThreadPlanStepOverRange
+(
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others
+) :
+ ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others),
+ m_first_resume(true)
+{
+}
+
+ThreadPlanStepOverRange::~ThreadPlanStepOverRange ()
+{
+}
+
+void
+ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf("step over");
+ else
+ {
+ s->Printf ("stepping through range (stepping over functions): ");
+ DumpRanges(s);
+ }
+}
+
+bool
+ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (log)
+ {
+ StreamString s;
+ s.Address (m_thread.GetRegisterContext()->GetPC(),
+ m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize());
+ log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData());
+ }
+
+ // If we're out of the range but in the same frame or in our caller's frame
+ // then we should stop.
+ // When stepping out we only stop others if we are forcing running one thread.
+ bool stop_others;
+ if (m_stop_others == lldb::eOnlyThisThread)
+ stop_others = true;
+ else
+ stop_others = false;
+
+ ThreadPlanSP new_plan_sp;
+
+ FrameComparison frame_order = CompareCurrentFrameToStartFrame();
+
+ if (frame_order == eFrameCompareOlder)
+ {
+ // If we're in an older frame then we should stop.
+ //
+ // A caveat to this is if we think the frame is older but we're actually in a trampoline.
+ // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are
+ // in a trampoline we think the frame is older because the trampoline confused the backtracer.
+ // As below, we step through first, and then try to figure out how to get back out again.
+
+ new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+
+ if (new_plan_sp && log)
+ log->Printf("Thought I stepped out, but in fact arrived at a trampoline.");
+ }
+ else if (frame_order == eFrameCompareYounger)
+ {
+ // Make sure we really are in a new frame. Do that by unwinding and seeing if the
+ // start function really is our start function...
+ StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
+
+ // But if we can't even unwind one frame we should just get out of here & stop...
+ if (older_frame_sp)
+ {
+ const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
+
+ // Match as much as is specified in the m_addr_context:
+ // This is a fairly loose sanity check. Note, sometimes the target doesn't get filled
+ // in so I left out the target check. And sometimes the module comes in as the .o file from the
+ // inlined range, so I left that out too...
+
+ bool older_ctx_is_equivalent = true;
+ if (m_addr_context.comp_unit)
+ {
+ if (m_addr_context.comp_unit == older_context.comp_unit)
+ {
+ if (m_addr_context.function && m_addr_context.function == older_context.function)
+ {
+ if (m_addr_context.block && m_addr_context.block == older_context.block)
+ {
+ older_ctx_is_equivalent = true;
+ }
+ }
+ }
+ }
+ else if (m_addr_context.symbol && m_addr_context.symbol == older_context.symbol)
+ {
+ older_ctx_is_equivalent = true;
+ }
+
+ if (older_ctx_is_equivalent)
+ {
+ new_plan_sp = m_thread.QueueThreadPlanForStepOut (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
+ }
+ else
+ {
+ new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+
+ }
+ }
+ }
+ else
+ {
+ // If we're still in the range, keep going.
+ if (InRange())
+ {
+ SetNextBranchBreakpoint();
+ return false;
+ }
+
+
+ if (!InSymbol())
+ {
+ // This one is a little tricky. Sometimes we may be in a stub or something similar,
+ // in which case we need to get out of there. But if we are in a stub then it's
+ // likely going to be hard to get out from here. It is probably easiest to step into the
+ // stub, and then it will be straight-forward to step out.
+ new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others);
+ }
+ else
+ {
+ // The current clang (at least through 424) doesn't always get the address range for the
+ // DW_TAG_inlined_subroutines right, so that when you leave the inlined range the line table says
+ // you are still in the source file of the inlining function. This is bad, because now you are missing
+ // the stack frame for the function containing the inlining, and if you sensibly do "finish" to get
+ // out of this function you will instead exit the containing function.
+ // To work around this, we check whether we are still in the source file we started in, and if not assume
+ // it is an error, and push a plan to get us out of this line and back to the containing file.
+
+ if (m_addr_context.line_entry.IsValid())
+ {
+ SymbolContext sc;
+ StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0);
+ sc = frame_sp->GetSymbolContext (eSymbolContextEverything);
+ if (sc.line_entry.IsValid())
+ {
+ if (sc.line_entry.file != m_addr_context.line_entry.file
+ && sc.comp_unit == m_addr_context.comp_unit
+ && sc.function == m_addr_context.function)
+ {
+ // Okay, find the next occurance of this file in the line table:
+ LineTable *line_table = m_addr_context.comp_unit->GetLineTable();
+ if (line_table)
+ {
+ Address cur_address = frame_sp->GetFrameCodeAddress();
+ uint32_t entry_idx;
+ LineEntry line_entry;
+ if (line_table->FindLineEntryByAddress (cur_address, line_entry, &entry_idx))
+ {
+ LineEntry next_line_entry;
+ bool step_past_remaining_inline = false;
+ if (entry_idx > 0)
+ {
+ // We require the the previous line entry and the current line entry come
+ // from the same file.
+ // The other requirement is that the previous line table entry be part of an
+ // inlined block, we don't want to step past cases where people have inlined
+ // some code fragment by using #include <source-fragment.c> directly.
+ LineEntry prev_line_entry;
+ if (line_table->GetLineEntryAtIndex(entry_idx - 1, prev_line_entry)
+ && prev_line_entry.file == line_entry.file)
+ {
+ SymbolContext prev_sc;
+ Address prev_address = prev_line_entry.range.GetBaseAddress();
+ prev_address.CalculateSymbolContext(&prev_sc);
+ if (prev_sc.block)
+ {
+ Block *inlined_block = prev_sc.block->GetContainingInlinedBlock();
+ if (inlined_block)
+ {
+ AddressRange inline_range;
+ inlined_block->GetRangeContainingAddress(prev_address, inline_range);
+ if (!inline_range.ContainsFileAddress(cur_address))
+ {
+
+ step_past_remaining_inline = true;
+ }
+
+ }
+ }
+ }
+ }
+
+ if (step_past_remaining_inline)
+ {
+ uint32_t look_ahead_step = 1;
+ while (line_table->GetLineEntryAtIndex(entry_idx + look_ahead_step, next_line_entry))
+ {
+ // Make sure we haven't wandered out of the function we started from...
+ Address next_line_address = next_line_entry.range.GetBaseAddress();
+ Function *next_line_function = next_line_address.CalculateSymbolContextFunction();
+ if (next_line_function != m_addr_context.function)
+ break;
+
+ if (next_line_entry.file == m_addr_context.line_entry.file)
+ {
+ const bool abort_other_plans = false;
+ const bool stop_other_threads = false;
+ new_plan_sp = m_thread.QueueThreadPlanForRunToAddress(abort_other_plans,
+ next_line_address,
+ stop_other_threads);
+ break;
+ }
+ look_ahead_step++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it:
+ ClearNextBranchBreakpoint();
+
+ if (!new_plan_sp)
+ m_no_more_plans = true;
+ else
+ m_no_more_plans = false;
+
+ if (!new_plan_sp)
+ {
+ // For efficiencies sake, we know we're done here so we don't have to do this
+ // calculation again in MischiefManaged.
+ SetPlanComplete();
+ return true;
+ }
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepOverRange::DoPlanExplainsStop (Event *event_ptr)
+{
+ // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan above us)
+ // handle the stop. That way the user can see the stop, step around, and then when they
+ // are done, continue and have their step complete. The exception is if we've hit our
+ // "run to next branch" breakpoint.
+ // Note, unlike the step in range plan, we don't mark ourselves complete if we hit an
+ // unexplained breakpoint/crash.
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ bool return_value;
+
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonTrace:
+ return_value = true;
+ break;
+ case eStopReasonBreakpoint:
+ if (NextRangeBreakpointExplainsStop(stop_info_sp))
+ return_value = true;
+ else
+ return_value = false;
+ break;
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ default:
+ if (log)
+ log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step.");
+ return_value = false;
+ break;
+ }
+ }
+ else
+ return_value = true;
+
+ return return_value;
+}
+
+bool
+ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool current_plan)
+{
+ if (resume_state != eStateSuspended && m_first_resume)
+ {
+ m_first_resume = false;
+ if (resume_state == eStateStepping && current_plan)
+ {
+ // See if we are about to step over an inlined call in the middle of the inlined stack, if so figure
+ // out its extents and reset our range to step over that.
+ bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth();
+ if (in_inlined_stack)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("ThreadPlanStepInRange::DoWillResume: adjusting range to the frame at inlined depth %d.",
+ m_thread.GetCurrentInlinedDepth());
+ StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0);
+ if (stack_sp)
+ {
+ Block *frame_block = stack_sp->GetFrameBlock();
+ lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
+ AddressRange my_range;
+ if (frame_block->GetRangeContainingLoadAddress(curr_pc, m_thread.GetProcess()->GetTarget(), my_range))
+ {
+ m_address_ranges.clear();
+ m_address_ranges.push_back(my_range);
+ if (log)
+ {
+ StreamString s;
+ const InlineFunctionInfo *inline_info = frame_block->GetInlinedFunctionInfo();
+ const char *name;
+ if (inline_info)
+ name = inline_info->GetName().AsCString();
+ else
+ name = "<unknown-notinlined>";
+
+ s.Printf ("Stepping over inlined function \"%s\" in inlined stack: ", name);
+ DumpRanges(&s);
+ log->PutCString(s.GetData());
+ }
+ }
+
+ }
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
new file mode 100644
index 000000000000..3940d542c10d
--- /dev/null
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -0,0 +1,522 @@
+//===-- ThreadPlanStepRange.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/ThreadPlanStepRange.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+#include "lldb/lldb-private-log.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointSite.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//----------------------------------------------------------------------
+// ThreadPlanStepRange: Step through a stack range, either stepping over or into
+// based on the value of \a type.
+//----------------------------------------------------------------------
+
+ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
+ const char *name,
+ Thread &thread,
+ const AddressRange &range,
+ const SymbolContext &addr_context,
+ lldb::RunMode stop_others) :
+ ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_addr_context (addr_context),
+ m_address_ranges (),
+ m_stop_others (stop_others),
+ m_stack_id (),
+ m_no_more_plans (false),
+ m_first_run_event (true),
+ m_use_fast_step(false)
+{
+ m_use_fast_step = GetTarget().GetUseFastStepping();
+ AddRange(range);
+ m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+}
+
+ThreadPlanStepRange::~ThreadPlanStepRange ()
+{
+ ClearNextBranchBreakpoint();
+
+ size_t num_instruction_ranges = m_instruction_ranges.size();
+
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ for (size_t i = 0; i < num_instruction_ranges; i++)
+ {
+ if (m_instruction_ranges[i])
+ m_instruction_ranges[i]->GetInstructionList().Clear();
+ }
+}
+
+void
+ThreadPlanStepRange::DidPush ()
+{
+ // See if we can find a "next range" breakpoint:
+ SetNextBranchBreakpoint();
+}
+
+bool
+ThreadPlanStepRange::ValidatePlan (Stream *error)
+{
+ return true;
+}
+
+Vote
+ThreadPlanStepRange::ShouldReportStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo;
+ if (log)
+ log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote);
+ return vote;
+}
+
+void
+ThreadPlanStepRange::AddRange(const AddressRange &new_range)
+{
+ // For now I'm just adding the ranges. At some point we may want to
+ // condense the ranges if they overlap, though I don't think it is likely
+ // to be very important.
+ m_address_ranges.push_back (new_range);
+
+ // Fill the slot for this address range with an empty DisassemblerSP in the instruction ranges. I want the
+ // indices to match, but I don't want to do the work to disassemble this range if I don't step into it.
+ m_instruction_ranges.push_back (DisassemblerSP());
+}
+
+void
+ThreadPlanStepRange::DumpRanges(Stream *s)
+{
+ size_t num_ranges = m_address_ranges.size();
+ if (num_ranges == 1)
+ {
+ m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ for (size_t i = 0; i < num_ranges; i++)
+ {
+ s->PutCString("%d: ");
+ m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress);
+ }
+ }
+}
+
+bool
+ThreadPlanStepRange::InRange ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ bool ret_value = false;
+
+ lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC();
+
+ size_t num_ranges = m_address_ranges.size();
+ for (size_t i = 0; i < num_ranges; i++)
+ {
+ ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get());
+ if (ret_value)
+ break;
+ }
+
+ if (!ret_value)
+ {
+ // See if we've just stepped to another part of the same line number...
+ StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
+
+ SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything));
+ if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid())
+ {
+ if (m_addr_context.line_entry.file == new_context.line_entry.file)
+ {
+ if (m_addr_context.line_entry.line == new_context.line_entry.line)
+ {
+ m_addr_context = new_context;
+ AddRange(m_addr_context.line_entry.range);
+ ret_value = true;
+ if (log)
+ {
+ StreamString s;
+ m_addr_context.line_entry.Dump (&s,
+ m_thread.CalculateTarget().get(),
+ true,
+ Address::DumpStyleLoadAddress,
+ Address::DumpStyleLoadAddress,
+ true);
+
+ log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData());
+ }
+ }
+ else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get())
+ != pc_load_addr)
+ {
+ // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another
+ // line. So far I mostly see this due to bugs in the debug information.
+ // But we probably don't want to be in the middle of a line range, so in that case reset the stepping
+ // range to the line we've stepped into the middle of and continue.
+ m_addr_context = new_context;
+ m_address_ranges.clear();
+ AddRange(m_addr_context.line_entry.range);
+ ret_value = true;
+ if (log)
+ {
+ StreamString s;
+ m_addr_context.line_entry.Dump (&s,
+ m_thread.CalculateTarget().get(),
+ true,
+ Address::DumpStyleLoadAddress,
+ Address::DumpStyleLoadAddress,
+ true);
+
+ log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.",
+ new_context.line_entry.line,
+ s.GetData());
+ }
+
+ }
+ }
+
+ }
+
+ }
+
+ if (!ret_value && log)
+ log->Printf ("Step range plan out of range to 0x%" PRIx64, pc_load_addr);
+
+ return ret_value;
+}
+
+bool
+ThreadPlanStepRange::InSymbol()
+{
+ lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ if (m_addr_context.function != NULL)
+ {
+ return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
+ }
+ else if (m_addr_context.symbol)
+ {
+ AddressRange range(m_addr_context.symbol->GetAddress(), m_addr_context.symbol->GetByteSize());
+ return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get());
+ }
+ return false;
+}
+
+// FIXME: This should also handle inlining if we aren't going to do inlining in the
+// main stack.
+//
+// Ideally we should remember the whole stack frame list, and then compare that
+// to the current list.
+
+lldb::FrameComparison
+ThreadPlanStepRange::CompareCurrentFrameToStartFrame()
+{
+ FrameComparison frame_order;
+
+ StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ if (cur_frame_id == m_stack_id)
+ {
+ frame_order = eFrameCompareEqual;
+ }
+ else if (cur_frame_id < m_stack_id)
+ {
+ frame_order = eFrameCompareYounger;
+ }
+ else
+ {
+ frame_order = eFrameCompareOlder;
+ }
+ return frame_order;
+}
+
+bool
+ThreadPlanStepRange::StopOthers ()
+{
+ if (m_stop_others == lldb::eOnlyThisThread
+ || m_stop_others == lldb::eOnlyDuringStepping)
+ return true;
+ else
+ return false;
+}
+
+InstructionList *
+ThreadPlanStepRange::GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset)
+{
+ size_t num_ranges = m_address_ranges.size();
+ for (size_t i = 0; i < num_ranges; i++)
+ {
+ if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget()))
+ {
+ // Some joker added a zero size range to the stepping range...
+ if (m_address_ranges[i].GetByteSize() == 0)
+ return NULL;
+
+ if (!m_instruction_ranges[i])
+ {
+ //Disassemble the address range given:
+ ExecutionContext exe_ctx (m_thread.GetProcess());
+ const char *plugin_name = NULL;
+ const char *flavor = NULL;
+ m_instruction_ranges[i] = Disassembler::DisassembleRange(GetTarget().GetArchitecture(),
+ plugin_name,
+ flavor,
+ exe_ctx,
+ m_address_ranges[i]);
+
+ }
+ if (!m_instruction_ranges[i])
+ return NULL;
+ else
+ {
+ // Find where we are in the instruction list as well. If we aren't at an instruction,
+ // return NULL. In this case, we're probably lost, and shouldn't try to do anything fancy.
+
+ insn_offset = m_instruction_ranges[i]->GetInstructionList().GetIndexOfInstructionAtLoadAddress(addr, GetTarget());
+ if (insn_offset == UINT32_MAX)
+ return NULL;
+ else
+ {
+ range_index = i;
+ return &m_instruction_ranges[i]->GetInstructionList();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+void
+ThreadPlanStepRange::ClearNextBranchBreakpoint()
+{
+ if (m_next_branch_bp_sp)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf ("Removing next branch breakpoint: %d.", m_next_branch_bp_sp->GetID());
+ GetTarget().RemoveBreakpointByID (m_next_branch_bp_sp->GetID());
+ m_next_branch_bp_sp.reset();
+ }
+}
+
+bool
+ThreadPlanStepRange::SetNextBranchBreakpoint ()
+{
+ if (m_next_branch_bp_sp)
+ return true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ // Stepping through ranges using breakpoints doesn't work yet, but with this off we fall back to instruction
+ // single stepping.
+ if (!m_use_fast_step)
+ return false;
+
+ lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC();
+ // Find the current address in our address ranges, and fetch the disassembly if we haven't already:
+ size_t pc_index;
+ size_t range_index;
+ InstructionList *instructions = GetInstructionsForAddress (cur_addr, range_index, pc_index);
+ if (instructions == NULL)
+ return false;
+ else
+ {
+ uint32_t branch_index;
+ branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index);
+
+ Address run_to_address;
+
+ // If we didn't find a branch, run to the end of the range.
+ if (branch_index == UINT32_MAX)
+ {
+ branch_index = instructions->GetSize() - 1;
+ }
+
+ if (branch_index - pc_index > 1)
+ {
+ const bool is_internal = true;
+ run_to_address = instructions->GetInstructionAtIndex(branch_index)->GetAddress();
+ m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal);
+ if (m_next_branch_bp_sp)
+ {
+ if (log)
+ {
+ lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID;
+ BreakpointLocationSP bp_loc = m_next_branch_bp_sp->GetLocationAtIndex(0);
+ if (bp_loc)
+ {
+ BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite();
+ if (bp_site)
+ {
+ bp_site_id = bp_site->GetID();
+ }
+ }
+ log->Printf ("ThreadPlanStepRange::SetNextBranchBreakpoint - Setting breakpoint %d (site %d) to run to address 0x%" PRIx64,
+ m_next_branch_bp_sp->GetID(),
+ bp_site_id,
+ run_to_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()));
+ }
+ m_next_branch_bp_sp->SetThreadID(m_thread.GetID());
+ m_next_branch_bp_sp->SetBreakpointKind ("next-branch-location");
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (!m_next_branch_bp_sp)
+ return false;
+
+ break_id_t bp_site_id = stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id);
+ if (!bp_site_sp)
+ return false;
+ else if (!bp_site_sp->IsBreakpointAtThisSite (m_next_branch_bp_sp->GetID()))
+ return false;
+ else
+ {
+ // If we've hit the next branch breakpoint, then clear it.
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ bool explains_stop = true;
+ // If all the owners are internal, then we are probably just stepping over this range from multiple threads,
+ // or multiple frames, so we want to continue. If one is not internal, then we should not explain the stop,
+ // and let the user breakpoint handle the stop.
+ for (size_t i = 0; i < num_owners; i++)
+ {
+ if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
+ {
+ explains_stop = false;
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %zu owners - explains stop: %u.",
+ num_owners,
+ explains_stop);
+ ClearNextBranchBreakpoint();
+ return explains_stop;
+ }
+}
+
+bool
+ThreadPlanStepRange::WillStop ()
+{
+ return true;
+}
+
+StateType
+ThreadPlanStepRange::GetPlanRunState ()
+{
+ if (m_next_branch_bp_sp)
+ return eStateRunning;
+ else
+ return eStateStepping;
+}
+
+bool
+ThreadPlanStepRange::MischiefManaged ()
+{
+ // If we have pushed some plans between ShouldStop & MischiefManaged, then we're not done...
+ // I do this check first because we might have stepped somewhere that will fool InRange into
+ // thinking it needs to step past the end of that line. This happens, for instance, when stepping
+ // over inlined code that is in the middle of the current line.
+
+ if (!m_no_more_plans)
+ return false;
+
+ bool done = true;
+ if (!IsPlanComplete())
+ {
+ if (InRange())
+ {
+ done = false;
+ }
+ else
+ {
+ FrameComparison frame_order = CompareCurrentFrameToStartFrame();
+ if (frame_order != eFrameCompareOlder)
+ {
+ if (m_no_more_plans)
+ done = true;
+ else
+ done = false;
+ }
+ else
+ done = true;
+ }
+ }
+
+ if (done)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Completed step through range plan.");
+ ClearNextBranchBreakpoint();
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+}
+
+bool
+ThreadPlanStepRange::IsPlanStale ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ FrameComparison frame_order = CompareCurrentFrameToStartFrame();
+
+ if (frame_order == eFrameCompareOlder)
+ {
+ if (log)
+ {
+ log->Printf("ThreadPlanStepRange::IsPlanStale returning true, we've stepped out.");
+ }
+ return true;
+ }
+ else if (frame_order == eFrameCompareEqual && InSymbol())
+ {
+ // If we are not in a place we should step through, we've gotten stale.
+ // One tricky bit here is that some stubs don't push a frame, so we should.
+ // check that we are in the same symbol.
+ if (!InRange())
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/source/Target/ThreadPlanStepThrough.cpp b/source/Target/ThreadPlanStepThrough.cpp
new file mode 100644
index 000000000000..92d1fcd850d8
--- /dev/null
+++ b/source/Target/ThreadPlanStepThrough.cpp
@@ -0,0 +1,290 @@
+//===-- ThreadPlanStepThrough.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/ThreadPlanStepThrough.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Breakpoint/Breakpoint.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it
+// If it is the beginning of the prologue of a function, step through that as well.
+// FIXME: At present only handles DYLD trampolines.
+//----------------------------------------------------------------------
+
+ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) :
+ ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_start_address (0),
+ m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID),
+ m_backstop_addr(LLDB_INVALID_ADDRESS),
+ m_return_stack_id (m_stack_id),
+ m_stop_others (stop_others)
+{
+
+ LookForPlanToStepThroughFromCurrentPC();
+
+ // If we don't get a valid step through plan, don't bother to set up a backstop.
+ if (m_sub_plan_sp)
+ {
+ m_start_address = GetThread().GetRegisterContext()->GetPC(0);
+
+ // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in
+ // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to.
+
+ StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id);
+
+ if (return_frame_sp)
+ {
+ m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get());
+ Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(m_thread.GetID());
+ m_backstop_bkpt_id = return_bp->GetID();
+ return_bp->SetBreakpointKind("step-through-backstop");
+ }
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr);
+ }
+ }
+ }
+}
+
+ThreadPlanStepThrough::~ThreadPlanStepThrough ()
+{
+ ClearBackstopBreakpoint ();
+}
+
+void
+ThreadPlanStepThrough::DidPush ()
+{
+ if (m_sub_plan_sp)
+ PushPlan(m_sub_plan_sp);
+}
+
+void
+ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
+{
+ m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->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())
+ {
+ ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime();
+ if (objc_runtime)
+ m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
+ }
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ {
+ lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0);
+ if (m_sub_plan_sp)
+ {
+ StreamString s;
+ m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull);
+ log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData());
+ }
+ else
+ {
+ log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address);
+ }
+ }
+}
+
+void
+ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ s->Printf ("Step through");
+ else
+ {
+ s->PutCString ("Stepping through trampoline code from: ");
+ s->Address(m_start_address, sizeof (addr_t));
+ if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
+ {
+ s->Printf (" with backstop breakpoint id: %d at address: ", m_backstop_bkpt_id);
+ s->Address (m_backstop_addr, sizeof (addr_t));
+ }
+ else
+ s->PutCString (" unable to set a backstop breakpoint.");
+ }
+}
+
+bool
+ThreadPlanStepThrough::ValidatePlan (Stream *error)
+{
+ return m_sub_plan_sp.get() != NULL;
+}
+
+bool
+ThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr)
+{
+ // If we have a sub-plan, it will have been asked first if we explain the stop, and
+ // we won't get asked. The only time we would be the one directly asked this question
+ // is if we hit our backstop breakpoint.
+
+ if (HitOurBackstopBreakpoint())
+ return true;
+ else
+ return false;
+}
+
+bool
+ThreadPlanStepThrough::ShouldStop (Event *event_ptr)
+{
+ // If we've already marked ourselves done, then we're done...
+ if (IsPlanComplete())
+ return true;
+
+ // First, did we hit the backstop breakpoint?
+ if (HitOurBackstopBreakpoint())
+ {
+ SetPlanComplete(false);
+ return true;
+ }
+
+ // If we don't have a sub-plan, then we're also done (can't see how we would ever get here
+ // without a plan, but just in case.
+
+ if (!m_sub_plan_sp)
+ {
+ SetPlanComplete();
+ return true;
+ }
+
+ // If the current sub plan is not done, we don't want to stop. Actually, we probably won't
+ // ever get here in this state, since we generally won't get asked any questions if out
+ // current sub-plan is not done...
+ if (!m_sub_plan_sp->IsPlanComplete())
+ return false;
+
+ // If our current sub plan failed, then let's just run to our backstop. If we can't do that then just stop.
+ if (!m_sub_plan_sp->PlanSucceeded())
+ {
+ if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_sub_plan_sp.reset();
+ return false;
+ }
+ else
+ {
+ SetPlanComplete(false);
+ return true;
+ }
+ }
+
+ // Next see if there is a specific step through plan at our current pc (these might
+ // chain, for instance stepping through a dylib trampoline to the objc dispatch function...)
+ LookForPlanToStepThroughFromCurrentPC();
+ if (m_sub_plan_sp)
+ {
+ PushPlan (m_sub_plan_sp);
+ return false;
+ }
+ else
+ {
+ SetPlanComplete();
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepThrough::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepThrough::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan)
+{
+ return true;
+}
+
+bool
+ThreadPlanStepThrough::WillStop ()
+{
+ return true;
+}
+
+void
+ThreadPlanStepThrough::ClearBackstopBreakpoint ()
+{
+ if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID)
+ {
+ m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id);
+ m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+bool
+ThreadPlanStepThrough::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+
+ if (!IsPlanComplete())
+ {
+ return false;
+ }
+ else
+ {
+ if (log)
+ log->Printf("Completed step through step plan.");
+
+ ClearBackstopBreakpoint ();
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+}
+
+bool
+ThreadPlanStepThrough::HitOurBackstopBreakpoint()
+{
+ StopInfoSP stop_info_sp(m_thread.GetStopInfo());
+ if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint)
+ {
+ break_id_t stop_value = (break_id_t) stop_info_sp->GetValue();
+ BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value);
+ if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id))
+ {
+ StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ if (cur_frame_zero_id == m_return_stack_id)
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint.");
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
new file mode 100644
index 000000000000..e1b5a0560c75
--- /dev/null
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -0,0 +1,413 @@
+//===-- ThreadPlanStepUntil.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//m_should_stop
+
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ThreadPlanStepUntil.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame
+//----------------------------------------------------------------------
+
+ThreadPlanStepUntil::ThreadPlanStepUntil
+(
+ Thread &thread,
+ lldb::addr_t *address_list,
+ size_t num_addresses,
+ bool stop_others,
+ uint32_t frame_idx
+) :
+ ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion),
+ m_step_from_insn (LLDB_INVALID_ADDRESS),
+ m_return_bp_id (LLDB_INVALID_BREAK_ID),
+ m_return_addr (LLDB_INVALID_ADDRESS),
+ m_stepped_out (false),
+ m_should_stop (false),
+ m_ran_analyze (false),
+ m_explains_stop (false),
+ m_until_points (),
+ m_stop_others (stop_others)
+{
+ // Stash away our "until" addresses:
+ TargetSP target_sp (m_thread.CalculateTarget());
+
+ StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx));
+ if (frame_sp)
+ {
+ m_step_from_insn = frame_sp->GetStackID().GetPC();
+ lldb::user_id_t thread_id = m_thread.GetID();
+
+ // Find the return address and set a breakpoint there:
+ // FIXME - can we do this more securely if we know first_insn?
+
+ StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1));
+ if (return_frame_sp)
+ {
+ // TODO: add inline functionality
+ m_return_addr = return_frame_sp->GetStackID().GetPC();
+ Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true).get();
+ if (return_bp != NULL)
+ {
+ return_bp->SetThreadID(thread_id);
+ m_return_bp_id = return_bp->GetID();
+ return_bp->SetBreakpointKind ("until-return-backstop");
+ }
+ }
+
+ m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
+
+ // Now set breakpoints on all our return addresses:
+ for (size_t i = 0; i < num_addresses; i++)
+ {
+ Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true).get();
+ if (until_bp != NULL)
+ {
+ until_bp->SetThreadID(thread_id);
+ m_until_points[address_list[i]] = until_bp->GetID();
+ until_bp->SetBreakpointKind("until-target");
+ }
+ else
+ {
+ m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID;
+ }
+ }
+ }
+}
+
+ThreadPlanStepUntil::~ThreadPlanStepUntil ()
+{
+ Clear();
+}
+
+void
+ThreadPlanStepUntil::Clear()
+{
+ TargetSP target_sp (m_thread.CalculateTarget());
+ if (target_sp)
+ {
+ if (m_return_bp_id != LLDB_INVALID_BREAK_ID)
+ {
+ target_sp->RemoveBreakpointByID(m_return_bp_id);
+ m_return_bp_id = LLDB_INVALID_BREAK_ID;
+ }
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ target_sp->RemoveBreakpointByID((*pos).second);
+ }
+ }
+ m_until_points.clear();
+}
+
+void
+ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level)
+{
+ if (level == lldb::eDescriptionLevelBrief)
+ {
+ s->Printf ("step until");
+ if (m_stepped_out)
+ s->Printf (" - stepped out");
+ }
+ else
+ {
+ if (m_until_points.size() == 1)
+ s->Printf ("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 " using breakpoint %d",
+ (uint64_t)m_step_from_insn,
+ (uint64_t) (*m_until_points.begin()).first,
+ (*m_until_points.begin()).second);
+ else
+ {
+ until_collection::iterator pos, end = m_until_points.end();
+ s->Printf ("Stepping from address 0x%" PRIx64 " until we reach one of:",
+ (uint64_t)m_step_from_insn);
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ s->Printf ("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second);
+ }
+ }
+ s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr);
+ }
+}
+
+bool
+ThreadPlanStepUntil::ValidatePlan (Stream *error)
+{
+ if (m_return_bp_id == LLDB_INVALID_BREAK_ID)
+ return false;
+ else
+ {
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ if (!LLDB_BREAK_ID_IS_VALID ((*pos).second))
+ return false;
+ }
+ return true;
+ }
+}
+
+void
+ThreadPlanStepUntil::AnalyzeStop()
+{
+ if (m_ran_analyze)
+ return;
+
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ m_should_stop = true;
+ m_explains_stop = false;
+
+ if (stop_info_sp)
+ {
+ StopReason reason = stop_info_sp->GetStopReason();
+
+ switch (reason)
+ {
+ case eStopReasonBreakpoint:
+ {
+ // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened...
+ BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue());
+ if (!this_site)
+ {
+ m_explains_stop = false;
+ return;
+ }
+
+ if (this_site->IsBreakpointAtThisSite (m_return_bp_id))
+ {
+ // If we are at our "step out" breakpoint, and the stack depth has shrunk, then
+ // this is indeed our stop.
+ // If the stack depth has grown, then we've hit our step out breakpoint recursively.
+ // If we are the only breakpoint at that location, then we do explain the stop, and
+ // we'll just continue.
+ // If there was another breakpoint here, then we don't explain the stop, but we won't
+ // mark ourselves Completed, because maybe that breakpoint will continue, and then
+ // we'll finish the "until".
+ bool done;
+ StackID cur_frame_zero_id;
+
+ if (m_stack_id < cur_frame_zero_id)
+ done = true;
+ else
+ done = false;
+
+ if (done)
+ {
+ m_stepped_out = true;
+ SetPlanComplete();
+ }
+ else
+ m_should_stop = false;
+
+ if (this_site->GetNumberOfOwners() == 1)
+ m_explains_stop = true;
+ else
+ m_explains_stop = false;
+ return;
+ }
+ else
+ {
+ // Check if we've hit one of our "until" breakpoints.
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ if (this_site->IsBreakpointAtThisSite ((*pos).second))
+ {
+ // If we're at the right stack depth, then we're done.
+
+ bool done;
+ StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+
+ if (frame_zero_id == m_stack_id)
+ done = true;
+ else if (frame_zero_id < m_stack_id)
+ done = false;
+ else
+ {
+ StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1);
+
+ // But if we can't even unwind one frame we should just get out of here & stop...
+ if (older_frame_sp)
+ {
+ const SymbolContext &older_context
+ = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
+ SymbolContext stack_context;
+ m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context);
+
+ if (older_context == stack_context)
+ done = true;
+ else
+ done = false;
+ }
+ else
+ done = false;
+ }
+
+ if (done)
+ SetPlanComplete();
+ else
+ m_should_stop = false;
+
+ // Otherwise we've hit this breakpoint recursively. If we're the
+ // only breakpoint here, then we do explain the stop, and we'll continue.
+ // If not then we should let higher plans handle this stop.
+ if (this_site->GetNumberOfOwners() == 1)
+ m_explains_stop = true;
+ else
+ {
+ m_should_stop = true;
+ m_explains_stop = false;
+ }
+ return;
+ }
+ }
+ }
+ // If we get here we haven't hit any of our breakpoints, so let the higher
+ // plans take care of the stop.
+ m_explains_stop = false;
+ return;
+ }
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ m_explains_stop = false;
+ break;
+ default:
+ m_explains_stop = true;
+ break;
+ }
+ }
+}
+
+bool
+ThreadPlanStepUntil::DoPlanExplainsStop (Event *event_ptr)
+{
+ // We don't explain signals or breakpoints (breakpoints that handle stepping in or
+ // out will be handled by a child plan.
+ AnalyzeStop();
+ return m_explains_stop;
+}
+
+bool
+ThreadPlanStepUntil::ShouldStop (Event *event_ptr)
+{
+ // If we've told our self in ExplainsStop that we plan to continue, then
+ // do so here. Otherwise, as long as this thread has stopped for a reason,
+ // we will stop.
+
+ StopInfoSP stop_info_sp = GetPrivateStopInfo ();
+ if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone)
+ return false;
+
+ AnalyzeStop();
+ return m_should_stop;
+}
+
+bool
+ThreadPlanStepUntil::StopOthers ()
+{
+ return m_stop_others;
+}
+
+StateType
+ThreadPlanStepUntil::GetPlanRunState ()
+{
+ return eStateRunning;
+}
+
+bool
+ThreadPlanStepUntil::DoWillResume (StateType resume_state, bool current_plan)
+{
+ if (current_plan)
+ {
+ TargetSP target_sp (m_thread.CalculateTarget());
+ if (target_sp)
+ {
+ Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (true);
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
+ if (until_bp != NULL)
+ until_bp->SetEnabled (true);
+ }
+ }
+ }
+
+ m_should_stop = true;
+ m_ran_analyze = false;
+ m_explains_stop = false;
+ return true;
+}
+
+bool
+ThreadPlanStepUntil::WillStop ()
+{
+ TargetSP target_sp (m_thread.CalculateTarget());
+ if (target_sp)
+ {
+ Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get();
+ if (return_bp != NULL)
+ return_bp->SetEnabled (false);
+
+ until_collection::iterator pos, end = m_until_points.end();
+ for (pos = m_until_points.begin(); pos != end; pos++)
+ {
+ Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get();
+ if (until_bp != NULL)
+ until_bp->SetEnabled (false);
+ }
+ }
+ return true;
+}
+
+bool
+ThreadPlanStepUntil::MischiefManaged ()
+{
+
+ // I'm letting "PlanExplainsStop" do all the work, and just reporting that here.
+ bool done = false;
+ if (IsPlanComplete())
+ {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Completed step until plan.");
+
+ Clear();
+ done = true;
+ }
+ if (done)
+ ThreadPlan::MischiefManaged ();
+
+ return done;
+
+}
+
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
new file mode 100644
index 000000000000..af6cef7ecc5a
--- /dev/null
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -0,0 +1,286 @@
+//===-- 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
+#include <string.h>
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+#pragma mark ThreadPlanTracer
+
+ThreadPlanTracer::ThreadPlanTracer (Thread &thread, lldb::StreamSP &stream_sp) :
+ m_thread (thread),
+ m_single_step(true),
+ m_enabled (false),
+ m_stream_sp (stream_sp)
+{
+}
+
+ThreadPlanTracer::ThreadPlanTracer (Thread &thread) :
+ m_thread (thread),
+ m_single_step(true),
+ m_enabled (false),
+ m_stream_sp ()
+{
+}
+
+Stream *
+ThreadPlanTracer::GetLogStream ()
+{
+
+ if (m_stream_sp.get())
+ return m_stream_sp.get();
+ else
+ {
+ TargetSP target_sp (m_thread.CalculateTarget());
+ if (target_sp)
+ return &target_sp->GetDebugger().GetOutputStream();
+ }
+ return NULL;
+}
+
+void
+ThreadPlanTracer::Log()
+{
+ SymbolContext sc;
+ bool show_frame_index = false;
+ bool show_fullpaths = false;
+
+ Stream *stream = GetLogStream();
+ if (stream)
+ {
+ m_thread.GetStackFrameAtIndex(0)->Dump (stream, show_frame_index, show_fullpaths);
+ stream->Printf("\n");
+ stream->Flush();
+ }
+
+}
+
+bool
+ThreadPlanTracer::TracerExplainsStop ()
+{
+ if (m_enabled && m_single_step)
+ {
+ lldb::StopInfoSP stop_info = m_thread.GetStopInfo();
+ if (stop_info->GetStopReason() == eStopReasonTrace)
+ return true;
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+#pragma mark ThreadPlanAssemblyTracer
+
+ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp) :
+ ThreadPlanTracer (thread, stream_sp),
+ m_disassembler_sp (),
+ m_intptr_type (),
+ m_register_values ()
+{
+}
+
+ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread) :
+ ThreadPlanTracer (thread),
+ m_disassembler_sp (),
+ m_intptr_type (),
+ m_register_values ()
+{
+}
+
+Disassembler *
+ThreadPlanAssemblyTracer::GetDisassembler ()
+{
+ if (m_disassembler_sp.get() == NULL)
+ m_disassembler_sp = Disassembler::FindPlugin(m_thread.GetProcess()->GetTarget().GetArchitecture(), NULL, NULL);
+ return m_disassembler_sp.get();
+}
+
+TypeFromUser
+ThreadPlanAssemblyTracer::GetIntPointerType()
+{
+ if (!m_intptr_type.IsValid ())
+ {
+ TargetSP target_sp (m_thread.CalculateTarget());
+ if (target_sp)
+ {
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+
+ if (exe_module)
+ {
+ m_intptr_type = TypeFromUser(exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, target_sp->GetArchitecture().GetAddressByteSize() * 8));
+ }
+ }
+ }
+ return m_intptr_type;
+}
+
+
+
+ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer()
+{
+}
+
+void
+ThreadPlanAssemblyTracer::TracingStarted ()
+{
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+
+ if (m_register_values.size() == 0)
+ m_register_values.resize (reg_ctx->GetRegisterCount());
+}
+
+void
+ThreadPlanAssemblyTracer::TracingEnded ()
+{
+ m_register_values.clear();
+}
+
+static void
+PadOutTo (StreamString &stream, int target)
+{
+ stream.Flush();
+
+ int length = stream.GetString().length();
+
+ if (length + 1 < target)
+ stream.Printf("%*s", target - (length + 1) + 1, "");
+}
+
+void
+ThreadPlanAssemblyTracer::Log ()
+{
+ Stream *stream = GetLogStream ();
+
+ if (!stream)
+ return;
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+
+ lldb::addr_t pc = reg_ctx->GetPC();
+ ProcessSP process_sp (m_thread.GetProcess());
+ Address pc_addr;
+ bool addr_valid = false;
+ uint8_t buffer[16] = {0}; // Must be big enough for any single instruction
+ addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, pc_addr);
+
+ pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress);
+ stream->PutCString (" ");
+
+ Disassembler *disassembler = GetDisassembler();
+ if (disassembler)
+ {
+ Error err;
+ process_sp->ReadMemory(pc, buffer, sizeof(buffer), err);
+
+ if (err.Success())
+ {
+ DataExtractor extractor(buffer, sizeof(buffer),
+ process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+
+ bool data_from_file = false;
+ if (addr_valid)
+ disassembler->DecodeInstructions (pc_addr, extractor, 0, 1, false, data_from_file);
+ else
+ disassembler->DecodeInstructions (Address (pc), extractor, 0, 1, false, data_from_file);
+
+ InstructionList &instruction_list = disassembler->GetInstructionList();
+ const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize();
+
+ if (instruction_list.GetSize())
+ {
+ const bool show_bytes = true;
+ const bool show_address = true;
+ Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get();
+ instruction->Dump (stream,
+ max_opcode_byte_size,
+ show_address,
+ show_bytes,
+ NULL);
+ }
+ }
+ }
+
+ const ABI *abi = process_sp->GetABI().get();
+ TypeFromUser intptr_type = GetIntPointerType();
+
+ if (abi && intptr_type.IsValid())
+ {
+ ValueList value_list;
+ const int num_args = 1;
+
+ for (int arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ Value value;
+ value.SetValueType (Value::eValueTypeScalar);
+// value.SetContext (Value::eContextTypeClangType, intptr_type.GetOpaqueQualType());
+ value.SetClangType (intptr_type);
+ value_list.PushValue (value);
+ }
+
+ if (abi->GetArgumentValues (m_thread, value_list))
+ {
+ for (int arg_index = 0; arg_index < num_args; ++arg_index)
+ {
+ stream->Printf("\n\targ[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong());
+
+ if (arg_index + 1 < num_args)
+ stream->PutCString (", ");
+ }
+ }
+ }
+
+
+ RegisterValue reg_value;
+ for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount();
+ reg_num < num_registers;
+ ++reg_num)
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num);
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ assert (reg_num < m_register_values.size());
+ if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid ||
+ reg_value != m_register_values[reg_num])
+ {
+ if (reg_value.GetType() != RegisterValue::eTypeInvalid)
+ {
+ stream->PutCString ("\n\t");
+ reg_value.Dump(stream, reg_info, true, false, eFormatDefault);
+ }
+ }
+ m_register_values[reg_num] = reg_value;
+ }
+ }
+ stream->EOL();
+ stream->Flush();
+}
diff --git a/source/Target/ThreadSpec.cpp b/source/Target/ThreadSpec.cpp
new file mode 100644
index 000000000000..cb54469ba901
--- /dev/null
+++ b/source/Target/ThreadSpec.cpp
@@ -0,0 +1,158 @@
+//===-- ThreadSpec.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadSpec.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadSpec::ThreadSpec() :
+ m_index (UINT32_MAX),
+ m_tid (LLDB_INVALID_THREAD_ID),
+ m_name(),
+ m_queue_name ()
+{
+}
+
+ThreadSpec::ThreadSpec (const ThreadSpec &rhs) :
+ m_index(rhs.m_index),
+ m_tid(rhs.m_tid),
+ m_name(rhs.m_name),
+ m_queue_name(rhs.m_queue_name)
+{
+}
+
+const ThreadSpec &
+ThreadSpec::operator=(const ThreadSpec &rhs)
+{
+ m_index = rhs.m_index;
+ m_tid = rhs.m_tid;
+ m_name = rhs.m_name;
+ m_queue_name = rhs.m_queue_name;
+ return *this;
+}
+
+const char *
+ThreadSpec::GetName () const
+{
+ if (m_name.empty())
+ return NULL;
+ else
+ return m_name.c_str();
+}
+
+const char *
+ThreadSpec::GetQueueName () const
+{
+ if (m_queue_name.empty())
+ return NULL;
+ else
+ return m_queue_name.c_str();
+}
+
+bool
+ThreadSpec::TIDMatches (Thread &thread) const
+{
+ if (m_tid == LLDB_INVALID_THREAD_ID)
+ return true;
+
+ lldb::tid_t thread_id = thread.GetID();
+ return TIDMatches (thread_id);
+}
+bool
+ThreadSpec::IndexMatches (Thread &thread) const
+{
+ if (m_index == UINT32_MAX)
+ return true;
+ uint32_t index = thread.GetIndexID();
+ return IndexMatches (index);
+}
+bool
+ThreadSpec::NameMatches (Thread &thread) const
+{
+ if (m_name.empty())
+ return true;
+
+ const char *name = thread.GetName();
+ return NameMatches (name);
+}
+bool
+ThreadSpec::QueueNameMatches (Thread &thread) const
+{
+ if (m_queue_name.empty())
+ return true;
+
+ const char *queue_name = thread.GetQueueName();
+ return QueueNameMatches (queue_name);
+}
+
+bool
+ThreadSpec::ThreadPassesBasicTests (Thread &thread) const
+{
+
+ if (!HasSpecification())
+ return true;
+
+ if (!TIDMatches(thread))
+ return false;
+
+ if (!IndexMatches(thread))
+ return false;
+
+ if (!NameMatches (thread))
+ return false;
+
+ if (!QueueNameMatches (thread))
+ return false;
+
+ return true;
+
+}
+
+bool
+ThreadSpec::HasSpecification() const
+{
+ return (m_index != UINT32_MAX || m_tid != LLDB_INVALID_THREAD_ID || !m_name.empty() || !m_queue_name.empty());
+}
+void
+ThreadSpec::GetDescription (Stream *s, lldb::DescriptionLevel level) const
+{
+ if (!HasSpecification())
+ {
+ if (level == eDescriptionLevelBrief)
+ {
+ s->PutCString("thread spec: no ");
+ }
+ }
+ else
+ {
+ if (level == eDescriptionLevelBrief)
+ {
+ s->PutCString("thread spec: yes ");
+ }
+ else
+ {
+ if (GetTID() != LLDB_INVALID_THREAD_ID)
+ s->Printf("tid: 0x%" PRIx64 " ", GetTID());
+
+ if (GetIndex() != UINT32_MAX)
+ s->Printf("index: %d ", GetIndex());
+
+ const char *name = GetName();
+ if (name)
+ s->Printf ("thread name: \"%s\" ", name);
+
+ const char *queue_name = GetQueueName();
+ if (queue_name)
+ s->Printf ("queue name: \"%s\" ", queue_name);
+ }
+
+ }
+}
diff --git a/source/Target/UnixSignals.cpp b/source/Target/UnixSignals.cpp
new file mode 100644
index 000000000000..7fe81f85e857
--- /dev/null
+++ b/source/Target/UnixSignals.cpp
@@ -0,0 +1,293 @@
+//===-- UnixSignals.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/UnixSignals.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+using namespace lldb_private;
+
+UnixSignals::Signal::Signal
+(
+ const char *name,
+ const char *short_name,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify,
+ const char *description
+) :
+ m_name (name),
+ m_short_name (short_name),
+ m_description (),
+ m_suppress (default_suppress),
+ m_stop (default_stop),
+ m_notify (default_notify)
+{
+ if (description)
+ m_description.assign (description);
+}
+
+//----------------------------------------------------------------------
+// UnixSignals constructor
+//----------------------------------------------------------------------
+UnixSignals::UnixSignals ()
+{
+ Reset ();
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+UnixSignals::~UnixSignals ()
+{
+}
+
+void
+UnixSignals::Reset ()
+{
+ // This builds one standard set of Unix Signals. If yours aren't quite in this
+ // order, you can either subclass this class, and use Add & Remove to change them
+ // or you can subclass and build them afresh in your constructor;
+ m_signals.clear();
+ // SIGNO NAME SHORT NAME SUPPRESS STOP NOTIFY DESCRIPTION
+ // ====== ============ ========== ======== ====== ====== ===================================================
+ AddSignal (1, "SIGHUP", "HUP", false, true , true , "hangup");
+ AddSignal (2, "SIGINT", "INT", true , true , true , "interrupt");
+ AddSignal (3, "SIGQUIT", "QUIT", false, true , true , "quit");
+ AddSignal (4, "SIGILL", "ILL", false, true , true , "illegal instruction");
+ AddSignal (5, "SIGTRAP", "TRAP", true , true , true , "trace trap (not reset when caught)");
+ AddSignal (6, "SIGABRT", "ABRT", false, true , true , "abort()");
+ AddSignal (7, "SIGEMT", "EMT", false, true , true , "pollable event");
+ AddSignal (8, "SIGFPE", "FPE", false, true , true , "floating point exception");
+ AddSignal (9, "SIGKILL", "KILL", false, true , true , "kill");
+ AddSignal (10, "SIGBUS", "BUS", false, true , true , "bus error");
+ AddSignal (11, "SIGSEGV", "SEGV", false, true , true , "segmentation violation");
+ AddSignal (12, "SIGSYS", "SYS", false, true , true , "bad argument to system call");
+ AddSignal (13, "SIGPIPE", "PIPE", false, true , true , "write on a pipe with no one to read it");
+ AddSignal (14, "SIGALRM", "ALRM", false, false, true , "alarm clock");
+ AddSignal (15, "SIGTERM", "TERM", false, true , true , "software termination signal from kill");
+ AddSignal (16, "SIGURG", "URG", false, false, false, "urgent condition on IO channel");
+ AddSignal (17, "SIGSTOP", "STOP", true , true , true , "sendable stop signal not from tty");
+ AddSignal (18, "SIGTSTP", "TSTP", false, true , true , "stop signal from tty");
+ AddSignal (19, "SIGCONT", "CONT", false, true , true , "continue a stopped process");
+ AddSignal (20, "SIGCHLD", "CHLD", false, false, true , "to parent on child stop or exit");
+ AddSignal (21, "SIGTTIN", "TTIN", false, true , true , "to readers process group upon background tty read");
+ AddSignal (22, "SIGTTOU", "TTOU", false, true , true , "to readers process group upon background tty write");
+ AddSignal (23, "SIGIO", "IO", false, false, false, "input/output possible signal");
+ AddSignal (24, "SIGXCPU", "XCPU", false, true , true , "exceeded CPU time limit");
+ AddSignal (25, "SIGXFSZ", "XFSZ", false, true , true , "exceeded file size limit");
+ AddSignal (26, "SIGVTALRM", "VTALRM", false, false, false, "virtual time alarm");
+ AddSignal (27, "SIGPROF", "PROF", false, false, false, "profiling time alarm");
+ AddSignal (28, "SIGWINCH", "WINCH", false, false, false, "window size changes");
+ AddSignal (29, "SIGINFO", "INFO", false, true , true , "information request");
+ AddSignal (30, "SIGUSR1", "USR1", false, true , true , "user defined signal 1");
+ AddSignal (31, "SIGUSR2", "USR2", false, true , true , "user defined signal 2");
+}
+
+void
+UnixSignals::AddSignal
+(
+ int signo,
+ const char *name,
+ const char *short_name,
+ bool default_suppress,
+ bool default_stop,
+ bool default_notify,
+ const char *description
+)
+{
+ Signal new_signal (name, short_name, default_suppress, default_stop, default_notify, description);
+ m_signals.insert (std::make_pair(signo, new_signal));
+}
+
+void
+UnixSignals::RemoveSignal (int signo)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ m_signals.erase (pos);
+}
+
+const char *
+UnixSignals::GetSignalAsCString (int signo) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return NULL;
+ else
+ return pos->second.m_name.GetCString ();
+}
+
+
+bool
+UnixSignals::SignalIsValid (int32_t signo) const
+{
+ return m_signals.find (signo) != m_signals.end();
+}
+
+
+int32_t
+UnixSignals::GetSignalNumberFromName (const char *name) const
+{
+ ConstString const_name (name);
+
+ collection::const_iterator pos, end = m_signals.end ();
+ for (pos = m_signals.begin (); pos != end; pos++)
+ {
+ if ((const_name == pos->second.m_name) || (const_name == pos->second.m_short_name))
+ return pos->first;
+ }
+
+ const int32_t signo = Args::StringToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0);
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ return signo;
+ return LLDB_INVALID_SIGNAL_NUMBER;
+}
+
+int32_t
+UnixSignals::GetFirstSignalNumber () const
+{
+ if (m_signals.empty())
+ return LLDB_INVALID_SIGNAL_NUMBER;
+
+ return (*m_signals.begin ()).first;
+}
+
+int32_t
+UnixSignals::GetNextSignalNumber (int32_t current_signal) const
+{
+ collection::const_iterator pos = m_signals.find (current_signal);
+ collection::const_iterator end = m_signals.end();
+ if (pos == end)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ {
+ pos++;
+ if (pos == end)
+ return LLDB_INVALID_SIGNAL_NUMBER;
+ else
+ return pos->first;
+ }
+}
+
+const char *
+UnixSignals::GetSignalInfo
+(
+ int32_t signo,
+ bool &should_suppress,
+ bool &should_stop,
+ bool &should_notify
+) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos == m_signals.end())
+ return NULL;
+ else
+ {
+ const Signal &signal = pos->second;
+ should_suppress = signal.m_suppress;
+ should_stop = signal.m_stop;
+ should_notify = signal.m_notify;
+ return signal.m_name.AsCString("");
+ }
+}
+
+bool
+UnixSignals::GetShouldSuppress (int signo) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ return pos->second.m_suppress;
+ return false;
+}
+
+bool
+UnixSignals::SetShouldSuppress (int signo, bool value)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ {
+ pos->second.m_suppress = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+UnixSignals::SetShouldSuppress (const char *signal_name, bool value)
+{
+ const int32_t signo = GetSignalNumberFromName (signal_name);
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ return SetShouldSuppress (signo, value);
+ return false;
+}
+
+bool
+UnixSignals::GetShouldStop (int signo) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ return pos->second.m_stop;
+ return false;
+}
+
+bool
+UnixSignals::SetShouldStop (int signo, bool value)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ {
+ pos->second.m_stop = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+UnixSignals::SetShouldStop (const char *signal_name, bool value)
+{
+ const int32_t signo = GetSignalNumberFromName (signal_name);
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ return SetShouldStop (signo, value);
+ return false;
+}
+
+bool
+UnixSignals::GetShouldNotify (int signo) const
+{
+ collection::const_iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ return pos->second.m_notify;
+ return false;
+}
+
+bool
+UnixSignals::SetShouldNotify (int signo, bool value)
+{
+ collection::iterator pos = m_signals.find (signo);
+ if (pos != m_signals.end())
+ {
+ pos->second.m_notify = value;
+ return true;
+ }
+ return false;
+}
+
+bool
+UnixSignals::SetShouldNotify (const char *signal_name, bool value)
+{
+ const int32_t signo = GetSignalNumberFromName (signal_name);
+ if (signo != LLDB_INVALID_SIGNAL_NUMBER)
+ return SetShouldNotify (signo, value);
+ return false;
+}
diff --git a/source/Target/UnwindAssembly.cpp b/source/Target/UnwindAssembly.cpp
new file mode 100644
index 000000000000..72137501f38b
--- /dev/null
+++ b/source/Target/UnwindAssembly.cpp
@@ -0,0 +1,41 @@
+//===-- UnwindAssembly.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/Core/PluginManager.h"
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindAssembly*
+UnwindAssembly::FindPlugin (const ArchSpec &arch)
+{
+ UnwindAssemblyCreateInstance create_callback;
+
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetUnwindAssemblyCreateCallbackAtIndex(idx)) != NULL;
+ ++idx)
+ {
+ std::unique_ptr<UnwindAssembly> assembly_profiler_ap (create_callback (arch));
+ if (assembly_profiler_ap.get ())
+ return assembly_profiler_ap.release ();
+ }
+ return NULL;
+}
+
+UnwindAssembly::UnwindAssembly (const ArchSpec &arch) :
+ m_arch (arch)
+{
+}
+
+UnwindAssembly::~UnwindAssembly ()
+{
+}
diff --git a/source/Utility/ARM_DWARF_Registers.cpp b/source/Utility/ARM_DWARF_Registers.cpp
new file mode 100644
index 000000000000..491ba040863e
--- /dev/null
+++ b/source/Utility/ARM_DWARF_Registers.cpp
@@ -0,0 +1,435 @@
+//===-- ARM_DWARF_Registers.c -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ARM_DWARF_Registers.h"
+#include <string.h>
+
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+GetARMDWARFRegisterName (unsigned reg_num)
+{
+ switch (reg_num)
+ {
+ case dwarf_r0: return "r0";
+ case dwarf_r1: return "r1";
+ case dwarf_r2: return "r2";
+ case dwarf_r3: return "r3";
+ case dwarf_r4: return "r4";
+ case dwarf_r5: return "r5";
+ case dwarf_r6: return "r6";
+ case dwarf_r7: return "r7";
+ case dwarf_r8: return "r8";
+ case dwarf_r9: return "r9";
+ case dwarf_r10: return "r10";
+ case dwarf_r11: return "r11";
+ case dwarf_r12: return "r12";
+ case dwarf_sp: return "sp";
+ case dwarf_lr: return "lr";
+ case dwarf_pc: return "pc";
+ case dwarf_cpsr:return "cpsr";
+
+ case dwarf_s0: return "s0";
+ case dwarf_s1: return "s1";
+ case dwarf_s2: return "s2";
+ case dwarf_s3: return "s3";
+ case dwarf_s4: return "s4";
+ case dwarf_s5: return "s5";
+ case dwarf_s6: return "s6";
+ case dwarf_s7: return "s7";
+ case dwarf_s8: return "s8";
+ case dwarf_s9: return "s9";
+ case dwarf_s10: return "s10";
+ case dwarf_s11: return "s11";
+ case dwarf_s12: return "s12";
+ case dwarf_s13: return "s13";
+ case dwarf_s14: return "s14";
+ case dwarf_s15: return "s15";
+ case dwarf_s16: return "s16";
+ case dwarf_s17: return "s17";
+ case dwarf_s18: return "s18";
+ case dwarf_s19: return "s19";
+ case dwarf_s20: return "s20";
+ case dwarf_s21: return "s21";
+ case dwarf_s22: return "s22";
+ case dwarf_s23: return "s23";
+ case dwarf_s24: return "s24";
+ case dwarf_s25: return "s25";
+ case dwarf_s26: return "s26";
+ case dwarf_s27: return "s27";
+ case dwarf_s28: return "s28";
+ case dwarf_s29: return "s29";
+ case dwarf_s30: return "s30";
+ case dwarf_s31: return "s31";
+
+ // FPA Registers 0-7
+ case dwarf_f0: return "f0";
+ case dwarf_f1: return "f1";
+ case dwarf_f2: return "f2";
+ case dwarf_f3: return "f3";
+ case dwarf_f4: return "f4";
+ case dwarf_f5: return "f5";
+ case dwarf_f6: return "f6";
+ case dwarf_f7: return "f7";
+
+ // Intel wireless MMX general purpose registers 0 - 7
+ // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
+ case dwarf_wCGR0: return "wCGR0/ACC0";
+ case dwarf_wCGR1: return "wCGR1/ACC1";
+ case dwarf_wCGR2: return "wCGR2/ACC2";
+ case dwarf_wCGR3: return "wCGR3/ACC3";
+ case dwarf_wCGR4: return "wCGR4/ACC4";
+ case dwarf_wCGR5: return "wCGR5/ACC5";
+ case dwarf_wCGR6: return "wCGR6/ACC6";
+ case dwarf_wCGR7: return "wCGR7/ACC7";
+
+ // Intel wireless MMX data registers 0 - 15
+ case dwarf_wR0: return "wR0";
+ case dwarf_wR1: return "wR1";
+ case dwarf_wR2: return "wR2";
+ case dwarf_wR3: return "wR3";
+ case dwarf_wR4: return "wR4";
+ case dwarf_wR5: return "wR5";
+ case dwarf_wR6: return "wR6";
+ case dwarf_wR7: return "wR7";
+ case dwarf_wR8: return "wR8";
+ case dwarf_wR9: return "wR9";
+ case dwarf_wR10: return "wR10";
+ case dwarf_wR11: return "wR11";
+ case dwarf_wR12: return "wR12";
+ case dwarf_wR13: return "wR13";
+ case dwarf_wR14: return "wR14";
+ case dwarf_wR15: return "wR15";
+
+ case dwarf_spsr: return "spsr";
+ case dwarf_spsr_fiq: return "spsr_fiq";
+ case dwarf_spsr_irq: return "spsr_irq";
+ case dwarf_spsr_abt: return "spsr_abt";
+ case dwarf_spsr_und: return "spsr_und";
+ case dwarf_spsr_svc: return "spsr_svc";
+
+ case dwarf_r8_usr: return "r8_usr";
+ case dwarf_r9_usr: return "r9_usr";
+ case dwarf_r10_usr: return "r10_usr";
+ case dwarf_r11_usr: return "r11_usr";
+ case dwarf_r12_usr: return "r12_usr";
+ case dwarf_r13_usr: return "r13_usr";
+ case dwarf_r14_usr: return "r14_usr";
+ case dwarf_r8_fiq: return "r8_fiq";
+ case dwarf_r9_fiq: return "r9_fiq";
+ case dwarf_r10_fiq: return "r10_fiq";
+ case dwarf_r11_fiq: return "r11_fiq";
+ case dwarf_r12_fiq: return "r12_fiq";
+ case dwarf_r13_fiq: return "r13_fiq";
+ case dwarf_r14_fiq: return "r14_fiq";
+ case dwarf_r13_irq: return "r13_irq";
+ case dwarf_r14_irq: return "r14_irq";
+ case dwarf_r13_abt: return "r13_abt";
+ case dwarf_r14_abt: return "r14_abt";
+ case dwarf_r13_und: return "r13_und";
+ case dwarf_r14_und: return "r14_und";
+ case dwarf_r13_svc: return "r13_svc";
+ case dwarf_r14_svc: return "r14_svc";
+
+ // Intel wireless MMX control register in co-processor 0 - 7
+ case dwarf_wC0: return "wC0";
+ case dwarf_wC1: return "wC1";
+ case dwarf_wC2: return "wC2";
+ case dwarf_wC3: return "wC3";
+ case dwarf_wC4: return "wC4";
+ case dwarf_wC5: return "wC5";
+ case dwarf_wC6: return "wC6";
+ case dwarf_wC7: return "wC7";
+
+ // VFP-v3/Neon
+ case dwarf_d0: return "d0";
+ case dwarf_d1: return "d1";
+ case dwarf_d2: return "d2";
+ case dwarf_d3: return "d3";
+ case dwarf_d4: return "d4";
+ case dwarf_d5: return "d5";
+ case dwarf_d6: return "d6";
+ case dwarf_d7: return "d7";
+ case dwarf_d8: return "d8";
+ case dwarf_d9: return "d9";
+ case dwarf_d10: return "d10";
+ case dwarf_d11: return "d11";
+ case dwarf_d12: return "d12";
+ case dwarf_d13: return "d13";
+ case dwarf_d14: return "d14";
+ case dwarf_d15: return "d15";
+ case dwarf_d16: return "d16";
+ case dwarf_d17: return "d17";
+ case dwarf_d18: return "d18";
+ case dwarf_d19: return "d19";
+ case dwarf_d20: return "d20";
+ case dwarf_d21: return "d21";
+ case dwarf_d22: return "d22";
+ case dwarf_d23: return "d23";
+ case dwarf_d24: return "d24";
+ case dwarf_d25: return "d25";
+ case dwarf_d26: return "d26";
+ case dwarf_d27: return "d27";
+ case dwarf_d28: return "d28";
+ case dwarf_d29: return "d29";
+ case dwarf_d30: return "d30";
+ case dwarf_d31: return "d31";
+
+ // NEON 128-bit vector registers (overlays the d registers)
+ case dwarf_q0: return "q0";
+ case dwarf_q1: return "q1";
+ case dwarf_q2: return "q2";
+ case dwarf_q3: return "q3";
+ case dwarf_q4: return "q4";
+ case dwarf_q5: return "q5";
+ case dwarf_q6: return "q6";
+ case dwarf_q7: return "q7";
+ case dwarf_q8: return "q8";
+ case dwarf_q9: return "q9";
+ case dwarf_q10: return "q10";
+ case dwarf_q11: return "q11";
+ case dwarf_q12: return "q12";
+ case dwarf_q13: return "q13";
+ case dwarf_q14: return "q14";
+ case dwarf_q15: return "q15";
+ }
+ return 0;
+}
+
+bool
+GetARMDWARFRegisterInfo (unsigned reg_num, RegisterInfo &reg_info)
+{
+ ::memset (&reg_info, 0, sizeof(RegisterInfo));
+ ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds));
+
+ if (reg_num >= dwarf_q0 && reg_num <= dwarf_q15)
+ {
+ reg_info.byte_size = 16;
+ reg_info.format = eFormatVectorOfUInt8;
+ reg_info.encoding = eEncodingVector;
+ }
+
+ if (reg_num >= dwarf_d0 && reg_num <= dwarf_d31)
+ {
+ reg_info.byte_size = 8;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
+ else if (reg_num >= dwarf_s0 && reg_num <= dwarf_s31)
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
+ else if (reg_num >= dwarf_f0 && reg_num <= dwarf_f7)
+ {
+ reg_info.byte_size = 12;
+ reg_info.format = eFormatFloat;
+ reg_info.encoding = eEncodingIEEE754;
+ }
+ else
+ {
+ reg_info.byte_size = 4;
+ reg_info.format = eFormatHex;
+ reg_info.encoding = eEncodingUint;
+ }
+
+ reg_info.kinds[eRegisterKindDWARF] = reg_num;
+
+ switch (reg_num)
+ {
+ case dwarf_r0: reg_info.name = "r0"; break;
+ case dwarf_r1: reg_info.name = "r1"; break;
+ case dwarf_r2: reg_info.name = "r2"; break;
+ case dwarf_r3: reg_info.name = "r3"; break;
+ case dwarf_r4: reg_info.name = "r4"; break;
+ case dwarf_r5: reg_info.name = "r5"; break;
+ case dwarf_r6: reg_info.name = "r6"; break;
+ case dwarf_r7: reg_info.name = "r7"; reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break;
+ case dwarf_r8: reg_info.name = "r8"; break;
+ case dwarf_r9: reg_info.name = "r9"; break;
+ case dwarf_r10: reg_info.name = "r10"; break;
+ case dwarf_r11: reg_info.name = "r11"; break;
+ case dwarf_r12: reg_info.name = "r12"; break;
+ case dwarf_sp: reg_info.name = "sp"; reg_info.alt_name = "r13"; reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break;
+ case dwarf_lr: reg_info.name = "lr"; reg_info.alt_name = "r14"; reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break;
+ case dwarf_pc: reg_info.name = "pc"; reg_info.alt_name = "r15"; reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break;
+ case dwarf_cpsr:reg_info.name = "cpsr"; reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break;
+
+ case dwarf_s0: reg_info.name = "s0"; break;
+ case dwarf_s1: reg_info.name = "s1"; break;
+ case dwarf_s2: reg_info.name = "s2"; break;
+ case dwarf_s3: reg_info.name = "s3"; break;
+ case dwarf_s4: reg_info.name = "s4"; break;
+ case dwarf_s5: reg_info.name = "s5"; break;
+ case dwarf_s6: reg_info.name = "s6"; break;
+ case dwarf_s7: reg_info.name = "s7"; break;
+ case dwarf_s8: reg_info.name = "s8"; break;
+ case dwarf_s9: reg_info.name = "s9"; break;
+ case dwarf_s10: reg_info.name = "s10"; break;
+ case dwarf_s11: reg_info.name = "s11"; break;
+ case dwarf_s12: reg_info.name = "s12"; break;
+ case dwarf_s13: reg_info.name = "s13"; break;
+ case dwarf_s14: reg_info.name = "s14"; break;
+ case dwarf_s15: reg_info.name = "s15"; break;
+ case dwarf_s16: reg_info.name = "s16"; break;
+ case dwarf_s17: reg_info.name = "s17"; break;
+ case dwarf_s18: reg_info.name = "s18"; break;
+ case dwarf_s19: reg_info.name = "s19"; break;
+ case dwarf_s20: reg_info.name = "s20"; break;
+ case dwarf_s21: reg_info.name = "s21"; break;
+ case dwarf_s22: reg_info.name = "s22"; break;
+ case dwarf_s23: reg_info.name = "s23"; break;
+ case dwarf_s24: reg_info.name = "s24"; break;
+ case dwarf_s25: reg_info.name = "s25"; break;
+ case dwarf_s26: reg_info.name = "s26"; break;
+ case dwarf_s27: reg_info.name = "s27"; break;
+ case dwarf_s28: reg_info.name = "s28"; break;
+ case dwarf_s29: reg_info.name = "s29"; break;
+ case dwarf_s30: reg_info.name = "s30"; break;
+ case dwarf_s31: reg_info.name = "s31"; break;
+
+ // FPA Registers 0-7
+ case dwarf_f0: reg_info.name = "f0"; break;
+ case dwarf_f1: reg_info.name = "f1"; break;
+ case dwarf_f2: reg_info.name = "f2"; break;
+ case dwarf_f3: reg_info.name = "f3"; break;
+ case dwarf_f4: reg_info.name = "f4"; break;
+ case dwarf_f5: reg_info.name = "f5"; break;
+ case dwarf_f6: reg_info.name = "f6"; break;
+ case dwarf_f7: reg_info.name = "f7"; break;
+
+ // Intel wireless MMX general purpose registers 0 - 7
+ // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
+ case dwarf_wCGR0: reg_info.name = "wCGR0/ACC0"; break;
+ case dwarf_wCGR1: reg_info.name = "wCGR1/ACC1"; break;
+ case dwarf_wCGR2: reg_info.name = "wCGR2/ACC2"; break;
+ case dwarf_wCGR3: reg_info.name = "wCGR3/ACC3"; break;
+ case dwarf_wCGR4: reg_info.name = "wCGR4/ACC4"; break;
+ case dwarf_wCGR5: reg_info.name = "wCGR5/ACC5"; break;
+ case dwarf_wCGR6: reg_info.name = "wCGR6/ACC6"; break;
+ case dwarf_wCGR7: reg_info.name = "wCGR7/ACC7"; break;
+
+ // Intel wireless MMX data registers 0 - 15
+ case dwarf_wR0: reg_info.name = "wR0"; break;
+ case dwarf_wR1: reg_info.name = "wR1"; break;
+ case dwarf_wR2: reg_info.name = "wR2"; break;
+ case dwarf_wR3: reg_info.name = "wR3"; break;
+ case dwarf_wR4: reg_info.name = "wR4"; break;
+ case dwarf_wR5: reg_info.name = "wR5"; break;
+ case dwarf_wR6: reg_info.name = "wR6"; break;
+ case dwarf_wR7: reg_info.name = "wR7"; break;
+ case dwarf_wR8: reg_info.name = "wR8"; break;
+ case dwarf_wR9: reg_info.name = "wR9"; break;
+ case dwarf_wR10: reg_info.name = "wR10"; break;
+ case dwarf_wR11: reg_info.name = "wR11"; break;
+ case dwarf_wR12: reg_info.name = "wR12"; break;
+ case dwarf_wR13: reg_info.name = "wR13"; break;
+ case dwarf_wR14: reg_info.name = "wR14"; break;
+ case dwarf_wR15: reg_info.name = "wR15"; break;
+
+ case dwarf_spsr: reg_info.name = "spsr"; break;
+ case dwarf_spsr_fiq: reg_info.name = "spsr_fiq"; break;
+ case dwarf_spsr_irq: reg_info.name = "spsr_irq"; break;
+ case dwarf_spsr_abt: reg_info.name = "spsr_abt"; break;
+ case dwarf_spsr_und: reg_info.name = "spsr_und"; break;
+ case dwarf_spsr_svc: reg_info.name = "spsr_svc"; break;
+
+ case dwarf_r8_usr: reg_info.name = "r8_usr"; break;
+ case dwarf_r9_usr: reg_info.name = "r9_usr"; break;
+ case dwarf_r10_usr: reg_info.name = "r10_usr"; break;
+ case dwarf_r11_usr: reg_info.name = "r11_usr"; break;
+ case dwarf_r12_usr: reg_info.name = "r12_usr"; break;
+ case dwarf_r13_usr: reg_info.name = "r13_usr"; break;
+ case dwarf_r14_usr: reg_info.name = "r14_usr"; break;
+ case dwarf_r8_fiq: reg_info.name = "r8_fiq"; break;
+ case dwarf_r9_fiq: reg_info.name = "r9_fiq"; break;
+ case dwarf_r10_fiq: reg_info.name = "r10_fiq"; break;
+ case dwarf_r11_fiq: reg_info.name = "r11_fiq"; break;
+ case dwarf_r12_fiq: reg_info.name = "r12_fiq"; break;
+ case dwarf_r13_fiq: reg_info.name = "r13_fiq"; break;
+ case dwarf_r14_fiq: reg_info.name = "r14_fiq"; break;
+ case dwarf_r13_irq: reg_info.name = "r13_irq"; break;
+ case dwarf_r14_irq: reg_info.name = "r14_irq"; break;
+ case dwarf_r13_abt: reg_info.name = "r13_abt"; break;
+ case dwarf_r14_abt: reg_info.name = "r14_abt"; break;
+ case dwarf_r13_und: reg_info.name = "r13_und"; break;
+ case dwarf_r14_und: reg_info.name = "r14_und"; break;
+ case dwarf_r13_svc: reg_info.name = "r13_svc"; break;
+ case dwarf_r14_svc: reg_info.name = "r14_svc"; break;
+
+ // Intel wireless MMX control register in co-processor 0 - 7
+ case dwarf_wC0: reg_info.name = "wC0"; break;
+ case dwarf_wC1: reg_info.name = "wC1"; break;
+ case dwarf_wC2: reg_info.name = "wC2"; break;
+ case dwarf_wC3: reg_info.name = "wC3"; break;
+ case dwarf_wC4: reg_info.name = "wC4"; break;
+ case dwarf_wC5: reg_info.name = "wC5"; break;
+ case dwarf_wC6: reg_info.name = "wC6"; break;
+ case dwarf_wC7: reg_info.name = "wC7"; break;
+
+ // VFP-v3/Neon
+ case dwarf_d0: reg_info.name = "d0"; break;
+ case dwarf_d1: reg_info.name = "d1"; break;
+ case dwarf_d2: reg_info.name = "d2"; break;
+ case dwarf_d3: reg_info.name = "d3"; break;
+ case dwarf_d4: reg_info.name = "d4"; break;
+ case dwarf_d5: reg_info.name = "d5"; break;
+ case dwarf_d6: reg_info.name = "d6"; break;
+ case dwarf_d7: reg_info.name = "d7"; break;
+ case dwarf_d8: reg_info.name = "d8"; break;
+ case dwarf_d9: reg_info.name = "d9"; break;
+ case dwarf_d10: reg_info.name = "d10"; break;
+ case dwarf_d11: reg_info.name = "d11"; break;
+ case dwarf_d12: reg_info.name = "d12"; break;
+ case dwarf_d13: reg_info.name = "d13"; break;
+ case dwarf_d14: reg_info.name = "d14"; break;
+ case dwarf_d15: reg_info.name = "d15"; break;
+ case dwarf_d16: reg_info.name = "d16"; break;
+ case dwarf_d17: reg_info.name = "d17"; break;
+ case dwarf_d18: reg_info.name = "d18"; break;
+ case dwarf_d19: reg_info.name = "d19"; break;
+ case dwarf_d20: reg_info.name = "d20"; break;
+ case dwarf_d21: reg_info.name = "d21"; break;
+ case dwarf_d22: reg_info.name = "d22"; break;
+ case dwarf_d23: reg_info.name = "d23"; break;
+ case dwarf_d24: reg_info.name = "d24"; break;
+ case dwarf_d25: reg_info.name = "d25"; break;
+ case dwarf_d26: reg_info.name = "d26"; break;
+ case dwarf_d27: reg_info.name = "d27"; break;
+ case dwarf_d28: reg_info.name = "d28"; break;
+ case dwarf_d29: reg_info.name = "d29"; break;
+ case dwarf_d30: reg_info.name = "d30"; break;
+ case dwarf_d31: reg_info.name = "d31"; break;
+
+ // NEON 128-bit vector registers (overlays the d registers)
+ case dwarf_q0: reg_info.name = "q0"; break;
+ case dwarf_q1: reg_info.name = "q1"; break;
+ case dwarf_q2: reg_info.name = "q2"; break;
+ case dwarf_q3: reg_info.name = "q3"; break;
+ case dwarf_q4: reg_info.name = "q4"; break;
+ case dwarf_q5: reg_info.name = "q5"; break;
+ case dwarf_q6: reg_info.name = "q6"; break;
+ case dwarf_q7: reg_info.name = "q7"; break;
+ case dwarf_q8: reg_info.name = "q8"; break;
+ case dwarf_q9: reg_info.name = "q9"; break;
+ case dwarf_q10: reg_info.name = "q10"; break;
+ case dwarf_q11: reg_info.name = "q11"; break;
+ case dwarf_q12: reg_info.name = "q12"; break;
+ case dwarf_q13: reg_info.name = "q13"; break;
+ case dwarf_q14: reg_info.name = "q14"; break;
+ case dwarf_q15: reg_info.name = "q15"; break;
+
+ default: return false;
+ }
+ return true;
+}
diff --git a/source/Utility/ARM_DWARF_Registers.h b/source/Utility/ARM_DWARF_Registers.h
new file mode 100644
index 000000000000..6850d3e80f11
--- /dev/null
+++ b/source/Utility/ARM_DWARF_Registers.h
@@ -0,0 +1,217 @@
+//===-- ARM_DWARF_Registers.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_ARM_DWARF_Registers_h_
+#define utility_ARM_DWARF_Registers_h_
+
+#include "lldb/lldb-private.h"
+
+enum
+{
+ dwarf_r0 = 0,
+ dwarf_r1,
+ dwarf_r2,
+ dwarf_r3,
+ dwarf_r4,
+ dwarf_r5,
+ dwarf_r6,
+ dwarf_r7,
+ dwarf_r8,
+ dwarf_r9,
+ dwarf_r10,
+ dwarf_r11,
+ dwarf_r12,
+ dwarf_sp,
+ dwarf_lr,
+ dwarf_pc,
+ dwarf_cpsr,
+
+ dwarf_s0 = 64,
+ dwarf_s1,
+ dwarf_s2,
+ dwarf_s3,
+ dwarf_s4,
+ dwarf_s5,
+ dwarf_s6,
+ dwarf_s7,
+ dwarf_s8,
+ dwarf_s9,
+ dwarf_s10,
+ dwarf_s11,
+ dwarf_s12,
+ dwarf_s13,
+ dwarf_s14,
+ dwarf_s15,
+ dwarf_s16,
+ dwarf_s17,
+ dwarf_s18,
+ dwarf_s19,
+ dwarf_s20,
+ dwarf_s21,
+ dwarf_s22,
+ dwarf_s23,
+ dwarf_s24,
+ dwarf_s25,
+ dwarf_s26,
+ dwarf_s27,
+ dwarf_s28,
+ dwarf_s29,
+ dwarf_s30,
+ dwarf_s31,
+
+ // FPA Registers 0-7
+ dwarf_f0 = 96,
+ dwarf_f1,
+ dwarf_f2,
+ dwarf_f3,
+ dwarf_f4,
+ dwarf_f5,
+ dwarf_f6,
+ dwarf_f7,
+
+ // Intel wireless MMX general purpose registers 0 - 7
+ dwarf_wCGR0 = 104,
+ dwarf_wCGR1,
+ dwarf_wCGR2,
+ dwarf_wCGR3,
+ dwarf_wCGR4,
+ dwarf_wCGR5,
+ dwarf_wCGR6,
+ dwarf_wCGR7,
+
+ // XScale accumulator register 0 - 7 (they do overlap with wCGR0 - wCGR7)
+ dwarf_ACC0 = 104,
+ dwarf_ACC1,
+ dwarf_ACC2,
+ dwarf_ACC3,
+ dwarf_ACC4,
+ dwarf_ACC5,
+ dwarf_ACC6,
+ dwarf_ACC7,
+
+ // Intel wireless MMX data registers 0 - 15
+ dwarf_wR0 = 112,
+ dwarf_wR1,
+ dwarf_wR2,
+ dwarf_wR3,
+ dwarf_wR4,
+ dwarf_wR5,
+ dwarf_wR6,
+ dwarf_wR7,
+ dwarf_wR8,
+ dwarf_wR9,
+ dwarf_wR10,
+ dwarf_wR11,
+ dwarf_wR12,
+ dwarf_wR13,
+ dwarf_wR14,
+ dwarf_wR15,
+
+ dwarf_spsr = 128,
+ dwarf_spsr_fiq,
+ dwarf_spsr_irq,
+ dwarf_spsr_abt,
+ dwarf_spsr_und,
+ dwarf_spsr_svc,
+
+ dwarf_r8_usr = 144,
+ dwarf_r9_usr,
+ dwarf_r10_usr,
+ dwarf_r11_usr,
+ dwarf_r12_usr,
+ dwarf_r13_usr,
+ dwarf_r14_usr,
+ dwarf_r8_fiq,
+ dwarf_r9_fiq,
+ dwarf_r10_fiq,
+ dwarf_r11_fiq,
+ dwarf_r12_fiq,
+ dwarf_r13_fiq,
+ dwarf_r14_fiq,
+ dwarf_r13_irq,
+ dwarf_r14_irq,
+ dwarf_r13_abt,
+ dwarf_r14_abt,
+ dwarf_r13_und,
+ dwarf_r14_und,
+ dwarf_r13_svc,
+ dwarf_r14_svc,
+
+ // Intel wireless MMX control register in co-processor 0 - 7
+ dwarf_wC0 = 192,
+ dwarf_wC1,
+ dwarf_wC2,
+ dwarf_wC3,
+ dwarf_wC4,
+ dwarf_wC5,
+ dwarf_wC6,
+ dwarf_wC7,
+
+ // VFP-v3/Neon
+ dwarf_d0 = 256,
+ dwarf_d1,
+ dwarf_d2,
+ dwarf_d3,
+ dwarf_d4,
+ dwarf_d5,
+ dwarf_d6,
+ dwarf_d7,
+ dwarf_d8,
+ dwarf_d9,
+ dwarf_d10,
+ dwarf_d11,
+ dwarf_d12,
+ dwarf_d13,
+ dwarf_d14,
+ dwarf_d15,
+ dwarf_d16,
+ dwarf_d17,
+ dwarf_d18,
+ dwarf_d19,
+ dwarf_d20,
+ dwarf_d21,
+ dwarf_d22,
+ dwarf_d23,
+ dwarf_d24,
+ dwarf_d25,
+ dwarf_d26,
+ dwarf_d27,
+ dwarf_d28,
+ dwarf_d29,
+ dwarf_d30,
+ dwarf_d31,
+
+ // Neon quadword registers
+ dwarf_q0 = 288,
+ dwarf_q1,
+ dwarf_q2,
+ dwarf_q3,
+ dwarf_q4,
+ dwarf_q5,
+ dwarf_q6,
+ dwarf_q7,
+ dwarf_q8,
+ dwarf_q9,
+ dwarf_q10,
+ dwarf_q11,
+ dwarf_q12,
+ dwarf_q13,
+ dwarf_q14,
+ dwarf_q15
+};
+
+const char *
+GetARMDWARFRegisterName (unsigned reg_num);
+
+bool
+GetARMDWARFRegisterInfo (unsigned reg_num,
+ lldb_private::RegisterInfo &reg_info);
+
+#endif // utility_ARM_DWARF_Registers_h_
+
diff --git a/source/Utility/ARM_GCC_Registers.h b/source/Utility/ARM_GCC_Registers.h
new file mode 100644
index 000000000000..974d01bfc78a
--- /dev/null
+++ b/source/Utility/ARM_GCC_Registers.h
@@ -0,0 +1,146 @@
+//===-- ARM_GCC_Registers.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef utility_ARM_GCC_Registers_h_
+#define utility_ARM_GCC_Registers_h_
+
+enum
+{
+ gcc_r0 = 0,
+ gcc_r1,
+ gcc_r2,
+ gcc_r3,
+ gcc_r4,
+ gcc_r5,
+ gcc_r6,
+ gcc_r7,
+ gcc_r8,
+ gcc_r9,
+ gcc_r10,
+ gcc_r11,
+ gcc_r12,
+ gcc_sp,
+ gcc_lr,
+ gcc_pc,
+ gcc_cpsr
+};
+
+enum
+{
+// Name Nr Rel Offset Size Type Raw value
+ gdb_arm_r0 = 0, // 0 0 4 int32_t
+ gdb_arm_r1 = 1, // 1 4 4 int32_t
+ gdb_arm_r2 = 2, // 2 8 4 int32_t
+ gdb_arm_r3 = 3, // 3 12 4 int32_t
+ gdb_arm_r4 = 4, // 4 16 4 int32_t
+ gdb_arm_r5 = 5, // 5 20 4 int32_t
+ gdb_arm_r6 = 6, // 6 24 4 int32_t
+ gdb_arm_r7 = 7, // 7 28 4 int32_t
+ gdb_arm_r8 = 8, // 8 32 4 int32_t
+ gdb_arm_r9 = 9, // 9 36 4 int32_t
+ gdb_arm_r10 = 10, // 10 40 4 int32_t
+ gdb_arm_r11 = 11, // 11 44 4 int32_t
+ gdb_arm_r12 = 12, // 12 48 4 int32_t
+ gdb_arm_sp = 13, // 13 52 4 int32_t
+ gdb_arm_lr = 14, // 14 56 4 int32_t
+ gdb_arm_pc = 15, // 15 60 4 int32_t
+ gdb_arm_f0 = 16, // 16 64 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f1 = 17, // 17 76 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f2 = 18, // 18 88 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f3 = 19, // 19 100 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f4 = 20, // 20 112 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f5 = 21, // 21 124 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f6 = 22, // 22 136 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f7 = 23, // 23 148 12 _arm_ext_littlebyte_bigword
+ gdb_arm_f8 = 24, // 24 160 12 _arm_ext_littlebyte_bigword
+ gdb_arm_cpsr = 25, // 25 172 4 int32_t
+ gdb_arm_s0 = 26, // 26 176 4 _ieee_single_little
+ gdb_arm_s1 = 27, // 27 180 4 _ieee_single_little
+ gdb_arm_s2 = 28, // 28 184 4 _ieee_single_little
+ gdb_arm_s3 = 29, // 29 188 4 _ieee_single_little
+ gdb_arm_s4 = 30, // 30 192 4 _ieee_single_little
+ gdb_arm_s5 = 31, // 31 196 4 _ieee_single_little
+ gdb_arm_s6 = 32, // 32 200 4 _ieee_single_little
+ gdb_arm_s7 = 33, // 33 204 4 _ieee_single_little
+ gdb_arm_s8 = 34, // 34 208 4 _ieee_single_little
+ gdb_arm_s9 = 35, // 35 212 4 _ieee_single_little
+ gdb_arm_s10 = 36, // 36 216 4 _ieee_single_little
+ gdb_arm_s11 = 37, // 37 220 4 _ieee_single_little
+ gdb_arm_s12 = 38, // 38 224 4 _ieee_single_little
+ gdb_arm_s13 = 39, // 39 228 4 _ieee_single_little
+ gdb_arm_s14 = 40, // 40 232 4 _ieee_single_little
+ gdb_arm_s15 = 41, // 41 236 4 _ieee_single_little
+ gdb_arm_s16 = 42, // 42 240 4 _ieee_single_little
+ gdb_arm_s17 = 43, // 43 244 4 _ieee_single_little
+ gdb_arm_s18 = 44, // 44 248 4 _ieee_single_little
+ gdb_arm_s19 = 45, // 45 252 4 _ieee_single_little
+ gdb_arm_s20 = 46, // 46 256 4 _ieee_single_little
+ gdb_arm_s21 = 47, // 47 260 4 _ieee_single_little
+ gdb_arm_s22 = 48, // 48 264 4 _ieee_single_little
+ gdb_arm_s23 = 49, // 49 268 4 _ieee_single_little
+ gdb_arm_s24 = 50, // 50 272 4 _ieee_single_little
+ gdb_arm_s25 = 51, // 51 276 4 _ieee_single_little
+ gdb_arm_s26 = 52, // 52 280 4 _ieee_single_little
+ gdb_arm_s27 = 53, // 53 284 4 _ieee_single_little
+ gdb_arm_s28 = 54, // 54 288 4 _ieee_single_little
+ gdb_arm_s29 = 55, // 55 292 4 _ieee_single_little
+ gdb_arm_s30 = 56, // 56 296 4 _ieee_single_little
+ gdb_arm_s31 = 57, // 57 300 4 _ieee_single_little
+ gdb_arm_fpscr = 58, // 58 304 4 int32_t
+ gdb_arm_d16 = 59, // 59 308 8 _ieee_double_little
+ gdb_arm_d17 = 60, // 60 316 8 _ieee_double_little
+ gdb_arm_d18 = 61, // 61 324 8 _ieee_double_little
+ gdb_arm_d19 = 62, // 62 332 8 _ieee_double_little
+ gdb_arm_d20 = 63, // 63 340 8 _ieee_double_little
+ gdb_arm_d21 = 64, // 64 348 8 _ieee_double_little
+ gdb_arm_d22 = 65, // 65 356 8 _ieee_double_little
+ gdb_arm_d23 = 66, // 66 364 8 _ieee_double_little
+ gdb_arm_d24 = 67, // 67 372 8 _ieee_double_little
+ gdb_arm_d25 = 68, // 68 380 8 _ieee_double_little
+ gdb_arm_d26 = 69, // 69 388 8 _ieee_double_little
+ gdb_arm_d27 = 70, // 70 396 8 _ieee_double_little
+ gdb_arm_d28 = 71, // 71 404 8 _ieee_double_little
+ gdb_arm_d29 = 72, // 72 412 8 _ieee_double_little
+ gdb_arm_d30 = 73, // 73 420 8 _ieee_double_little
+ gdb_arm_d31 = 74, // 74 428 8 _ieee_double_little
+ gdb_arm_d0 = 75, // 0 436 8 _ieee_double_little
+ gdb_arm_d1 = 76, // 1 444 8 _ieee_double_little
+ gdb_arm_d2 = 77, // 2 452 8 _ieee_double_little
+ gdb_arm_d3 = 78, // 3 460 8 _ieee_double_little
+ gdb_arm_d4 = 79, // 4 468 8 _ieee_double_little
+ gdb_arm_d5 = 80, // 5 476 8 _ieee_double_little
+ gdb_arm_d6 = 81, // 6 484 8 _ieee_double_little
+ gdb_arm_d7 = 82, // 7 492 8 _ieee_double_little
+ gdb_arm_d8 = 83, // 8 500 8 _ieee_double_little
+ gdb_arm_d9 = 84, // 9 508 8 _ieee_double_little
+ gdb_arm_d10 = 85, // 10 516 8 _ieee_double_little
+ gdb_arm_d11 = 86, // 11 524 8 _ieee_double_little
+ gdb_arm_d12 = 87, // 12 532 8 _ieee_double_little
+ gdb_arm_d13 = 88, // 13 540 8 _ieee_double_little
+ gdb_arm_d14 = 89, // 14 548 8 _ieee_double_little
+ gdb_arm_d15 = 90, // 15 556 8 _ieee_double_little
+ gdb_arm_q0 = 91, // 16 564 16 _vec128
+ gdb_arm_q1 = 92, // 17 580 16 _vec128
+ gdb_arm_q2 = 93, // 18 596 16 _vec128
+ gdb_arm_q3 = 94, // 19 612 16 _vec128
+ gdb_arm_q4 = 95, // 20 628 16 _vec128
+ gdb_arm_q5 = 96, // 21 644 16 _vec128
+ gdb_arm_q6 = 97, // 22 660 16 _vec128
+ gdb_arm_q7 = 98, // 23 676 16 _vec128
+ gdb_arm_q8 = 99, // 24 692 16 _vec128
+ gdb_arm_q9 = 100, // 25 708 16 _vec128
+ gdb_arm_q10 = 101, // 26 724 16 _vec128
+ gdb_arm_q11 = 102, // 27 740 16 _vec128
+ gdb_arm_q12 = 103, // 28 756 16 _vec128
+ gdb_arm_q13 = 104, // 29 772 16 _vec128
+ gdb_arm_q14 = 105, // 30 788 16 _vec128
+ gdb_arm_q15 = 106 // 31 804 16 _vec128
+};
+#endif // utility_ARM_GCC_Registers_h_
+
diff --git a/source/Utility/KQueue.cpp b/source/Utility/KQueue.cpp
new file mode 100644
index 000000000000..c0aace448951
--- /dev/null
+++ b/source/Utility/KQueue.cpp
@@ -0,0 +1,87 @@
+//===--------------------- KQueue.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "KQueue.h"
+
+#ifdef LLDB_USE_KQUEUES
+
+#include "lldb/Core/Error.h"
+
+#include "Utility/TimeSpecTimeout.h"
+
+using namespace lldb_private;
+
+int
+KQueue::GetFD (bool can_create)
+{
+ if (!IsValid () && can_create)
+ m_fd = kqueue();
+ return m_fd;
+}
+
+int
+KQueue::Close ()
+{
+ const int fd = m_fd;
+ if (fd >= 0)
+ {
+ m_fd = -1;
+ return close(fd);
+ }
+ return 0;
+}
+
+int
+KQueue::WaitForEvents (struct kevent *events, int num_events, Error &error, uint32_t timeout_usec)
+{
+ const int fd_kqueue = GetFD(false);
+ if (fd_kqueue >= 0)
+ {
+ TimeSpecTimeout timeout;
+ const struct timespec *timeout_ptr = timeout.SetRelativeTimeoutMircoSeconds32 (timeout_usec);
+ int result = ::kevent(fd_kqueue, NULL, 0, events, num_events, timeout_ptr);
+ if (result == -1)
+ error.SetErrorToErrno();
+ else
+ error.Clear();
+ return result;
+ }
+ else
+ {
+ error.SetErrorString("invalid kqueue fd");
+ }
+ return 0;
+}
+
+bool
+KQueue::AddFDEvent (int fd, bool read, bool write, bool vnode)
+{
+ const int fd_kqueue = GetFD(true);
+ if (fd_kqueue >= 0)
+ {
+ struct kevent event;
+ event.ident = fd;
+ event.filter = 0;
+ if (read)
+ event.filter |= EVFILT_READ;
+ if (write)
+ event.filter |= EVFILT_WRITE;
+ if (vnode)
+ event.filter |= EVFILT_VNODE;
+ event.flags = EV_ADD | EV_CLEAR;
+ event.fflags = 0;
+ event.data = 0;
+ event.udata = NULL;
+ int err = ::kevent(fd_kqueue, &event, 1, NULL, 0, NULL);
+ return err == 0;
+ }
+ return false;
+}
+
+#endif
diff --git a/source/Utility/KQueue.h b/source/Utility/KQueue.h
new file mode 100644
index 000000000000..c5680aaa6314
--- /dev/null
+++ b/source/Utility/KQueue.h
@@ -0,0 +1,72 @@
+//===--------------------- KQueue.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_KQueue_h_
+#define utility_KQueue_h_
+
+#if defined(__APPLE__)
+#define LLDB_USE_KQUEUES
+#endif
+
+#ifdef LLDB_USE_KQUEUES
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#include "lldb/lldb-defines.h"
+
+namespace lldb_private {
+
+class KQueue
+{
+public:
+ KQueue() :
+ m_fd(-1)
+ {
+ }
+
+ ~KQueue()
+ {
+ Close();
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_fd >= 0;
+ }
+
+ int
+ GetFD (bool can_create);
+
+ int
+ Close ();
+
+ bool
+ AddFDEvent (int fd,
+ bool read,
+ bool write,
+ bool vnode);
+
+ int
+ WaitForEvents (struct kevent *events,
+ int num_events,
+ Error &error,
+ uint32_t timeout_usec = UINT32_MAX); // UINT32_MAX means infinite timeout
+
+protected:
+ int m_fd; // The kqueue fd
+};
+
+} // namespace lldb_private
+
+#endif // #ifdef LLDB_USE_KQUEUES
+
+#endif // #ifndef utility_KQueue_h_
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
new file mode 100644
index 000000000000..e4b444c36873
--- /dev/null
+++ b/source/Utility/PseudoTerminal.cpp
@@ -0,0 +1,339 @@
+//===-- PseudoTerminal.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/PseudoTerminal.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#if defined(TIOCSCTTY)
+#include <sys/ioctl.h>
+#endif
+
+using namespace lldb_utility;
+
+//----------------------------------------------------------------------
+// PseudoTerminal constructor
+//----------------------------------------------------------------------
+PseudoTerminal::PseudoTerminal () :
+ m_master_fd(invalid_fd),
+ m_slave_fd(invalid_fd)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//
+// The destructor will close the master and slave file descriptors
+// if they are valid and ownwership has not been released using the
+// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor()
+// member functions.
+//----------------------------------------------------------------------
+PseudoTerminal::~PseudoTerminal ()
+{
+ CloseMasterFileDescriptor();
+ CloseSlaveFileDescriptor();
+}
+
+//----------------------------------------------------------------------
+// Close the master file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseMasterFileDescriptor ()
+{
+ if (m_master_fd >= 0)
+ {
+ ::close (m_master_fd);
+ m_master_fd = invalid_fd;
+ }
+}
+
+//----------------------------------------------------------------------
+// Close the slave file descriptor if it is valid.
+//----------------------------------------------------------------------
+void
+PseudoTerminal::CloseSlaveFileDescriptor ()
+{
+ if (m_slave_fd >= 0)
+ {
+ ::close (m_slave_fd);
+ m_slave_fd = invalid_fd;
+ }
+}
+
+//----------------------------------------------------------------------
+// Open the first available pseudo terminal with OFLAG as the
+// permissions. The file descriptor is stored in this object and can
+// be accessed with the MasterFileDescriptor() accessor. The
+// ownership of the master file descriptor can be released using
+// the ReleaseMasterFileDescriptor() accessor. If this object has
+// a valid master files descriptor when its destructor is called, it
+// will close the master file descriptor, therefore clients must
+// call ReleaseMasterFileDescriptor() if they wish to use the master
+// file descriptor after this object is out of scope or destroyed.
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ // Open the master side of a pseudo terminal
+ m_master_fd = ::posix_openpt (oflag);
+ if (m_master_fd < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ return false;
+ }
+
+ // Grant access to the slave pseudo terminal
+ if (::grantpt (m_master_fd) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ CloseMasterFileDescriptor ();
+ return false;
+ }
+
+ // Clear the lock flag on the slave pseudo terminal
+ if (::unlockpt (m_master_fd) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ CloseMasterFileDescriptor ();
+ return false;
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------
+// Open the slave pseudo terminal for the current master pseudo
+// terminal. A master pseudo terminal should already be valid prior to
+// calling this function (see OpenFirstAvailableMaster()).
+// The file descriptor is stored this object's member variables and can
+// be accessed via the GetSlaveFileDescriptor(), or released using the
+// ReleaseSlaveFileDescriptor() member function.
+//
+// RETURNS:
+// Zero when successful, non-zero indicating an error occurred.
+//----------------------------------------------------------------------
+bool
+PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ CloseSlaveFileDescriptor();
+
+ // Open the master side of a pseudo terminal
+ const char *slave_name = GetSlaveName (error_str, error_len);
+
+ if (slave_name == NULL)
+ return false;
+
+ m_slave_fd = ::open (slave_name, oflag);
+
+ if (m_slave_fd < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ return false;
+ }
+
+ return true;
+}
+
+
+
+//----------------------------------------------------------------------
+// Get the name of the slave pseudo terminal. A master pseudo terminal
+// should already be valid prior to calling this function (see
+// OpenFirstAvailableMaster()).
+//
+// RETURNS:
+// NULL if no valid master pseudo terminal or if ptsname() fails.
+// The name of the slave pseudo terminal as a NULL terminated C string
+// that comes from static memory, so a copy of the string should be
+// made as subsequent calls can change this value.
+//----------------------------------------------------------------------
+const char*
+PseudoTerminal::GetSlaveName (char *error_str, size_t error_len) const
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ if (m_master_fd < 0)
+ {
+ if (error_str)
+ ::snprintf (error_str, error_len, "%s", "master file descriptor is invalid");
+ return NULL;
+ }
+ const char *slave_name = ::ptsname (m_master_fd);
+
+ if (error_str && slave_name == NULL)
+ ::strerror_r (errno, error_str, error_len);
+
+ return slave_name;
+}
+
+
+//----------------------------------------------------------------------
+// Fork a child process and have its stdio routed to a pseudo terminal.
+//
+// In the parent process when a valid pid is returned, the master file
+// descriptor can be used as a read/write access to stdio of the
+// child process.
+//
+// In the child process the stdin/stdout/stderr will already be routed
+// to the slave pseudo terminal and the master file descriptor will be
+// closed as it is no longer needed by the child process.
+//
+// This class will close the file descriptors for the master/slave
+// when the destructor is called, so be sure to call
+// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any
+// file descriptors are going to be used past the lifespan of this
+// object.
+//
+// RETURNS:
+// in the parent process: the pid of the child, or -1 if fork fails
+// in the child process: zero
+//----------------------------------------------------------------------
+lldb::pid_t
+PseudoTerminal::Fork (char *error_str, size_t error_len)
+{
+ if (error_str)
+ error_str[0] = '\0';
+
+ pid_t pid = LLDB_INVALID_PROCESS_ID;
+ if (OpenFirstAvailableMaster (O_RDWR, error_str, error_len))
+ {
+ // Successfully opened our master pseudo terminal
+
+ pid = ::fork ();
+ if (pid < 0)
+ {
+ // Fork failed
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ }
+ else if (pid == 0)
+ {
+ // Child Process
+ ::setsid();
+
+ if (OpenSlave (O_RDWR, error_str, error_len))
+ {
+ // Successfully opened slave
+ // We are done with the master in the child process so lets close it
+ CloseMasterFileDescriptor ();
+
+#if defined(TIOCSCTTY)
+ // Acquire the controlling terminal
+ if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0)
+ {
+ if (error_str)
+ ::strerror_r (errno, error_str, error_len);
+ }
+#endif
+ // Duplicate all stdio file descriptors to the slave pseudo terminal
+ if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+
+ if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+
+ if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO)
+ {
+ if (error_str && !error_str[0])
+ ::strerror_r (errno, error_str, error_len);
+ }
+ }
+ }
+ else
+ {
+ // Parent Process
+ // Do nothing and let the pid get returned!
+ }
+ }
+ return pid;
+}
+
+//----------------------------------------------------------------------
+// The master file descriptor accessor. This object retains ownership
+// of the master file descriptor when this accessor is used. Use
+// ReleaseMasterFileDescriptor() if you wish this object to release
+// ownership of the master file descriptor.
+//
+// Returns the master file descriptor, or -1 if the master file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetMasterFileDescriptor () const
+{
+ return m_master_fd;
+}
+
+//----------------------------------------------------------------------
+// The slave file descriptor accessor.
+//
+// Returns the slave file descriptor, or -1 if the slave file
+// descriptor is not currently valid.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::GetSlaveFileDescriptor () const
+{
+ return m_slave_fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the master pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// master file descriptor if the ownership isn't released using this
+// call and the master file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseMasterFileDescriptor ()
+{
+ // Release ownership of the master pseudo terminal file
+ // descriptor without closing it. (the destructor for this
+ // class will close it otherwise!)
+ int fd = m_master_fd;
+ m_master_fd = invalid_fd;
+ return fd;
+}
+
+//----------------------------------------------------------------------
+// Release ownership of the slave pseudo terminal file descriptor
+// without closing it. The destructor for this class will close the
+// slave file descriptor if the ownership isn't released using this
+// call and the slave file descriptor has been opened.
+//----------------------------------------------------------------------
+int
+PseudoTerminal::ReleaseSlaveFileDescriptor ()
+{
+ // Release ownership of the slave pseudo terminal file
+ // descriptor without closing it (the destructor for this
+ // class will close it otherwise!)
+ int fd = m_slave_fd;
+ m_slave_fd = invalid_fd;
+ return fd;
+}
+
diff --git a/source/Utility/Range.cpp b/source/Utility/Range.cpp
new file mode 100644
index 000000000000..158d1e729d48
--- /dev/null
+++ b/source/Utility/Range.cpp
@@ -0,0 +1,103 @@
+//===--------------------- Range.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/Range.h"
+
+using namespace lldb_utility;
+
+Range::Range (const Range& rng) :
+m_low(rng.m_low),
+m_high(rng.m_high)
+{
+ InitRange();
+}
+
+Range::Range (Range::ValueType low,
+ Range::ValueType high) :
+m_low(low),
+m_high(high)
+{
+ InitRange();
+}
+
+void
+Range::InitRange ()
+{
+ if (m_low == OPEN_END)
+ {
+ if (m_high == OPEN_END)
+ m_low = 0;
+ else
+ {
+ // make an empty range
+ m_low = 1;
+ m_high = 0;
+ }
+ }
+}
+
+Range&
+Range::operator = (const Range& rhs)
+{
+ if (&rhs != this)
+ {
+ this->m_low = rhs.m_low;
+ this->m_high = rhs.m_high;
+ }
+ return *this;
+}
+
+void
+Range::Flip ()
+{
+ std::swap(m_high, m_low);
+}
+
+void
+Range::Intersection (const Range& other)
+{
+ m_low = std::max(m_low,other.m_low);
+ m_high = std::min(m_high,other.m_high);
+}
+
+void
+Range::Union (const Range& other)
+{
+ m_low = std::min(m_low,other.m_low);
+ m_high = std::max(m_high,other.m_high);
+}
+
+void
+Range::Iterate (RangeCallback callback)
+{
+ ValueType counter = m_low;
+ while (counter <= m_high)
+ {
+ bool should_continue = callback(counter);
+ if (!should_continue)
+ return;
+ counter++;
+ }
+}
+
+bool
+Range::IsEmpty ()
+{
+ return (m_low > m_high);
+}
+
+Range::ValueType
+Range::GetSize ()
+{
+ if (m_high == OPEN_END)
+ return OPEN_END;
+ if (m_high >= m_low)
+ return m_high - m_low + 1;
+ return 0;
+}
diff --git a/source/Utility/RefCounter.cpp b/source/Utility/RefCounter.cpp
new file mode 100644
index 000000000000..c3acedd2f056
--- /dev/null
+++ b/source/Utility/RefCounter.cpp
@@ -0,0 +1,25 @@
+//===---------------------RefCounter.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/RefCounter.h"
+
+namespace lldb_utility {
+
+RefCounter::RefCounter(RefCounter::value_type* ctr):
+m_counter(ctr)
+{
+ increment(m_counter);
+}
+
+RefCounter::~RefCounter()
+{
+ decrement(m_counter);
+}
+
+} // namespace lldb_utility
diff --git a/source/Utility/SharingPtr.cpp b/source/Utility/SharingPtr.cpp
new file mode 100644
index 000000000000..f64d7e3995b8
--- /dev/null
+++ b/source/Utility/SharingPtr.cpp
@@ -0,0 +1,158 @@
+//===---------------------SharingPtr.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/SharingPtr.h"
+
+#if defined (ENABLE_SP_LOGGING)
+
+// If ENABLE_SP_LOGGING is defined, then log all shared pointer assignements
+// and allow them to be queried using a pointer by a call to:
+#include <execinfo.h>
+#include <map>
+#include <assert.h>
+#include "lldb/Host/Mutex.h"
+
+#include <vector>
+
+class Backtrace
+{
+public:
+ Backtrace ();
+
+ ~Backtrace ();
+
+ void
+ GetFrames ();
+
+ void
+ Dump () const;
+
+private:
+ void *m_sp_this;
+ std::vector<void *> m_frames;
+};
+
+
+Backtrace::Backtrace () : m_frames()
+{
+}
+
+Backtrace::~Backtrace ()
+{
+}
+
+void
+Backtrace::GetFrames ()
+{
+ void *frames[1024];
+ const int count = ::backtrace (frames, sizeof(frames)/sizeof(void*));
+ if (count > 2)
+ m_frames.assign (frames + 2, frames + (count - 2));
+}
+
+void
+Backtrace::Dump () const
+{
+ if (!m_frames.empty())
+ ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), STDOUT_FILENO);
+ write (STDOUT_FILENO, "\n\n", 2);
+}
+
+extern "C" void track_sp (void *sp_this, void *ptr, long use_count)
+{
+ typedef std::pair<void *, Backtrace> PtrBacktracePair;
+ typedef std::map<void *, PtrBacktracePair> PtrToBacktraceMap;
+ static lldb_private::Mutex g_mutex(lldb_private::Mutex::eMutexTypeNormal);
+ lldb_private::Mutex::Locker locker (g_mutex);
+ static PtrToBacktraceMap g_map;
+
+ if (sp_this)
+ {
+ printf ("sp(%p) -> %p %lu\n", sp_this, ptr, use_count);
+
+ if (ptr)
+ {
+ Backtrace bt;
+ bt.GetFrames();
+ g_map[sp_this] = std::make_pair(ptr, bt);
+ }
+ else
+ {
+ g_map.erase (sp_this);
+ }
+ }
+ else
+ {
+ if (ptr)
+ printf ("Searching for shared pointers that are tracking %p: ", ptr);
+ else
+ printf ("Dump all live shared pointres: ");
+
+ uint32_t matches = 0;
+ PtrToBacktraceMap::iterator pos, end = g_map.end();
+ for (pos = g_map.begin(); pos != end; ++pos)
+ {
+ if (ptr == NULL || pos->second.first == ptr)
+ {
+ ++matches;
+ printf ("\nsp(%p): %p\n", pos->first, pos->second.first);
+ pos->second.second.Dump();
+ }
+ }
+ if (matches == 0)
+ {
+ printf ("none.\n");
+ }
+ }
+}
+// Put dump_sp_refs in the lldb namespace to it gets through our exports lists filter in the LLDB.framework or lldb.so
+namespace lldb {
+
+ void dump_sp_refs (void *ptr)
+ {
+ // Use a specially crafted call to "track_sp" which will
+ // dump info on all live shared pointers that reference "ptr"
+ track_sp (NULL, ptr, 0);
+ }
+
+}
+
+#endif
+
+namespace lldb_private {
+
+namespace imp
+{
+
+
+ shared_count::~shared_count()
+ {
+ }
+
+ void
+ shared_count::add_shared()
+ {
+ increment(shared_owners_);
+ }
+
+ void
+ shared_count::release_shared()
+ {
+ if (decrement(shared_owners_) == -1)
+ {
+ on_zero_shared();
+ delete this;
+ }
+ }
+
+} // imp
+
+
+} // namespace lldb
+
diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp
new file mode 100644
index 000000000000..2f4bcecda8f3
--- /dev/null
+++ b/source/Utility/StringExtractor.cpp
@@ -0,0 +1,397 @@
+//===-- StringExtractor.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/StringExtractor.h"
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// 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)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ if (ch >= 'A' && ch <= 'F')
+ return 10 + ch - 'A';
+ return ch - '0';
+}
+
+static inline unsigned int
+xdigit_to_uint (uint8_t ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return 10u + ch - 'a';
+ if (ch >= 'A' && ch <= 'F')
+ return 10u + ch - 'A';
+ return ch - '0';
+}
+
+//----------------------------------------------------------------------
+// StringExtractor constructor
+//----------------------------------------------------------------------
+StringExtractor::StringExtractor() :
+ m_packet(),
+ m_index (0)
+{
+}
+
+
+StringExtractor::StringExtractor(const char *packet_cstr) :
+ m_packet(),
+ m_index (0)
+{
+ if (packet_cstr)
+ m_packet.assign (packet_cstr);
+}
+
+
+//----------------------------------------------------------------------
+// StringExtractor copy constructor
+//----------------------------------------------------------------------
+StringExtractor::StringExtractor(const StringExtractor& rhs) :
+ m_packet (rhs.m_packet),
+ m_index (rhs.m_index)
+{
+
+}
+
+//----------------------------------------------------------------------
+// StringExtractor assignment operator
+//----------------------------------------------------------------------
+const StringExtractor&
+StringExtractor::operator=(const StringExtractor& rhs)
+{
+ if (this != &rhs)
+ {
+ m_packet = rhs.m_packet;
+ m_index = rhs.m_index;
+
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StringExtractor::~StringExtractor()
+{
+}
+
+
+char
+StringExtractor::GetChar (char fail_value)
+{
+ if (m_index < m_packet.size())
+ {
+ char ch = m_packet[m_index];
+ ++m_index;
+ return ch;
+ }
+ m_index = UINT64_MAX;
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// 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)
+{
+ uint32_t i = m_index;
+ if ((i + 2) <= m_packet.size())
+ {
+ const uint8_t hi_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i])];
+ const uint8_t lo_nibble = g_hex_ascii_to_hex_integer[static_cast<uint8_t>(m_packet[i+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;
+}
+
+uint32_t
+StringExtractor::GetU32 (uint32_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = NULL;
+ const char *start = m_packet.c_str();
+ const char *uint_cstr = start + m_index;
+ uint32_t result = ::strtoul (uint_cstr, &end, base);
+
+ if (end && end != uint_cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+
+uint32_t
+StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
+{
+ uint32_t result = 0;
+ uint32_t nibble_count = 0;
+
+ if (little_endian)
+ {
+ uint32_t shift_amount = 0;
+ while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ // Make sure we don't exceed the size of a uint32_t...
+ if (nibble_count >= (sizeof(uint32_t) * 2))
+ {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble_lo;
+ uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
+ ++m_index;
+ if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ nibble_lo = xdigit_to_sint (m_packet[m_index]);
+ ++m_index;
+ result |= ((uint32_t)nibble_hi << (shift_amount + 4));
+ result |= ((uint32_t)nibble_lo << shift_amount);
+ nibble_count += 2;
+ shift_amount += 8;
+ }
+ else
+ {
+ result |= ((uint32_t)nibble_hi << shift_amount);
+ nibble_count += 1;
+ shift_amount += 4;
+ }
+
+ }
+ }
+ else
+ {
+ while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ // Make sure we don't exceed the size of a uint32_t...
+ if (nibble_count >= (sizeof(uint32_t) * 2))
+ {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
+ // Big Endian
+ result <<= 4;
+ result |= nibble;
+
+ ++m_index;
+ ++nibble_count;
+ }
+ }
+ return result;
+}
+
+uint64_t
+StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
+{
+ uint64_t result = 0;
+ uint32_t nibble_count = 0;
+
+ if (little_endian)
+ {
+ uint32_t shift_amount = 0;
+ while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ // Make sure we don't exceed the size of a uint64_t...
+ if (nibble_count >= (sizeof(uint64_t) * 2))
+ {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble_lo;
+ uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]);
+ ++m_index;
+ if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ nibble_lo = xdigit_to_sint (m_packet[m_index]);
+ ++m_index;
+ result |= ((uint64_t)nibble_hi << (shift_amount + 4));
+ result |= ((uint64_t)nibble_lo << shift_amount);
+ nibble_count += 2;
+ shift_amount += 8;
+ }
+ else
+ {
+ result |= ((uint64_t)nibble_hi << shift_amount);
+ nibble_count += 1;
+ shift_amount += 4;
+ }
+
+ }
+ }
+ else
+ {
+ while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index]))
+ {
+ // Make sure we don't exceed the size of a uint64_t...
+ if (nibble_count >= (sizeof(uint64_t) * 2))
+ {
+ m_index = UINT64_MAX;
+ return fail_value;
+ }
+
+ uint8_t nibble = xdigit_to_sint (m_packet[m_index]);
+ // Big Endian
+ result <<= 4;
+ result |= nibble;
+
+ ++m_index;
+ ++nibble_count;
+ }
+ }
+ return result;
+}
+
+size_t
+StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value)
+{
+ uint8_t *dst = (uint8_t*)dst_void;
+ size_t bytes_extracted = 0;
+ while (bytes_extracted < dst_len && GetBytesLeft ())
+ {
+ dst[bytes_extracted] = GetHexU8 (fail_fill_value);
+ if (IsGood())
+ ++bytes_extracted;
+ else
+ break;
+ }
+
+ for (size_t i = bytes_extracted; i < dst_len; ++i)
+ dst[i] = fail_fill_value;
+
+ return bytes_extracted;
+}
+
+
+// Consume ASCII hex nibble character pairs until we have decoded byte_size
+// bytes of data.
+
+uint64_t
+StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value)
+{
+ if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2)
+ {
+ uint64_t result = 0;
+ uint32_t i;
+ if (little_endian)
+ {
+ // Little Endian
+ uint32_t shift_amount;
+ for (i = 0, shift_amount = 0;
+ i < byte_size && IsGood();
+ ++i, shift_amount += 8)
+ {
+ result |= ((uint64_t)GetHexU8() << shift_amount);
+ }
+ }
+ else
+ {
+ // Big Endian
+ for (i = 0; i < byte_size && IsGood(); ++i)
+ {
+ result <<= 8;
+ result |= GetHexU8();
+ }
+ }
+ }
+ m_index = UINT64_MAX;
+ return fail_value;
+}
+
+size_t
+StringExtractor::GetHexByteString (std::string &str)
+{
+ str.clear();
+ char ch;
+ while ((ch = GetHexU8()) != '\0')
+ str.append(1, ch);
+ return str.size();
+}
+
+bool
+StringExtractor::GetNameColonValue (std::string &name, std::string &value)
+{
+ // Read something in the form of NNNN:VVVV; where NNNN is any character
+ // that is not a colon, followed by a ':' character, then a value (one or
+ // more ';' chars), followed by a ';'
+ if (m_index < m_packet.size())
+ {
+ const size_t colon_idx = m_packet.find (':', m_index);
+ if (colon_idx != std::string::npos)
+ {
+ const size_t semicolon_idx = m_packet.find (';', colon_idx);
+ if (semicolon_idx != std::string::npos)
+ {
+ name.assign (m_packet, m_index, colon_idx - m_index);
+ value.assign (m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1));
+ m_index = semicolon_idx + 1;
+ return true;
+ }
+ }
+ }
+ m_index = UINT64_MAX;
+ return false;
+}
diff --git a/source/Utility/StringExtractor.h b/source/Utility/StringExtractor.h
new file mode 100644
index 000000000000..0ded3101fcca
--- /dev/null
+++ b/source/Utility/StringExtractor.h
@@ -0,0 +1,141 @@
+//===-- StringExtractor.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_StringExtractor_h_
+#define utility_StringExtractor_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <stdint.h>
+
+// Other libraries and framework includes
+// Project includes
+
+class StringExtractor
+{
+public:
+
+ enum {
+ BigEndian = 0,
+ LittleEndian = 1
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StringExtractor();
+ StringExtractor(const char *packet_cstr);
+ StringExtractor(const StringExtractor& rhs);
+ virtual ~StringExtractor();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const StringExtractor&
+ operator=(const StringExtractor& rhs);
+
+ // Returns true if the file position is still valid for the data
+ // contained in this string extractor object.
+ bool
+ IsGood() const
+ {
+ return m_index != UINT64_MAX;
+ }
+
+ uint64_t
+ GetFilePos () const
+ {
+ return m_index;
+ }
+
+ void
+ SetFilePos (uint32_t idx)
+ {
+ m_index = idx;
+ }
+
+ void
+ Clear ()
+ {
+ m_packet.clear();
+ m_index = 0;
+ }
+
+ std::string &
+ GetStringRef ()
+ {
+ return m_packet;
+ }
+
+ const std::string &
+ GetStringRef () const
+ {
+ return m_packet;
+ }
+
+ bool
+ Empty()
+ {
+ return m_packet.empty();
+ }
+
+ size_t
+ GetBytesLeft ()
+ {
+ if (m_index < m_packet.size())
+ return m_packet.size() - m_index;
+ return 0;
+ }
+ char
+ GetChar (char fail_value = '\0');
+
+ uint8_t
+ GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true);
+
+ bool
+ GetNameColonValue (std::string &name, std::string &value);
+
+ uint32_t
+ GetU32 (uint32_t fail_value, int base = 0);
+
+ uint32_t
+ GetHexMaxU32 (bool little_endian, uint32_t fail_value);
+
+ uint64_t
+ GetHexMaxU64 (bool little_endian, uint64_t fail_value);
+
+ size_t
+ GetHexBytes (void *dst, size_t dst_len, uint8_t fail_fill_value);
+
+ uint64_t
+ GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value);
+
+ size_t
+ GetHexByteString (std::string &str);
+
+ const char *
+ Peek ()
+ {
+ if (m_index < m_packet.size())
+ return m_packet.c_str() + m_index;
+ return NULL;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // For StringExtractor only
+ //------------------------------------------------------------------
+ std::string m_packet; // The string in which to extract data.
+ uint64_t m_index; // When extracting data from a packet, this index
+ // will march along as things get extracted. If set
+ // to UINT64_MAX the end of the packet data was
+ // reached when decoding information
+};
+
+#endif // utility_StringExtractor_h_
diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp
new file mode 100644
index 000000000000..7e06a0f59bc9
--- /dev/null
+++ b/source/Utility/StringExtractorGDBRemote.cpp
@@ -0,0 +1,182 @@
+//===-- StringExtractorGDBRemote.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+
+
+StringExtractorGDBRemote::ResponseType
+StringExtractorGDBRemote::GetResponseType () const
+{
+ if (m_packet.empty())
+ return eUnsupported;
+
+ switch (m_packet[0])
+ {
+ case 'E':
+ if (m_packet.size() == 3 &&
+ isxdigit(m_packet[1]) &&
+ isxdigit(m_packet[2]))
+ return eError;
+ break;
+
+ case 'O':
+ if (m_packet.size() == 2 && m_packet[1] == 'K')
+ return eOK;
+ break;
+
+ case '+':
+ if (m_packet.size() == 1)
+ return eAck;
+ break;
+
+ case '-':
+ if (m_packet.size() == 1)
+ return eNack;
+ break;
+ }
+ return eResponse;
+}
+
+StringExtractorGDBRemote::ServerPacketType
+StringExtractorGDBRemote::GetServerPacketType () const
+{
+#define PACKET_MATCHES(s) ((packet_size == (sizeof(s)-1)) && (strcmp((packet_cstr),(s)) == 0))
+#define PACKET_STARTS_WITH(s) ((packet_size >= (sizeof(s)-1)) && ::strncmp(packet_cstr, s, (sizeof(s)-1))==0)
+
+ // Empty is not a supported packet...
+ if (m_packet.empty())
+ return eServerPacketType_invalid;
+
+ const size_t packet_size = m_packet.size();
+ const char *packet_cstr = m_packet.c_str();
+ switch (m_packet[0])
+ {
+ case '\x03':
+ if (packet_size == 1) return eServerPacketType_interrupt;
+ break;
+
+ case '-':
+ if (packet_size == 1) return eServerPacketType_nack;
+ break;
+
+ case '+':
+ if (packet_size == 1) return eServerPacketType_ack;
+ break;
+
+ case 'A':
+ return eServerPacketType_A;
+
+ case 'Q':
+ switch (packet_cstr[1])
+ {
+ case 'E':
+ if (PACKET_STARTS_WITH ("QEnvironment:")) return eServerPacketType_QEnvironment;
+ break;
+
+ case 'S':
+ if (PACKET_MATCHES ("QStartNoAckMode")) return eServerPacketType_QStartNoAckMode;
+ else if (PACKET_STARTS_WITH ("QSetDisableASLR:")) return eServerPacketType_QSetDisableASLR;
+ else if (PACKET_STARTS_WITH ("QSetSTDIN:")) return eServerPacketType_QSetSTDIN;
+ else if (PACKET_STARTS_WITH ("QSetSTDOUT:")) return eServerPacketType_QSetSTDOUT;
+ else if (PACKET_STARTS_WITH ("QSetSTDERR:")) return eServerPacketType_QSetSTDERR;
+ else if (PACKET_STARTS_WITH ("QSetWorkingDir:")) return eServerPacketType_QSetWorkingDir;
+ break;
+ }
+ break;
+
+ case 'q':
+ switch (packet_cstr[1])
+ {
+ case 's':
+ if (PACKET_MATCHES ("qsProcessInfo")) return eServerPacketType_qsProcessInfo;
+ break;
+
+ case 'f':
+ if (PACKET_STARTS_WITH ("qfProcessInfo")) return eServerPacketType_qfProcessInfo;
+ break;
+
+ case 'C':
+ if (packet_size == 2) return eServerPacketType_qC;
+ break;
+
+ case 'G':
+ if (PACKET_STARTS_WITH ("qGroupName:")) return eServerPacketType_qGroupName;
+ break;
+
+ case 'H':
+ if (PACKET_MATCHES ("qHostInfo")) return eServerPacketType_qHostInfo;
+ break;
+
+ case 'L':
+ if (PACKET_MATCHES ("qLaunchGDBServer")) return eServerPacketType_qLaunchGDBServer;
+ if (PACKET_MATCHES ("qLaunchSuccess")) return eServerPacketType_qLaunchSuccess;
+ break;
+
+ case 'P':
+ if (PACKET_STARTS_WITH ("qProcessInfoPID:")) return eServerPacketType_qProcessInfoPID;
+ break;
+
+ case 'S':
+ if (PACKET_STARTS_WITH ("qSpeedTest:")) return eServerPacketType_qSpeedTest;
+ break;
+
+ case 'U':
+ if (PACKET_STARTS_WITH ("qUserName:")) return eServerPacketType_qUserName;
+ break;
+ }
+ break;
+ }
+ return eServerPacketType_unimplemented;
+}
+
+bool
+StringExtractorGDBRemote::IsOKResponse() const
+{
+ return GetResponseType () == eOK;
+}
+
+
+bool
+StringExtractorGDBRemote::IsUnsupportedResponse() const
+{
+ return GetResponseType () == eUnsupported;
+}
+
+bool
+StringExtractorGDBRemote::IsNormalResponse() const
+{
+ return GetResponseType () == eResponse;
+}
+
+bool
+StringExtractorGDBRemote::IsErrorResponse() const
+{
+ return GetResponseType () == eError &&
+ m_packet.size() == 3 &&
+ isxdigit(m_packet[1]) &&
+ isxdigit(m_packet[2]);
+}
+
+uint8_t
+StringExtractorGDBRemote::GetError ()
+{
+ if (GetResponseType() == eError)
+ {
+ SetFilePos(1);
+ return GetHexU8(255);
+ }
+ return 0;
+}
diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h
new file mode 100644
index 000000000000..5a24d894b105
--- /dev/null
+++ b/source/Utility/StringExtractorGDBRemote.h
@@ -0,0 +1,103 @@
+//===-- StringExtractorGDBRemote.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_StringExtractorGDBRemote_h_
+#define utility_StringExtractorGDBRemote_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+// Other libraries and framework includes
+// Project includes
+#include "Utility/StringExtractor.h"
+
+class StringExtractorGDBRemote : public StringExtractor
+{
+public:
+
+ StringExtractorGDBRemote() :
+ StringExtractor ()
+ {
+ }
+
+ StringExtractorGDBRemote(const char *cstr) :
+ StringExtractor (cstr)
+ {
+ }
+ StringExtractorGDBRemote(const StringExtractorGDBRemote& rhs) :
+ StringExtractor (rhs)
+ {
+ }
+
+ virtual ~StringExtractorGDBRemote()
+ {
+ }
+
+ enum ServerPacketType
+ {
+ eServerPacketType_nack = 0,
+ eServerPacketType_ack,
+ eServerPacketType_invalid,
+ eServerPacketType_unimplemented,
+ eServerPacketType_interrupt, // CTRL+c packet or "\x03"
+ eServerPacketType_A, // Program arguments packet
+ eServerPacketType_qfProcessInfo,
+ eServerPacketType_qsProcessInfo,
+ eServerPacketType_qC,
+ eServerPacketType_qGroupName,
+ eServerPacketType_qHostInfo,
+ eServerPacketType_qLaunchGDBServer,
+ eServerPacketType_qLaunchSuccess,
+ eServerPacketType_qProcessInfoPID,
+ eServerPacketType_qSpeedTest,
+ eServerPacketType_qUserName,
+ eServerPacketType_QEnvironment,
+ eServerPacketType_QSetDisableASLR,
+ eServerPacketType_QSetSTDIN,
+ eServerPacketType_QSetSTDOUT,
+ eServerPacketType_QSetSTDERR,
+ eServerPacketType_QSetWorkingDir,
+ eServerPacketType_QStartNoAckMode
+ };
+
+ ServerPacketType
+ GetServerPacketType () const;
+
+ enum ResponseType
+ {
+ eUnsupported = 0,
+ eAck,
+ eNack,
+ eError,
+ eOK,
+ eResponse
+ };
+
+ ResponseType
+ GetResponseType () const;
+
+ bool
+ IsOKResponse() const;
+
+ bool
+ IsUnsupportedResponse() const;
+
+ bool
+ IsNormalResponse () const;
+
+ bool
+ IsErrorResponse() const;
+
+ // Returns zero if the packet isn't a EXX packet where XX are two hex
+ // digits. Otherwise the error encoded in XX is returned.
+ uint8_t
+ GetError();
+};
+
+#endif // utility_StringExtractorGDBRemote_h_
diff --git a/source/Utility/TimeSpecTimeout.cpp b/source/Utility/TimeSpecTimeout.cpp
new file mode 100644
index 000000000000..33b3b4e6c391
--- /dev/null
+++ b/source/Utility/TimeSpecTimeout.cpp
@@ -0,0 +1,48 @@
+//===--------------------- TimeSpecTimeout.cpp ------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TimeSpecTimeout.h"
+
+using namespace lldb_private;
+
+const struct timespec *
+TimeSpecTimeout::SetAbsoluteTimeoutMircoSeconds32 (uint32_t timeout_usec)
+{
+ if (timeout_usec == UINT32_MAX)
+ {
+ m_infinite = true;
+ }
+ else
+ {
+ m_infinite = false;
+ TimeValue time_value(TimeValue::Now());
+ time_value.OffsetWithMicroSeconds(timeout_usec);
+ m_timespec = time_value.GetAsTimeSpec();
+ }
+ return GetTimeSpecPtr ();
+}
+
+const struct timespec *
+TimeSpecTimeout::SetRelativeTimeoutMircoSeconds32 (uint32_t timeout_usec)
+{
+ if (timeout_usec == UINT32_MAX)
+ {
+ m_infinite = true;
+ }
+ else
+ {
+ m_infinite = false;
+ TimeValue time_value;
+ time_value.OffsetWithMicroSeconds(timeout_usec);
+ m_timespec = time_value.GetAsTimeSpec();
+ }
+ return GetTimeSpecPtr ();
+}
+
+
diff --git a/source/Utility/TimeSpecTimeout.h b/source/Utility/TimeSpecTimeout.h
new file mode 100644
index 000000000000..32cdd067658c
--- /dev/null
+++ b/source/Utility/TimeSpecTimeout.h
@@ -0,0 +1,90 @@
+//===--------------------- TimeSpecTimeout.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_TimeSpecTimeout_h_
+#define utility_TimeSpecTimeout_h_
+
+#include "lldb/Host/TimeValue.h"
+
+namespace lldb_private {
+
+class TimeSpecTimeout
+{
+public:
+ TimeSpecTimeout() :
+ m_infinite (false)
+ {
+ m_timespec.tv_sec = 0;
+ m_timespec.tv_nsec = 0;
+ }
+ ~TimeSpecTimeout()
+ {
+ }
+
+ //----------------------------------------------------------------------
+ /// Sets the timespec pointer correctly given a timeout relative to the
+ /// current time. This function should be called immediately prior to
+ /// calling the function you will use this timeout with since time can
+ /// elapse between when this function is called and when the timeout is
+ /// used.
+ ///
+ /// @param[in] timeout_usec
+ /// The timeout in micro seconds. If timeout_usec is UINT32_MAX, the
+ /// timeout should be set to INFINITE. Otherwise the current time is
+ /// filled into the timespec and \a timeout_usec is added to the
+ /// current time.
+ ///
+ /// @return
+ /// If the timeout is INFINITE, then return NULL, otherwise return
+ /// a pointer to the timespec with the appropriate timeout value.
+ //----------------------------------------------------------------------
+ const struct timespec *
+ SetAbsoluteTimeoutMircoSeconds32 (uint32_t timeout_usec);
+
+ //----------------------------------------------------------------------
+ /// Sets the timespec pointer correctly given a relative time in micro
+ /// seconds.
+ ///
+ /// @param[in] timeout_usec
+ /// The timeout in micro seconds. If timeout_usec is UINT32_MAX, the
+ /// timeout should be set to INFINITE. Otherwise \a timeout_usec
+ /// is correctly placed into the timespec.
+ ///
+ /// @return
+ /// If the timeout is INFINITE, then return NULL, otherwise return
+ /// a pointer to the timespec with the appropriate timeout value.
+ //----------------------------------------------------------------------
+ const struct timespec *
+ SetRelativeTimeoutMircoSeconds32 (uint32_t timeout_usec);
+
+ //----------------------------------------------------------------------
+ /// Gets the timespec pointer that is appropriate for the timeout
+ /// specified. This function should only be used after a call to
+ /// SetRelativeTimeoutXXX() functions.
+ ///
+ /// @return
+ /// If the timeout is INFINITE, then return NULL, otherwise return
+ /// a pointer to the timespec with the appropriate timeout value.
+ //----------------------------------------------------------------------
+ const struct timespec *
+ GetTimeSpecPtr () const
+ {
+ if (m_infinite)
+ return NULL;
+ return &m_timespec;
+ }
+
+protected:
+ struct timespec m_timespec;
+ bool m_infinite;
+};
+
+} // namespace lldb_private
+
+#endif // #ifndef utility_TimeSpecTimeout_h_
diff --git a/source/Utility/UuidCompatibility.h b/source/Utility/UuidCompatibility.h
new file mode 100644
index 000000000000..df26f77ab52d
--- /dev/null
+++ b/source/Utility/UuidCompatibility.h
@@ -0,0 +1,18 @@
+//===-- UuidCompatibility.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Include this header if your system does not have a definition of uuid_t
+
+#ifndef utility_UUID_COMPATIBILITY_H
+#define utility_UUID_COMPATIBILITY_H
+
+// uuid_t is guaranteed to always be a 16-byte array
+typedef unsigned char uuid_t[16];
+
+#endif // utility_UUID_COMPATIBILITY_H
diff --git a/source/lldb-log.cpp b/source/lldb-log.cpp
new file mode 100644
index 000000000000..c53fa56ef019
--- /dev/null
+++ b/source/lldb-log.cpp
@@ -0,0 +1,257 @@
+//===-- lldb-log.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-log.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include <string.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_lob_sp the first time this function is
+// called.
+
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+uint32_t
+lldb_private::GetLogMask ()
+{
+ Log *log(GetLog ());
+ if (log)
+ return log->GetMask().Get();
+ return 0;
+}
+
+bool
+lldb_private::IsLogVerbose ()
+{
+ uint32_t mask = GetLogMask();
+ return (mask & LIBLLDB_LOG_VERBOSE);
+}
+
+Log *
+lldb_private::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+void
+lldb_private::LogIfAllCategoriesSet (uint32_t mask, const char *format, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+void
+lldb_private::LogIfAnyCategoriesSet (uint32_t mask, const char *format, ...)
+{
+ Log *log(GetLogIfAnyCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+Log *
+lldb_private::GetLogIfAnyCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask && (mask & log->GetMask().Get()))
+ return log;
+ return NULL;
+}
+
+void
+lldb_private::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log(GetLog ());
+
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (0 == ::strcasecmp(arg, "all")) flag_bits &= ~LIBLLDB_LOG_ALL;
+ else if (0 == ::strcasecmp(arg, "api")) flag_bits &= ~LIBLLDB_LOG_API;
+ else if (0 == ::strncasecmp(arg, "break", 5)) flag_bits &= ~LIBLLDB_LOG_BREAKPOINTS;
+ else if (0 == ::strcasecmp(arg, "commands")) flag_bits &= ~LIBLLDB_LOG_COMMANDS;
+ else if (0 == ::strcasecmp(arg, "default")) flag_bits &= ~LIBLLDB_LOG_DEFAULT;
+ else if (0 == ::strcasecmp(arg, "dyld")) flag_bits &= ~LIBLLDB_LOG_DYNAMIC_LOADER;
+ else if (0 == ::strncasecmp(arg, "event", 5)) flag_bits &= ~LIBLLDB_LOG_EVENTS;
+ else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits &= ~LIBLLDB_LOG_EXPRESSIONS;
+ else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits &= ~LIBLLDB_LOG_OBJECT;
+ else if (0 == ::strcasecmp(arg, "process")) flag_bits &= ~LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "script")) flag_bits &= ~LIBLLDB_LOG_SCRIPT;
+ else if (0 == ::strcasecmp(arg, "state")) flag_bits &= ~LIBLLDB_LOG_STATE;
+ else if (0 == ::strcasecmp(arg, "step")) flag_bits &= ~LIBLLDB_LOG_STEP;
+ else if (0 == ::strcasecmp(arg, "thread")) flag_bits &= ~LIBLLDB_LOG_THREAD;
+ else if (0 == ::strcasecmp(arg, "target")) flag_bits &= ~LIBLLDB_LOG_TARGET;
+ else if (0 == ::strcasecmp(arg, "verbose")) flag_bits &= ~LIBLLDB_LOG_VERBOSE;
+ else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits &= ~LIBLLDB_LOG_WATCHPOINTS;
+ else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits &= ~LIBLLDB_LOG_TEMPORARY;
+ else if (0 == ::strncasecmp(arg, "comm", 4)) flag_bits &= ~LIBLLDB_LOG_COMMUNICATION;
+ else if (0 == ::strncasecmp(arg, "conn", 4)) flag_bits &= ~LIBLLDB_LOG_CONNECTION;
+ else if (0 == ::strncasecmp(arg, "host", 4)) flag_bits &= ~LIBLLDB_LOG_HOST;
+ else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits &= ~LIBLLDB_LOG_UNWIND;
+ else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits &= ~LIBLLDB_LOG_TYPES;
+ else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits &= ~LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits &= ~LIBLLDB_LOG_MODULES;
+ else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits &= ~LIBLLDB_LOG_MMAP;
+ else if (0 == ::strcasecmp(arg, "os")) flag_bits &= ~LIBLLDB_LOG_OS;
+ else
+ {
+ feedback_strm->Printf ("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ return;
+ }
+
+ }
+ }
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+lldb_private::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+ else
+ flag_bits = 0;
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (0 == ::strcasecmp(arg, "all")) flag_bits |= LIBLLDB_LOG_ALL;
+ else if (0 == ::strcasecmp(arg, "api")) flag_bits |= LIBLLDB_LOG_API;
+ else if (0 == ::strncasecmp(arg, "break", 5)) flag_bits |= LIBLLDB_LOG_BREAKPOINTS;
+ else if (0 == ::strcasecmp(arg, "commands")) flag_bits |= LIBLLDB_LOG_COMMANDS;
+ else if (0 == ::strcasecmp(arg, "default")) flag_bits |= LIBLLDB_LOG_DEFAULT;
+ else if (0 == ::strcasecmp(arg, "dyld")) flag_bits |= LIBLLDB_LOG_DYNAMIC_LOADER;
+ else if (0 == ::strncasecmp(arg, "event", 5)) flag_bits |= LIBLLDB_LOG_EVENTS;
+ else if (0 == ::strncasecmp(arg, "expr", 4)) flag_bits |= LIBLLDB_LOG_EXPRESSIONS;
+ else if (0 == ::strncasecmp(arg, "object", 6)) flag_bits |= LIBLLDB_LOG_OBJECT;
+ else if (0 == ::strcasecmp(arg, "process")) flag_bits |= LIBLLDB_LOG_PROCESS;
+ else if (0 == ::strcasecmp(arg, "script")) flag_bits |= LIBLLDB_LOG_SCRIPT;
+ else if (0 == ::strcasecmp(arg, "state")) flag_bits |= LIBLLDB_LOG_STATE;
+ else if (0 == ::strcasecmp(arg, "step")) flag_bits |= LIBLLDB_LOG_STEP;
+ else if (0 == ::strcasecmp(arg, "thread")) flag_bits |= LIBLLDB_LOG_THREAD;
+ else if (0 == ::strcasecmp(arg, "target")) flag_bits |= LIBLLDB_LOG_TARGET;
+ else if (0 == ::strcasecmp(arg, "verbose")) flag_bits |= LIBLLDB_LOG_VERBOSE;
+ else if (0 == ::strncasecmp(arg, "watch", 5)) flag_bits |= LIBLLDB_LOG_WATCHPOINTS;
+ else if (0 == ::strncasecmp(arg, "temp", 4)) flag_bits |= LIBLLDB_LOG_TEMPORARY;
+ else if (0 == ::strncasecmp(arg, "comm", 4)) flag_bits |= LIBLLDB_LOG_COMMUNICATION;
+ else if (0 == ::strncasecmp(arg, "conn", 4)) flag_bits |= LIBLLDB_LOG_CONNECTION;
+ else if (0 == ::strncasecmp(arg, "host", 4)) flag_bits |= LIBLLDB_LOG_HOST;
+ else if (0 == ::strncasecmp(arg, "unwind", 6)) flag_bits |= LIBLLDB_LOG_UNWIND;
+ else if (0 == ::strncasecmp(arg, "types", 5)) flag_bits |= LIBLLDB_LOG_TYPES;
+ else if (0 == ::strncasecmp(arg, "symbol", 6)) flag_bits |= LIBLLDB_LOG_SYMBOLS;
+ else if (0 == ::strncasecmp(arg, "module", 6)) flag_bits |= LIBLLDB_LOG_MODULES;
+ else if (0 == ::strncasecmp(arg, "mmap", 4)) flag_bits |= LIBLLDB_LOG_MMAP;
+ else if (0 == ::strcasecmp(arg, "os")) flag_bits |= LIBLLDB_LOG_OS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ return g_log;
+ }
+ }
+
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+
+void
+lldb_private::ListLogCategories (Stream *strm)
+{
+ strm->Printf("Logging categories for 'lldb':\n"
+ " all - turn on all available logging categories\n"
+ " api - enable logging of API calls and return values\n"
+ " break - log breakpoints\n"
+ " commands - log command argument parsing\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " dyld - log shared library related activities\n"
+ " events - log broadcaster, listener and event queue activities\n"
+ " expr - log expressions\n"
+ " object - log object construction/destruction for important objects\n"
+ " module - log module activities such as when modules are created, detroyed, replaced, and more\n"
+ " process - log process events and activities\n"
+ " script - log events about the script interpreter\n"
+ " state - log private and public process state changes\n"
+ " step - log step related activities\n"
+ " symbol - log symbol related issues and warnings\n"
+ " target - log target events and activities\n"
+ " thread - log thread events and activities\n"
+ " types - log type system related activities\n"
+ " unwind - log stack unwind activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n");
+}
diff --git a/source/lldb.cpp b/source/lldb.cpp
new file mode 100644
index 000000000000..1ac03f4f190c
--- /dev/null
+++ b/source/lldb.cpp
@@ -0,0 +1,425 @@
+//===-- lldb.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/lldb-private.h"
+#include "lldb/lldb-private-log.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/StringRef.h"
+
+#include "Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h"
+#include "Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h"
+#include "Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h"
+#include "Plugins/Disassembler/llvm/DisassemblerLLVMC.h"
+#include "Plugins/Instruction/ARM/EmulateInstructionARM.h"
+#include "Plugins/SymbolVendor/MacOSX/SymbolVendorMacOSX.h"
+#include "Plugins/SymbolVendor/ELF/SymbolVendorELF.h"
+#include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h"
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
+#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
+#include "Plugins/SymbolFile/Symtab/SymbolFileSymtab.h"
+#include "Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h"
+#include "Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h"
+#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+#include "Plugins/Platform/FreeBSD/PlatformFreeBSD.h"
+#include "Plugins/Platform/Linux/PlatformLinux.h"
+#include "Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h"
+#ifndef LLDB_DISABLE_PYTHON
+#include "Plugins/OperatingSystem/Python/OperatingSystemPython.h"
+#endif
+#if defined (__APPLE__)
+#include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h"
+#include "Plugins/DynamicLoader/Darwin-Kernel/DynamicLoaderDarwinKernel.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h"
+#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
+#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
+#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
+#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
+#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
+#include "Plugins/Platform/MacOSX/PlatformDarwinKernel.h"
+#include "Plugins/Platform/MacOSX/PlatformiOSSimulator.h"
+#endif
+
+#include "Plugins/Process/mach-core/ProcessMachCore.h"
+
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#endif
+
+#if defined (__linux__)
+#include "Plugins/Process/Linux/ProcessLinux.h"
+#endif
+
+#if defined (__FreeBSD__)
+#include "Plugins/Process/POSIX/ProcessPOSIX.h"
+#include "Plugins/Process/FreeBSD/ProcessFreeBSD.h"
+#endif
+
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+lldb_private::Initialize ()
+{
+ // Make sure we inialize only once
+ static Mutex g_inited_mutex(Mutex::eMutexTypeRecursive);
+ static bool g_inited = false;
+
+ Mutex::Locker locker(g_inited_mutex);
+ if (!g_inited)
+ {
+ g_inited = true;
+ Log::Initialize();
+ Timer::Initialize ();
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ ABIMacOSX_i386::Initialize();
+ ABIMacOSX_arm::Initialize();
+ ABISysV_x86_64::Initialize();
+ DisassemblerLLVMC::Initialize();
+ ObjectContainerBSDArchive::Initialize();
+ ObjectFileELF::Initialize();
+ SymbolVendorELF::Initialize();
+ SymbolFileDWARF::Initialize();
+ SymbolFileSymtab::Initialize();
+ UnwindAssemblyInstEmulation::Initialize();
+ UnwindAssembly_x86::Initialize();
+ EmulateInstructionARM::Initialize ();
+ ObjectFilePECOFF::Initialize ();
+ DynamicLoaderPOSIXDYLD::Initialize ();
+ PlatformFreeBSD::Initialize();
+ PlatformLinux::Initialize();
+ SymbolFileDWARFDebugMap::Initialize();
+ ItaniumABILanguageRuntime::Initialize();
+#ifndef LLDB_DISABLE_PYTHON
+ OperatingSystemPython::Initialize();
+#endif
+
+#if defined (__APPLE__)
+ //----------------------------------------------------------------------
+ // Apple/Darwin hosted plugins
+ //----------------------------------------------------------------------
+ DynamicLoaderMacOSXDYLD::Initialize();
+ DynamicLoaderDarwinKernel::Initialize();
+ AppleObjCRuntimeV2::Initialize();
+ AppleObjCRuntimeV1::Initialize();
+ ObjectContainerUniversalMachO::Initialize();
+ ObjectFileMachO::Initialize();
+ ProcessKDP::Initialize();
+ ProcessMachCore::Initialize();
+ SymbolVendorMacOSX::Initialize();
+ PlatformDarwinKernel::Initialize();
+ PlatformRemoteiOS::Initialize();
+ PlatformMacOSX::Initialize();
+ PlatformiOSSimulator::Initialize();
+#endif
+#if defined (__linux__)
+ //----------------------------------------------------------------------
+ // Linux hosted plugins
+ //----------------------------------------------------------------------
+ ProcessLinux::Initialize();
+#endif
+#if defined (__FreeBSD__)
+ ProcessFreeBSD::Initialize();
+#endif
+
+#if defined(__linux__) or defined(__FreeBSD__)
+ ProcessElfCore::Initialize();
+#endif
+ //----------------------------------------------------------------------
+ // Platform agnostic plugins
+ //----------------------------------------------------------------------
+ PlatformRemoteGDBServer::Initialize ();
+ ProcessGDBRemote::Initialize();
+ DynamicLoaderStatic::Initialize();
+
+ // Scan for any system or user LLDB plug-ins
+ PluginManager::Initialize();
+
+ // The process settings need to know about installed plug-ins, so the Settings must be initialized
+ // AFTER PluginManager::Initialize is called.
+
+ Debugger::SettingsInitialize();
+ }
+}
+
+void
+lldb_private::WillTerminate()
+{
+ Host::WillTerminate();
+}
+
+void
+lldb_private::Terminate ()
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ // Terminate and unload and loaded system or user LLDB plug-ins
+ PluginManager::Terminate();
+
+ ABIMacOSX_i386::Terminate();
+ ABIMacOSX_arm::Terminate();
+ ABISysV_x86_64::Terminate();
+ DisassemblerLLVMC::Terminate();
+ ObjectContainerBSDArchive::Terminate();
+ ObjectFileELF::Terminate();
+ SymbolVendorELF::Terminate();
+ SymbolFileDWARF::Terminate();
+ SymbolFileSymtab::Terminate();
+ UnwindAssembly_x86::Terminate();
+ UnwindAssemblyInstEmulation::Terminate();
+ EmulateInstructionARM::Terminate ();
+ ObjectFilePECOFF::Terminate ();
+ DynamicLoaderPOSIXDYLD::Terminate ();
+ PlatformFreeBSD::Terminate();
+ PlatformLinux::Terminate();
+ SymbolFileDWARFDebugMap::Terminate();
+ ItaniumABILanguageRuntime::Terminate();
+#ifndef LLDB_DISABLE_PYTHON
+ OperatingSystemPython::Terminate();
+#endif
+
+#if defined (__APPLE__)
+ DynamicLoaderMacOSXDYLD::Terminate();
+ DynamicLoaderDarwinKernel::Terminate();
+ AppleObjCRuntimeV2::Terminate();
+ AppleObjCRuntimeV1::Terminate();
+ ObjectContainerUniversalMachO::Terminate();
+ ObjectFileMachO::Terminate();
+ ProcessMachCore::Terminate();
+ ProcessKDP::Terminate();
+ SymbolVendorMacOSX::Terminate();
+ PlatformMacOSX::Terminate();
+ PlatformDarwinKernel::Terminate();
+ PlatformRemoteiOS::Terminate();
+ PlatformiOSSimulator::Terminate();
+#endif
+
+ Debugger::SettingsTerminate ();
+
+#if defined (__linux__)
+ ProcessLinux::Terminate();
+#endif
+
+#if defined (__FreeBSD__)
+ ProcessFreeBSD::Terminate();
+#endif
+
+#if defined(__linux__) or defined(__FreeBSD__)
+ ProcessElfCore::Terminate();
+#endif
+ ProcessGDBRemote::Terminate();
+ DynamicLoaderStatic::Terminate();
+
+ Log::Terminate();
+}
+
+#if defined (__APPLE__)
+extern "C" const unsigned char liblldb_coreVersionString[];
+#else
+
+#include "clang/Basic/Version.h"
+
+static const char *
+GetLLDBRevision()
+{
+#ifdef LLDB_REVISION
+ return LLDB_REVISION;
+#else
+ return NULL;
+#endif
+}
+
+static const char *
+GetLLDBRepository()
+{
+#ifdef LLDB_REPOSITORY
+ return LLDB_REPOSITORY;
+#else
+ return NULL;
+#endif
+}
+
+#endif
+
+const char *
+lldb_private::GetVersion ()
+{
+#if defined (__APPLE__)
+ static char g_version_string[32];
+ if (g_version_string[0] == '\0')
+ {
+ const char *version_string = ::strstr ((const char *)liblldb_coreVersionString, "PROJECT:");
+
+ if (version_string)
+ version_string += sizeof("PROJECT:") - 1;
+ else
+ version_string = "unknown";
+
+ const char *newline_loc = strchr(version_string, '\n');
+
+ size_t version_len = sizeof(g_version_string);
+
+ if (newline_loc && (newline_loc - version_string < version_len))
+ version_len = newline_loc - version_string;
+
+ ::strncpy(g_version_string, version_string, version_len);
+ }
+
+ return g_version_string;
+#else
+ // On Linux/FreeBSD/Windows, report a version number in the same style as the clang tool.
+ static std::string g_version_str;
+ if (g_version_str.empty())
+ {
+ g_version_str += "lldb version ";
+ g_version_str += CLANG_VERSION_STRING;
+ const char * lldb_repo = GetLLDBRepository();
+ if (lldb_repo)
+ {
+ g_version_str += " (";
+ g_version_str += lldb_repo;
+ }
+
+ const char *lldb_rev = GetLLDBRevision();
+ if (lldb_rev)
+ {
+ g_version_str += " revision ";
+ g_version_str += lldb_rev;
+ }
+ std::string clang_rev (clang::getClangRevision());
+ if (clang_rev.length() > 0)
+ {
+ g_version_str += " clang revision ";
+ g_version_str += clang_rev;
+ }
+ std::string llvm_rev (clang::getLLVMRevision());
+ if (llvm_rev.length() > 0)
+ {
+ g_version_str += " llvm revision ";
+ g_version_str += llvm_rev;
+ }
+
+ if (lldb_repo)
+ g_version_str += ")";
+ }
+ return g_version_str.c_str();
+#endif
+}
+
+const char *
+lldb_private::GetVoteAsCString (Vote vote)
+{
+ switch (vote)
+ {
+ case eVoteNo: return "no";
+ case eVoteNoOpinion: return "no opinion";
+ case eVoteYes: return "yes";
+ }
+ return "invalid";
+}
+
+
+const char *
+lldb_private::GetSectionTypeAsCString (SectionType sect_type)
+{
+ switch (sect_type)
+ {
+ case eSectionTypeInvalid: return "invalid";
+ case eSectionTypeCode: return "code";
+ case eSectionTypeContainer: return "container";
+ case eSectionTypeData: return "data";
+ case eSectionTypeDataCString: return "data-cstr";
+ case eSectionTypeDataCStringPointers: return "data-cstr-ptr";
+ case eSectionTypeDataSymbolAddress: return "data-symbol-addr";
+ case eSectionTypeData4: return "data-4-byte";
+ case eSectionTypeData8: return "data-8-byte";
+ case eSectionTypeData16: return "data-16-byte";
+ case eSectionTypeDataPointers: return "data-ptrs";
+ case eSectionTypeDebug: return "debug";
+ case eSectionTypeZeroFill: return "zero-fill";
+ case eSectionTypeDataObjCMessageRefs: return "objc-message-refs";
+ case eSectionTypeDataObjCCFStrings: return "objc-cfstrings";
+ case eSectionTypeDWARFDebugAbbrev: return "dwarf-abbrev";
+ case eSectionTypeDWARFDebugAranges: return "dwarf-aranges";
+ case eSectionTypeDWARFDebugFrame: return "dwarf-frame";
+ case eSectionTypeDWARFDebugInfo: return "dwarf-info";
+ case eSectionTypeDWARFDebugLine: return "dwarf-line";
+ case eSectionTypeDWARFDebugLoc: return "dwarf-loc";
+ case eSectionTypeDWARFDebugMacInfo: return "dwarf-macinfo";
+ case eSectionTypeDWARFDebugPubNames: return "dwarf-pubnames";
+ case eSectionTypeDWARFDebugPubTypes: return "dwarf-pubtypes";
+ case eSectionTypeDWARFDebugRanges: return "dwarf-ranges";
+ case eSectionTypeDWARFDebugStr: return "dwarf-str";
+ case eSectionTypeELFSymbolTable: return "elf-symbol-table";
+ case eSectionTypeELFDynamicSymbols: return "elf-dynamic-symbols";
+ case eSectionTypeELFRelocationEntries: return "elf-relocation-entries";
+ case eSectionTypeELFDynamicLinkInfo: return "elf-dynamic-link-info";
+ case eSectionTypeDWARFAppleNames: return "apple-names";
+ case eSectionTypeDWARFAppleTypes: return "apple-types";
+ case eSectionTypeDWARFAppleNamespaces: return "apple-namespaces";
+ case eSectionTypeDWARFAppleObjC: return "apple-objc";
+ case eSectionTypeEHFrame: return "eh-frame";
+ case eSectionTypeOther: return "regular";
+ }
+ return "unknown";
+
+}
+
+bool
+lldb_private::NameMatches (const char *name,
+ NameMatchType match_type,
+ const char *match)
+{
+ if (match_type == eNameMatchIgnore)
+ return true;
+
+ if (name == match)
+ return true;
+
+ if (name && match)
+ {
+ llvm::StringRef name_sref(name);
+ llvm::StringRef match_sref(match);
+ switch (match_type)
+ {
+ case eNameMatchIgnore:
+ return true;
+ case eNameMatchEquals: return name_sref == match_sref;
+ case eNameMatchContains: return name_sref.find (match_sref) != llvm::StringRef::npos;
+ case eNameMatchStartsWith: return name_sref.startswith (match_sref);
+ case eNameMatchEndsWith: return name_sref.endswith (match_sref);
+ case eNameMatchRegularExpression:
+ {
+ RegularExpression regex (match);
+ return regex.Execute (name);
+ }
+ break;
+ }
+ }
+ return false;
+}
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp
new file mode 100644
index 000000000000..875adc22283a
--- /dev/null
+++ b/tools/driver/Driver.cpp
@@ -0,0 +1,1733 @@
+//===-- Driver.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Driver.h"
+
+#include <getopt.h>
+#include <libgen.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <string>
+
+#include "IOChannel.h"
+#include "lldb/API/SBBreakpoint.h"
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBCommandReturnObject.h"
+#include "lldb/API/SBCommunication.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBHostOS.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBTarget.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBProcess.h"
+
+using namespace lldb;
+
+static void reset_stdin_termios ();
+static bool g_old_stdin_termios_is_valid = false;
+static struct termios g_old_stdin_termios;
+
+static char *g_debugger_name = (char *) "";
+static Driver *g_driver = NULL;
+
+// In the Driver::MainLoop, we change the terminal settings. This function is
+// added as an atexit handler to make sure we clean them up.
+static void
+reset_stdin_termios ()
+{
+ if (g_old_stdin_termios_is_valid)
+ {
+ g_old_stdin_termios_is_valid = false;
+ ::tcsetattr (STDIN_FILENO, TCSANOW, &g_old_stdin_termios);
+ }
+}
+
+typedef struct
+{
+ uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0
+ // then this option belongs to option set n.
+ bool required; // This option is required (in the current usage level)
+ const char * long_option; // Full name for this option.
+ int short_option; // Single character for this option.
+ int option_has_arg; // no_argument, required_argument or optional_argument
+ uint32_t completion_type; // Cookie the option class can use to do define the argument completion.
+ lldb::CommandArgumentType argument_type; // Type of argument this option takes
+ const char * usage_text; // Full text explaining what this options does and what (if any) argument to
+ // pass it.
+} OptionDefinition;
+
+#define LLDB_3_TO_5 LLDB_OPT_SET_3|LLDB_OPT_SET_4|LLDB_OPT_SET_5
+#define LLDB_4_TO_5 LLDB_OPT_SET_4|LLDB_OPT_SET_5
+
+static OptionDefinition g_options[] =
+{
+ { LLDB_OPT_SET_1, true , "help" , 'h', no_argument , 0, eArgTypeNone,
+ "Prints out the usage information for the LLDB debugger." },
+ { LLDB_OPT_SET_2, true , "version" , 'v', no_argument , 0, eArgTypeNone,
+ "Prints out the current version number of the LLDB debugger." },
+ { LLDB_OPT_SET_3, true , "arch" , 'a', required_argument, 0, eArgTypeArchitecture,
+ "Tells the debugger to use the specified architecture when starting and running the program. <architecture> must "
+ "be one of the architectures for which the program was compiled." },
+ { LLDB_OPT_SET_3, true , "file" , 'f', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to use the file <filename> as the program to be debugged." },
+ { LLDB_OPT_SET_3, false, "core" , 'c', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to use the fullpath to <path> as the core file." },
+ { LLDB_OPT_SET_4, true , "attach-name" , 'n', required_argument, 0, eArgTypeProcessName,
+ "Tells the debugger to attach to a process with the given name." },
+ { LLDB_OPT_SET_4, true , "wait-for" , 'w', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to wait for a process with the given pid or name to launch before attaching." },
+ { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid,
+ "Tells the debugger to attach to a process with the given pid." },
+ { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang,
+ "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. "
+ "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python "
+ "extensions have been implemented." },
+ { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to print out extra information for debugging itself." },
+ { LLDB_3_TO_5, false, "source" , 's', required_argument, 0, eArgTypeFilename,
+ "Tells the debugger to read in and execute the file <file>, which should contain lldb commands." },
+ { LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone,
+ "Tells the debugger to open source files using the host's \"external editor\" mechanism." },
+ { LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone,
+ "Do not automatically parse any '.lldbinit' files." },
+ { LLDB_3_TO_5, false, "no-use-colors" , 'o', no_argument , 0, eArgTypeNone,
+ "Do not use colors." },
+ { LLDB_OPT_SET_6, true , "python-path" , 'P', no_argument , 0, eArgTypeNone,
+ "Prints out the path to the lldb.py file for this version of lldb." },
+ { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL }
+};
+
+static const uint32_t last_option_set_with_args = 2;
+
+Driver::Driver () :
+ SBBroadcaster ("Driver"),
+ m_debugger (SBDebugger::Create(false)),
+ m_editline_pty (),
+ m_editline_slave_fh (NULL),
+ m_editline_reader (),
+ m_io_channel_ap (),
+ m_option_data (),
+ m_executing_user_command (false),
+ m_waiting_for_command (false),
+ m_done(false)
+{
+ // We want to be able to handle CTRL+D in the terminal to have it terminate
+ // certain input
+ m_debugger.SetCloseInputOnEOF (false);
+ g_debugger_name = (char *) m_debugger.GetInstanceName();
+ if (g_debugger_name == NULL)
+ g_debugger_name = (char *) "";
+ g_driver = this;
+}
+
+Driver::~Driver ()
+{
+ g_driver = NULL;
+ g_debugger_name = NULL;
+}
+
+void
+Driver::CloseIOChannelFile ()
+{
+ // Write an End of File sequence to the file descriptor to ensure any
+ // read functions can exit.
+ char eof_str[] = "\x04";
+ ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
+
+ m_editline_pty.CloseMasterFileDescriptor();
+
+ if (m_editline_slave_fh)
+ {
+ ::fclose (m_editline_slave_fh);
+ m_editline_slave_fh = NULL;
+ }
+}
+
+// This function takes INDENT, which tells how many spaces to output at the front
+// of each line; TEXT, which is the text that is to be output. It outputs the
+// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the
+// front of each line. It breaks lines on spaces, tabs or newlines, shortening
+// the line if necessary to not break in the middle of a word. It assumes that
+// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
+
+void
+OutputFormattedUsageText (FILE *out, int indent, const char *text, int output_max_columns)
+{
+ int len = strlen (text);
+ std::string text_string (text);
+
+ // Force indentation to be reasonable.
+ if (indent >= output_max_columns)
+ indent = 0;
+
+ // Will it all fit on one line?
+
+ if (len + indent < output_max_columns)
+ // Output as a single line
+ fprintf (out, "%*s%s\n", indent, "", text);
+ else
+ {
+ // We need to break it up into multiple lines.
+ int text_width = output_max_columns - indent - 1;
+ int start = 0;
+ int end = start;
+ int final_end = len;
+ int sub_len;
+
+ while (end < final_end)
+ {
+ // Dont start the 'text' on a space, since we're already outputting the indentation.
+ while ((start < final_end) && (text[start] == ' '))
+ start++;
+
+ end = start + text_width;
+ if (end > final_end)
+ end = final_end;
+ else
+ {
+ // If we're not at the end of the text, make sure we break the line on white space.
+ while (end > start
+ && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
+ end--;
+ }
+ sub_len = end - start;
+ std::string substring = text_string.substr (start, sub_len);
+ fprintf (out, "%*s%s\n", indent, "", substring.c_str());
+ start = end + 1;
+ }
+ }
+}
+
+void
+ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data)
+{
+ uint32_t screen_width = 80;
+ uint32_t indent_level = 0;
+ const char *name = "lldb";
+
+ fprintf (out, "\nUsage:\n\n");
+
+ indent_level += 2;
+
+
+ // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
+ // <cmd> [options-for-level-1]
+ // etc.
+
+ uint32_t num_options;
+ uint32_t num_option_sets = 0;
+
+ for (num_options = 0; option_table[num_options].long_option != NULL; ++num_options)
+ {
+ uint32_t this_usage_mask = option_table[num_options].usage_mask;
+ if (this_usage_mask == LLDB_OPT_SET_ALL)
+ {
+ if (num_option_sets == 0)
+ num_option_sets = 1;
+ }
+ else
+ {
+ for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
+ {
+ if (this_usage_mask & 1 << j)
+ {
+ if (num_option_sets <= j)
+ num_option_sets = j + 1;
+ }
+ }
+ }
+ }
+
+ for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++)
+ {
+ uint32_t opt_set_mask;
+
+ opt_set_mask = 1 << opt_set;
+
+ if (opt_set > 0)
+ fprintf (out, "\n");
+ fprintf (out, "%*s%s", indent_level, "", name);
+ bool is_help_line = false;
+
+ for (uint32_t i = 0; i < num_options; ++i)
+ {
+ if (option_table[i].usage_mask & opt_set_mask)
+ {
+ CommandArgumentType arg_type = option_table[i].argument_type;
+ const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
+ // This is a bit of a hack, but there's no way to say certain options don't have arguments yet...
+ // so we do it by hand here.
+ if (option_table[i].short_option == 'h')
+ is_help_line = true;
+
+ if (option_table[i].required)
+ {
+ if (option_table[i].option_has_arg == required_argument)
+ fprintf (out, " -%c <%s>", option_table[i].short_option, arg_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " -%c [<%s>]", option_table[i].short_option, arg_name);
+ else
+ fprintf (out, " -%c", option_table[i].short_option);
+ }
+ else
+ {
+ if (option_table[i].option_has_arg == required_argument)
+ fprintf (out, " [-%c <%s>]", option_table[i].short_option, arg_name);
+ else if (option_table[i].option_has_arg == optional_argument)
+ fprintf (out, " [-%c [<%s>]]", option_table[i].short_option, arg_name);
+ else
+ fprintf (out, " [-%c]", option_table[i].short_option);
+ }
+ }
+ }
+ if (!is_help_line && (opt_set <= last_option_set_with_args))
+ fprintf (out, " [[--] <PROGRAM-ARG-1> [<PROGRAM_ARG-2> ...]]");
+ }
+
+ fprintf (out, "\n\n");
+
+ // Now print out all the detailed information about the various options: long form, short form and help text:
+ // -- long_name <argument>
+ // - short <argument>
+ // help text
+
+ // This variable is used to keep track of which options' info we've printed out, because some options can be in
+ // more than one usage level, but we only want to print the long form of its information once.
+
+ Driver::OptionData::OptionSet options_seen;
+ Driver::OptionData::OptionSet::iterator pos;
+
+ indent_level += 5;
+
+ for (uint32_t i = 0; i < num_options; ++i)
+ {
+ // Only print this option if we haven't already seen it.
+ pos = options_seen.find (option_table[i].short_option);
+ if (pos == options_seen.end())
+ {
+ CommandArgumentType arg_type = option_table[i].argument_type;
+ const char *arg_name = SBCommandInterpreter::GetArgumentTypeAsCString (arg_type);
+
+ options_seen.insert (option_table[i].short_option);
+ fprintf (out, "%*s-%c ", indent_level, "", option_table[i].short_option);
+ if (arg_type != eArgTypeNone)
+ fprintf (out, "<%s>", arg_name);
+ fprintf (out, "\n");
+ fprintf (out, "%*s--%s ", indent_level, "", option_table[i].long_option);
+ if (arg_type != eArgTypeNone)
+ fprintf (out, "<%s>", arg_name);
+ fprintf (out, "\n");
+ indent_level += 5;
+ OutputFormattedUsageText (out, indent_level, option_table[i].usage_text, screen_width);
+ indent_level -= 5;
+ fprintf (out, "\n");
+ }
+ }
+
+ indent_level -= 5;
+
+ fprintf (out, "\n%*s(If you don't provide -f then the first argument will be the file to be debugged"
+ "\n%*s so '%s -- <filename> [<ARG1> [<ARG2>]]' also works."
+ "\n%*s Remember to end the options with \"--\" if any of your arguments have a \"-\" in them.)\n\n",
+ indent_level, "",
+ indent_level, "",
+ name,
+ indent_level, "");
+}
+
+void
+BuildGetOptTable (OptionDefinition *expanded_option_table, std::vector<struct option> &getopt_table,
+ uint32_t num_options)
+{
+ if (num_options == 0)
+ return;
+
+ uint32_t i;
+ uint32_t j;
+ std::bitset<256> option_seen;
+
+ getopt_table.resize (num_options + 1);
+
+ for (i = 0, j = 0; i < num_options; ++i)
+ {
+ char short_opt = expanded_option_table[i].short_option;
+
+ if (option_seen.test(short_opt) == false)
+ {
+ getopt_table[j].name = expanded_option_table[i].long_option;
+ getopt_table[j].has_arg = expanded_option_table[i].option_has_arg;
+ getopt_table[j].flag = NULL;
+ getopt_table[j].val = expanded_option_table[i].short_option;
+ option_seen.set(short_opt);
+ ++j;
+ }
+ }
+
+ getopt_table[j].name = NULL;
+ getopt_table[j].has_arg = 0;
+ getopt_table[j].flag = NULL;
+ getopt_table[j].val = 0;
+
+}
+
+Driver::OptionData::OptionData () :
+ m_args(),
+ m_script_lang (lldb::eScriptLanguageDefault),
+ m_core_file (),
+ m_crash_log (),
+ m_source_command_files (),
+ m_debug_mode (false),
+ m_print_version (false),
+ m_print_python_path (false),
+ m_print_help (false),
+ m_wait_for(false),
+ m_process_name(),
+ m_process_pid(LLDB_INVALID_PROCESS_ID),
+ m_use_external_editor(false),
+ m_seen_options()
+{
+}
+
+Driver::OptionData::~OptionData ()
+{
+}
+
+void
+Driver::OptionData::Clear ()
+{
+ m_args.clear ();
+ m_script_lang = lldb::eScriptLanguageDefault;
+ m_source_command_files.clear ();
+ m_debug_mode = false;
+ m_print_help = false;
+ m_print_version = false;
+ m_print_python_path = false;
+ m_use_external_editor = false;
+ m_wait_for = false;
+ m_process_name.erase();
+ m_process_pid = LLDB_INVALID_PROCESS_ID;
+}
+
+void
+Driver::ResetOptionValues ()
+{
+ m_option_data.Clear ();
+}
+
+const char *
+Driver::GetFilename() const
+{
+ if (m_option_data.m_args.empty())
+ return NULL;
+ return m_option_data.m_args.front().c_str();
+}
+
+const char *
+Driver::GetCrashLogFilename() const
+{
+ if (m_option_data.m_crash_log.empty())
+ return NULL;
+ return m_option_data.m_crash_log.c_str();
+}
+
+lldb::ScriptLanguage
+Driver::GetScriptLanguage() const
+{
+ return m_option_data.m_script_lang;
+}
+
+size_t
+Driver::GetNumSourceCommandFiles () const
+{
+ return m_option_data.m_source_command_files.size();
+}
+
+const char *
+Driver::GetSourceCommandFileAtIndex (uint32_t idx) const
+{
+ if (idx < m_option_data.m_source_command_files.size())
+ return m_option_data.m_source_command_files[idx].c_str();
+ return NULL;
+}
+
+bool
+Driver::GetDebugMode() const
+{
+ return m_option_data.m_debug_mode;
+}
+
+
+// Check the arguments that were passed to this program to make sure they are valid and to get their
+// argument values (if any). Return a boolean value indicating whether or not to start up the full
+// debugger (i.e. the Command Interpreter) or not. Return FALSE if the arguments were invalid OR
+// if the user only wanted help or version information.
+
+SBError
+Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
+{
+ ResetOptionValues ();
+
+ SBCommandReturnObject result;
+
+ SBError error;
+ std::string option_string;
+ struct option *long_options = NULL;
+ std::vector<struct option> long_options_vector;
+ uint32_t num_options;
+
+ for (num_options = 0; g_options[num_options].long_option != NULL; ++num_options)
+ /* Do Nothing. */;
+
+ if (num_options == 0)
+ {
+ if (argc > 1)
+ error.SetErrorStringWithFormat ("invalid number of options");
+ return error;
+ }
+
+ BuildGetOptTable (g_options, long_options_vector, num_options);
+
+ if (long_options_vector.empty())
+ long_options = NULL;
+ else
+ long_options = &long_options_vector.front();
+
+ if (long_options == NULL)
+ {
+ error.SetErrorStringWithFormat ("invalid long options");
+ return error;
+ }
+
+ // Build the option_string argument for call to getopt_long_only.
+
+ for (int i = 0; long_options[i].name != NULL; ++i)
+ {
+ if (long_options[i].flag == NULL)
+ {
+ option_string.push_back ((char) long_options[i].val);
+ switch (long_options[i].has_arg)
+ {
+ default:
+ case no_argument:
+ break;
+ case required_argument:
+ option_string.push_back (':');
+ break;
+ case optional_argument:
+ option_string.append ("::");
+ break;
+ }
+ }
+ }
+
+ // This is kind of a pain, but since we make the debugger in the Driver's constructor, we can't
+ // know at that point whether we should read in init files yet. So we don't read them in in the
+ // Driver constructor, then set the flags back to "read them in" here, and then if we see the
+ // "-n" flag, we'll turn it off again. Finally we have to read them in by hand later in the
+ // main loop.
+
+ m_debugger.SkipLLDBInitFiles (false);
+ m_debugger.SkipAppInitFiles (false);
+
+ // Prepare for & make calls to getopt_long_only.
+#if __GLIBC__
+ optind = 0;
+#else
+ optreset = 1;
+ optind = 1;
+#endif
+ int val;
+ while (1)
+ {
+ int long_options_index = -1;
+ val = ::getopt_long_only (argc, const_cast<char **>(argv), option_string.c_str(), long_options, &long_options_index);
+
+ if (val == -1)
+ break;
+ else if (val == '?')
+ {
+ m_option_data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unknown or ambiguous option");
+ break;
+ }
+ else if (val == 0)
+ continue;
+ else
+ {
+ m_option_data.m_seen_options.insert ((char) val);
+ if (long_options_index == -1)
+ {
+ for (int i = 0;
+ long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val;
+ ++i)
+ {
+ if (long_options[i].val == val)
+ {
+ long_options_index = i;
+ break;
+ }
+ }
+ }
+
+ if (long_options_index >= 0)
+ {
+ const int short_option = g_options[long_options_index].short_option;
+
+ switch (short_option)
+ {
+ case 'h':
+ m_option_data.m_print_help = true;
+ break;
+
+ case 'v':
+ m_option_data.m_print_version = true;
+ break;
+
+ case 'P':
+ m_option_data.m_print_python_path = true;
+ break;
+
+ case 'c':
+ {
+ SBFileSpec file(optarg);
+ if (file.Exists())
+ {
+ m_option_data.m_core_file = optarg;
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --core (-c) option doesn't exist: '%s'", optarg);
+ }
+ break;
+
+ case 'e':
+ m_option_data.m_use_external_editor = true;
+ break;
+
+ case 'x':
+ m_debugger.SkipLLDBInitFiles (true);
+ m_debugger.SkipAppInitFiles (true);
+ break;
+
+ case 'o':
+ m_debugger.SetUseColor (false);
+ break;
+
+ case 'f':
+ {
+ SBFileSpec file(optarg);
+ if (file.Exists())
+ {
+ m_option_data.m_args.push_back (optarg);
+ }
+ else if (file.ResolveExecutableLocation())
+ {
+ char path[PATH_MAX];
+ file.GetPath (path, sizeof(path));
+ m_option_data.m_args.push_back (path);
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --file (-f) option doesn't exist: '%s'", optarg);
+ }
+ break;
+
+ case 'a':
+ if (!m_debugger.SetDefaultArchitecture (optarg))
+ error.SetErrorStringWithFormat("invalid architecture in the -a or --arch option: '%s'", optarg);
+ break;
+
+ case 'l':
+ m_option_data.m_script_lang = m_debugger.GetScriptingLanguage (optarg);
+ break;
+
+ case 'd':
+ m_option_data.m_debug_mode = true;
+ break;
+
+ case 'n':
+ m_option_data.m_process_name = optarg;
+ break;
+
+ case 'w':
+ m_option_data.m_wait_for = true;
+ break;
+
+ case 'p':
+ {
+ char *remainder;
+ m_option_data.m_process_pid = strtol (optarg, &remainder, 0);
+ if (remainder == optarg || *remainder != '\0')
+ error.SetErrorStringWithFormat ("Could not convert process PID: \"%s\" into a pid.",
+ optarg);
+ }
+ break;
+ case 's':
+ {
+ SBFileSpec file(optarg);
+ if (file.Exists())
+ m_option_data.m_source_command_files.push_back (optarg);
+ else if (file.ResolveExecutableLocation())
+ {
+ char final_path[PATH_MAX];
+ file.GetPath (final_path, sizeof(final_path));
+ std::string path_str (final_path);
+ m_option_data.m_source_command_files.push_back (path_str);
+ }
+ else
+ error.SetErrorStringWithFormat("file specified in --source (-s) option doesn't exist: '%s'", optarg);
+ }
+ break;
+
+ default:
+ m_option_data.m_print_help = true;
+ error.SetErrorStringWithFormat ("unrecognized option %c", short_option);
+ break;
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("invalid option with value %i", val);
+ }
+ if (error.Fail())
+ {
+ return error;
+ }
+ }
+ }
+
+ if (error.Fail() || m_option_data.m_print_help)
+ {
+ ShowUsage (out_fh, g_options, m_option_data);
+ exit = true;
+ }
+ else if (m_option_data.m_print_version)
+ {
+ ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
+ exit = true;
+ }
+ else if (m_option_data.m_print_python_path)
+ {
+ SBFileSpec python_file_spec = SBHostOS::GetLLDBPythonPath();
+ if (python_file_spec.IsValid())
+ {
+ char python_path[PATH_MAX];
+ size_t num_chars = python_file_spec.GetPath(python_path, PATH_MAX);
+ if (num_chars < PATH_MAX)
+ {
+ ::fprintf (out_fh, "%s\n", python_path);
+ }
+ else
+ ::fprintf (out_fh, "<PATH TOO LONG>\n");
+ }
+ else
+ ::fprintf (out_fh, "<COULD NOT FIND PATH>\n");
+ exit = true;
+ }
+ else if (m_option_data.m_process_name.empty() && m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // Any arguments that are left over after option parsing are for
+ // the program. If a file was specified with -f then the filename
+ // is already in the m_option_data.m_args array, and any remaining args
+ // are arguments for the inferior program. If no file was specified with
+ // -f, then what is left is the program name followed by any arguments.
+
+ // Skip any options we consumed with getopt_long_only
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ {
+ for (int arg_idx=0; arg_idx<argc; ++arg_idx)
+ {
+ const char *arg = argv[arg_idx];
+ if (arg)
+ m_option_data.m_args.push_back (arg);
+ }
+ }
+
+ }
+ else
+ {
+ // Skip any options we consumed with getopt_long_only
+ argc -= optind;
+ //argv += optind; // Commented out to keep static analyzer happy
+
+ if (argc > 0)
+ ::fprintf (out_fh, "Warning: program arguments are ignored when attaching.\n");
+ }
+
+ return error;
+}
+
+size_t
+Driver::GetProcessSTDOUT ()
+{
+ // The process has stuff waiting for stdout; get it and write it out to the appropriate place.
+ char stdio_buffer[1024];
+ size_t len;
+ size_t total_bytes = 0;
+ while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ {
+ m_io_channel_ap->OutWrite (stdio_buffer, len, NO_ASYNC);
+ total_bytes += len;
+ }
+ return total_bytes;
+}
+
+size_t
+Driver::GetProcessSTDERR ()
+{
+ // The process has stuff waiting for stderr; get it and write it out to the appropriate place.
+ char stdio_buffer[1024];
+ size_t len;
+ size_t total_bytes = 0;
+ while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0)
+ {
+ m_io_channel_ap->ErrWrite (stdio_buffer, len, NO_ASYNC);
+ total_bytes += len;
+ }
+ return total_bytes;
+}
+
+void
+Driver::UpdateSelectedThread ()
+{
+ using namespace lldb;
+ SBProcess process(m_debugger.GetSelectedTarget().GetProcess());
+ if (process.IsValid())
+ {
+ SBThread curr_thread (process.GetSelectedThread());
+ SBThread thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ curr_thread_stop_reason = curr_thread.GetStopReason();
+
+ if (!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.
+ SBThread plan_thread;
+ SBThread other_thread;
+ const size_t num_threads = process.GetNumThreads();
+ size_t i;
+ for (i = 0; i < num_threads; ++i)
+ {
+ thread = process.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.IsValid())
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread.IsValid())
+ plan_thread = thread;
+ break;
+ }
+ }
+ if (plan_thread.IsValid())
+ process.SetSelectedThread (plan_thread);
+ else if (other_thread.IsValid())
+ process.SetSelectedThread (other_thread);
+ else
+ {
+ if (curr_thread.IsValid())
+ thread = curr_thread;
+ else
+ thread = process.GetThreadAtIndex(0);
+
+ if (thread.IsValid())
+ process.SetSelectedThread (thread);
+ }
+ }
+ }
+}
+
+// This function handles events that were broadcast by the process.
+void
+Driver::HandleBreakpointEvent (const SBEvent &event)
+{
+ using namespace lldb;
+ const uint32_t event_type = SBBreakpoint::GetBreakpointEventTypeFromEvent (event);
+
+ if (event_type & eBreakpointEventTypeAdded
+ || event_type & eBreakpointEventTypeRemoved
+ || event_type & eBreakpointEventTypeEnabled
+ || event_type & eBreakpointEventTypeDisabled
+ || event_type & eBreakpointEventTypeCommandChanged
+ || event_type & eBreakpointEventTypeConditionChanged
+ || event_type & eBreakpointEventTypeIgnoreChanged
+ || event_type & eBreakpointEventTypeLocationsResolved)
+ {
+ // Don't do anything about these events, since the breakpoint commands already echo these actions.
+ }
+ else if (event_type & eBreakpointEventTypeLocationsAdded)
+ {
+ char message[256];
+ uint32_t num_new_locations = SBBreakpoint::GetNumBreakpointLocationsFromEvent(event);
+ if (num_new_locations > 0)
+ {
+ SBBreakpoint breakpoint = SBBreakpoint::GetBreakpointFromEvent(event);
+ int message_len = ::snprintf (message, sizeof(message), "%d location%s added to breakpoint %d\n",
+ num_new_locations,
+ num_new_locations == 1 ? "" : "s",
+ breakpoint.GetID());
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
+ }
+ }
+ else if (event_type & eBreakpointEventTypeLocationsRemoved)
+ {
+ // These locations just get disabled, not sure it is worth spamming folks about this on the command line.
+ }
+ else if (event_type & eBreakpointEventTypeLocationsResolved)
+ {
+ // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy.
+ }
+}
+
+// This function handles events that were broadcast by the process.
+void
+Driver::HandleProcessEvent (const SBEvent &event)
+{
+ using namespace lldb;
+ const uint32_t event_type = event.GetType();
+
+ if (event_type & SBProcess::eBroadcastBitSTDOUT)
+ {
+ // The process has stdout available, get it and write it out to the
+ // appropriate place.
+ GetProcessSTDOUT ();
+ }
+ else if (event_type & SBProcess::eBroadcastBitSTDERR)
+ {
+ // The process has stderr available, get it and write it out to the
+ // appropriate place.
+ GetProcessSTDERR ();
+ }
+ else if (event_type & SBProcess::eBroadcastBitStateChanged)
+ {
+ // Drain all stout and stderr so we don't see any output come after
+ // we print our prompts
+ GetProcessSTDOUT ();
+ GetProcessSTDERR ();
+ // Something changed in the process; get the event and report the process's current status and location to
+ // the user.
+ StateType event_state = SBProcess::GetStateFromEvent (event);
+ if (event_state == eStateInvalid)
+ return;
+
+ SBProcess process (SBProcess::GetProcessFromEvent (event));
+ assert (process.IsValid());
+
+ switch (event_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStepping:
+ case eStateDetached:
+ {
+ char message[1024];
+ int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " %s\n", process.GetProcessID(),
+ m_debugger.StateAsCString (event_state));
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
+ }
+ break;
+
+ case eStateRunning:
+ // Don't be chatty when we run...
+ break;
+
+ case eStateExited:
+ {
+ SBCommandReturnObject result;
+ m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
+ m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+ m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
+ }
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // Make sure the program hasn't been auto-restarted:
+ if (SBProcess::GetRestartedFromEvent (event))
+ {
+ size_t num_reasons = SBProcess::GetNumRestartedReasonsFromEvent(event);
+ if (num_reasons > 0)
+ {
+ // FIXME: Do we want to report this, or would that just be annoyingly chatty?
+ if (num_reasons == 1)
+ {
+ char message[1024];
+ const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, 0);
+ int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted: %s\n",
+ process.GetProcessID(), reason ? reason : "<UNKNOWN REASON>");
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
+ }
+ else
+ {
+ char message[1024];
+ int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted, reasons:\n",
+ process.GetProcessID());
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
+ for (size_t i = 0; i < num_reasons; i++)
+ {
+ const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, i);
+ int message_len = ::snprintf(message, sizeof(message), "\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+ m_io_channel_ap->OutWrite(message, message_len, ASYNC);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (GetDebugger().GetSelectedTarget() == process.GetTarget())
+ {
+ SBCommandReturnObject result;
+ UpdateSelectedThread ();
+ m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false);
+ m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC);
+ m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC);
+ }
+ else
+ {
+ SBStream out_stream;
+ uint32_t target_idx = GetDebugger().GetIndexOfTarget(process.GetTarget());
+ if (target_idx != UINT32_MAX)
+ out_stream.Printf ("Target %d: (", target_idx);
+ else
+ out_stream.Printf ("Target <unknown index>: (");
+ process.GetTarget().GetDescription (out_stream, eDescriptionLevelBrief);
+ out_stream.Printf (") stopped.\n");
+ m_io_channel_ap->OutWrite (out_stream.GetData(), out_stream.GetSize(), ASYNC);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void
+Driver::HandleThreadEvent (const SBEvent &event)
+{
+ // At present the only thread event we handle is the Frame Changed event, and all we do for that is just
+ // reprint the thread status for that thread.
+ using namespace lldb;
+ const uint32_t event_type = event.GetType();
+ if (event_type == SBThread::eBroadcastBitStackChanged
+ || event_type == SBThread::eBroadcastBitThreadSelected)
+ {
+ SBThread thread = SBThread::GetThreadFromEvent (event);
+ if (thread.IsValid())
+ {
+ SBStream out_stream;
+ thread.GetStatus(out_stream);
+ m_io_channel_ap->OutWrite (out_stream.GetData (), out_stream.GetSize (), ASYNC);
+ }
+ }
+}
+
+// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit).
+
+bool
+Driver::HandleIOEvent (const SBEvent &event)
+{
+ bool quit = false;
+
+ const uint32_t event_type = event.GetType();
+
+ if (event_type & IOChannel::eBroadcastBitHasUserInput)
+ {
+ // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for
+ // handling.
+
+ const char *command_string = SBEvent::GetCStringFromEvent(event);
+ if (command_string == NULL)
+ command_string = "";
+ SBCommandReturnObject result;
+
+ // We don't want the result to bypass the OutWrite function in IOChannel, as this can result in odd
+ // output orderings and problems with the prompt.
+
+ // Note that we are in the process of executing a command
+ m_executing_user_command = true;
+
+ m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true);
+
+ // Note that we are back from executing a user command
+ m_executing_user_command = false;
+
+ // Display any STDOUT/STDERR _prior_ to emitting the command result text
+ GetProcessSTDOUT ();
+ GetProcessSTDERR ();
+
+ const bool only_if_no_immediate = true;
+
+ // Now emit the command output text from the command we just executed
+ const size_t output_size = result.GetOutputSize();
+ if (output_size > 0)
+ m_io_channel_ap->OutWrite (result.GetOutput(only_if_no_immediate), output_size, NO_ASYNC);
+
+ // Now emit the command error text from the command we just executed
+ const size_t error_size = result.GetErrorSize();
+ if (error_size > 0)
+ m_io_channel_ap->OutWrite (result.GetError(only_if_no_immediate), error_size, NO_ASYNC);
+
+ // We are done getting and running our command, we can now clear the
+ // m_waiting_for_command so we can get another one.
+ m_waiting_for_command = false;
+
+ // If our editline input reader is active, it means another input reader
+ // got pushed onto the input reader and caused us to become deactivated.
+ // When the input reader above us gets popped, we will get re-activated
+ // and our prompt will refresh in our callback
+ if (m_editline_reader.IsActive())
+ {
+ ReadyForCommand ();
+ }
+ }
+ else if (event_type & IOChannel::eBroadcastBitUserInterrupt)
+ {
+ // This is here to handle control-c interrupts from the user. It has not yet really been implemented.
+ // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER
+ //m_io_channel_ap->CancelInput();
+ // Anything else? Send Interrupt to process?
+ }
+ else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
+ (event_type & IOChannel::eBroadcastBitThreadDidExit))
+ {
+ // If the IOChannel thread is trying to go away, then it is definitely
+ // time to end the debugging session.
+ quit = true;
+ }
+
+ return quit;
+}
+
+void
+Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ Driver *driver = (Driver*)baton;
+ driver->GetFromMaster ((const char *)src, src_len);
+}
+
+void
+Driver::GetFromMaster (const char *src, size_t src_len)
+{
+ // Echo the characters back to the Debugger's stdout, that way if you
+ // type characters while a command is running, you'll see what you've typed.
+ FILE *out_fh = m_debugger.GetOutputFileHandle();
+ if (out_fh)
+ ::fwrite (src, 1, src_len, out_fh);
+}
+
+size_t
+Driver::EditLineInputReaderCallback
+(
+ void *baton,
+ SBInputReader *reader,
+ InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ Driver *driver = (Driver *)baton;
+
+ switch (notification)
+ {
+ case eInputReaderActivate:
+ break;
+
+ case eInputReaderReactivate:
+ if (driver->m_executing_user_command == false)
+ driver->ReadyForCommand();
+ break;
+
+ case eInputReaderDeactivate:
+ break;
+
+ case eInputReaderAsynchronousOutputWritten:
+ if (driver->m_io_channel_ap.get() != NULL)
+ driver->m_io_channel_ap->RefreshPrompt();
+ break;
+
+ case eInputReaderInterrupt:
+ if (driver->m_io_channel_ap.get() != NULL)
+ {
+ SBProcess process(driver->GetDebugger().GetSelectedTarget().GetProcess());
+ if (!driver->m_io_channel_ap->EditLineHasCharacters()
+ && process.IsValid()
+ && (process.GetState() == lldb::eStateRunning || process.GetState() == lldb::eStateAttaching))
+ {
+ process.SendAsyncInterrupt ();
+ }
+ else
+ {
+ driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC);
+ // I wish I could erase the entire input line, but there's no public API for that.
+ driver->m_io_channel_ap->EraseCharsBeforeCursor();
+ driver->m_io_channel_ap->RefreshPrompt();
+ }
+ }
+ break;
+
+ case eInputReaderEndOfFile:
+ if (driver->m_io_channel_ap.get() != NULL)
+ {
+ driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC);
+ driver->m_io_channel_ap->RefreshPrompt ();
+ }
+ write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5);
+ break;
+
+ case eInputReaderGotToken:
+ write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len);
+ break;
+
+ case eInputReaderDone:
+ break;
+ }
+ return bytes_len;
+}
+
+void
+Driver::MainLoop ()
+{
+ char error_str[1024];
+ if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false)
+ {
+ ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str);
+ exit(1);
+ }
+ else
+ {
+ const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str));
+ if (driver_slave_name == NULL)
+ {
+ ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str);
+ exit(2);
+ }
+ else
+ {
+ m_editline_slave_fh = ::fopen (driver_slave_name, "r+");
+ if (m_editline_slave_fh == NULL)
+ {
+ SBError error;
+ error.SetErrorToErrno();
+ ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s",
+ error.GetCString());
+ exit(3);
+ }
+
+ ::setbuf (m_editline_slave_fh, NULL);
+ }
+ }
+
+ lldb_utility::PseudoTerminal editline_output_pty;
+ FILE *editline_output_slave_fh = NULL;
+
+ if (editline_output_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, sizeof (error_str)) == false)
+ {
+ ::fprintf (stderr, "error: failed to open output pseudo terminal : %s", error_str);
+ exit(1);
+ }
+ else
+ {
+ const char *output_slave_name = editline_output_pty.GetSlaveName (error_str, sizeof(error_str));
+ if (output_slave_name == NULL)
+ {
+ ::fprintf (stderr, "error: failed to get slave name for output pseudo terminal : %s", error_str);
+ exit(2);
+ }
+ else
+ {
+ editline_output_slave_fh = ::fopen (output_slave_name, "r+");
+ if (editline_output_slave_fh == NULL)
+ {
+ SBError error;
+ error.SetErrorToErrno();
+ ::fprintf (stderr, "error: failed to get open slave for output pseudo terminal : %s",
+ error.GetCString());
+ exit(3);
+ }
+ ::setbuf (editline_output_slave_fh, NULL);
+ }
+ }
+
+ // struct termios stdin_termios;
+
+ if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0)
+ {
+ g_old_stdin_termios_is_valid = true;
+ atexit (reset_stdin_termios);
+ }
+
+ ::setbuf (stdin, NULL);
+ ::setbuf (stdout, NULL);
+
+ m_debugger.SetErrorFileHandle (stderr, false);
+ m_debugger.SetOutputFileHandle (stdout, false);
+ m_debugger.SetInputFileHandle (stdin, true);
+
+ m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor);
+
+ // You have to drain anything that comes to the master side of the PTY. master_out_comm is
+ // for that purpose. The reason you need to do this is a curious reason... editline will echo
+ // characters to the PTY when it gets characters while el_gets is not running, and then when
+ // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks
+ // if there are unconsumed characters in the out buffer.
+ // However, you don't need to do anything with the characters, since editline will dump these
+ // unconsumed characters after printing the prompt again in el_gets.
+
+ SBCommunication master_out_comm("driver.editline");
+ master_out_comm.SetCloseOnEOF (false);
+ master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false);
+ master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this);
+
+ if (master_out_comm.ReadThreadStart () == false)
+ {
+ ::fprintf (stderr, "error: failed to start master out read thread");
+ exit(5);
+ }
+
+ SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter();
+
+ m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this));
+
+ SBCommunication out_comm_2("driver.editline_output");
+ out_comm_2.SetCloseOnEOF (false);
+ out_comm_2.AdoptFileDesriptor (editline_output_pty.GetMasterFileDescriptor(), false);
+ out_comm_2.SetReadThreadBytesReceivedCallback (IOChannel::LibeditOutputBytesReceived, m_io_channel_ap.get());
+
+ if (out_comm_2.ReadThreadStart () == false)
+ {
+ ::fprintf (stderr, "error: failed to start libedit output read thread");
+ exit (5);
+ }
+
+
+ struct winsize window_size;
+ if (isatty (STDIN_FILENO)
+ && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
+ {
+ if (window_size.ws_col > 0)
+ m_debugger.SetTerminalWidth (window_size.ws_col);
+ }
+
+ // Since input can be redirected by the debugger, we must insert our editline
+ // input reader in the queue so we know when our reader should be active
+ // and so we can receive bytes only when we are supposed to.
+ SBError err (m_editline_reader.Initialize (m_debugger,
+ Driver::EditLineInputReaderCallback, // callback
+ this, // baton
+ eInputReaderGranularityByte, // token_size
+ NULL, // end token - NULL means never done
+ NULL, // prompt - taken care of elsewhere
+ false)); // echo input - don't need Debugger
+ // to do this, we handle it elsewhere
+
+ if (err.Fail())
+ {
+ ::fprintf (stderr, "error: %s", err.GetCString());
+ exit (6);
+ }
+
+ m_debugger.PushInputReader (m_editline_reader);
+
+ SBListener listener(m_debugger.GetListener());
+ if (listener.IsValid())
+ {
+
+ listener.StartListeningForEventClass(m_debugger,
+ SBTarget::GetBroadcasterClassName(),
+ SBTarget::eBroadcastBitBreakpointChanged);
+ listener.StartListeningForEventClass(m_debugger,
+ SBThread::GetBroadcasterClassName(),
+ SBThread::eBroadcastBitStackChanged |
+ SBThread::eBroadcastBitThreadSelected);
+ listener.StartListeningForEvents (*m_io_channel_ap,
+ IOChannel::eBroadcastBitHasUserInput |
+ IOChannel::eBroadcastBitUserInterrupt |
+ IOChannel::eBroadcastBitThreadShouldExit |
+ IOChannel::eBroadcastBitThreadDidStart |
+ IOChannel::eBroadcastBitThreadDidExit);
+
+ if (m_io_channel_ap->Start ())
+ {
+ bool iochannel_thread_exited = false;
+
+ listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(),
+ SBCommandInterpreter::eBroadcastBitQuitCommandReceived |
+ SBCommandInterpreter::eBroadcastBitAsynchronousOutputData |
+ SBCommandInterpreter::eBroadcastBitAsynchronousErrorData);
+
+ // Before we handle any options from the command line, we parse the
+ // .lldbinit file in the user's home directory.
+ SBCommandReturnObject result;
+ sb_interpreter.SourceInitFileInHomeDirectory(result);
+ if (GetDebugMode())
+ {
+ result.PutError (m_debugger.GetErrorFileHandle());
+ result.PutOutput (m_debugger.GetOutputFileHandle());
+ }
+
+ // Now we handle options we got from the command line
+ char command_string[PATH_MAX * 2];
+ const size_t num_source_command_files = GetNumSourceCommandFiles();
+ const bool dump_stream_only_if_no_immediate = true;
+ if (num_source_command_files > 0)
+ {
+ for (size_t i=0; i < num_source_command_files; ++i)
+ {
+ const char *command_file = GetSourceCommandFileAtIndex(i);
+ ::snprintf (command_string, sizeof(command_string), "command source '%s'", command_file);
+ m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, false);
+ if (GetDebugMode())
+ {
+ result.PutError (m_debugger.GetErrorFileHandle());
+ result.PutOutput (m_debugger.GetOutputFileHandle());
+ }
+
+ // if the command sourcing generated an error - dump the result object
+ if (result.Succeeded() == false)
+ {
+ const size_t output_size = result.GetOutputSize();
+ if (output_size > 0)
+ m_io_channel_ap->OutWrite (result.GetOutput(dump_stream_only_if_no_immediate), output_size, NO_ASYNC);
+ const size_t error_size = result.GetErrorSize();
+ if (error_size > 0)
+ m_io_channel_ap->OutWrite (result.GetError(dump_stream_only_if_no_immediate), error_size, NO_ASYNC);
+ }
+
+ result.Clear();
+ }
+ }
+
+ // Was there a core file specified?
+ std::string core_file_spec("");
+ if (!m_option_data.m_core_file.empty())
+ core_file_spec.append("--core ").append(m_option_data.m_core_file);
+
+ const size_t num_args = m_option_data.m_args.size();
+ if (num_args > 0)
+ {
+ char arch_name[64];
+ if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name)))
+ ::snprintf (command_string,
+ sizeof (command_string),
+ "target create --arch=%s %s \"%s\"",
+ arch_name,
+ core_file_spec.c_str(),
+ m_option_data.m_args[0].c_str());
+ else
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "target create %s \"%s\"",
+ core_file_spec.c_str(),
+ m_option_data.m_args[0].c_str());
+
+ m_debugger.HandleCommand (command_string);
+
+ if (num_args > 1)
+ {
+ m_debugger.HandleCommand ("settings clear target.run-args");
+ char arg_cstr[1024];
+ for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx)
+ {
+ ::snprintf (arg_cstr,
+ sizeof(arg_cstr),
+ "settings append target.run-args \"%s\"",
+ m_option_data.m_args[arg_idx].c_str());
+ m_debugger.HandleCommand (arg_cstr);
+ }
+ }
+ }
+ else if (!core_file_spec.empty())
+ {
+ ::snprintf (command_string,
+ sizeof(command_string),
+ "target create %s",
+ core_file_spec.c_str());
+ m_debugger.HandleCommand (command_string);;
+ }
+
+ // Now that all option parsing is done, we try and parse the .lldbinit
+ // file in the current working directory
+ sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result);
+ if (GetDebugMode())
+ {
+ result.PutError(m_debugger.GetErrorFileHandle());
+ result.PutOutput(m_debugger.GetOutputFileHandle());
+ }
+
+ SBEvent event;
+
+ // Make sure the IO channel is started up before we try to tell it we
+ // are ready for input
+ listener.WaitForEventForBroadcasterWithType (UINT32_MAX,
+ *m_io_channel_ap,
+ IOChannel::eBroadcastBitThreadDidStart,
+ event);
+ // If we were asked to attach, then do that here:
+ // I'm going to use the command string rather than directly
+ // calling the API's because then I don't have to recode the
+ // event handling here.
+ if (!m_option_data.m_process_name.empty()
+ || m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ std::string command_str("process attach ");
+ if (m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ command_str.append("-p ");
+ char pid_buffer[32];
+ ::snprintf (pid_buffer, sizeof(pid_buffer), "%" PRIu64, m_option_data.m_process_pid);
+ command_str.append(pid_buffer);
+ }
+ else
+ {
+ command_str.append("-n \"");
+ command_str.append(m_option_data.m_process_name);
+ command_str.push_back('\"');
+ if (m_option_data.m_wait_for)
+ command_str.append(" -w");
+ }
+
+ if (m_debugger.GetOutputFileHandle())
+ ::fprintf (m_debugger.GetOutputFileHandle(),
+ "Attaching to process with:\n %s\n",
+ command_str.c_str());
+
+ // Force the attach to be synchronous:
+ bool orig_async = m_debugger.GetAsync();
+ m_debugger.SetAsync(true);
+ m_debugger.HandleCommand(command_str.c_str());
+ m_debugger.SetAsync(orig_async);
+ }
+
+ ReadyForCommand ();
+
+ while (!GetIsDone())
+ {
+ listener.WaitForEvent (UINT32_MAX, event);
+ if (event.IsValid())
+ {
+ if (event.GetBroadcaster().IsValid())
+ {
+ uint32_t event_type = event.GetType();
+ if (event.BroadcasterMatchesRef (*m_io_channel_ap))
+ {
+ if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) ||
+ (event_type & IOChannel::eBroadcastBitThreadDidExit))
+ {
+ SetIsDone();
+ if (event_type & IOChannel::eBroadcastBitThreadDidExit)
+ iochannel_thread_exited = true;
+ }
+ else
+ {
+ if (HandleIOEvent (event))
+ SetIsDone();
+ }
+ }
+ else if (SBProcess::EventIsProcessEvent (event))
+ {
+ HandleProcessEvent (event);
+ }
+ else if (SBBreakpoint::EventIsBreakpointEvent (event))
+ {
+ HandleBreakpointEvent (event);
+ }
+ else if (SBThread::EventIsThreadEvent (event))
+ {
+ HandleThreadEvent (event);
+ }
+ else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster()))
+ {
+ // TODO: deprecate the eBroadcastBitQuitCommandReceived event
+ // now that we have SBCommandInterpreter::SetCommandOverrideCallback()
+ // that can take over a command
+ if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived)
+ {
+ SetIsDone();
+ }
+ else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousErrorData)
+ {
+ const char *data = SBEvent::GetCStringFromEvent (event);
+ m_io_channel_ap->ErrWrite (data, strlen(data), ASYNC);
+ }
+ else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousOutputData)
+ {
+ const char *data = SBEvent::GetCStringFromEvent (event);
+ m_io_channel_ap->OutWrite (data, strlen(data), ASYNC);
+ }
+ }
+ }
+ }
+ }
+
+ master_out_comm.SetReadThreadBytesReceivedCallback(NULL, NULL);
+ master_out_comm.Disconnect();
+ master_out_comm.ReadThreadStop();
+
+ out_comm_2.SetReadThreadBytesReceivedCallback(NULL, NULL);
+ out_comm_2.Disconnect();
+ out_comm_2.ReadThreadStop();
+
+ editline_output_pty.CloseMasterFileDescriptor();
+ reset_stdin_termios();
+ fclose (stdin);
+
+ CloseIOChannelFile ();
+
+ if (!iochannel_thread_exited)
+ {
+ event.Clear();
+ listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap,
+ IOChannel::eBroadcastBitThreadDidExit,
+ event);
+ if (!event.IsValid())
+ {
+ // Send end EOF to the driver file descriptor
+ m_io_channel_ap->Stop();
+ }
+ }
+
+ SBDebugger::Destroy (m_debugger);
+ }
+ }
+}
+
+
+void
+Driver::ReadyForCommand ()
+{
+ if (m_waiting_for_command == false)
+ {
+ m_waiting_for_command = true;
+ BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true);
+ }
+}
+
+void
+Driver::ResizeWindow (unsigned short col)
+{
+ GetDebugger().SetTerminalWidth (col);
+ if (m_io_channel_ap.get() != NULL)
+ {
+ m_io_channel_ap->ElResize();
+ }
+}
+
+void
+sigwinch_handler (int signo)
+{
+ struct winsize window_size;
+ if (isatty (STDIN_FILENO)
+ && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
+ {
+ if ((window_size.ws_col > 0) && g_driver != NULL)
+ {
+ g_driver->ResizeWindow (window_size.ws_col);
+ }
+ }
+}
+
+void
+sigint_handler (int signo)
+{
+ static bool g_interrupt_sent = false;
+ if (g_driver)
+ {
+ if (!g_interrupt_sent)
+ {
+ g_interrupt_sent = true;
+ g_driver->GetDebugger().DispatchInputInterrupt();
+ g_interrupt_sent = false;
+ return;
+ }
+ }
+
+ exit (signo);
+}
+
+void
+sigtstp_handler (int signo)
+{
+ g_driver->GetDebugger().SaveInputTerminalState();
+ signal (signo, SIG_DFL);
+ kill (getpid(), signo);
+ signal (signo, sigtstp_handler);
+}
+
+void
+sigcont_handler (int signo)
+{
+ g_driver->GetDebugger().RestoreInputTerminalState();
+ signal (signo, SIG_DFL);
+ kill (getpid(), signo);
+ signal (signo, sigcont_handler);
+}
+
+int
+main (int argc, char const *argv[], const char *envp[])
+{
+ SBDebugger::Initialize();
+
+ SBHostOS::ThreadCreated ("<lldb.driver.main-thread>");
+
+ signal (SIGPIPE, SIG_IGN);
+ signal (SIGWINCH, sigwinch_handler);
+ signal (SIGINT, sigint_handler);
+ signal (SIGTSTP, sigtstp_handler);
+ signal (SIGCONT, sigcont_handler);
+
+ // Create a scope for driver so that the driver object will destroy itself
+ // before SBDebugger::Terminate() is called.
+ {
+ Driver driver;
+
+ bool exit = false;
+ SBError error (driver.ParseArgs (argc, argv, stdout, exit));
+ if (error.Fail())
+ {
+ const char *error_cstr = error.GetCString ();
+ if (error_cstr)
+ ::fprintf (stderr, "error: %s\n", error_cstr);
+ }
+ else if (!exit)
+ {
+ driver.MainLoop ();
+ }
+ }
+
+ SBDebugger::Terminate();
+ return 0;
+}
diff --git a/tools/driver/Driver.h b/tools/driver/Driver.h
new file mode 100644
index 000000000000..2a4a27df4cdc
--- /dev/null
+++ b/tools/driver/Driver.h
@@ -0,0 +1,201 @@
+//===-- Driver.h ------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Driver_h_
+#define lldb_Driver_h_
+
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include <set>
+#include <bitset>
+#include <string>
+#include <vector>
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBBroadcaster.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBInputReader.h"
+
+#define ASYNC true
+#define NO_ASYNC false
+
+class IOChannel;
+
+namespace lldb
+{
+ class SBInputReader;
+}
+
+
+class Driver : public lldb::SBBroadcaster
+{
+public:
+ enum {
+ eBroadcastBitReadyForInput = (1 << 0),
+ eBroadcastBitThreadShouldExit = (1 << 1)
+ };
+
+ Driver ();
+
+ virtual
+ ~Driver ();
+
+ void
+ MainLoop ();
+
+ void
+ PutSTDIN (const char *src, size_t src_len);
+
+ void
+ GetFromMaster (const char *src, size_t src_len);
+
+ bool
+ HandleIOEvent (const lldb::SBEvent &event);
+
+ void
+ HandleProcessEvent (const lldb::SBEvent &event);
+
+ void
+ HandleBreakpointEvent (const lldb::SBEvent &event);
+
+ void
+ HandleThreadEvent (const lldb::SBEvent &event);
+
+ lldb::SBError
+ ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &do_exit);
+
+ const char *
+ GetFilename() const;
+
+ const char *
+ GetCrashLogFilename() const;
+
+ const char *
+ GetArchName() const;
+
+ lldb::ScriptLanguage
+ GetScriptLanguage() const;
+
+ size_t
+ GetNumSourceCommandFiles () const;
+
+ const char *
+ GetSourceCommandFileAtIndex (uint32_t idx) const;
+
+ bool
+ GetDebugMode() const;
+
+
+ class OptionData
+ {
+ public:
+ OptionData ();
+ ~OptionData ();
+
+ void
+ Clear();
+
+ //static OptionDefinition m_cmd_option_table[];
+
+ std::vector<std::string> m_args;
+ lldb::ScriptLanguage m_script_lang;
+ std::string m_core_file;
+ std::string m_crash_log;
+ std::vector<std::string> m_source_command_files;
+ bool m_debug_mode;
+ bool m_print_version;
+ bool m_print_python_path;
+ bool m_print_help;
+ bool m_wait_for;
+ std::string m_process_name;
+ lldb::pid_t m_process_pid;
+ bool m_use_external_editor; // FIXME: When we have set/show variables we can remove this from here.
+ typedef std::set<char> OptionSet;
+ OptionSet m_seen_options;
+ };
+
+
+ static lldb::SBError
+ SetOptionValue (int option_idx,
+ const char *option_arg,
+ Driver::OptionData &data);
+
+
+ lldb::SBDebugger &
+ GetDebugger()
+ {
+ return m_debugger;
+ }
+
+ bool
+ EditlineReaderIsTop ()
+ {
+ return m_debugger.InputReaderIsTopReader (m_editline_reader);
+ }
+
+ bool
+ GetIsDone () const
+ {
+ return m_done;
+ }
+
+ void
+ SetIsDone ()
+ {
+ m_done = true;
+ }
+
+ void
+ ResizeWindow (unsigned short col);
+
+private:
+ lldb::SBDebugger m_debugger;
+ lldb_utility::PseudoTerminal m_editline_pty;
+ FILE *m_editline_slave_fh;
+ lldb::SBInputReader m_editline_reader;
+ std::unique_ptr<IOChannel> m_io_channel_ap;
+ OptionData m_option_data;
+ bool m_executing_user_command;
+ bool m_waiting_for_command;
+ bool m_done;
+
+ void
+ ResetOptionValues ();
+
+ size_t
+ GetProcessSTDOUT ();
+
+ size_t
+ GetProcessSTDERR ();
+
+ void
+ UpdateSelectedThread ();
+
+ void
+ CloseIOChannelFile ();
+
+ static size_t
+ EditLineInputReaderCallback (void *baton,
+ lldb::SBInputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ static void
+ ReadThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ static void
+ MasterThreadBytesReceived (void *baton, const void *src, size_t src_len);
+
+ void
+ ReadyForCommand ();
+};
+
+#endif // lldb_Driver_h_
diff --git a/tools/driver/IOChannel.cpp b/tools/driver/IOChannel.cpp
new file mode 100644
index 000000000000..7adf2e4e85e9
--- /dev/null
+++ b/tools/driver/IOChannel.cpp
@@ -0,0 +1,647 @@
+//===-- IOChannel.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IOChannel.h"
+
+#include <map>
+
+#include "lldb/API/SBCommandInterpreter.h"
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBEvent.h"
+#include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBHostOS.h"
+#include "lldb/API/SBListener.h"
+#include "lldb/API/SBStringList.h"
+
+#include <string.h>
+#include <limits.h>
+
+using namespace lldb;
+
+typedef std::map<EditLine *, std::string> PromptMap;
+const char *g_default_prompt = "(lldb) ";
+PromptMap g_prompt_map;
+
+// Printing the following string causes libedit to back up to the beginning of the line & blank it out.
+const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75};
+
+static const char*
+el_prompt(EditLine *el)
+{
+ PromptMap::const_iterator pos = g_prompt_map.find (el);
+ if (pos == g_prompt_map.end())
+ return g_default_prompt;
+ return pos->second.c_str();
+}
+
+const char *
+IOChannel::GetPrompt ()
+{
+ PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line);
+ if (pos == g_prompt_map.end())
+ return g_default_prompt;
+ return pos->second.c_str();
+}
+
+bool
+IOChannel::EditLineHasCharacters ()
+{
+ const LineInfo *line_info = el_line(m_edit_line);
+ if (line_info)
+ {
+ // Sometimes we get called after the user has submitted the line, but before editline has
+ // cleared the buffer. In that case the cursor will be pointing at the newline. That's
+ // equivalent to having no characters on the line, since it has already been submitted.
+ if (*line_info->cursor == '\n')
+ return false;
+ else
+ return line_info->cursor != line_info->buffer;
+ }
+ else
+ return false;
+}
+
+
+void
+IOChannel::EraseCharsBeforeCursor ()
+{
+ const LineInfo *line_info = el_line(m_edit_line);
+ el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
+}
+
+unsigned char
+IOChannel::ElCompletionFn (EditLine *e, int ch)
+{
+ IOChannel *io_channel;
+ if (el_get(e, EL_CLIENTDATA, &io_channel) == 0)
+ {
+ return io_channel->HandleCompletion (e, ch);
+ }
+ else
+ {
+ return CC_ERROR;
+ }
+}
+
+void
+IOChannel::ElResize()
+{
+ el_resize(m_edit_line);
+}
+
+unsigned char
+IOChannel::HandleCompletion (EditLine *e, int ch)
+{
+ assert (e == m_edit_line);
+
+ const LineInfo *line_info = el_line(m_edit_line);
+ SBStringList completions;
+ int page_size = 40;
+
+ int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer,
+ line_info->cursor,
+ line_info->lastchar,
+ 0,
+ -1,
+ completions);
+
+ if (num_completions == -1)
+ {
+ el_insertstr (m_edit_line, m_completion_key);
+ return CC_REDISPLAY;
+ }
+ else if (num_completions == -2)
+ {
+ el_deletestr (m_edit_line, line_info->cursor - line_info->buffer);
+ el_insertstr (m_edit_line, 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')
+ {
+ el_insertstr (m_edit_line, completion_str);
+ return CC_REDISPLAY;
+ }
+
+ if (num_completions > 1)
+ {
+ const char *comment = "\nAvailable completions:";
+
+ int num_elements = num_completions + 1;
+ OutWrite(comment, strlen (comment), NO_ASYNC);
+ if (num_completions < page_size)
+ {
+ for (int i = 1; i < num_elements; i++)
+ {
+ completion_str = completions.GetStringAtIndex(i);
+ OutWrite("\n\t", 2, NO_ASYNC);
+ OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
+ }
+ OutWrite ("\n", 1, NO_ASYNC);
+ }
+ else
+ {
+ int cur_pos = 1;
+ char reply;
+ int got_char;
+ while (cur_pos < num_elements)
+ {
+ int endpoint = cur_pos + page_size;
+ if (endpoint > num_elements)
+ endpoint = num_elements;
+ for (; cur_pos < endpoint; cur_pos++)
+ {
+ completion_str = completions.GetStringAtIndex(cur_pos);
+ OutWrite("\n\t", 2, NO_ASYNC);
+ OutWrite(completion_str, strlen (completion_str), NO_ASYNC);
+ }
+
+ if (cur_pos >= num_elements)
+ {
+ OutWrite("\n", 1, NO_ASYNC);
+ break;
+ }
+
+ OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC);
+ reply = 'n';
+ got_char = el_getc(m_edit_line, &reply);
+ if (got_char == -1 || reply == 'n')
+ break;
+ if (reply == 'a')
+ page_size = num_elements - cur_pos;
+ }
+ }
+
+ }
+
+ if (num_completions == 0)
+ return CC_REFRESH_BEEP;
+ else
+ return CC_REDISPLAY;
+}
+
+IOChannel::IOChannel
+(
+ FILE *editline_in,
+ FILE *editline_out,
+ FILE *out,
+ FILE *err,
+ Driver *driver
+) :
+ SBBroadcaster ("IOChannel"),
+ m_output_mutex (),
+ m_enter_elgets_time (),
+ m_driver (driver),
+ m_read_thread (LLDB_INVALID_HOST_THREAD),
+ m_read_thread_should_exit (false),
+ m_out_file (out),
+ m_err_file (err),
+ m_command_queue (),
+ m_completion_key ("\t"),
+ m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)),
+ m_history (history_init()),
+ m_history_event(),
+ m_getting_command (false),
+ m_expecting_prompt (false),
+ m_prompt_str (),
+ m_refresh_request_pending (false)
+{
+ assert (m_edit_line);
+ ::el_set (m_edit_line, EL_PROMPT, el_prompt);
+ ::el_set (m_edit_line, EL_EDITOR, "emacs");
+ ::el_set (m_edit_line, EL_HIST, history, m_history);
+
+ el_set (m_edit_line, EL_ADDFN, "lldb_complete",
+ "LLDB completion function",
+ IOChannel::ElCompletionFn);
+ el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL);
+ el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string
+ el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does.
+ el_set (m_edit_line, EL_BIND, "\e[3~", "ed-delete-next-char", NULL); // Fix the delete key.
+ el_set (m_edit_line, EL_CLIENTDATA, this);
+
+ // Source $PWD/.editrc then $HOME/.editrc
+ ::el_source (m_edit_line, NULL);
+
+ assert (m_history);
+ ::history (m_history, &m_history_event, H_SETSIZE, 800);
+ ::history (m_history, &m_history_event, H_SETUNIQUE, 1);
+ // Load history
+ HistorySaveLoad (false);
+
+ // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
+ // with each other when writing.
+
+ int error;
+ ::pthread_mutexattr_t attr;
+ error = ::pthread_mutexattr_init (&attr);
+ assert (error == 0);
+ error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
+ assert (error == 0);
+ error = ::pthread_mutex_init (&m_output_mutex, &attr);
+ assert (error == 0);
+ error = ::pthread_mutexattr_destroy (&attr);
+ assert (error == 0);
+
+ // Initialize time that ::el_gets was last called.
+
+ m_enter_elgets_time.tv_sec = 0;
+ m_enter_elgets_time.tv_usec = 0;
+}
+
+IOChannel::~IOChannel ()
+{
+ // Save history
+ HistorySaveLoad (true);
+
+ if (m_history != NULL)
+ {
+ ::history_end (m_history);
+ m_history = NULL;
+ }
+
+ if (m_edit_line != NULL)
+ {
+ ::el_end (m_edit_line);
+ m_edit_line = NULL;
+ }
+
+ ::pthread_mutex_destroy (&m_output_mutex);
+}
+
+void
+IOChannel::HistorySaveLoad (bool save)
+{
+ if (m_history != NULL)
+ {
+ char history_path[PATH_MAX];
+ ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename());
+ if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1)
+ {
+ const char *path_ptr = history_path;
+ if (save)
+ ::history (m_history, &m_history_event, H_SAVE, path_ptr);
+ else
+ ::history (m_history, &m_history_event, H_LOAD, path_ptr);
+ }
+ }
+}
+
+void
+IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
+{
+ // Make this a member variable.
+ // static std::string prompt_str;
+ IOChannel *io_channel = (IOChannel *) baton;
+ IOLocker locker (io_channel->m_output_mutex);
+ const char *bytes = (const char *) src;
+
+ if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt)
+ {
+ io_channel->m_prompt_str.append (bytes, src_len);
+ // Log this to make sure the prompt is really what you think it is.
+ if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0)
+ {
+ io_channel->m_expecting_prompt = false;
+ io_channel->m_refresh_request_pending = false;
+ io_channel->OutWrite (io_channel->m_prompt_str.c_str(),
+ io_channel->m_prompt_str.size(), NO_ASYNC);
+ io_channel->m_prompt_str.clear();
+ }
+ }
+ else
+ {
+ if (io_channel->m_prompt_str.size() > 0)
+ io_channel->m_prompt_str.clear();
+ std::string tmp_str (bytes, src_len);
+ if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0)
+ io_channel->m_refresh_request_pending = false;
+ io_channel->OutWrite (bytes, src_len, NO_ASYNC);
+ }
+}
+
+IOChannel::LibeditGetInputResult
+IOChannel::LibeditGetInput (std::string &new_line)
+{
+ IOChannel::LibeditGetInputResult retval = IOChannel::eLibeditGetInputResultUnknown;
+ if (m_edit_line != NULL)
+ {
+ int line_len = 0;
+
+ // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt
+ // to refresh the prompt after writing data).
+ SetGettingCommand (true);
+ m_expecting_prompt = true;
+
+ // Call el_gets to prompt the user and read the user's input.
+ const char *line = ::el_gets (m_edit_line, &line_len);
+
+ // Re-set the boolean indicating whether or not el_gets is trying to get input.
+ SetGettingCommand (false);
+
+ if (line)
+ {
+ retval = IOChannel::eLibeditGetInputValid;
+ // strip any newlines off the end of the string...
+ while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r'))
+ --line_len;
+ if (line_len > 0)
+ {
+ ::history (m_history, &m_history_event, H_ENTER, line);
+ new_line.assign (line, line_len); // Omit the newline
+ }
+ else
+ {
+ retval = IOChannel::eLibeditGetInputEmpty;
+ // Someone just hit ENTER, return the empty string
+ new_line.clear();
+ }
+ // Return true to indicate success even if a string is empty
+ return retval;
+ }
+ else
+ {
+ retval = (line_len == 0 ? IOChannel::eLibeditGetInputEOF : IOChannel::eLibeditGetInputResultError);
+ }
+ }
+ // Return false to indicate failure. This can happen when the file handle
+ // is closed (EOF).
+ new_line.clear();
+ return retval;
+}
+
+void *
+IOChannel::IOReadThread (void *ptr)
+{
+ IOChannel *myself = static_cast<IOChannel *> (ptr);
+ myself->Run();
+ return NULL;
+}
+
+void
+IOChannel::Run ()
+{
+ SBListener listener("IOChannel::Run");
+ std::string new_line;
+
+ SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster());
+ listener.StartListeningForEvents (interpreter_broadcaster,
+ SBCommandInterpreter::eBroadcastBitResetPrompt |
+ SBCommandInterpreter::eBroadcastBitThreadShouldExit |
+ SBCommandInterpreter::eBroadcastBitQuitCommandReceived);
+
+ listener.StartListeningForEvents (*this,
+ IOChannel::eBroadcastBitThreadShouldExit);
+
+ listener.StartListeningForEvents (*m_driver,
+ Driver::eBroadcastBitReadyForInput |
+ Driver::eBroadcastBitThreadShouldExit);
+
+ // Let anyone know that the IO channel is up and listening and ready for events
+ BroadcastEventByType (eBroadcastBitThreadDidStart);
+ bool done = false;
+ while (!done)
+ {
+ SBEvent event;
+
+ listener.WaitForEvent (UINT32_MAX, event);
+ if (!event.IsValid())
+ continue;
+
+ const uint32_t event_type = event.GetType();
+
+ if (event.GetBroadcaster().IsValid())
+ {
+ if (event.BroadcasterMatchesPtr (m_driver))
+ {
+ if (event_type & Driver::eBroadcastBitReadyForInput)
+ {
+ std::string line;
+
+ if (CommandQueueIsEmpty())
+ {
+ IOChannel::LibeditGetInputResult getline_result = LibeditGetInput(line);
+ if (getline_result == IOChannel::eLibeditGetInputEOF)
+ {
+ // EOF occurred
+ // pretend that a quit was typed so the user gets a potential
+ // chance to confirm
+ line.assign("quit");
+ }
+ else if (getline_result == IOChannel::eLibeditGetInputResultError || getline_result == IOChannel::eLibeditGetInputResultUnknown)
+ {
+ // some random error occurred, exit and don't ask because the state might be corrupt
+ done = true;
+ continue;
+ }
+ }
+ else
+ {
+ GetCommandFromQueue (line);
+ }
+
+ // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN'
+ // AND TAKE CARE OF THAT HERE.
+
+ SBEvent line_event(IOChannel::eBroadcastBitHasUserInput,
+ line.c_str(),
+ line.size());
+ BroadcastEvent (line_event);
+ }
+ else if (event_type & Driver::eBroadcastBitThreadShouldExit)
+ {
+ done = true;
+ continue;
+ }
+ }
+ else if (event.BroadcasterMatchesRef (interpreter_broadcaster))
+ {
+ switch (event_type)
+ {
+ case SBCommandInterpreter::eBroadcastBitResetPrompt:
+ {
+ const char *new_prompt = SBEvent::GetCStringFromEvent (event);
+ if (new_prompt)
+ g_prompt_map[m_edit_line] = new_prompt;
+ }
+ break;
+
+ case SBCommandInterpreter::eBroadcastBitThreadShouldExit:
+ case SBCommandInterpreter::eBroadcastBitQuitCommandReceived:
+ done = true;
+ break;
+ }
+ }
+ else if (event.BroadcasterMatchesPtr (this))
+ {
+ if (event_type & IOChannel::eBroadcastBitThreadShouldExit)
+ {
+ done = true;
+ continue;
+ }
+ }
+ }
+ }
+ BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit);
+ m_driver = NULL;
+ m_read_thread = 0;
+}
+
+bool
+IOChannel::Start ()
+{
+ if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ return true;
+
+ m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
+ NULL);
+
+ return (IS_VALID_LLDB_HOST_THREAD(m_read_thread));
+}
+
+bool
+IOChannel::Stop ()
+{
+ if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread))
+ return true;
+
+ BroadcastEventByType (eBroadcastBitThreadShouldExit);
+
+ // Don't call Host::ThreadCancel since el_gets won't respond to this
+ // function call -- the thread will just die and all local variables in
+ // IOChannel::Run() won't get destructed down which is bad since there is
+ // a local listener holding onto broadcasters... To ensure proper shutdown,
+ // a ^D (control-D) sequence (0x04) should be written to other end of the
+ // the "in" file handle that was passed into the contructor as closing the
+ // file handle doesn't seem to make el_gets() exit....
+ return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL);
+}
+
+void
+IOChannel::RefreshPrompt ()
+{
+ // If we are not in the middle of getting input from the user, there is no need to
+ // refresh the prompt.
+ IOLocker locker (m_output_mutex);
+ if (! IsGettingCommand())
+ return;
+
+ // If we haven't finished writing the prompt, there's no need to refresh it.
+ if (m_expecting_prompt)
+ return;
+
+ if (m_refresh_request_pending)
+ return;
+
+ ::el_set (m_edit_line, EL_REFRESH);
+ m_refresh_request_pending = true;
+}
+
+void
+IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous)
+{
+ if (len == 0 || buffer == NULL)
+ return;
+
+ // We're in the process of exiting -- IOChannel::Run() has already completed
+ // and set m_driver to NULL - it is time for us to leave now. We might not
+ // print the final ^D to stdout in this case. We need to do some re-work on
+ // how the I/O streams are managed at some point.
+ if (m_driver == NULL)
+ {
+ return;
+ }
+
+ // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+ IOLocker locker (m_output_mutex);
+ if (m_driver->EditlineReaderIsTop() && asynchronous)
+ ::fwrite (undo_prompt_string, 1, 4, m_out_file);
+ ::fwrite (buffer, 1, len, m_out_file);
+ if (asynchronous)
+ m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
+}
+
+void
+IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous)
+{
+ if (len == 0 || buffer == NULL)
+ return;
+
+ // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
+ IOLocker locker (m_output_mutex);
+ if (asynchronous)
+ ::fwrite (undo_prompt_string, 1, 4, m_err_file);
+ ::fwrite (buffer, 1, len, m_err_file);
+ if (asynchronous)
+ m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten);
+}
+
+void
+IOChannel::AddCommandToQueue (const char *command)
+{
+ m_command_queue.push (std::string(command));
+}
+
+bool
+IOChannel::GetCommandFromQueue (std::string &cmd)
+{
+ if (m_command_queue.empty())
+ return false;
+ cmd.swap(m_command_queue.front());
+ m_command_queue.pop ();
+ return true;
+}
+
+int
+IOChannel::CommandQueueSize () const
+{
+ return m_command_queue.size();
+}
+
+void
+IOChannel::ClearCommandQueue ()
+{
+ while (!m_command_queue.empty())
+ m_command_queue.pop();
+}
+
+bool
+IOChannel::CommandQueueIsEmpty () const
+{
+ return m_command_queue.empty();
+}
+
+bool
+IOChannel::IsGettingCommand () const
+{
+ return m_getting_command;
+}
+
+void
+IOChannel::SetGettingCommand (bool new_value)
+{
+ m_getting_command = new_value;
+}
+
+IOLocker::IOLocker (pthread_mutex_t &mutex) :
+ m_mutex_ptr (&mutex)
+{
+ if (m_mutex_ptr)
+ ::pthread_mutex_lock (m_mutex_ptr);
+
+}
+
+IOLocker::~IOLocker ()
+{
+ if (m_mutex_ptr)
+ ::pthread_mutex_unlock (m_mutex_ptr);
+}
diff --git a/tools/driver/IOChannel.h b/tools/driver/IOChannel.h
new file mode 100644
index 000000000000..36653a0c289f
--- /dev/null
+++ b/tools/driver/IOChannel.h
@@ -0,0 +1,174 @@
+//===-- IOChannel.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_IOChannel_h_
+#define lldb_IOChannel_h_
+
+#include <string>
+#include <queue>
+
+#if defined(__FreeBSD__)
+#include <readline/readline.h>
+#else
+#include <editline/readline.h>
+#endif
+#include <histedit.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include "Driver.h"
+
+class IOChannel : public lldb::SBBroadcaster
+{
+public:
+ enum {
+ eBroadcastBitHasUserInput = (1 << 0),
+ eBroadcastBitUserInterrupt = (1 << 1),
+ eBroadcastBitThreadShouldExit = (1 << 2),
+ eBroadcastBitThreadDidExit = (1 << 3),
+ eBroadcastBitThreadDidStart = (1 << 4),
+ eBroadcastBitsSTDOUT = (1 << 5),
+ eBroadcastBitsSTDERR = (1 << 6),
+ eBroadcastBitsSTDIN = (1 << 7),
+ eAllEventBits = 0xffffffff
+ };
+
+ enum LibeditGetInputResult
+ {
+ eLibeditGetInputEOF = 0,
+ eLibeditGetInputValid = 1,
+ eLibeditGetInputEmpty = 2,
+ eLibeditGetInputResultError = 4,
+ eLibeditGetInputResultUnknown = 0xffffffff
+ };
+
+ IOChannel (FILE *editline_in,
+ FILE *editline_out,
+ FILE *out,
+ FILE *err,
+ Driver *driver = NULL);
+
+ virtual
+ ~IOChannel ();
+
+ bool
+ Start ();
+
+ bool
+ Stop ();
+
+ static void *
+ IOReadThread (void *);
+
+ void
+ Run ();
+
+ void
+ OutWrite (const char *buffer, size_t len, bool asynchronous);
+
+ void
+ ErrWrite (const char *buffer, size_t len, bool asynchronous);
+
+ LibeditGetInputResult
+ LibeditGetInput (std::string &);
+
+ static void
+ LibeditOutputBytesReceived (void *baton, const void *src,size_t src_len);
+
+ void
+ SetPrompt ();
+
+ void
+ RefreshPrompt ();
+
+ void
+ AddCommandToQueue (const char *command);
+
+ bool
+ GetCommandFromQueue (std::string &cmd);
+
+ int
+ CommandQueueSize () const;
+
+ void
+ ClearCommandQueue ();
+
+ bool
+ CommandQueueIsEmpty () const;
+
+ const char *
+ GetPrompt ();
+
+ bool
+ EditLineHasCharacters ();
+
+ void
+ EraseCharsBeforeCursor ();
+
+ static unsigned char
+ ElCompletionFn (EditLine *e, int ch);
+
+ void
+ ElResize();
+
+protected:
+
+ bool
+ IsGettingCommand () const;
+
+ void
+ SetGettingCommand (bool new_value);
+
+private:
+
+ pthread_mutex_t m_output_mutex;
+ struct timeval m_enter_elgets_time;
+
+ Driver *m_driver;
+ lldb::thread_t m_read_thread;
+ bool m_read_thread_should_exit;
+ FILE *m_out_file;
+ FILE *m_err_file;
+ std::queue<std::string> m_command_queue;
+ const char *m_completion_key;
+
+ EditLine *m_edit_line;
+ History *m_history;
+ HistEvent m_history_event;
+ bool m_getting_command;
+ bool m_expecting_prompt;
+ std::string m_prompt_str; // for accumlating the prompt as it gets written out by editline
+ bool m_refresh_request_pending;
+
+ void
+ HistorySaveLoad (bool save);
+
+ unsigned char
+ HandleCompletion (EditLine *e, int ch);
+};
+
+class IOLocker
+{
+public:
+
+ IOLocker (pthread_mutex_t &mutex);
+
+ ~IOLocker ();
+
+protected:
+
+ pthread_mutex_t *m_mutex_ptr;
+
+private:
+
+ IOLocker (const IOLocker&);
+ const IOLocker& operator= (const IOLocker&);
+};
+
+#endif // lldb_IOChannel_h_